@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 CHANGED
@@ -1,18 +1,30 @@
1
- # @27appstudio/react-native-bottom-toolbar
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
- | | iOS 26 | iOS 18 | Android |
9
- |---|---|---|---|
10
- | 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"> |
11
- | 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"> |
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://github.com/27AppStudio) and used in production in [Splitify](https://splitify.cc).
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({ navigation }: NativeStackScreenProps<Params, 'Expense'>) {
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
- { id: 'share', systemImage: 'square.and.arrow.up', androidIcon: 'ic_share', onPress: share },
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 | Fields |
87
- |---|---|
88
- | Button (default) | `id` (required), `onPress`, `systemImage` (iOS SF Symbol), `androidIcon` (drawable name), `title` (used when there's no icon), `accessibilityLabel` (defaults to `title`), `disabled` |
89
- | `{ type: 'flexibleSpace' }` | iOS: pushes the items apart. Android: ignored. |
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)
@@ -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) ? {
@@ -1 +1 @@
1
- {"version":3,"names":["processColor","NativeBottomToolbar","isAvailable","buttons","show","items","options","filter","isButton","tintColor","map","item","accessibilityLabel","title","onPress","undefined","type","hide","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,OAAO,SAASC,IAAIA,CAACC,KAAoB,EAAEC,OAAuB,GAAG,CAAC,CAAC,EAAE;EACvE,IAAI,CAACL,mBAAmB,EAAE;IACxB;EACF;EACAE,OAAO,GAAGE,KAAK,CAACE,MAAM,CAACC,QAAQ,CAAC;EAChC,MAAMC,SAAS,GAAGT,YAAY,CAACM,OAAO,CAACG,SAAS,CAAC;EACjDR,mBAAmB,CAACG,IAAI,CACtBC,KAAK,CAACK,GAAG,CAAEC,IAAI,IACbH,QAAQ,CAACG,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,SAASQ,IAAIA,CAAA,EAAG;EACrBd,OAAO,GAAG,EAAE;EACZF,mBAAmB,EAAEgB,IAAI,CAAC,CAAC;AAC7B;;AAEA;AACA;AACA;AACA;AACA,OAAO,SAASC,gBAAgBA,CAACC,QAA8B,EAAE;EAC/D,MAAMC,YAAY,GAAGnB,mBAAmB,EAAEoB,WAAW,CAACF,QAAQ,CAAC;EAC/D,OAAO,MAAMC,YAAY,EAAEE,MAAM,CAAC,CAAC;AACrC;AAEA,SAASd,QAAQA,CAACG,IAAiB,EAAyB;EAC1D,OAAOA,IAAI,CAACK,IAAI,KAAKD,SAAS,IAAIJ,IAAI,CAACK,IAAI,KAAK,QAAQ;AAC1D;AAEAf,mBAAmB,EAAEoB,WAAW,CAAEE,EAAE,IAClCpB,OAAO,CAACqB,IAAI,CAAEC,MAAM,IAAKA,MAAM,CAACF,EAAE,KAAKA,EAAE,CAAC,EAAET,OAAO,GAAG,CACxD,CAAC","ignoreList":[]}
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;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAC,KAAK,EAAE,WAAW,EAAE,EAAE,OAAO,GAAE,cAAmB,QAmBtE;AAED,yBAAyB;AACzB,wBAAgB,IAAI,SAGnB;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,0BAG9D"}
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.0",
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://github.com/27AppStudio)",
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": true
157
+ "publish": false
158
158
  },
159
159
  "github": {
160
- "release": true
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(