@rdlabo/ionic-theme-ios27 1.2.0-beta.pr243.shae972a0e49191 → 1.2.0-beta.pr246.sha237333ceac21
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 +8 -8
- package/dist/css/ionic-theme-ios27.css +1 -1
- package/dist/css/vertical-bars.css +1 -1
- package/dist/native/definitions.d.ts.map +1 -1
- package/dist/native/prehide.js +2 -0
- package/dist/native/prehide.js.map +1 -1
- package/dist/native/shared/candidate.js +3 -2
- package/dist/native/shared/candidate.js.map +1 -1
- package/dist/native/shared/dom.d.ts +1 -1
- package/dist/native/shared/dom.js +4 -4
- package/dist/native/shared/dom.js.map +1 -1
- package/docs/features.md +2 -2
- package/docs/iphone-duo-with-original-theme.md +7 -9
- package/docs/iphone-duo.md +3 -3
- package/docs/native-ui-shell.md +11 -9
- package/docs/special-markup.md +2 -2
- package/docs/vertical-bars.md +20 -13
- package/package.json +1 -1
- package/src/native/definitions.ts +4 -3
- package/src/native/prehide.ts +3 -1
- package/src/native/shared/candidate.ts +10 -6
- package/src/native/shared/dom.ts +4 -4
- package/src/styles/vertical-bars.scss +3 -2
package/docs/native-ui-shell.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: Native UI Shell (
|
|
2
|
+
title: Native UI Shell (Preview)
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
# Native UI Shell (
|
|
5
|
+
# Native UI Shell (Preview)
|
|
6
6
|
|
|
7
|
-
Native UI Shell is
|
|
7
|
+
Native UI Shell is available as a **preview** in `1.2.0`. Its API and supported controls may change before stable status. Stable status is planned after the official release of Xcode 27.1.
|
|
8
8
|
|
|
9
9
|
Native UI Shell gives an Ionic app native navigation and action controls around its Web content. The optional Capacitor iOS plugin renders supported fixed Ionic controls with UIKit or SwiftUI and the system's Liquid Glass material. Page content, scrolling, application state and routing remain in Ionic's WebView.
|
|
10
10
|
|
|
@@ -52,12 +52,14 @@ The table below describes the ordinary Native UI Shell. Vertical Bars uses the s
|
|
|
52
52
|
| `ion-segment` | Fixed toolbar, non-scrollable, text **or** one icon per item | `UISegmentedControl` |
|
|
53
53
|
| `ion-fab` / `ion-fab-button` / `ion-fab-list` | Glass FAB in an `ion-content` fixed slot; one main button and optional directional lists | Persistent glass `UIButton` per button; one FAB synchronization group |
|
|
54
54
|
|
|
55
|
-
For the ordinary Native UI Shell, only iOS-mode components with the theme variables installed are eligible. Explicitly enabled Vertical Bars is mode-independent as described below. `
|
|
55
|
+
For the ordinary Native UI Shell, only iOS-mode components with the theme variables installed are eligible. Explicitly enabled Vertical Bars is mode-independent as described below. `ios-theme-disabled` and the legacy `ios26-disabled` on an element or ancestor always exclude it. A disabled theme on one tab/segment item keeps its whole group on the Web.
|
|
56
56
|
|
|
57
|
-
Use `ios-theme-shell-disabled` to disable only the iOS Native UI Shell while keeping the Web theme. It excludes the element and all its descendants. Adding or removing the class at runtime automatically restores Web rendering or re-evaluates native eligibility.
|
|
57
|
+
Use `data-shell="disabled"` (or the equivalent `ios-theme-shell-disabled` class) to disable only the iOS Native UI Shell while keeping the Web theme. It excludes the element and all its descendants. Adding or removing the attribute or class at runtime automatically restores Web rendering or re-evaluates native eligibility.
|
|
58
|
+
|
|
59
|
+
Only the exact value `disabled` opts out; an empty or unknown value is ignored. Remove the attribute to re-enable projection. If the class is also present, remove both to re-enable projection. This does not disable clicks or change the Web theme. The data attribute is available in `1.2.0`.
|
|
58
60
|
|
|
59
61
|
```html
|
|
60
|
-
<ion-toolbar
|
|
62
|
+
<ion-toolbar data-shell="disabled">
|
|
61
63
|
<ion-button>Web glass button</ion-button>
|
|
62
64
|
</ion-toolbar>
|
|
63
65
|
```
|
|
@@ -171,9 +173,9 @@ Suspensions are nestable and `resume()` is idempotent. Native projection resumes
|
|
|
171
173
|
|
|
172
174
|
The native material and control appearance follow the running iOS version; an iOS 26 device does not acquire iOS 27's appearance merely by installing this theme.
|
|
173
175
|
|
|
174
|
-
## Support iPhone Duo (
|
|
176
|
+
## Support iPhone Duo (preview)
|
|
175
177
|
|
|
176
|
-
iPhone Duo support
|
|
178
|
+
iPhone Duo support, including standalone vertical bars without Native UI Shell, is available as a **preview** in `1.2.0` alongside Native UI Shell. Its APIs and supported behavior may change.
|
|
177
179
|
|
|
178
180
|
The standalone Vertical Control Area entry point (`@rdlabo/ionic-theme-ios27/vertical-bars`) and `dist/css/vertical-bars.css` work without loading the iOS 27 theme. Call `enableVerticalControlArea()` for this use case; it projects only controls placed in the vertical area. Apps already calling `enableNativeUIShell()` should keep that single runtime rather than starting both. See [iPhone Duo support](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/iphone-duo) for the complete setup, including hinge posture and the split-pane layout for apps that do not use this shell at all.
|
|
179
181
|
|
|
@@ -181,7 +183,7 @@ Vertical Bars uses a SwiftUI `TabView` and toolbar in the system rail. Ionic rem
|
|
|
181
183
|
|
|
182
184
|
In Vertical Bars, fixed-toolbar `ion-button` actions need an `ion-icon` or SVG with `slot="icon-only"`. All fills and Ionic colors are eligible; submit buttons follow the same placement rule. Add `.ios-theme-horizontal-only` to a button or its `ion-buttons` group to keep it horizontal. See [Toolbar actions](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/vertical-bars#toolbar-actions) for placement and exclusion rules.
|
|
183
185
|
|
|
184
|
-
**
|
|
186
|
+
**Native button appearance:** `1.2.0` defaults native vertical buttons to `buttonProjection: 'system'`. Use `source` to project Ionic fill and colors, with `data-projection="source|system"` or the equivalent `ios-theme-projection-source` / `ios-theme-projection-system` classes for local exceptions. These settings affect native vertical `ion-button` and `ion-menu-button` actions only. Horizontal controls and Web clones keep their existing behavior. See [Choose button appearance](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/vertical-bars#choose-button-appearance) for migration, priority and fill rules.
|
|
185
187
|
|
|
186
188
|
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).
|
|
187
189
|
|
package/docs/special-markup.md
CHANGED
|
@@ -47,9 +47,9 @@ Add one of `tab-bar-position-start`, `tab-bar-position-center`, or `tab-bar-posi
|
|
|
47
47
|
|
|
48
48
|
These classes do not reposition a separate `ion-fab`; leave room for it when choosing the bar's position.
|
|
49
49
|
|
|
50
|
-
## Support iPhone Duo (
|
|
50
|
+
## Support iPhone Duo (preview)
|
|
51
51
|
|
|
52
|
-
iPhone Duo support
|
|
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.
|
|
53
53
|
|
|
54
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.
|
|
55
55
|
|
package/docs/vertical-bars.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
---
|
|
2
|
-
title: Vertical Bars (
|
|
2
|
+
title: Vertical Bars (preview)
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
# Vertical Bars (
|
|
5
|
+
# Vertical Bars (preview)
|
|
6
6
|
|
|
7
7
|
Vertical Bars moves eligible Ionic navigation and actions into a side rail while keeping the original components as the source of labels, icons and behavior. It works with this theme or an existing Ionic theme, independently of hinge posture and the full Native UI Shell.
|
|
8
8
|
|
|
9
9
|
Use this page for layout, control eligibility, native button appearance and the runtime API. For device events and split panes, see [iPhone Duo support](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/iphone-duo). For a step-by-step browser preview and native setup, start with [iPhone Duo with your existing theme](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/iphone-duo-with-original-theme).
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
Available in `1.2.0` as a **preview** feature. APIs and supported behavior may change.
|
|
12
12
|
|
|
13
13
|
## Enable Vertical Bars
|
|
14
14
|
|
|
@@ -87,7 +87,7 @@ The rule applies to individual buttons and buttons inside `ion-buttons`, on ordi
|
|
|
87
87
|
|
|
88
88
|
### Choose button appearance
|
|
89
89
|
|
|
90
|
-
|
|
90
|
+
`buttonProjection` and the local projection settings below are available in `1.2.0`.
|
|
91
91
|
|
|
92
92
|
For native vertical `ion-button` and `ion-menu-button` actions, choose who controls appearance:
|
|
93
93
|
|
|
@@ -102,18 +102,23 @@ const rail = await enableVerticalControlArea({ buttonProjection: 'source' });
|
|
|
102
102
|
|
|
103
103
|
Both `enableVerticalControlArea()` and `enableNativeUIShell()` accept the option. Use one runtime, and destroy it before restarting with different options. Either mode preserves actions, disabled state and grouping. These appearance settings do not affect horizontal controls, source elements or Web fallback clones, so compare the native appearance on supported iOS.
|
|
104
104
|
|
|
105
|
-
**Migration:** the default changes from source styling to `system`. Set `buttonProjection: 'source'` to retain the previous projection behavior.
|
|
105
|
+
**Migration from the experimental releases:** the default changes from source styling to `system`. Set `buttonProjection: 'source'` to retain the previous projection behavior.
|
|
106
106
|
|
|
107
107
|
### Override individual buttons or groups
|
|
108
108
|
|
|
109
|
-
Use `
|
|
109
|
+
Use `data-projection` for local exceptions. Existing classes remain supported:
|
|
110
|
+
|
|
111
|
+
| Attribute | Equivalent class |
|
|
112
|
+
| --- | --- |
|
|
113
|
+
| `data-projection="source"` | `ios-theme-projection-source` |
|
|
114
|
+
| `data-projection="system"` | `ios-theme-projection-system` |
|
|
110
115
|
|
|
111
116
|
```html
|
|
112
|
-
<ion-buttons
|
|
117
|
+
<ion-buttons data-projection="source">
|
|
113
118
|
<ion-button fill="solid" aria-label="Add">
|
|
114
119
|
<ion-icon name="add-outline" slot="icon-only"></ion-icon>
|
|
115
120
|
</ion-button>
|
|
116
|
-
<ion-button
|
|
121
|
+
<ion-button data-projection="system" aria-label="Search">
|
|
117
122
|
<ion-icon name="search-outline" slot="icon-only"></ion-icon>
|
|
118
123
|
</ion-button>
|
|
119
124
|
</ion-buttons>
|
|
@@ -121,11 +126,13 @@ Use `ios-theme-projection-source` or `ios-theme-projection-system` for local exc
|
|
|
121
126
|
|
|
122
127
|
The first matching setting wins:
|
|
123
128
|
|
|
124
|
-
1. The button's
|
|
125
|
-
2. Its nearest `ion-buttons`
|
|
129
|
+
1. The button's local setting.
|
|
130
|
+
2. Its nearest `ion-buttons` local setting.
|
|
126
131
|
3. The startup `buttonProjection` option, or `system` if omitted.
|
|
127
132
|
|
|
128
|
-
|
|
133
|
+
On the same element, a valid `data-projection` value takes precedence over the classes. Empty or unknown values are ignored. Without a valid attribute, `system` wins if both classes are present. Removing an attribute falls back to the element's classes, then the next level above. Attribute and class changes apply without restarting the runtime; grouping and placement stay unchanged.
|
|
134
|
+
|
|
135
|
+
Only native vertical `ion-button` and `ion-menu-button` actions interpret these settings. Other ancestors, back buttons, tabs and FABs do not. They do not change Web styling. To keep a control or subtree on the Web entirely, use [`data-shell="disabled"`](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/native-ui-shell#supported-markup).
|
|
129
136
|
|
|
130
137
|
### Source fill rules
|
|
131
138
|
|
|
@@ -146,7 +153,7 @@ const rail = await enableVerticalControlArea({ buttonDefaultFill: 'solid' });
|
|
|
146
153
|
|
|
147
154
|
```html
|
|
148
155
|
<!-- In a fixed toolbar, outside ion-buttons: omitted fill resolves to solid. -->
|
|
149
|
-
<ion-button
|
|
156
|
+
<ion-button data-projection="source" aria-label="Add">
|
|
150
157
|
<ion-icon name="add-outline" slot="icon-only"></ion-icon>
|
|
151
158
|
</ion-button>
|
|
152
159
|
```
|
|
@@ -158,7 +165,7 @@ const rail = await enableVerticalControlArea({ buttonDefaultFill: 'solid' });
|
|
|
158
165
|
| `outline` | Computed border color and width, with native glass |
|
|
159
166
|
| `null` | Native glass with source icon colors |
|
|
160
167
|
|
|
161
|
-
Inside `ion-buttons`, explicitly set `fill="solid"` to project a background; `buttonDefaultFill: 'solid'` does not override the group's clear default. Native Liquid Glass tinting can differ from the CSS color, especially for translucent backgrounds. With the iOS theme, ordinary `ion-buttons` retain group projection; `ion-buttons.ios-theme-disabled` projects eligible buttons individually.
|
|
168
|
+
Inside `ion-buttons`, explicitly set `fill="solid"` to project a background; `buttonDefaultFill: 'solid'` does not override the group's clear default. Native Liquid Glass tinting can differ from the CSS color, especially for translucent backgrounds. With the iOS theme, ordinary `ion-buttons` retain group projection; `ion-buttons.ios-theme-disabled` projects eligible buttons individually. Local projection settings do not change that grouping rule.
|
|
162
169
|
|
|
163
170
|
## Tab bar
|
|
164
171
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rdlabo/ionic-theme-ios27",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "1.2.0-beta.
|
|
4
|
+
"version": "1.2.0-beta.pr246.sha237333ceac21",
|
|
5
5
|
"description": "iOS27 Theme for Ionic Framework",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -13,9 +13,10 @@ export interface NativeUIShellStatus {
|
|
|
13
13
|
export interface VerticalControlAreaOptions {
|
|
14
14
|
/** Appearance of native vertical ion-button and ion-menu-button actions.
|
|
15
15
|
* `system` (default) uses SwiftUI styling and template icons; `source` projects supported Ionic fill and colors.
|
|
16
|
-
* Local ios-theme-projection-source / ios-theme-projection-system
|
|
17
|
-
* the button itself, then its nearest ion-buttons, then this option. On the same element,
|
|
18
|
-
*
|
|
16
|
+
* Local data-projection="source|system" or ios-theme-projection-source / ios-theme-projection-system take precedence:
|
|
17
|
+
* the button itself, then its nearest ion-buttons, then this option. On the same element, a valid attribute wins;
|
|
18
|
+
* otherwise system wins if both classes are present. Invalid attribute values are ignored.
|
|
19
|
+
* Local settings update live; removing them restores inheritance. Actions, disabled state and grouping are preserved.
|
|
19
20
|
* Does not affect back buttons, tabs, FABs, horizontal controls, source elements or Web clones.
|
|
20
21
|
*/
|
|
21
22
|
buttonProjection?: 'source' | 'system';
|
package/src/native/prehide.ts
CHANGED
|
@@ -74,6 +74,8 @@ export const prehideVerticalBarsToolbarSources = (doc: Document): { suspend: ()
|
|
|
74
74
|
};
|
|
75
75
|
const sources = scope.matches('ion-back-button') ? [scope] : Array.from(scope.querySelectorAll<HTMLElement>(sourceSelector));
|
|
76
76
|
sources.forEach((element) => {
|
|
77
|
+
// Shell opt-out is temporary; decide initial placement once it is lifted.
|
|
78
|
+
if (isShellDisabled(element)) return;
|
|
77
79
|
if (!modalUsesVerticalBars(element) || element.closest(overlays) || (scope.matches('.ion-page') && routedPage(element) !== scope))
|
|
78
80
|
return;
|
|
79
81
|
if (element.matches('ion-buttons')) {
|
|
@@ -228,7 +230,7 @@ export const prehideVerticalBarsToolbarSources = (doc: Document): { suspend: ()
|
|
|
228
230
|
childList: true,
|
|
229
231
|
attributes: true,
|
|
230
232
|
attributeOldValue: true,
|
|
231
|
-
attributeFilter: ['class', 'hidden', 'inert', 'icon', 'color'],
|
|
233
|
+
attributeFilter: ['class', 'data-shell', 'hidden', 'inert', 'icon', 'color'],
|
|
232
234
|
});
|
|
233
235
|
return {
|
|
234
236
|
suspend: () => {
|
|
@@ -65,13 +65,17 @@ export const appendItem = (
|
|
|
65
65
|
const badgeStyle = badge && visible(badge) ? getComputedStyle(badge) : undefined;
|
|
66
66
|
const sourceFill = (child as HTMLIonButtonElement).fill;
|
|
67
67
|
const projectionOwner = [child, child.closest('ion-buttons')].find((element) =>
|
|
68
|
-
element?.matches('.ios-theme-projection-source, .ios-theme-projection-system'),
|
|
68
|
+
element?.matches('[data-projection="source"], [data-projection="system"], .ios-theme-projection-source, .ios-theme-projection-system'),
|
|
69
69
|
);
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
70
|
+
const attributeProjection = projectionOwner?.getAttribute('data-projection');
|
|
71
|
+
const projection =
|
|
72
|
+
attributeProjection === 'source' || attributeProjection === 'system'
|
|
73
|
+
? attributeProjection
|
|
74
|
+
: projectionOwner
|
|
75
|
+
? projectionOwner.classList.contains('ios-theme-projection-system')
|
|
76
|
+
? 'system'
|
|
77
|
+
: 'source'
|
|
78
|
+
: candidate.buttonProjection;
|
|
75
79
|
const systemButton = projection !== 'source' && isVerticalBarsSource(child) && child.matches('ion-button, ion-menu-button');
|
|
76
80
|
// Ionic defaults buttons inside ion-buttons to clear, even when the app defaults to solid.
|
|
77
81
|
const defaultFill = child.closest('ion-buttons') ? 'clear' : candidate.buttonDefaultFill;
|
package/src/native/shared/dom.ts
CHANGED
|
@@ -52,7 +52,7 @@ export const isDark = (style: CSSStyleDeclaration): boolean => {
|
|
|
52
52
|
const background = style.getPropertyValue('--ion-background-color-rgb').match(/\d+/g)?.slice(0, 3).map(Number);
|
|
53
53
|
return !!background && background.length === 3 && background[0] * 0.2126 + background[1] * 0.7152 + background[2] * 0.0722 < 128;
|
|
54
54
|
};
|
|
55
|
-
const permanentlyExcluded = '.
|
|
55
|
+
const permanentlyExcluded = '.ios-theme-disabled, .ios26-disabled, .ion-cloned-element, [hidden], [inert]';
|
|
56
56
|
export const excluded = `${permanentlyExcluded}, .ion-page-hidden, .ion-page-invisible`;
|
|
57
57
|
const enteringPages = new WeakSet<HTMLElement>();
|
|
58
58
|
export const setVerticalBarsEnteringPage = (page: HTMLElement, entering: boolean): void => {
|
|
@@ -88,8 +88,8 @@ export const createVerticalBarsPageState = () => {
|
|
|
88
88
|
},
|
|
89
89
|
};
|
|
90
90
|
};
|
|
91
|
-
const disabledButtonGroup = 'ion-buttons:is(.
|
|
92
|
-
const shellDisabledSelector = '.ios-theme-shell-disabled';
|
|
91
|
+
const disabledButtonGroup = 'ion-buttons:is(.ios-theme-disabled, .ios26-disabled)';
|
|
92
|
+
const shellDisabledSelector = '.ios-theme-shell-disabled, [data-shell="disabled"]';
|
|
93
93
|
|
|
94
94
|
export const isDisabledButtonGroupChild = (element: HTMLElement): boolean =>
|
|
95
95
|
element.matches('ion-button') && element.parentElement?.matches(disabledButtonGroup) === true;
|
|
@@ -188,7 +188,7 @@ export const isVerticalBarsToolbarGroup = (element: HTMLElement): boolean => {
|
|
|
188
188
|
return (
|
|
189
189
|
element.matches('ion-buttons') &&
|
|
190
190
|
verticalBarsOwned(element) &&
|
|
191
|
-
!element.matches('.
|
|
191
|
+
!element.matches('.ios-theme-disabled, .ios26-disabled') &&
|
|
192
192
|
!isShellDisabled(element)
|
|
193
193
|
);
|
|
194
194
|
};
|
|
@@ -283,7 +283,8 @@ html.ios-theme-native-ui-shell-prehide
|
|
|
283
283
|
[icon],
|
|
284
284
|
[color],
|
|
285
285
|
.ios-theme-vertical-bars-back-web-owned,
|
|
286
|
-
.
|
|
286
|
+
.ios-theme-shell-disabled,
|
|
287
|
+
[data-shell='disabled'],
|
|
287
288
|
.ios-theme-disabled,
|
|
288
289
|
.ios26-disabled,
|
|
289
290
|
.ios-theme-vertical-bars-back-button-projection
|
|
@@ -296,7 +297,7 @@ html.ios-theme-native-ui-shell-prehide
|
|
|
296
297
|
ion-footer[collapse] *,
|
|
297
298
|
ion-buttons.ios-theme-horizontal-only *,
|
|
298
299
|
.ios-theme-shell-disabled *,
|
|
299
|
-
|
|
300
|
+
[data-shell='disabled'] *,
|
|
300
301
|
.ios-theme-disabled *,
|
|
301
302
|
.ios26-disabled *
|
|
302
303
|
)
|