@rdlabo/ionic-theme-ios27 0.1.0-0 → 0.1.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.
- package/README.md +12 -10
- package/dist/css/components/ion-action-sheet.css +1 -1
- package/dist/css/components/ion-alert.css +1 -1
- package/dist/css/components/ion-button.css +1 -1
- package/dist/css/components/ion-card.css +1 -1
- package/dist/css/components/ion-content.css +1 -1
- package/dist/css/components/ion-datetime.css +1 -1
- package/dist/css/components/ion-fab.css +1 -1
- package/dist/css/components/ion-inputs.css +1 -1
- package/dist/css/components/ion-list.css +1 -1
- package/dist/css/components/ion-loading.css +1 -1
- package/dist/css/components/ion-menu.css +1 -1
- package/dist/css/components/ion-modal.css +1 -1
- package/dist/css/components/ion-popover.css +1 -1
- package/dist/css/components/ion-range.css +1 -1
- package/dist/css/components/ion-searchbar.css +1 -1
- package/dist/css/components/ion-segment.css +1 -1
- package/dist/css/components/ion-tabs.css +1 -1
- package/dist/css/components/ion-toast.css +1 -1
- package/dist/css/components/ion-toggle.css +1 -1
- package/dist/css/components/ion-toolbar.css +1 -1
- package/dist/css/ionic-theme-ios27-dark-always.css +1 -0
- package/dist/css/ionic-theme-ios27-dark-class.css +1 -0
- package/dist/css/ionic-theme-ios27-dark-system.css +1 -0
- package/dist/css/ionic-theme-ios27.css +1 -0
- package/dist/css/md-remove-ios-class-effect.css +1 -1
- package/dist/css/utils/translucent.css +1 -1
- package/dist/popover/animations/ios.enter.js +2 -2
- package/dist/popover/animations/ios.leave.js +2 -2
- package/dist/sheets-of-glass/index.js +2 -2
- package/dist/transition/ios.transition.d.ts.map +1 -1
- package/dist/transition/ios.transition.js +10 -9
- package/docs/eslint.md +1 -1
- package/docs/feedback.md +2 -2
- package/docs/ios-adaptive.md +90 -0
- package/docs/migration.md +6 -83
- package/docs/special-markup.md +5 -3
- package/docs/using-ion-item-group.md +2 -2
- package/package.json +2 -2
- package/src/popover/animations/ios.enter.ts +2 -2
- package/src/popover/animations/ios.leave.ts +2 -2
- package/src/sheets-of-glass/index.ts +2 -2
- package/src/styles/components/ion-action-sheet.scss +4 -4
- package/src/styles/components/ion-alert.scss +1 -1
- package/src/styles/components/ion-button.scss +25 -21
- package/src/styles/components/ion-card.scss +1 -1
- package/src/styles/components/ion-content.scss +10 -8
- package/src/styles/components/ion-datetime.scss +1 -1
- package/src/styles/components/ion-fab.scss +11 -9
- package/src/styles/components/ion-inputs.scss +2 -2
- package/src/styles/components/ion-list.scss +2 -2
- package/src/styles/components/ion-loading.scss +1 -1
- package/src/styles/components/ion-menu.scss +26 -21
- package/src/styles/components/ion-modal.scss +3 -3
- package/src/styles/components/ion-picker.scss +1 -1
- package/src/styles/components/ion-popover.scss +4 -3
- package/src/styles/components/ion-range.scss +2 -2
- package/src/styles/components/ion-searchbar.scss +6 -4
- package/src/styles/components/ion-segment.scss +8 -8
- package/src/styles/components/ion-tabs.scss +13 -13
- package/src/styles/components/ion-toast.scss +8 -7
- package/src/styles/components/ion-toggle.scss +4 -4
- package/src/styles/components/ion-toolbar.scss +13 -12
- package/src/styles/default-variables.scss +4 -3
- package/src/styles/md-remove-ios-class-effect.scss +2 -2
- package/src/styles/utils/api.scss +16 -16
- package/src/styles/utils/dark/ion-button.scss +8 -8
- package/src/styles/utils/dark/ion-fab.scss +1 -1
- package/src/styles/utils/dark/ion-segment.scss +3 -2
- package/src/styles/utils/dark/ion-tabs.scss +3 -2
- package/src/styles/utils/translucent.scss +21 -16
- package/src/transition/ios.transition.ts +12 -9
- package/dist/css/ionic-theme-ios26-dark-always.css +0 -1
- package/dist/css/ionic-theme-ios26-dark-class.css +0 -1
- package/dist/css/ionic-theme-ios26-dark-system.css +0 -1
- package/dist/css/ionic-theme-ios26.css +0 -1
- package/dist/docs.json +0 -234
- package/dist/focus-controller /index.d.ts +0 -6
- package/dist/focus-controller /index.d.ts.map +0 -1
- package/dist/focus-controller /index.js +0 -62
- package/docs/ios-18.md +0 -16
- /package/src/styles/{ionic-theme-ios26-dark-always.scss → ionic-theme-ios27-dark-always.scss} +0 -0
- /package/src/styles/{ionic-theme-ios26-dark-class.scss → ionic-theme-ios27-dark-class.scss} +0 -0
- /package/src/styles/{ionic-theme-ios26-dark-system.scss → ionic-theme-ios27-dark-system.scss} +0 -0
- /package/src/styles/{ionic-theme-ios26.scss → ionic-theme-ios27.scss} +0 -0
package/docs/eslint.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
title: Keep lists consistent with ESLint
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
Catch missing list groups before they reach the screen. In Ionic Angular apps, `@rdlabo/eslint-plugin-rules` checks the markup used by iOS
|
|
5
|
+
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
6
|
|
|
7
7
|
## Enable the list check
|
|
8
8
|
|
package/docs/feedback.md
CHANGED
|
@@ -31,7 +31,7 @@ export interface IonicConfig {
|
|
|
31
31
|
|
|
32
32
|
### native-inner(or item-inner) part to ion-item
|
|
33
33
|
|
|
34
|
-
The styling for `ion-item[lines=inset]` is applied to `.item-inner`, which cannot be styled directly. This limitation means that for iOS
|
|
34
|
+
The styling for `ion-item[lines=inset]` is applied to `.item-inner`, which cannot be styled directly. This limitation means that for iOS 27 styling, I can only modify the border-bottom style through `::part(native)` with padding-right, preventing me from utilizing the full right side of `ion-item`. Adding `::part(native-inner)` would increase styling flexibility.
|
|
35
35
|
|
|
36
36
|
```diff
|
|
37
37
|
<ion-item>
|
|
@@ -54,7 +54,7 @@ Resolved.
|
|
|
54
54
|
|
|
55
55
|
### should disable ion-back-button Animation
|
|
56
56
|
|
|
57
|
-
Resolved: by created https://github.com/rdlabo-dev/ionic-theme-
|
|
57
|
+
Resolved: by created https://github.com/rdlabo-dev/ionic-theme-ios27/tree/main/src/transition
|
|
58
58
|
|
|
59
59
|
## feat(): ion-content[fullscreen=true] will have .content-fullscreen class
|
|
60
60
|
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Adaptive iOS themes
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# Adaptive iOS themes
|
|
6
|
+
|
|
7
|
+
Use CSS feature queries to choose a theme while keeping Ionic's default iOS styles on older browsers. Safari 27 adds `:heading` support; see the [WebKit announcement](https://webkit.org/blog/17967/news-from-wwdc26-webkit-in-safari-27-beta/).
|
|
8
|
+
|
|
9
|
+
These checks detect browser capabilities, not the operating system version. Other browsers may support the same features. Keep Ionic mode and platform-specific animation configuration consistent with your application.
|
|
10
|
+
|
|
11
|
+
## Load only the iOS 27 theme
|
|
12
|
+
|
|
13
|
+
In your global Sass stylesheet, use `meta.load-css` inside the feature query. Unlike `@use`, it can emit the theme inside `@supports`.
|
|
14
|
+
|
|
15
|
+
```scss
|
|
16
|
+
@use 'sass:meta';
|
|
17
|
+
|
|
18
|
+
@supports selector(:heading) {
|
|
19
|
+
@include meta.load-css('@rdlabo/ionic-theme-ios27/src/styles/default-variables');
|
|
20
|
+
@include meta.load-css('@rdlabo/ionic-theme-ios27/src/styles/ionic-theme-ios27');
|
|
21
|
+
@include meta.load-css('@rdlabo/ionic-theme-ios27/src/styles/ionic-theme-ios27-dark-class');
|
|
22
|
+
@include meta.load-css('@rdlabo/ionic-theme-ios27/src/styles/md-remove-ios-class-effect');
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Use the iOS 26 and iOS 27 themes together
|
|
27
|
+
|
|
28
|
+
Install both packages:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install @rdlabo/ionic-theme-ios26 @rdlabo/ionic-theme-ios27
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Use this global Sass configuration instead of unconditional theme imports:
|
|
35
|
+
|
|
36
|
+
```scss
|
|
37
|
+
@use 'sass:meta';
|
|
38
|
+
|
|
39
|
+
@supports selector(:heading) {
|
|
40
|
+
@include meta.load-css('@rdlabo/ionic-theme-ios27/src/styles/default-variables');
|
|
41
|
+
@include meta.load-css('@rdlabo/ionic-theme-ios27/src/styles/ionic-theme-ios27');
|
|
42
|
+
@include meta.load-css('@rdlabo/ionic-theme-ios27/src/styles/ionic-theme-ios27-dark-class');
|
|
43
|
+
@include meta.load-css('@rdlabo/ionic-theme-ios27/src/styles/md-remove-ios-class-effect');
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
@supports (text-wrap: pretty) and (not selector(:heading)) {
|
|
47
|
+
@include meta.load-css('@rdlabo/ionic-theme-ios26/src/styles/default-variables');
|
|
48
|
+
@include meta.load-css('@rdlabo/ionic-theme-ios26/src/styles/ionic-theme-ios26');
|
|
49
|
+
@include meta.load-css('@rdlabo/ionic-theme-ios26/src/styles/ionic-theme-ios26-dark-class');
|
|
50
|
+
@include meta.load-css('@rdlabo/ionic-theme-ios26/src/styles/md-remove-ios-class-effect');
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The branches are mutually exclusive. Browsers without either feature retain Ionic's default styling. The `text-wrap: pretty` check preserves the earlier theme's capability-based fallback for older Safari versions.
|
|
55
|
+
|
|
56
|
+
Both examples use class-based dark mode. Load Ionic's matching dark palette in your application; for system or always-dark mode, replace the `-dark-class` imports with the matching variant. If you also use `md-ion-list-inset`, load the corresponding package's stylesheet inside each branch.
|
|
57
|
+
|
|
58
|
+
## Select matching JavaScript animations
|
|
59
|
+
|
|
60
|
+
Use the same feature checks for dynamic imports before initializing Ionic. Call this loader for the iOS platform; leave other platforms on their existing animation configuration.
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
async function loadIOSAnimations() {
|
|
64
|
+
if (typeof CSS === 'undefined') {
|
|
65
|
+
return {};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const theme = CSS.supports('selector(:heading)')
|
|
69
|
+
? await import('@rdlabo/ionic-theme-ios27')
|
|
70
|
+
: CSS.supports('text-wrap: pretty')
|
|
71
|
+
? await import('@rdlabo/ionic-theme-ios26')
|
|
72
|
+
: undefined;
|
|
73
|
+
|
|
74
|
+
if (!theme) {
|
|
75
|
+
return {};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
navAnimation: theme.iosTransitionAnimation,
|
|
80
|
+
popoverEnter: theme.popoverEnterAnimation,
|
|
81
|
+
popoverLeave: theme.popoverLeaveAnimation,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// In your browser bootstrap, before initializing Ionic:
|
|
86
|
+
const animations = isPlatform('ios') ? await loadIOSAnimations() : {};
|
|
87
|
+
provideIonicAngular({ ...animations });
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Import `isPlatform` and `provideIonicAngular` from your Ionic Angular entry point as shown in the README. Pass the same options to `setupIonicReact` or `IonicVue` when using those frameworks. The imports are selected at runtime; the bundler may still emit chunks for both packages. In server-rendered apps, run the selection during browser initialization.
|
package/docs/migration.md
CHANGED
|
@@ -4,91 +4,14 @@ title: Migration
|
|
|
4
4
|
|
|
5
5
|
# Migration
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
## iOS 27 naming
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
Use `@rdlabo/ionic-theme-ios27` for the current theme. Update stylesheet imports to `ionic-theme-ios27.scss` or `ionic-theme-ios27.css`, including the `-dark-always`, `-dark-system`, and `-dark-class` variants.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
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`.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
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.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
See [Special markup and classes](./special-markup.md) and [Default variables](../src/styles/default-variables.scss) for the current names.
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
### Rename `.header-item-group` to `.item-group-header`
|
|
20
|
-
|
|
21
|
-
The class for an `ion-item-group` used as a section header has been renamed for consistency with the element it modifies. Replace every occurrence of `.header-item-group` in application templates and styles.
|
|
22
|
-
|
|
23
|
-
```diff
|
|
24
|
-
- <ion-item-group class="header-item-group">
|
|
25
|
-
+ <ion-item-group class="item-group-header">
|
|
26
|
-
...
|
|
27
|
-
</ion-item-group>
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
The old class is no longer styled by the theme. This rename applies to markup shared with `@rdlabo/ionic-theme-md3` as well.
|
|
31
|
-
|
|
32
|
-
## Migrating to 2.0.0
|
|
33
|
-
|
|
34
|
-
### Configure `iosTransitionAnimation`
|
|
35
|
-
|
|
36
|
-
Version 2 requires the package navigation transition. It follows Ionic's default iOS transition without the obsolete `animateBackButton()` behavior that animated a Large Title into the back-button label.
|
|
37
|
-
|
|
38
|
-
```ts
|
|
39
|
-
import { isPlatform } from '@ionic/core'; // or @ionic/angular/standalone, @ionic/react, @ionic/vue
|
|
40
|
-
import { iosTransitionAnimation } from '@rdlabo/ionic-theme-ios26';
|
|
41
|
-
|
|
42
|
-
// Angular
|
|
43
|
-
provideIonicAngular({
|
|
44
|
-
// ...
|
|
45
|
-
navAnimation: isPlatform('ios') ? iosTransitionAnimation : undefined,
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
// React
|
|
49
|
-
setupIonicReact({
|
|
50
|
-
// ...
|
|
51
|
-
navAnimation: isPlatform('ios') ? iosTransitionAnimation : undefined,
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
// Vue
|
|
55
|
-
createApp(App).use(IonicVue, {
|
|
56
|
-
// ...
|
|
57
|
-
navAnimation: isPlatform('ios') ? iosTransitionAnimation : undefined,
|
|
58
|
-
});
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
With this transition configured, `<ion-buttons><ion-back-button></ion-back-button></ion-buttons>` can be used without the unwanted transition side effects caused by the old animation.
|
|
62
|
-
|
|
63
|
-
## Migrating to 1.0.0
|
|
64
|
-
|
|
65
|
-
### Update SCSS import paths
|
|
66
|
-
|
|
67
|
-
The source files moved under `src/styles` when JavaScript files were added to the package.
|
|
68
|
-
|
|
69
|
-
```diff
|
|
70
|
-
- @import '@rdlabo/ionic-theme-ios26/src/default-variables.scss';
|
|
71
|
-
+ @import '@rdlabo/ionic-theme-ios26/src/styles/default-variables.scss';
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
Generated CSS paths under `dist` did not change.
|
|
75
|
-
|
|
76
|
-
### Rename `--ios26-color-background-rgb`
|
|
77
|
-
|
|
78
|
-
```diff
|
|
79
|
-
:root {
|
|
80
|
-
- --ios26-color-background-rgb: 255, 255, 255;
|
|
81
|
-
+ --ios26-content-box-shadow-rgb: 255, 255, 255;
|
|
82
|
-
}
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
### Rename brightness variables
|
|
86
|
-
|
|
87
|
-
Replace each `--ion-color-*-brightness-rgb` variable with `--ion-color-*-brightness` and use a color value instead of an RGB channel list.
|
|
88
|
-
|
|
89
|
-
```diff
|
|
90
|
-
:root {
|
|
91
|
-
- --ion-color-primary-brightness-rgb: 130, 255, 255;
|
|
92
|
-
+ --ion-color-primary-brightness: #96feff;
|
|
93
|
-
}
|
|
94
|
-
```
|
|
17
|
+
Earlier migration notes are preserved on the [previous theme branch](https://github.com/rdlabo-dev/ionic-theme-ios27/blob/ios26/docs/migration.md).
|
package/docs/special-markup.md
CHANGED
|
@@ -79,7 +79,7 @@ Add `.segment-expand` when segment buttons should divide the available width eve
|
|
|
79
79
|
|
|
80
80
|
## Classic search bar in a condense header
|
|
81
81
|
|
|
82
|
-
The theme gives iOS search bars the iOS
|
|
82
|
+
The theme gives iOS search bars the iOS 27 appearance by default. Add `.searchbar-classic` to the search field shown beneath a large title in an `ion-header` with `collapse="condense"`. It uses the conventional filled iOS appearance and collapses with the large title instead of remaining in the fixed header.
|
|
83
83
|
|
|
84
84
|
Place it in a toolbar with a color, such as `color="light"`; the classic background is derived from that color's contrast value.
|
|
85
85
|
|
|
@@ -136,10 +136,12 @@ Add `.toolbar-searchbar` when an `ion-toolbar` combines a search bar with start
|
|
|
136
136
|
|
|
137
137
|
## Opting out
|
|
138
138
|
|
|
139
|
-
Add `.
|
|
139
|
+
Add `.ios-theme-disabled` to an individual Ionic component when it must retain Ionic's standard iOS styling.
|
|
140
|
+
|
|
141
|
+
`.ios26-disabled` is deprecated but remains supported as an alias with the same behavior. Use `.ios-theme-disabled` for new code.
|
|
140
142
|
|
|
141
143
|
```html preview
|
|
142
|
-
<ion-button>iOS
|
|
144
|
+
<ion-button>iOS 27 theme</ion-button> <ion-button class="ios-theme-disabled">Standard Ionic button</ion-button>
|
|
143
145
|
```
|
|
144
146
|
|
|
145
147
|
For the background model behind inset lists, see [Using `ion-item-group`](./using-ion-item-group.md).
|
|
@@ -24,9 +24,9 @@ No wrapper is required for lists that do not use `inset="true"`.
|
|
|
24
24
|
|
|
25
25
|
## Why the wrapper is required
|
|
26
26
|
|
|
27
|
-
Ionic normally gives `ion-list` its background, which makes `ion-list-header` appear inside the same surface as the items. The iOS
|
|
27
|
+
Ionic normally gives `ion-list` its background, which makes `ion-list-header` appear inside the same surface as the items. The iOS 27 layout treats the header and item surface separately.
|
|
28
28
|
|
|
29
|
-

|
|
30
30
|
|
|
31
31
|
The theme therefore:
|
|
32
32
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rdlabo/ionic-theme-ios27",
|
|
3
3
|
"private": false,
|
|
4
|
-
"version": "0.1.0-
|
|
4
|
+
"version": "0.1.0-1",
|
|
5
5
|
"description": "iOS27 Theme for Ionic Framework",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"bugs": {
|
|
47
47
|
"url": "https://github.com/rdlabo-dev/ionic-theme-ios27/issues"
|
|
48
48
|
},
|
|
49
|
-
"homepage": "https://docs.rdlabo.dev/projects/ionic-theme-
|
|
49
|
+
"homepage": "https://docs.rdlabo.dev/projects/ionic-theme-ios27",
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"@ionic/angular": "^9.0.0",
|
|
52
52
|
"husky": "^9.1.7",
|
|
@@ -27,7 +27,7 @@ export const iosEnterAnimation = (baseEl: HTMLElement, opts?: any): Animation =>
|
|
|
27
27
|
if (!['ion-button', 'ion-buttons'].includes(referenceSizeEl.localName)) {
|
|
28
28
|
return false;
|
|
29
29
|
}
|
|
30
|
-
if (referenceSizeEl.
|
|
30
|
+
if (referenceSizeEl.matches('.ios-theme-disabled, .ios26-disabled')) {
|
|
31
31
|
return false;
|
|
32
32
|
}
|
|
33
33
|
return true;
|
|
@@ -102,7 +102,7 @@ export const iosEnterAnimation = (baseEl: HTMLElement, opts?: any): Animation =>
|
|
|
102
102
|
.duration(200)
|
|
103
103
|
.addElement(referenceSizeEl)
|
|
104
104
|
.beforeStyles({ 'transform-origin': `${originY} ${originX}` })
|
|
105
|
-
.beforeAddClass('
|
|
105
|
+
.beforeAddClass('ios27-replace-element')
|
|
106
106
|
.fromTo('transform', 'scale(1)', 'scale(1.05)')
|
|
107
107
|
.fromTo('opacity', 1, 0);
|
|
108
108
|
}
|
|
@@ -17,7 +17,7 @@ export const iosLeaveAnimation = (baseEl: HTMLElement): Animation => {
|
|
|
17
17
|
const targetAnimation = createAnimation();
|
|
18
18
|
|
|
19
19
|
const doc = baseEl.ownerDocument as any;
|
|
20
|
-
const replaceElement = doc.querySelector('.
|
|
20
|
+
const replaceElement = doc.querySelector('.ios27-replace-element') as HTMLElement | null;
|
|
21
21
|
|
|
22
22
|
if (replaceElement) {
|
|
23
23
|
const ratio = contentEl.getBoundingClientRect().width / contentEl.getBoundingClientRect().height;
|
|
@@ -27,7 +27,7 @@ export const iosLeaveAnimation = (baseEl: HTMLElement): Animation => {
|
|
|
27
27
|
.addElement(replaceElement)
|
|
28
28
|
.delay(100)
|
|
29
29
|
.duration(300)
|
|
30
|
-
.afterRemoveClass('
|
|
30
|
+
.afterRemoveClass('ios27-replace-element')
|
|
31
31
|
.fromTo('transform', `scale(${scale})`, 'scale(1)')
|
|
32
32
|
.fromTo('opacity', 0, 0.9);
|
|
33
33
|
}
|
|
@@ -4,8 +4,8 @@ import type { Animation, Gesture, GestureDetail } from '@ionic/core';
|
|
|
4
4
|
import { changeSelectedElement, cloneElement, getStep } from '../utils';
|
|
5
5
|
import { createMoveAnimation, createPreMoveAnimation, getMoveAnimationKeyframe, getScaleAnimation } from './animations';
|
|
6
6
|
|
|
7
|
-
const GESTURE_NAME = '
|
|
8
|
-
const ANIMATED_NAME = '
|
|
7
|
+
const GESTURE_NAME = 'ios27-enable-gesture';
|
|
8
|
+
const ANIMATED_NAME = 'ios27-animated';
|
|
9
9
|
|
|
10
10
|
export const registerEffect = (
|
|
11
11
|
targetElement: HTMLElement,
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
@use '../utils/api';
|
|
2
2
|
|
|
3
|
-
ion-action-sheet.ios:not(.ios26-disabled) {
|
|
3
|
+
ion-action-sheet.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
4
4
|
--backdrop-opacity: 0.2;
|
|
5
5
|
--color: var(--ion-color-step-600, var(--ion-text-color-step-400, #666666));
|
|
6
6
|
|
|
7
7
|
.action-sheet-wrapper {
|
|
8
8
|
padding-bottom: 0;
|
|
9
|
-
bottom: var(--ios26-floating-safe-area-bottom);
|
|
9
|
+
bottom: var(--ios-theme-floating-safe-area-bottom, var(--ios26-floating-safe-area-bottom));
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
.action-sheet-container {
|
|
@@ -71,10 +71,10 @@ ion-action-sheet.ios:not(.ios26-disabled) {
|
|
|
71
71
|
|
|
72
72
|
/**
|
|
73
73
|
* For ion-select[interface=action-sheet].
|
|
74
|
-
*
|
|
74
|
+
* ios27, action-sheet should not has 'cancel'.
|
|
75
75
|
* It is recommend to use Popover.
|
|
76
76
|
*/
|
|
77
|
-
ion-action-sheet.ios.select-action-sheet:not(.ios26-disabled) {
|
|
77
|
+
ion-action-sheet.ios.select-action-sheet:not(.ios-theme-disabled, .ios26-disabled) {
|
|
78
78
|
.action-sheet-container {
|
|
79
79
|
.action-sheet-group {
|
|
80
80
|
button.action-sheet-cancel {
|
|
@@ -23,7 +23,7 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only;
|
|
|
23
23
|
/**
|
|
24
24
|
* compare .header-collapse-main ion-toolbar.in-toolbar ion-title, .header-collapse-main ion-toolbar.in-toolbar ion-buttons
|
|
25
25
|
*/
|
|
26
|
-
transition: transform var(--ios26-activated-transition-duration) ease-out;
|
|
26
|
+
transition: transform var(--ios-theme-activated-transition-duration, var(--ios26-activated-transition-duration)) ease-out;
|
|
27
27
|
|
|
28
28
|
z-index: 0;
|
|
29
29
|
|
|
@@ -59,11 +59,11 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only;
|
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
&:has(ion-button:not(.ios26-disabled).button-clear.button-large) {
|
|
62
|
+
&:has(ion-button:not(.ios-theme-disabled, .ios26-disabled).button-clear.button-large) {
|
|
63
63
|
border-radius: 30px;
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
ion-button:not(.ios26-disabled).button-clear {
|
|
66
|
+
ion-button:not(.ios-theme-disabled, .ios26-disabled).button-clear {
|
|
67
67
|
--background: transparent;
|
|
68
68
|
--border-style: none;
|
|
69
69
|
--border-width: 0;
|
|
@@ -121,11 +121,11 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only;
|
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
|
|
124
|
-
ion-button:not(.ios26-disabled) {
|
|
124
|
+
ion-button:not(.ios-theme-disabled, .ios26-disabled) {
|
|
125
125
|
margin: 0;
|
|
126
126
|
}
|
|
127
127
|
|
|
128
|
-
ion-menu-button:not(.ios26-disabled) {
|
|
128
|
+
ion-menu-button:not(.ios-theme-disabled, .ios26-disabled) {
|
|
129
129
|
width: 44px;
|
|
130
130
|
height: 44px;
|
|
131
131
|
padding: 2px;
|
|
@@ -140,7 +140,7 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only;
|
|
|
140
140
|
}
|
|
141
141
|
|
|
142
142
|
transition:
|
|
143
|
-
transform var(--ios26-activated-transition-duration) ease-out,
|
|
143
|
+
transform var(--ios-theme-activated-transition-duration, var(--ios26-activated-transition-duration)) ease-out,
|
|
144
144
|
color 50ms ease;
|
|
145
145
|
|
|
146
146
|
&.in-toolbar:not(.ion-color):not(.in-toolbar-color) {
|
|
@@ -153,13 +153,13 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only;
|
|
|
153
153
|
}
|
|
154
154
|
|
|
155
155
|
// will-change is optimized to only apply when needed for performance
|
|
156
|
-
&:not(.ios26-disabled):hover,
|
|
157
|
-
&:not(.ios26-disabled):active,
|
|
158
|
-
&:not(.ios26-disabled).ion-activated {
|
|
156
|
+
&:not(.ios-theme-disabled, .ios26-disabled):hover,
|
|
157
|
+
&:not(.ios-theme-disabled, .ios26-disabled):active,
|
|
158
|
+
&:not(.ios-theme-disabled, .ios26-disabled).ion-activated {
|
|
159
159
|
will-change: transform;
|
|
160
160
|
}
|
|
161
161
|
|
|
162
|
-
&:not(.ios26-disabled):not(:hover):not(:active):not(.ion-activated) {
|
|
162
|
+
&:not(.ios-theme-disabled, .ios26-disabled):not(:hover):not(:active):not(.ion-activated) {
|
|
163
163
|
will-change: auto;
|
|
164
164
|
}
|
|
165
165
|
|
|
@@ -248,8 +248,8 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only;
|
|
|
248
248
|
}
|
|
249
249
|
} @else {
|
|
250
250
|
--box-shadow:
|
|
251
|
-
inset 0 0 8px 0 rgba(var(--ios26-glass-box-shadow-color-rgb), 0.2),
|
|
252
|
-
0 0 8px -4px rgba(var(--ios26-glass-box-shadow-color-rgb), 0.92);
|
|
251
|
+
inset 0 0 8px 0 rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), 0.2),
|
|
252
|
+
0 0 8px -4px rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), 0.92);
|
|
253
253
|
}
|
|
254
254
|
&::part(native)::before {
|
|
255
255
|
content: '';
|
|
@@ -313,13 +313,13 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only;
|
|
|
313
313
|
|
|
314
314
|
// fill:default only
|
|
315
315
|
&:not(.button-solid):not(.button-outline):not(.button-clear) {
|
|
316
|
-
--background: rgba(var(--ios26-glass-background-rgb), 0.72);
|
|
316
|
+
--background: rgba(var(--ios-theme-glass-background-rgb, var(--ios26-glass-background-rgb)), 0.72);
|
|
317
317
|
--background-hover: transparent;
|
|
318
318
|
--background-activated: transparent;
|
|
319
319
|
@if not $is-back-button {
|
|
320
320
|
--box-shadow:
|
|
321
|
-
inset 0 0 8px 0 rgba(var(--ios26-glass-box-shadow-color-rgb), 0.2),
|
|
322
|
-
0 0.5px 1px 0 rgba(var(--ios26-glass-box-shadow-color-rgb), 0.08);
|
|
321
|
+
inset 0 0 8px 0 rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), 0.2),
|
|
322
|
+
0 0.5px 1px 0 rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), 0.08);
|
|
323
323
|
}
|
|
324
324
|
|
|
325
325
|
&:not(.button-has-icon-only):not(.back-button-has-icon-only) {
|
|
@@ -409,18 +409,22 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only;
|
|
|
409
409
|
}
|
|
410
410
|
}
|
|
411
411
|
|
|
412
|
-
ion-buttons.ios:not(.
|
|
412
|
+
ion-buttons.ios:not(.ios-theme-disabled, .ios26-disabled):not(
|
|
413
|
+
:has(ion-back-button, ion-button:not(.button-clear), ion-menu-button.menu-button-hidden)
|
|
414
|
+
) {
|
|
413
415
|
@include theme-buttons;
|
|
414
416
|
}
|
|
415
417
|
|
|
416
418
|
// Ionic's collapsing-header transition has a more specific contextual selector.
|
|
417
419
|
.header-collapse-main
|
|
418
420
|
:where(ion-toolbar.in-toolbar)
|
|
419
|
-
ion-buttons.ios:not(.
|
|
420
|
-
|
|
421
|
+
ion-buttons.ios:not(.ios-theme-disabled, .ios26-disabled):not(
|
|
422
|
+
:has(ion-back-button, ion-button:not(.button-clear), ion-menu-button.menu-button-hidden)
|
|
423
|
+
) {
|
|
424
|
+
transition: transform var(--ios-theme-activated-transition-duration, var(--ios26-activated-transition-duration)) ease-out;
|
|
421
425
|
}
|
|
422
426
|
|
|
423
|
-
ion-buttons.ios:not(.ios26-disabled):not(:has(ion-back-button, ion-button.button-clear)) {
|
|
427
|
+
ion-buttons.ios:not(.ios-theme-disabled, .ios26-disabled):not(:has(ion-back-button, ion-button.button-clear)) {
|
|
424
428
|
ion-button {
|
|
425
429
|
margin: 0 6px;
|
|
426
430
|
&:first-child {
|
|
@@ -435,9 +439,9 @@ ion-buttons.ios:not(.ios26-disabled):not(:has(ion-back-button, ion-button.button
|
|
|
435
439
|
}
|
|
436
440
|
}
|
|
437
441
|
|
|
438
|
-
ion-button.ios:not(.ios26-disabled) {
|
|
442
|
+
ion-button.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
439
443
|
@include theme-button;
|
|
440
444
|
}
|
|
441
|
-
ion-back-button.ios:not(.ios26-disabled) {
|
|
445
|
+
ion-back-button.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
442
446
|
@include theme-button($is-back-button: true);
|
|
443
447
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Since
|
|
2
|
+
* Since iOS27, content is now displayed to the full extent of the top and bottom safe areas,
|
|
3
3
|
* so we adjust the margin and padding of the content.
|
|
4
4
|
* Also supports virtual scrolling using .ion-content-scroll-host.
|
|
5
5
|
*/
|
|
6
|
-
.ion-page.ios:not(.ios26-disabled):has(ion-header.header-translucent)
|
|
7
|
-
ion-content.ios:not(.ios26-disabled).content-fullscreen:has(.ion-content-scroll-host) {
|
|
6
|
+
.ion-page.ios:not(.ios-theme-disabled, .ios26-disabled):has(ion-header.header-translucent)
|
|
7
|
+
ion-content.ios:not(.ios-theme-disabled, .ios26-disabled).content-fullscreen:has(.ion-content-scroll-host) {
|
|
8
8
|
--padding-top: calc(var(--offset-top) * -1);
|
|
9
9
|
> *:not(.ion-content-scroll-host, ion-fab) {
|
|
10
10
|
transform: translateY(var(--offset-top));
|
|
@@ -13,10 +13,12 @@
|
|
|
13
13
|
padding-top: var(--offset-top);
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
|
-
.ion-page.ios:not(.ios26-disabled):not(:has(ion-footer))
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
.ion-page.ios:not(.ios-theme-disabled, .ios26-disabled):not(:has(ion-footer))
|
|
17
|
+
ion-content.ios:not(.ios-theme-disabled, .ios26-disabled).content-fullscreen
|
|
18
|
+
.ion-content-scroll-host {
|
|
19
|
+
margin-bottom: calc(calc(60px + var(--ios-theme-floating-safe-area-bottom, var(--ios26-floating-safe-area-bottom))) * -1);
|
|
20
|
+
padding-bottom: calc(60px + var(--ios-theme-floating-safe-area-bottom, var(--ios26-floating-safe-area-bottom)));
|
|
19
21
|
}
|
|
20
|
-
ion-content.ios:not(.ios26-disabled).content-fullscreen:not(:has(.ion-content-scroll-host)) {
|
|
21
|
-
--padding-bottom: calc(60px + var(--ios26-floating-safe-area-bottom));
|
|
22
|
+
ion-content.ios:not(.ios-theme-disabled, .ios26-disabled).content-fullscreen:not(:has(.ion-content-scroll-host)) {
|
|
23
|
+
--padding-bottom: calc(60px + var(--ios-theme-floating-safe-area-bottom, var(--ios26-floating-safe-area-bottom)));
|
|
22
24
|
}
|
|
@@ -4,19 +4,21 @@ $scaleup-small-icon-only: api.$button-scaleup-small-icon-only;
|
|
|
4
4
|
$scaleup-default-icon-only: api.$button-scaleup-default-icon-only;
|
|
5
5
|
$scaleup-large-icon-only: api.$button-scaleup-large-icon-only;
|
|
6
6
|
|
|
7
|
-
ion-fab.ios:not(.ios26-disabled) {
|
|
7
|
+
ion-fab.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
8
8
|
--transform-value: 2.5px;
|
|
9
9
|
&:has(> ion-fab-button.fab-button-small) {
|
|
10
10
|
--transform-value: 4px;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
ion-fab-button {
|
|
14
|
-
--background: rgba(var(--ios26-glass-background-rgb), 0.72);
|
|
14
|
+
--background: rgba(var(--ios-theme-glass-background-rgb, var(--ios26-glass-background-rgb)), 0.72);
|
|
15
15
|
--box-shadow:
|
|
16
|
-
inset 0 0 8px 0 rgba(var(--
|
|
16
|
+
inset 0 0 8px 0 rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), 0.2),
|
|
17
|
+
0 0.5px 1px 0 rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), 0.08);
|
|
17
18
|
--transition:
|
|
18
|
-
var(--ios26-activated-transition-duration) transform
|
|
19
|
-
|
|
19
|
+
var(--ios-theme-activated-transition-duration, var(--ios26-activated-transition-duration)) transform
|
|
20
|
+
cubic-bezier(0.25, 1.11, 0.78, 1.59),
|
|
21
|
+
var(--ios-theme-activated-transition-duration, var(--ios26-activated-transition-duration)) color ease;
|
|
20
22
|
--background-activated-opacity: 0;
|
|
21
23
|
--background-focused-opacity: 0;
|
|
22
24
|
--background-hover-opacity: 0;
|
|
@@ -77,15 +79,15 @@ ion-fab.ios:not(.ios26-disabled) {
|
|
|
77
79
|
}
|
|
78
80
|
|
|
79
81
|
&.fab-vertical-top {
|
|
80
|
-
top: var(--ios26-floating-safe-area-top);
|
|
82
|
+
top: var(--ios-theme-floating-safe-area-top, var(--ios26-floating-safe-area-top));
|
|
81
83
|
}
|
|
82
84
|
|
|
83
85
|
&.fab-vertical-bottom {
|
|
84
|
-
bottom: var(--ios26-floating-safe-area-bottom);
|
|
86
|
+
bottom: var(--ios-theme-floating-safe-area-bottom, var(--ios26-floating-safe-area-bottom));
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
&.fab-horizontal-start {
|
|
88
|
-
left: calc(16px + var(--ios26-menu-width, var(--ion-safe-area-left), 0px));
|
|
90
|
+
left: calc(16px + var(--ios-theme-menu-width, var(--ios26-menu-width, var(--ion-safe-area-left), 0px)));
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
&.fab-horizontal-end {
|
|
@@ -94,7 +96,7 @@ ion-fab.ios:not(.ios26-disabled) {
|
|
|
94
96
|
|
|
95
97
|
&:has(.fab-button-small) {
|
|
96
98
|
&.fab-horizontal-start {
|
|
97
|
-
left: calc(10px + var(--ios26-menu-width, var(--ion-safe-area-left), 0px));
|
|
99
|
+
left: calc(10px + var(--ios-theme-menu-width, var(--ios26-menu-width, var(--ion-safe-area-left), 0px)));
|
|
98
100
|
}
|
|
99
101
|
|
|
100
102
|
&.fab-horizontal-end {
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
57
|
-
ion-input.ios:not(.ios26-disabled) {
|
|
57
|
+
ion-input.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
58
58
|
&.input-fill-outline {
|
|
59
59
|
@include outline-field('input');
|
|
60
60
|
|
|
@@ -65,7 +65,7 @@ ion-input.ios:not(.ios26-disabled) {
|
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
ion-textarea.ios:not(.ios26-disabled) {
|
|
68
|
+
ion-textarea.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
69
69
|
&.textarea-fill-outline {
|
|
70
70
|
@include outline-field('textarea');
|
|
71
71
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
@use '../utils/structured-list';
|
|
2
2
|
|
|
3
|
-
ion-list.ios:not(.ios26-disabled) {
|
|
3
|
+
ion-list.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
4
4
|
@include structured-list.support-text;
|
|
5
5
|
ion-item {
|
|
6
6
|
--background-hover-opacity: 0;
|
|
@@ -8,7 +8,7 @@ ion-list.ios:not(.ios26-disabled) {
|
|
|
8
8
|
}
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
ion-list.list-inset.ios:not(.ios26-disabled) {
|
|
11
|
+
ion-list.list-inset.ios:not(.ios-theme-disabled, .ios26-disabled) {
|
|
12
12
|
@include structured-list.layout(20px, 24px);
|
|
13
13
|
|
|
14
14
|
ion-radio-group,
|