capacitor-native-tabbar 0.0.1

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.
@@ -0,0 +1,17 @@
1
+ require 'json'
2
+
3
+ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4
+
5
+ Pod::Spec.new do |s|
6
+ s.name = 'CapacitorNativeTabbar'
7
+ s.version = package['version']
8
+ s.summary = package['description']
9
+ s.license = package['license']
10
+ s.homepage = package['repository']['url']
11
+ s.author = package['author']
12
+ s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
13
+ s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
14
+ s.ios.deployment_target = '15.0'
15
+ s.dependency 'Capacitor'
16
+ s.swift_version = '5.1'
17
+ end
package/Package.swift ADDED
@@ -0,0 +1,28 @@
1
+ // swift-tools-version: 5.9
2
+ import PackageDescription
3
+
4
+ let package = Package(
5
+ name: "CapacitorNativeTabbar",
6
+ platforms: [.iOS(.v15)],
7
+ products: [
8
+ .library(
9
+ name: "CapacitorNativeTabbar",
10
+ targets: ["CapTabbarPlugin"])
11
+ ],
12
+ dependencies: [
13
+ .package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "8.0.0")
14
+ ],
15
+ targets: [
16
+ .target(
17
+ name: "CapTabbarPlugin",
18
+ dependencies: [
19
+ .product(name: "Capacitor", package: "capacitor-swift-pm"),
20
+ .product(name: "Cordova", package: "capacitor-swift-pm")
21
+ ],
22
+ path: "ios/Sources/CapTabbarPlugin"),
23
+ .testTarget(
24
+ name: "CapTabbarPluginTests",
25
+ dependencies: ["CapTabbarPlugin"],
26
+ path: "ios/Tests/CapTabbarPluginTests")
27
+ ]
28
+ )
package/README.md ADDED
@@ -0,0 +1,262 @@
1
+ # Capacitor Native Tab Bar
2
+
3
+ [Русский](./README.ru.md)
4
+
5
+ <p align="center">
6
+ <img src="demo/demo.gif" alt="Demo" width="320" />
7
+ </p>
8
+
9
+ <p align="center">
10
+ Native tab bar for Capacitor apps — shows a bottom tab bar over the WebView on iOS and Android.
11
+ </p>
12
+
13
+ <p align="center">
14
+ <img src="https://img.shields.io/npm/v/capacitor-native-tabbar.svg" alt="npm version" />
15
+ <img src="https://img.shields.io/npm/dm/capacitor-native-tabbar.svg" alt="npm downloads" />
16
+ <img src="https://img.shields.io/npm/l/capacitor-native-tabbar.svg" alt="license" />
17
+ </p>
18
+
19
+ ---
20
+
21
+ ## Features
22
+
23
+ - **Native UI** — Uses `UITabBar` on iOS and `BottomNavigationView` on Android
24
+ - **Flexible icons** — Bundle assets (`{id}.png`, `{id}_active.png`) or base64
25
+ - **Custom colors** — Label colors for active/inactive states
26
+ - **Safe area** — Respects bottom safe area (notch, gesture bar)
27
+ - **Web fallback** — Works in browser for development
28
+
29
+ ## Installation
30
+
31
+ ```bash
32
+ npm install capacitor-native-tabbar
33
+ # or
34
+ yarn add capacitor-native-tabbar
35
+ ```
36
+
37
+ Sync native projects:
38
+
39
+ ```bash
40
+ npx cap sync
41
+ ```
42
+
43
+ ## Quick Start
44
+
45
+ ```typescript
46
+ import { CapTabbar } from 'capacitor-native-tabbar';
47
+
48
+ // Show tab bar
49
+ CapTabbar.show({
50
+ tabs: [
51
+ { id: 'home', label: 'Home' },
52
+ { id: 'search', label: 'Search' },
53
+ { id: 'profile', label: 'Profile' },
54
+ ],
55
+ selectedId: 'home',
56
+ label_color: '#000000',
57
+ label_color_active: '#007AFF',
58
+ });
59
+
60
+ // Listen for tab changes
61
+ CapTabbar.addListener('tabChange', (event) => {
62
+ console.log('Selected tab:', event.tabId);
63
+ });
64
+
65
+ // Get current state
66
+ const { visible, activeTabId } = await CapTabbar.getState();
67
+
68
+ // Hide / show
69
+ CapTabbar.hide();
70
+ CapTabbar.show({ tabs, selectedId: activeTabId });
71
+ ```
72
+
73
+ ## Icons
74
+
75
+ Two options (base64 takes priority):
76
+
77
+ ### Option 1: Base64
78
+
79
+ ```typescript
80
+ {
81
+ id: 'fav',
82
+ label: 'Favorites',
83
+ base64_icon: 'iVBORw0KGgo...',
84
+ base64_active_icon: 'iVBORw0KGgo...',
85
+ }
86
+ ```
87
+
88
+ ### Option 2: Native resources
89
+
90
+ Place icons in the native project by tab `id`:
91
+
92
+ | Tab (id) | Inactive | Active |
93
+ |----------|----------------|---------------------|
94
+ | home | `home.png` | `home_active.png` |
95
+
96
+ **Android:** `android/app/src/main/res/drawable/`
97
+ **iOS:** `ios/App/App/Assets.xcassets/` — Image Sets `home`, `home_active`
98
+
99
+ Supports PNG and vector drawable (`.xml`) on Android. Use underscores for spaces/dashes in filenames. Missing icons show a placeholder.
100
+
101
+ ## Label colors
102
+
103
+ ```typescript
104
+ CapTabbar.show({
105
+ tabs,
106
+ selectedId: 'home',
107
+ label_color: '#666666', // inactive
108
+ label_color_active: '#007AFF', // active
109
+ });
110
+ ```
111
+
112
+ ## API
113
+
114
+ <docgen-index>
115
+
116
+ * [`show(...)`](#show)
117
+ * [`hide()`](#hide)
118
+ * [`setSelectedTab(...)`](#setselectedtab)
119
+ * [`getState()`](#getstate)
120
+ * [`addListener('tabChange', ...)`](#addlistenertabchange-)
121
+ * [Interfaces](#interfaces)
122
+
123
+ </docgen-index>
124
+
125
+ <docgen-api>
126
+ <!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
127
+
128
+ ### show(...)
129
+
130
+ ```typescript
131
+ show(options: ShowOptions) => Promise<void>
132
+ ```
133
+
134
+ Show the native tab bar with the given configuration
135
+
136
+ | Param | Type |
137
+ | ------------- | --------------------------------------------------- |
138
+ | **`options`** | <code><a href="#showoptions">ShowOptions</a></code> |
139
+
140
+ --------------------
141
+
142
+
143
+ ### hide()
144
+
145
+ ```typescript
146
+ hide() => Promise<void>
147
+ ```
148
+
149
+ Hide the tab bar
150
+
151
+ --------------------
152
+
153
+
154
+ ### setSelectedTab(...)
155
+
156
+ ```typescript
157
+ setSelectedTab(options: SetSelectedTabOptions) => Promise<void>
158
+ ```
159
+
160
+ Programmatically set the selected tab
161
+
162
+ | Param | Type |
163
+ | ------------- | ----------------------------------------------------------------------- |
164
+ | **`options`** | <code><a href="#setselectedtaboptions">SetSelectedTabOptions</a></code> |
165
+
166
+ --------------------
167
+
168
+
169
+ ### getState()
170
+
171
+ ```typescript
172
+ getState() => Promise<GetStateResult>
173
+ ```
174
+
175
+ Get current state: visible and active tab id
176
+
177
+ **Returns:** <code>Promise&lt;<a href="#getstateresult">GetStateResult</a>&gt;</code>
178
+
179
+ --------------------
180
+
181
+
182
+ ### addListener('tabChange', ...)
183
+
184
+ ```typescript
185
+ addListener(eventName: 'tabChange', listenerFunc: (event: TabChangeEvent) => void) => Promise<{ remove: () => Promise<void>; }>
186
+ ```
187
+
188
+ Add listener for tab change events (when user taps a tab)
189
+
190
+ | Param | Type |
191
+ | ------------------ | ----------------------------------------------------------------------------- |
192
+ | **`eventName`** | <code>'tabChange'</code> |
193
+ | **`listenerFunc`** | <code>(event: <a href="#tabchangeevent">TabChangeEvent</a>) =&gt; void</code> |
194
+
195
+ **Returns:** <code>Promise&lt;{ remove: () =&gt; Promise&lt;void&gt;; }&gt;</code>
196
+
197
+ --------------------
198
+
199
+
200
+ ### Interfaces
201
+
202
+
203
+ #### ShowOptions
204
+
205
+ Icons: 2 variants (base64 has priority over bundle)
206
+
207
+ 1) **Base64** – if `base64_icon` / `base64_active_icon` are set, they are used.
208
+
209
+ 2) **Bundle assets** – if base64 not set, icons are loaded from native resources:
210
+
211
+ **Android** – `android/app/src/main/res/drawable/`:
212
+ - `{id}.png` or `{id}.xml` – inactive icon
213
+ - `{id}_active.png` or `{id}_active.xml` – active icon
214
+
215
+ **iOS** – Assets.xcassets: Image Set `{id}` and `{id}_active`.
216
+
217
+ If an icon is missing, a placeholder is shown.
218
+
219
+ | Prop | Type | Description |
220
+ | ------------------------ | ---------------------- | ------------------------------------------------------------------- |
221
+ | **`tabs`** | <code>TabItem[]</code> | Array of tab items to display |
222
+ | **`selectedId`** | <code>string</code> | ID of the initially selected tab |
223
+ | **`label_color`** | <code>string</code> | Label color for inactive tabs (hex, e.g. "#000000"). Default: black |
224
+ | **`label_color_active`** | <code>string</code> | Label color for selected tab (hex, e.g. "#007AFF"). Default: blue |
225
+
226
+
227
+ #### TabItem
228
+
229
+ | Prop | Type | Description |
230
+ | ------------------------ | ------------------- | -------------------------------------------------------------------------------- |
231
+ | **`id`** | <code>string</code> | Unique identifier for the tab. Used for bundle assets: {id}.png, {id}_active.png |
232
+ | **`label`** | <code>string</code> | Display label |
233
+ | **`base64_icon`** | <code>string</code> | Base64-encoded image for inactive state. If set, overrides bundle assets |
234
+ | **`base64_active_icon`** | <code>string</code> | Base64-encoded image for active/selected state. If set, overrides bundle assets |
235
+
236
+
237
+ #### SetSelectedTabOptions
238
+
239
+ | Prop | Type | Description |
240
+ | ----------- | ------------------- | ----------------------- |
241
+ | **`tabId`** | <code>string</code> | ID of the tab to select |
242
+
243
+
244
+ #### GetStateResult
245
+
246
+ | Prop | Type | Description |
247
+ | ----------------- | -------------------- | ------------------------------------------------- |
248
+ | **`visible`** | <code>boolean</code> | Whether the tab bar is currently shown |
249
+ | **`activeTabId`** | <code>string</code> | ID of the active/selected tab (empty when hidden) |
250
+
251
+
252
+ #### TabChangeEvent
253
+
254
+ | Prop | Type | Description |
255
+ | ----------- | ------------------- | ---------------------------- |
256
+ | **`tabId`** | <code>string</code> | ID of the newly selected tab |
257
+
258
+ </docgen-api>
259
+
260
+ ## License
261
+
262
+ MIT © Anton Seagull
package/README.ru.md ADDED
@@ -0,0 +1,168 @@
1
+ # Capacitor Native Tab Bar
2
+
3
+ [English](./README.md)
4
+
5
+ <p align="center">
6
+ <img src="demo/demo.gif" alt="Демо" width="320" />
7
+ </p>
8
+
9
+ <p align="center">
10
+ Нативный таб-бар для Capacitor — нижняя панель вкладок поверх WebView на iOS и Android.
11
+ </p>
12
+
13
+ <p align="center">
14
+ <img src="https://img.shields.io/npm/v/capacitor-native-tabbar.svg" alt="npm version" />
15
+ <img src="https://img.shields.io/npm/dm/capacitor-native-tabbar.svg" alt="npm downloads" />
16
+ <img src="https://img.shields.io/npm/l/capacitor-native-tabbar.svg" alt="license" />
17
+ </p>
18
+
19
+ ---
20
+
21
+ ## Возможности
22
+
23
+ - **Нативный UI** — `UITabBar` на iOS, `BottomNavigationView` на Android
24
+ - **Гибкие иконки** — из ресурсов (`{id}.png`, `{id}_active.png`) или base64
25
+ - **Цвета** — цвета лейбла для активного/неактивного состояния
26
+ - **Safe area** — учитывает нижнюю безопасную зону (вырез, жесты)
27
+ - **Web fallback** — работает в браузере при разработке
28
+
29
+ ## Установка
30
+
31
+ ```bash
32
+ npm install capacitor-native-tabbar
33
+ # или
34
+ yarn add capacitor-native-tabbar
35
+ ```
36
+
37
+ Синхронизация нативных проектов:
38
+
39
+ ```bash
40
+ npx cap sync
41
+ ```
42
+
43
+ ## Быстрый старт
44
+
45
+ ```typescript
46
+ import { CapTabbar } from 'capacitor-native-tabbar';
47
+
48
+ // Показать таб-бар
49
+ CapTabbar.show({
50
+ tabs: [
51
+ { id: 'home', label: 'Главная' },
52
+ { id: 'search', label: 'Поиск' },
53
+ { id: 'profile', label: 'Профиль' },
54
+ ],
55
+ selectedId: 'home',
56
+ label_color: '#000000',
57
+ label_color_active: '#007AFF',
58
+ });
59
+
60
+ // Слушать смену вкладки
61
+ CapTabbar.addListener('tabChange', (event) => {
62
+ console.log('Выбрана вкладка:', event.tabId);
63
+ });
64
+
65
+ // Получить текущее состояние
66
+ const { visible, activeTabId } = await CapTabbar.getState();
67
+
68
+ // Скрыть / показать
69
+ CapTabbar.hide();
70
+ CapTabbar.show({ tabs, selectedId: activeTabId });
71
+ ```
72
+
73
+ ## Иконки
74
+
75
+ Два варианта (base64 имеет приоритет):
76
+
77
+ ### Вариант 1: Base64
78
+
79
+ ```typescript
80
+ {
81
+ id: 'fav',
82
+ label: 'Избранное',
83
+ base64_icon: 'iVBORw0KGgo...',
84
+ base64_active_icon: 'iVBORw0KGgo...',
85
+ }
86
+ ```
87
+
88
+ ### Вариант 2: Ресурсы нативного проекта
89
+
90
+ Положите иконки по `id` таба:
91
+
92
+ | Таб (id) | Обычная | Активная |
93
+ |----------|-------------|------------------|
94
+ | home | `home.png` | `home_active.png`|
95
+
96
+ **Android:** `android/app/src/main/res/drawable/`
97
+ **iOS:** `ios/App/App/Assets.xcassets/` — Image Sets `home`, `home_active`
98
+
99
+ Поддерживаются PNG и vector drawable (`.xml`) на Android. Пробелы и дефисы в `id` заменяйте подчёркиванием в имени файла. При отсутствии иконки показывается заглушка.
100
+
101
+ ## Цвета лейбла
102
+
103
+ ```typescript
104
+ CapTabbar.show({
105
+ tabs,
106
+ selectedId: 'home',
107
+ label_color: '#666666', // неактивный
108
+ label_color_active: '#007AFF', // активный
109
+ });
110
+ ```
111
+
112
+ ## API
113
+
114
+ ### show(options)
115
+
116
+ Показать таб-бар с заданной конфигурацией.
117
+
118
+ ```typescript
119
+ show(options: ShowOptions) => Promise<void>
120
+ ```
121
+
122
+ ### hide()
123
+
124
+ Скрыть таб-бар.
125
+
126
+ ```typescript
127
+ hide() => Promise<void>
128
+ ```
129
+
130
+ ### setSelectedTab(options)
131
+
132
+ Программно переключить вкладку.
133
+
134
+ ```typescript
135
+ setSelectedTab(options: SetSelectedTabOptions) => Promise<void>
136
+ ```
137
+
138
+ ### getState()
139
+
140
+ Вернуть текущее состояние: виден ли таб-бар и id активной вкладки.
141
+
142
+ ```typescript
143
+ getState() => Promise<{ visible: boolean, activeTabId: string }>
144
+ ```
145
+
146
+ ### addListener('tabChange', listenerFunc)
147
+
148
+ Подписка на смену вкладки при нажатии пользователя.
149
+
150
+ ```typescript
151
+ addListener(eventName: 'tabChange', listenerFunc: (event: TabChangeEvent) => void) => Promise<{ remove: () => Promise<void> }>
152
+ ```
153
+
154
+ ## Интерфейсы
155
+
156
+ **ShowOptions:** `tabs`, `selectedId`, `label_color?`, `label_color_active?`
157
+
158
+ **TabItem:** `id`, `label`, `base64_icon?`, `base64_active_icon?`
159
+
160
+ **SetSelectedTabOptions:** `tabId`
161
+
162
+ **GetStateResult:** `visible`, `activeTabId`
163
+
164
+ **TabChangeEvent:** `tabId`
165
+
166
+ ## Лицензия
167
+
168
+ MIT © Anton Seagull
@@ -0,0 +1,68 @@
1
+ ext {
2
+ junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
3
+ androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.1'
4
+ androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.3.0'
5
+ androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.7.0'
6
+ androidxCoreKTXVersion = project.hasProperty('androidxCoreKTXVersion') ? rootProject.ext.androidxCoreKTXVersion : '1.17.0'
7
+ }
8
+
9
+ buildscript {
10
+ ext.kotlin_version = project.hasProperty("kotlin_version") ? rootProject.ext.kotlin_version : '2.2.20'
11
+ repositories {
12
+ google()
13
+ mavenCentral()
14
+ }
15
+ dependencies {
16
+ classpath 'com.android.tools.build:gradle:8.13.0'
17
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
18
+ }
19
+ }
20
+
21
+ apply plugin: 'com.android.library'
22
+ apply plugin: 'kotlin-android'
23
+
24
+ android {
25
+ namespace = "com.antonseagull.cap.tabbar"
26
+ compileSdk = project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 36
27
+ defaultConfig {
28
+ minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 24
29
+ targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 36
30
+ versionCode 1
31
+ versionName "1.0"
32
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
33
+ }
34
+ buildTypes {
35
+ release {
36
+ minifyEnabled false
37
+ proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
38
+ }
39
+ }
40
+ lintOptions {
41
+ abortOnError = false
42
+ }
43
+ compileOptions {
44
+ sourceCompatibility JavaVersion.VERSION_21
45
+ targetCompatibility JavaVersion.VERSION_21
46
+ }
47
+ }
48
+
49
+ kotlin {
50
+ jvmToolchain(21)
51
+ }
52
+
53
+ repositories {
54
+ google()
55
+ mavenCentral()
56
+ }
57
+
58
+
59
+ dependencies {
60
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
61
+ implementation project(':capacitor-android')
62
+ implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
63
+ implementation "androidx.core:core-ktx:$androidxCoreKTXVersion"
64
+ implementation "com.google.android.material:material:1.11.0"
65
+ testImplementation "junit:junit:$junitVersion"
66
+ androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
67
+ androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
68
+ }
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>