react-native-magic-tab-bar 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +121 -0
- package/lib/module/MagicTabBar.js +130 -0
- package/lib/module/MagicTabBar.js.map +1 -0
- package/lib/module/MagicTabItem.js +96 -0
- package/lib/module/MagicTabItem.js.map +1 -0
- package/lib/module/MagicTabs.js +60 -0
- package/lib/module/MagicTabs.js.map +1 -0
- package/lib/module/defaultTabs.js +52 -0
- package/lib/module/defaultTabs.js.map +1 -0
- package/lib/module/index.js +8 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/theme.js +16 -0
- package/lib/module/theme.js.map +1 -0
- package/lib/module/types.js +4 -0
- package/lib/module/types.js.map +1 -0
- package/lib/typescript/MagicTabBar.d.ts +38 -0
- package/lib/typescript/MagicTabBar.d.ts.map +1 -0
- package/lib/typescript/MagicTabItem.d.ts +28 -0
- package/lib/typescript/MagicTabItem.d.ts.map +1 -0
- package/lib/typescript/MagicTabs.d.ts +49 -0
- package/lib/typescript/MagicTabs.d.ts.map +1 -0
- package/lib/typescript/defaultTabs.d.ts +10 -0
- package/lib/typescript/defaultTabs.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +10 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/theme.d.ts +4 -0
- package/lib/typescript/theme.d.ts.map +1 -0
- package/lib/typescript/types.d.ts +48 -0
- package/lib/typescript/types.d.ts.map +1 -0
- package/package.json +91 -0
- package/src/MagicTabBar.tsx +181 -0
- package/src/MagicTabItem.tsx +123 -0
- package/src/MagicTabs.tsx +87 -0
- package/src/defaultTabs.tsx +55 -0
- package/src/index.tsx +15 -0
- package/src/theme.ts +15 -0
- package/src/types.ts +51 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015-present 650 Industries, Inc. (aka Expo)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
# react-native-magic-tab-bar
|
|
2
|
+
|
|
3
|
+
A customizable, animated floating tab bar for **Expo Router** (SDK 56+). You bring
|
|
4
|
+
your own icons and labels — the package handles the layout, the active-pill
|
|
5
|
+
animation, and the navigation wiring.
|
|
6
|
+
|
|
7
|
+
> Built on Expo Router's headless tabs (`expo-router/ui`). It works in any
|
|
8
|
+
> Expo Router project on iOS and Android. (Bare React Native / React Navigation
|
|
9
|
+
> is not supported yet — see [Roadmap](#roadmap).)
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install react-native-magic-tab-bar
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
### Peer dependencies
|
|
18
|
+
|
|
19
|
+
These are normally already present in an Expo Router app:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx expo install expo-router react-native-reanimated react-native-safe-area-context react-native-worklets
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Make sure the Reanimated/Worklets Babel plugin is enabled (Expo SDK 56's
|
|
26
|
+
`babel-preset-expo` configures this automatically).
|
|
27
|
+
|
|
28
|
+
## Usage
|
|
29
|
+
|
|
30
|
+
Use `MagicTabs` as your tab navigator in an `app/_layout.tsx`. Each entry in
|
|
31
|
+
`tabs` maps a route to an icon and label:
|
|
32
|
+
|
|
33
|
+
```tsx
|
|
34
|
+
// app/_layout.tsx
|
|
35
|
+
import { MagicTabs, type MagicTabIconProps } from "react-native-magic-tab-bar";
|
|
36
|
+
import { Home, Search, User } from "./icons"; // any icon components you like
|
|
37
|
+
|
|
38
|
+
export default function Layout() {
|
|
39
|
+
return (
|
|
40
|
+
<MagicTabs
|
|
41
|
+
tabs={[
|
|
42
|
+
{ name: "index", href: "/", label: "Home", icon: ({ color, size }) => <Home color={color} size={size} /> },
|
|
43
|
+
{ name: "search", href: "/search", label: "Search", icon: ({ color, size }) => <Search color={color} size={size} /> },
|
|
44
|
+
{ name: "profile", href: "/profile", label: "Profile", icon: ({ color, size }) => <User color={color} size={size} /> },
|
|
45
|
+
]}
|
|
46
|
+
/>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
The `name` must match the route file in your `app/` directory (e.g. `index`,
|
|
52
|
+
`search`, `profile`), and `href` is where the tab navigates.
|
|
53
|
+
|
|
54
|
+
### The glass / blur look
|
|
55
|
+
|
|
56
|
+
Pass `renderBackground` to render any view behind the bar — e.g. a blur:
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import { GlassView } from "expo-glass-effect"; // or @react-native-community/blur on bare RN
|
|
60
|
+
|
|
61
|
+
<MagicTabs
|
|
62
|
+
tabs={tabs}
|
|
63
|
+
renderBackground={() => <GlassView style={{ flex: 1 }} />}
|
|
64
|
+
/>;
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
When `renderBackground` is omitted, a solid `barColor` is used.
|
|
68
|
+
|
|
69
|
+
## API
|
|
70
|
+
|
|
71
|
+
### `<MagicTabs />`
|
|
72
|
+
|
|
73
|
+
| Prop | Type | Default | Description |
|
|
74
|
+
| ------------------ | --------------------------------- | ------------ | ------------------------------------------------- |
|
|
75
|
+
| `tabs` | `MagicTabConfig[]` | — | The tabs, in order. |
|
|
76
|
+
| `theme` | `Partial<MagicTabBarTheme>` | `defaultTheme` | Override any visual token. |
|
|
77
|
+
| `variant` | `'floating' \| 'docked'` | `'floating'` | Float over content, or dock in flow. |
|
|
78
|
+
| `renderBackground` | `() => ReactNode` | — | Custom background (blur/glass) behind the bar. |
|
|
79
|
+
|
|
80
|
+
### `MagicTabConfig`
|
|
81
|
+
|
|
82
|
+
| Field | Type | Description |
|
|
83
|
+
| ------- | ------------------------------------------ | --------------------------------------------- |
|
|
84
|
+
| `name` | `string` | Route name (matches the file in `app/`). |
|
|
85
|
+
| `href` | `Href` | Destination, e.g. `/` or `/search`. |
|
|
86
|
+
| `label` | `string?` | Shown next to the icon while active. |
|
|
87
|
+
| `icon` | `(p: MagicTabIconProps) => ReactNode` | Renders the icon. Gets `{ focused, color, size }`. |
|
|
88
|
+
|
|
89
|
+
### Theming (`MagicTabBarTheme`)
|
|
90
|
+
|
|
91
|
+
`barColor`, `activePillColor`, `activeColor`, `inactiveColor`, `iconSize`,
|
|
92
|
+
`height`, `radius`, `horizontalMargin`, `bottomInset`. See `defaultTheme`.
|
|
93
|
+
|
|
94
|
+
## Development
|
|
95
|
+
|
|
96
|
+
This repo is a monorepo: the library lives at the root (`src/`) and `example/`
|
|
97
|
+
is a runnable Expo app that imports the library straight from source.
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# from the repo root
|
|
101
|
+
npm install # installs example deps + build tooling, links the library
|
|
102
|
+
cd example && npx expo start
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Editing files in `src/` hot-reloads in the example app.
|
|
106
|
+
|
|
107
|
+
### Building / publishing
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
npm run build # react-native-builder-bob -> lib/ (ESM + d.ts)
|
|
111
|
+
npm publish
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Roadmap
|
|
115
|
+
|
|
116
|
+
- Sliding active-pill that animates between tabs (currently per-tab pill).
|
|
117
|
+
- A React Navigation (`@react-navigation/bottom-tabs`) adapter for bare RN.
|
|
118
|
+
|
|
119
|
+
## License
|
|
120
|
+
|
|
121
|
+
MIT
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { forwardRef } from "react";
|
|
4
|
+
import { StyleSheet, View } from "react-native";
|
|
5
|
+
import { useSafeAreaInsets } from "react-native-safe-area-context";
|
|
6
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
7
|
+
/**
|
|
8
|
+
* `expo-glass-effect` is an optional peer dependency. We load it through a
|
|
9
|
+
* guarded `require` so the library still installs and runs for consumers who
|
|
10
|
+
* don't need (or install) it — when it's absent, `glass` mode silently falls
|
|
11
|
+
* back to the translucent `barColor`. The try/catch lets Metro treat it as an
|
|
12
|
+
* optional dependency instead of failing the bundle.
|
|
13
|
+
*/
|
|
14
|
+
const glassEffect = (() => {
|
|
15
|
+
try {
|
|
16
|
+
return require("expo-glass-effect");
|
|
17
|
+
} catch {
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
})();
|
|
21
|
+
|
|
22
|
+
/** Lowest bar opacity we allow, so a transparent bar never becomes invisible. */
|
|
23
|
+
export const MIN_BAR_OPACITY = 0.1;
|
|
24
|
+
/**
|
|
25
|
+
* The visual container of the tab bar. Designed to be used as the `asChild`
|
|
26
|
+
* target of an Expo Router `<TabList>`.
|
|
27
|
+
*/
|
|
28
|
+
export const MagicTabBar = /*#__PURE__*/forwardRef(function MagicTabBar({
|
|
29
|
+
theme,
|
|
30
|
+
variant = "floating",
|
|
31
|
+
isTransparent = false,
|
|
32
|
+
transparency = 0.6,
|
|
33
|
+
glass = false,
|
|
34
|
+
renderBackground,
|
|
35
|
+
children,
|
|
36
|
+
style,
|
|
37
|
+
...rest
|
|
38
|
+
}, ref) {
|
|
39
|
+
const insets = useSafeAreaInsets();
|
|
40
|
+
const floating = variant !== "docked";
|
|
41
|
+
// Native Liquid Glass needs the optional `expo-glass-effect` dep and iOS
|
|
42
|
+
// 26+; everywhere else we fall back to the translucent color background.
|
|
43
|
+
const useGlass = glass && !!glassEffect?.isLiquidGlassAvailable();
|
|
44
|
+
// Only a transparent bar fades; otherwise it stays fully opaque. The level
|
|
45
|
+
// is clamped so it never drops below MIN_BAR_OPACITY or above 1.
|
|
46
|
+
const barOpacity = isTransparent ? Math.min(Math.max(transparency, MIN_BAR_OPACITY), 1) : 1;
|
|
47
|
+
// A see-through bar shouldn't cast a hard drop shadow — it reads as an odd
|
|
48
|
+
// halo around the translucent fill. Keep the shadow only for a solid bar.
|
|
49
|
+
const seeThrough = useGlass || isTransparent;
|
|
50
|
+
return /*#__PURE__*/_jsx(View, {
|
|
51
|
+
ref: ref,
|
|
52
|
+
pointerEvents: "box-none",
|
|
53
|
+
style: [floating ? styles.floatingWrapper : styles.dockedWrapper, {
|
|
54
|
+
paddingHorizontal: theme.horizontalMargin,
|
|
55
|
+
paddingBottom: (floating ? insets.bottom : 0) + theme.bottomInset
|
|
56
|
+
}],
|
|
57
|
+
children: /*#__PURE__*/_jsxs(View, {
|
|
58
|
+
style: [styles.bar, !seeThrough && styles.barShadow, {
|
|
59
|
+
height: theme.height,
|
|
60
|
+
borderRadius: theme.radius
|
|
61
|
+
}],
|
|
62
|
+
children: [renderBackground ? /*#__PURE__*/_jsx(View, {
|
|
63
|
+
pointerEvents: "none",
|
|
64
|
+
style: [StyleSheet.absoluteFill, {
|
|
65
|
+
borderRadius: theme.radius,
|
|
66
|
+
overflow: "hidden"
|
|
67
|
+
}],
|
|
68
|
+
children: renderBackground()
|
|
69
|
+
}) : useGlass && glassEffect ?
|
|
70
|
+
/*#__PURE__*/
|
|
71
|
+
// Native iOS Liquid Glass. We tint it with the bar color so themes
|
|
72
|
+
// still carry through, and clip it to the bar's rounded corners.
|
|
73
|
+
_jsx(glassEffect.GlassView, {
|
|
74
|
+
pointerEvents: "none",
|
|
75
|
+
glassEffectStyle: "regular",
|
|
76
|
+
tintColor: theme.barColor,
|
|
77
|
+
style: [StyleSheet.absoluteFill, {
|
|
78
|
+
borderRadius: theme.radius
|
|
79
|
+
}]
|
|
80
|
+
}) :
|
|
81
|
+
/*#__PURE__*/
|
|
82
|
+
// Background color lives in its own layer so `transparency` fades
|
|
83
|
+
// only the bar's fill, never the icons or labels on top of it.
|
|
84
|
+
_jsx(View, {
|
|
85
|
+
pointerEvents: "none",
|
|
86
|
+
style: [StyleSheet.absoluteFill, {
|
|
87
|
+
backgroundColor: theme.barColor,
|
|
88
|
+
borderRadius: theme.radius,
|
|
89
|
+
opacity: barOpacity
|
|
90
|
+
}]
|
|
91
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
92
|
+
style: [styles.row, style],
|
|
93
|
+
...rest,
|
|
94
|
+
children: children
|
|
95
|
+
})]
|
|
96
|
+
})
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
const styles = StyleSheet.create({
|
|
100
|
+
floatingWrapper: {
|
|
101
|
+
position: "absolute",
|
|
102
|
+
left: 0,
|
|
103
|
+
right: 0,
|
|
104
|
+
bottom: 0
|
|
105
|
+
},
|
|
106
|
+
dockedWrapper: {
|
|
107
|
+
width: "100%"
|
|
108
|
+
},
|
|
109
|
+
bar: {
|
|
110
|
+
flexDirection: "row"
|
|
111
|
+
},
|
|
112
|
+
barShadow: {
|
|
113
|
+
shadowColor: "#000",
|
|
114
|
+
shadowOpacity: 0.25,
|
|
115
|
+
shadowRadius: 16,
|
|
116
|
+
shadowOffset: {
|
|
117
|
+
width: 0,
|
|
118
|
+
height: 8
|
|
119
|
+
},
|
|
120
|
+
elevation: 12
|
|
121
|
+
},
|
|
122
|
+
row: {
|
|
123
|
+
flex: 1,
|
|
124
|
+
flexDirection: "row",
|
|
125
|
+
alignItems: "center",
|
|
126
|
+
justifyContent: "space-around",
|
|
127
|
+
paddingHorizontal: 6
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
//# sourceMappingURL=MagicTabBar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["forwardRef","StyleSheet","View","useSafeAreaInsets","jsx","_jsx","jsxs","_jsxs","glassEffect","require","MIN_BAR_OPACITY","MagicTabBar","theme","variant","isTransparent","transparency","glass","renderBackground","children","style","rest","ref","insets","floating","useGlass","isLiquidGlassAvailable","barOpacity","Math","min","max","seeThrough","pointerEvents","styles","floatingWrapper","dockedWrapper","paddingHorizontal","horizontalMargin","paddingBottom","bottom","bottomInset","bar","barShadow","height","borderRadius","radius","absoluteFill","overflow","GlassView","glassEffectStyle","tintColor","barColor","backgroundColor","opacity","row","create","position","left","right","width","flexDirection","shadowColor","shadowOpacity","shadowRadius","shadowOffset","elevation","flex","alignItems","justifyContent"],"sourceRoot":"../../src","sources":["MagicTabBar.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { forwardRef, useEffect } from 'react';
|
|
4
|
+
import { Pressable, StyleSheet } from 'react-native';
|
|
5
|
+
import Animated, { FadeIn, LinearTransition, useAnimatedStyle, useSharedValue, withSpring } from 'react-native-reanimated';
|
|
6
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
7
|
+
const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
|
|
8
|
+
const SPRING = {
|
|
9
|
+
mass: 0.6,
|
|
10
|
+
damping: 18,
|
|
11
|
+
stiffness: 180
|
|
12
|
+
};
|
|
13
|
+
const transition = LinearTransition.springify().mass(SPRING.mass).damping(SPRING.damping).stiffness(SPRING.stiffness);
|
|
14
|
+
/**
|
|
15
|
+
* A single tab. Designed to be used as the `asChild` target of an
|
|
16
|
+
* Expo Router `<TabTrigger>`, which injects the focus state and press handlers.
|
|
17
|
+
*
|
|
18
|
+
* Each tab sizes to its content — just the icon when inactive, icon + label
|
|
19
|
+
* when active — so the active label is never clipped, on any screen width.
|
|
20
|
+
*/
|
|
21
|
+
export const MagicTabItem = /*#__PURE__*/forwardRef(function MagicTabItem({
|
|
22
|
+
icon,
|
|
23
|
+
label,
|
|
24
|
+
theme,
|
|
25
|
+
isFocused,
|
|
26
|
+
onPress,
|
|
27
|
+
onLongPress
|
|
28
|
+
}, ref) {
|
|
29
|
+
const focused = Boolean(isFocused);
|
|
30
|
+
const progress = useSharedValue(focused ? 1 : 0);
|
|
31
|
+
useEffect(() => {
|
|
32
|
+
progress.value = withSpring(focused ? 1 : 0, SPRING);
|
|
33
|
+
}, [focused, progress]);
|
|
34
|
+
const pillStyle = useAnimatedStyle(() => ({
|
|
35
|
+
opacity: progress.value,
|
|
36
|
+
transform: [{
|
|
37
|
+
scale: 0.8 + progress.value * 0.2
|
|
38
|
+
}]
|
|
39
|
+
}));
|
|
40
|
+
const color = focused ? theme.activeColor : theme.inactiveColor;
|
|
41
|
+
const showLabel = focused && !!label;
|
|
42
|
+
return /*#__PURE__*/_jsxs(AnimatedPressable, {
|
|
43
|
+
ref: ref,
|
|
44
|
+
onPress: onPress,
|
|
45
|
+
onLongPress: onLongPress,
|
|
46
|
+
accessibilityRole: "tab",
|
|
47
|
+
accessibilityState: {
|
|
48
|
+
selected: focused
|
|
49
|
+
},
|
|
50
|
+
layout: transition,
|
|
51
|
+
style: [styles.pressable, focused && styles.pressableActive],
|
|
52
|
+
children: [/*#__PURE__*/_jsx(Animated.View, {
|
|
53
|
+
pointerEvents: "none",
|
|
54
|
+
style: [StyleSheet.absoluteFill, {
|
|
55
|
+
backgroundColor: theme.activePillColor,
|
|
56
|
+
borderRadius: theme.radius
|
|
57
|
+
}, pillStyle]
|
|
58
|
+
}), icon({
|
|
59
|
+
focused,
|
|
60
|
+
color,
|
|
61
|
+
size: theme.iconSize
|
|
62
|
+
}), showLabel ? /*#__PURE__*/_jsx(Animated.Text, {
|
|
63
|
+
entering: FadeIn.duration(150),
|
|
64
|
+
numberOfLines: 1,
|
|
65
|
+
style: [styles.label, {
|
|
66
|
+
color,
|
|
67
|
+
fontSize: theme.fontSize
|
|
68
|
+
}],
|
|
69
|
+
children: label
|
|
70
|
+
}) : null]
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
const styles = StyleSheet.create({
|
|
74
|
+
pressable: {
|
|
75
|
+
alignSelf: 'center',
|
|
76
|
+
flexDirection: 'row',
|
|
77
|
+
alignItems: 'center',
|
|
78
|
+
justifyContent: 'center',
|
|
79
|
+
gap: 6,
|
|
80
|
+
paddingVertical: 8,
|
|
81
|
+
paddingHorizontal: 12
|
|
82
|
+
},
|
|
83
|
+
// The active tab gets extra padding so its pill is a touch larger than the
|
|
84
|
+
// inactive icons, making the current tab easy to spot. flexShrink lets it
|
|
85
|
+
// truncate its label only as a last resort on very narrow screens.
|
|
86
|
+
pressableActive: {
|
|
87
|
+
flexShrink: 1,
|
|
88
|
+
paddingVertical: 10,
|
|
89
|
+
paddingHorizontal: 18
|
|
90
|
+
},
|
|
91
|
+
label: {
|
|
92
|
+
fontWeight: '600',
|
|
93
|
+
flexShrink: 1
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
//# sourceMappingURL=MagicTabItem.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["forwardRef","useEffect","Pressable","StyleSheet","Animated","FadeIn","LinearTransition","useAnimatedStyle","useSharedValue","withSpring","jsx","_jsx","jsxs","_jsxs","AnimatedPressable","createAnimatedComponent","SPRING","mass","damping","stiffness","transition","springify","MagicTabItem","icon","label","theme","isFocused","onPress","onLongPress","ref","focused","Boolean","progress","value","pillStyle","opacity","transform","scale","color","activeColor","inactiveColor","showLabel","accessibilityRole","accessibilityState","selected","layout","style","styles","pressable","pressableActive","children","View","pointerEvents","absoluteFill","backgroundColor","activePillColor","borderRadius","radius","size","iconSize","Text","entering","duration","numberOfLines","fontSize","create","alignSelf","flexDirection","alignItems","justifyContent","gap","paddingVertical","paddingHorizontal","flexShrink","fontWeight"],"sourceRoot":"../../src","sources":["MagicTabItem.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { Tabs, TabList, TabSlot, TabTrigger } from 'expo-router/ui';
|
|
4
|
+
import { MagicTabBar } from "./MagicTabBar.js";
|
|
5
|
+
import { MagicTabItem } from "./MagicTabItem.js";
|
|
6
|
+
import { defaultTabs } from "./defaultTabs.js";
|
|
7
|
+
import { defaultTheme } from "./theme.js";
|
|
8
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
9
|
+
/**
|
|
10
|
+
* A drop-in custom tab bar for Expo Router.
|
|
11
|
+
*
|
|
12
|
+
* Use it in an `app/_layout.tsx` and pass your routes, icons and labels as props:
|
|
13
|
+
*
|
|
14
|
+
* ```tsx
|
|
15
|
+
* <MagicTabs
|
|
16
|
+
* tabs={[
|
|
17
|
+
* { name: 'index', href: '/', label: 'Home', icon: ({ color }) => <Home color={color} /> },
|
|
18
|
+
* { name: 'search', href: '/search', label: 'Search', icon: ({ color }) => <Search color={color} /> },
|
|
19
|
+
* ]}
|
|
20
|
+
* />
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
export function MagicTabs({
|
|
24
|
+
tabs = defaultTabs,
|
|
25
|
+
theme: themeOverride,
|
|
26
|
+
variant,
|
|
27
|
+
isTransparent,
|
|
28
|
+
transparency,
|
|
29
|
+
glass,
|
|
30
|
+
renderBackground
|
|
31
|
+
}) {
|
|
32
|
+
const theme = {
|
|
33
|
+
...defaultTheme,
|
|
34
|
+
...themeOverride
|
|
35
|
+
};
|
|
36
|
+
return /*#__PURE__*/_jsxs(Tabs, {
|
|
37
|
+
children: [/*#__PURE__*/_jsx(TabSlot, {}), /*#__PURE__*/_jsx(TabList, {
|
|
38
|
+
asChild: true,
|
|
39
|
+
children: /*#__PURE__*/_jsx(MagicTabBar, {
|
|
40
|
+
theme: theme,
|
|
41
|
+
variant: variant,
|
|
42
|
+
isTransparent: isTransparent,
|
|
43
|
+
transparency: transparency,
|
|
44
|
+
glass: glass,
|
|
45
|
+
renderBackground: renderBackground,
|
|
46
|
+
children: tabs.map(tab => /*#__PURE__*/_jsx(TabTrigger, {
|
|
47
|
+
name: tab.name,
|
|
48
|
+
href: tab.href,
|
|
49
|
+
asChild: true,
|
|
50
|
+
children: /*#__PURE__*/_jsx(MagicTabItem, {
|
|
51
|
+
icon: tab.icon,
|
|
52
|
+
label: tab.label,
|
|
53
|
+
theme: theme
|
|
54
|
+
})
|
|
55
|
+
}, tab.name))
|
|
56
|
+
})
|
|
57
|
+
})]
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=MagicTabs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["Tabs","TabList","TabSlot","TabTrigger","MagicTabBar","MagicTabItem","defaultTabs","defaultTheme","jsx","_jsx","jsxs","_jsxs","MagicTabs","tabs","theme","themeOverride","variant","isTransparent","transparency","glass","renderBackground","children","asChild","map","tab","name","href","icon","label"],"sourceRoot":"../../src","sources":["MagicTabs.tsx"],"mappings":";;AACA,SAASA,IAAI,EAAEC,OAAO,EAAEC,OAAO,EAAEC,UAAU,QAAQ,gBAAgB;AACnE,SAASC,WAAW,QAAQ,kBAAe;AAC3C,SAASC,YAAY,QAAQ,mBAAgB;AAC7C,SAASC,WAAW,QAAQ,kBAAe;AAC3C,SAASC,YAAY,QAAQ,YAAS;AAAC,SAAAC,GAAA,IAAAC,IAAA,EAAAC,IAAA,IAAAC,KAAA;AAmCvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,SAASA,CAAC;EACxBC,IAAI,GAAGP,WAAW;EAClBQ,KAAK,EAAEC,aAAa;EACpBC,OAAO;EACPC,aAAa;EACbC,YAAY;EACZC,KAAK;EACLC;AACc,CAAC,EAAE;EACjB,MAAMN,KAAuB,GAAG;IAAE,GAAGP,YAAY;IAAE,GAAGQ;EAAc,CAAC;EAErE,oBACEJ,KAAA,CAACX,IAAI;IAAAqB,QAAA,gBACHZ,IAAA,CAACP,OAAO,IAAE,CAAC,eACXO,IAAA,CAACR,OAAO;MAACqB,OAAO;MAAAD,QAAA,eACdZ,IAAA,CAACL,WAAW;QACVU,KAAK,EAAEA,KAAM;QACbE,OAAO,EAAEA,OAAQ;QACjBC,aAAa,EAAEA,aAAc;QAC7BC,YAAY,EAAEA,YAAa;QAC3BC,KAAK,EAAEA,KAAM;QACbC,gBAAgB,EAAEA,gBAAiB;QAAAC,QAAA,EAElCR,IAAI,CAACU,GAAG,CAAEC,GAAG,iBACZf,IAAA,CAACN,UAAU;UAAgBsB,IAAI,EAAED,GAAG,CAACC,IAAK;UAACC,IAAI,EAAEF,GAAG,CAACE,IAAK;UAACJ,OAAO;UAAAD,QAAA,eAChEZ,IAAA,CAACJ,YAAY;YAACsB,IAAI,EAAEH,GAAG,CAACG,IAAK;YAACC,KAAK,EAAEJ,GAAG,CAACI,KAAM;YAACd,KAAK,EAAEA;UAAM,CAAE;QAAC,GADjDU,GAAG,CAACC,IAET,CACb;MAAC,CACS;IAAC,CACP,CAAC;EAAA,CACN,CAAC;AAEX","ignoreList":[]}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { Ionicons } from "@expo/vector-icons";
|
|
4
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
5
|
+
/**
|
|
6
|
+
* Builds an icon renderer from a pair of Ionicons glyphs. The filled variant
|
|
7
|
+
* is shown for the active tab and the outline variant for inactive tabs.
|
|
8
|
+
*/
|
|
9
|
+
const ionicon = (active, inactive) => ({
|
|
10
|
+
focused,
|
|
11
|
+
color,
|
|
12
|
+
size
|
|
13
|
+
}) => /*#__PURE__*/_jsx(Ionicons, {
|
|
14
|
+
name: focused ? active : inactive,
|
|
15
|
+
color: color,
|
|
16
|
+
size: size
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* The tabs used when `<MagicTabs />` is rendered without a `tabs` prop:
|
|
21
|
+
* Home, Explore, Notifications, Inbox and Profile, each with a matching Ionicon.
|
|
22
|
+
*
|
|
23
|
+
* Assumes the app has routes named `index` (`/`), `explore`, `notifications`,
|
|
24
|
+
* `inbox` and `profile`. Pass your own `tabs` to `<MagicTabs />` to override.
|
|
25
|
+
*/
|
|
26
|
+
export const defaultTabs = [{
|
|
27
|
+
name: "index",
|
|
28
|
+
href: "/",
|
|
29
|
+
label: "Home",
|
|
30
|
+
icon: ionicon("home", "home-outline")
|
|
31
|
+
}, {
|
|
32
|
+
name: "explore",
|
|
33
|
+
href: "/explore",
|
|
34
|
+
label: "Explore",
|
|
35
|
+
icon: ionicon("compass", "compass-outline")
|
|
36
|
+
}, {
|
|
37
|
+
name: "notifications",
|
|
38
|
+
href: "/notifications",
|
|
39
|
+
label: "Notifications",
|
|
40
|
+
icon: ionicon("notifications", "notifications-outline")
|
|
41
|
+
}, {
|
|
42
|
+
name: "inbox",
|
|
43
|
+
href: "/inbox",
|
|
44
|
+
label: "Inbox",
|
|
45
|
+
icon: ionicon("chatbubble-sharp", "chatbubble-outline")
|
|
46
|
+
}, {
|
|
47
|
+
name: "profile",
|
|
48
|
+
href: "/profile",
|
|
49
|
+
label: "Profile",
|
|
50
|
+
icon: ionicon("person", "person-outline")
|
|
51
|
+
}];
|
|
52
|
+
//# sourceMappingURL=defaultTabs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["Ionicons","jsx","_jsx","ionicon","active","inactive","focused","color","size","name","defaultTabs","href","label","icon"],"sourceRoot":"../../src","sources":["defaultTabs.tsx"],"mappings":";;AAAA,SAASA,QAAQ,QAAQ,oBAAoB;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAM9C;AACA;AACA;AACA;AACA,MAAMC,OAAO,GACXA,CAACC,MAAmB,EAAEC,QAAqB,KAC3C,CAAC;EAAEC,OAAO;EAAEC,KAAK;EAAEC;AAAwB,CAAC,kBAC1CN,IAAA,CAACF,QAAQ;EAACS,IAAI,EAAEH,OAAO,GAAGF,MAAM,GAAGC,QAAS;EAACE,KAAK,EAAEA,KAAM;EAACC,IAAI,EAAEA;AAAK,CAAE,CACzE;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,MAAME,WAA6B,GAAG,CAC3C;EACED,IAAI,EAAE,OAAO;EACbE,IAAI,EAAE,GAAG;EACTC,KAAK,EAAE,MAAM;EACbC,IAAI,EAAEV,OAAO,CAAC,MAAM,EAAE,cAAc;AACtC,CAAC,EACD;EACEM,IAAI,EAAE,SAAS;EACfE,IAAI,EAAE,UAAU;EAChBC,KAAK,EAAE,SAAS;EAChBC,IAAI,EAAEV,OAAO,CAAC,SAAS,EAAE,iBAAiB;AAC5C,CAAC,EACD;EACEM,IAAI,EAAE,eAAe;EACrBE,IAAI,EAAE,gBAAgB;EACtBC,KAAK,EAAE,eAAe;EACtBC,IAAI,EAAEV,OAAO,CAAC,eAAe,EAAE,uBAAuB;AACxD,CAAC,EACD;EACEM,IAAI,EAAE,OAAO;EACbE,IAAI,EAAE,QAAQ;EACdC,KAAK,EAAE,OAAO;EACdC,IAAI,EAAEV,OAAO,CAAC,kBAAkB,EAAE,oBAAoB;AACxD,CAAC,EACD;EACEM,IAAI,EAAE,SAAS;EACfE,IAAI,EAAE,UAAU;EAChBC,KAAK,EAAE,SAAS;EAChBC,IAAI,EAAEV,OAAO,CAAC,QAAQ,EAAE,gBAAgB;AAC1C,CAAC,CACF","ignoreList":[]}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
export { MagicTabs } from "./MagicTabs.js";
|
|
4
|
+
export { MagicTabBar } from "./MagicTabBar.js";
|
|
5
|
+
export { MagicTabItem } from "./MagicTabItem.js";
|
|
6
|
+
export { defaultTabs } from "./defaultTabs.js";
|
|
7
|
+
export { defaultTheme } from "./theme.js";
|
|
8
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["MagicTabs","MagicTabBar","MagicTabItem","defaultTabs","defaultTheme"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,SAAS,QAAQ,gBAAa;AACvC,SAASC,WAAW,QAAQ,kBAAe;AAC3C,SAASC,YAAY,QAAQ,mBAAgB;AAC7C,SAASC,WAAW,QAAQ,kBAAe;AAC3C,SAASC,YAAY,QAAQ,YAAS","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"type":"module"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
/** Default dark, floating-pill theme. */
|
|
4
|
+
export const defaultTheme = {
|
|
5
|
+
barColor: 'rgba(38, 38, 40, 0.94)',
|
|
6
|
+
activePillColor: 'rgba(120, 120, 124, 0.55)',
|
|
7
|
+
activeColor: '#FFFFFF',
|
|
8
|
+
inactiveColor: '#FFFFFF',
|
|
9
|
+
iconSize: 22,
|
|
10
|
+
fontSize: 12,
|
|
11
|
+
height: 56,
|
|
12
|
+
radius: 28,
|
|
13
|
+
horizontalMargin: 14,
|
|
14
|
+
bottomInset: 10
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["defaultTheme","barColor","activePillColor","activeColor","inactiveColor","iconSize","fontSize","height","radius","horizontalMargin","bottomInset"],"sourceRoot":"../../src","sources":["theme.ts"],"mappings":";;AAEA;AACA,OAAO,MAAMA,YAA8B,GAAG;EAC5CC,QAAQ,EAAE,wBAAwB;EAClCC,eAAe,EAAE,2BAA2B;EAC5CC,WAAW,EAAE,SAAS;EACtBC,aAAa,EAAE,SAAS;EACxBC,QAAQ,EAAE,EAAE;EACZC,QAAQ,EAAE,EAAE;EACZC,MAAM,EAAE,EAAE;EACVC,MAAM,EAAE,EAAE;EACVC,gBAAgB,EAAE,EAAE;EACpBC,WAAW,EAAE;AACf,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":[],"sourceRoot":"../../src","sources":["types.ts"],"mappings":"","ignoreList":[]}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { type ReactNode } from "react";
|
|
2
|
+
import { View, type ViewProps } from "react-native";
|
|
3
|
+
import type { MagicTabBarTheme, MagicTabBarVariant } from "./types";
|
|
4
|
+
/** Lowest bar opacity we allow, so a transparent bar never becomes invisible. */
|
|
5
|
+
export declare const MIN_BAR_OPACITY = 0.1;
|
|
6
|
+
export interface MagicTabBarProps extends ViewProps {
|
|
7
|
+
/** Resolved theme. Provided automatically by `MagicTabs`. */
|
|
8
|
+
theme: MagicTabBarTheme;
|
|
9
|
+
/** Position the bar floating over content (default) or docked in-flow. */
|
|
10
|
+
variant?: MagicTabBarVariant;
|
|
11
|
+
/**
|
|
12
|
+
* Make the bar background see-through. Off by default — the bar is fully
|
|
13
|
+
* opaque. Set the strength of the effect with `transparency`.
|
|
14
|
+
*/
|
|
15
|
+
isTransparent?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Opacity of the bar background while `isTransparent` is true, from 0 to 1
|
|
18
|
+
* (e.g. `0.4` = 40% visible). Clamped to a minimum of {@link MIN_BAR_OPACITY}
|
|
19
|
+
* so the bar never disappears. Defaults to 0.6 when omitted.
|
|
20
|
+
*/
|
|
21
|
+
transparency?: number;
|
|
22
|
+
/**
|
|
23
|
+
* Render the bar as native iOS Liquid Glass (via `expo-glass-effect`).
|
|
24
|
+
* Requires iOS 26+; on any other platform/version it automatically falls
|
|
25
|
+
* back to the translucent `barColor` (honoring `transparency`).
|
|
26
|
+
*/
|
|
27
|
+
glass?: boolean;
|
|
28
|
+
/** Render a custom background (e.g. a blur/glass view) behind the bar. */
|
|
29
|
+
renderBackground?: () => ReactNode;
|
|
30
|
+
/** The tab items. Provided automatically by `MagicTabs`. */
|
|
31
|
+
children?: ReactNode;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* The visual container of the tab bar. Designed to be used as the `asChild`
|
|
35
|
+
* target of an Expo Router `<TabList>`.
|
|
36
|
+
*/
|
|
37
|
+
export declare const MagicTabBar: import("react").ForwardRefExoticComponent<MagicTabBarProps & import("react").RefAttributes<View>>;
|
|
38
|
+
//# sourceMappingURL=MagicTabBar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MagicTabBar.d.ts","sourceRoot":"","sources":["../../src/MagicTabBar.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AACnD,OAAO,EAEL,IAAI,EAEJ,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAEtB,OAAO,KAAK,EAAE,gBAAgB,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAmBpE,iFAAiF;AACjF,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC,MAAM,WAAW,gBAAiB,SAAQ,SAAS;IACjD,6DAA6D;IAC7D,KAAK,EAAE,gBAAgB,CAAC;IACxB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,kBAAkB,CAAC;IAC7B;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;;OAIG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,0EAA0E;IAC1E,gBAAgB,CAAC,EAAE,MAAM,SAAS,CAAC;IACnC,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,SAAS,CAAC;CACtB;AAED;;;GAGG;AACH,eAAO,MAAM,WAAW,mGAyFvB,CAAC"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type ReactNode } from 'react';
|
|
2
|
+
import { type GestureResponderEvent, type View as RNView } from 'react-native';
|
|
3
|
+
import type { MagicTabBarTheme, MagicTabIconProps } from './types';
|
|
4
|
+
export interface MagicTabItemProps {
|
|
5
|
+
/** Renders the icon. Provided automatically by `MagicTabs`. */
|
|
6
|
+
icon: (props: MagicTabIconProps) => ReactNode;
|
|
7
|
+
/** Optional label shown while the tab is active. */
|
|
8
|
+
label?: string;
|
|
9
|
+
/** Resolved theme. Provided automatically by `MagicTabs`. */
|
|
10
|
+
theme: MagicTabBarTheme;
|
|
11
|
+
/** @internal */
|
|
12
|
+
isFocused?: boolean;
|
|
13
|
+
/** @internal */
|
|
14
|
+
onPress?: (event: GestureResponderEvent) => void;
|
|
15
|
+
/** @internal */
|
|
16
|
+
onLongPress?: (event: GestureResponderEvent) => void;
|
|
17
|
+
/** @internal */
|
|
18
|
+
href?: string;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A single tab. Designed to be used as the `asChild` target of an
|
|
22
|
+
* Expo Router `<TabTrigger>`, which injects the focus state and press handlers.
|
|
23
|
+
*
|
|
24
|
+
* Each tab sizes to its content — just the icon when inactive, icon + label
|
|
25
|
+
* when active — so the active label is never clipped, on any screen width.
|
|
26
|
+
*/
|
|
27
|
+
export declare const MagicTabItem: import("react").ForwardRefExoticComponent<MagicTabItemProps & import("react").RefAttributes<RNView>>;
|
|
28
|
+
//# sourceMappingURL=MagicTabItem.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MagicTabItem.d.ts","sourceRoot":"","sources":["../../src/MagicTabItem.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAC9D,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,IAAI,IAAI,MAAM,EACpB,MAAM,cAAc,CAAC;AAQtB,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAUnE,MAAM,WAAW,iBAAiB;IAChC,+DAA+D;IAC/D,IAAI,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,SAAS,CAAC;IAC9C,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6DAA6D;IAC7D,KAAK,EAAE,gBAAgB,CAAC;IAGxB,gBAAgB;IAChB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB;IAChB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;IACjD,gBAAgB;IAChB,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE,qBAAqB,KAAK,IAAI,CAAC;IACrD,gBAAgB;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,sGAgDxB,CAAC"}
|