@rdlabo/ionic-theme-ios27 1.2.1 → 2.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.
Files changed (195) hide show
  1. package/README.md +24 -280
  2. package/dist/css/components/ion-toolbar.css +1 -1
  3. package/dist/css/ionic-theme-ios27.css +1 -1
  4. package/dist/css/vertical-bars.css +1 -1
  5. package/dist/index.d.ts +3 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +3 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/layout/index.d.ts +18 -0
  10. package/dist/layout/index.d.ts.map +1 -0
  11. package/dist/layout/index.js +26 -0
  12. package/dist/layout/index.js.map +1 -0
  13. package/dist/segment/index.js +3 -3
  14. package/dist/segment/index.js.map +1 -1
  15. package/dist/sheets-of-glass/index.js +7 -7
  16. package/dist/sheets-of-glass/index.js.map +1 -1
  17. package/dist/tab-bar-searchable/dismiss-button.js +53 -3
  18. package/dist/tab-bar-searchable/dismiss-button.js.map +1 -1
  19. package/dist/tab-bar-searchable/index.js +18 -3
  20. package/dist/tab-bar-searchable/index.js.map +1 -1
  21. package/dist/transition/ios.transition.d.ts.map +1 -1
  22. package/dist/transition/ios.transition.js +7 -4
  23. package/dist/transition/ios.transition.js.map +1 -1
  24. package/dist/transition/native-ui.d.ts +6 -0
  25. package/dist/transition/native-ui.d.ts.map +1 -0
  26. package/dist/{native-integration/index.js → transition/native-ui.js} +16 -30
  27. package/dist/transition/native-ui.js.map +1 -0
  28. package/docs/adaptive-themes.md +161 -0
  29. package/docs/add-native-ui.md +53 -0
  30. package/docs/animation.md +19 -3
  31. package/docs/eslint.md +3 -1
  32. package/docs/features.md +9 -5
  33. package/docs/iphone-duo.md +62 -35
  34. package/docs/migration.md +17 -26
  35. package/docs/setup.md +92 -0
  36. package/docs/special-markup.md +41 -10
  37. package/docs/using-ion-item-group.md +2 -2
  38. package/docs/vertical-bars-layout.md +67 -0
  39. package/package.json +12 -42
  40. package/src/index.ts +3 -1
  41. package/src/layout/index.ts +29 -0
  42. package/src/segment/index.ts +3 -3
  43. package/src/sheets-of-glass/index.ts +7 -7
  44. package/src/styles/components/ion-toolbar.scss +1 -1
  45. package/src/styles/vertical-bars.scss +15 -18
  46. package/src/tab-bar-searchable/dismiss-button.ts +73 -4
  47. package/src/tab-bar-searchable/index.ts +20 -3
  48. package/src/transition/ios.transition.ts +7 -4
  49. package/src/{native-integration/index.ts → transition/native-ui.ts} +17 -46
  50. package/Package.swift +0 -21
  51. package/dist/_virtual/_rolldown/runtime.js +0 -13
  52. package/dist/native/components/index.d.ts +0 -19
  53. package/dist/native/components/index.d.ts.map +0 -1
  54. package/dist/native/components/index.js +0 -40
  55. package/dist/native/components/index.js.map +0 -1
  56. package/dist/native/components/ion-back-button.d.ts +0 -9
  57. package/dist/native/components/ion-back-button.d.ts.map +0 -1
  58. package/dist/native/components/ion-back-button.js +0 -20
  59. package/dist/native/components/ion-back-button.js.map +0 -1
  60. package/dist/native/components/ion-button.d.ts +0 -10
  61. package/dist/native/components/ion-button.d.ts.map +0 -1
  62. package/dist/native/components/ion-button.js +0 -23
  63. package/dist/native/components/ion-button.js.map +0 -1
  64. package/dist/native/components/ion-buttons.d.ts +0 -11
  65. package/dist/native/components/ion-buttons.d.ts.map +0 -1
  66. package/dist/native/components/ion-buttons.js +0 -30
  67. package/dist/native/components/ion-buttons.js.map +0 -1
  68. package/dist/native/components/ion-fab.d.ts +0 -10
  69. package/dist/native/components/ion-fab.d.ts.map +0 -1
  70. package/dist/native/components/ion-fab.js +0 -132
  71. package/dist/native/components/ion-fab.js.map +0 -1
  72. package/dist/native/components/ion-menu-button.d.ts +0 -13
  73. package/dist/native/components/ion-menu-button.d.ts.map +0 -1
  74. package/dist/native/components/ion-menu-button.js +0 -31
  75. package/dist/native/components/ion-menu-button.js.map +0 -1
  76. package/dist/native/components/ion-segment.d.ts +0 -11
  77. package/dist/native/components/ion-segment.d.ts.map +0 -1
  78. package/dist/native/components/ion-segment.js +0 -30
  79. package/dist/native/components/ion-segment.js.map +0 -1
  80. package/dist/native/components/ion-tab-bar.d.ts +0 -11
  81. package/dist/native/components/ion-tab-bar.d.ts.map +0 -1
  82. package/dist/native/components/ion-tab-bar.js +0 -50
  83. package/dist/native/components/ion-tab-bar.js.map +0 -1
  84. package/dist/native/components/searchable-tabs.d.ts +0 -20
  85. package/dist/native/components/searchable-tabs.d.ts.map +0 -1
  86. package/dist/native/components/searchable-tabs.js +0 -383
  87. package/dist/native/components/searchable-tabs.js.map +0 -1
  88. package/dist/native/definitions.d.ts +0 -152
  89. package/dist/native/definitions.d.ts.map +0 -1
  90. package/dist/native/definitions.js +0 -0
  91. package/dist/native/foldable/fold-state.d.ts +0 -5
  92. package/dist/native/foldable/fold-state.d.ts.map +0 -1
  93. package/dist/native/foldable/fold-state.js +0 -14
  94. package/dist/native/foldable/fold-state.js.map +0 -1
  95. package/dist/native/foldable/types.d.ts +0 -12
  96. package/dist/native/foldable/types.d.ts.map +0 -1
  97. package/dist/native/foldable/types.js +0 -0
  98. package/dist/native/index.d.ts +0 -11
  99. package/dist/native/index.d.ts.map +0 -1
  100. package/dist/native/index.js +0 -242
  101. package/dist/native/index.js.map +0 -1
  102. package/dist/native/prehide.d.ts +0 -7
  103. package/dist/native/prehide.d.ts.map +0 -1
  104. package/dist/native/prehide.js +0 -230
  105. package/dist/native/prehide.js.map +0 -1
  106. package/dist/native/runtime.d.ts +0 -5
  107. package/dist/native/runtime.d.ts.map +0 -1
  108. package/dist/native/runtime.js +0 -640
  109. package/dist/native/runtime.js.map +0 -1
  110. package/dist/native/shared/candidate.d.ts +0 -21
  111. package/dist/native/shared/candidate.d.ts.map +0 -1
  112. package/dist/native/shared/candidate.js +0 -98
  113. package/dist/native/shared/candidate.js.map +0 -1
  114. package/dist/native/shared/crossfade.d.ts +0 -10
  115. package/dist/native/shared/crossfade.d.ts.map +0 -1
  116. package/dist/native/shared/crossfade.js +0 -50
  117. package/dist/native/shared/crossfade.js.map +0 -1
  118. package/dist/native/shared/dom.d.ts +0 -46
  119. package/dist/native/shared/dom.d.ts.map +0 -1
  120. package/dist/native/shared/dom.js +0 -172
  121. package/dist/native/shared/dom.js.map +0 -1
  122. package/dist/native/shared/events.d.ts +0 -11
  123. package/dist/native/shared/events.d.ts.map +0 -1
  124. package/dist/native/shared/events.js +0 -13
  125. package/dist/native/shared/events.js.map +0 -1
  126. package/dist/native/shared/icons.d.ts +0 -8
  127. package/dist/native/shared/icons.d.ts.map +0 -1
  128. package/dist/native/shared/icons.js +0 -61
  129. package/dist/native/shared/icons.js.map +0 -1
  130. package/dist/native/shared/modal.d.ts +0 -10
  131. package/dist/native/shared/modal.d.ts.map +0 -1
  132. package/dist/native/shared/modal.js +0 -160
  133. package/dist/native/shared/modal.js.map +0 -1
  134. package/dist/native/vertical-bars-web-search.d.ts +0 -9
  135. package/dist/native/vertical-bars-web-search.d.ts.map +0 -1
  136. package/dist/native/vertical-bars-web-search.js +0 -84
  137. package/dist/native/vertical-bars-web-search.js.map +0 -1
  138. package/dist/native/vertical-bars-web.d.ts +0 -5
  139. package/dist/native/vertical-bars-web.d.ts.map +0 -1
  140. package/dist/native/vertical-bars-web.js +0 -341
  141. package/dist/native/vertical-bars-web.js.map +0 -1
  142. package/dist/native-integration/index.d.ts +0 -23
  143. package/dist/native-integration/index.d.ts.map +0 -1
  144. package/dist/native-integration/index.js.map +0 -1
  145. package/dist/native-integration/transition.d.ts +0 -5
  146. package/dist/native-integration/transition.d.ts.map +0 -1
  147. package/dist/native-integration/transition.js +0 -16
  148. package/dist/native-integration/transition.js.map +0 -1
  149. package/dist/vertical-bars.d.ts +0 -5
  150. package/dist/vertical-bars.js +0 -4
  151. package/docs/e2e-testing.md +0 -51
  152. package/docs/feedback.md +0 -65
  153. package/docs/iphone-duo-with-original-theme.md +0 -158
  154. package/docs/native-ui-shell.md +0 -285
  155. package/docs/vertical-bars.md +0 -285
  156. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellButton.swift +0 -71
  157. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellButtons.swift +0 -24
  158. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellComponents.swift +0 -18
  159. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellFab.swift +0 -83
  160. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellSearchController.swift +0 -432
  161. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellSegment.swift +0 -91
  162. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellTabBar.swift +0 -221
  163. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellVerticalBars.swift +0 -437
  164. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellVerticalSearch.swift +0 -118
  165. package/ios/Sources/IonicNativeUIShellPlugin/IonicNativeUIShellPlugin.swift +0 -396
  166. package/ios/Sources/IonicNativeUIShellPlugin/Shared/ShellCrossfade.swift +0 -35
  167. package/ios/Sources/IonicNativeUIShellPlugin/Shared/ShellHost.swift +0 -8
  168. package/ios/Sources/IonicNativeUIShellPlugin/Shared/ShellRendering.swift +0 -27
  169. package/ios/Sources/IonicNativeUIShellPlugin/Shared/ShellSnapshot.swift +0 -135
  170. package/ios/Tests/IonicNativeUIShellPluginTests/ShellSnapshotTests.swift +0 -650
  171. package/src/native/components/index.ts +0 -53
  172. package/src/native/components/ion-back-button.ts +0 -19
  173. package/src/native/components/ion-button.ts +0 -24
  174. package/src/native/components/ion-buttons.ts +0 -38
  175. package/src/native/components/ion-fab.ts +0 -151
  176. package/src/native/components/ion-menu-button.ts +0 -24
  177. package/src/native/components/ion-segment.ts +0 -27
  178. package/src/native/components/ion-tab-bar.ts +0 -50
  179. package/src/native/components/searchable-tabs.ts +0 -459
  180. package/src/native/definitions.ts +0 -191
  181. package/src/native/foldable/fold-state.ts +0 -9
  182. package/src/native/foldable/types.ts +0 -4
  183. package/src/native/index.ts +0 -281
  184. package/src/native/prehide.ts +0 -265
  185. package/src/native/runtime.ts +0 -781
  186. package/src/native/shared/candidate.ts +0 -150
  187. package/src/native/shared/crossfade.ts +0 -50
  188. package/src/native/shared/dom.ts +0 -286
  189. package/src/native/shared/events.ts +0 -8
  190. package/src/native/shared/icons.ts +0 -57
  191. package/src/native/shared/modal.ts +0 -157
  192. package/src/native/vertical-bars-web-search.ts +0 -80
  193. package/src/native/vertical-bars-web.ts +0 -411
  194. package/src/native-integration/transition.ts +0 -15
  195. package/src/vertical-bars.ts +0 -11
package/docs/eslint.md CHANGED
@@ -2,6 +2,8 @@
2
2
  title: Keep lists consistent with ESLint
3
3
  ---
4
4
 
5
+ # Keep lists consistent with ESLint
6
+
5
7
  Catch missing list groups before they reach the screen. In Ionic Angular apps, `@rdlabo/eslint-plugin-rules` checks the markup used by iOS 27.
6
8
 
7
9
  ## Enable the list check
@@ -60,7 +62,7 @@ Group the items and import `IonItemGroup` in the standalone component:
60
62
 
61
63
  The rule checks all `ion-list` elements, including non-inset lists. Radio, reorder, and accordion groups are also supported. It checks Angular templates; it does not inspect React or Vue templates.
62
64
 
63
- See [Using ion-item-group](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/using-ion-item-group) for layout examples and the [rule reference](https://docs.rdlabo.dev/projects/eslint-plugin-rules/docs/rules/require-ion-item-group) for supported structures and automatic fixes.
65
+ See [Using ion-item-group](using-ion-item-group.md) for layout examples and the [rule reference](https://docs.rdlabo.dev/projects/eslint-plugin-rules/docs/rules/require-ion-item-group) for supported structures and automatic fixes.
64
66
 
65
67
  ## Keep it checked
66
68
 
package/docs/features.md CHANGED
@@ -4,16 +4,20 @@ title: Features
4
4
 
5
5
  # Features
6
6
 
7
- Customize the theme with CSS variables and Sass mixins, or adopt it one component at a time. Markup-specific opt-ins are documented in [Special markup and classes](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/special-markup).
7
+ Customize the theme with CSS variables and Sass mixins, or adopt it one component at a time. Markup-specific opt-ins are documented in [Special markup and classes](special-markup.md).
8
8
 
9
9
  ## CSS variables
10
10
 
11
11
  To customize the library's default styles to match your design, several CSS variables are provided. See this file for details:
12
12
  [Default variables](../src/styles/default-variables.scss)
13
13
 
14
- For menus, `--ios-theme-menu-background-rgb` sets the surface RGB channels (light: `225, 230, 240`; dark: `26, 31, 34`). `--ios-theme-menu-background-opacity` controls opacity and defaults to `0.96`. Both are public customization variables and can be set on `ion-menu`.
14
+ | Variable | Default | Purpose |
15
+ | ------------------------------------- | ------------------------------------------ | ----------------------------------------------------------------- |
16
+ | `--ios-theme-menu-background-rgb` | Light: `225, 230, 240`; dark: `26, 31, 34` | Menu surface RGB channels; set on `ion-menu`. |
17
+ | `--ios-theme-menu-background-opacity` | `0.96` | Menu surface opacity; set on `ion-menu`. |
18
+ | `--ios-theme-button-press-duration` | `380ms` | Duration of the button's `:active` scaling with slight overshoot. |
15
19
 
16
- Button press scaling follows `:active` with a slight overshoot. Set `--ios-theme-button-press-duration` (default: `380ms`) to customize its duration instead of the shared activated-transition duration variables.
20
+ Use `--ios-theme-button-press-duration` instead of the shared activated-transition duration variables to customize button press scaling.
17
21
 
18
22
  ## Liquid Glass mixin
19
23
 
@@ -27,9 +31,9 @@ ion-textarea label.textarea-wrapper {
27
31
  }
28
32
  ```
29
33
 
30
- ## Native UI Shell (Preview)
34
+ ## Native UI (Preview)
31
35
 
32
- Capacitor iOS apps can use the optional [Native UI Shell](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/native-ui-shell) to render supported fixed Ionic controls with UIKit and system Liquid Glass. It is available as a preview in `1.2.0`. Content and application logic stay in the WebView, with Ionic owning routing and page transitions. The guide explains the hybrid approach's origins in Basecamp and Capacitor, setup, supported controls and Web fallback behavior.
36
+ Once your theme is working, [add Native UI](add-native-ui.md) to render supported fixed controls with UIKit and SwiftUI on iOS. Keep theme styles for Web content and fallback controls. Native UI is an optional preview; adding styles alone does not enable it.
33
37
 
34
38
  ## Selective component imports
35
39
 
@@ -1,32 +1,40 @@
1
1
  ---
2
- title: iPhone Duo support (preview)
2
+ title: iPhone Duo support
3
3
  ---
4
4
 
5
- # iPhone Duo support (preview)
5
+ # iPhone Duo support
6
6
 
7
7
  Adapt your Ionic app to iPhone Duo: place navigation and actions in its vertical system rail, and adjust your split pane as the device opens and closes. Existing Ionic markup remains the source of labels, icons, routing, and click handlers.
8
8
 
9
- **New here?** Start with [iPhone Duo with your existing theme](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/iphone-duo-with-original-theme) to preview the side layout in Chrome. This page explains device events, placement and split panes. [Vertical Bars](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/vertical-bars) documents control projection and the runtime API.
9
+ **New here?** Start with [iPhone Duo with your existing theme](../../capacitor-native-ui/docs/ionic-vertical-bars.md) to preview the side layout in Chrome. This page explains device events, placement and split panes. [Vertical Bars](../../capacitor-native-ui/docs/vertical-bars.md) documents control projection and the runtime API.
10
10
 
11
- Available in `1.2.0` as a **preview** feature alongside [Native UI Shell](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/native-ui-shell). APIs and supported behavior may change before stable status. Stable status is planned after the official release of Xcode 27.1. The real system rail and hinge reporting require iOS 27.1 or later and an app built with Xcode 27.1 or newer.
11
+ iPhone Duo support is stable starting with version 2.0.0. The real system rail and hinge reporting require iOS 27.1 or later and an app built with Xcode 27.1 or newer.
12
12
 
13
- This package provides two independent pieces for that hardware. Each works **without the iOS 27 theme stylesheets** and **without the full Native UI Shell**:
13
+ Use the theme layout and native plugin independently for that hardware. Neither requires the full iOS 27 appearance:
14
14
 
15
- - `dist/css/vertical-bars.css` — opt-in classes that reserve the rail's safe area, plus a registered custom property for a posture-driven split-pane width.
16
- - `enableVerticalControlArea()` — moves eligible tabs and toolbar controls into the reserved area. On Capacitor iOS they are rendered by a native SwiftUI `TabView` and toolbar; everywhere else the same controls appear as Web clones.
15
+ - Theme: `dist/css/vertical-bars.css` — opt-in classes that reserve the rail's safe area, plus a registered custom property for a posture-driven split-pane width.
16
+ - Native UI: `enableNativeUI({ controls: 'verticalOnly' })` — selects eligible tabs and toolbar controls placed in the reserved area. On Capacitor iOS they are rendered by a native SwiftUI `TabView` and toolbar; everywhere else the same controls appear as Web clones.
17
17
 
18
- Device state belongs to [`@erkamyaman/capacitor-foldable`](https://github.com/erkamyaman/capacitor-foldable). The **application** subscribes to its events and chooses its layout. This package's **stylesheet and runtime** apply that decision by reserving space, projecting controls and adapting the split pane. The theme does not monitor hinge state or bar placement.
18
+ Device state belongs to [`@erkamyaman/capacitor-foldable`](https://github.com/erkamyaman/capacitor-foldable). The **application** subscribes to its events and chooses its layout. The theme reserves space and adapts the split pane; Native UI projects eligible controls. The theme does not monitor hinge state or bar placement.
19
+
20
+ | Owner | Responsibility |
21
+ | ------------------- | ----------------------------------------------------------------------------------------------------------- |
22
+ | Foldable | Report bar placement and hinge posture, initially and when they change. |
23
+ | Application / theme | Subscribe to device events and apply Web layout through `setVerticalBarsLayout` or `applyFoldStateClasses`. |
24
+ | Native UI | Project eligible controls and determine native rail availability independently. |
25
+
26
+ For the native package's integration, including application-owned CSS and plain HTML, see [Use with Capacitor Foldable](../../capacitor-native-ui/docs/vertical-bars.md#use-with-capacitor-foldable).
19
27
 
20
28
  ## Choose what to adopt
21
29
 
22
- To keep your existing theme and add only the standalone support, follow [iPhone Duo with your existing theme](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/iphone-duo-with-original-theme). This page covers the shared device-layout rules.
30
+ To keep your existing theme and add only the standalone support, follow [iPhone Duo with your existing theme](../../capacitor-native-ui/docs/ionic-vertical-bars.md). This page covers the shared device-layout rules.
23
31
 
24
- | Goal | Stylesheet | Runtime |
25
- | ------------------------------------------------ | ------------------- | ------------------------------------------------------------------ |
26
- | Hinge posture only (layout switches) | none | none — subscribe to `Foldable` directly |
27
- | Posture-driven split-pane width | `vertical-bars.css` | none — subscribe to `Foldable` directly |
28
- | Vertical rail for tabs and toolbar actions | `vertical-bars.css` | `enableVerticalControlArea()` |
29
- | Native shell plus the rail | `vertical-bars.css` | `enableNativeUIShell()` — includes rail projection |
32
+ | Goal | Stylesheet | Runtime |
33
+ | ------------------------------------------ | ------------------- | ---------------------------------------------- |
34
+ | Hinge posture only (layout switches) | none | none — subscribe to `Foldable` directly |
35
+ | Posture-driven split-pane width | `vertical-bars.css` | none — subscribe to `Foldable` directly |
36
+ | Vertical rail for tabs and toolbar actions | `vertical-bars.css` | `enableNativeUI({ controls: 'verticalOnly' })` |
37
+ | Native shell plus the rail | `vertical-bars.css` | `enableNativeUI()` — includes rail projection |
30
38
 
31
39
  ```scss
32
40
  @use '@rdlabo/ionic-theme-ios27/dist/css/vertical-bars.css';
@@ -51,7 +59,7 @@ After `ion-app` is mounted, pass device state to `applyFoldStateClasses`. The ap
51
59
 
52
60
  ```ts
53
61
  import { Foldable } from '@erkamyaman/capacitor-foldable';
54
- import { applyFoldStateClasses } from '@rdlabo/ionic-theme-ios27/vertical-bars';
62
+ import { applyFoldStateClasses } from '@rdlabo/ionic-theme-ios27';
55
63
 
56
64
  const root = document.querySelector('ion-app')!;
57
65
  const listener = await Foldable.addListener('foldStateChange', (fold) => applyFoldStateClasses(root, fold));
@@ -66,9 +74,31 @@ await listener.remove();
66
74
 
67
75
  Subscribe to changes, then read the current state. The same helper handles initial values and events.
68
76
 
69
- `applyFoldStateClasses` keeps one of `ios-theme-fold-flat`, `ios-theme-fold-half-opened`, and `ios-theme-fold-closed` on the supplied root, preserving unrelated classes. It also sets `ios-theme-fold-expanded` for a half-opened state or a flat state with hinge geometry. A flat state without geometry (including the Web fallback) and a closed state clear that class. The helper does not subscribe to the plugin or change Ionic's split-pane `when` property.
77
+ ### Posture classes
78
+
79
+ `applyFoldStateClasses` updates the supplied root while preserving unrelated classes:
80
+
81
+ | Class | Applied when |
82
+ | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
83
+ | `ios-theme-fold-flat` | Flat posture. |
84
+ | `ios-theme-fold-half-opened` | Half-opened posture. |
85
+ | `ios-theme-fold-closed` | Closed posture. |
86
+ | `ios-theme-fold-expanded` | Half-opened, or flat with hinge geometry. Cleared for flat without geometry (including Web fallback) and closed posture. |
87
+
88
+ Only one of the first three classes is retained. The helper does not subscribe to the plugin or change Ionic's split-pane `when` property.
89
+
90
+ ### Placement values
91
+
92
+ For rail placement, import `setVerticalBarsLayout` from the theme and pass the reported logical `edge` with the measured `inset`:
93
+
94
+ | Value | Web layout effect |
95
+ | ------------------ | ---------------------------------------------------- |
96
+ | `edge: 'leading'` | Physical left in LTR; physical right in RTL. |
97
+ | `edge: 'trailing'` | Physical right in LTR; physical left in RTL. |
98
+ | `edge: null` | Restores ordinary layout. |
99
+ | Measured `inset` | Reserves that width; zero clears the explicit width. |
70
100
 
71
- For rail placement, use `setVerticalControlAreaPlacement` as shown below. Pass the reported logical edge as both `edge` and `nativeEdge`, together with the measured `inset`. Leading is the physical left in LTR and the physical right in RTL. A null edge restores the ordinary layout; an inset of zero clears the explicit width. No start/stop monitoring calls are needed.
101
+ The helper does not report native availability or activate projection. No start/stop monitoring calls are needed. See [Project controls into the rail](#project-controls-into-the-rail) for the subscription.
72
102
 
73
103
  WebView corner radius remains a rendering concern: `configureNativeTransition()` uses the shell's `getWebViewMetrics()` API, independently of `Foldable`.
74
104
 
@@ -76,22 +106,23 @@ WebView corner radius remains a rendering concern: `configureNativeTransition()`
76
106
 
77
107
  ## Reserve the vertical rail
78
108
 
79
- Load `vertical-bars.css` as shown above. For class-based browser simulation, safe-area handling, RTL and overlay layout, see [Reserve the vertical rail](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/vertical-bars#reserve-the-vertical-rail). On device, the placement helper below applies the layout classes and measured inset.
109
+ Load `vertical-bars.css` as shown above. For class-based browser simulation, safe-area handling, RTL and overlay layout, see [Reserve the vertical rail](vertical-bars-layout.md#reserve-the-vertical-rail). On device, the placement helper below applies the layout classes and measured inset.
80
110
 
81
111
  ## Project controls into the rail
82
112
 
83
- Start the standalone runtime once after `ion-app` is mounted, and apply the plugin's placement with `setVerticalControlAreaPlacement`:
113
+ Enable rail projection once after `ion-app` is mounted, and apply Foldable's placement to the Web layout with `setVerticalBarsLayout`:
84
114
 
85
115
  ```ts
86
116
  import { Foldable } from '@erkamyaman/capacitor-foldable';
87
- import { setVerticalControlAreaPlacement, enableVerticalControlArea } from '@rdlabo/ionic-theme-ios27/vertical-bars';
117
+ import { setVerticalBarsLayout } from '@rdlabo/ionic-theme-ios27';
118
+ import { enableNativeUI } from '@rdlabo/capacitor-native-ui';
88
119
 
89
- const rail = await enableVerticalControlArea();
120
+ const rail = await enableNativeUI({ controls: 'verticalOnly' });
90
121
  const listener = await Foldable.addListener('barPlacementChange', ({ verticalBarEdge, inset }) =>
91
- setVerticalControlAreaPlacement({ edge: verticalBarEdge, nativeEdge: verticalBarEdge, inset }),
122
+ setVerticalBarsLayout({ edge: verticalBarEdge, inset }),
92
123
  );
93
124
  const { verticalBarEdge, inset } = await Foldable.getBarPlacement();
94
- setVerticalControlAreaPlacement({ edge: verticalBarEdge, nativeEdge: verticalBarEdge, inset });
125
+ setVerticalBarsLayout({ edge: verticalBarEdge, inset });
95
126
  ```
96
127
 
97
128
  When the application owner is disposed:
@@ -101,30 +132,26 @@ await listener.remove();
101
132
  await rail.destroy();
102
133
  ```
103
134
 
104
- Supply `nativeEdge` on both the initial read and each event so the renderer knows which rail the system actually provides. The measured `inset` is passed through instead of assuming a fixed width. Devices without a reported rail, including Web and Android, return a null edge and retain the ordinary layout. For browser simulation, use the [class-based preview](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/vertical-bars#reserve-the-vertical-rail) without connecting device placement.
135
+ Native UI detects native availability independently through its own device metrics. The theme helper controls Web layout only. The measured `inset` is passed through instead of assuming a fixed width. Devices without a reported rail, including Web and Android, return a null edge and retain the ordinary layout. For browser simulation, use the [class-based preview](vertical-bars-layout.md#reserve-the-vertical-rail) without connecting device placement.
105
136
 
106
- Start either `enableVerticalControlArea()` or the full `enableNativeUIShell()` — not both. If the app already uses Native UI Shell, keep that runtime and use the same `setVerticalControlAreaPlacement` callback. The application owner removes its listeners and destroys its runtime on teardown.
137
+ Start either `enableNativeUI({ controls: 'verticalOnly' })` or the full `enableNativeUI()` — not both. If the app already uses Native UI, keep that runtime and use the same `setVerticalBarsLayout` callback. The application owner removes its listeners and destroys its runtime on teardown.
107
138
 
108
- On supported iOS versions the runtime hands eligible tabs, back navigation, menu buttons, and fixed-toolbar actions to a native SwiftUI `TabView` and toolbar; on Web, Android, or when native projection is unavailable, Web clones remain the fallback. See [Toolbar actions](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/vertical-bars#toolbar-actions) for control eligibility.
139
+ On supported iOS versions the runtime hands eligible tabs, back navigation, menu buttons, and fixed-toolbar actions to a native SwiftUI `TabView` and toolbar; on Web, Android, or when native projection is unavailable, Web clones remain the fallback. See [Toolbar actions](../../capacitor-native-ui/docs/vertical-bars.md#toolbar-actions) for control eligibility.
109
140
 
110
141
  ### Toolbar actions
111
142
 
112
- See [Vertical Bars: Toolbar actions](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/vertical-bars#toolbar-actions) for eligible markup, placement, button appearance and local overrides.
143
+ See [Vertical Bars: Toolbar actions](../../capacitor-native-ui/docs/vertical-bars.md#toolbar-actions) for eligible markup, placement, button appearance and local overrides.
113
144
 
114
145
  ### Tab bar
115
146
 
116
- See [Vertical Bars: Tab bar](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/vertical-bars#tab-bar) for navigation, labels and Web fallback behavior.
147
+ See [Vertical Bars: Tab bar](../../capacitor-native-ui/docs/vertical-bars.md#tab-bar) for navigation, labels and Web fallback behavior.
117
148
 
118
149
  ## Adapt the split pane
119
150
 
120
151
  For a side-by-side menu on iPhone Duo, opt the `ion-split-pane` into the separately measured Settings layout. The sidebar is 320pt when fully unfolded and reaches the display midpoint when half-opened (50vw). The application supplies the posture; both states have the same viewport width, so a width media query cannot distinguish them:
121
152
 
122
153
  ```html
123
- <ion-split-pane
124
- class="split-pane-fold-layout"
125
- contentId="main-content"
126
- when="(min-width: 900px)"
127
- >
154
+ <ion-split-pane class="split-pane-fold-layout" contentId="main-content" when="(min-width: 900px)">
128
155
  <ion-menu contentId="main-content">...</ion-menu>
129
156
  <div id="main-content">...</div>
130
157
  </ion-split-pane>
@@ -147,4 +174,4 @@ Ionic's `when` still controls whether the menu is persistent. The example choose
147
174
 
148
175
  ## Vertical Control Area API
149
176
 
150
- The runtime handle reference is maintained in [Vertical Bars](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/vertical-bars#vertical-control-area-api).
177
+ The runtime handle reference is maintained in [Vertical Bars](../../capacitor-native-ui/docs/vertical-bars.md#vertical-control-area-api).
package/docs/migration.md CHANGED
@@ -1,35 +1,23 @@
1
1
  ---
2
- title: Migration
2
+ title: Theme migration
3
3
  ---
4
4
 
5
- # Migration
5
+ # Theme migration
6
6
 
7
- ## Native UI Shell transition adapter
7
+ ## Native UI package separation
8
8
 
9
- Use `withNativeUIShellTransition()` to keep your existing Ionic navigation animation while coordinating Native UI Shell controls.
9
+ Theme styles and ordinary theme API imports remain supported. If you previously used native controls through this package, the `/native` and `/vertical-bars` entries have been removed:
10
10
 
11
- - If you already import `iosTransitionAnimation` from `@rdlabo/ionic-theme-ios27`, keep the [package animation setup](./iphone-duo-with-original-theme.md#use-this-package%27s-ios-animation); no configuration change is needed. It now uses the shared adapter internally; do not add another wrapper.
12
- - If you use Ionic's default animation without a `navAnimation` option, follow [Keep Ionic's default animation](./iphone-duo-with-original-theme.md#keep-ionic%27s-default-animation). The example selects Ionic's standard iOS or MD builder from the transition mode.
13
- - If you use a custom navigation animation with Native UI Shell or the standalone Vertical Control Area, wrap your existing builder when configuring Ionic:
11
+ | Previous import | Replacement |
12
+ | ----------------------------------------- | ------------------------------------------- |
13
+ | `@rdlabo/ionic-theme-ios27/native` | `@rdlabo/capacitor-native-ui` |
14
+ | `@rdlabo/ionic-theme-ios27/vertical-bars` | `@rdlabo/capacitor-native-ui/vertical-bars` |
14
15
 
15
- ```diff
16
- + import { withNativeUIShellTransition } from '@rdlabo/ionic-theme-ios27/vertical-bars';
17
-
18
- const ionicConfig = {
19
- - navAnimation: existingTransition,
20
- + navAnimation: withNativeUIShellTransition(existingTransition),
21
- };
22
- ```
23
-
24
- Merge this option into your existing Ionic configuration before initialization. The adapter preserves the animation's effects, duration, and easing while coordinating native retirement, swipe progress, and cancellation. Keep your existing theme stylesheet imports and Native UI Shell or Vertical Control Area startup.
25
-
26
- Use the adapter only for navigation; leave modal and popover animations unchanged. Your builder must create a fresh `Animation` for each navigation because Ionic destroys it afterward. Keep lifecycle events for control registration and transitions without animation. If the custom builder animates a horizontal back button separately, exclude that effect while `.ios-theme-vertical-bars` is active.
27
-
28
- See [Connect your navigation animation](./iphone-duo-with-original-theme.md#3.-connect-your-navigation-animation) for the setup and supported scope.
16
+ Add the native package as a direct application dependency, update imports, rebuild Web assets, and run `npx cap sync ios`. Follow the [Native UI migration guide](https://github.com/rdlabo-dev/ionic-theme-ios27/blob/main/packages/capacitor-native-ui/docs/migration.md) for 1.2.1 startup settings and native project changes. Theme-only apps do not need native startup or plugin setup.
29
17
 
30
18
  ## From the iOS 26 theme
31
19
 
32
- For an app using `@rdlabo/ionic-theme-ios26`, the recommended migration keeps that package and adds `@rdlabo/ionic-theme-ios27`. The [README setup](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/readme#get-started) selects iOS 27 or iOS 26 styles by browser capability and leaves Ionic's default iOS appearance on older browsers.
20
+ For an app using `@rdlabo/ionic-theme-ios26`, the recommended migration keeps that package and adds `@rdlabo/ionic-theme-ios27`. The [adaptive theme setup](adaptive-themes.md) selects iOS 27 or iOS 26 styles by browser capability and leaves Ionic's default iOS appearance on older browsers.
33
21
 
34
22
  ### 1. Add the new package
35
23
 
@@ -127,17 +115,20 @@ To switch entirely to iOS 27, remove the iOS 26 package and replace its styleshe
127
115
  + @use '@rdlabo/ionic-theme-ios27/src/styles/md-remove-ios-class-effect.scss';
128
116
  ```
129
117
 
130
- Change the animation import from `@rdlabo/ionic-theme-ios26` to `@rdlabo/ionic-theme-ios27`; the existing `isPlatform('ios')` configuration can stay. See the README's [iOS 27-only setup](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/readme#use-only-the-ios-27-theme). Unconditional imports apply the new styles on every browser using Ionic iOS mode.
118
+ Change the animation import from `@rdlabo/ionic-theme-ios26` to `@rdlabo/ionic-theme-ios27`; the existing `isPlatform('ios')` configuration can stay. See the [iOS 27 setup](setup.md). Unconditional imports apply the new styles on every browser using Ionic iOS mode.
131
119
 
132
120
  ## iOS 27 naming
133
121
 
134
122
  For the iOS 27 branch or an iOS 27-only app, use `@rdlabo/ionic-theme-ios27`. Its stylesheets are `ionic-theme-ios27.scss` or `ionic-theme-ios27.css`, including the `-dark-always`, `-dark-system`, and `-dark-class` variants. Keep the iOS 26 stylesheet names in the iOS 26 branch of an adaptive setup.
135
123
 
136
- Use the version-independent `--ios-theme-*` CSS variables. The corresponding `--ios26-*` variables remain supported as deprecated fallbacks. When both are set, the new name takes precedence. For example, use `--ios-theme-content-box-shadow-rgb` instead of `--ios26-content-box-shadow-rgb`.
124
+ | Customization | Current name | Legacy behavior |
125
+ | ------------------- | ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
126
+ | CSS variables | `--ios-theme-*`, for example `--ios-theme-content-box-shadow-rgb` | Corresponding `--ios26-*` names remain deprecated fallbacks. Current names win when both are set. |
127
+ | Theme opt-out class | `ios-theme-disabled` | `ios26-disabled` remains a deprecated alias; migrate existing markup when convenient. |
137
128
 
138
- For opting out of the theme, use the version-independent `ios-theme-disabled` class. The `ios26-disabled` class remains supported as a deprecated alias; migrate existing markup when convenient.
129
+ Use the version-independent names for new customizations.
139
130
 
140
- See [Special markup and classes](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/special-markup) and [Default variables](../src/styles/default-variables.scss) for the current names.
131
+ See [Special markup and classes](special-markup.md) and [Default variables](../src/styles/default-variables.scss) for the current names.
141
132
 
142
133
  Earlier migration notes are preserved in the [iOS 26 migration guide](https://docs.rdlabo.dev/projects/ionic-theme-ios26/docs/migration).
143
134
 
package/docs/setup.md ADDED
@@ -0,0 +1,92 @@
1
+ # Set up the iOS 27 theme
2
+
3
+ Give an existing Ionic app the iOS 27 appearance in four steps. This guide uses the iOS 27 theme on its own and system dark mode. For browser-dependent iOS 26/27 styling or MD3, use [adaptive themes](adaptive-themes.md) instead.
4
+
5
+ ## Before you start
6
+
7
+ Use an existing Ionic Angular, React, or Vue application with Ionic `>=8.8.1 <10`. Keep Ionic's base CSS imports. Capacitor is not required, including for browser-only apps.
8
+
9
+ ## 1. Install the theme
10
+
11
+ ```sh
12
+ npm install @rdlabo/ionic-theme-ios27
13
+ ```
14
+
15
+ ## 2. Load the styles
16
+
17
+ Add these imports to your global stylesheet after Ionic's base styles. Replace an existing Ionic dark palette import rather than loading multiple palettes:
18
+
19
+ ```css
20
+ @import '@ionic/core/css/palettes/dark.system.css';
21
+ @import '@rdlabo/ionic-theme-ios27/dist/css/default-variables.css';
22
+ @import '@rdlabo/ionic-theme-ios27/dist/css/ionic-theme-ios27.css';
23
+ @import '@rdlabo/ionic-theme-ios27/dist/css/md-remove-ios-class-effect.css';
24
+ @import '@rdlabo/ionic-theme-ios27/dist/css/ionic-theme-ios27-dark-system.css';
25
+ ```
26
+
27
+ ### Choose one dark-mode pair
28
+
29
+ Use one matching Ionic palette and theme variant. Paths below are relative to `@ionic/core/css/palettes/` and `@rdlabo/ionic-theme-ios27/dist/css/` respectively.
30
+
31
+ | Mode | Ionic palette | Theme stylesheet | Activation |
32
+ | ---------------------- | ----------------- | ----------------------------------- | ----------------------------------------------- |
33
+ | System (example above) | `dark.system.css` | `ionic-theme-ios27-dark-system.css` | System appearance. |
34
+ | Manual | `dark.class.css` | `ionic-theme-ios27-dark-class.css` | Toggle `ion-palette-dark` on the document root. |
35
+ | Always dark | `dark.always.css` | `ionic-theme-ios27-dark-always.css` | Always active. |
36
+
37
+ If you also enable Native UI, these styles provide its light/dark appearance marker. Keep the Ionic palette and theme variant paired so Web and native controls agree. See [native appearance inheritance](../../capacitor-native-ui/docs/appearance.md) for the resolution order and shared rail behavior.
38
+
39
+ ## 3. Configure Ionic animations
40
+
41
+ Set these options in your existing Ionic initialization, before rendering the app:
42
+
43
+ ```ts
44
+ import { iosTransitionAnimation, popoverEnterAnimation, popoverLeaveAnimation } from '@rdlabo/ionic-theme-ios27';
45
+
46
+ const ionicConfig = {
47
+ mode: 'ios' as const,
48
+ navAnimation: iosTransitionAnimation,
49
+ popoverEnter: popoverEnterAnimation,
50
+ popoverLeave: popoverLeaveAnimation,
51
+ };
52
+ ```
53
+
54
+ This example deliberately uses `ios` mode so desktop browsers show the theme too. Pass `ionicConfig` to the initializer your app already uses:
55
+
56
+ | Framework | Apply the options |
57
+ | ----------------- | ---------------------------------------------------------------------------- |
58
+ | Angular / Ionic 8 | `provideIonicAngular(ionicConfig)` imported from `@ionic/angular/standalone` |
59
+ | Angular / Ionic 9 | `provideIonicAngular(ionicConfig)` imported from `@ionic/angular` |
60
+ | React | `setupIonicReact(ionicConfig)` imported from `@ionic/react` |
61
+ | Vue | `app.use(IonicVue, ionicConfig)` with `IonicVue` from `@ionic/vue` |
62
+
63
+ Merge with existing options; do not initialize Ionic twice. To retain Material Design mode on Android, keep your platform-based mode selection and apply these animation options only to the iOS configuration. See [adaptive themes](adaptive-themes.md) for a complete platform-aware example.
64
+
65
+ ## 4. Preview your first screen
66
+
67
+ Start your application's usual development server and open an existing page. Add this markup inside its `ion-content` (use your framework's component syntax):
68
+
69
+ ```html
70
+ <ion-list inset="true">
71
+ <ion-item-group>
72
+ <ion-item><ion-label>Notifications</ion-label></ion-item>
73
+ <ion-item><ion-label>Appearance</ion-label></ion-item>
74
+ </ion-item-group>
75
+ </ion-list>
76
+ ```
77
+
78
+ You should see an inset group with rounded edges. Switch the system between light and dark appearance, then navigate between pages to see the theme transition. Read [Using ion-item-group](using-ion-item-group.md) for list structure.
79
+
80
+ | If you see… | Check… |
81
+ | ----------------------------------- | ------------------------------------------------------------- |
82
+ | Material Design controls on desktop | Set `mode: 'ios'` in the existing Ionic initializer. |
83
+ | Unstyled controls | Load the theme stylesheet globally after Ionic's base styles. |
84
+ | Mixed light and dark surfaces | Use one matching Ionic palette and theme dark-mode variant. |
85
+ | Default page transitions | Pass the animation options before Ionic initializes. |
86
+
87
+ ## Next steps
88
+
89
+ - [Customize styles and components](features.md).
90
+ - [Add Native UI](add-native-ui.md) for supported controls in a Capacitor iOS app. Theme installation alone does not enable native controls.
91
+ - [Add Vertical Bars with an existing theme](../../capacitor-native-ui/docs/ionic-vertical-bars.md).
92
+ - [Migrate an existing app](migration.md).
@@ -28,15 +28,38 @@ buttons: [
28
28
  ];
29
29
  ```
30
30
 
31
- Buttons with no role or `default` keep the normal text color. `cancel` retains Ionic's cancellation behavior, `selected` remains a selection state, and `destructive` uses `--ios-theme-destructive-color`. An existing `confirm` role is not treated as preferred. Use `preferred` for the recommended action, not simply any action that confirms a choice.
31
+ Choose the role by action semantics:
32
+
33
+ | Role | Appearance and behavior |
34
+ | -------------------- | ------------------------------------------------------------------------------------------------- |
35
+ | `preferred` | Filled primary action; dismissal reports `preferred`. Does not automatically select or invoke it. |
36
+ | No role or `default` | Normal text color. |
37
+ | `cancel` | Retains Ionic's cancellation behavior. |
38
+ | `selected` | Retains selection state. |
39
+ | `destructive` | Uses `--ios-theme-destructive-color`. |
40
+ | `confirm` | Not treated as preferred. Use `preferred` for a recommended action, not simply any confirmation. |
32
41
 
33
42
  ## Floating iPad sheets
34
43
 
35
- Set `expandToScroll: false` on a sheet modal to use floating lower corners and a 20px bottom gap on iPad. Ionic then sizes the visible page at each breakpoint, so the theme can style it with CSS alone. Content scrolls within the current breakpoint; dragging the handle still resizes the sheet. With the default `expandToScroll: true`, the sheet keeps Ionic's bottom-attached layout and scroll-to-expand behavior.
44
+ Choose the sheet's scrolling behavior with `expandToScroll`:
45
+
46
+ | Setting | iPad appearance | Scrolling and resizing |
47
+ | ---------------- | --------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
48
+ | `false` | Floating lower corners and a 20px bottom gap. | Content scrolls within the current breakpoint; dragging the handle resizes the sheet. Ionic sizes the visible page at each breakpoint so CSS can style it. |
49
+ | `true` (default) | Ionic's bottom-attached layout. | Scroll-to-expand behavior. |
36
50
 
37
51
  ## Tab bar position
38
52
 
39
- Add one of `tab-bar-position-start`, `tab-bar-position-center`, or `tab-bar-position-end` to an iOS `ion-tab-bar` to position the whole bar within its safe area. These classes work with both `slot="top"` and `slot="bottom"` and preserve the bar's width and press animation. Start and end follow the text direction (reversed in RTL). Without a class, the existing placement is unchanged.
53
+ Choose a class on an iOS `ion-tab-bar` to position the whole bar within its safe area:
54
+
55
+ | Class | Placement |
56
+ | ------------------------- | ------------------------------- |
57
+ | `tab-bar-position-start` | Start of the reading direction. |
58
+ | `tab-bar-position-center` | Center. |
59
+ | `tab-bar-position-end` | End of the reading direction. |
60
+ | None | Existing placement unchanged. |
61
+
62
+ All three classes support `slot="top"` and `slot="bottom"`, preserve width and press animation, and resolve start/end in RTL.
40
63
 
41
64
  ```html
42
65
  <ion-tab-bar slot="bottom" class="tab-bar-position-center">
@@ -47,15 +70,15 @@ Add one of `tab-bar-position-start`, `tab-bar-position-center`, or `tab-bar-posi
47
70
 
48
71
  These classes do not reposition a separate `ion-fab`; leave room for it when choosing the bar's position.
49
72
 
50
- ## Support iPhone Duo (preview)
73
+ ## Support iPhone Duo
51
74
 
52
- iPhone Duo support, including standalone vertical bars, is available as a **preview** in `1.2.0` alongside Native UI Shell. Its APIs and supported behavior may change.
75
+ iPhone Duo support, including standalone Vertical Bars, is stable starting with version 2.0.0.
53
76
 
54
- iPhone Duo support — the vertical system rail, hinge posture, and the posture-driven split-pane layout — is independent of the iOS 27 theme and the full Native UI Shell. See [iPhone Duo support](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/iphone-duo) for the complete setup, including device-layout monitoring without a projection runtime.
77
+ iPhone Duo support — the vertical system rail, hinge posture, and the posture-driven split-pane layout — is independent of the iOS 27 theme and the full Native UI. See [iPhone Duo support](https://github.com/rdlabo-dev/ionic-theme-ios27/blob/main/packages/theme-ios27/docs/iphone-duo.md) for the complete setup, including device-layout monitoring without a projection runtime.
55
78
 
56
- See [Vertical Bars](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/vertical-bars) for rail layout classes, control eligibility and native button appearance.
79
+ See [Vertical Bars](https://github.com/rdlabo-dev/ionic-theme-ios27/blob/main/packages/capacitor-native-ui/docs/vertical-bars.md) for rail layout classes, control eligibility and native button appearance.
57
80
 
58
- For standalone setup while keeping your existing theme, see [iPhone Duo with your existing theme](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/iphone-duo-with-original-theme).
81
+ For standalone setup while keeping your existing theme, see [iPhone Duo with your existing theme](https://github.com/rdlabo-dev/ionic-theme-ios27/blob/main/packages/capacitor-native-ui/docs/ionic-vertical-bars.md).
59
82
 
60
83
  ## Two-line inset list items
61
84
 
@@ -115,7 +138,15 @@ For colored segments, use Ionic's `color` property (for example, `color="primary
115
138
 
116
139
  Add `.segment-expand` when segment buttons should divide the available width evenly. The class also changes the Liquid Glass effect sizing when `registerSegmentEffect` is used.
117
140
 
118
- Segments use a 32px minimum height in content and a 48px minimum height inside `ion-toolbar`. `.segment-expand` keeps the compact 32px layout in a toolbar. Compact segments retain Ionic's flat background and indicator colors; only the regular toolbar variant has a glass container and scales its outer container while pressed. Content and expanded segments keep their outer bounds. The optional moving glass lens is independent of the container's background.
141
+ ### Segment size and press behavior
142
+
143
+ | Placement | Minimum height | Container behavior |
144
+ | ----------------------------------------- | -------------- | ---------------------------------------------------------------- |
145
+ | In content | 32px | Compact, flat background and indicator; outer bounds stay fixed. |
146
+ | Inside `ion-toolbar` | 48px | Glass container; outer container scales while pressed. |
147
+ | `.segment-expand`, including in a toolbar | 32px | Compact, flat background and indicator; outer bounds stay fixed. |
148
+
149
+ The optional moving glass lens is independent of the container's background.
119
150
 
120
151
  ```html preview
121
152
  <ion-segment class="segment-expand" value="new">
@@ -178,4 +209,4 @@ Add `.ios-theme-disabled` to an individual Ionic component when it must retain I
178
209
  <ion-button>iOS 27 theme</ion-button> <ion-button class="ios-theme-disabled">Standard Ionic button</ion-button>
179
210
  ```
180
211
 
181
- For the background model behind inset lists, see [Using `ion-item-group`](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/using-ion-item-group).
212
+ For the background model behind inset lists, see [Using `ion-item-group`](using-ion-item-group.md).
@@ -20,7 +20,7 @@ The examples use framework-neutral Web Component markup. In React or Vue, use th
20
20
 
21
21
  No wrapper is required for lists that do not use `inset="true"`.
22
22
 
23
- [Check list structure with ESLint](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/eslint).
23
+ [Check list structure with ESLint](eslint.md).
24
24
 
25
25
  ## Why the wrapper is required
26
26
 
@@ -44,4 +44,4 @@ When an application uses this package without `@rdlabo/ionic-theme-md3`, import
44
44
  @import '@rdlabo/ionic-theme-ios27/dist/css/md-ion-list-inset.css';
45
45
  ```
46
46
 
47
- For two-line items and section-header groups, see [Special markup and classes](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/special-markup).
47
+ For two-line items and section-header groups, see [Special markup and classes](special-markup.md).
@@ -0,0 +1,67 @@
1
+ # Vertical Bars layout
2
+
3
+ This optional theme stylesheet owns Web spacing and positioning around a vertical rail. It can be used with your existing theme without loading the full iOS 27 appearance. Native rendering and state synchronization are provided separately by [Capacitor Native UI](https://github.com/rdlabo-dev/ionic-theme-ios27/blob/main/packages/capacitor-native-ui/docs/vertical-bars.md).
4
+
5
+ ```sh
6
+ npm install @rdlabo/ionic-theme-ios27
7
+ ```
8
+
9
+ ```scss
10
+ @use '@rdlabo/ionic-theme-ios27/dist/css/vertical-bars.css';
11
+ ```
12
+
13
+ The layout behavior below assumes this stylesheet is loaded. For native runtime setup and device placement, follow the [integration guide](https://github.com/rdlabo-dev/ionic-theme-ios27/blob/main/packages/capacitor-native-ui/docs/ionic-vertical-bars.md).
14
+
15
+ ## Reserve the vertical rail
16
+
17
+ Add `.ios-theme-vertical-bars` to `ion-app` to reserve the rail region on the physical right, or add `.ios-theme-vertical-bars-left` as well to use the physical left:
18
+
19
+ ```html
20
+ <ion-app class="ios-theme-vertical-bars">...</ion-app>
21
+ ```
22
+
23
+ The classes are physical — `-left` always means the physical left edge — because CSS and the native renderer work in physical coordinates. `setVerticalBarsLayout` applies the logical `verticalBarEdge` reported by the device plugin and resolves it through the document's direction, so an RTL app does not need its own conversion.
24
+
25
+ ### Rail width
26
+
27
+ | Source | Reserved width |
28
+ | ---------------------------------------- | --------------------------------------------------------------------------------------------------- |
29
+ | Classes alone, including Chrome previews | `80px`; no native plugin required. |
30
+ | `setVerticalBarsLayout({ edge, inset })` | The supplied inset, even below `80px`. |
31
+ | Custom CSS preview | Override `--ios-theme-vertical-bars-safe-area-left` or `--ios-theme-vertical-bars-safe-area-right`. |
32
+
33
+ ### Content and overlay layout
34
+
35
+ | Surface | Layout with the rail stylesheet |
36
+ | ---------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
37
+ | Routers and component backgrounds | Remain full-viewport. |
38
+ | `ion-content` | Insets its scroll foreground. |
39
+ | `ion-toolbar` | Insets its container foreground. |
40
+ | `ion-fab` | Adjusts only when placed beside the system UI. |
41
+ | Full-width `ion-modal`, including sheets | Applies the foreground inset. With the runtime enabled, the topmost modal projects eligible toolbar controls into its own rail; sheet rails follow visible bounds as the breakpoint changes. |
42
+ | Centered modal | Keeps toolbar buttons and receives no page-rail inset. |
43
+ | `ion-menu` / `ion-popover` | Internal foreground components retain Ionic's standard safe-area handling, without the main-page conversion. |
44
+ | Menu beside the system UI | Keeps its full-viewport animation host; offsets only the visible container by the inset. |
45
+ | Menu on the opposite side | Unchanged. |
46
+
47
+ The corresponding Ionic safe-area variable is reset inside inset foreground components so descendants do not add the inset again.
48
+
49
+ Modal eligibility follows the visible dialog width, not hinge posture or modal type. Left and right remain physical coordinates in RTL; Ionic's `side="start"` and `side="end"` remain logical.
50
+
51
+ The mode is component-mode independent: an app can keep Ionic `mode: 'md'` on iOS and still enable Vertical Bars. No component needs `mode="ios"`.
52
+
53
+ ## Layout API
54
+
55
+ ```ts
56
+ import { setVerticalBarsLayout } from '@rdlabo/ionic-theme-ios27';
57
+
58
+ setVerticalBarsLayout({ edge: 'trailing', inset: 80 });
59
+ // Optionally supply a root element and explicit RTL boolean as the next arguments.
60
+ setVerticalBarsLayout({ edge: null }); // restore ordinary Web layout
61
+ ```
62
+
63
+ The helper operates on Web CSS only and works without Capacitor or Native UI startup. The application supplies device state and owns subscriptions. Starting, disabling or destroying Native UI does not change these layout classes or the reserved inset. Unsupported native rails retain the chosen Web rail; choose `edge: null` explicitly if the application wants a horizontal layout instead.
64
+
65
+ ## Migration
66
+
67
+ Move `setVerticalControlAreaPlacement` calls from the plugin to `setVerticalBarsLayout({ edge, inset })` from the theme. Move `applyFoldStateClasses` imports to the theme too. Remove `nativeEdge`: it no longer reports availability. The old plugin helpers are deprecated; update existing imports using the [migration guide](../../capacitor-native-ui/docs/migration.md#web-layout-ownership).