@27appstudio/react-native-bottom-toolbar 0.1.0 → 0.1.2
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/README.md +55 -14
- package/lib/module/index.js +8 -0
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/src/index.d.ts +4 -0
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/index.tsx +8 -0
package/README.md
CHANGED
|
@@ -1,18 +1,30 @@
|
|
|
1
|
-
|
|
1
|
+
<h1>
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/wordmark-on-dark.svg">
|
|
4
|
+
<img src="docs/images/wordmark.svg" width="568" alt="@27appstudio/react-native-bottom-toolbar">
|
|
5
|
+
</picture>
|
|
6
|
+
</h1>
|
|
7
|
+
|
|
8
|
+
<p>
|
|
9
|
+
<a href="https://www.npmjs.com/package/@27appstudio/react-native-bottom-toolbar"><img src="https://img.shields.io/npm/v/@27appstudio/react-native-bottom-toolbar?label=npm&labelColor=0B0B0F&color=3340FF" alt="npm version"></a>
|
|
10
|
+
<a href="https://github.com/27AppStudio/react-native-bottom-toolbar/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/27AppStudio/react-native-bottom-toolbar/ci.yml?branch=main&label=ci&labelColor=0B0B0F" alt="CI status"></a>
|
|
11
|
+
<a href="#installation"><img src="https://img.shields.io/badge/platforms-iOS%20%7C%20Android-3340FF?labelColor=0B0B0F" alt="Platforms: iOS and Android"></a>
|
|
12
|
+
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-3340FF?labelColor=0B0B0F" alt="MIT license"></a>
|
|
13
|
+
</p>
|
|
2
14
|
|
|
3
15
|
The platform's own bottom toolbar for React Native screens:
|
|
4
16
|
|
|
5
17
|
- **iOS**: UIKit's navigation-controller toolbar, so you get what the system draws. On iOS 26 that's Liquid Glass (a lone item becomes a glass circle, like the bin in Photos), and earlier versions get the classic toolbar. Your app follows each iOS redesign without changes.
|
|
6
18
|
- **Android**: Material 3 components. One button shows as a FAB; two or more show as the M3 Expressive floating toolbar. Both sit above the navigation bar.
|
|
7
19
|
|
|
8
|
-
|
|
|
9
|
-
|
|
10
|
-
| Several items
|
|
11
|
-
| One item, red `tintColor` | <img src="docs/images/ios26-single.png" width="220" alt="iOS 26: a red bin in a glass circle">
|
|
20
|
+
| | iOS 26 | iOS 18 | Android |
|
|
21
|
+
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------ |
|
|
22
|
+
| Several items | <img src="docs/images/ios26-several.png" width="220" alt="iOS 26: a glass plus button on the left, pencil and share grouped in a glass capsule on the right"> | <img src="docs/images/ios18-several.png" width="220" alt="iOS 18: plus on the left, pencil and share on the right of the classic toolbar"> | <img src="docs/images/android-several.png" width="220" alt="Android: plus, pencil and share in a Material 3 floating toolbar"> |
|
|
23
|
+
| One item, red `tintColor` | <img src="docs/images/ios26-single.png" width="220" alt="iOS 26: a red bin in a glass circle"> | <img src="docs/images/ios18-single.png" width="220" alt="iOS 18: a red bin at the trailing edge of the toolbar"> | <img src="docs/images/android-single.png" width="220" alt="Android: a Material 3 FAB with a red bin icon"> |
|
|
12
24
|
|
|
13
25
|
It's a TurboModule with no views of its own in JS, no Expo modules, and no config plugin.
|
|
14
26
|
|
|
15
|
-
Made by [27AppStudio](https://
|
|
27
|
+
Made by [27AppStudio](https://27appstudio.com) and used in production in [Splitify](https://splitify.cc).
|
|
16
28
|
|
|
17
29
|
## When to use something else
|
|
18
30
|
|
|
@@ -42,7 +54,9 @@ Requirements:
|
|
|
42
54
|
```tsx
|
|
43
55
|
import { useBottomToolbar } from '@27appstudio/react-native-bottom-toolbar/react-navigation';
|
|
44
56
|
|
|
45
|
-
function ExpenseScreen({
|
|
57
|
+
function ExpenseScreen({
|
|
58
|
+
navigation,
|
|
59
|
+
}: NativeStackScreenProps<Params, 'Expense'>) {
|
|
46
60
|
useBottomToolbar(navigation, [
|
|
47
61
|
{
|
|
48
62
|
id: 'delete',
|
|
@@ -67,7 +81,12 @@ show(
|
|
|
67
81
|
[
|
|
68
82
|
{ id: 'add', systemImage: 'plus', androidIcon: 'ic_add', onPress: add },
|
|
69
83
|
{ type: 'flexibleSpace' },
|
|
70
|
-
{
|
|
84
|
+
{
|
|
85
|
+
id: 'share',
|
|
86
|
+
systemImage: 'square.and.arrow.up',
|
|
87
|
+
androidIcon: 'ic_share',
|
|
88
|
+
onPress: share,
|
|
89
|
+
},
|
|
71
90
|
],
|
|
72
91
|
{ tintColor: '#0A7D6E' }
|
|
73
92
|
);
|
|
@@ -83,13 +102,13 @@ On iOS, `show` targets the visible navigation controller's top screen, and waits
|
|
|
83
102
|
|
|
84
103
|
Replaces the items of any toolbar already shown.
|
|
85
104
|
|
|
86
|
-
| Item
|
|
87
|
-
|
|
88
|
-
| Button (default)
|
|
89
|
-
| `{ type: 'flexibleSpace' }`
|
|
90
|
-
| `{ type: 'fixedSpace', width? }` | iOS: a fixed gap; on iOS 26 it also splits glass groups. Android: ignored.
|
|
105
|
+
| Item | Fields |
|
|
106
|
+
| -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
107
|
+
| Button (default) | `id` (required), `onPress`, `systemImage` (iOS SF Symbol), `androidIcon` (drawable name), `title` (used when there's no icon), `accessibilityLabel` (defaults to `title`), `disabled` |
|
|
108
|
+
| `{ type: 'flexibleSpace' }` | iOS: pushes the items apart. Android: ignored. |
|
|
109
|
+
| `{ type: 'fixedSpace', width? }` | iOS: a fixed gap; on iOS 26 it also splits glass groups. Android: ignored. |
|
|
91
110
|
|
|
92
|
-
When `items` contains no space, iOS puts the buttons at the trailing edge.
|
|
111
|
+
When `items` contains no space, iOS puts the buttons at the trailing edge. When it contains no button at all (`[]` or spacers only), `show` hides the toolbar, as `hide()` does, so a screen can pass an empty array while it has nothing to offer.
|
|
93
112
|
|
|
94
113
|
`options.tintColor` sets the icon and title color. iOS defaults to the navigation bar's tint (matching the header buttons); Android defaults to the Material 3 theme.
|
|
95
114
|
|
|
@@ -122,3 +141,25 @@ Imported from `/react-navigation`. `items` and `options` are read each time the
|
|
|
122
141
|
## License
|
|
123
142
|
|
|
124
143
|
MIT
|
|
144
|
+
|
|
145
|
+
## Made by 27AppStudio
|
|
146
|
+
|
|
147
|
+
<p>
|
|
148
|
+
<a href="https://27appstudio.com">
|
|
149
|
+
<picture>
|
|
150
|
+
<source media="(prefers-color-scheme: dark)" srcset="docs/images/27appstudio-on-dark.svg">
|
|
151
|
+
<img src="docs/images/27appstudio.svg" width="180" alt="27AppStudio">
|
|
152
|
+
</picture>
|
|
153
|
+
</a>
|
|
154
|
+
</p>
|
|
155
|
+
|
|
156
|
+
An independent French mobile app studio. We design, build and launch iPhone and Android apps, and open-source the native pieces we make along the way, most of them for [Splitify](https://splitify.cc).
|
|
157
|
+
|
|
158
|
+
| Library | What it does |
|
|
159
|
+
| ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- |
|
|
160
|
+
| [react-native-alert](https://github.com/27AppStudio/react-native-alert) | Native alerts and text prompts in your app's colors |
|
|
161
|
+
| [react-native-bottom-toolbar](https://github.com/27AppStudio/react-native-bottom-toolbar) | The platform's own bottom toolbar: UIKit on iOS, Material 3 on Android |
|
|
162
|
+
| [react-native-emoji-picker](https://github.com/27AppStudio/react-native-emoji-picker) | A native emoji picker: iOS popover, Material 3 bottom sheet |
|
|
163
|
+
| [rn-ship](https://github.com/27AppStudio/rn-ship) | EAS-style release pipeline for bare React Native apps |
|
|
164
|
+
|
|
165
|
+
Need an app built, or a hand with a React Native one? [27appstudio.com](https://27appstudio.com)
|
package/lib/module/index.js
CHANGED
|
@@ -16,11 +16,19 @@ let buttons = [];
|
|
|
16
16
|
* on top.
|
|
17
17
|
* - Android: a Material 3 FAB for one button, a floating toolbar for more,
|
|
18
18
|
* above the navigation bar. Spacers are ignored.
|
|
19
|
+
*
|
|
20
|
+
* Without any button (an empty array, or spacers only) it hides the toolbar, as
|
|
21
|
+
* `hide` does: on iOS an empty bar would still take the bottom band's touches and
|
|
22
|
+
* add its height to the scroll views' insets.
|
|
19
23
|
*/
|
|
20
24
|
export function show(items, options = {}) {
|
|
21
25
|
if (!NativeBottomToolbar) {
|
|
22
26
|
return;
|
|
23
27
|
}
|
|
28
|
+
if (!items.some(isButton)) {
|
|
29
|
+
hide();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
24
32
|
buttons = items.filter(isButton);
|
|
25
33
|
const tintColor = processColor(options.tintColor);
|
|
26
34
|
NativeBottomToolbar.show(items.map(item => isButton(item) ? {
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["processColor","NativeBottomToolbar","isAvailable","buttons","show","items","options","
|
|
1
|
+
{"version":3,"names":["processColor","NativeBottomToolbar","isAvailable","buttons","show","items","options","some","isButton","hide","filter","tintColor","map","item","accessibilityLabel","title","onPress","undefined","type","addPressListener","listener","subscription","onItemPress","remove","id","find","button"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAEA,SAASA,YAAY,QAAQ,cAAc;AAE3C,OAAOC,mBAAmB,MAAM,0BAAuB;AASvD;AACA,OAAO,MAAMC,WAAW,GAAGD,mBAAmB,IAAI,IAAI;AAEtD,IAAIE,OAAwB,GAAG,EAAE;;AAEjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,IAAIA,CAACC,KAAoB,EAAEC,OAAuB,GAAG,CAAC,CAAC,EAAE;EACvE,IAAI,CAACL,mBAAmB,EAAE;IACxB;EACF;EACA,IAAI,CAACI,KAAK,CAACE,IAAI,CAACC,QAAQ,CAAC,EAAE;IACzBC,IAAI,CAAC,CAAC;IACN;EACF;EACAN,OAAO,GAAGE,KAAK,CAACK,MAAM,CAACF,QAAQ,CAAC;EAChC,MAAMG,SAAS,GAAGX,YAAY,CAACM,OAAO,CAACK,SAAS,CAAC;EACjDV,mBAAmB,CAACG,IAAI,CACtBC,KAAK,CAACO,GAAG,CAAEC,IAAI,IACbL,QAAQ,CAACK,IAAI,CAAC,GACV;IACE,GAAGA,IAAI;IACPC,kBAAkB,EAAED,IAAI,CAACC,kBAAkB,IAAID,IAAI,CAACE,KAAK;IACzDC,OAAO,EAAEC,SAAS;IAClBC,IAAI,EAAE;EACR,CAAC,GACDL,IACN,CAAC,EACD,OAAOF,SAAS,KAAK,QAAQ,GAAG;IAAEA;EAAU,CAAC,GAAG,CAAC,CACnD,CAAC;AACH;;AAEA;AACA,OAAO,SAASF,IAAIA,CAAA,EAAG;EACrBN,OAAO,GAAG,EAAE;EACZF,mBAAmB,EAAEQ,IAAI,CAAC,CAAC;AAC7B;;AAEA;AACA;AACA;AACA;AACA,OAAO,SAASU,gBAAgBA,CAACC,QAA8B,EAAE;EAC/D,MAAMC,YAAY,GAAGpB,mBAAmB,EAAEqB,WAAW,CAACF,QAAQ,CAAC;EAC/D,OAAO,MAAMC,YAAY,EAAEE,MAAM,CAAC,CAAC;AACrC;AAEA,SAASf,QAAQA,CAACK,IAAiB,EAAyB;EAC1D,OAAOA,IAAI,CAACK,IAAI,KAAKD,SAAS,IAAIJ,IAAI,CAACK,IAAI,KAAK,QAAQ;AAC1D;AAEAjB,mBAAmB,EAAEqB,WAAW,CAAEE,EAAE,IAClCrB,OAAO,CAACsB,IAAI,CAAEC,MAAM,IAAKA,MAAM,CAACF,EAAE,KAAKA,EAAE,CAAC,EAAER,OAAO,GAAG,CACxD,CAAC","ignoreList":[]}
|
|
@@ -12,6 +12,10 @@ export declare const isAvailable: boolean;
|
|
|
12
12
|
* on top.
|
|
13
13
|
* - Android: a Material 3 FAB for one button, a floating toolbar for more,
|
|
14
14
|
* above the navigation bar. Spacers are ignored.
|
|
15
|
+
*
|
|
16
|
+
* Without any button (an empty array, or spacers only) it hides the toolbar, as
|
|
17
|
+
* `hide` does: on iOS an empty bar would still take the bottom band's touches and
|
|
18
|
+
* add its height to the scroll views' insets.
|
|
15
19
|
*/
|
|
16
20
|
export declare function show(items: ToolbarItem[], options?: ToolbarOptions): void;
|
|
17
21
|
/** Hides the toolbar. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,WAAW,EAAE,cAAc,EAAE,MAAM,YAAS,CAAC;AAM1E,YAAY,EACV,aAAa,EACb,WAAW,EACX,cAAc,EACd,YAAY,GACb,MAAM,YAAS,CAAC;AAEjB,iFAAiF;AACjF,eAAO,MAAM,WAAW,SAA8B,CAAC;AAIvD
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAiB,WAAW,EAAE,cAAc,EAAE,MAAM,YAAS,CAAC;AAM1E,YAAY,EACV,aAAa,EACb,WAAW,EACX,cAAc,EACd,YAAY,GACb,MAAM,YAAS,CAAC;AAEjB,iFAAiF;AACjF,eAAO,MAAM,WAAW,SAA8B,CAAC;AAIvD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,OAAO,GAAE,cAAmB,QAuBtE;AAED,yBAAyB;AACzB,wBAAgB,IAAI,SAGnB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,0BAG9D"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@27appstudio/react-native-bottom-toolbar",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Native bottom toolbar for React Native: UIKit's toolbar on iOS (Liquid Glass on iOS 26) and a Material 3 floating toolbar on Android.",
|
|
5
5
|
"main": "./lib/module/index.js",
|
|
6
6
|
"types": "./lib/typescript/src/index.d.ts",
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
"type": "git",
|
|
58
58
|
"url": "git+https://github.com/27AppStudio/react-native-bottom-toolbar.git"
|
|
59
59
|
},
|
|
60
|
-
"author": "27AppStudio <hello@27appstudio.com> (https://
|
|
60
|
+
"author": "27AppStudio <hello@27appstudio.com> (https://27appstudio.com)",
|
|
61
61
|
"license": "MIT",
|
|
62
62
|
"bugs": {
|
|
63
63
|
"url": "https://github.com/27AppStudio/react-native-bottom-toolbar/issues"
|
|
@@ -154,10 +154,10 @@
|
|
|
154
154
|
"tagName": "v${version}"
|
|
155
155
|
},
|
|
156
156
|
"npm": {
|
|
157
|
-
"publish":
|
|
157
|
+
"publish": false
|
|
158
158
|
},
|
|
159
159
|
"github": {
|
|
160
|
-
"release":
|
|
160
|
+
"release": false
|
|
161
161
|
},
|
|
162
162
|
"plugins": {
|
|
163
163
|
"@release-it/conventional-changelog": {
|
package/src/index.tsx
CHANGED
|
@@ -26,11 +26,19 @@ let buttons: ToolbarButton[] = [];
|
|
|
26
26
|
* on top.
|
|
27
27
|
* - Android: a Material 3 FAB for one button, a floating toolbar for more,
|
|
28
28
|
* above the navigation bar. Spacers are ignored.
|
|
29
|
+
*
|
|
30
|
+
* Without any button (an empty array, or spacers only) it hides the toolbar, as
|
|
31
|
+
* `hide` does: on iOS an empty bar would still take the bottom band's touches and
|
|
32
|
+
* add its height to the scroll views' insets.
|
|
29
33
|
*/
|
|
30
34
|
export function show(items: ToolbarItem[], options: ToolbarOptions = {}) {
|
|
31
35
|
if (!NativeBottomToolbar) {
|
|
32
36
|
return;
|
|
33
37
|
}
|
|
38
|
+
if (!items.some(isButton)) {
|
|
39
|
+
hide();
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
34
42
|
buttons = items.filter(isButton);
|
|
35
43
|
const tintColor = processColor(options.tintColor);
|
|
36
44
|
NativeBottomToolbar.show(
|