@capgo/capacitor-native-navigation 8.0.9 → 8.0.11

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
@@ -324,7 +324,7 @@ Inline SVG supports the icon-focused subset used by common sets such as Lucide a
324
324
 
325
325
  ## Platform Notes
326
326
 
327
- - iOS uses UIKit `UINavigationBar` and `UITabBar`. iOS 26+ leaves bar backgrounds to Apple's system Liquid Glass; earlier versions use native translucent/material fallback styling.
327
+ - iOS uses UIKit `UINavigationBar` and `UITabBar`. iOS 26+ hosts the tabbar in a real `UITabBarController` so Apple owns the system Liquid Glass background; earlier versions use native translucent/material fallback styling.
328
328
  - Android uses an AppCompat `Toolbar` and a floating native tab capsule with edge-to-edge placement.
329
329
  - Web fallback does not draw native bars; it mirrors inset variables and events for development.
330
330
 
@@ -678,22 +678,23 @@ because icons are rendered by native UI.
678
678
 
679
679
  Native tabbar state.
680
680
 
681
- | Prop | Type | Description |
682
- | -------------------------- | --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
683
- | **`hidden`** | <code>boolean</code> | Hide the native tabbar. |
684
- | **`tabs`** | <code>NativeNavigationTab[]</code> | Tab definitions. |
685
- | **`selectedId`** | <code>string</code> | Currently selected tab id. |
686
- | **`labels`** | <code>boolean</code> | Show text labels. Defaults to `true`. |
687
- | **`labelVisibilityMode`** | <code><a href="#nativenavigationtablabelvisibilitymode">NativeNavigationTabLabelVisibilityMode</a></code> | Native label visibility mode. Overrides `labels` when provided. |
688
- | **`icons`** | <code>boolean</code> | Show icons. Defaults to `true`. |
689
- | **`colors`** | <code><a href="#nativenavigationcolors">NativeNavigationColors</a></code> | Tabbar color hints. |
690
- | **`blurEffect`** | <code><a href="#nativenavigationblureffect">NativeNavigationBlurEffect</a></code> | iOS blur/material effect for the tabbar background when glass is not available. |
691
- | **`disableIndicator`** | <code>boolean</code> | Disable the Android active tab indicator. |
692
- | **`indicatorColor`** | <code>string</code> | Active tab indicator color on Android. `colors.indicator` is also supported. |
693
- | **`rippleColor`** | <code>string</code> | Tab press ripple color on Android. `colors.ripple` is also supported. |
694
- | **`badgeBackgroundColor`** | <code>string</code> | Badge background color. `colors.badgeBackground` is also supported. |
695
- | **`badgeTextColor`** | <code>string</code> | Badge text color. `colors.badgeText` is also supported. |
696
- | **`animated`** | <code>boolean</code> | Animate native tabbar changes. |
681
+ | Prop | Type | Description |
682
+ | ------------------------------------ | --------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
683
+ | **`hidden`** | <code>boolean</code> | Hide the native tabbar. |
684
+ | **`tabs`** | <code>NativeNavigationTab[]</code> | Tab definitions. |
685
+ | **`selectedId`** | <code>string</code> | Currently selected tab id. |
686
+ | **`labels`** | <code>boolean</code> | Show text labels. Defaults to `true`. |
687
+ | **`labelVisibilityMode`** | <code><a href="#nativenavigationtablabelvisibilitymode">NativeNavigationTabLabelVisibilityMode</a></code> | Native label visibility mode. Overrides `labels` when provided. |
688
+ | **`icons`** | <code>boolean</code> | Show icons. Defaults to `true`. |
689
+ | **`colors`** | <code><a href="#nativenavigationcolors">NativeNavigationColors</a></code> | Tabbar color hints. |
690
+ | **`blurEffect`** | <code><a href="#nativenavigationblureffect">NativeNavigationBlurEffect</a></code> | iOS blur/material effect for the tabbar background when glass is not available. |
691
+ | **`disableTransparentOnScrollEdge`** | <code>boolean</code> | Keep the iOS scroll-edge tabbar appearance from becoming transparent. Mirrors Expo Router native tabs' `disableTransparentOnScrollEdge` option. Defaults to `false`. |
692
+ | **`disableIndicator`** | <code>boolean</code> | Disable the Android active tab indicator. |
693
+ | **`indicatorColor`** | <code>string</code> | Active tab indicator color on Android. `colors.indicator` is also supported. |
694
+ | **`rippleColor`** | <code>string</code> | Tab press ripple color on Android. `colors.ripple` is also supported. |
695
+ | **`badgeBackgroundColor`** | <code>string</code> | Badge background color. `colors.badgeBackground` is also supported. |
696
+ | **`badgeTextColor`** | <code>string</code> | Badge text color. `colors.badgeText` is also supported. |
697
+ | **`animated`** | <code>boolean</code> | Animate native tabbar changes. |
697
698
 
698
699
 
699
700
  #### NativeNavigationTab
package/dist/docs.json CHANGED
@@ -738,6 +738,13 @@
738
738
  ],
739
739
  "type": "NativeNavigationBlurEffect"
740
740
  },
741
+ {
742
+ "name": "disableTransparentOnScrollEdge",
743
+ "tags": [],
744
+ "docs": "Keep the iOS scroll-edge tabbar appearance from becoming transparent.\nMirrors Expo Router native tabs' `disableTransparentOnScrollEdge` option.\nDefaults to `false`.",
745
+ "complexTypes": [],
746
+ "type": "boolean | undefined"
747
+ },
741
748
  {
742
749
  "name": "disableIndicator",
743
750
  "tags": [],
@@ -311,6 +311,12 @@ export interface NativeNavigationTabbarOptions {
311
311
  * available.
312
312
  */
313
313
  blurEffect?: NativeNavigationBlurEffect;
314
+ /**
315
+ * Keep the iOS scroll-edge tabbar appearance from becoming transparent.
316
+ * Mirrors Expo Router native tabs' `disableTransparentOnScrollEdge` option.
317
+ * Defaults to `false`.
318
+ */
319
+ disableTransparentOnScrollEdge?: boolean;
314
320
  /**
315
321
  * Disable the Android active tab indicator.
316
322
  */
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\n\n/**\n * Platform rendering preference for the native bars.\n */\nexport type NativeNavigationPlatformStyle = 'auto' | 'ios' | 'android';\n\n/**\n * How the plugin exposes native bar sizes to web content.\n */\nexport type NativeNavigationContentInsetMode = 'css' | 'none';\n\n/**\n * Navigation animation direction.\n */\nexport type NativeNavigationTransitionDirection = 'forward' | 'back' | 'root' | 'tab' | 'zoom' | 'none';\n\n/**\n * Native material/blur effect preference.\n */\nexport type NativeNavigationBlurEffect =\n | 'none'\n | 'systemDefault'\n | 'extraLight'\n | 'light'\n | 'dark'\n | 'regular'\n | 'prominent'\n | 'systemUltraThinMaterial'\n | 'systemThinMaterial'\n | 'systemMaterial'\n | 'systemThickMaterial'\n | 'systemChromeMaterial'\n | 'systemUltraThinMaterialLight'\n | 'systemThinMaterialLight'\n | 'systemMaterialLight'\n | 'systemThickMaterialLight'\n | 'systemChromeMaterialLight'\n | 'systemUltraThinMaterialDark'\n | 'systemThinMaterialDark'\n | 'systemMaterialDark'\n | 'systemThickMaterialDark'\n | 'systemChromeMaterialDark';\n\n/**\n * Native tab label visibility behavior.\n */\nexport type NativeNavigationTabLabelVisibilityMode = 'auto' | 'selected' | 'labeled' | 'unlabeled';\n\n/**\n * A rectangle in WebView viewport coordinates, expressed in native points/dp.\n */\nexport interface NativeNavigationRect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/**\n * A serializable icon descriptor. Framework nodes are intentionally not accepted\n * because icons are rendered by native UI.\n */\nexport interface NativeNavigationIcon {\n /**\n * Cross-platform asset path or URL fallback.\n */\n src?: string;\n\n /**\n * Cross-platform inline SVG markup. The native renderers support common icon\n * shapes such as path, line, polyline, polygon, circle, and rect. SVG icons\n * are rendered as template images by default so native tint colors still\n * apply.\n */\n svg?: string;\n\n /**\n * Preferred rendered icon width in native points/dp. Defaults to `24`.\n */\n width?: number;\n\n /**\n * Preferred rendered icon height in native points/dp. Defaults to `24`.\n */\n height?: number;\n\n /**\n * When `true`, native tint colors are applied to the rendered SVG/image.\n * Defaults to `true`.\n */\n template?: boolean;\n\n /**\n * iOS-specific SF Symbol, bundled image name, or inline SVG.\n */\n ios?: {\n /**\n * SF Symbol name, for example `house.fill`.\n */\n sfSymbol?: string;\n\n /**\n * Bundled image name from the app asset catalog.\n */\n image?: string;\n\n /**\n * iOS-specific inline SVG markup.\n */\n svg?: string;\n };\n\n /**\n * Android-specific drawable resource, asset name, or inline SVG.\n */\n android?: {\n /**\n * Drawable resource name without the `R.drawable.` prefix.\n */\n resource?: string;\n\n /**\n * Bundled image asset name.\n */\n image?: string;\n\n /**\n * Android-specific inline SVG markup.\n */\n svg?: string;\n };\n}\n\n/**\n * Native bar colors. Use CSS-style hex strings (`#RRGGBB` or `#AARRGGBB`).\n */\nexport interface NativeNavigationColors {\n /**\n * When `true`, Android 12+ derives unspecified bar colors from Material You\n * system palettes. Explicit color fields still win.\n */\n dynamic?: boolean;\n\n /**\n * Tint color for active buttons/items.\n */\n tint?: string;\n\n /**\n * Color for inactive tab items.\n */\n inactiveTint?: string;\n\n /**\n * Optional background tint. Ignored on iOS 26+ so UIKit can preserve the\n * system Liquid Glass navigation appearance.\n */\n background?: string;\n\n /**\n * Title and label text color where the native platform supports it.\n */\n foreground?: string;\n\n /**\n * Badge background color for native tab badges.\n */\n badgeBackground?: string;\n\n /**\n * Badge text color for native tab badges.\n */\n badgeText?: string;\n\n /**\n * Active tab indicator color on Android.\n */\n indicator?: string;\n\n /**\n * Tab press ripple color on Android.\n */\n ripple?: string;\n}\n\n/**\n * Global plugin configuration.\n */\nexport interface NativeNavigationConfigureOptions {\n /**\n * Enables or disables the native chrome host.\n */\n enabled?: boolean;\n\n /**\n * Native style preference. `auto` uses the current platform.\n */\n platformStyle?: NativeNavigationPlatformStyle;\n\n /**\n * When `css`, the plugin writes CSS variables on `document.documentElement`.\n */\n contentInsetMode?: NativeNavigationContentInsetMode;\n\n /**\n * Default native transition duration in milliseconds.\n */\n animationDuration?: number;\n\n /**\n * Shared color hints for native bars.\n */\n colors?: NativeNavigationColors;\n}\n\n/**\n * A button shown in the native navbar.\n */\nexport interface NativeNavigationBarButton {\n /**\n * Stable id returned in `navbarItemTap`.\n */\n id: string;\n\n /**\n * Visible text label.\n */\n title?: string;\n\n /**\n * Native icon descriptor.\n */\n icon?: NativeNavigationIcon;\n\n /**\n * Whether the action is enabled. Defaults to `true`.\n */\n enabled?: boolean;\n}\n\n/**\n * Native back button configuration.\n */\nexport interface NativeNavigationBackButton {\n /**\n * Show the native back affordance.\n */\n visible?: boolean;\n\n /**\n * Optional back title.\n */\n title?: string;\n}\n\n/**\n * Native navbar state.\n */\nexport interface NativeNavigationNavbarOptions {\n /**\n * Hide the native navbar.\n */\n hidden?: boolean;\n\n /**\n * Main title.\n */\n title?: string;\n\n /**\n * Secondary title where supported by the platform.\n */\n subtitle?: string;\n\n /**\n * Prefer a large iOS title style.\n */\n large?: boolean;\n\n /**\n * Prefer transparent/scroll-edge style.\n */\n transparent?: boolean;\n\n /**\n * iOS blur/material effect for the navbar background when glass is not\n * available. Defaults to `systemChromeMaterial` for transparent bars.\n */\n blurEffect?: NativeNavigationBlurEffect;\n\n /**\n * Back button state.\n */\n backButton?: NativeNavigationBackButton;\n\n /**\n * Left-side action buttons.\n */\n leftItems?: NativeNavigationBarButton[];\n\n /**\n * Right-side action buttons.\n */\n rightItems?: NativeNavigationBarButton[];\n\n /**\n * Navbar color hints.\n */\n colors?: NativeNavigationColors;\n\n /**\n * Animate native navbar changes.\n */\n animated?: boolean;\n}\n\n/**\n * A native tab item.\n */\nexport interface NativeNavigationTab {\n /**\n * Stable tab id returned in `tabSelect`.\n */\n id: string;\n\n /**\n * Visible tab label.\n */\n title?: string;\n\n /**\n * Native icon descriptor.\n */\n icon?: NativeNavigationIcon;\n\n /**\n * Optional selected-state icon.\n */\n selectedIcon?: NativeNavigationIcon;\n\n /**\n * Optional badge. Numeric badges are supported on both platforms; text badge\n * support depends on platform capabilities.\n */\n badge?: string | number;\n\n /**\n * Whether the tab is enabled. Defaults to `true`.\n */\n enabled?: boolean;\n}\n\n/**\n * Native tabbar state.\n */\nexport interface NativeNavigationTabbarOptions {\n /**\n * Hide the native tabbar.\n */\n hidden?: boolean;\n\n /**\n * Tab definitions.\n */\n tabs?: NativeNavigationTab[];\n\n /**\n * Currently selected tab id.\n */\n selectedId?: string;\n\n /**\n * Show text labels. Defaults to `true`.\n */\n labels?: boolean;\n\n /**\n * Native label visibility mode. Overrides `labels` when provided.\n */\n labelVisibilityMode?: NativeNavigationTabLabelVisibilityMode;\n\n /**\n * Show icons. Defaults to `true`.\n */\n icons?: boolean;\n\n /**\n * Tabbar color hints.\n */\n colors?: NativeNavigationColors;\n\n /**\n * iOS blur/material effect for the tabbar background when glass is not\n * available.\n */\n blurEffect?: NativeNavigationBlurEffect;\n\n /**\n * Disable the Android active tab indicator.\n */\n disableIndicator?: boolean;\n\n /**\n * Active tab indicator color on Android. `colors.indicator` is also\n * supported.\n */\n indicatorColor?: string;\n\n /**\n * Tab press ripple color on Android. `colors.ripple` is also supported.\n */\n rippleColor?: string;\n\n /**\n * Badge background color. `colors.badgeBackground` is also supported.\n */\n badgeBackgroundColor?: string;\n\n /**\n * Badge text color. `colors.badgeText` is also supported.\n */\n badgeTextColor?: string;\n\n /**\n * Animate native tabbar changes.\n */\n animated?: boolean;\n}\n\n/**\n * Insets exposed to web content.\n */\nexport interface NativeNavigationInsets {\n top: number;\n right: number;\n bottom: number;\n left: number;\n navbarHeight: number;\n tabbarHeight: number;\n}\n\n/**\n * Returned by methods that may change safe content bounds.\n */\nexport interface NativeNavigationInsetsResult {\n insets: NativeNavigationInsets;\n}\n\n/**\n * Begin a native transition transaction before JS changes route content.\n */\nexport interface NativeNavigationBeginTransitionOptions {\n id?: string;\n direction?: NativeNavigationTransitionDirection;\n duration?: number;\n /**\n * Source rectangle for `zoom` transitions. Use viewport coordinates such as\n * those returned by `Element.getBoundingClientRect()`.\n */\n sourceRect?: NativeNavigationRect;\n /**\n * Destination rectangle for shared-element-style `zoom` transitions.\n */\n targetRect?: NativeNavigationRect;\n /**\n * Corner radius used while animating a `zoom` transition.\n */\n cornerRadius?: number;\n}\n\n/**\n * Finish a native transition transaction after JS has changed route content.\n */\nexport interface NativeNavigationFinishTransitionOptions {\n id?: string;\n direction?: NativeNavigationTransitionDirection;\n duration?: number;\n /**\n * Source rectangle for `zoom` transitions when no active source was recorded.\n */\n sourceRect?: NativeNavigationRect;\n /**\n * Destination rectangle for shared-element-style `zoom` transitions.\n */\n targetRect?: NativeNavigationRect;\n /**\n * Corner radius used while animating a `zoom` transition.\n */\n cornerRadius?: number;\n}\n\n/**\n * Native transition result.\n */\nexport interface NativeNavigationTransitionResult {\n id: string;\n direction: NativeNavigationTransitionDirection;\n duration: number;\n}\n\n/**\n * Plugin version payload.\n */\nexport interface PluginVersionResult {\n /**\n * Version identifier returned by the platform implementation.\n */\n version: string;\n}\n\nexport interface NativeNavigationBackEvent {\n source: 'navbar';\n}\n\nexport interface NativeNavigationBarItemTapEvent {\n id: string;\n title?: string;\n placement: 'left' | 'right';\n}\n\nexport interface NativeNavigationTabSelectEvent {\n id: string;\n index: number;\n title?: string;\n}\n\nexport interface NativeNavigationSafeAreaChangedEvent {\n insets: NativeNavigationInsets;\n}\n\nexport interface NativeNavigationTransitionEvent {\n id: string;\n direction: NativeNavigationTransitionDirection;\n duration: number;\n}\n\n/**\n * Framework-agnostic native navigation chrome API.\n */\nexport interface NativeNavigationPlugin {\n /**\n * Configure the native chrome host and content inset behavior.\n */\n configure(options?: NativeNavigationConfigureOptions): Promise<NativeNavigationInsetsResult>;\n\n /**\n * Render or update the native navbar.\n */\n setNavbar(options: NativeNavigationNavbarOptions): Promise<NativeNavigationInsetsResult>;\n\n /**\n * Render or update the native tabbar.\n */\n setTabbar(options: NativeNavigationTabbarOptions): Promise<NativeNavigationInsetsResult>;\n\n /**\n * Capture the current WebView and prepare a native transition.\n */\n beginTransition(options?: NativeNavigationBeginTransitionOptions): Promise<NativeNavigationTransitionResult>;\n\n /**\n * Animate from the captured WebView snapshot to the current live WebView.\n */\n finishTransition(options?: NativeNavigationFinishTransitionOptions): Promise<NativeNavigationTransitionResult>;\n\n /**\n * Returns the platform implementation version marker.\n */\n getPluginVersion(): Promise<PluginVersionResult>;\n\n addListener(\n eventName: 'navbarBack',\n listenerFunc: (event: NativeNavigationBackEvent) => void,\n ): Promise<PluginListenerHandle>;\n\n addListener(\n eventName: 'navbarItemTap',\n listenerFunc: (event: NativeNavigationBarItemTapEvent) => void,\n ): Promise<PluginListenerHandle>;\n\n addListener(\n eventName: 'tabSelect',\n listenerFunc: (event: NativeNavigationTabSelectEvent) => void,\n ): Promise<PluginListenerHandle>;\n\n addListener(\n eventName: 'safeAreaChanged',\n listenerFunc: (event: NativeNavigationSafeAreaChangedEvent) => void,\n ): Promise<PluginListenerHandle>;\n\n addListener(\n eventName: 'transitionStart',\n listenerFunc: (event: NativeNavigationTransitionEvent) => void,\n ): Promise<PluginListenerHandle>;\n\n addListener(\n eventName: 'transitionEnd',\n listenerFunc: (event: NativeNavigationTransitionEvent) => void,\n ): Promise<PluginListenerHandle>;\n}\n"]}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"","sourcesContent":["import type { PluginListenerHandle } from '@capacitor/core';\n\n/**\n * Platform rendering preference for the native bars.\n */\nexport type NativeNavigationPlatformStyle = 'auto' | 'ios' | 'android';\n\n/**\n * How the plugin exposes native bar sizes to web content.\n */\nexport type NativeNavigationContentInsetMode = 'css' | 'none';\n\n/**\n * Navigation animation direction.\n */\nexport type NativeNavigationTransitionDirection = 'forward' | 'back' | 'root' | 'tab' | 'zoom' | 'none';\n\n/**\n * Native material/blur effect preference.\n */\nexport type NativeNavigationBlurEffect =\n | 'none'\n | 'systemDefault'\n | 'extraLight'\n | 'light'\n | 'dark'\n | 'regular'\n | 'prominent'\n | 'systemUltraThinMaterial'\n | 'systemThinMaterial'\n | 'systemMaterial'\n | 'systemThickMaterial'\n | 'systemChromeMaterial'\n | 'systemUltraThinMaterialLight'\n | 'systemThinMaterialLight'\n | 'systemMaterialLight'\n | 'systemThickMaterialLight'\n | 'systemChromeMaterialLight'\n | 'systemUltraThinMaterialDark'\n | 'systemThinMaterialDark'\n | 'systemMaterialDark'\n | 'systemThickMaterialDark'\n | 'systemChromeMaterialDark';\n\n/**\n * Native tab label visibility behavior.\n */\nexport type NativeNavigationTabLabelVisibilityMode = 'auto' | 'selected' | 'labeled' | 'unlabeled';\n\n/**\n * A rectangle in WebView viewport coordinates, expressed in native points/dp.\n */\nexport interface NativeNavigationRect {\n x: number;\n y: number;\n width: number;\n height: number;\n}\n\n/**\n * A serializable icon descriptor. Framework nodes are intentionally not accepted\n * because icons are rendered by native UI.\n */\nexport interface NativeNavigationIcon {\n /**\n * Cross-platform asset path or URL fallback.\n */\n src?: string;\n\n /**\n * Cross-platform inline SVG markup. The native renderers support common icon\n * shapes such as path, line, polyline, polygon, circle, and rect. SVG icons\n * are rendered as template images by default so native tint colors still\n * apply.\n */\n svg?: string;\n\n /**\n * Preferred rendered icon width in native points/dp. Defaults to `24`.\n */\n width?: number;\n\n /**\n * Preferred rendered icon height in native points/dp. Defaults to `24`.\n */\n height?: number;\n\n /**\n * When `true`, native tint colors are applied to the rendered SVG/image.\n * Defaults to `true`.\n */\n template?: boolean;\n\n /**\n * iOS-specific SF Symbol, bundled image name, or inline SVG.\n */\n ios?: {\n /**\n * SF Symbol name, for example `house.fill`.\n */\n sfSymbol?: string;\n\n /**\n * Bundled image name from the app asset catalog.\n */\n image?: string;\n\n /**\n * iOS-specific inline SVG markup.\n */\n svg?: string;\n };\n\n /**\n * Android-specific drawable resource, asset name, or inline SVG.\n */\n android?: {\n /**\n * Drawable resource name without the `R.drawable.` prefix.\n */\n resource?: string;\n\n /**\n * Bundled image asset name.\n */\n image?: string;\n\n /**\n * Android-specific inline SVG markup.\n */\n svg?: string;\n };\n}\n\n/**\n * Native bar colors. Use CSS-style hex strings (`#RRGGBB` or `#AARRGGBB`).\n */\nexport interface NativeNavigationColors {\n /**\n * When `true`, Android 12+ derives unspecified bar colors from Material You\n * system palettes. Explicit color fields still win.\n */\n dynamic?: boolean;\n\n /**\n * Tint color for active buttons/items.\n */\n tint?: string;\n\n /**\n * Color for inactive tab items.\n */\n inactiveTint?: string;\n\n /**\n * Optional background tint. Ignored on iOS 26+ so UIKit can preserve the\n * system Liquid Glass navigation appearance.\n */\n background?: string;\n\n /**\n * Title and label text color where the native platform supports it.\n */\n foreground?: string;\n\n /**\n * Badge background color for native tab badges.\n */\n badgeBackground?: string;\n\n /**\n * Badge text color for native tab badges.\n */\n badgeText?: string;\n\n /**\n * Active tab indicator color on Android.\n */\n indicator?: string;\n\n /**\n * Tab press ripple color on Android.\n */\n ripple?: string;\n}\n\n/**\n * Global plugin configuration.\n */\nexport interface NativeNavigationConfigureOptions {\n /**\n * Enables or disables the native chrome host.\n */\n enabled?: boolean;\n\n /**\n * Native style preference. `auto` uses the current platform.\n */\n platformStyle?: NativeNavigationPlatformStyle;\n\n /**\n * When `css`, the plugin writes CSS variables on `document.documentElement`.\n */\n contentInsetMode?: NativeNavigationContentInsetMode;\n\n /**\n * Default native transition duration in milliseconds.\n */\n animationDuration?: number;\n\n /**\n * Shared color hints for native bars.\n */\n colors?: NativeNavigationColors;\n}\n\n/**\n * A button shown in the native navbar.\n */\nexport interface NativeNavigationBarButton {\n /**\n * Stable id returned in `navbarItemTap`.\n */\n id: string;\n\n /**\n * Visible text label.\n */\n title?: string;\n\n /**\n * Native icon descriptor.\n */\n icon?: NativeNavigationIcon;\n\n /**\n * Whether the action is enabled. Defaults to `true`.\n */\n enabled?: boolean;\n}\n\n/**\n * Native back button configuration.\n */\nexport interface NativeNavigationBackButton {\n /**\n * Show the native back affordance.\n */\n visible?: boolean;\n\n /**\n * Optional back title.\n */\n title?: string;\n}\n\n/**\n * Native navbar state.\n */\nexport interface NativeNavigationNavbarOptions {\n /**\n * Hide the native navbar.\n */\n hidden?: boolean;\n\n /**\n * Main title.\n */\n title?: string;\n\n /**\n * Secondary title where supported by the platform.\n */\n subtitle?: string;\n\n /**\n * Prefer a large iOS title style.\n */\n large?: boolean;\n\n /**\n * Prefer transparent/scroll-edge style.\n */\n transparent?: boolean;\n\n /**\n * iOS blur/material effect for the navbar background when glass is not\n * available. Defaults to `systemChromeMaterial` for transparent bars.\n */\n blurEffect?: NativeNavigationBlurEffect;\n\n /**\n * Back button state.\n */\n backButton?: NativeNavigationBackButton;\n\n /**\n * Left-side action buttons.\n */\n leftItems?: NativeNavigationBarButton[];\n\n /**\n * Right-side action buttons.\n */\n rightItems?: NativeNavigationBarButton[];\n\n /**\n * Navbar color hints.\n */\n colors?: NativeNavigationColors;\n\n /**\n * Animate native navbar changes.\n */\n animated?: boolean;\n}\n\n/**\n * A native tab item.\n */\nexport interface NativeNavigationTab {\n /**\n * Stable tab id returned in `tabSelect`.\n */\n id: string;\n\n /**\n * Visible tab label.\n */\n title?: string;\n\n /**\n * Native icon descriptor.\n */\n icon?: NativeNavigationIcon;\n\n /**\n * Optional selected-state icon.\n */\n selectedIcon?: NativeNavigationIcon;\n\n /**\n * Optional badge. Numeric badges are supported on both platforms; text badge\n * support depends on platform capabilities.\n */\n badge?: string | number;\n\n /**\n * Whether the tab is enabled. Defaults to `true`.\n */\n enabled?: boolean;\n}\n\n/**\n * Native tabbar state.\n */\nexport interface NativeNavigationTabbarOptions {\n /**\n * Hide the native tabbar.\n */\n hidden?: boolean;\n\n /**\n * Tab definitions.\n */\n tabs?: NativeNavigationTab[];\n\n /**\n * Currently selected tab id.\n */\n selectedId?: string;\n\n /**\n * Show text labels. Defaults to `true`.\n */\n labels?: boolean;\n\n /**\n * Native label visibility mode. Overrides `labels` when provided.\n */\n labelVisibilityMode?: NativeNavigationTabLabelVisibilityMode;\n\n /**\n * Show icons. Defaults to `true`.\n */\n icons?: boolean;\n\n /**\n * Tabbar color hints.\n */\n colors?: NativeNavigationColors;\n\n /**\n * iOS blur/material effect for the tabbar background when glass is not\n * available.\n */\n blurEffect?: NativeNavigationBlurEffect;\n\n /**\n * Keep the iOS scroll-edge tabbar appearance from becoming transparent.\n * Mirrors Expo Router native tabs' `disableTransparentOnScrollEdge` option.\n * Defaults to `false`.\n */\n disableTransparentOnScrollEdge?: boolean;\n\n /**\n * Disable the Android active tab indicator.\n */\n disableIndicator?: boolean;\n\n /**\n * Active tab indicator color on Android. `colors.indicator` is also\n * supported.\n */\n indicatorColor?: string;\n\n /**\n * Tab press ripple color on Android. `colors.ripple` is also supported.\n */\n rippleColor?: string;\n\n /**\n * Badge background color. `colors.badgeBackground` is also supported.\n */\n badgeBackgroundColor?: string;\n\n /**\n * Badge text color. `colors.badgeText` is also supported.\n */\n badgeTextColor?: string;\n\n /**\n * Animate native tabbar changes.\n */\n animated?: boolean;\n}\n\n/**\n * Insets exposed to web content.\n */\nexport interface NativeNavigationInsets {\n top: number;\n right: number;\n bottom: number;\n left: number;\n navbarHeight: number;\n tabbarHeight: number;\n}\n\n/**\n * Returned by methods that may change safe content bounds.\n */\nexport interface NativeNavigationInsetsResult {\n insets: NativeNavigationInsets;\n}\n\n/**\n * Begin a native transition transaction before JS changes route content.\n */\nexport interface NativeNavigationBeginTransitionOptions {\n id?: string;\n direction?: NativeNavigationTransitionDirection;\n duration?: number;\n /**\n * Source rectangle for `zoom` transitions. Use viewport coordinates such as\n * those returned by `Element.getBoundingClientRect()`.\n */\n sourceRect?: NativeNavigationRect;\n /**\n * Destination rectangle for shared-element-style `zoom` transitions.\n */\n targetRect?: NativeNavigationRect;\n /**\n * Corner radius used while animating a `zoom` transition.\n */\n cornerRadius?: number;\n}\n\n/**\n * Finish a native transition transaction after JS has changed route content.\n */\nexport interface NativeNavigationFinishTransitionOptions {\n id?: string;\n direction?: NativeNavigationTransitionDirection;\n duration?: number;\n /**\n * Source rectangle for `zoom` transitions when no active source was recorded.\n */\n sourceRect?: NativeNavigationRect;\n /**\n * Destination rectangle for shared-element-style `zoom` transitions.\n */\n targetRect?: NativeNavigationRect;\n /**\n * Corner radius used while animating a `zoom` transition.\n */\n cornerRadius?: number;\n}\n\n/**\n * Native transition result.\n */\nexport interface NativeNavigationTransitionResult {\n id: string;\n direction: NativeNavigationTransitionDirection;\n duration: number;\n}\n\n/**\n * Plugin version payload.\n */\nexport interface PluginVersionResult {\n /**\n * Version identifier returned by the platform implementation.\n */\n version: string;\n}\n\nexport interface NativeNavigationBackEvent {\n source: 'navbar';\n}\n\nexport interface NativeNavigationBarItemTapEvent {\n id: string;\n title?: string;\n placement: 'left' | 'right';\n}\n\nexport interface NativeNavigationTabSelectEvent {\n id: string;\n index: number;\n title?: string;\n}\n\nexport interface NativeNavigationSafeAreaChangedEvent {\n insets: NativeNavigationInsets;\n}\n\nexport interface NativeNavigationTransitionEvent {\n id: string;\n direction: NativeNavigationTransitionDirection;\n duration: number;\n}\n\n/**\n * Framework-agnostic native navigation chrome API.\n */\nexport interface NativeNavigationPlugin {\n /**\n * Configure the native chrome host and content inset behavior.\n */\n configure(options?: NativeNavigationConfigureOptions): Promise<NativeNavigationInsetsResult>;\n\n /**\n * Render or update the native navbar.\n */\n setNavbar(options: NativeNavigationNavbarOptions): Promise<NativeNavigationInsetsResult>;\n\n /**\n * Render or update the native tabbar.\n */\n setTabbar(options: NativeNavigationTabbarOptions): Promise<NativeNavigationInsetsResult>;\n\n /**\n * Capture the current WebView and prepare a native transition.\n */\n beginTransition(options?: NativeNavigationBeginTransitionOptions): Promise<NativeNavigationTransitionResult>;\n\n /**\n * Animate from the captured WebView snapshot to the current live WebView.\n */\n finishTransition(options?: NativeNavigationFinishTransitionOptions): Promise<NativeNavigationTransitionResult>;\n\n /**\n * Returns the platform implementation version marker.\n */\n getPluginVersion(): Promise<PluginVersionResult>;\n\n addListener(\n eventName: 'navbarBack',\n listenerFunc: (event: NativeNavigationBackEvent) => void,\n ): Promise<PluginListenerHandle>;\n\n addListener(\n eventName: 'navbarItemTap',\n listenerFunc: (event: NativeNavigationBarItemTapEvent) => void,\n ): Promise<PluginListenerHandle>;\n\n addListener(\n eventName: 'tabSelect',\n listenerFunc: (event: NativeNavigationTabSelectEvent) => void,\n ): Promise<PluginListenerHandle>;\n\n addListener(\n eventName: 'safeAreaChanged',\n listenerFunc: (event: NativeNavigationSafeAreaChangedEvent) => void,\n ): Promise<PluginListenerHandle>;\n\n addListener(\n eventName: 'transitionStart',\n listenerFunc: (event: NativeNavigationTransitionEvent) => void,\n ): Promise<PluginListenerHandle>;\n\n addListener(\n eventName: 'transitionEnd',\n listenerFunc: (event: NativeNavigationTransitionEvent) => void,\n ): Promise<PluginListenerHandle>;\n}\n"]}
Binary file
Binary file
Binary file
@@ -23,7 +23,7 @@ private struct NativeNavigationZoomTransitionContext {
23
23
 
24
24
  // swiftlint:disable type_body_length
25
25
  @objc(NativeNavigationPlugin)
26
- public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarDelegate {
26
+ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarControllerDelegate, UITabBarDelegate {
27
27
  public let identifier = "NativeNavigationPlugin"
28
28
  public let jsName = "NativeNavigation"
29
29
  public let pluginMethods: [CAPPluginMethod] = [
@@ -42,6 +42,8 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarDelega
42
42
  private var tabContainer: UIView?
43
43
  private var tabEffectView: UIVisualEffectView?
44
44
  private var tabBar: UITabBar?
45
+ private var tabBarController: NativeNavigationTabController?
46
+ private var tabViewControllers: [UIViewController] = []
45
47
  private var navbarHeight: CGFloat = 44
46
48
  private var tabbarHeight: CGFloat = 64
47
49
  private let floatingTabbarHorizontalMargin: CGFloat = 24
@@ -56,6 +58,7 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarDelega
56
58
  private var navbarItemTitle: [String: String] = [:]
57
59
  private var tabIds: [String] = []
58
60
  private var tabTitles: [String] = []
61
+ private var suppressTabSelectEvent = false
59
62
  private var transitionSnapshot: UIView?
60
63
  private var activeTransitionId: String?
61
64
  private var activeTransitionDirection = "forward"
@@ -93,6 +96,7 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarDelega
93
96
  if !self.isEnabled {
94
97
  self.navContainer?.isHidden = true
95
98
  self.tabContainer?.isHidden = true
99
+ self.tabBarController?.view.isHidden = true
96
100
  self.tabBar?.isHidden = true
97
101
  }
98
102
 
@@ -167,6 +171,7 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarDelega
167
171
 
168
172
  guard !hidden else {
169
173
  self.tabContainer?.isHidden = true
174
+ self.tabBarController?.view.isHidden = true
170
175
  self.tabBar?.isHidden = true
171
176
  self.updateInsetsAndNotify()
172
177
  call.resolve(self.insetsResult())
@@ -187,15 +192,20 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarDelega
187
192
  icons: icons
188
193
  )
189
194
 
190
- tabBar.items = items
191
- if let selectedIndex = selectedIndex, selectedIndex < items.count {
192
- tabBar.selectedItem = items[selectedIndex]
193
- } else if tabBar.selectedItem == nil {
194
- tabBar.selectedItem = items.first
195
+ if self.usesSystemLiquidGlass {
196
+ self.applySystemTabBarItems(items, selectedIndex: selectedIndex, animated: call.getBool("animated", false))
197
+ } else {
198
+ tabBar.items = items
199
+ if let selectedIndex = selectedIndex, selectedIndex < items.count {
200
+ tabBar.selectedItem = items[selectedIndex]
201
+ } else if tabBar.selectedItem == nil {
202
+ tabBar.selectedItem = items.first
203
+ }
195
204
  }
196
205
 
197
206
  self.applyTabBarAppearance(tabBar: tabBar, options: call)
198
207
  self.tabContainer?.isHidden = false
208
+ self.tabBarController?.view.isHidden = false
199
209
  tabBar.isHidden = false
200
210
  self.layoutChrome()
201
211
  self.updateInsetsAndNotify()
@@ -422,7 +432,18 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarDelega
422
432
  }
423
433
 
424
434
  public func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
425
- let index = item.tag
435
+ notifyTabSelect(index: item.tag)
436
+ }
437
+
438
+ public func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
439
+ guard !suppressTabSelectEvent else {
440
+ return
441
+ }
442
+ let index = tabBarController.viewControllers?.firstIndex(of: viewController) ?? viewController.tabBarItem.tag
443
+ notifyTabSelect(index: index)
444
+ }
445
+
446
+ private func notifyTabSelect(index: Int) {
426
447
  guard index >= 0 && index < tabIds.count else {
427
448
  return
428
449
  }
@@ -474,6 +495,10 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarDelega
474
495
  }
475
496
 
476
497
  private func ensureTabBar() -> UITabBar {
498
+ if usesSystemLiquidGlass {
499
+ return ensureSystemTabBar()
500
+ }
501
+
477
502
  if let tabBar = tabBar {
478
503
  return tabBar
479
504
  }
@@ -484,28 +509,24 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarDelega
484
509
  container.autoresizingMask = [.flexibleWidth, .flexibleTopMargin]
485
510
  container.backgroundColor = .clear
486
511
 
487
- if !usesSystemLiquidGlass {
488
- container.layer.shadowColor = UIColor.black.cgColor
489
- container.layer.shadowOpacity = 0.14
490
- container.layer.shadowRadius = 18
491
- container.layer.shadowOffset = CGSize(width: 0, height: 10)
512
+ container.layer.shadowColor = UIColor.black.cgColor
513
+ container.layer.shadowOpacity = 0.14
514
+ container.layer.shadowRadius = 18
515
+ container.layer.shadowOffset = CGSize(width: 0, height: 10)
492
516
 
493
- let effectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemChromeMaterial))
494
- effectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
495
- effectView.isUserInteractionEnabled = false
496
- effectView.clipsToBounds = true
497
- container.addSubview(effectView)
498
- self.tabEffectView = effectView
499
- }
517
+ let effectView = UIVisualEffectView(effect: UIBlurEffect(style: .systemChromeMaterial))
518
+ effectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
519
+ effectView.isUserInteractionEnabled = false
520
+ effectView.clipsToBounds = true
521
+ container.addSubview(effectView)
522
+ self.tabEffectView = effectView
500
523
 
501
524
  let bar = UITabBar()
502
525
  bar.isTranslucent = true
503
- if !usesSystemLiquidGlass {
504
- bar.backgroundColor = .clear
505
- bar.backgroundImage = UIImage()
506
- bar.shadowImage = UIImage()
507
- bar.clipsToBounds = true
508
- }
526
+ bar.backgroundColor = .clear
527
+ bar.backgroundImage = UIImage()
528
+ bar.shadowImage = UIImage()
529
+ bar.clipsToBounds = true
509
530
  bar.delegate = self
510
531
  bar.autoresizingMask = [.flexibleWidth, .flexibleTopMargin]
511
532
  container.addSubview(bar)
@@ -515,6 +536,52 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarDelega
515
536
  return bar
516
537
  }
517
538
 
539
+ private func ensureSystemTabBar() -> UITabBar {
540
+ if let tabBarController = tabBarController {
541
+ return tabBarController.tabBar
542
+ }
543
+
544
+ let controller = NativeNavigationTabController()
545
+ controller.delegate = self
546
+ controller.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
547
+ controller.view.isHidden = !tabbarVisible
548
+
549
+ if let parent = bridge?.viewController {
550
+ parent.addChild(controller)
551
+ parent.view.addSubview(controller.view)
552
+ controller.didMove(toParent: parent)
553
+ }
554
+
555
+ self.tabBarController = controller
556
+ self.tabBar = controller.tabBar
557
+ return controller.tabBar
558
+ }
559
+
560
+ private func applySystemTabBarItems(_ items: [UITabBarItem], selectedIndex: Int?, animated: Bool) {
561
+ guard let tabBarController = tabBarController else {
562
+ return
563
+ }
564
+
565
+ let previousSelectedIndex = tabBarController.selectedIndex
566
+ let controllers = items.map { item -> UIViewController in
567
+ let controller = NativeNavigationTabContentController()
568
+ controller.tabBarItem = item
569
+ return controller
570
+ }
571
+ let shouldAnimate = animated && tabBarController.viewControllers?.count == controllers.count
572
+
573
+ suppressTabSelectEvent = true
574
+ tabBarController.setViewControllers(controllers, animated: shouldAnimate)
575
+ if !controllers.isEmpty {
576
+ let fallbackIndex = selectedIndex ?? previousSelectedIndex
577
+ let index = min(max(fallbackIndex, 0), controllers.count - 1)
578
+ tabBarController.selectedIndex = index
579
+ }
580
+ suppressTabSelectEvent = false
581
+
582
+ tabViewControllers = controllers
583
+ }
584
+
518
585
  private func makeBarButtonItems(_ rawItems: [[String: Any]], placement: String) -> [UIBarButtonItem] {
519
586
  return rawItems.map { rawItem in
520
587
  let id = rawItem["id"] as? String ?? UUID().uuidString
@@ -780,6 +847,30 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarDelega
780
847
  }
781
848
 
782
849
  private func applyTabBarAppearance(tabBar: UITabBar, options call: CAPPluginCall) {
850
+ if usesSystemLiquidGlass {
851
+ let standardAppearance = UITabBarAppearance()
852
+ configureSystemTabBarStandardBackground(standardAppearance)
853
+ applyTabBarColorOptions(standardAppearance, tabBar: tabBar, options: call)
854
+ applyTabBarBadgeOptions(standardAppearance, options: call)
855
+
856
+ let scrollEdgeAppearance = UITabBarAppearance()
857
+ configureSystemTabBarScrollEdgeBackground(scrollEdgeAppearance, options: call)
858
+ applyTabBarColorOptions(scrollEdgeAppearance, tabBar: tabBar, options: call)
859
+ applyTabBarBadgeOptions(scrollEdgeAppearance, options: call)
860
+
861
+ tabBar.standardAppearance = standardAppearance
862
+ if #available(iOS 15.0, *) {
863
+ tabBar.scrollEdgeAppearance = scrollEdgeAppearance
864
+ }
865
+ tabBar.items?.forEach { item in
866
+ item.standardAppearance = standardAppearance
867
+ if #available(iOS 15.0, *) {
868
+ item.scrollEdgeAppearance = scrollEdgeAppearance
869
+ }
870
+ }
871
+ return
872
+ }
873
+
783
874
  let appearance = UITabBarAppearance()
784
875
  configureTabBarBackground(appearance, options: call)
785
876
  applyTabBarColorOptions(appearance, tabBar: tabBar, options: call)
@@ -792,19 +883,27 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarDelega
792
883
  }
793
884
 
794
885
  private func configureTabBarBackground(_ appearance: UITabBarAppearance, options call: CAPPluginCall) {
795
- if usesSystemLiquidGlass {
796
- appearance.configureWithDefaultBackground()
886
+ appearance.configureWithDefaultBackground()
887
+ if let effect = blurEffect(from: call.getString("blurEffect"), fallback: nil) {
888
+ appearance.configureWithTransparentBackground()
889
+ appearance.backgroundColor = .clear
890
+ tabEffectView?.effect = effect
891
+ tabEffectView?.isHidden = false
892
+ } else {
797
893
  tabEffectView?.isHidden = true
894
+ }
895
+ }
896
+
897
+ private func configureSystemTabBarStandardBackground(_ appearance: UITabBarAppearance) {
898
+ appearance.configureWithDefaultBackground()
899
+ }
900
+
901
+ private func configureSystemTabBarScrollEdgeBackground(_ appearance: UITabBarAppearance, options call: CAPPluginCall) {
902
+ if call.getBool("disableTransparentOnScrollEdge", false) {
903
+ configureSystemTabBarStandardBackground(appearance)
798
904
  } else {
799
- appearance.configureWithDefaultBackground()
800
- if let effect = blurEffect(from: call.getString("blurEffect"), fallback: nil) {
801
- appearance.configureWithTransparentBackground()
802
- appearance.backgroundColor = .clear
803
- tabEffectView?.effect = effect
804
- tabEffectView?.isHidden = false
805
- } else {
806
- tabEffectView?.isHidden = true
807
- }
905
+ appearance.configureWithTransparentBackground()
906
+ appearance.shadowColor = .clear
808
907
  }
809
908
  }
810
909
 
@@ -888,32 +987,23 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarDelega
888
987
  }
889
988
 
890
989
  if let container = tabContainer {
891
- if usesSystemLiquidGlass {
892
- container.frame = CGRect(
893
- x: 0,
894
- y: height - safeInsets.bottom - tabbarHeight,
895
- width: width,
896
- height: tabbarHeight + safeInsets.bottom
897
- )
898
- container.layer.cornerRadius = 0
899
- container.layer.shadowOpacity = 0
900
- container.layer.shadowPath = nil
901
- tabEffectView?.isHidden = true
902
- tabBar?.frame = container.bounds
903
- tabBar?.layer.cornerRadius = 0
904
- } else {
905
- let availableWidth = max(0, width - (floatingTabbarHorizontalMargin * 2))
906
- let tabbarWidth = min(availableWidth, floatingTabbarMaxWidth)
907
- let originX = (width - tabbarWidth) / 2
908
- let originY = height - safeInsets.bottom - floatingTabbarBottomGap - tabbarHeight
909
- container.frame = CGRect(x: originX, y: originY, width: tabbarWidth, height: tabbarHeight)
910
- container.layer.cornerRadius = tabbarHeight / 2
911
- container.layer.shadowPath = UIBezierPath(roundedRect: container.bounds, cornerRadius: tabbarHeight / 2).cgPath
912
- tabEffectView?.frame = container.bounds
913
- tabEffectView?.layer.cornerRadius = tabbarHeight / 2
914
- tabBar?.frame = container.bounds
915
- tabBar?.layer.cornerRadius = tabbarHeight / 2
916
- }
990
+ let availableWidth = max(0, width - (floatingTabbarHorizontalMargin * 2))
991
+ let tabbarWidth = min(availableWidth, floatingTabbarMaxWidth)
992
+ let originX = (width - tabbarWidth) / 2
993
+ let originY = height - safeInsets.bottom - floatingTabbarBottomGap - tabbarHeight
994
+ container.frame = CGRect(x: originX, y: originY, width: tabbarWidth, height: tabbarHeight)
995
+ container.layer.cornerRadius = tabbarHeight / 2
996
+ container.layer.shadowPath = UIBezierPath(roundedRect: container.bounds, cornerRadius: tabbarHeight / 2).cgPath
997
+ tabEffectView?.frame = container.bounds
998
+ tabEffectView?.layer.cornerRadius = tabbarHeight / 2
999
+ tabBar?.frame = container.bounds
1000
+ tabBar?.layer.cornerRadius = tabbarHeight / 2
1001
+ }
1002
+
1003
+ if let tabBarController = tabBarController {
1004
+ tabBarController.view.frame = CGRect(x: 0, y: 0, width: width, height: height)
1005
+ tabBarController.view.setNeedsLayout()
1006
+ tabBarController.view.layoutIfNeeded()
917
1007
  }
918
1008
 
919
1009
  bringChromeToFront()
@@ -926,6 +1016,9 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarDelega
926
1016
  if let tabContainer = tabContainer {
927
1017
  bridge?.viewController?.view.bringSubviewToFront(tabContainer)
928
1018
  }
1019
+ if let tabBarController = tabBarController {
1020
+ bridge?.viewController?.view.bringSubviewToFront(tabBarController.view)
1021
+ }
929
1022
  }
930
1023
 
931
1024
  private func colorValue(_ value: Any?) -> UIColor? {
@@ -1007,9 +1100,11 @@ public class NativeNavigationPlugin: CAPPlugin, CAPBridgedPlugin, UITabBarDelega
1007
1100
 
1008
1101
  private func currentInsets() -> [String: Any] {
1009
1102
  let safeInsets = bridge?.viewController?.view.safeAreaInsets ?? .zero
1010
- let navHeight = navbarVisible ? navbarHeight + safeInsets.top : 0
1011
- let tabbarGap = usesSystemLiquidGlass ? 0 : floatingTabbarBottomGap
1012
- let tabHeight = tabbarVisible ? tabbarHeight + safeInsets.bottom + tabbarGap : 0
1103
+ let navHeight = isEnabled && navbarVisible ? navbarHeight + safeInsets.top : 0
1104
+ let nativeTabHeight = max(tabBar?.frame.height ?? 0, 49 + safeInsets.bottom)
1105
+ let tabHeight = isEnabled && tabbarVisible
1106
+ ? (usesSystemLiquidGlass ? nativeTabHeight : tabbarHeight + safeInsets.bottom + floatingTabbarBottomGap)
1107
+ : 0
1013
1108
  return [
1014
1109
  "top": navHeight,
1015
1110
  "right": safeInsets.right,
@@ -1137,6 +1232,44 @@ private final class NativeNavigationBar: UINavigationBar {
1137
1232
  }
1138
1233
  }
1139
1234
 
1235
+ private final class NativeNavigationTabController: UITabBarController {
1236
+ override func loadView() {
1237
+ let view = NativeNavigationTabControllerView()
1238
+ view.backgroundColor = .clear
1239
+ view.isOpaque = false
1240
+ self.view = view
1241
+ }
1242
+
1243
+ override func viewDidLoad() {
1244
+ super.viewDidLoad()
1245
+ view.backgroundColor = .clear
1246
+ view.isOpaque = false
1247
+ tabBar.isTranslucent = true
1248
+ (view as? NativeNavigationTabControllerView)?.tabBar = tabBar
1249
+ }
1250
+ }
1251
+
1252
+ private final class NativeNavigationTabControllerView: UIView {
1253
+ weak var tabBar: UITabBar?
1254
+
1255
+ override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
1256
+ guard let tabBar = tabBar, !tabBar.isHidden, tabBar.alpha > 0.01 else {
1257
+ return false
1258
+ }
1259
+ let tabPoint = convert(point, to: tabBar)
1260
+ return tabBar.point(inside: tabPoint, with: event)
1261
+ }
1262
+ }
1263
+
1264
+ private final class NativeNavigationTabContentController: UIViewController {
1265
+ override func loadView() {
1266
+ let view = UIView()
1267
+ view.backgroundColor = .clear
1268
+ view.isOpaque = false
1269
+ self.view = view
1270
+ }
1271
+ }
1272
+
1140
1273
  private final class SVGIconRenderer: NSObject, XMLParserDelegate {
1141
1274
  private let context: CGContext
1142
1275
  private var styleStack = [SVGRenderStyle()]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/capacitor-native-navigation",
3
- "version": "8.0.9",
3
+ "version": "8.0.11",
4
4
  "description": "Capacitor plugin for native navbar, tabbar, and route transition chrome over a WebView.",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",