Skip to content

feat: project UITabAccessory mini-player from Ionic markup - #248

Open
phiamo wants to merge 14 commits into
rdlabo-dev:mainfrom
phiamo:feat/uitab-accessory-mini-player
Open

phiamo wants to merge 14 commits into
rdlabo-dev:mainfrom
phiamo:feat/uitab-accessory-mini-player

Conversation

@phiamo

@phiamo phiamo commented Sep 29, 2026 •

Copy link
Copy Markdown

Summary

  • Native UI Shell projects ion-toolbar.tab-accessory (alias ios-theme-tab-accessory: thumbnail, title, subtitle, play/pause, progress) into iOS 26+ UITabAccessory above the projected tab bar.
  • Taps go back to the original Ionic play button or toolbar. There is no setBottomAccessory / listener API.
  • Overlay coordination matches the rest of the shell: the accessory reader skips ion-modal / ion-popover / ion-menu / ion-content, and overlayOpen() retires native covers so a presented modal can sit in front.
  • Web/classic: enableTabAccessory() — swipe-up follow-finger lift/fade, then toolbar.click(). Native pan does the same. Skip the play button, skip when Native UI Shell owns the bar, skip while the host sets .tab-accessory-panning-x (or .ios-theme-tab-accessory-panning-x). Optional lift wrapper: .tab-accessory-lift / data-tab-accessory-lift.
  • Shared opt-in is tab-accessory so Material does not need an ios-theme-* class. Related: feat: MD3 styles for shared tab accessory markup ionic-theme-md3#51 (CSS + its own enableTabAccessory(), no import of this package). Dual-theme apps should call enableTabAccessory() once.
  • Segment: registerSegmentEffect / toolbar spring only when CSS.supports('overflow-anchor: auto') so iOS 15–26 do not stretch the bar.

Test plan

  • Place ion-toolbar.tab-accessory (or the ios-theme-tab-accessory alias) above ion-tab-bar and confirm the native glass mini-player
  • Play/pause clicks the original ion-button; body tap/swipe clicks the toolbar
  • Swipe-up on Web/classic and native opens via the original toolbar; play stays isolated
  • Present an ion-modal and confirm the accessory is not projected in front of it
  • MD3 demo Library tab: feat: MD3 styles for shared tab accessory markup ionic-theme-md3#51
  • Docs: docs/native-ui-shell.md. Tests: demo/src/ion-tab-accessory.spec.ts, demo/src/tab-accessory.spec.ts, ShellSnapshotTests.testTabAccessoryDecodesOptionalFieldsAndRejectsEmptyItems

Related to rdlabo-dev/ionic-theme-md3#51

Expose setBottomAccessory on Native UI Shell so apps can host an iOS 26 mini-player on UITabBarController (searchable tabs today). Ordinary overlay UITabBar still needs a controller host.

Co-authored-by: Cursor <cursoragent@cursor.com>
@rdlabo

rdlabo commented Sep 30, 2026

Copy link
Copy Markdown
Contributor

Thanks for the pull request, and sorry I haven’t put proper contribution guidelines in place yet.

For now, Native UI Shell is designed to display native UI as a “projection” of the Web UI. With that in mind, could you implement this using a combination of Ionic components on the Web side, which the shell can then project?

Keeping the Ionic components as the source lets us coordinate with the rest of the app—for example, temporarily suspending native projection when an ion-modal opens so the modal can appear in front.

phiamo and others added 3 commits September 30, 2026 15:15
Add support for `ion-toolbar.ios-theme-tab-accessory` to enable a mini-player in the fixed footer region above the tab bar. This includes updates to the ShellControl structure to accommodate optional fields like title, subtitle, artwork URL, and playback progress. The previous bottom accessory functionality has been removed in favor of this new implementation.

Co-authored-by: Cursor <cursoragent@cursor.com>
Enhance test coverage for the tab accessory by adding a test case to verify that the progress value can be set to zero. This ensures that the mini-player correctly reflects a progress state of 0, contributing to the overall reliability of the tab accessory functionality.

Co-authored-by: Cursor <cursoragent@cursor.com>
Cover the overlay rule rdlabo asked for: a marked mini-player toolbar inside ion-modal must stay on the Web.

Co-authored-by: Cursor <cursoragent@cursor.com>
@phiamo phiamo changed the title feat: UITabAccessory mini-player API feat: project UITabAccessory mini-player from Ionic markup Sep 30, 2026
@phiamo

phiamo commented Sep 30, 2026

Copy link
Copy Markdown
Author

Thanks — rewritten as projection of Ionic markup, not a native-only API.

The Web source is ion-toolbar.ios-theme-tab-accessory (thumbnail, title, subtitle, play/pause, progress). The shell snapshots that DOM into UITabAccessory and routes taps back by clicking the original play button or toolbar. No setBottomAccessory / listener API.

Overlays keep the existing shell behavior: the accessory reader skips ion-modal / ion-popover / ion-menu / ion-content, and overlayOpen() retires native covers so a presented modal can sit in front.

Docs: docs/native-ui-shell.md. Tests: demo/src/ion-tab-accessory.spec.ts and ShellSnapshotTests.testTabAccessoryDecodesOptionalFieldsAndRejectsEmptyItems.

phiamo and others added 5 commits September 30, 2026 19:48
Keep the 28px capsule as the default on iOS 17.4+, and sit the player above the 62px island. Classic is opt-in via class, or automatic in the demo when text-wrap: pretty is missing.

Co-authored-by: Cursor <cursoragent@cursor.com>
Refine the positioning of the classic 12px mini-player to ensure it aligns correctly above the 62px island on iOS 15 devices. This change enhances the user experience by maintaining consistent layout across different iOS versions.

Co-authored-by: Cursor <cursoragent@cursor.com>
Add support for displaying elapsed time and duration in the tab accessory mini-player. This update includes modifications to the ShellControl structure and related components to accommodate the new fields, improving the user experience by providing more detailed playback information.

Co-authored-by: Cursor <cursoragent@cursor.com>
Refactor the SCSS for the ion-tab-accessory component to enhance the layout and responsiveness. Changes include adjusting padding, min-height, and alignment properties to ensure better visual consistency across iOS devices. This update aims to improve the overall user experience by refining the appearance of the tab accessory.

Co-authored-by: Cursor <cursoragent@cursor.com>
Add functionality to activate the tab accessory on click, improving user interaction with the mini-player. This update includes a new method for handling accessory activation and integrates the enableTabAccessory feature for better performance. Additionally, minor adjustments were made to the layout of the play button for a more streamlined appearance.

Co-authored-by: Cursor <cursoragent@cursor.com>
@phiamo

phiamo commented Oct 1, 2026 •

Copy link
Copy Markdown
Author

Follow-up: swipe-up now lives in the plugin. Shared opt-in is tab-accessory so Material does not need an ios-theme-* class.

enableTabAccessory() on Web/classic: swipe-up follows the finger (lift + fade) and then clicks the original ion-toolbar. Native pan does the same. Play stays a separate hit target; hosts can set .tab-accessory-panning-x (or .ios-theme-tab-accessory-panning-x) so a horizontal dismiss is not stolen.

ios-theme-tab-accessory stays the Native UI Shell hook and an alias. Android / Material uses the same toolbar markup; CSS + swipe are in rdlabo-dev/ionic-theme-md3#51 (no import of this package). Dual-theme apps should call enableTabAccessory() once.

Also in this commit: iOS 27 segment host scale is gated on overflow-anchor so iOS 15–26 bars are not stretched.

phiamo and others added 2 commits October 1, 2026 11:33
Match ion-toolbar.tab-accessory in CSS, swipe JS, and Native UI Shell. ios-theme-tab-accessory stays the native hook and an alias for existing markup.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@rdlabo

rdlabo commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

Thank you for this wonderful PR! I'm really looking forward to reviewing your contribution!

@phiamo

phiamo commented Oct 2, 2026

Copy link
Copy Markdown
Author

Thank you for the great ios26/ios27/md3 plugins. They made my day last year to push our app on a new level. Now trying to give smth back 🙏😊

phiamo and others added 2 commits October 2, 2026 10:59
Tab accessory host taps still need a matching toolbar id with no item, but standalone buttons share that id and were ignoring disabled/pointer-events none (verticalBars Save while the Ionic menu is open). Align the Playwright thumb assertion with the 36px CSS token.

Co-authored-by: Cursor <cursoragent@cursor.com>
Keep tab-accessory candidate skips and wrap reads in withoutPrehide so empty projected toolbars still collapse correctly.

Co-authored-by: Cursor <cursoragent@cursor.com>
@rdlabo

rdlabo commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

The mini-player content looks like it sits about 2px too low—is that intentional? Also, is the intended height around 42px? Understanding the reasoning behind the height would help with my review. Thanks!

…rchable tabs

UITabAccessory is ~42pt; the previous 8/10 pins and required 36pt thumb over-constrained that height and sat content ~2pt low. Searchable Library also detached the ordinary tabs controller, which dropped the mini-player after the first snapshot.

Co-authored-by: Cursor <cursoragent@cursor.com>
@phiamo

phiamo commented Oct 3, 2026

Copy link
Copy Markdown
Author

Not intentional. Native content was pinned 8pt top / 10pt bottom with a required 36pt thumb and 44pt play button. UITabAccessory sizes its own glass platter — about 42pt on iOS 26 — so those constraints over-constrained the layout and Auto Layout kept the top inset, which dropped the content ~2pt.

Native height is chosen by UIKit, not a plugin token. Content is now vertically centered with symmetric minimum insets and a shrinkable thumb so it fits that platter. The 64px CSS height is only the Web/classic fallback (8px padding, 36px thumb, two text lines, 2.5px progress). Hosts can still override --ios-theme-tab-accessory-height.

Also on Library: searchable tabs were replacing the ordinary UITabBarController, which tore down UITabAccessory after the first snapshot. The accessory now stays on the searchable controller as well.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants