From e1f84f6a81f261908d280b9cb52b75ae6f8cd069 Mon Sep 17 00:00:00 2001 From: rdlabo Date: Thu, 10 Sep 2026 17:06:04 +0900 Subject: [PATCH 1/7] refactor: align theme names with iOS 27 and remove SwiftUI demo --- README.md | 15 +- demo/README.md | 4 +- demo/capacitor.config.ts | 4 +- demo/ios/App/App.xcodeproj/project.pbxproj | 4 +- demo/ios/App/App/Info.plist | 2 +- demo/src/app/album/album-page.component.html | 2 +- demo/src/app/docs/docs-content.generated.ts | 2 +- demo/src/app/docs/docs-page.component.html | 2 +- demo/src/app/index/index-page.component.html | 2 +- .../index/pages/accordion/accordion.page.html | 2 +- .../pages/action-sheet/action-sheet.page.html | 2 +- .../src/app/index/pages/alert/alert.page.html | 2 +- .../pages/breadcrumbs/breadcrumbs.page.html | 2 +- .../app/index/pages/button/button.page.html | 6 +- demo/src/app/index/pages/card/card.page.html | 2 +- .../index/pages/checkbox/checkbox.page.html | 2 +- demo/src/app/index/pages/chip/chip.page.html | 12 +- .../date-and-time-pickers.page.html | 2 +- .../floating-action-button-fixed.page.html | 2 +- .../floating-action-button.page.html | 2 +- .../app/index/pages/inputs/inputs.page.html | 2 +- .../src/app/index/pages/modal/modal.page.html | 2 +- .../app/index/pages/popover/popover.page.html | 2 +- .../progress-indicators.page.html | 2 +- .../src/app/index/pages/radio/radio.page.html | 2 +- .../src/app/index/pages/range/range.page.html | 2 +- .../app/index/pages/reorder/reorder.page.html | 2 +- .../index/pages/searchbar/searchbar.page.html | 10 +- .../app/index/pages/segment/segment.page.html | 4 +- .../app/index/pages/select/select.page.html | 2 +- demo/src/app/index/pages/tabs/tabs.page.html | 2 +- .../src/app/index/pages/toast/toast.page.html | 2 +- .../app/index/pages/toggle/toggle.page.html | 2 +- .../app/index/pages/toolbar/toolbar.page.html | 2 +- .../app/settings/settings-page.component.html | 4 +- demo/src/global.scss | 8 +- demo/src/index.html | 2 +- docs/eslint.md | 2 +- docs/feedback.md | 4 +- docs/ios-18.md | 2 +- docs/migration.md | 89 +---- docs/special-markup.md | 6 +- docs/using-ion-item-group.md | 4 +- package.json | 2 +- screenshots/{ios26.png => legacy-theme.png} | Bin src/popover/animations/ios.enter.ts | 4 +- src/popover/animations/ios.leave.ts | 4 +- src/sheets-of-glass/index.ts | 4 +- src/styles/components/ion-action-sheet.scss | 8 +- src/styles/components/ion-alert.scss | 2 +- src/styles/components/ion-button.scss | 42 +-- src/styles/components/ion-card.scss | 2 +- src/styles/components/ion-content.scss | 16 +- src/styles/components/ion-datetime.scss | 2 +- src/styles/components/ion-fab.scss | 18 +- src/styles/components/ion-inputs.scss | 4 +- src/styles/components/ion-list.scss | 4 +- src/styles/components/ion-loading.scss | 2 +- src/styles/components/ion-menu.scss | 44 +-- src/styles/components/ion-modal.scss | 6 +- src/styles/components/ion-picker.scss | 2 +- src/styles/components/ion-popover.scss | 6 +- src/styles/components/ion-range.scss | 4 +- src/styles/components/ion-searchbar.scss | 8 +- src/styles/components/ion-segment.scss | 16 +- src/styles/components/ion-tabs.scss | 26 +- src/styles/components/ion-toast.scss | 14 +- src/styles/components/ion-toggle.scss | 8 +- src/styles/components/ion-toolbar.scss | 24 +- src/styles/default-variables.scss | 26 +- ...css => ionic-theme-ios27-dark-always.scss} | 0 ...scss => ionic-theme-ios27-dark-class.scss} | 0 ...css => ionic-theme-ios27-dark-system.scss} | 0 ...heme-ios26.scss => ionic-theme-ios27.scss} | 0 src/styles/md-remove-ios-class-effect.scss | 4 +- src/styles/utils/api.scss | 32 +- src/styles/utils/dark/ion-button.scss | 16 +- src/styles/utils/dark/ion-fab.scss | 2 +- src/styles/utils/dark/ion-segment.scss | 6 +- src/styles/utils/dark/ion-tabs.scss | 6 +- src/styles/utils/theme-dark.scss | 12 +- src/styles/utils/translucent.scss | 32 +- src/transition/ios.transition.ts | 18 +- .../project.pbxproj | 337 ------------------ .../contents.xcworkspacedata | 7 - .../UserInterfaceState.xcuserstate | Bin 22818 -> 0 bytes .../xcschemes/xcschememanagement.plist | 14 - .../AccentColor.colorset/Contents.json | 11 - .../AppIcon.appiconset/Contents.json | 35 -- .../Assets.xcassets/Contents.json | 6 - swiftui/ionic-ios26-native/ContentView.swift | 11 - .../ionic-ios26-native/Theme/IOS26Theme.swift | 35 -- .../Views/ComponentDetailView.swift | 28 -- .../ionic-ios26-native/Views/IndexView.swift | 112 ------ .../ionic_ios26_nativeApp.swift | 10 - 95 files changed, 289 insertions(+), 975 deletions(-) rename screenshots/{ios26.png => legacy-theme.png} (100%) rename src/styles/{ionic-theme-ios26-dark-always.scss => ionic-theme-ios27-dark-always.scss} (100%) rename src/styles/{ionic-theme-ios26-dark-class.scss => ionic-theme-ios27-dark-class.scss} (100%) rename src/styles/{ionic-theme-ios26-dark-system.scss => ionic-theme-ios27-dark-system.scss} (100%) rename src/styles/{ionic-theme-ios26.scss => ionic-theme-ios27.scss} (100%) delete mode 100644 swiftui/ionic-ios26-native.xcodeproj/project.pbxproj delete mode 100644 swiftui/ionic-ios26-native.xcodeproj/project.xcworkspace/contents.xcworkspacedata delete mode 100644 swiftui/ionic-ios26-native.xcodeproj/project.xcworkspace/xcuserdata/sakakibara.xcuserdatad/UserInterfaceState.xcuserstate delete mode 100644 swiftui/ionic-ios26-native.xcodeproj/xcuserdata/sakakibara.xcuserdatad/xcschemes/xcschememanagement.plist delete mode 100644 swiftui/ionic-ios26-native/Assets.xcassets/AccentColor.colorset/Contents.json delete mode 100644 swiftui/ionic-ios26-native/Assets.xcassets/AppIcon.appiconset/Contents.json delete mode 100644 swiftui/ionic-ios26-native/Assets.xcassets/Contents.json delete mode 100644 swiftui/ionic-ios26-native/ContentView.swift delete mode 100644 swiftui/ionic-ios26-native/Theme/IOS26Theme.swift delete mode 100644 swiftui/ionic-ios26-native/Views/ComponentDetailView.swift delete mode 100644 swiftui/ionic-ios26-native/Views/IndexView.swift delete mode 100644 swiftui/ionic-ios26-native/ionic_ios26_nativeApp.swift diff --git a/README.md b/README.md index c7405139..3855c6c3 100644 --- a/README.md +++ b/README.md @@ -25,13 +25,11 @@ Requires `@ionic/core` 8.8.1 or later (Ionic 8 and 9). After the first npm relea npm install @rdlabo/ionic-theme-ios27 ``` -The stylesheet filenames still use `ionic-theme-ios26` inside the new package. Use the paths below to load the iOS 27 theme. - And import the theme in your project's main CSS file (e.g., `src/styles.scss`). ```css @import '@rdlabo/ionic-theme-ios27/dist/css/default-variables.css'; -@import '@rdlabo/ionic-theme-ios27/dist/css/ionic-theme-ios26.css'; +@import '@rdlabo/ionic-theme-ios27/dist/css/ionic-theme-ios27.css'; /** * Keep Material Design mode unaffected by the iOS theme @@ -50,9 +48,9 @@ And import the theme in your project's main CSS file (e.g., `src/styles.scss`). /* * Support Dark Mode * We support Ionic Dark Mode. More information is here: https://ionicframework.com/docs/theming/dark-mode - * use Always: @import '@rdlabo/ionic-theme-ios27/dist/css/ionic-theme-ios26-dark-always.css' - * use System: @import '@rdlabo/ionic-theme-ios27/dist/css/ionic-theme-ios26-dark-system.css' - * use CSS Class: @import '@rdlabo/ionic-theme-ios27/dist/css/ionic-theme-ios26-dark-class.css' + * use Always: @import '@rdlabo/ionic-theme-ios27/dist/css/ionic-theme-ios27-dark-always.css' + * use System: @import '@rdlabo/ionic-theme-ios27/dist/css/ionic-theme-ios27-dark-system.css' + * use CSS Class: @import '@rdlabo/ionic-theme-ios27/dist/css/ionic-theme-ios27-dark-class.css' */ ``` @@ -119,8 +117,8 @@ When your global stylesheet uses Sass, initialize the themes in this order: ```scss @use '@rdlabo/ionic-theme-ios27/src/styles/default-variables.scss' as ios27-vars; -@use '@rdlabo/ionic-theme-ios27/src/styles/ionic-theme-ios26.scss'; -@use '@rdlabo/ionic-theme-ios27/src/styles/ionic-theme-ios26-dark-class.scss'; +@use '@rdlabo/ionic-theme-ios27/src/styles/ionic-theme-ios27.scss'; +@use '@rdlabo/ionic-theme-ios27/src/styles/ionic-theme-ios27-dark-class.scss'; @use '@rdlabo/ionic-theme-ios27/src/styles/md-remove-ios-class-effect.scss'; @use '@rdlabo/ionic-theme-md3/dist/css/default-variables.css' as md3-vars; @use '@rdlabo/ionic-theme-md3/dist/css/ionic-theme-md3.css'; @@ -168,6 +166,7 @@ createApp(App) - [ESLint](./docs/eslint.md) — check list structure with ESLint rules. - [Features](./docs/features.md) — CSS variables, Liquid Glass, selective imports, and dark mode. - [Experimental Animation](./docs/experimental-animation.md) — tab bar and searchable effects. +- [Migration](./docs/migration.md) — stylesheet, class, and CSS variable naming changes. - [iOS 26 migration history](https://github.com/rdlabo-dev/ionic-theme-ios27/blob/ios26/docs/migration.md) — earlier major-version changes for the previous package. diff --git a/demo/README.md b/demo/README.md index e6f5d38d..a846295a 100644 --- a/demo/README.md +++ b/demo/README.md @@ -1,6 +1,6 @@ # Demo Application -This is an Angular-based demo application for the Ionic iOS26 Theme Library. +This is an Angular-based demo application for the Ionic iOS27 Theme Library. ## Getting Started @@ -84,7 +84,7 @@ demo/ │ │ ├── pages/ # All page components │ │ └── index.routes.ts │ ├── theme/ -│ │ └── theme-ios26.scss # iOS26 theme +│ │ └── theme-ios27.scss # iOS27 theme │ └── global.scss ├── playwright.config.ts # Playwright configuration └── package.json diff --git a/demo/capacitor.config.ts b/demo/capacitor.config.ts index 2a9e4e8c..70129205 100644 --- a/demo/capacitor.config.ts +++ b/demo/capacitor.config.ts @@ -1,8 +1,8 @@ import type { CapacitorConfig } from '@capacitor/cli'; const config: CapacitorConfig = { - appId: 'io.ionic.theme.ios26', - appName: 'theme-ios26', + appId: 'io.ionic.theme.ios27', + appName: 'theme-ios27', webDir: 'www', }; diff --git a/demo/ios/App/App.xcodeproj/project.pbxproj b/demo/ios/App/App.xcodeproj/project.pbxproj index d1f414b8..164886b4 100644 --- a/demo/ios/App/App.xcodeproj/project.pbxproj +++ b/demo/ios/App/App.xcodeproj/project.pbxproj @@ -355,7 +355,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MARKETING_VERSION = 1.0; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\""; - PRODUCT_BUNDLE_IDENTIFIER = io.ionic.theme.ios26; + PRODUCT_BUNDLE_IDENTIFIER = io.ionic.theme.ios27; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_VERSION = 5.0; @@ -375,7 +375,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = io.ionic.theme.ios26; + PRODUCT_BUNDLE_IDENTIFIER = io.ionic.theme.ios27; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = ""; SWIFT_VERSION = 5.0; diff --git a/demo/ios/App/App/Info.plist b/demo/ios/App/App/Info.plist index 2389efbd..927649dc 100644 --- a/demo/ios/App/App/Info.plist +++ b/demo/ios/App/App/Info.plist @@ -5,7 +5,7 @@ CFBundleDevelopmentRegion en CFBundleDisplayName - theme-ios26 + theme-ios27 CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier diff --git a/demo/src/app/album/album-page.component.html b/demo/src/app/album/album-page.component.html index bc1f08ab..292c116d 100644 --- a/demo/src/app/album/album-page.component.html +++ b/demo/src/app/album/album-page.component.html @@ -2,7 +2,7 @@ Library - Select diff --git a/demo/src/app/docs/docs-content.generated.ts b/demo/src/app/docs/docs-content.generated.ts index e332be5c..e0e542ba 100644 --- a/demo/src/app/docs/docs-content.generated.ts +++ b/demo/src/app/docs/docs-content.generated.ts @@ -1,3 +1,3 @@ // Generated from docs/special-markup.md. Do not edit directly. export const docsContentHtml = - '

Special markup and classes

\n

Most Ionic markup works without changes. The combinations below are explicit opt-ins provided by the theme.

\n

Primary submit buttons

\n

Solid primary submit buttons use --ion-color-primary-brightness for their foreground and border treatment. Define a value with sufficient contrast for your primary color.

\n
:root {\n  --ion-color-primary-brightness: #96feff;\n}
\n\n
<ion-button type="submit" color="primary">Submit</ion-button>\n<ion-button class="button-submit" fill="solid" color="primary">Continue</ion-button>
\n\n
\n
Preview
\nSubmit\nContinue\n
\n\n

Use .button-submit when the button needs the same treatment but cannot use type="submit".

\n

Two-line inset list items

\n

Place an unslotted ion-label immediately alongside an unslotted ion-note to render a two-line item. When using the iOS-style inset-list background, wrap the items in ion-item-group; keep ion-list-header outside the group.

\n
<ion-list inset="true">\n  <ion-list-header>\n    <ion-label>Connections</ion-label>\n  </ion-list-header>\n  <ion-item-group>\n    <ion-item>\n      <ion-label>Network &amp; internet</ion-label>\n      <ion-note>Mobile, Wi-Fi, hotspot</ion-note>\n    </ion-item>\n  </ion-item-group>\n</ion-list>
\n\n
\n
Preview
\n\n \n Connections\n \n \n \n Network & internet\n Mobile, Wi-Fi, hotspot\n \n \n\n
\n\n

Use slot="end" on ion-note when you want the standard trailing-note layout instead.

\n

Inset-list section headers

\n

Add .item-group-header to an ion-item-group to create the centered icon, title, and description used at the top of the component demo pages.

\n

This is an introductory group. Place regular list items in a separate ion-item-group that follows it.

\n
<ion-list inset="true">\n  <ion-item-group class="item-group-header">\n    <ion-item>\n      <ion-label>\n        <ion-icon name="list" style="background: var(--ion-color-primary)"></ion-icon>\n        <h2>Lists</h2>\n        <ion-text>Inset-list examples</ion-text>\n      </ion-label>\n    </ion-item>\n  </ion-item-group>\n  <ion-item-group>\n    <ion-item><ion-label>First item</ion-label></ion-item>\n  </ion-item-group>\n</ion-list>
\n\n
\n
Preview
\n\n \n \n \n \n

Lists

\n Inset-list examples\n
\n
\n
\n \n First item\n \n
\n
\n\n

Full-width segments

\n

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.

\n
<ion-segment class="segment-expand" value="new">\n  <ion-segment-button value="new"><ion-label>New</ion-label></ion-segment-button>\n  <ion-segment-button value="replied"><ion-label>Replied</ion-label></ion-segment-button>\n</ion-segment>
\n\n
\n
Preview
\n\n New\n Replied\n\n
\n\n

Classic search bar in a condense header

\n

The theme gives iOS search bars the iOS 26 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.

\n

Place it in a toolbar with a color, such as color="light"; the classic background is derived from that color's contrast value.

\n

The example uses Ionic's standard collapsible large-title structure. Scroll the preview to collapse the large title and reveal the fixed header.

\n
<div class="ion-page">\n  <ion-header translucent="true">\n    <ion-toolbar color="light">\n      <ion-title>Search</ion-title>\n    </ion-toolbar>\n  </ion-header>\n  <ion-content color="light" fullscreen="true">\n    <ion-header collapse="condense">\n      <ion-toolbar color="light">\n        <ion-title size="large">Search</ion-title>\n      </ion-toolbar>\n      <ion-toolbar color="light">\n        <ion-searchbar class="searchbar-classic" placeholder="Filter results"></ion-searchbar>\n      </ion-toolbar>\n    </ion-header>\n    <ion-list inset="true">\n      <ion-item-group>\n        <ion-item><ion-label>Recent item 1</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 2</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 3</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 4</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 5</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 6</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 7</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 8</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 9</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 10</ion-label></ion-item>\n      </ion-item-group>\n    </ion-list>\n  </ion-content>\n</div>
\n\n
\n
Preview
\n
\n \n \n Search\n \n \n \n \n \n Search\n \n \n \n \n \n \n \n Recent item 1\n Recent item 2\n Recent item 3\n Recent item 4\n Recent item 5\n Recent item 6\n Recent item 7\n Recent item 8\n Recent item 9\n Recent item 10\n \n \n \n
\n
\n\n

The .ion-page wrapper makes this embedded preview behave like a complete routed page. An application using ion-router-outlet normally receives that page container automatically. The inset list and its items only provide enough content to demonstrate scrolling; they are not required by .searchbar-classic.

\n

Search-bar toolbars

\n

Add .toolbar-searchbar when an ion-toolbar combines a search bar with start or end buttons. The class centers the slotted controls and adjusts the spacing around the search field.

\n
<ion-toolbar class="toolbar-searchbar">\n  <ion-buttons slot="start">\n    <ion-button>Cancel</ion-button>\n  </ion-buttons>\n  <ion-searchbar></ion-searchbar>\n</ion-toolbar>
\n\n
\n
Preview
\n\n \n Cancel\n \n \n\n
\n\n

Opting out

\n

Add .ios26-disabled to an individual Ionic component when it must retain Ionic's standard iOS styling.

\n
<ion-button>iOS 26 theme</ion-button> <ion-button class="ios26-disabled">Standard Ionic button</ion-button>
\n\n
\n
Preview
\niOS 26 theme Standard Ionic button\n
\n\n

For the background model behind inset lists, see Using ion-item-group.

\n'; + '

Special markup and classes

\n

Most Ionic markup works without changes. The combinations below are explicit opt-ins provided by the theme.

\n

Primary submit buttons

\n

Solid primary submit buttons use --ion-color-primary-brightness for their foreground and border treatment. Define a value with sufficient contrast for your primary color.

\n
:root {\n  --ion-color-primary-brightness: #96feff;\n}
\n\n
<ion-button type="submit" color="primary">Submit</ion-button>\n<ion-button class="button-submit" fill="solid" color="primary">Continue</ion-button>
\n\n
\n
Preview
\nSubmit\nContinue\n
\n\n

Use .button-submit when the button needs the same treatment but cannot use type="submit".

\n

Two-line inset list items

\n

Place an unslotted ion-label immediately alongside an unslotted ion-note to render a two-line item. When using the iOS-style inset-list background, wrap the items in ion-item-group; keep ion-list-header outside the group.

\n
<ion-list inset="true">\n  <ion-list-header>\n    <ion-label>Connections</ion-label>\n  </ion-list-header>\n  <ion-item-group>\n    <ion-item>\n      <ion-label>Network &amp; internet</ion-label>\n      <ion-note>Mobile, Wi-Fi, hotspot</ion-note>\n    </ion-item>\n  </ion-item-group>\n</ion-list>
\n\n
\n
Preview
\n\n \n Connections\n \n \n \n Network & internet\n Mobile, Wi-Fi, hotspot\n \n \n\n
\n\n

Use slot="end" on ion-note when you want the standard trailing-note layout instead.

\n

Inset-list section headers

\n

Add .item-group-header to an ion-item-group to create the centered icon, title, and description used at the top of the component demo pages.

\n

This is an introductory group. Place regular list items in a separate ion-item-group that follows it.

\n
<ion-list inset="true">\n  <ion-item-group class="item-group-header">\n    <ion-item>\n      <ion-label>\n        <ion-icon name="list" style="background: var(--ion-color-primary)"></ion-icon>\n        <h2>Lists</h2>\n        <ion-text>Inset-list examples</ion-text>\n      </ion-label>\n    </ion-item>\n  </ion-item-group>\n  <ion-item-group>\n    <ion-item><ion-label>First item</ion-label></ion-item>\n  </ion-item-group>\n</ion-list>
\n\n
\n
Preview
\n\n \n \n \n \n

Lists

\n Inset-list examples\n
\n
\n
\n \n First item\n \n
\n
\n\n

Full-width segments

\n

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.

\n
<ion-segment class="segment-expand" value="new">\n  <ion-segment-button value="new"><ion-label>New</ion-label></ion-segment-button>\n  <ion-segment-button value="replied"><ion-label>Replied</ion-label></ion-segment-button>\n</ion-segment>
\n\n
\n
Preview
\n\n New\n Replied\n\n
\n\n

Classic search bar in a condense header

\n

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.

\n

Place it in a toolbar with a color, such as color="light"; the classic background is derived from that color's contrast value.

\n

The example uses Ionic's standard collapsible large-title structure. Scroll the preview to collapse the large title and reveal the fixed header.

\n
<div class="ion-page">\n  <ion-header translucent="true">\n    <ion-toolbar color="light">\n      <ion-title>Search</ion-title>\n    </ion-toolbar>\n  </ion-header>\n  <ion-content color="light" fullscreen="true">\n    <ion-header collapse="condense">\n      <ion-toolbar color="light">\n        <ion-title size="large">Search</ion-title>\n      </ion-toolbar>\n      <ion-toolbar color="light">\n        <ion-searchbar class="searchbar-classic" placeholder="Filter results"></ion-searchbar>\n      </ion-toolbar>\n    </ion-header>\n    <ion-list inset="true">\n      <ion-item-group>\n        <ion-item><ion-label>Recent item 1</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 2</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 3</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 4</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 5</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 6</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 7</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 8</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 9</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 10</ion-label></ion-item>\n      </ion-item-group>\n    </ion-list>\n  </ion-content>\n</div>
\n\n
\n
Preview
\n
\n \n \n Search\n \n \n \n \n \n Search\n \n \n \n \n \n \n \n Recent item 1\n Recent item 2\n Recent item 3\n Recent item 4\n Recent item 5\n Recent item 6\n Recent item 7\n Recent item 8\n Recent item 9\n Recent item 10\n \n \n \n
\n
\n\n

The .ion-page wrapper makes this embedded preview behave like a complete routed page. An application using ion-router-outlet normally receives that page container automatically. The inset list and its items only provide enough content to demonstrate scrolling; they are not required by .searchbar-classic.

\n

Search-bar toolbars

\n

Add .toolbar-searchbar when an ion-toolbar combines a search bar with start or end buttons. The class centers the slotted controls and adjusts the spacing around the search field.

\n
<ion-toolbar class="toolbar-searchbar">\n  <ion-buttons slot="start">\n    <ion-button>Cancel</ion-button>\n  </ion-buttons>\n  <ion-searchbar></ion-searchbar>\n</ion-toolbar>
\n\n
\n
Preview
\n\n \n Cancel\n \n \n\n
\n\n

Opting out

\n

Add .ios27-disabled to an individual Ionic component when it must retain Ionic's standard iOS styling.

\n
<ion-button>iOS 27 theme</ion-button> <ion-button class="ios27-disabled">Standard Ionic button</ion-button>
\n\n
\n
Preview
\niOS 27 theme Standard Ionic button\n
\n\n

For the background model behind inset lists, see Using ion-item-group.

\n'; diff --git a/demo/src/app/docs/docs-page.component.html b/demo/src/app/docs/docs-page.component.html index 887cac9a..34166c0d 100644 --- a/demo/src/app/docs/docs-page.component.html +++ b/demo/src/app/docs/docs-page.component.html @@ -2,7 +2,7 @@ Docs - + diff --git a/demo/src/app/index/index-page.component.html b/demo/src/app/index/index-page.component.html index 6d8b340f..2fcf5580 100644 --- a/demo/src/app/index/index-page.component.html +++ b/demo/src/app/index/index-page.component.html @@ -5,7 +5,7 @@
Index - diff --git a/demo/src/app/index/pages/accordion/accordion.page.html b/demo/src/app/index/pages/accordion/accordion.page.html index 2af94547..edd2b9c7 100644 --- a/demo/src/app/index/pages/accordion/accordion.page.html +++ b/demo/src/app/index/pages/accordion/accordion.page.html @@ -17,7 +17,7 @@

accordion

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. diff --git a/demo/src/app/index/pages/action-sheet/action-sheet.page.html b/demo/src/app/index/pages/action-sheet/action-sheet.page.html index 42399ea4..d927095e 100644 --- a/demo/src/app/index/pages/action-sheet/action-sheet.page.html +++ b/demo/src/app/index/pages/action-sheet/action-sheet.page.html @@ -17,7 +17,7 @@

action-sheet

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. diff --git a/demo/src/app/index/pages/alert/alert.page.html b/demo/src/app/index/pages/alert/alert.page.html index 243076d4..922f47e6 100644 --- a/demo/src/app/index/pages/alert/alert.page.html +++ b/demo/src/app/index/pages/alert/alert.page.html @@ -17,7 +17,7 @@

alert

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. diff --git a/demo/src/app/index/pages/breadcrumbs/breadcrumbs.page.html b/demo/src/app/index/pages/breadcrumbs/breadcrumbs.page.html index 5b86a800..d9be6eb3 100644 --- a/demo/src/app/index/pages/breadcrumbs/breadcrumbs.page.html +++ b/demo/src/app/index/pages/breadcrumbs/breadcrumbs.page.html @@ -17,7 +17,7 @@

breadcrumbs

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. diff --git a/demo/src/app/index/pages/button/button.page.html b/demo/src/app/index/pages/button/button.page.html index c5d926ae..5c9865bd 100644 --- a/demo/src/app/index/pages/button/button.page.html +++ b/demo/src/app/index/pages/button/button.page.html @@ -12,7 +12,7 @@ Example - + Example Example Example @@ -30,7 +30,7 @@

button

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. @@ -144,7 +144,7 @@

button

buttons > button[fill=default][size=large] Buttons Shadow - Default Theme + Default Theme diff --git a/demo/src/app/index/pages/card/card.page.html b/demo/src/app/index/pages/card/card.page.html index 040ebf65..7c011b78 100644 --- a/demo/src/app/index/pages/card/card.page.html +++ b/demo/src/app/index/pages/card/card.page.html @@ -17,7 +17,7 @@

card

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27.
diff --git a/demo/src/app/index/pages/checkbox/checkbox.page.html b/demo/src/app/index/pages/checkbox/checkbox.page.html index a7ac85e3..ce08ff44 100644 --- a/demo/src/app/index/pages/checkbox/checkbox.page.html +++ b/demo/src/app/index/pages/checkbox/checkbox.page.html @@ -17,7 +17,7 @@

checkbox

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. diff --git a/demo/src/app/index/pages/chip/chip.page.html b/demo/src/app/index/pages/chip/chip.page.html index 01fc479d..987055d0 100644 --- a/demo/src/app/index/pages/chip/chip.page.html +++ b/demo/src/app/index/pages/chip/chip.page.html @@ -17,24 +17,24 @@

chip

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27.
- Default - Disabled - Outline - + Default + Disabled + Outline + Silhouette of a person's head Avatar Chip - + Icon Chip diff --git a/demo/src/app/index/pages/date-and-time-pickers/date-and-time-pickers.page.html b/demo/src/app/index/pages/date-and-time-pickers/date-and-time-pickers.page.html index 3ad95e10..61335526 100644 --- a/demo/src/app/index/pages/date-and-time-pickers/date-and-time-pickers.page.html +++ b/demo/src/app/index/pages/date-and-time-pickers/date-and-time-pickers.page.html @@ -17,7 +17,7 @@

date-and-time-pickers

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. diff --git a/demo/src/app/index/pages/floating-action-button-fixed/floating-action-button-fixed.page.html b/demo/src/app/index/pages/floating-action-button-fixed/floating-action-button-fixed.page.html index e232d929..acec65e4 100644 --- a/demo/src/app/index/pages/floating-action-button-fixed/floating-action-button-fixed.page.html +++ b/demo/src/app/index/pages/floating-action-button-fixed/floating-action-button-fixed.page.html @@ -17,7 +17,7 @@

floating-action-button

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. diff --git a/demo/src/app/index/pages/floating-action-button/floating-action-button.page.html b/demo/src/app/index/pages/floating-action-button/floating-action-button.page.html index bfec1ba9..8bd7ac08 100644 --- a/demo/src/app/index/pages/floating-action-button/floating-action-button.page.html +++ b/demo/src/app/index/pages/floating-action-button/floating-action-button.page.html @@ -17,7 +17,7 @@

floating-action-button

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. diff --git a/demo/src/app/index/pages/inputs/inputs.page.html b/demo/src/app/index/pages/inputs/inputs.page.html index 13c0bfbe..d02a63d3 100644 --- a/demo/src/app/index/pages/inputs/inputs.page.html +++ b/demo/src/app/index/pages/inputs/inputs.page.html @@ -17,7 +17,7 @@

inputs

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. diff --git a/demo/src/app/index/pages/modal/modal.page.html b/demo/src/app/index/pages/modal/modal.page.html index 33f45d7d..792af614 100644 --- a/demo/src/app/index/pages/modal/modal.page.html +++ b/demo/src/app/index/pages/modal/modal.page.html @@ -26,7 +26,7 @@

modal

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. diff --git a/demo/src/app/index/pages/popover/popover.page.html b/demo/src/app/index/pages/popover/popover.page.html index bf5a2012..5b04510b 100644 --- a/demo/src/app/index/pages/popover/popover.page.html +++ b/demo/src/app/index/pages/popover/popover.page.html @@ -17,7 +17,7 @@

popover

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. diff --git a/demo/src/app/index/pages/progress-indicators/progress-indicators.page.html b/demo/src/app/index/pages/progress-indicators/progress-indicators.page.html index 50bfac83..338e3fb6 100644 --- a/demo/src/app/index/pages/progress-indicators/progress-indicators.page.html +++ b/demo/src/app/index/pages/progress-indicators/progress-indicators.page.html @@ -17,7 +17,7 @@

progress-indicators

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. diff --git a/demo/src/app/index/pages/radio/radio.page.html b/demo/src/app/index/pages/radio/radio.page.html index d1550d51..289ef957 100644 --- a/demo/src/app/index/pages/radio/radio.page.html +++ b/demo/src/app/index/pages/radio/radio.page.html @@ -17,7 +17,7 @@

radio

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. diff --git a/demo/src/app/index/pages/range/range.page.html b/demo/src/app/index/pages/range/range.page.html index 0ec9bc81..a9b1a9f1 100644 --- a/demo/src/app/index/pages/range/range.page.html +++ b/demo/src/app/index/pages/range/range.page.html @@ -17,7 +17,7 @@

range

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. diff --git a/demo/src/app/index/pages/reorder/reorder.page.html b/demo/src/app/index/pages/reorder/reorder.page.html index 82237c11..719b0a25 100644 --- a/demo/src/app/index/pages/reorder/reorder.page.html +++ b/demo/src/app/index/pages/reorder/reorder.page.html @@ -17,7 +17,7 @@

reorder

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. diff --git a/demo/src/app/index/pages/searchbar/searchbar.page.html b/demo/src/app/index/pages/searchbar/searchbar.page.html index 03e05894..fc92e07b 100644 --- a/demo/src/app/index/pages/searchbar/searchbar.page.html +++ b/demo/src/app/index/pages/searchbar/searchbar.page.html @@ -17,7 +17,7 @@

searchbar

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. @@ -25,10 +25,10 @@

searchbar

- - - - Search + + + + Search diff --git a/demo/src/app/index/pages/segment/segment.page.html b/demo/src/app/index/pages/segment/segment.page.html index c679f335..c8413c17 100644 --- a/demo/src/app/index/pages/segment/segment.page.html +++ b/demo/src/app/index/pages/segment/segment.page.html @@ -38,7 +38,7 @@

segment

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. @@ -57,7 +57,7 @@

segment

Segment - +
diff --git a/demo/src/app/index/pages/select/select.page.html b/demo/src/app/index/pages/select/select.page.html index 243441ad..20bad4c0 100644 --- a/demo/src/app/index/pages/select/select.page.html +++ b/demo/src/app/index/pages/select/select.page.html @@ -17,7 +17,7 @@

select

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. diff --git a/demo/src/app/index/pages/tabs/tabs.page.html b/demo/src/app/index/pages/tabs/tabs.page.html index b39b711f..cd186e5c 100644 --- a/demo/src/app/index/pages/tabs/tabs.page.html +++ b/demo/src/app/index/pages/tabs/tabs.page.html @@ -17,7 +17,7 @@

tabs

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. diff --git a/demo/src/app/index/pages/toast/toast.page.html b/demo/src/app/index/pages/toast/toast.page.html index f48e3df2..5decb793 100644 --- a/demo/src/app/index/pages/toast/toast.page.html +++ b/demo/src/app/index/pages/toast/toast.page.html @@ -17,7 +17,7 @@

toast

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. diff --git a/demo/src/app/index/pages/toggle/toggle.page.html b/demo/src/app/index/pages/toggle/toggle.page.html index 4757ccd6..c7aefabf 100644 --- a/demo/src/app/index/pages/toggle/toggle.page.html +++ b/demo/src/app/index/pages/toggle/toggle.page.html @@ -17,7 +17,7 @@

toggle

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. diff --git a/demo/src/app/index/pages/toolbar/toolbar.page.html b/demo/src/app/index/pages/toolbar/toolbar.page.html index fa9c6126..7bf1890a 100644 --- a/demo/src/app/index/pages/toolbar/toolbar.page.html +++ b/demo/src/app/index/pages/toolbar/toolbar.page.html @@ -17,7 +17,7 @@

toolbar

- This page is a component demo for @rdlabo/ionic-theme-ios26. + This page is a component demo for @rdlabo/ionic-theme-ios27. diff --git a/demo/src/app/settings/settings-page.component.html b/demo/src/app/settings/settings-page.component.html index 6acca9e1..62567054 100644 --- a/demo/src/app/settings/settings-page.component.html +++ b/demo/src/app/settings/settings-page.component.html @@ -4,8 +4,8 @@ Settings - - + diff --git a/demo/src/global.scss b/demo/src/global.scss index d7bf2204..d9712057 100644 --- a/demo/src/global.scss +++ b/demo/src/global.scss @@ -37,13 +37,13 @@ @use '@ionic/angular/css/palettes/dark.class.css'; @use '../../src/styles/default-variables'; -@use '../../src/styles/ionic-theme-ios26'; -@use '../../src/styles/ionic-theme-ios26-dark-class'; +@use '../../src/styles/ionic-theme-ios27'; +@use '../../src/styles/ionic-theme-ios27-dark-class'; @use '../../src/styles/md-ion-list-inset'; @use '../../src/styles/md-remove-ios-class-effect'; :root { - --ios26-menu-width: 300px; + --ios27-menu-width: 300px; } /** @@ -189,7 +189,7 @@ code { } ion-content { - --ios26-content-box-shadow-rgb: var(--ion-color-base-rgb, var(--ion-background-color-rgb, 255, 255, 255)); + --ios27-content-box-shadow-rgb: var(--ion-color-base-rgb, var(--ion-background-color-rgb, 255, 255, 255)); } #main-content { diff --git a/demo/src/index.html b/demo/src/index.html index 19bf77f9..08708166 100644 --- a/demo/src/index.html +++ b/demo/src/index.html @@ -2,7 +2,7 @@ - Demo for ionic-theme-ios26 + Demo for ionic-theme-ios27 @@ -54,7 +54,7 @@ Resolved. ### should disable ion-back-button Animation -Resolved: by created https://github.com/rdlabo-dev/ionic-theme-ios26/tree/main/src/transition +Resolved: by created https://github.com/rdlabo-dev/ionic-theme-ios27/tree/main/src/transition ## feat(): ion-content[fullscreen=true] will have .content-fullscreen class diff --git a/docs/ios-18.md b/docs/ios-18.md index bd61b8e9..677b55c1 100644 --- a/docs/ios-18.md +++ b/docs/ios-18.md @@ -10,7 +10,7 @@ If you want to load a theme file only when the user's device is running iOS 26 ( ```css @import '@rdlabo/ionic-theme-ios27/dist/css/default-variables.css' supports(text-wrap: pretty); -@import '@rdlabo/ionic-theme-ios27/dist/css/ionic-theme-ios26.css' supports(text-wrap: pretty); +@import '@rdlabo/ionic-theme-ios27/dist/css/ionic-theme-ios27.css' supports(text-wrap: pretty); @import '@rdlabo/ionic-theme-ios27/dist/css/md-remove-ios-class-effect.css' supports(text-wrap: pretty); @import '@rdlabo/ionic-theme-ios27/dist/css/md-ion-list-inset.css' supports(text-wrap: pretty); ``` diff --git a/docs/migration.md b/docs/migration.md index e0e32f2b..3f9cf981 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -4,91 +4,12 @@ title: Migration # Migration -Review every section newer than the version currently installed, in ascending order. For example, when upgrading from 1.x to 9.0.0, complete the 2.0.0 and 3.0.0 migration steps before reviewing 9.0.0. +## iOS 27 naming -Each section lists only the changes that require application code or configuration updates. +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. -## Migrating to 9.0.0 +The theme now uses the `ios27-` prefix consistently. Update custom CSS variables, selectors, and markup to match, including `ios27-disabled` and `--ios27-*` variables. Legacy names are no longer recognized. -Version 9 aligns the theme's major version with Ionic Framework 9. It does not introduce additional breaking changes beyond those documented in the earlier migration sections. +See [Special markup and classes](./special-markup.md) and [Default variables](../src/styles/default-variables.scss) for the current names. -Both Ionic 8 and Ionic 9 remain supported. Version 9 requires `@ionic/core >=8.8.1 <10`. - -## Migrating to 3.0.0 - -### Rename `.header-item-group` to `.item-group-header` - -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. - -```diff -- -+ - ... - -``` - -The old class is no longer styled by the theme. This rename applies to markup shared with `@rdlabo/ionic-theme-md3` as well. - -## Migrating to 2.0.0 - -### Configure `iosTransitionAnimation` - -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. - -```ts -import { isPlatform } from '@ionic/core'; // or @ionic/angular/standalone, @ionic/react, @ionic/vue -import { iosTransitionAnimation } from '@rdlabo/ionic-theme-ios26'; - -// Angular -provideIonicAngular({ - // ... - navAnimation: isPlatform('ios') ? iosTransitionAnimation : undefined, -}); - -// React -setupIonicReact({ - // ... - navAnimation: isPlatform('ios') ? iosTransitionAnimation : undefined, -}); - -// Vue -createApp(App).use(IonicVue, { - // ... - navAnimation: isPlatform('ios') ? iosTransitionAnimation : undefined, -}); -``` - -With this transition configured, `` can be used without the unwanted transition side effects caused by the old animation. - -## Migrating to 1.0.0 - -### Update SCSS import paths - -The source files moved under `src/styles` when JavaScript files were added to the package. - -```diff -- @import '@rdlabo/ionic-theme-ios26/src/default-variables.scss'; -+ @import '@rdlabo/ionic-theme-ios26/src/styles/default-variables.scss'; -``` - -Generated CSS paths under `dist` did not change. - -### Rename `--ios26-color-background-rgb` - -```diff - :root { -- --ios26-color-background-rgb: 255, 255, 255; -+ --ios26-content-box-shadow-rgb: 255, 255, 255; - } -``` - -### Rename brightness variables - -Replace each `--ion-color-*-brightness-rgb` variable with `--ion-color-*-brightness` and use a color value instead of an RGB channel list. - -```diff - :root { -- --ion-color-primary-brightness-rgb: 130, 255, 255; -+ --ion-color-primary-brightness: #96feff; - } -``` +Earlier migration notes are preserved on the [previous theme branch](https://github.com/rdlabo-dev/ionic-theme-ios27/blob/ios26/docs/migration.md). diff --git a/docs/special-markup.md b/docs/special-markup.md index 3d146c03..08a33231 100644 --- a/docs/special-markup.md +++ b/docs/special-markup.md @@ -79,7 +79,7 @@ Add `.segment-expand` when segment buttons should divide the available width eve ## Classic search bar in a condense header -The theme gives iOS search bars the iOS 26 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. +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. Place it in a toolbar with a color, such as `color="light"`; the classic background is derived from that color's contrast value. @@ -136,10 +136,10 @@ Add `.toolbar-searchbar` when an `ion-toolbar` combines a search bar with start ## Opting out -Add `.ios26-disabled` to an individual Ionic component when it must retain Ionic's standard iOS styling. +Add `.ios27-disabled` to an individual Ionic component when it must retain Ionic's standard iOS styling. ```html preview -iOS 26 theme Standard Ionic button +iOS 27 theme Standard Ionic button ``` For the background model behind inset lists, see [Using `ion-item-group`](./using-ion-item-group.md). diff --git a/docs/using-ion-item-group.md b/docs/using-ion-item-group.md index 4ae58088..ed9d732f 100644 --- a/docs/using-ion-item-group.md +++ b/docs/using-ion-item-group.md @@ -24,9 +24,9 @@ No wrapper is required for lists that do not use `inset="true"`. ## Why the wrapper is required -Ionic normally gives `ion-list` its background, which makes `ion-list-header` appear inside the same surface as the items. The iOS 26 layout treats the header and item surface separately. +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. -![Inset list background comparison showing why ion-item-group is required](https://raw.githubusercontent.com/rdlabo-dev/ionic-theme-ios26/v3.0.0/screenshots/why-ion-list-inset.png) +![Inset list background comparison showing why ion-item-group is required](https://raw.githubusercontent.com/rdlabo-dev/ionic-theme-ios27/v3.0.0/screenshots/why-ion-list-inset.png) The theme therefore: diff --git a/package.json b/package.json index 4ec5a42a..bd056e51 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,7 @@ "bugs": { "url": "https://github.com/rdlabo-dev/ionic-theme-ios27/issues" }, - "homepage": "https://docs.rdlabo.dev/projects/ionic-theme-ios26", + "homepage": "https://docs.rdlabo.dev/projects/ionic-theme-ios27", "devDependencies": { "@ionic/angular": "^9.0.0", "husky": "^9.1.7", diff --git a/screenshots/ios26.png b/screenshots/legacy-theme.png similarity index 100% rename from screenshots/ios26.png rename to screenshots/legacy-theme.png diff --git a/src/popover/animations/ios.enter.ts b/src/popover/animations/ios.enter.ts index 18721b5e..0d7e63cb 100644 --- a/src/popover/animations/ios.enter.ts +++ b/src/popover/animations/ios.enter.ts @@ -27,7 +27,7 @@ export const iosEnterAnimation = (baseEl: HTMLElement, opts?: any): Animation => if (!['ion-button', 'ion-buttons'].includes(referenceSizeEl.localName)) { return false; } - if (referenceSizeEl.classList.contains('ios26-disabled')) { + if (referenceSizeEl.classList.contains('ios27-disabled')) { return false; } return true; @@ -102,7 +102,7 @@ export const iosEnterAnimation = (baseEl: HTMLElement, opts?: any): Animation => .duration(200) .addElement(referenceSizeEl) .beforeStyles({ 'transform-origin': `${originY} ${originX}` }) - .beforeAddClass('ios26-replace-element') + .beforeAddClass('ios27-replace-element') .fromTo('transform', 'scale(1)', 'scale(1.05)') .fromTo('opacity', 1, 0); } diff --git a/src/popover/animations/ios.leave.ts b/src/popover/animations/ios.leave.ts index e71b7a92..ec04d218 100644 --- a/src/popover/animations/ios.leave.ts +++ b/src/popover/animations/ios.leave.ts @@ -17,7 +17,7 @@ export const iosLeaveAnimation = (baseEl: HTMLElement): Animation => { const targetAnimation = createAnimation(); const doc = baseEl.ownerDocument as any; - const replaceElement = doc.querySelector('.ios26-replace-element') as HTMLElement | null; + const replaceElement = doc.querySelector('.ios27-replace-element') as HTMLElement | null; if (replaceElement) { const ratio = contentEl.getBoundingClientRect().width / contentEl.getBoundingClientRect().height; @@ -27,7 +27,7 @@ export const iosLeaveAnimation = (baseEl: HTMLElement): Animation => { .addElement(replaceElement) .delay(100) .duration(300) - .afterRemoveClass('ios26-replace-element') + .afterRemoveClass('ios27-replace-element') .fromTo('transform', `scale(${scale})`, 'scale(1)') .fromTo('opacity', 0, 0.9); } diff --git a/src/sheets-of-glass/index.ts b/src/sheets-of-glass/index.ts index 18d180fe..fdcac39e 100644 --- a/src/sheets-of-glass/index.ts +++ b/src/sheets-of-glass/index.ts @@ -4,8 +4,8 @@ import type { Animation, Gesture, GestureDetail } from '@ionic/core'; import { changeSelectedElement, cloneElement, getStep } from '../utils'; import { createMoveAnimation, createPreMoveAnimation, getMoveAnimationKeyframe, getScaleAnimation } from './animations'; -const GESTURE_NAME = 'ios26-enable-gesture'; -const ANIMATED_NAME = 'ios26-animated'; +const GESTURE_NAME = 'ios27-enable-gesture'; +const ANIMATED_NAME = 'ios27-animated'; export const registerEffect = ( targetElement: HTMLElement, diff --git a/src/styles/components/ion-action-sheet.scss b/src/styles/components/ion-action-sheet.scss index e0ed4629..459da124 100644 --- a/src/styles/components/ion-action-sheet.scss +++ b/src/styles/components/ion-action-sheet.scss @@ -1,12 +1,12 @@ @use '../utils/api'; -ion-action-sheet.ios:not(.ios26-disabled) { +ion-action-sheet.ios:not(.ios27-disabled) { --backdrop-opacity: 0.2; --color: var(--ion-color-step-600, var(--ion-text-color-step-400, #666666)); .action-sheet-wrapper { padding-bottom: 0; - bottom: var(--ios26-floating-safe-area-bottom); + bottom: var(--ios27-floating-safe-area-bottom); } .action-sheet-container { @@ -71,10 +71,10 @@ ion-action-sheet.ios:not(.ios26-disabled) { /** * For ion-select[interface=action-sheet]. - * ios26, action-sheet should not has 'cancel'. + * ios27, action-sheet should not has 'cancel'. * It is recommend to use Popover. */ -ion-action-sheet.ios.select-action-sheet:not(.ios26-disabled) { +ion-action-sheet.ios.select-action-sheet:not(.ios27-disabled) { .action-sheet-container { .action-sheet-group { button.action-sheet-cancel { diff --git a/src/styles/components/ion-alert.scss b/src/styles/components/ion-alert.scss index 07d23683..aa548721 100644 --- a/src/styles/components/ion-alert.scss +++ b/src/styles/components/ion-alert.scss @@ -1,6 +1,6 @@ @use '../utils/api'; -ion-alert.ios:not(.ios26-disabled) { +ion-alert.ios:not(.ios27-disabled) { --min-width: 280px; --backdrop-opacity: 0.2; diff --git a/src/styles/components/ion-button.scss b/src/styles/components/ion-button.scss index 0dde1f38..bec6dd1b 100644 --- a/src/styles/components/ion-button.scss +++ b/src/styles/components/ion-button.scss @@ -23,7 +23,7 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only; /** * compare .header-collapse-main ion-toolbar.in-toolbar ion-title, .header-collapse-main ion-toolbar.in-toolbar ion-buttons */ - transition: transform var(--ios26-activated-transition-duration) ease-out; + transition: transform var(--ios27-activated-transition-duration) ease-out; z-index: 0; @@ -59,11 +59,11 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only; } } - &:has(ion-button:not(.ios26-disabled).button-clear.button-large) { + &:has(ion-button:not(.ios27-disabled).button-clear.button-large) { border-radius: 30px; } - ion-button:not(.ios26-disabled).button-clear { + ion-button:not(.ios27-disabled).button-clear { --background: transparent; --border-style: none; --border-width: 0; @@ -121,11 +121,11 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only; } } - ion-button:not(.ios26-disabled) { + ion-button:not(.ios27-disabled) { margin: 0; } - ion-menu-button:not(.ios26-disabled) { + ion-menu-button:not(.ios27-disabled) { width: 44px; height: 44px; padding: 2px; @@ -140,7 +140,7 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only; } transition: - transform var(--ios26-activated-transition-duration) ease-out, + transform var(--ios27-activated-transition-duration) ease-out, color 50ms ease; &.in-toolbar:not(.ion-color):not(.in-toolbar-color) { @@ -153,13 +153,13 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only; } // will-change is optimized to only apply when needed for performance - &:not(.ios26-disabled):hover, - &:not(.ios26-disabled):active, - &:not(.ios26-disabled).ion-activated { + &:not(.ios27-disabled):hover, + &:not(.ios27-disabled):active, + &:not(.ios27-disabled).ion-activated { will-change: transform; } - &:not(.ios26-disabled):not(:hover):not(:active):not(.ion-activated) { + &:not(.ios27-disabled):not(:hover):not(:active):not(.ion-activated) { will-change: auto; } @@ -248,8 +248,8 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only; } } @else { --box-shadow: - inset 0 0 8px 0 rgba(var(--ios26-glass-box-shadow-color-rgb), 0.2), - 0 0 8px -4px rgba(var(--ios26-glass-box-shadow-color-rgb), 0.92); + inset 0 0 8px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.2), + 0 0 8px -4px rgba(var(--ios27-glass-box-shadow-color-rgb), 0.92); } &::part(native)::before { content: ''; @@ -313,13 +313,13 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only; // fill:default only &:not(.button-solid):not(.button-outline):not(.button-clear) { - --background: rgba(var(--ios26-glass-background-rgb), 0.72); + --background: rgba(var(--ios27-glass-background-rgb), 0.72); --background-hover: transparent; --background-activated: transparent; @if not $is-back-button { --box-shadow: - inset 0 0 8px 0 rgba(var(--ios26-glass-box-shadow-color-rgb), 0.2), - 0 0.5px 1px 0 rgba(var(--ios26-glass-box-shadow-color-rgb), 0.08); + inset 0 0 8px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.2), + 0 0.5px 1px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.08); } &:not(.button-has-icon-only):not(.back-button-has-icon-only) { @@ -409,18 +409,18 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only; } } -ion-buttons.ios:not(.ios26-disabled):not(:has(ion-back-button, ion-button:not(.button-clear), ion-menu-button.menu-button-hidden)) { +ion-buttons.ios:not(.ios27-disabled):not(:has(ion-back-button, ion-button:not(.button-clear), ion-menu-button.menu-button-hidden)) { @include theme-buttons; } // Ionic's collapsing-header transition has a more specific contextual selector. .header-collapse-main :where(ion-toolbar.in-toolbar) - ion-buttons.ios:not(.ios26-disabled):not(:has(ion-back-button, ion-button:not(.button-clear), ion-menu-button.menu-button-hidden)) { - transition: transform var(--ios26-activated-transition-duration) ease-out; + ion-buttons.ios:not(.ios27-disabled):not(:has(ion-back-button, ion-button:not(.button-clear), ion-menu-button.menu-button-hidden)) { + transition: transform var(--ios27-activated-transition-duration) ease-out; } -ion-buttons.ios:not(.ios26-disabled):not(:has(ion-back-button, ion-button.button-clear)) { +ion-buttons.ios:not(.ios27-disabled):not(:has(ion-back-button, ion-button.button-clear)) { ion-button { margin: 0 6px; &:first-child { @@ -435,9 +435,9 @@ ion-buttons.ios:not(.ios26-disabled):not(:has(ion-back-button, ion-button.button } } -ion-button.ios:not(.ios26-disabled) { +ion-button.ios:not(.ios27-disabled) { @include theme-button; } -ion-back-button.ios:not(.ios26-disabled) { +ion-back-button.ios:not(.ios27-disabled) { @include theme-button($is-back-button: true); } diff --git a/src/styles/components/ion-card.scss b/src/styles/components/ion-card.scss index e6510259..f314e43c 100644 --- a/src/styles/components/ion-card.scss +++ b/src/styles/components/ion-card.scss @@ -1,4 +1,4 @@ -ion-card.ios:not(.ios26-disabled) { +ion-card.ios:not(.ios27-disabled) { border-radius: 24px; ion-list ion-item { diff --git a/src/styles/components/ion-content.scss b/src/styles/components/ion-content.scss index f5ea5d14..1795260b 100644 --- a/src/styles/components/ion-content.scss +++ b/src/styles/components/ion-content.scss @@ -1,10 +1,10 @@ /** - * Since iOS26, content is now displayed to the full extent of the top and bottom safe areas, + * Since iOS27, content is now displayed to the full extent of the top and bottom safe areas, * so we adjust the margin and padding of the content. * Also supports virtual scrolling using .ion-content-scroll-host. */ -.ion-page.ios:not(.ios26-disabled):has(ion-header.header-translucent) - ion-content.ios:not(.ios26-disabled).content-fullscreen:has(.ion-content-scroll-host) { +.ion-page.ios:not(.ios27-disabled):has(ion-header.header-translucent) + ion-content.ios:not(.ios27-disabled).content-fullscreen:has(.ion-content-scroll-host) { --padding-top: calc(var(--offset-top) * -1); > *:not(.ion-content-scroll-host, ion-fab) { transform: translateY(var(--offset-top)); @@ -13,10 +13,10 @@ padding-top: var(--offset-top); } } -.ion-page.ios:not(.ios26-disabled):not(:has(ion-footer)) ion-content.ios:not(.ios26-disabled).content-fullscreen .ion-content-scroll-host { - margin-bottom: calc(calc(60px + var(--ios26-floating-safe-area-bottom)) * -1); - padding-bottom: calc(60px + var(--ios26-floating-safe-area-bottom)); +.ion-page.ios:not(.ios27-disabled):not(:has(ion-footer)) ion-content.ios:not(.ios27-disabled).content-fullscreen .ion-content-scroll-host { + margin-bottom: calc(calc(60px + var(--ios27-floating-safe-area-bottom)) * -1); + padding-bottom: calc(60px + var(--ios27-floating-safe-area-bottom)); } -ion-content.ios:not(.ios26-disabled).content-fullscreen:not(:has(.ion-content-scroll-host)) { - --padding-bottom: calc(60px + var(--ios26-floating-safe-area-bottom)); +ion-content.ios:not(.ios27-disabled).content-fullscreen:not(:has(.ion-content-scroll-host)) { + --padding-bottom: calc(60px + var(--ios27-floating-safe-area-bottom)); } diff --git a/src/styles/components/ion-datetime.scss b/src/styles/components/ion-datetime.scss index 069a16a1..f4c6a17a 100644 --- a/src/styles/components/ion-datetime.scss +++ b/src/styles/components/ion-datetime.scss @@ -1,6 +1,6 @@ @use '../utils/api'; -ion-datetime.ios:not(.ios26-disabled) { +ion-datetime.ios:not(.ios27-disabled) { @include api.glass-background-overlay; border-radius: 24px; diff --git a/src/styles/components/ion-fab.scss b/src/styles/components/ion-fab.scss index 01b15dc7..6cd7fce7 100644 --- a/src/styles/components/ion-fab.scss +++ b/src/styles/components/ion-fab.scss @@ -4,19 +4,19 @@ $scaleup-small-icon-only: api.$button-scaleup-small-icon-only; $scaleup-default-icon-only: api.$button-scaleup-default-icon-only; $scaleup-large-icon-only: api.$button-scaleup-large-icon-only; -ion-fab.ios:not(.ios26-disabled) { +ion-fab.ios:not(.ios27-disabled) { --transform-value: 2.5px; &:has(> ion-fab-button.fab-button-small) { --transform-value: 4px; } ion-fab-button { - --background: rgba(var(--ios26-glass-background-rgb), 0.72); + --background: rgba(var(--ios27-glass-background-rgb), 0.72); --box-shadow: - inset 0 0 8px 0 rgba(var(--ios26-glass-box-shadow-color-rgb), 0.2), 0 0.5px 1px 0 rgba(var(--ios26-glass-box-shadow-color-rgb), 0.08); + inset 0 0 8px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.2), 0 0.5px 1px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.08); --transition: - var(--ios26-activated-transition-duration) transform cubic-bezier(0.25, 1.11, 0.78, 1.59), - var(--ios26-activated-transition-duration) color ease; + var(--ios27-activated-transition-duration) transform cubic-bezier(0.25, 1.11, 0.78, 1.59), + var(--ios27-activated-transition-duration) color ease; --background-activated-opacity: 0; --background-focused-opacity: 0; --background-hover-opacity: 0; @@ -77,15 +77,15 @@ ion-fab.ios:not(.ios26-disabled) { } &.fab-vertical-top { - top: var(--ios26-floating-safe-area-top); + top: var(--ios27-floating-safe-area-top); } &.fab-vertical-bottom { - bottom: var(--ios26-floating-safe-area-bottom); + bottom: var(--ios27-floating-safe-area-bottom); } &.fab-horizontal-start { - left: calc(16px + var(--ios26-menu-width, var(--ion-safe-area-left), 0px)); + left: calc(16px + var(--ios27-menu-width, var(--ion-safe-area-left), 0px)); } &.fab-horizontal-end { @@ -94,7 +94,7 @@ ion-fab.ios:not(.ios26-disabled) { &:has(.fab-button-small) { &.fab-horizontal-start { - left: calc(10px + var(--ios26-menu-width, var(--ion-safe-area-left), 0px)); + left: calc(10px + var(--ios27-menu-width, var(--ion-safe-area-left), 0px)); } &.fab-horizontal-end { diff --git a/src/styles/components/ion-inputs.scss b/src/styles/components/ion-inputs.scss index 06f8e6cb..36f055c3 100644 --- a/src/styles/components/ion-inputs.scss +++ b/src/styles/components/ion-inputs.scss @@ -54,7 +54,7 @@ } } -ion-input.ios:not(.ios26-disabled) { +ion-input.ios:not(.ios27-disabled) { &.input-fill-outline { @include outline-field('input'); @@ -65,7 +65,7 @@ ion-input.ios:not(.ios26-disabled) { } } -ion-textarea.ios:not(.ios26-disabled) { +ion-textarea.ios:not(.ios27-disabled) { &.textarea-fill-outline { @include outline-field('textarea'); diff --git a/src/styles/components/ion-list.scss b/src/styles/components/ion-list.scss index f71def38..6785f29c 100644 --- a/src/styles/components/ion-list.scss +++ b/src/styles/components/ion-list.scss @@ -1,6 +1,6 @@ @use '../utils/structured-list'; -ion-list.ios:not(.ios26-disabled) { +ion-list.ios:not(.ios27-disabled) { @include structured-list.support-text; ion-item { --background-hover-opacity: 0; @@ -8,7 +8,7 @@ ion-list.ios:not(.ios26-disabled) { } } -ion-list.list-inset.ios:not(.ios26-disabled) { +ion-list.list-inset.ios:not(.ios27-disabled) { @include structured-list.layout(20px, 24px); ion-radio-group, diff --git a/src/styles/components/ion-loading.scss b/src/styles/components/ion-loading.scss index c7e907a2..1ad96bc0 100644 --- a/src/styles/components/ion-loading.scss +++ b/src/styles/components/ion-loading.scss @@ -1,6 +1,6 @@ @use '../utils/api'; -ion-loading.ios:not(.ios26-disabled) { +ion-loading.ios:not(.ios27-disabled) { --backdrop-opacity: 0.2; .loading-wrapper { @include api.glass-background; diff --git a/src/styles/components/ion-menu.scss b/src/styles/components/ion-menu.scss index 5fe03eec..3da25186 100644 --- a/src/styles/components/ion-menu.scss +++ b/src/styles/components/ion-menu.scss @@ -1,20 +1,20 @@ @use '../utils/api'; -ion-split-pane.ios:not(.ios26-disabled) { - --side-max-width: var(--ios26-menu-width); +ion-split-pane.ios:not(.ios27-disabled) { + --side-max-width: var(--ios27-menu-width); } -ion-split-pane.ios:not(.ios26-disabled).split-pane-visible:has(ion-menu.menu-pane-visible) { +ion-split-pane.ios:not(.ios27-disabled).split-pane-visible:has(ion-menu.menu-pane-visible) { .split-pane-main { - ion-tab-bar.ios:not(.ios26-disabled) { + ion-tab-bar.ios:not(.ios27-disabled) { width: calc( 100% - calc(18px + var(--ion-safe-area-left, 0px)) - calc(18px + var(--ion-safe-area-left, 0px)) - 60px - - 12px - var(--ios26-menu-width) + 12px - var(--ios27-menu-width) ); &:has(:nth-child(5)) { width: calc( - 100% - calc(18px + var(--ion-safe-area-left, 0px)) - calc(18px + var(--ion-safe-area-left, 0px)) - var(--ios26-menu-width) + 100% - calc(18px + var(--ion-safe-area-left, 0px)) - calc(18px + var(--ion-safe-area-left, 0px)) - var(--ios27-menu-width) ); } } @@ -25,62 +25,62 @@ ion-split-pane.ios:not(.ios26-disabled).split-pane-visible:has(ion-menu.menu-pan /* * 4px: https://github.com/ionic-team/ionic-framework/blob/main/core/src/components/toolbar/toolbar.ios.vars.scss#L28-L32 */ - --padding-start: calc(var(--ios26-menu-width) + 4px); + --padding-start: calc(var(--ios27-menu-width) + 4px); ion-title.title-default { /* * 90px: https://github.com/ionic-team/ionic-framework/blob/main/core/src/components/title/title.ios.scss#L8 */ - padding-left: calc(90px + var(--ios26-menu-width)); + padding-left: calc(90px + var(--ios27-menu-width)); } } ion-content { - --padding-start: var(--ios26-menu-width); + --padding-start: var(--ios27-menu-width); ion-header ion-toolbar { --padding-start: 4px; } } ion-footer ion-toolbar { - --padding-start: var(--ios26-menu-width); + --padding-start: var(--ios27-menu-width); } - ion-tab-bar.ios:not(.ios26-disabled) { + ion-tab-bar.ios:not(.ios27-disabled) { &[slot='bottom'] { - left: calc(16px + var(--ion-safe-area-left, 0px) + var(--ios26-menu-width)); + left: calc(16px + var(--ion-safe-area-left, 0px) + var(--ios27-menu-width)); } } } } - &:has(ion-menu.ios:not(.ios26-disabled).menu-side-end) { + &:has(ion-menu.ios:not(.ios27-disabled).menu-side-end) { .split-pane-main { ion-header ion-toolbar { /* * 4px: https://github.com/ionic-team/ionic-framework/blob/main/core/src/components/toolbar/toolbar.ios.vars.scss#L28-L32 */ - --padding-end: calc(var(--ios26-menu-width) + 4px); + --padding-end: calc(var(--ios27-menu-width) + 4px); ion-title.title-default { /* * 90px: https://github.com/ionic-team/ionic-framework/blob/main/core/src/components/title/title.ios.scss#L8 */ - padding-right: calc(90px + var(--ios26-menu-width)); + padding-right: calc(90px + var(--ios27-menu-width)); } } ion-content { - --padding-end: var(--ios26-menu-width); + --padding-end: var(--ios27-menu-width); ion-header ion-toolbar { --padding-start: 4px; } } ion-footer ion-toolbar { - --padding-end: var(--ios26-menu-width); + --padding-end: var(--ios27-menu-width); } } } } -ion-menu.ios:not(.ios26-disabled) { +ion-menu.ios:not(.ios27-disabled) { --border: none; --background: transparent; - --max-width: var(--ios26-menu-width); + --max-width: var(--ios27-menu-width); position: absolute; top: 0; z-index: 999; @@ -89,7 +89,7 @@ ion-menu.ios:not(.ios26-disabled) { left: 0; } &.menu-side-end { - left: calc(100vw - var(--ios26-menu-width)); + left: calc(100vw - var(--ios27-menu-width)); } &::part(backdrop) { @@ -98,11 +98,11 @@ ion-menu.ios:not(.ios26-disabled) { ion-content { --background: transparent; - --ios26-content-box-shadow-rgb: transparent; + --ios27-content-box-shadow-rgb: transparent; &::part(scroll) { @include api.glass-background; - margin: calc(var(--ios26-floating-safe-area-top) + 6px) calc(16px + var(--ion-safe-area-right)) var(--ios26-floating-safe-area-bottom) + margin: calc(var(--ios27-floating-safe-area-top) + 6px) calc(16px + var(--ion-safe-area-right)) var(--ios27-floating-safe-area-bottom) calc(12px + var(--ion-safe-area-left)); border-radius: 24px; } diff --git a/src/styles/components/ion-modal.scss b/src/styles/components/ion-modal.scss index e4519b25..3b03f478 100644 --- a/src/styles/components/ion-modal.scss +++ b/src/styles/components/ion-modal.scss @@ -1,6 +1,6 @@ @use '../utils/api'; -ion-modal.ios:not(.ios26-disabled) { +ion-modal.ios:not(.ios27-disabled) { --backdrop-opacity: 0.2; &::part(handle) { @@ -22,7 +22,7 @@ ion-modal.ios:not(.ios26-disabled) { &.modal-card { /** * IonicでCardModalのborder-radiusはハードコーディングされています。 - * また、iOS26のドキュメントで見つからないため、サポートは行いません。 + * また、iOS27のドキュメントで見つからないため、サポートは行いません。 * https://github.com/ionic-team/ionic-framework/blob/3b80473f2fd5ad4da5a9f5d66f783a69909c8965/core/src/components/modal/animations/ios.enter.ts#L82-L83 */ } @@ -34,7 +34,7 @@ ion-modal.ios:not(.ios26-disabled) { &.modal-sheet { --border-radius: 30px; - --background: rgba(var(--ios26-glass-background-rgb), 1); + --background: rgba(var(--ios27-glass-background-rgb), 1); &::part(content) { @include api.glass-background($opacity: 1, $include-background: false); } diff --git a/src/styles/components/ion-picker.scss b/src/styles/components/ion-picker.scss index 70d07925..c4cbbe2e 100644 --- a/src/styles/components/ion-picker.scss +++ b/src/styles/components/ion-picker.scss @@ -1,4 +1,4 @@ @use '../utils/api'; -ion-picker.ios:not(.ios26-disabled) { +ion-picker.ios:not(.ios27-disabled) { } diff --git a/src/styles/components/ion-popover.scss b/src/styles/components/ion-popover.scss index 2c36974b..79a38fdb 100644 --- a/src/styles/components/ion-popover.scss +++ b/src/styles/components/ion-popover.scss @@ -1,10 +1,10 @@ @use '../utils/api'; -ion-popover.ios:not(.ios26-disabled) { +ion-popover.ios:not(.ios27-disabled) { --backdrop-opacity: 0.2; - --background: rgba(var(--ios26-glass-background-rgb), 0.72); + --background: rgba(var(--ios27-glass-background-rgb), 0.72); --box-shadow: - inset 0 0 8px 0 rgba(var(--ios26-glass-box-shadow-color-rgb), 0.2), 0 0 10px 0 rgba(var(--ios26-glass-box-shadow-color-rgb), 0.82); + inset 0 0 8px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.2), 0 0 10px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.82); &::part(arrow) { display: none; ::after { diff --git a/src/styles/components/ion-range.scss b/src/styles/components/ion-range.scss index 43658cdc..c5456bf9 100644 --- a/src/styles/components/ion-range.scss +++ b/src/styles/components/ion-range.scss @@ -5,7 +5,7 @@ -webkit-transform: scale(1.56, 1.47) translateX(calc(#{$translate-x} * -0.1)) translateZ(0); } -ion-range.ios:not(.ios26-disabled) { +ion-range.ios:not(.ios27-disabled) { --knob-size: 20px; --knob-width: 38px; --knob-border-radius: 24px; @@ -36,7 +36,7 @@ ion-range.ios:not(.ios26-disabled) { } &:not(.range-dual-knobs).range-pressed { - --knob-background: rgba(var(--ios26-glass-background-rgb), 0.1); + --knob-background: rgba(var(--ios27-glass-background-rgb), 0.1); --knob-box-shadow: 0 0.5px 4px rgba(0, 0, 0, 0.12), 0 6px 4px rgba(0, 0, 0, 0.05), inset 0.4px 0.4px 1px 0 var(--bar-background-active); &::part(knob) { diff --git a/src/styles/components/ion-searchbar.scss b/src/styles/components/ion-searchbar.scss index bc8a97d3..bf6bb1b6 100644 --- a/src/styles/components/ion-searchbar.scss +++ b/src/styles/components/ion-searchbar.scss @@ -1,7 +1,7 @@ @use '../utils/api'; ion-modal.ios { - ion-searchbar:not(.ios26-disabled) { + ion-searchbar:not(.ios27-disabled) { .searchbar-input-container { input.searchbar-input { // Modal表示でのアイコン非表示の不具合の対応 @@ -11,7 +11,7 @@ ion-modal.ios { } } -ion-searchbar.ios:not(.ios26-disabled):not(.searchbar-classic) { +ion-searchbar.ios:not(.ios27-disabled):not(.searchbar-classic) { min-height: 60px; padding: 0; @@ -45,10 +45,10 @@ ion-searchbar.ios:not(.ios26-disabled):not(.searchbar-classic) { /** * add searchbar-classic */ -ion-toolbar.ios:not(.ios26-disabled):has(ion-searchbar.searchbar-classic.ios:not(.ios26-disabled)) { +ion-toolbar.ios:not(.ios27-disabled):has(ion-searchbar.searchbar-classic.ios:not(.ios27-disabled)) { --min-height: auto; } -ion-searchbar.ios:not(.ios26-disabled).searchbar-classic { +ion-searchbar.ios:not(.ios27-disabled).searchbar-classic { padding-bottom: 12px; min-height: auto; .searchbar-input-container input.searchbar-input { diff --git a/src/styles/components/ion-segment.scss b/src/styles/components/ion-segment.scss index 6e0b8e9a..8fa44928 100644 --- a/src/styles/components/ion-segment.scss +++ b/src/styles/components/ion-segment.scss @@ -1,11 +1,11 @@ @use '../utils/api'; -ion-segment.ios:not(.ios26-disabled) { +ion-segment.ios:not(.ios27-disabled) { @include api.glass-background; min-height: 48px; border-radius: 25px; - transition: transform var(--ios26-activated-transition-duration) ease-out; + transition: transform var(--ios27-activated-transition-duration) ease-out; // will-change is optimized to only apply when needed for performance &.segment-activated, @@ -28,7 +28,7 @@ ion-segment.ios:not(.ios26-disabled) { } } - &:not(.ios26-enable-gesture).segment-activated { + &:not(.ios27-enable-gesture).segment-activated { transform: scale(1.1) translateZ(0); -webkit-transform: scale(1.1) translateZ(0); ion-segment-button { @@ -47,7 +47,7 @@ ion-segment.ios:not(.ios26-disabled) { } } - &.ios26-enable-gesture { + &.ios27-enable-gesture { &:has(ion-segment-button.ion-activated) { transform: scale(1.1) translateZ(0); -webkit-transform: scale(1.1) translateZ(0); @@ -65,7 +65,7 @@ ion-segment.ios:not(.ios26-disabled) { } } } - &.ios26-animated { + &.ios27-animated { ion-segment-button { --indicator-color: rgba(var(--ion-text-color-rgb, 0, 0, 0), 0); } @@ -87,7 +87,7 @@ ion-segment.ios:not(.ios26-disabled) { min-height: 24px; } - &.ios26-enable-gesture { + &.ios27-enable-gesture { &:has(ion-segment-button.ion-activated) { transform: scale(1) translateZ(0); -webkit-transform: scale(1) translateZ(0); @@ -105,7 +105,7 @@ ion-segment.ios:not(.ios26-disabled) { } } } - &.ios26-animated { + &.ios27-animated { ion-segment-button { --indicator-color: rgba(var(--ion-text-color-rgb, 0, 0, 0), 0); } @@ -114,7 +114,7 @@ ion-segment.ios:not(.ios26-disabled) { } } -ion-segment-button.ios:not(.ios26-disabled) { +ion-segment-button.ios:not(.ios27-disabled) { --border-width: 0; --indicator-box-shadow: none; --indicator-color: rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.06); diff --git a/src/styles/components/ion-tabs.scss b/src/styles/components/ion-tabs.scss index 5b24d814..80f67818 100644 --- a/src/styles/components/ion-tabs.scss +++ b/src/styles/components/ion-tabs.scss @@ -1,6 +1,6 @@ @use '../utils/api'; -ion-tab-bar.ios:not(.ios26-disabled) { +ion-tab-bar.ios:not(.ios27-disabled) { @include api.glass-background; z-index: 2; @@ -9,13 +9,13 @@ ion-tab-bar.ios:not(.ios26-disabled) { &[slot='top'] { position: absolute; - top: var(--ios26-floating-safe-area-top); + top: var(--ios27-floating-safe-area-top); right: calc(16px + var(--ion-safe-area-right, 0px)); } &[slot='bottom'] { position: absolute; - bottom: var(--ios26-floating-safe-area-bottom); + bottom: var(--ios27-floating-safe-area-bottom); left: calc(16px + var(--ion-safe-area-left, 0px)); } @@ -31,7 +31,7 @@ ion-tab-bar.ios:not(.ios26-disabled) { } padding: 2px 2px; - transition: transform var(--ios26-activated-transition-duration) ease-out; + transition: transform var(--ios27-activated-transition-duration) ease-out; // will-change is optimized to only apply when needed for performance &:has(ion-tab-button.ion-activated) { @@ -53,9 +53,9 @@ ion-tab-bar.ios:not(.ios26-disabled) { /** * effectが有効な場合、effectでスタイリングするため不要 */ - &.ios26-enable-gesture.ios26-animated { + &.ios27-enable-gesture.ios27-animated { ion-tab-button.tab-selected::part(native) { - background: rgba(var(--ios26-button-color-selected-rgb), 0); + background: rgba(var(--ios27-button-color-selected-rgb), 0); } ion-tab-button.ion-activated { ion-label, @@ -66,19 +66,19 @@ ion-tab-bar.ios:not(.ios26-disabled) { } } -ion-tab-button.ios:not(.ios26-disabled) { +ion-tab-button.ios:not(.ios27-disabled) { ion-icon { font-size: 26px; } ion-label, ion-icon { transition: - filter var(--ios26-activated-transition-duration) ease, - color var(--ios26-activated-transition-duration) ease; + filter var(--ios27-activated-transition-duration) ease, + color var(--ios27-activated-transition-duration) ease; } - background: rgba(var(--ios26-glass-background-rgb), 0); + background: rgba(var(--ios27-glass-background-rgb), 0); height: auto; - transition: transform var(--ios26-activated-transition-duration) ease; + transition: transform var(--ios27-activated-transition-duration) ease; &::part(native) { overflow: visible; min-height: 56px; @@ -97,8 +97,8 @@ ion-tab-button.ios:not(.ios26-disabled) { &.tab-selected { &::part(native) { - background: rgba(var(--ios26-button-color-selected-rgb), 0.095); - transition: background var(--ios26-activated-transition-duration) ease; + background: rgba(var(--ios27-button-color-selected-rgb), 0.095); + transition: background var(--ios27-activated-transition-duration) ease; } } diff --git a/src/styles/components/ion-toast.scss b/src/styles/components/ion-toast.scss index e78ab596..0e562db7 100644 --- a/src/styles/components/ion-toast.scss +++ b/src/styles/components/ion-toast.scss @@ -1,21 +1,21 @@ @use '../utils/api'; -ion-toast.ios:not(.ios26-disabled) { - --background: rgba(var(--ios26-glass-background-rgb), 0.72); +ion-toast.ios:not(.ios27-disabled) { + --background: rgba(var(--ios27-glass-background-rgb), 0.72); --border-radius: 24px; --border-style: solid; --border-width: 0.5px; --box-shadow: - inset 0 0 8px 0 rgba(var(--ios26-glass-box-shadow-color-rgb), 0.2), 0 0 10px 0 rgba(var(--ios26-glass-box-shadow-color-rgb), 0.82); + inset 0 0 8px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.2), 0 0 10px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.82); --start: 16px; --end: 16px; &::part(wrapper) { @include api.glass-background($include-background: false, $include-box-shadow: false, $include-border: false); - border-top-color: rgba(var(--ios26-glass-border-color-rgb), 1); - border-right-color: rgba(var(--ios26-glass-border-color-rgb), 0.8); - border-bottom-color: rgba(var(--ios26-glass-border-color-rgb), 1); - border-left-color: rgba(var(--ios26-glass-border-color-rgb), 0.6); + border-top-color: rgba(var(--ios27-glass-border-color-rgb), 1); + border-right-color: rgba(var(--ios27-glass-border-color-rgb), 0.8); + border-bottom-color: rgba(var(--ios27-glass-border-color-rgb), 1); + border-left-color: rgba(var(--ios27-glass-border-color-rgb), 0.6); } &.ion-color { diff --git a/src/styles/components/ion-toggle.scss b/src/styles/components/ion-toggle.scss index 18508905..ced4b8e3 100644 --- a/src/styles/components/ion-toggle.scss +++ b/src/styles/components/ion-toggle.scss @@ -4,7 +4,7 @@ * Adjustments have been made to prevent the right edge from being cut off within the ion-item. * When the native-inner part be added to the ion-item, it will be removed. */ -ion-item.ios:not(.ios26-disabled) ion-toggle.ios:not(.ios26-disabled) { +ion-item.ios:not(.ios27-disabled) ion-toggle.ios:not(.ios27-disabled) { &.toggle-checked.toggle-activated::part(track) { transform-origin: left; transform: scaleX(0.894) translateZ(0); @@ -16,7 +16,7 @@ ion-item.ios:not(.ios26-disabled) ion-toggle.ios:not(.ios26-disabled) { } } -ion-toggle.ios:not(.ios26-disabled) { +ion-toggle.ios:not(.ios27-disabled) { --handle-width: 38px; --handle-height: 24px; --handle-max-width: none; @@ -48,8 +48,8 @@ ion-toggle.ios:not(.ios26-disabled) { @include api.glass-background($opacity: 0.1, $blur: 0.5px, $saturate: 120%, $include-background: false, $include-box-shadow: false); } &.toggle-activated { - --handle-background: rgba(var(--ios26-glass-background-rgb), 0.1); - --handle-background-checked: rgba(var(--ios26-glass-background-rgb), 0.1); + --handle-background: rgba(var(--ios27-glass-background-rgb), 0.1); + --handle-background-checked: rgba(var(--ios27-glass-background-rgb), 0.1); --handle-box-shadow: inset 0 0 8px 0 var(--track-background); } &.ion-color.toggle-checked.toggle-activated { diff --git a/src/styles/components/ion-toolbar.scss b/src/styles/components/ion-toolbar.scss index 4b6f80e7..6a299071 100644 --- a/src/styles/components/ion-toolbar.scss +++ b/src/styles/components/ion-toolbar.scss @@ -6,34 +6,34 @@ * padding-top: var(--ion-safe-area-top, 0); * } */ -ion-header.ios:not(.ios26-disabled) ion-toolbar:not(.ios26-disabled):first-of-type { +ion-header.ios:not(.ios27-disabled) ion-toolbar:not(.ios27-disabled):first-of-type { padding-top: max(calc(var(--ion-safe-area-top) - 12px), 4px); } -ion-modal.ios:not(.ios26-disabled).modal-card, -ion-modal.ios:not(.ios26-disabled).modal-sheet { - ion-header.ios:not(.ios26-disabled) ion-toolbar.ios:not(.ios26-disabled):first-of-type { +ion-modal.ios:not(.ios27-disabled).modal-card, +ion-modal.ios:not(.ios27-disabled).modal-sheet { + ion-header.ios:not(.ios27-disabled) ion-toolbar.ios:not(.ios27-disabled):first-of-type { padding-top: 6px; } } -ion-header.ios.header-collapse-condense:not(.ios26-disabled) ion-toolbar:not(.ios26-disabled):first-of-type { +ion-header.ios.header-collapse-condense:not(.ios27-disabled) ion-toolbar:not(.ios27-disabled):first-of-type { padding-top: 0; } -ion-toolbar.ios:not(.toolbar-title-large):not(.ios26-disabled):not(:has(ion-segment.segment-expand)) { +ion-toolbar.ios:not(.toolbar-title-large):not(.ios27-disabled):not(:has(ion-segment.segment-expand)) { --min-height: 68px; } -ion-header.ios:not(.ios26-disabled):not(.header-collapse-condense):not(:where(ion-modal *)) - > ion-toolbar.ios:not(.ios26-disabled):not(.toolbar-title-large):not(.toolbar-searchbar):not( +ion-header.ios:not(.ios27-disabled):not(.header-collapse-condense):not(:where(ion-modal *)) + > ion-toolbar.ios:not(.ios27-disabled):not(.toolbar-title-large):not(.toolbar-searchbar):not( :has(ion-segment.segment-expand) ):first-of-type { padding-top: max(calc(var(--ion-safe-area-top) - 10px), 6px); --min-height: 64px; } -ion-toolbar.ios:not(.ios26-disabled).toolbar-searchbar { +ion-toolbar.ios:not(.ios27-disabled).toolbar-searchbar { *[slot='start'], *[slot='end'] { align-self: center; @@ -42,7 +42,7 @@ ion-toolbar.ios:not(.ios26-disabled).toolbar-searchbar { ion-buttons[slot='start'] { margin-right: 6px; } - ion-searchbar.ios:not(.ios26-disabled) { + ion-searchbar.ios:not(.ios27-disabled) { .searchbar-input-container { margin: 0 12px 0 6px; } @@ -52,7 +52,7 @@ ion-toolbar.ios:not(.ios26-disabled).toolbar-searchbar { ion-buttons[slot='end'] { margin-left: 6px; } - ion-searchbar.ios:not(.ios26-disabled) { + ion-searchbar.ios:not(.ios27-disabled) { .searchbar-input-container { margin: 0 6px 0 12px; } @@ -60,7 +60,7 @@ ion-toolbar.ios:not(.ios26-disabled).toolbar-searchbar { } } -ion-toolbar.ios:not(.ios26-disabled) { +ion-toolbar.ios:not(.ios27-disabled) { ion-buttons { margin-left: 12px; margin-right: 12px; diff --git a/src/styles/default-variables.scss b/src/styles/default-variables.scss index eccfd2d3..10cde2ed 100644 --- a/src/styles/default-variables.scss +++ b/src/styles/default-variables.scss @@ -1,6 +1,6 @@ /** * @naming - * prefix: ios26 + * prefix: ios27 * target-element: tab-button * target css property: color * status: selected @@ -8,25 +8,25 @@ */ :root { - --ios26-floating-safe-area-top: max(10px, var(--ion-safe-area-top, 0px)); - --ios26-floating-safe-area-bottom: max(10px, calc(var(--ion-safe-area-bottom, 0px) - 12px)); + --ios27-floating-safe-area-top: max(10px, var(--ion-safe-area-top, 0px)); + --ios27-floating-safe-area-bottom: max(10px, calc(var(--ion-safe-area-bottom, 0px) - 12px)); - --ios26-activated-transition-duration: 140ms; + --ios27-activated-transition-duration: 140ms; - --ios26-glass-background-rgb: 255, 255, 255; - --ios26-glass-box-shadow-color-rgb: 220, 220, 220; - --ios26-glass-border-color-rgb: 255, 255, 255; - --ios26-button-color-selected-rgb: 16, 16, 16; + --ios27-glass-background-rgb: 255, 255, 255; + --ios27-glass-box-shadow-color-rgb: 220, 220, 220; + --ios27-glass-border-color-rgb: 255, 255, 255; + --ios27-button-color-selected-rgb: 16, 16, 16; - --ios26-menu-width: 360px; + --ios27-menu-width: 360px; /** - * `--ios26-color-background-rgb` is deprecated. - * You should replace to '--ios26-content-box-shadow-rgb'. + * `--ios27-color-background-rgb` is deprecated. + * You should replace to '--ios27-content-box-shadow-rgb'. * This variable can also be defined in root, but if you want to set multiple background colors individually, it is easier to set them as follows. - * ion-content { --ios26-content-box-shadow-rgb: var(--ion-color-base-rgb); } + * ion-content { --ios27-content-box-shadow-rgb: var(--ion-color-base-rgb); } */ - --ios26-content-box-shadow-rgb: var(--ion-color-base-rgb, var(--ion-background-color-rgb, 255, 255, 255)); + --ios27-content-box-shadow-rgb: var(--ion-color-base-rgb, var(--ion-background-color-rgb, 255, 255, 255)); /** * `--ion-color-**-brightness-rgb` is deprecated. diff --git a/src/styles/ionic-theme-ios26-dark-always.scss b/src/styles/ionic-theme-ios27-dark-always.scss similarity index 100% rename from src/styles/ionic-theme-ios26-dark-always.scss rename to src/styles/ionic-theme-ios27-dark-always.scss diff --git a/src/styles/ionic-theme-ios26-dark-class.scss b/src/styles/ionic-theme-ios27-dark-class.scss similarity index 100% rename from src/styles/ionic-theme-ios26-dark-class.scss rename to src/styles/ionic-theme-ios27-dark-class.scss diff --git a/src/styles/ionic-theme-ios26-dark-system.scss b/src/styles/ionic-theme-ios27-dark-system.scss similarity index 100% rename from src/styles/ionic-theme-ios26-dark-system.scss rename to src/styles/ionic-theme-ios27-dark-system.scss diff --git a/src/styles/ionic-theme-ios26.scss b/src/styles/ionic-theme-ios27.scss similarity index 100% rename from src/styles/ionic-theme-ios26.scss rename to src/styles/ionic-theme-ios27.scss diff --git a/src/styles/md-remove-ios-class-effect.scss b/src/styles/md-remove-ios-class-effect.scss index 0180a5ff..e36c9402 100644 --- a/src/styles/md-remove-ios-class-effect.scss +++ b/src/styles/md-remove-ios-class-effect.scss @@ -1,9 +1,9 @@ ion-buttons.md { /** - * ion-buttons.ios26-disabled > ion-button.button-default is for ios26 structure. + * ion-buttons.ios27-disabled > ion-button.button-default is for ios27 structure. * for .md, remove button-default styles. Will be button-clear. */ - ion-button.md:not(.ios26-disabled).button-default { + ion-button.md:not(.ios27-disabled).button-default { // copy .button-clear --color: initial; --background: transparent; diff --git a/src/styles/utils/api.scss b/src/styles/utils/api.scss index f2d843cc..6f09db5b 100644 --- a/src/styles/utils/api.scss +++ b/src/styles/utils/api.scss @@ -22,8 +22,8 @@ $_glass-surface: linear-gradient( $opacity: 0.72, $blur: 2px, $saturate: 360%, - $background-rgb: var(--ios26-glass-background-rgb), - $border-color-rgb: var(--ios26-glass-border-color-rgb), + $background-rgb: var(--ios27-glass-background-rgb), + $border-color-rgb: var(--ios27-glass-border-color-rgb), $include-background: true, $include-box-shadow: true, $include-border: true, @@ -40,10 +40,10 @@ $_glass-surface: linear-gradient( @if $include-box-shadow { box-shadow: inset 0 0 0 0.5px rgba($border-color-rgb, 0.6), - inset 0 0 1px 0 rgba(var(--ios26-glass-box-shadow-color-rgb), 0.18), + inset 0 0 1px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.18), inset 0 1px 2px 0 rgba($border-color-rgb, 0.8), inset 0 -1px 2px 0 rgba($border-color-rgb, 0.5), - 0 0.5px 1px 0 rgba(var(--ios26-glass-box-shadow-color-rgb), $shadow-opacity); + 0 0.5px 1px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), $shadow-opacity); } @if $include-border { border: 0.5px solid; @@ -84,14 +84,14 @@ $_glass-surface: linear-gradient( } @mixin glass-background-button-activated { - background-color: rgba(var(--ios26-glass-background-rgb), 0.96); + background-color: rgba(var(--ios27-glass-background-rgb), 0.96); border-color: rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.12) rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.32) rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.16) rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.28); box-shadow: - inset 0 0 0 0.5px rgba(var(--ios26-glass-border-color-rgb), 0.95), - inset 0 1px 3px 0 rgba(var(--ios26-glass-border-color-rgb), 0.85), - inset 0 -1px 2px 0 rgba(var(--ios26-glass-border-color-rgb), 0.6), - 0 0.5px 1px 0 rgba(var(--ios26-glass-box-shadow-color-rgb), 0.12); + inset 0 0 0 0.5px rgba(var(--ios27-glass-border-color-rgb), 0.95), + inset 0 1px 3px 0 rgba(var(--ios27-glass-border-color-rgb), 0.85), + inset 0 -1px 2px 0 rgba(var(--ios27-glass-border-color-rgb), 0.6), + 0 0.5px 1px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.12); } @mixin glass-background-button-activated-dark( @@ -102,18 +102,18 @@ $_glass-surface: linear-gradient( $include-box-shadow: true ) { @if $include-background { - background: rgba(var(--ios26-button-color-selected-rgb), $opacity); + background: rgba(var(--ios27-button-color-selected-rgb), $opacity); } @else { - background-color: rgba(var(--ios26-button-color-selected-rgb), $opacity); + background-color: rgba(var(--ios27-button-color-selected-rgb), $opacity); } backdrop-filter: blur($blur) saturate($saturate); @if $include-box-shadow { - box-shadow: inset 0 0 16px 0 rgba(var(--ios26-glass-box-shadow-color-rgb), 0.55); + box-shadow: inset 0 0 16px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.55); } - border-top: 0.8px solid rgba(var(--ios26-button-color-selected-rgb), 0.8); - border-right: 0.8px solid rgba(var(--ios26-button-color-selected-rgb), 0.4); - border-bottom: 0.8px solid rgba(var(--ios26-button-color-selected-rgb), 0.8); - border-left: 0.8px solid rgba(var(--ios26-button-color-selected-rgb), 0.6); + border-top: 0.8px solid rgba(var(--ios27-button-color-selected-rgb), 0.8); + border-right: 0.8px solid rgba(var(--ios27-button-color-selected-rgb), 0.4); + border-bottom: 0.8px solid rgba(var(--ios27-button-color-selected-rgb), 0.8); + border-left: 0.8px solid rgba(var(--ios27-button-color-selected-rgb), 0.6); background-image: none; background-clip: border-box; background-origin: padding-box; diff --git a/src/styles/utils/dark/ion-button.scss b/src/styles/utils/dark/ion-button.scss index 2d2f3fdc..c4dbde57 100644 --- a/src/styles/utils/dark/ion-button.scss +++ b/src/styles/utils/dark/ion-button.scss @@ -5,7 +5,7 @@ @include api.glass-background-button-activated-dark; } - ion-button:not(.ios26-disabled).button-clear { + ion-button:not(.ios27-disabled).button-clear { &.ion-activated { color: rgb(var(--ion-text-color-rgb, 0, 0, 0)); &.ion-color { @@ -14,8 +14,8 @@ } } - ion-button:not(.ios26-disabled), - ion-back-button:not(.ios26-disabled) { + ion-button:not(.ios27-disabled), + ion-back-button:not(.ios27-disabled) { &.ion-activated { --color: rgba(var(--ion-text-color-rgb, 0, 0, 0), 1); @@ -28,10 +28,10 @@ @mixin theme-dark-button($is-back-button: false) { &.ion-activated:not(.button-solid):not(.button-outline):not(.button-clear) { - --background: rgba(var(--ios26-button-color-selected-rgb), 0.56); + --background: rgba(var(--ios27-button-color-selected-rgb), 0.56); --color: rgba(var(--ion-text-color-rgb, 0, 0, 0), 1); @if not $is-back-button { - --box-shadow: inset 0 0 16px 0 rgba(var(--ios26-glass-box-shadow-color-rgb), 0.55); + --box-shadow: inset 0 0 16px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.55); } &.ion-color { --color: rgba(var(--ion-color-base-rgb, var(--ion-text-color-rgb, 0, 0, 0)), 1); @@ -46,13 +46,13 @@ } @mixin ion-button { - ion-buttons.ios:not(.ios26-disabled):not(:has(ion-back-button, ion-button:not(.button-clear))) { + ion-buttons.ios:not(.ios27-disabled):not(:has(ion-back-button, ion-button:not(.button-clear))) { @include theme-dark-buttons; } - ion-button.ios:not(.ios26-disabled) { + ion-button.ios:not(.ios27-disabled) { @include theme-dark-button; } - ion-back-button.ios:not(.ios26-disabled) { + ion-back-button.ios:not(.ios27-disabled) { @include theme-dark-button($is-back-button: true); } } diff --git a/src/styles/utils/dark/ion-fab.scss b/src/styles/utils/dark/ion-fab.scss index b6933207..a3defa29 100644 --- a/src/styles/utils/dark/ion-fab.scss +++ b/src/styles/utils/dark/ion-fab.scss @@ -1,7 +1,7 @@ @use '../api'; @mixin ion-fab { - ion-fab.ios:not(.ios26-disabled) { + ion-fab.ios:not(.ios27-disabled) { ion-fab-button { &.ion-activated { &::part(native) { diff --git a/src/styles/utils/dark/ion-segment.scss b/src/styles/utils/dark/ion-segment.scss index 535ba659..b858e912 100644 --- a/src/styles/utils/dark/ion-segment.scss +++ b/src/styles/utils/dark/ion-segment.scss @@ -1,10 +1,10 @@ @mixin ion-segment { - ion-segment.ios:not(.ios26-disabled) { + ion-segment.ios:not(.ios27-disabled) { } - ion-segment-button.ios:not(.ios26-disabled) { + ion-segment-button.ios:not(.ios27-disabled) { &.ion-cloned-element { &::part(native) { - --ios26-glass-border-color-rgb: 120, 120, 120; + --ios27-glass-border-color-rgb: 120, 120, 120; box-shadow: inset 0 0 8px 0 rgba(255, 255, 255, 0.2); } } diff --git a/src/styles/utils/dark/ion-tabs.scss b/src/styles/utils/dark/ion-tabs.scss index 1d9bf51d..c6923576 100644 --- a/src/styles/utils/dark/ion-tabs.scss +++ b/src/styles/utils/dark/ion-tabs.scss @@ -1,9 +1,9 @@ @use '../api'; @mixin ion-tabs { - ion-tab-bar.ios:not(.ios26-disabled) { + ion-tab-bar.ios:not(.ios27-disabled) { } - ion-tab-button.ios:not(.ios26-disabled) { + ion-tab-button.ios:not(.ios27-disabled) { &.ion-activated { ion-label, ion-icon { @@ -13,7 +13,7 @@ } &.ion-cloned-element { &::part(native) { - --ios26-glass-border-color-rgb: 120, 120, 120; + --ios27-glass-border-color-rgb: 120, 120, 120; box-shadow: inset 0 0 8px 0 rgba(255, 255, 255, 0.2); } } diff --git a/src/styles/utils/theme-dark.scss b/src/styles/utils/theme-dark.scss index c162c761..99e32432 100644 --- a/src/styles/utils/theme-dark.scss +++ b/src/styles/utils/theme-dark.scss @@ -8,13 +8,13 @@ @use 'dark/ion-segment' as *; @mixin default-variables { - //--ios26-glass-background-rgb: 35, 35, 35; - --ios26-glass-background-rgb: 62, 62, 62; - --ios26-glass-box-shadow-color-rgb: 0, 0, 0 / 0; - --ios26-glass-border-color-rgb: 68, 68, 68; - --ios26-button-color-selected-rgb: 255, 255, 255; + //--ios27-glass-background-rgb: 35, 35, 35; + --ios27-glass-background-rgb: 62, 62, 62; + --ios27-glass-box-shadow-color-rgb: 0, 0, 0 / 0; + --ios27-glass-border-color-rgb: 68, 68, 68; + --ios27-button-color-selected-rgb: 255, 255, 255; - --ios26-content-box-shadow-rgb: 0, 0, 0; + --ios27-content-box-shadow-rgb: 0, 0, 0; } @mixin theme-dark { diff --git a/src/styles/utils/translucent.scss b/src/styles/utils/translucent.scss index e6830ed5..2fa37234 100644 --- a/src/styles/utils/translucent.scss +++ b/src/styles/utils/translucent.scss @@ -1,7 +1,7 @@ @use 'api'; -ion-header.ios:not(.ios26-disabled).header-translucent, -ion-footer.ios:not(.ios26-disabled).footer-translucent { +ion-header.ios:not(.ios27-disabled).header-translucent, +ion-footer.ios:not(.ios27-disabled).footer-translucent { .header-background, .footer-background { backdrop-filter: none; @@ -20,14 +20,14 @@ ion-footer.ios:not(.ios26-disabled).footer-translucent { } } -ion-header.ios:not(.ios26-disabled).header-translucent:not(.header-collapse-condense) { - &:has(> ion-toolbar.ios:not(.ios26-disabled) > *)::before { +ion-header.ios:not(.ios27-disabled).header-translucent:not(.header-collapse-condense) { + &:has(> ion-toolbar.ios:not(.ios27-disabled) > *)::before { height: 100%; - background: rgba(var(--ion-color-base-rgb, var(--ios26-content-box-shadow-rgb)), calc(0.2 * var(--opacity-scale, 1))); + background: rgba(var(--ion-color-base-rgb, var(--ios27-content-box-shadow-rgb)), calc(0.2 * var(--opacity-scale, 1))); backdrop-filter: blur(8px); } - &:not(.ion-no-border) > ion-toolbar.ios:not(.ios26-disabled):has(> *):last-of-type { + &:not(.ion-no-border) > ion-toolbar.ios:not(.ios27-disabled):has(> *):last-of-type { --border-width: 0 0 0.5px; --border-color: var(--ion-toolbar-border-color, rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.08)); &::part(background) { @@ -37,7 +37,7 @@ ion-header.ios:not(.ios26-disabled).header-translucent:not(.header-collapse-cond } } -ion-header.ios:not(.ios26-disabled).header-collapse-main ion-toolbar.in-toolbar ion-title { +ion-header.ios:not(.ios27-disabled).header-collapse-main ion-toolbar.in-toolbar ion-title { transition: opacity 0.5s ease-in-out, color 0.5s ease-in-out, @@ -45,15 +45,15 @@ ion-header.ios:not(.ios26-disabled).header-collapse-main ion-toolbar.in-toolbar transform 0.5s ease-in-out; } -ion-header.ios:not(.ios26-disabled).header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-title { +ion-header.ios:not(.ios27-disabled).header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-title { color: transparent; text-shadow: 0 0 1px var(--ion-color-base, var(--ion-toolbar-color, var(--ion-text-color, #000))); transform: translateY(8px); } -ion-header.ios:not(.ios26-disabled).header-translucent::before, -ion-header.ios:not(.ios26-disabled).header-translucent::after, -ion-content.ios:not(.ios26-disabled).content-fullscreen::part(background)::before { +ion-header.ios:not(.ios27-disabled).header-translucent::before, +ion-header.ios:not(.ios27-disabled).header-translucent::after, +ion-content.ios:not(.ios27-disabled).content-fullscreen::part(background)::before { content: ''; position: absolute; width: 100%; @@ -61,7 +61,7 @@ ion-content.ios:not(.ios26-disabled).content-fullscreen::part(background)::befor z-index: 1; } -ion-header.ios:not(.ios26-disabled).header-translucent::before { +ion-header.ios:not(.ios27-disabled).header-translucent::before { /** * With safe-area effect, this is need. */ @@ -70,7 +70,7 @@ ion-header.ios:not(.ios26-disabled).header-translucent::before { height: var(--ion-safe-area-top); } -ion-header.ios:not(.ios26-disabled).header-translucent::after { +ion-header.ios:not(.ios27-disabled).header-translucent::after { z-index: 2; top: 0; height: 100%; @@ -88,8 +88,8 @@ ion-header.ios:not(.ios26-disabled).header-translucent::after { height: var(--offset-top, 0px); background: linear-gradient( in oklab, - rgba(var(--ios26-content-box-shadow-rgb), 0.5) 0%, - rgba(var(--ios26-content-box-shadow-rgb), 0.2) 50%, - rgba(var(--ios26-content-box-shadow-rgb), 0) 100% + rgba(var(--ios27-content-box-shadow-rgb), 0.5) 0%, + rgba(var(--ios27-content-box-shadow-rgb), 0.2) 50%, + rgba(var(--ios27-content-box-shadow-rgb), 0) 100% ); } diff --git a/src/transition/ios.transition.ts b/src/transition/ios.transition.ts index e5301941..9dd479c3 100644 --- a/src/transition/ios.transition.ts +++ b/src/transition/ios.transition.ts @@ -24,14 +24,14 @@ const animateFixedBackButton = ( otherPage?: HTMLElement, ) => { const button = page.querySelector( - ':scope > ion-header.header-translucent:not(.ios26-disabled) ion-back-button:not(.ios26-disabled)', + ':scope > ion-header.header-translucent:not(.ios27-disabled) ion-back-button:not(.ios27-disabled)', ); if (!button || button.offsetWidth === 0) { return; } const otherButton = otherPage?.querySelector( - ':scope > ion-header.header-translucent:not(.ios26-disabled) ion-back-button:not(.ios26-disabled)', + ':scope > ion-header.header-translucent:not(.ios27-disabled) ion-back-button:not(.ios27-disabled)', ); const persistent = !!otherButton && otherButton.offsetWidth > 0; const buttons = [button, ...(persistent ? [otherButton!] : [])].map((element) => ({ @@ -623,7 +623,7 @@ export const iosTransitionAnimation = (navEl: HTMLElement, opts: TransitionOptio .beforeRemoveClass('ion-page-invisible'); const topPage = backDirection ? leavingEl : enteringEl; - if (topPage?.querySelector(':scope > ion-header.header-translucent:not(.ios26-disabled)')) { + if (topPage?.querySelector(':scope > ion-header.header-translucent:not(.ios27-disabled)')) { const shadow = topPage.style.boxShadow; rootAnimation.beforeAddWrite(() => { topPage.style.boxShadow = `${isRTL ? 4 : -4}px 0 24px rgba(0, 0, 0, 0.04)`; @@ -640,7 +640,7 @@ export const iosTransitionAnimation = (navEl: HTMLElement, opts: TransitionOptio rootAnimation.addAnimation(navDecorAnimation); } - if (enteringEl.querySelector(':scope > ion-header.header-translucent:not(.ios26-disabled)')) { + if (enteringEl.querySelector(':scope > ion-header.header-translucent:not(.ios27-disabled)')) { enteringContentAnimation.addElement(enteringEl); } else if (!contentEl && enteringToolBarEls.length === 0 && headerEls.length === 0) { enteringContentAnimation.addElement(enteringEl.querySelector(':scope > .ion-page, :scope > ion-nav, :scope > ion-tabs')!); // REVIEW @@ -661,7 +661,7 @@ export const iosTransitionAnimation = (navEl: HTMLElement, opts: TransitionOptio enteringContentAnimation.beforeClearStyles([OPACITY]).fromTo('transform', `translateX(${OFF_RIGHT})`, `translateX(${CENTER})`); } - if (contentEl && !enteringEl.querySelector(':scope > ion-header.header-translucent:not(.ios26-disabled)')) { + if (contentEl && !enteringEl.querySelector(':scope > ion-header.header-translucent:not(.ios27-disabled)')) { const enteringTransitionEffectEl = shadow(contentEl).querySelector('.transition-effect'); if (enteringTransitionEffectEl) { const enteringTransitionCoverEl = enteringTransitionEffectEl.querySelector('.transition-cover'); @@ -705,7 +705,7 @@ export const iosTransitionAnimation = (navEl: HTMLElement, opts: TransitionOptio const enteringContentHasLargeTitle = enteringEl.querySelector('ion-header.header-collapse-condense'); enteringToolBarEls.forEach((enteringToolBarEl) => { - if (enteringToolBarEl.closest('ion-header')?.matches('.header-translucent:not(.ios26-disabled)')) { + if (enteringToolBarEl.closest('ion-header')?.matches('.header-translucent:not(.ios27-disabled)')) { return; } const enteringToolBar = createAnimation(); @@ -796,7 +796,7 @@ export const iosTransitionAnimation = (navEl: HTMLElement, opts: TransitionOptio const leavingToolBarEls = leavingEl.querySelectorAll(':scope > ion-header > ion-toolbar'); const leavingHeaderEls = leavingEl.querySelectorAll(':scope > ion-header > *:not(ion-toolbar), :scope > ion-footer > *'); - if (leavingEl.querySelector(':scope > ion-header.header-translucent:not(.ios26-disabled)')) { + if (leavingEl.querySelector(':scope > ion-header.header-translucent:not(.ios27-disabled)')) { leavingContent.addElement(leavingEl); } else if (!leavingContentEl && leavingToolBarEls.length === 0 && leavingHeaderEls.length === 0) { leavingContent.addElement(leavingEl.querySelector(':scope > .ion-page, :scope > ion-nav, :scope > ion-tabs')!); // REVIEW @@ -824,7 +824,7 @@ export const iosTransitionAnimation = (navEl: HTMLElement, opts: TransitionOptio leavingContent.fromTo('transform', `translateX(${CENTER})`, `translateX(${OFF_LEFT})`).fromTo(OPACITY, 1, OFF_OPACITY); } - if (leavingContentEl && !leavingEl.querySelector(':scope > ion-header.header-translucent:not(.ios26-disabled)')) { + if (leavingContentEl && !leavingEl.querySelector(':scope > ion-header.header-translucent:not(.ios27-disabled)')) { const leavingTransitionEffectEl = shadow(leavingContentEl).querySelector('.transition-effect'); if (leavingTransitionEffectEl) { @@ -856,7 +856,7 @@ export const iosTransitionAnimation = (navEl: HTMLElement, opts: TransitionOptio } leavingToolBarEls.forEach((leavingToolBarEl) => { - if (leavingToolBarEl.closest('ion-header')?.matches('.header-translucent:not(.ios26-disabled)')) { + if (leavingToolBarEl.closest('ion-header')?.matches('.header-translucent:not(.ios27-disabled)')) { return; } const leavingToolBar = createAnimation(); diff --git a/swiftui/ionic-ios26-native.xcodeproj/project.pbxproj b/swiftui/ionic-ios26-native.xcodeproj/project.pbxproj deleted file mode 100644 index 028dd38c..00000000 --- a/swiftui/ionic-ios26-native.xcodeproj/project.pbxproj +++ /dev/null @@ -1,337 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 77; - objects = { - -/* Begin PBXFileReference section */ - DBF0AF4E2F5BBC5100EBC719 /* ionic-ios26-native.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ionic-ios26-native.app"; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFileSystemSynchronizedRootGroup section */ - DBF0AF502F5BBC5100EBC719 /* ionic-ios26-native */ = { - isa = PBXFileSystemSynchronizedRootGroup; - path = "ionic-ios26-native"; - sourceTree = ""; - }; -/* End PBXFileSystemSynchronizedRootGroup section */ - -/* Begin PBXFrameworksBuildPhase section */ - DBF0AF4B2F5BBC5100EBC719 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - DBF0AF452F5BBC5100EBC719 = { - isa = PBXGroup; - children = ( - DBF0AF502F5BBC5100EBC719 /* ionic-ios26-native */, - DBF0AF4F2F5BBC5100EBC719 /* Products */, - ); - sourceTree = ""; - }; - DBF0AF4F2F5BBC5100EBC719 /* Products */ = { - isa = PBXGroup; - children = ( - DBF0AF4E2F5BBC5100EBC719 /* ionic-ios26-native.app */, - ); - name = Products; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXNativeTarget section */ - DBF0AF4D2F5BBC5100EBC719 /* ionic-ios26-native */ = { - isa = PBXNativeTarget; - buildConfigurationList = DBF0AF592F5BBC5200EBC719 /* Build configuration list for PBXNativeTarget "ionic-ios26-native" */; - buildPhases = ( - DBF0AF4A2F5BBC5100EBC719 /* Sources */, - DBF0AF4B2F5BBC5100EBC719 /* Frameworks */, - DBF0AF4C2F5BBC5100EBC719 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - fileSystemSynchronizedGroups = ( - DBF0AF502F5BBC5100EBC719 /* ionic-ios26-native */, - ); - name = "ionic-ios26-native"; - packageProductDependencies = ( - ); - productName = "ionic-ios26-native"; - productReference = DBF0AF4E2F5BBC5100EBC719 /* ionic-ios26-native.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - DBF0AF462F5BBC5100EBC719 /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 2610; - LastUpgradeCheck = 2610; - TargetAttributes = { - DBF0AF4D2F5BBC5100EBC719 = { - CreatedOnToolsVersion = 26.1.1; - }; - }; - }; - buildConfigurationList = DBF0AF492F5BBC5100EBC719 /* Build configuration list for PBXProject "ionic-ios26-native" */; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = DBF0AF452F5BBC5100EBC719; - minimizedProjectReferenceProxies = 1; - preferredProjectObjectVersion = 77; - productRefGroup = DBF0AF4F2F5BBC5100EBC719 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - DBF0AF4D2F5BBC5100EBC719 /* ionic-ios26-native */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - DBF0AF4C2F5BBC5100EBC719 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - DBF0AF4A2F5BBC5100EBC719 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - DBF0AF572F5BBC5200EBC719 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = dwarf; - DEVELOPMENT_TEAM = P7E2DJ2G49; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 26.1; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - }; - name = Debug; - }; - DBF0AF582F5BBC5200EBC719 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - DEVELOPMENT_TEAM = P7E2DJ2G49; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 26.1; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - VALIDATE_PRODUCT = YES; - }; - name = Release; - }; - DBF0AF5A2F5BBC5200EBC719 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = P7E2DJ2G49; - ENABLE_PREVIEWS = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchScreen_Generation = YES; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = "jp.rdlabo.ionic-ios26-native"; - PRODUCT_NAME = "$(TARGET_NAME)"; - STRING_CATALOG_GENERATE_SYMBOLS = YES; - SWIFT_APPROACHABLE_CONCURRENCY = YES; - SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - DBF0AF5B2F5BBC5200EBC719 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = P7E2DJ2G49; - ENABLE_PREVIEWS = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_UIApplicationSceneManifest_Generation = YES; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchScreen_Generation = YES; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = "jp.rdlabo.ionic-ios26-native"; - PRODUCT_NAME = "$(TARGET_NAME)"; - STRING_CATALOG_GENERATE_SYMBOLS = YES; - SWIFT_APPROACHABLE_CONCURRENCY = YES; - SWIFT_DEFAULT_ACTOR_ISOLATION = MainActor; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_UPCOMING_FEATURE_MEMBER_IMPORT_VISIBILITY = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - DBF0AF492F5BBC5100EBC719 /* Build configuration list for PBXProject "ionic-ios26-native" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - DBF0AF572F5BBC5200EBC719 /* Debug */, - DBF0AF582F5BBC5200EBC719 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - DBF0AF592F5BBC5200EBC719 /* Build configuration list for PBXNativeTarget "ionic-ios26-native" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - DBF0AF5A2F5BBC5200EBC719 /* Debug */, - DBF0AF5B2F5BBC5200EBC719 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = DBF0AF462F5BBC5100EBC719 /* Project object */; -} diff --git a/swiftui/ionic-ios26-native.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/swiftui/ionic-ios26-native.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a6..00000000 --- a/swiftui/ionic-ios26-native.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/swiftui/ionic-ios26-native.xcodeproj/project.xcworkspace/xcuserdata/sakakibara.xcuserdatad/UserInterfaceState.xcuserstate b/swiftui/ionic-ios26-native.xcodeproj/project.xcworkspace/xcuserdata/sakakibara.xcuserdatad/UserInterfaceState.xcuserstate deleted file mode 100644 index c1bbedf77c72853b9c7a8fdc506492ed5f9a42ee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22818 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 diff --git a/swiftui/ionic-ios26-native.xcodeproj/xcuserdata/sakakibara.xcuserdatad/xcschemes/xcschememanagement.plist b/swiftui/ionic-ios26-native.xcodeproj/xcuserdata/sakakibara.xcuserdatad/xcschemes/xcschememanagement.plist deleted file mode 100644 index 6f24c05d..00000000 --- a/swiftui/ionic-ios26-native.xcodeproj/xcuserdata/sakakibara.xcuserdatad/xcschemes/xcschememanagement.plist +++ /dev/null @@ -1,14 +0,0 @@ - - - - - SchemeUserState - - ionic-ios26-native.xcscheme_^#shared#^_ - - orderHint - 0 - - - - diff --git a/swiftui/ionic-ios26-native/Assets.xcassets/AccentColor.colorset/Contents.json b/swiftui/ionic-ios26-native/Assets.xcassets/AccentColor.colorset/Contents.json deleted file mode 100644 index eb878970..00000000 --- a/swiftui/ionic-ios26-native/Assets.xcassets/AccentColor.colorset/Contents.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "colors" : [ - { - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/swiftui/ionic-ios26-native/Assets.xcassets/AppIcon.appiconset/Contents.json b/swiftui/ionic-ios26-native/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 23058801..00000000 --- a/swiftui/ionic-ios26-native/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "tinted" - } - ], - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/swiftui/ionic-ios26-native/Assets.xcassets/Contents.json b/swiftui/ionic-ios26-native/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596..00000000 --- a/swiftui/ionic-ios26-native/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/swiftui/ionic-ios26-native/ContentView.swift b/swiftui/ionic-ios26-native/ContentView.swift deleted file mode 100644 index d217f2a0..00000000 --- a/swiftui/ionic-ios26-native/ContentView.swift +++ /dev/null @@ -1,11 +0,0 @@ -import SwiftUI - -struct ContentView: View { - var body: some View { - IndexView() - } -} - -#Preview { - ContentView() -} diff --git a/swiftui/ionic-ios26-native/Theme/IOS26Theme.swift b/swiftui/ionic-ios26-native/Theme/IOS26Theme.swift deleted file mode 100644 index b8f53f9f..00000000 --- a/swiftui/ionic-ios26-native/Theme/IOS26Theme.swift +++ /dev/null @@ -1,35 +0,0 @@ -import SwiftUI -extension Color { - /// Light theme: rgb(255, 255, 255) - static let ios26GlassBackground = Color(red: 255/255, green: 255/255, blue: 255/255) - /// Light theme: rgb(220, 220, 220) - static let ios26GlassBoxShadow = Color(red: 220/255, green: 220/255, blue: 220/255) - /// Selected/primary text: rgb(16, 16, 16) - static let ios26ButtonColorSelected = Color(red: 16/255, green: 16/255, blue: 16/255) - - /// Dark theme: rgb(62, 62, 62) - static let ios26DarkGlassBackground = Color(red: 62/255, green: 62/255, blue: 62/255) - /// Dark theme: rgb(68, 68, 68) - static let ios26DarkGlassBorder = Color(red: 68/255, green: 68/255, blue: 68/255) - /// Dark theme selected: rgb(255, 255, 255) - static let ios26DarkButtonColorSelected = Color.white - - /// Content background (light) - #f2f2f7 - static let ios26ContentBackground = Color(red: 242/255, green: 242/255, blue: 247/255) - /// Content background (dark) - static let ios26DarkContentBackground = Color(red: 0/255, green: 0/255, blue: 0/255) -} - -struct IOS26InsetListStyle: ViewModifier { - func body(content: Content) -> some View { - content - .listStyle(.insetGrouped) - .scrollContentBackground(.hidden) - } -} - -extension View { - func ios26InsetList() -> some View { - modifier(IOS26InsetListStyle()) - } -} diff --git a/swiftui/ionic-ios26-native/Views/ComponentDetailView.swift b/swiftui/ionic-ios26-native/Views/ComponentDetailView.swift deleted file mode 100644 index 2db8cd7b..00000000 --- a/swiftui/ionic-ios26-native/Views/ComponentDetailView.swift +++ /dev/null @@ -1,28 +0,0 @@ -import SwiftUI - -struct ComponentDetailView: View { - let component: ComponentItem - - var body: some View { - VStack(spacing: 16) { - Image(systemName: "square.grid.2x2") - .font(.system(size: 64)) - .foregroundStyle(.secondary) - Text(component.name) - .font(.title2) - Text("Component demo placeholder") - .font(.subheadline) - .foregroundStyle(.secondary) - } - .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(Color(.systemGroupedBackground)) - .navigationTitle(component.name) - .navigationBarTitleDisplayMode(.inline) - } -} - -#Preview { - NavigationStack { - ComponentDetailView(component: ComponentItem(name: "button", enable: true)) - } -} diff --git a/swiftui/ionic-ios26-native/Views/IndexView.swift b/swiftui/ionic-ios26-native/Views/IndexView.swift deleted file mode 100644 index 553f2a99..00000000 --- a/swiftui/ionic-ios26-native/Views/IndexView.swift +++ /dev/null @@ -1,112 +0,0 @@ -import SwiftUI - -struct ComponentItem: Identifiable, Hashable { - let id = UUID() - let name: String - var enable: Bool - - func hash(into hasher: inout Hasher) { hasher.combine(name) } - static func == (lhs: ComponentItem, rhs: ComponentItem) -> Bool { lhs.name == rhs.name } -} - -struct IndexView: View { - @State private var components: [ComponentItem] = [ - ComponentItem(name: "accordion", enable: true), - ComponentItem(name: "action-sheet", enable: true), - ComponentItem(name: "alert", enable: true), - ComponentItem(name: "breadcrumbs", enable: true), - ComponentItem(name: "button", enable: true), - ComponentItem(name: "card", enable: true), - ComponentItem(name: "checkbox", enable: true), - ComponentItem(name: "chip", enable: true), - ComponentItem(name: "date-and-time-pickers", enable: true), - ComponentItem(name: "floating-action-button", enable: true), - ComponentItem(name: "inputs", enable: true), - ComponentItem(name: "item-list", enable: true), - ComponentItem(name: "modal", enable: true), - ComponentItem(name: "popover", enable: true), - ComponentItem(name: "progress-indicators", enable: true), - ComponentItem(name: "radio", enable: true), - ComponentItem(name: "range", enable: true), - ComponentItem(name: "reorder", enable: true), - ComponentItem(name: "searchbar", enable: true), - ComponentItem(name: "segment", enable: true), - ComponentItem(name: "select", enable: true), - ComponentItem(name: "tabs", enable: true), - ComponentItem(name: "toast", enable: true), - ComponentItem(name: "toggle", enable: true), - ComponentItem(name: "toolbar", enable: true), - ] - - @AppStorage("isDarkMode") private var isDarkMode = false - @Environment(\.colorScheme) private var systemColorScheme - @Environment(\.openURL) private var openURL - - private var effectiveColorScheme: ColorScheme { - isDarkMode ? .dark : systemColorScheme - } - - private var enableComponents: [ComponentItem] { - components.filter { $0.enable } - } - - var body: some View { - NavigationStack { - ZStack { - backgroundColor - .ignoresSafeArea() - - List { - Section { - Toggle("Dark Mode", isOn: $isDarkMode) - } header: { - Text("Settings") - } - - Section { - ForEach(enableComponents) { item in - NavigationLink(value: item) { - Text(item.name) - } - } - } header: { - Text("Components") - } - } - .ios26InsetList() - .scrollContentBackground(.hidden) - } - .navigationTitle("Index") - .navigationBarTitleDisplayMode(.large) - .toolbar { - ToolbarItem(placement: .topBarTrailing) { - HStack(spacing: 12) { - Button { - openURL(URL(string: "https://github.com/rdlabo-dev/ionic-theme-ios26")!) - } label: { - Image(systemName: "chevron.left.forwardslash.chevron.right") - } - - Button { - openURL(URL(string: "https://ionicframework.com/")!) - } label: { - Image(systemName: "bolt.fill") - } - } - } - } - .navigationDestination(for: ComponentItem.self) { item in - ComponentDetailView(component: item) - } - } - .preferredColorScheme(isDarkMode ? .dark : nil) - } - - private var backgroundColor: Color { - effectiveColorScheme == .dark ? .ios26DarkContentBackground : .ios26ContentBackground - } -} - -#Preview { - IndexView() -} diff --git a/swiftui/ionic-ios26-native/ionic_ios26_nativeApp.swift b/swiftui/ionic-ios26-native/ionic_ios26_nativeApp.swift deleted file mode 100644 index df4253b2..00000000 --- a/swiftui/ionic-ios26-native/ionic_ios26_nativeApp.swift +++ /dev/null @@ -1,10 +0,0 @@ -import SwiftUI - -@main -struct ionic_ios26_nativeApp: App { - var body: some Scene { - WindowGroup { - ContentView() - } - } -} From 189dbc77158633371999dc0d3c2e333f692a7882 Mon Sep 17 00:00:00 2001 From: rdlabo Date: Thu, 10 Sep 2026 17:12:39 +0900 Subject: [PATCH 2/7] fix: use stable theme opt-out class with deprecated iOS 26 alias --- demo/src/app/docs/docs-content.generated.ts | 2 +- .../app/index/pages/button/button.page.html | 4 +-- demo/src/app/index/pages/chip/chip.page.html | 10 +++---- .../index/pages/searchbar/searchbar.page.html | 8 ++--- .../app/index/pages/segment/segment.page.html | 2 +- .../app/settings/settings-page.component.html | 2 +- docs/migration.md | 4 ++- docs/special-markup.md | 6 ++-- src/popover/animations/ios.enter.ts | 2 +- src/styles/components/ion-action-sheet.scss | 4 +-- src/styles/components/ion-alert.scss | 2 +- src/styles/components/ion-button.scss | 30 +++++++++++-------- src/styles/components/ion-card.scss | 2 +- src/styles/components/ion-content.scss | 10 ++++--- src/styles/components/ion-datetime.scss | 2 +- src/styles/components/ion-fab.scss | 2 +- src/styles/components/ion-inputs.scss | 4 +-- src/styles/components/ion-list.scss | 4 +-- src/styles/components/ion-loading.scss | 2 +- src/styles/components/ion-menu.scss | 12 ++++---- src/styles/components/ion-modal.scss | 2 +- src/styles/components/ion-picker.scss | 2 +- src/styles/components/ion-popover.scss | 2 +- src/styles/components/ion-range.scss | 2 +- src/styles/components/ion-searchbar.scss | 10 ++++--- src/styles/components/ion-segment.scss | 4 +-- src/styles/components/ion-tabs.scss | 4 +-- src/styles/components/ion-toast.scss | 2 +- src/styles/components/ion-toggle.scss | 4 +-- src/styles/components/ion-toolbar.scss | 25 ++++++++-------- src/styles/md-remove-ios-class-effect.scss | 4 +-- src/styles/utils/dark/ion-button.scss | 12 ++++---- src/styles/utils/dark/ion-fab.scss | 2 +- src/styles/utils/dark/ion-segment.scss | 4 +-- src/styles/utils/dark/ion-tabs.scss | 4 +-- src/styles/utils/translucent.scss | 26 ++++++++-------- src/transition/ios.transition.ts | 21 +++++++------ 37 files changed, 131 insertions(+), 113 deletions(-) diff --git a/demo/src/app/docs/docs-content.generated.ts b/demo/src/app/docs/docs-content.generated.ts index e0e542ba..5033ae16 100644 --- a/demo/src/app/docs/docs-content.generated.ts +++ b/demo/src/app/docs/docs-content.generated.ts @@ -1,3 +1,3 @@ // Generated from docs/special-markup.md. Do not edit directly. export const docsContentHtml = - '

Special markup and classes

\n

Most Ionic markup works without changes. The combinations below are explicit opt-ins provided by the theme.

\n

Primary submit buttons

\n

Solid primary submit buttons use --ion-color-primary-brightness for their foreground and border treatment. Define a value with sufficient contrast for your primary color.

\n
:root {\n  --ion-color-primary-brightness: #96feff;\n}
\n\n
<ion-button type="submit" color="primary">Submit</ion-button>\n<ion-button class="button-submit" fill="solid" color="primary">Continue</ion-button>
\n\n
\n
Preview
\nSubmit\nContinue\n
\n\n

Use .button-submit when the button needs the same treatment but cannot use type="submit".

\n

Two-line inset list items

\n

Place an unslotted ion-label immediately alongside an unslotted ion-note to render a two-line item. When using the iOS-style inset-list background, wrap the items in ion-item-group; keep ion-list-header outside the group.

\n
<ion-list inset="true">\n  <ion-list-header>\n    <ion-label>Connections</ion-label>\n  </ion-list-header>\n  <ion-item-group>\n    <ion-item>\n      <ion-label>Network &amp; internet</ion-label>\n      <ion-note>Mobile, Wi-Fi, hotspot</ion-note>\n    </ion-item>\n  </ion-item-group>\n</ion-list>
\n\n
\n
Preview
\n\n \n Connections\n \n \n \n Network & internet\n Mobile, Wi-Fi, hotspot\n \n \n\n
\n\n

Use slot="end" on ion-note when you want the standard trailing-note layout instead.

\n

Inset-list section headers

\n

Add .item-group-header to an ion-item-group to create the centered icon, title, and description used at the top of the component demo pages.

\n

This is an introductory group. Place regular list items in a separate ion-item-group that follows it.

\n
<ion-list inset="true">\n  <ion-item-group class="item-group-header">\n    <ion-item>\n      <ion-label>\n        <ion-icon name="list" style="background: var(--ion-color-primary)"></ion-icon>\n        <h2>Lists</h2>\n        <ion-text>Inset-list examples</ion-text>\n      </ion-label>\n    </ion-item>\n  </ion-item-group>\n  <ion-item-group>\n    <ion-item><ion-label>First item</ion-label></ion-item>\n  </ion-item-group>\n</ion-list>
\n\n
\n
Preview
\n\n \n \n \n \n

Lists

\n Inset-list examples\n
\n
\n
\n \n First item\n \n
\n
\n\n

Full-width segments

\n

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.

\n
<ion-segment class="segment-expand" value="new">\n  <ion-segment-button value="new"><ion-label>New</ion-label></ion-segment-button>\n  <ion-segment-button value="replied"><ion-label>Replied</ion-label></ion-segment-button>\n</ion-segment>
\n\n
\n
Preview
\n\n New\n Replied\n\n
\n\n

Classic search bar in a condense header

\n

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.

\n

Place it in a toolbar with a color, such as color="light"; the classic background is derived from that color's contrast value.

\n

The example uses Ionic's standard collapsible large-title structure. Scroll the preview to collapse the large title and reveal the fixed header.

\n
<div class="ion-page">\n  <ion-header translucent="true">\n    <ion-toolbar color="light">\n      <ion-title>Search</ion-title>\n    </ion-toolbar>\n  </ion-header>\n  <ion-content color="light" fullscreen="true">\n    <ion-header collapse="condense">\n      <ion-toolbar color="light">\n        <ion-title size="large">Search</ion-title>\n      </ion-toolbar>\n      <ion-toolbar color="light">\n        <ion-searchbar class="searchbar-classic" placeholder="Filter results"></ion-searchbar>\n      </ion-toolbar>\n    </ion-header>\n    <ion-list inset="true">\n      <ion-item-group>\n        <ion-item><ion-label>Recent item 1</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 2</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 3</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 4</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 5</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 6</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 7</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 8</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 9</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 10</ion-label></ion-item>\n      </ion-item-group>\n    </ion-list>\n  </ion-content>\n</div>
\n\n
\n
Preview
\n
\n \n \n Search\n \n \n \n \n \n Search\n \n \n \n \n \n \n \n Recent item 1\n Recent item 2\n Recent item 3\n Recent item 4\n Recent item 5\n Recent item 6\n Recent item 7\n Recent item 8\n Recent item 9\n Recent item 10\n \n \n \n
\n
\n\n

The .ion-page wrapper makes this embedded preview behave like a complete routed page. An application using ion-router-outlet normally receives that page container automatically. The inset list and its items only provide enough content to demonstrate scrolling; they are not required by .searchbar-classic.

\n

Search-bar toolbars

\n

Add .toolbar-searchbar when an ion-toolbar combines a search bar with start or end buttons. The class centers the slotted controls and adjusts the spacing around the search field.

\n
<ion-toolbar class="toolbar-searchbar">\n  <ion-buttons slot="start">\n    <ion-button>Cancel</ion-button>\n  </ion-buttons>\n  <ion-searchbar></ion-searchbar>\n</ion-toolbar>
\n\n
\n
Preview
\n\n \n Cancel\n \n \n\n
\n\n

Opting out

\n

Add .ios27-disabled to an individual Ionic component when it must retain Ionic's standard iOS styling.

\n
<ion-button>iOS 27 theme</ion-button> <ion-button class="ios27-disabled">Standard Ionic button</ion-button>
\n\n
\n
Preview
\niOS 27 theme Standard Ionic button\n
\n\n

For the background model behind inset lists, see Using ion-item-group.

\n'; + '

Special markup and classes

\n

Most Ionic markup works without changes. The combinations below are explicit opt-ins provided by the theme.

\n

Primary submit buttons

\n

Solid primary submit buttons use --ion-color-primary-brightness for their foreground and border treatment. Define a value with sufficient contrast for your primary color.

\n
:root {\n  --ion-color-primary-brightness: #96feff;\n}
\n\n
<ion-button type="submit" color="primary">Submit</ion-button>\n<ion-button class="button-submit" fill="solid" color="primary">Continue</ion-button>
\n\n
\n
Preview
\nSubmit\nContinue\n
\n\n

Use .button-submit when the button needs the same treatment but cannot use type="submit".

\n

Two-line inset list items

\n

Place an unslotted ion-label immediately alongside an unslotted ion-note to render a two-line item. When using the iOS-style inset-list background, wrap the items in ion-item-group; keep ion-list-header outside the group.

\n
<ion-list inset="true">\n  <ion-list-header>\n    <ion-label>Connections</ion-label>\n  </ion-list-header>\n  <ion-item-group>\n    <ion-item>\n      <ion-label>Network &amp; internet</ion-label>\n      <ion-note>Mobile, Wi-Fi, hotspot</ion-note>\n    </ion-item>\n  </ion-item-group>\n</ion-list>
\n\n
\n
Preview
\n\n \n Connections\n \n \n \n Network & internet\n Mobile, Wi-Fi, hotspot\n \n \n\n
\n\n

Use slot="end" on ion-note when you want the standard trailing-note layout instead.

\n

Inset-list section headers

\n

Add .item-group-header to an ion-item-group to create the centered icon, title, and description used at the top of the component demo pages.

\n

This is an introductory group. Place regular list items in a separate ion-item-group that follows it.

\n
<ion-list inset="true">\n  <ion-item-group class="item-group-header">\n    <ion-item>\n      <ion-label>\n        <ion-icon name="list" style="background: var(--ion-color-primary)"></ion-icon>\n        <h2>Lists</h2>\n        <ion-text>Inset-list examples</ion-text>\n      </ion-label>\n    </ion-item>\n  </ion-item-group>\n  <ion-item-group>\n    <ion-item><ion-label>First item</ion-label></ion-item>\n  </ion-item-group>\n</ion-list>
\n\n
\n
Preview
\n\n \n \n \n \n

Lists

\n Inset-list examples\n
\n
\n
\n \n First item\n \n
\n
\n\n

Full-width segments

\n

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.

\n
<ion-segment class="segment-expand" value="new">\n  <ion-segment-button value="new"><ion-label>New</ion-label></ion-segment-button>\n  <ion-segment-button value="replied"><ion-label>Replied</ion-label></ion-segment-button>\n</ion-segment>
\n\n
\n
Preview
\n\n New\n Replied\n\n
\n\n

Classic search bar in a condense header

\n

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.

\n

Place it in a toolbar with a color, such as color="light"; the classic background is derived from that color's contrast value.

\n

The example uses Ionic's standard collapsible large-title structure. Scroll the preview to collapse the large title and reveal the fixed header.

\n
<div class="ion-page">\n  <ion-header translucent="true">\n    <ion-toolbar color="light">\n      <ion-title>Search</ion-title>\n    </ion-toolbar>\n  </ion-header>\n  <ion-content color="light" fullscreen="true">\n    <ion-header collapse="condense">\n      <ion-toolbar color="light">\n        <ion-title size="large">Search</ion-title>\n      </ion-toolbar>\n      <ion-toolbar color="light">\n        <ion-searchbar class="searchbar-classic" placeholder="Filter results"></ion-searchbar>\n      </ion-toolbar>\n    </ion-header>\n    <ion-list inset="true">\n      <ion-item-group>\n        <ion-item><ion-label>Recent item 1</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 2</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 3</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 4</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 5</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 6</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 7</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 8</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 9</ion-label></ion-item>\n        <ion-item><ion-label>Recent item 10</ion-label></ion-item>\n      </ion-item-group>\n    </ion-list>\n  </ion-content>\n</div>
\n\n
\n
Preview
\n
\n \n \n Search\n \n \n \n \n \n Search\n \n \n \n \n \n \n \n Recent item 1\n Recent item 2\n Recent item 3\n Recent item 4\n Recent item 5\n Recent item 6\n Recent item 7\n Recent item 8\n Recent item 9\n Recent item 10\n \n \n \n
\n
\n\n

The .ion-page wrapper makes this embedded preview behave like a complete routed page. An application using ion-router-outlet normally receives that page container automatically. The inset list and its items only provide enough content to demonstrate scrolling; they are not required by .searchbar-classic.

\n

Search-bar toolbars

\n

Add .toolbar-searchbar when an ion-toolbar combines a search bar with start or end buttons. The class centers the slotted controls and adjusts the spacing around the search field.

\n
<ion-toolbar class="toolbar-searchbar">\n  <ion-buttons slot="start">\n    <ion-button>Cancel</ion-button>\n  </ion-buttons>\n  <ion-searchbar></ion-searchbar>\n</ion-toolbar>
\n\n
\n
Preview
\n\n \n Cancel\n \n \n\n
\n\n

Opting out

\n

Add .ios-theme-disabled to an individual Ionic component when it must retain Ionic's standard iOS styling.

\n

.ios26-disabled is deprecated but remains supported as an alias with the same behavior. Use .ios-theme-disabled for new code.

\n
<ion-button>iOS 27 theme</ion-button> <ion-button class="ios-theme-disabled">Standard Ionic button</ion-button>
\n\n
\n
Preview
\niOS 27 theme Standard Ionic button\n
\n\n

For the background model behind inset lists, see Using ion-item-group.

\n'; diff --git a/demo/src/app/index/pages/button/button.page.html b/demo/src/app/index/pages/button/button.page.html index 5c9865bd..4f0b0d9a 100644 --- a/demo/src/app/index/pages/button/button.page.html +++ b/demo/src/app/index/pages/button/button.page.html @@ -12,7 +12,7 @@ Example - + Example Example Example @@ -144,7 +144,7 @@

button

buttons > button[fill=default][size=large] Buttons Shadow - Default Theme + Default Theme diff --git a/demo/src/app/index/pages/chip/chip.page.html b/demo/src/app/index/pages/chip/chip.page.html index 987055d0..9640b69e 100644 --- a/demo/src/app/index/pages/chip/chip.page.html +++ b/demo/src/app/index/pages/chip/chip.page.html @@ -24,17 +24,17 @@

chip

- Default - Disabled - Outline - + Default + Disabled + Outline + Silhouette of a person's head Avatar Chip - + Icon Chip diff --git a/demo/src/app/index/pages/searchbar/searchbar.page.html b/demo/src/app/index/pages/searchbar/searchbar.page.html index fc92e07b..1b0c1859 100644 --- a/demo/src/app/index/pages/searchbar/searchbar.page.html +++ b/demo/src/app/index/pages/searchbar/searchbar.page.html @@ -25,10 +25,10 @@

searchbar

- - - - Search + + + + Search diff --git a/demo/src/app/index/pages/segment/segment.page.html b/demo/src/app/index/pages/segment/segment.page.html index c8413c17..b8683793 100644 --- a/demo/src/app/index/pages/segment/segment.page.html +++ b/demo/src/app/index/pages/segment/segment.page.html @@ -57,7 +57,7 @@

segment

Segment - +
diff --git a/demo/src/app/settings/settings-page.component.html b/demo/src/app/settings/settings-page.component.html index 62567054..44a3a8e9 100644 --- a/demo/src/app/settings/settings-page.component.html +++ b/demo/src/app/settings/settings-page.component.html @@ -4,7 +4,7 @@ Settings - + diff --git a/docs/migration.md b/docs/migration.md index 3f9cf981..a2855d7c 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -8,7 +8,9 @@ title: Migration 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. -The theme now uses the `ios27-` prefix consistently. Update custom CSS variables, selectors, and markup to match, including `ios27-disabled` and `--ios27-*` variables. Legacy names are no longer recognized. +Update theme CSS variables and selectors to the `ios27-` prefix, including `--ios27-*` variables. Old variable names are no longer recognized. + +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. See [Special markup and classes](./special-markup.md) and [Default variables](../src/styles/default-variables.scss) for the current names. diff --git a/docs/special-markup.md b/docs/special-markup.md index 08a33231..49a1c63d 100644 --- a/docs/special-markup.md +++ b/docs/special-markup.md @@ -136,10 +136,12 @@ Add `.toolbar-searchbar` when an `ion-toolbar` combines a search bar with start ## Opting out -Add `.ios27-disabled` to an individual Ionic component when it must retain Ionic's standard iOS styling. +Add `.ios-theme-disabled` to an individual Ionic component when it must retain Ionic's standard iOS styling. + +`.ios26-disabled` is deprecated but remains supported as an alias with the same behavior. Use `.ios-theme-disabled` for new code. ```html preview -iOS 27 theme Standard Ionic button +iOS 27 theme Standard Ionic button ``` For the background model behind inset lists, see [Using `ion-item-group`](./using-ion-item-group.md). diff --git a/src/popover/animations/ios.enter.ts b/src/popover/animations/ios.enter.ts index 0d7e63cb..709e76e0 100644 --- a/src/popover/animations/ios.enter.ts +++ b/src/popover/animations/ios.enter.ts @@ -27,7 +27,7 @@ export const iosEnterAnimation = (baseEl: HTMLElement, opts?: any): Animation => if (!['ion-button', 'ion-buttons'].includes(referenceSizeEl.localName)) { return false; } - if (referenceSizeEl.classList.contains('ios27-disabled')) { + if (referenceSizeEl.matches('.ios-theme-disabled, .ios26-disabled')) { return false; } return true; diff --git a/src/styles/components/ion-action-sheet.scss b/src/styles/components/ion-action-sheet.scss index 459da124..0300a8b7 100644 --- a/src/styles/components/ion-action-sheet.scss +++ b/src/styles/components/ion-action-sheet.scss @@ -1,6 +1,6 @@ @use '../utils/api'; -ion-action-sheet.ios:not(.ios27-disabled) { +ion-action-sheet.ios:not(.ios-theme-disabled, .ios26-disabled) { --backdrop-opacity: 0.2; --color: var(--ion-color-step-600, var(--ion-text-color-step-400, #666666)); @@ -74,7 +74,7 @@ ion-action-sheet.ios:not(.ios27-disabled) { * ios27, action-sheet should not has 'cancel'. * It is recommend to use Popover. */ -ion-action-sheet.ios.select-action-sheet:not(.ios27-disabled) { +ion-action-sheet.ios.select-action-sheet:not(.ios-theme-disabled, .ios26-disabled) { .action-sheet-container { .action-sheet-group { button.action-sheet-cancel { diff --git a/src/styles/components/ion-alert.scss b/src/styles/components/ion-alert.scss index aa548721..1fc4cddc 100644 --- a/src/styles/components/ion-alert.scss +++ b/src/styles/components/ion-alert.scss @@ -1,6 +1,6 @@ @use '../utils/api'; -ion-alert.ios:not(.ios27-disabled) { +ion-alert.ios:not(.ios-theme-disabled, .ios26-disabled) { --min-width: 280px; --backdrop-opacity: 0.2; diff --git a/src/styles/components/ion-button.scss b/src/styles/components/ion-button.scss index bec6dd1b..cd71dc37 100644 --- a/src/styles/components/ion-button.scss +++ b/src/styles/components/ion-button.scss @@ -59,11 +59,11 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only; } } - &:has(ion-button:not(.ios27-disabled).button-clear.button-large) { + &:has(ion-button:not(.ios-theme-disabled, .ios26-disabled).button-clear.button-large) { border-radius: 30px; } - ion-button:not(.ios27-disabled).button-clear { + ion-button:not(.ios-theme-disabled, .ios26-disabled).button-clear { --background: transparent; --border-style: none; --border-width: 0; @@ -121,11 +121,11 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only; } } - ion-button:not(.ios27-disabled) { + ion-button:not(.ios-theme-disabled, .ios26-disabled) { margin: 0; } - ion-menu-button:not(.ios27-disabled) { + ion-menu-button:not(.ios-theme-disabled, .ios26-disabled) { width: 44px; height: 44px; padding: 2px; @@ -153,13 +153,13 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only; } // will-change is optimized to only apply when needed for performance - &:not(.ios27-disabled):hover, - &:not(.ios27-disabled):active, - &:not(.ios27-disabled).ion-activated { + &:not(.ios-theme-disabled, .ios26-disabled):hover, + &:not(.ios-theme-disabled, .ios26-disabled):active, + &:not(.ios-theme-disabled, .ios26-disabled).ion-activated { will-change: transform; } - &:not(.ios27-disabled):not(:hover):not(:active):not(.ion-activated) { + &:not(.ios-theme-disabled, .ios26-disabled):not(:hover):not(:active):not(.ion-activated) { will-change: auto; } @@ -409,18 +409,22 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only; } } -ion-buttons.ios:not(.ios27-disabled):not(:has(ion-back-button, ion-button:not(.button-clear), ion-menu-button.menu-button-hidden)) { +ion-buttons.ios:not(.ios-theme-disabled, .ios26-disabled):not( + :has(ion-back-button, ion-button:not(.button-clear), ion-menu-button.menu-button-hidden) + ) { @include theme-buttons; } // Ionic's collapsing-header transition has a more specific contextual selector. .header-collapse-main :where(ion-toolbar.in-toolbar) - ion-buttons.ios:not(.ios27-disabled):not(:has(ion-back-button, ion-button:not(.button-clear), ion-menu-button.menu-button-hidden)) { + ion-buttons.ios:not(.ios-theme-disabled, .ios26-disabled):not( + :has(ion-back-button, ion-button:not(.button-clear), ion-menu-button.menu-button-hidden) + ) { transition: transform var(--ios27-activated-transition-duration) ease-out; } -ion-buttons.ios:not(.ios27-disabled):not(:has(ion-back-button, ion-button.button-clear)) { +ion-buttons.ios:not(.ios-theme-disabled, .ios26-disabled):not(:has(ion-back-button, ion-button.button-clear)) { ion-button { margin: 0 6px; &:first-child { @@ -435,9 +439,9 @@ ion-buttons.ios:not(.ios27-disabled):not(:has(ion-back-button, ion-button.button } } -ion-button.ios:not(.ios27-disabled) { +ion-button.ios:not(.ios-theme-disabled, .ios26-disabled) { @include theme-button; } -ion-back-button.ios:not(.ios27-disabled) { +ion-back-button.ios:not(.ios-theme-disabled, .ios26-disabled) { @include theme-button($is-back-button: true); } diff --git a/src/styles/components/ion-card.scss b/src/styles/components/ion-card.scss index f314e43c..ee549c5c 100644 --- a/src/styles/components/ion-card.scss +++ b/src/styles/components/ion-card.scss @@ -1,4 +1,4 @@ -ion-card.ios:not(.ios27-disabled) { +ion-card.ios:not(.ios-theme-disabled, .ios26-disabled) { border-radius: 24px; ion-list ion-item { diff --git a/src/styles/components/ion-content.scss b/src/styles/components/ion-content.scss index 1795260b..515b4980 100644 --- a/src/styles/components/ion-content.scss +++ b/src/styles/components/ion-content.scss @@ -3,8 +3,8 @@ * so we adjust the margin and padding of the content. * Also supports virtual scrolling using .ion-content-scroll-host. */ -.ion-page.ios:not(.ios27-disabled):has(ion-header.header-translucent) - ion-content.ios:not(.ios27-disabled).content-fullscreen:has(.ion-content-scroll-host) { +.ion-page.ios:not(.ios-theme-disabled, .ios26-disabled):has(ion-header.header-translucent) + ion-content.ios:not(.ios-theme-disabled, .ios26-disabled).content-fullscreen:has(.ion-content-scroll-host) { --padding-top: calc(var(--offset-top) * -1); > *:not(.ion-content-scroll-host, ion-fab) { transform: translateY(var(--offset-top)); @@ -13,10 +13,12 @@ padding-top: var(--offset-top); } } -.ion-page.ios:not(.ios27-disabled):not(:has(ion-footer)) ion-content.ios:not(.ios27-disabled).content-fullscreen .ion-content-scroll-host { +.ion-page.ios:not(.ios-theme-disabled, .ios26-disabled):not(:has(ion-footer)) + ion-content.ios:not(.ios-theme-disabled, .ios26-disabled).content-fullscreen + .ion-content-scroll-host { margin-bottom: calc(calc(60px + var(--ios27-floating-safe-area-bottom)) * -1); padding-bottom: calc(60px + var(--ios27-floating-safe-area-bottom)); } -ion-content.ios:not(.ios27-disabled).content-fullscreen:not(:has(.ion-content-scroll-host)) { +ion-content.ios:not(.ios-theme-disabled, .ios26-disabled).content-fullscreen:not(:has(.ion-content-scroll-host)) { --padding-bottom: calc(60px + var(--ios27-floating-safe-area-bottom)); } diff --git a/src/styles/components/ion-datetime.scss b/src/styles/components/ion-datetime.scss index f4c6a17a..2ede64da 100644 --- a/src/styles/components/ion-datetime.scss +++ b/src/styles/components/ion-datetime.scss @@ -1,6 +1,6 @@ @use '../utils/api'; -ion-datetime.ios:not(.ios27-disabled) { +ion-datetime.ios:not(.ios-theme-disabled, .ios26-disabled) { @include api.glass-background-overlay; border-radius: 24px; diff --git a/src/styles/components/ion-fab.scss b/src/styles/components/ion-fab.scss index 6cd7fce7..c54c14da 100644 --- a/src/styles/components/ion-fab.scss +++ b/src/styles/components/ion-fab.scss @@ -4,7 +4,7 @@ $scaleup-small-icon-only: api.$button-scaleup-small-icon-only; $scaleup-default-icon-only: api.$button-scaleup-default-icon-only; $scaleup-large-icon-only: api.$button-scaleup-large-icon-only; -ion-fab.ios:not(.ios27-disabled) { +ion-fab.ios:not(.ios-theme-disabled, .ios26-disabled) { --transform-value: 2.5px; &:has(> ion-fab-button.fab-button-small) { --transform-value: 4px; diff --git a/src/styles/components/ion-inputs.scss b/src/styles/components/ion-inputs.scss index 36f055c3..a01b75db 100644 --- a/src/styles/components/ion-inputs.scss +++ b/src/styles/components/ion-inputs.scss @@ -54,7 +54,7 @@ } } -ion-input.ios:not(.ios27-disabled) { +ion-input.ios:not(.ios-theme-disabled, .ios26-disabled) { &.input-fill-outline { @include outline-field('input'); @@ -65,7 +65,7 @@ ion-input.ios:not(.ios27-disabled) { } } -ion-textarea.ios:not(.ios27-disabled) { +ion-textarea.ios:not(.ios-theme-disabled, .ios26-disabled) { &.textarea-fill-outline { @include outline-field('textarea'); diff --git a/src/styles/components/ion-list.scss b/src/styles/components/ion-list.scss index 6785f29c..2b457e81 100644 --- a/src/styles/components/ion-list.scss +++ b/src/styles/components/ion-list.scss @@ -1,6 +1,6 @@ @use '../utils/structured-list'; -ion-list.ios:not(.ios27-disabled) { +ion-list.ios:not(.ios-theme-disabled, .ios26-disabled) { @include structured-list.support-text; ion-item { --background-hover-opacity: 0; @@ -8,7 +8,7 @@ ion-list.ios:not(.ios27-disabled) { } } -ion-list.list-inset.ios:not(.ios27-disabled) { +ion-list.list-inset.ios:not(.ios-theme-disabled, .ios26-disabled) { @include structured-list.layout(20px, 24px); ion-radio-group, diff --git a/src/styles/components/ion-loading.scss b/src/styles/components/ion-loading.scss index 1ad96bc0..f0adbccd 100644 --- a/src/styles/components/ion-loading.scss +++ b/src/styles/components/ion-loading.scss @@ -1,6 +1,6 @@ @use '../utils/api'; -ion-loading.ios:not(.ios27-disabled) { +ion-loading.ios:not(.ios-theme-disabled, .ios26-disabled) { --backdrop-opacity: 0.2; .loading-wrapper { @include api.glass-background; diff --git a/src/styles/components/ion-menu.scss b/src/styles/components/ion-menu.scss index 3da25186..05faa392 100644 --- a/src/styles/components/ion-menu.scss +++ b/src/styles/components/ion-menu.scss @@ -1,12 +1,12 @@ @use '../utils/api'; -ion-split-pane.ios:not(.ios27-disabled) { +ion-split-pane.ios:not(.ios-theme-disabled, .ios26-disabled) { --side-max-width: var(--ios27-menu-width); } -ion-split-pane.ios:not(.ios27-disabled).split-pane-visible:has(ion-menu.menu-pane-visible) { +ion-split-pane.ios:not(.ios-theme-disabled, .ios26-disabled).split-pane-visible:has(ion-menu.menu-pane-visible) { .split-pane-main { - ion-tab-bar.ios:not(.ios27-disabled) { + ion-tab-bar.ios:not(.ios-theme-disabled, .ios26-disabled) { width: calc( 100% - calc(18px + var(--ion-safe-area-left, 0px)) - calc(18px + var(--ion-safe-area-left, 0px)) - 60px - 12px - var(--ios27-menu-width) @@ -42,7 +42,7 @@ ion-split-pane.ios:not(.ios27-disabled).split-pane-visible:has(ion-menu.menu-pan ion-footer ion-toolbar { --padding-start: var(--ios27-menu-width); } - ion-tab-bar.ios:not(.ios27-disabled) { + ion-tab-bar.ios:not(.ios-theme-disabled, .ios26-disabled) { &[slot='bottom'] { left: calc(16px + var(--ion-safe-area-left, 0px) + var(--ios27-menu-width)); } @@ -50,7 +50,7 @@ ion-split-pane.ios:not(.ios27-disabled).split-pane-visible:has(ion-menu.menu-pan } } - &:has(ion-menu.ios:not(.ios27-disabled).menu-side-end) { + &:has(ion-menu.ios:not(.ios-theme-disabled, .ios26-disabled).menu-side-end) { .split-pane-main { ion-header ion-toolbar { /* @@ -77,7 +77,7 @@ ion-split-pane.ios:not(.ios27-disabled).split-pane-visible:has(ion-menu.menu-pan } } -ion-menu.ios:not(.ios27-disabled) { +ion-menu.ios:not(.ios-theme-disabled, .ios26-disabled) { --border: none; --background: transparent; --max-width: var(--ios27-menu-width); diff --git a/src/styles/components/ion-modal.scss b/src/styles/components/ion-modal.scss index 3b03f478..d176ad0d 100644 --- a/src/styles/components/ion-modal.scss +++ b/src/styles/components/ion-modal.scss @@ -1,6 +1,6 @@ @use '../utils/api'; -ion-modal.ios:not(.ios27-disabled) { +ion-modal.ios:not(.ios-theme-disabled, .ios26-disabled) { --backdrop-opacity: 0.2; &::part(handle) { diff --git a/src/styles/components/ion-picker.scss b/src/styles/components/ion-picker.scss index c4cbbe2e..60b5f614 100644 --- a/src/styles/components/ion-picker.scss +++ b/src/styles/components/ion-picker.scss @@ -1,4 +1,4 @@ @use '../utils/api'; -ion-picker.ios:not(.ios27-disabled) { +ion-picker.ios:not(.ios-theme-disabled, .ios26-disabled) { } diff --git a/src/styles/components/ion-popover.scss b/src/styles/components/ion-popover.scss index 79a38fdb..e0ea6871 100644 --- a/src/styles/components/ion-popover.scss +++ b/src/styles/components/ion-popover.scss @@ -1,6 +1,6 @@ @use '../utils/api'; -ion-popover.ios:not(.ios27-disabled) { +ion-popover.ios:not(.ios-theme-disabled, .ios26-disabled) { --backdrop-opacity: 0.2; --background: rgba(var(--ios27-glass-background-rgb), 0.72); --box-shadow: diff --git a/src/styles/components/ion-range.scss b/src/styles/components/ion-range.scss index c5456bf9..da866335 100644 --- a/src/styles/components/ion-range.scss +++ b/src/styles/components/ion-range.scss @@ -5,7 +5,7 @@ -webkit-transform: scale(1.56, 1.47) translateX(calc(#{$translate-x} * -0.1)) translateZ(0); } -ion-range.ios:not(.ios27-disabled) { +ion-range.ios:not(.ios-theme-disabled, .ios26-disabled) { --knob-size: 20px; --knob-width: 38px; --knob-border-radius: 24px; diff --git a/src/styles/components/ion-searchbar.scss b/src/styles/components/ion-searchbar.scss index bf6bb1b6..4f0c0f0f 100644 --- a/src/styles/components/ion-searchbar.scss +++ b/src/styles/components/ion-searchbar.scss @@ -1,7 +1,7 @@ @use '../utils/api'; ion-modal.ios { - ion-searchbar:not(.ios27-disabled) { + ion-searchbar:not(.ios-theme-disabled, .ios26-disabled) { .searchbar-input-container { input.searchbar-input { // Modal表示でのアイコン非表示の不具合の対応 @@ -11,7 +11,7 @@ ion-modal.ios { } } -ion-searchbar.ios:not(.ios27-disabled):not(.searchbar-classic) { +ion-searchbar.ios:not(.ios-theme-disabled, .ios26-disabled):not(.searchbar-classic) { min-height: 60px; padding: 0; @@ -45,10 +45,12 @@ ion-searchbar.ios:not(.ios27-disabled):not(.searchbar-classic) { /** * add searchbar-classic */ -ion-toolbar.ios:not(.ios27-disabled):has(ion-searchbar.searchbar-classic.ios:not(.ios27-disabled)) { +ion-toolbar.ios:not(.ios-theme-disabled, .ios26-disabled):has( + ion-searchbar.searchbar-classic.ios:not(.ios-theme-disabled, .ios26-disabled) + ) { --min-height: auto; } -ion-searchbar.ios:not(.ios27-disabled).searchbar-classic { +ion-searchbar.ios:not(.ios-theme-disabled, .ios26-disabled).searchbar-classic { padding-bottom: 12px; min-height: auto; .searchbar-input-container input.searchbar-input { diff --git a/src/styles/components/ion-segment.scss b/src/styles/components/ion-segment.scss index 8fa44928..5d838d7c 100644 --- a/src/styles/components/ion-segment.scss +++ b/src/styles/components/ion-segment.scss @@ -1,6 +1,6 @@ @use '../utils/api'; -ion-segment.ios:not(.ios27-disabled) { +ion-segment.ios:not(.ios-theme-disabled, .ios26-disabled) { @include api.glass-background; min-height: 48px; border-radius: 25px; @@ -114,7 +114,7 @@ ion-segment.ios:not(.ios27-disabled) { } } -ion-segment-button.ios:not(.ios27-disabled) { +ion-segment-button.ios:not(.ios-theme-disabled, .ios26-disabled) { --border-width: 0; --indicator-box-shadow: none; --indicator-color: rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.06); diff --git a/src/styles/components/ion-tabs.scss b/src/styles/components/ion-tabs.scss index 80f67818..ab5ed209 100644 --- a/src/styles/components/ion-tabs.scss +++ b/src/styles/components/ion-tabs.scss @@ -1,6 +1,6 @@ @use '../utils/api'; -ion-tab-bar.ios:not(.ios27-disabled) { +ion-tab-bar.ios:not(.ios-theme-disabled, .ios26-disabled) { @include api.glass-background; z-index: 2; @@ -66,7 +66,7 @@ ion-tab-bar.ios:not(.ios27-disabled) { } } -ion-tab-button.ios:not(.ios27-disabled) { +ion-tab-button.ios:not(.ios-theme-disabled, .ios26-disabled) { ion-icon { font-size: 26px; } diff --git a/src/styles/components/ion-toast.scss b/src/styles/components/ion-toast.scss index 0e562db7..bdbdeecd 100644 --- a/src/styles/components/ion-toast.scss +++ b/src/styles/components/ion-toast.scss @@ -1,6 +1,6 @@ @use '../utils/api'; -ion-toast.ios:not(.ios27-disabled) { +ion-toast.ios:not(.ios-theme-disabled, .ios26-disabled) { --background: rgba(var(--ios27-glass-background-rgb), 0.72); --border-radius: 24px; --border-style: solid; diff --git a/src/styles/components/ion-toggle.scss b/src/styles/components/ion-toggle.scss index ced4b8e3..a0007b6c 100644 --- a/src/styles/components/ion-toggle.scss +++ b/src/styles/components/ion-toggle.scss @@ -4,7 +4,7 @@ * Adjustments have been made to prevent the right edge from being cut off within the ion-item. * When the native-inner part be added to the ion-item, it will be removed. */ -ion-item.ios:not(.ios27-disabled) ion-toggle.ios:not(.ios27-disabled) { +ion-item.ios:not(.ios-theme-disabled, .ios26-disabled) ion-toggle.ios:not(.ios-theme-disabled, .ios26-disabled) { &.toggle-checked.toggle-activated::part(track) { transform-origin: left; transform: scaleX(0.894) translateZ(0); @@ -16,7 +16,7 @@ ion-item.ios:not(.ios27-disabled) ion-toggle.ios:not(.ios27-disabled) { } } -ion-toggle.ios:not(.ios27-disabled) { +ion-toggle.ios:not(.ios-theme-disabled, .ios26-disabled) { --handle-width: 38px; --handle-height: 24px; --handle-max-width: none; diff --git a/src/styles/components/ion-toolbar.scss b/src/styles/components/ion-toolbar.scss index 6a299071..d2878602 100644 --- a/src/styles/components/ion-toolbar.scss +++ b/src/styles/components/ion-toolbar.scss @@ -6,34 +6,35 @@ * padding-top: var(--ion-safe-area-top, 0); * } */ -ion-header.ios:not(.ios27-disabled) ion-toolbar:not(.ios27-disabled):first-of-type { +ion-header.ios:not(.ios-theme-disabled, .ios26-disabled) ion-toolbar:not(.ios-theme-disabled, .ios26-disabled):first-of-type { padding-top: max(calc(var(--ion-safe-area-top) - 12px), 4px); } -ion-modal.ios:not(.ios27-disabled).modal-card, -ion-modal.ios:not(.ios27-disabled).modal-sheet { - ion-header.ios:not(.ios27-disabled) ion-toolbar.ios:not(.ios27-disabled):first-of-type { +ion-modal.ios:not(.ios-theme-disabled, .ios26-disabled).modal-card, +ion-modal.ios:not(.ios-theme-disabled, .ios26-disabled).modal-sheet { + ion-header.ios:not(.ios-theme-disabled, .ios26-disabled) ion-toolbar.ios:not(.ios-theme-disabled, .ios26-disabled):first-of-type { padding-top: 6px; } } -ion-header.ios.header-collapse-condense:not(.ios27-disabled) ion-toolbar:not(.ios27-disabled):first-of-type { +ion-header.ios.header-collapse-condense:not(.ios-theme-disabled, .ios26-disabled) + ion-toolbar:not(.ios-theme-disabled, .ios26-disabled):first-of-type { padding-top: 0; } -ion-toolbar.ios:not(.toolbar-title-large):not(.ios27-disabled):not(:has(ion-segment.segment-expand)) { +ion-toolbar.ios:not(.toolbar-title-large):not(.ios-theme-disabled, .ios26-disabled):not(:has(ion-segment.segment-expand)) { --min-height: 68px; } -ion-header.ios:not(.ios27-disabled):not(.header-collapse-condense):not(:where(ion-modal *)) - > ion-toolbar.ios:not(.ios27-disabled):not(.toolbar-title-large):not(.toolbar-searchbar):not( +ion-header.ios:not(.ios-theme-disabled, .ios26-disabled):not(.header-collapse-condense):not(:where(ion-modal *)) + > ion-toolbar.ios:not(.ios-theme-disabled, .ios26-disabled):not(.toolbar-title-large):not(.toolbar-searchbar):not( :has(ion-segment.segment-expand) ):first-of-type { padding-top: max(calc(var(--ion-safe-area-top) - 10px), 6px); --min-height: 64px; } -ion-toolbar.ios:not(.ios27-disabled).toolbar-searchbar { +ion-toolbar.ios:not(.ios-theme-disabled, .ios26-disabled).toolbar-searchbar { *[slot='start'], *[slot='end'] { align-self: center; @@ -42,7 +43,7 @@ ion-toolbar.ios:not(.ios27-disabled).toolbar-searchbar { ion-buttons[slot='start'] { margin-right: 6px; } - ion-searchbar.ios:not(.ios27-disabled) { + ion-searchbar.ios:not(.ios-theme-disabled, .ios26-disabled) { .searchbar-input-container { margin: 0 12px 0 6px; } @@ -52,7 +53,7 @@ ion-toolbar.ios:not(.ios27-disabled).toolbar-searchbar { ion-buttons[slot='end'] { margin-left: 6px; } - ion-searchbar.ios:not(.ios27-disabled) { + ion-searchbar.ios:not(.ios-theme-disabled, .ios26-disabled) { .searchbar-input-container { margin: 0 6px 0 12px; } @@ -60,7 +61,7 @@ ion-toolbar.ios:not(.ios27-disabled).toolbar-searchbar { } } -ion-toolbar.ios:not(.ios27-disabled) { +ion-toolbar.ios:not(.ios-theme-disabled, .ios26-disabled) { ion-buttons { margin-left: 12px; margin-right: 12px; diff --git a/src/styles/md-remove-ios-class-effect.scss b/src/styles/md-remove-ios-class-effect.scss index e36c9402..adb5f84c 100644 --- a/src/styles/md-remove-ios-class-effect.scss +++ b/src/styles/md-remove-ios-class-effect.scss @@ -1,9 +1,9 @@ ion-buttons.md { /** - * ion-buttons.ios27-disabled > ion-button.button-default is for ios27 structure. + * ion-buttons.ios-theme-disabled > ion-button.button-default is for ios27 structure. * for .md, remove button-default styles. Will be button-clear. */ - ion-button.md:not(.ios27-disabled).button-default { + ion-button.md:not(.ios-theme-disabled, .ios26-disabled).button-default { // copy .button-clear --color: initial; --background: transparent; diff --git a/src/styles/utils/dark/ion-button.scss b/src/styles/utils/dark/ion-button.scss index c4dbde57..f4e8d582 100644 --- a/src/styles/utils/dark/ion-button.scss +++ b/src/styles/utils/dark/ion-button.scss @@ -5,7 +5,7 @@ @include api.glass-background-button-activated-dark; } - ion-button:not(.ios27-disabled).button-clear { + ion-button:not(.ios-theme-disabled, .ios26-disabled).button-clear { &.ion-activated { color: rgb(var(--ion-text-color-rgb, 0, 0, 0)); &.ion-color { @@ -14,8 +14,8 @@ } } - ion-button:not(.ios27-disabled), - ion-back-button:not(.ios27-disabled) { + ion-button:not(.ios-theme-disabled, .ios26-disabled), + ion-back-button:not(.ios-theme-disabled, .ios26-disabled) { &.ion-activated { --color: rgba(var(--ion-text-color-rgb, 0, 0, 0), 1); @@ -46,13 +46,13 @@ } @mixin ion-button { - ion-buttons.ios:not(.ios27-disabled):not(:has(ion-back-button, ion-button:not(.button-clear))) { + ion-buttons.ios:not(.ios-theme-disabled, .ios26-disabled):not(:has(ion-back-button, ion-button:not(.button-clear))) { @include theme-dark-buttons; } - ion-button.ios:not(.ios27-disabled) { + ion-button.ios:not(.ios-theme-disabled, .ios26-disabled) { @include theme-dark-button; } - ion-back-button.ios:not(.ios27-disabled) { + ion-back-button.ios:not(.ios-theme-disabled, .ios26-disabled) { @include theme-dark-button($is-back-button: true); } } diff --git a/src/styles/utils/dark/ion-fab.scss b/src/styles/utils/dark/ion-fab.scss index a3defa29..ece43c82 100644 --- a/src/styles/utils/dark/ion-fab.scss +++ b/src/styles/utils/dark/ion-fab.scss @@ -1,7 +1,7 @@ @use '../api'; @mixin ion-fab { - ion-fab.ios:not(.ios27-disabled) { + ion-fab.ios:not(.ios-theme-disabled, .ios26-disabled) { ion-fab-button { &.ion-activated { &::part(native) { diff --git a/src/styles/utils/dark/ion-segment.scss b/src/styles/utils/dark/ion-segment.scss index b858e912..196d29f9 100644 --- a/src/styles/utils/dark/ion-segment.scss +++ b/src/styles/utils/dark/ion-segment.scss @@ -1,7 +1,7 @@ @mixin ion-segment { - ion-segment.ios:not(.ios27-disabled) { + ion-segment.ios:not(.ios-theme-disabled, .ios26-disabled) { } - ion-segment-button.ios:not(.ios27-disabled) { + ion-segment-button.ios:not(.ios-theme-disabled, .ios26-disabled) { &.ion-cloned-element { &::part(native) { --ios27-glass-border-color-rgb: 120, 120, 120; diff --git a/src/styles/utils/dark/ion-tabs.scss b/src/styles/utils/dark/ion-tabs.scss index c6923576..b7b8afc3 100644 --- a/src/styles/utils/dark/ion-tabs.scss +++ b/src/styles/utils/dark/ion-tabs.scss @@ -1,9 +1,9 @@ @use '../api'; @mixin ion-tabs { - ion-tab-bar.ios:not(.ios27-disabled) { + ion-tab-bar.ios:not(.ios-theme-disabled, .ios26-disabled) { } - ion-tab-button.ios:not(.ios27-disabled) { + ion-tab-button.ios:not(.ios-theme-disabled, .ios26-disabled) { &.ion-activated { ion-label, ion-icon { diff --git a/src/styles/utils/translucent.scss b/src/styles/utils/translucent.scss index 2fa37234..d8952748 100644 --- a/src/styles/utils/translucent.scss +++ b/src/styles/utils/translucent.scss @@ -1,7 +1,7 @@ @use 'api'; -ion-header.ios:not(.ios27-disabled).header-translucent, -ion-footer.ios:not(.ios27-disabled).footer-translucent { +ion-header.ios:not(.ios-theme-disabled, .ios26-disabled).header-translucent, +ion-footer.ios:not(.ios-theme-disabled, .ios26-disabled).footer-translucent { .header-background, .footer-background { backdrop-filter: none; @@ -20,14 +20,14 @@ ion-footer.ios:not(.ios27-disabled).footer-translucent { } } -ion-header.ios:not(.ios27-disabled).header-translucent:not(.header-collapse-condense) { - &:has(> ion-toolbar.ios:not(.ios27-disabled) > *)::before { +ion-header.ios:not(.ios-theme-disabled, .ios26-disabled).header-translucent:not(.header-collapse-condense) { + &:has(> ion-toolbar.ios:not(.ios-theme-disabled, .ios26-disabled) > *)::before { height: 100%; background: rgba(var(--ion-color-base-rgb, var(--ios27-content-box-shadow-rgb)), calc(0.2 * var(--opacity-scale, 1))); backdrop-filter: blur(8px); } - &:not(.ion-no-border) > ion-toolbar.ios:not(.ios27-disabled):has(> *):last-of-type { + &:not(.ion-no-border) > ion-toolbar.ios:not(.ios-theme-disabled, .ios26-disabled):has(> *):last-of-type { --border-width: 0 0 0.5px; --border-color: var(--ion-toolbar-border-color, rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.08)); &::part(background) { @@ -37,7 +37,7 @@ ion-header.ios:not(.ios27-disabled).header-translucent:not(.header-collapse-cond } } -ion-header.ios:not(.ios27-disabled).header-collapse-main ion-toolbar.in-toolbar ion-title { +ion-header.ios:not(.ios-theme-disabled, .ios26-disabled).header-collapse-main ion-toolbar.in-toolbar ion-title { transition: opacity 0.5s ease-in-out, color 0.5s ease-in-out, @@ -45,15 +45,17 @@ ion-header.ios:not(.ios27-disabled).header-collapse-main ion-toolbar.in-toolbar transform 0.5s ease-in-out; } -ion-header.ios:not(.ios27-disabled).header-collapse-condense-inactive:not(.header-collapse-condense) ion-toolbar.in-toolbar ion-title { +ion-header.ios:not(.ios-theme-disabled, .ios26-disabled).header-collapse-condense-inactive:not(.header-collapse-condense) + ion-toolbar.in-toolbar + ion-title { color: transparent; text-shadow: 0 0 1px var(--ion-color-base, var(--ion-toolbar-color, var(--ion-text-color, #000))); transform: translateY(8px); } -ion-header.ios:not(.ios27-disabled).header-translucent::before, -ion-header.ios:not(.ios27-disabled).header-translucent::after, -ion-content.ios:not(.ios27-disabled).content-fullscreen::part(background)::before { +ion-header.ios:not(.ios-theme-disabled, .ios26-disabled).header-translucent::before, +ion-header.ios:not(.ios-theme-disabled, .ios26-disabled).header-translucent::after, +ion-content.ios:not(.ios-theme-disabled, .ios26-disabled).content-fullscreen::part(background)::before { content: ''; position: absolute; width: 100%; @@ -61,7 +63,7 @@ ion-content.ios:not(.ios27-disabled).content-fullscreen::part(background)::befor z-index: 1; } -ion-header.ios:not(.ios27-disabled).header-translucent::before { +ion-header.ios:not(.ios-theme-disabled, .ios26-disabled).header-translucent::before { /** * With safe-area effect, this is need. */ @@ -70,7 +72,7 @@ ion-header.ios:not(.ios27-disabled).header-translucent::before { height: var(--ion-safe-area-top); } -ion-header.ios:not(.ios27-disabled).header-translucent::after { +ion-header.ios:not(.ios-theme-disabled, .ios26-disabled).header-translucent::after { z-index: 2; top: 0; height: 100%; diff --git a/src/transition/ios.transition.ts b/src/transition/ios.transition.ts index 9dd479c3..b70fa817 100644 --- a/src/transition/ios.transition.ts +++ b/src/transition/ios.transition.ts @@ -24,14 +24,14 @@ const animateFixedBackButton = ( otherPage?: HTMLElement, ) => { const button = page.querySelector( - ':scope > ion-header.header-translucent:not(.ios27-disabled) ion-back-button:not(.ios27-disabled)', + ':scope > ion-header.header-translucent:not(.ios-theme-disabled, .ios26-disabled) ion-back-button:not(.ios-theme-disabled, .ios26-disabled)', ); if (!button || button.offsetWidth === 0) { return; } const otherButton = otherPage?.querySelector( - ':scope > ion-header.header-translucent:not(.ios27-disabled) ion-back-button:not(.ios27-disabled)', + ':scope > ion-header.header-translucent:not(.ios-theme-disabled, .ios26-disabled) ion-back-button:not(.ios-theme-disabled, .ios26-disabled)', ); const persistent = !!otherButton && otherButton.offsetWidth > 0; const buttons = [button, ...(persistent ? [otherButton!] : [])].map((element) => ({ @@ -623,7 +623,7 @@ export const iosTransitionAnimation = (navEl: HTMLElement, opts: TransitionOptio .beforeRemoveClass('ion-page-invisible'); const topPage = backDirection ? leavingEl : enteringEl; - if (topPage?.querySelector(':scope > ion-header.header-translucent:not(.ios27-disabled)')) { + if (topPage?.querySelector(':scope > ion-header.header-translucent:not(.ios-theme-disabled, .ios26-disabled)')) { const shadow = topPage.style.boxShadow; rootAnimation.beforeAddWrite(() => { topPage.style.boxShadow = `${isRTL ? 4 : -4}px 0 24px rgba(0, 0, 0, 0.04)`; @@ -640,7 +640,7 @@ export const iosTransitionAnimation = (navEl: HTMLElement, opts: TransitionOptio rootAnimation.addAnimation(navDecorAnimation); } - if (enteringEl.querySelector(':scope > ion-header.header-translucent:not(.ios27-disabled)')) { + if (enteringEl.querySelector(':scope > ion-header.header-translucent:not(.ios-theme-disabled, .ios26-disabled)')) { enteringContentAnimation.addElement(enteringEl); } else if (!contentEl && enteringToolBarEls.length === 0 && headerEls.length === 0) { enteringContentAnimation.addElement(enteringEl.querySelector(':scope > .ion-page, :scope > ion-nav, :scope > ion-tabs')!); // REVIEW @@ -661,7 +661,7 @@ export const iosTransitionAnimation = (navEl: HTMLElement, opts: TransitionOptio enteringContentAnimation.beforeClearStyles([OPACITY]).fromTo('transform', `translateX(${OFF_RIGHT})`, `translateX(${CENTER})`); } - if (contentEl && !enteringEl.querySelector(':scope > ion-header.header-translucent:not(.ios27-disabled)')) { + if (contentEl && !enteringEl.querySelector(':scope > ion-header.header-translucent:not(.ios-theme-disabled, .ios26-disabled)')) { const enteringTransitionEffectEl = shadow(contentEl).querySelector('.transition-effect'); if (enteringTransitionEffectEl) { const enteringTransitionCoverEl = enteringTransitionEffectEl.querySelector('.transition-cover'); @@ -705,7 +705,7 @@ export const iosTransitionAnimation = (navEl: HTMLElement, opts: TransitionOptio const enteringContentHasLargeTitle = enteringEl.querySelector('ion-header.header-collapse-condense'); enteringToolBarEls.forEach((enteringToolBarEl) => { - if (enteringToolBarEl.closest('ion-header')?.matches('.header-translucent:not(.ios27-disabled)')) { + if (enteringToolBarEl.closest('ion-header')?.matches('.header-translucent:not(.ios-theme-disabled, .ios26-disabled)')) { return; } const enteringToolBar = createAnimation(); @@ -796,7 +796,7 @@ export const iosTransitionAnimation = (navEl: HTMLElement, opts: TransitionOptio const leavingToolBarEls = leavingEl.querySelectorAll(':scope > ion-header > ion-toolbar'); const leavingHeaderEls = leavingEl.querySelectorAll(':scope > ion-header > *:not(ion-toolbar), :scope > ion-footer > *'); - if (leavingEl.querySelector(':scope > ion-header.header-translucent:not(.ios27-disabled)')) { + if (leavingEl.querySelector(':scope > ion-header.header-translucent:not(.ios-theme-disabled, .ios26-disabled)')) { leavingContent.addElement(leavingEl); } else if (!leavingContentEl && leavingToolBarEls.length === 0 && leavingHeaderEls.length === 0) { leavingContent.addElement(leavingEl.querySelector(':scope > .ion-page, :scope > ion-nav, :scope > ion-tabs')!); // REVIEW @@ -824,7 +824,10 @@ export const iosTransitionAnimation = (navEl: HTMLElement, opts: TransitionOptio leavingContent.fromTo('transform', `translateX(${CENTER})`, `translateX(${OFF_LEFT})`).fromTo(OPACITY, 1, OFF_OPACITY); } - if (leavingContentEl && !leavingEl.querySelector(':scope > ion-header.header-translucent:not(.ios27-disabled)')) { + if ( + leavingContentEl && + !leavingEl.querySelector(':scope > ion-header.header-translucent:not(.ios-theme-disabled, .ios26-disabled)') + ) { const leavingTransitionEffectEl = shadow(leavingContentEl).querySelector('.transition-effect'); if (leavingTransitionEffectEl) { @@ -856,7 +859,7 @@ export const iosTransitionAnimation = (navEl: HTMLElement, opts: TransitionOptio } leavingToolBarEls.forEach((leavingToolBarEl) => { - if (leavingToolBarEl.closest('ion-header')?.matches('.header-translucent:not(.ios27-disabled)')) { + if (leavingToolBarEl.closest('ion-header')?.matches('.header-translucent:not(.ios-theme-disabled, .ios26-disabled)')) { return; } const leavingToolBar = createAnimation(); From 6e916f2bbb990b158b577d8400f680a3f6f9af74 Mon Sep 17 00:00:00 2001 From: rdlabo Date: Thu, 10 Sep 2026 17:18:05 +0900 Subject: [PATCH 3/7] fix: stabilize theme CSS variables with legacy fallbacks --- demo/src/global.scss | 4 +-- docs/migration.md | 2 +- src/styles/components/ion-action-sheet.scss | 2 +- src/styles/components/ion-button.scss | 16 ++++----- src/styles/components/ion-content.scss | 6 ++-- src/styles/components/ion-fab.scss | 18 ++++++----- src/styles/components/ion-menu.scss | 36 ++++++++++++--------- src/styles/components/ion-modal.scss | 2 +- src/styles/components/ion-popover.scss | 5 +-- src/styles/components/ion-range.scss | 2 +- src/styles/components/ion-segment.scss | 2 +- src/styles/components/ion-tabs.scss | 20 ++++++------ src/styles/components/ion-toast.scss | 13 ++++---- src/styles/components/ion-toggle.scss | 4 +-- src/styles/default-variables.scss | 27 ++++++++-------- src/styles/utils/api.scss | 32 +++++++++--------- src/styles/utils/dark/ion-button.scss | 4 +-- src/styles/utils/dark/ion-segment.scss | 2 +- src/styles/utils/dark/ion-tabs.scss | 2 +- src/styles/utils/theme-dark.scss | 12 +++---- src/styles/utils/translucent.scss | 11 ++++--- 21 files changed, 117 insertions(+), 105 deletions(-) diff --git a/demo/src/global.scss b/demo/src/global.scss index d9712057..707cffa2 100644 --- a/demo/src/global.scss +++ b/demo/src/global.scss @@ -43,7 +43,7 @@ @use '../../src/styles/md-remove-ios-class-effect'; :root { - --ios27-menu-width: 300px; + --ios-theme-menu-width: 300px; } /** @@ -189,7 +189,7 @@ code { } ion-content { - --ios27-content-box-shadow-rgb: var(--ion-color-base-rgb, var(--ion-background-color-rgb, 255, 255, 255)); + --ios-theme-content-box-shadow-rgb: var(--ion-color-base-rgb, var(--ion-background-color-rgb, 255, 255, 255)); } #main-content { diff --git a/docs/migration.md b/docs/migration.md index a2855d7c..8d9b5935 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -8,7 +8,7 @@ title: Migration 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. -Update theme CSS variables and selectors to the `ios27-` prefix, including `--ios27-*` variables. Old variable names are no longer recognized. +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`. 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. diff --git a/src/styles/components/ion-action-sheet.scss b/src/styles/components/ion-action-sheet.scss index 0300a8b7..6e144545 100644 --- a/src/styles/components/ion-action-sheet.scss +++ b/src/styles/components/ion-action-sheet.scss @@ -6,7 +6,7 @@ ion-action-sheet.ios:not(.ios-theme-disabled, .ios26-disabled) { .action-sheet-wrapper { padding-bottom: 0; - bottom: var(--ios27-floating-safe-area-bottom); + bottom: var(--ios-theme-floating-safe-area-bottom, var(--ios26-floating-safe-area-bottom)); } .action-sheet-container { diff --git a/src/styles/components/ion-button.scss b/src/styles/components/ion-button.scss index cd71dc37..cb74a60d 100644 --- a/src/styles/components/ion-button.scss +++ b/src/styles/components/ion-button.scss @@ -23,7 +23,7 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only; /** * compare .header-collapse-main ion-toolbar.in-toolbar ion-title, .header-collapse-main ion-toolbar.in-toolbar ion-buttons */ - transition: transform var(--ios27-activated-transition-duration) ease-out; + transition: transform var(--ios-theme-activated-transition-duration, var(--ios26-activated-transition-duration)) ease-out; z-index: 0; @@ -140,7 +140,7 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only; } transition: - transform var(--ios27-activated-transition-duration) ease-out, + transform var(--ios-theme-activated-transition-duration, var(--ios26-activated-transition-duration)) ease-out, color 50ms ease; &.in-toolbar:not(.ion-color):not(.in-toolbar-color) { @@ -248,8 +248,8 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only; } } @else { --box-shadow: - inset 0 0 8px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.2), - 0 0 8px -4px rgba(var(--ios27-glass-box-shadow-color-rgb), 0.92); + inset 0 0 8px 0 rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), 0.2), + 0 0 8px -4px rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), 0.92); } &::part(native)::before { content: ''; @@ -313,13 +313,13 @@ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only; // fill:default only &:not(.button-solid):not(.button-outline):not(.button-clear) { - --background: rgba(var(--ios27-glass-background-rgb), 0.72); + --background: rgba(var(--ios-theme-glass-background-rgb, var(--ios26-glass-background-rgb)), 0.72); --background-hover: transparent; --background-activated: transparent; @if not $is-back-button { --box-shadow: - inset 0 0 8px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.2), - 0 0.5px 1px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.08); + inset 0 0 8px 0 rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), 0.2), + 0 0.5px 1px 0 rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), 0.08); } &:not(.button-has-icon-only):not(.back-button-has-icon-only) { @@ -421,7 +421,7 @@ ion-buttons.ios:not(.ios-theme-disabled, .ios26-disabled):not( ion-buttons.ios:not(.ios-theme-disabled, .ios26-disabled):not( :has(ion-back-button, ion-button:not(.button-clear), ion-menu-button.menu-button-hidden) ) { - transition: transform var(--ios27-activated-transition-duration) ease-out; + transition: transform var(--ios-theme-activated-transition-duration, var(--ios26-activated-transition-duration)) ease-out; } ion-buttons.ios:not(.ios-theme-disabled, .ios26-disabled):not(:has(ion-back-button, ion-button.button-clear)) { diff --git a/src/styles/components/ion-content.scss b/src/styles/components/ion-content.scss index 515b4980..39a0e7c7 100644 --- a/src/styles/components/ion-content.scss +++ b/src/styles/components/ion-content.scss @@ -16,9 +16,9 @@ .ion-page.ios:not(.ios-theme-disabled, .ios26-disabled):not(:has(ion-footer)) ion-content.ios:not(.ios-theme-disabled, .ios26-disabled).content-fullscreen .ion-content-scroll-host { - margin-bottom: calc(calc(60px + var(--ios27-floating-safe-area-bottom)) * -1); - padding-bottom: calc(60px + var(--ios27-floating-safe-area-bottom)); + margin-bottom: calc(calc(60px + var(--ios-theme-floating-safe-area-bottom, var(--ios26-floating-safe-area-bottom))) * -1); + padding-bottom: calc(60px + var(--ios-theme-floating-safe-area-bottom, var(--ios26-floating-safe-area-bottom))); } ion-content.ios:not(.ios-theme-disabled, .ios26-disabled).content-fullscreen:not(:has(.ion-content-scroll-host)) { - --padding-bottom: calc(60px + var(--ios27-floating-safe-area-bottom)); + --padding-bottom: calc(60px + var(--ios-theme-floating-safe-area-bottom, var(--ios26-floating-safe-area-bottom))); } diff --git a/src/styles/components/ion-fab.scss b/src/styles/components/ion-fab.scss index c54c14da..0ec08abc 100644 --- a/src/styles/components/ion-fab.scss +++ b/src/styles/components/ion-fab.scss @@ -11,12 +11,14 @@ ion-fab.ios:not(.ios-theme-disabled, .ios26-disabled) { } ion-fab-button { - --background: rgba(var(--ios27-glass-background-rgb), 0.72); + --background: rgba(var(--ios-theme-glass-background-rgb, var(--ios26-glass-background-rgb)), 0.72); --box-shadow: - inset 0 0 8px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.2), 0 0.5px 1px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.08); + inset 0 0 8px 0 rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), 0.2), + 0 0.5px 1px 0 rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), 0.08); --transition: - var(--ios27-activated-transition-duration) transform cubic-bezier(0.25, 1.11, 0.78, 1.59), - var(--ios27-activated-transition-duration) color ease; + var(--ios-theme-activated-transition-duration, var(--ios26-activated-transition-duration)) transform + cubic-bezier(0.25, 1.11, 0.78, 1.59), + var(--ios-theme-activated-transition-duration, var(--ios26-activated-transition-duration)) color ease; --background-activated-opacity: 0; --background-focused-opacity: 0; --background-hover-opacity: 0; @@ -77,15 +79,15 @@ ion-fab.ios:not(.ios-theme-disabled, .ios26-disabled) { } &.fab-vertical-top { - top: var(--ios27-floating-safe-area-top); + top: var(--ios-theme-floating-safe-area-top, var(--ios26-floating-safe-area-top)); } &.fab-vertical-bottom { - bottom: var(--ios27-floating-safe-area-bottom); + bottom: var(--ios-theme-floating-safe-area-bottom, var(--ios26-floating-safe-area-bottom)); } &.fab-horizontal-start { - left: calc(16px + var(--ios27-menu-width, var(--ion-safe-area-left), 0px)); + left: calc(16px + var(--ios-theme-menu-width, var(--ios26-menu-width, var(--ion-safe-area-left), 0px))); } &.fab-horizontal-end { @@ -94,7 +96,7 @@ ion-fab.ios:not(.ios-theme-disabled, .ios26-disabled) { &:has(.fab-button-small) { &.fab-horizontal-start { - left: calc(10px + var(--ios27-menu-width, var(--ion-safe-area-left), 0px)); + left: calc(10px + var(--ios-theme-menu-width, var(--ios26-menu-width, var(--ion-safe-area-left), 0px))); } &.fab-horizontal-end { diff --git a/src/styles/components/ion-menu.scss b/src/styles/components/ion-menu.scss index 05faa392..8e5c578e 100644 --- a/src/styles/components/ion-menu.scss +++ b/src/styles/components/ion-menu.scss @@ -1,7 +1,7 @@ @use '../utils/api'; ion-split-pane.ios:not(.ios-theme-disabled, .ios26-disabled) { - --side-max-width: var(--ios27-menu-width); + --side-max-width: var(--ios-theme-menu-width, var(--ios26-menu-width)); } ion-split-pane.ios:not(.ios-theme-disabled, .ios26-disabled).split-pane-visible:has(ion-menu.menu-pane-visible) { @@ -9,12 +9,15 @@ ion-split-pane.ios:not(.ios-theme-disabled, .ios26-disabled).split-pane-visible: ion-tab-bar.ios:not(.ios-theme-disabled, .ios26-disabled) { width: calc( 100% - calc(18px + var(--ion-safe-area-left, 0px)) - calc(18px + var(--ion-safe-area-left, 0px)) - 60px - - 12px - var(--ios27-menu-width) + 12px - var(--ios-theme-menu-width, var(--ios26-menu-width)) ); &:has(:nth-child(5)) { width: calc( - 100% - calc(18px + var(--ion-safe-area-left, 0px)) - calc(18px + var(--ion-safe-area-left, 0px)) - var(--ios27-menu-width) + 100% - calc(18px + var(--ion-safe-area-left, 0px)) - calc(18px + var(--ion-safe-area-left, 0px)) - var( + --ios-theme-menu-width, + var(--ios26-menu-width) + ) ); } } @@ -25,26 +28,26 @@ ion-split-pane.ios:not(.ios-theme-disabled, .ios26-disabled).split-pane-visible: /* * 4px: https://github.com/ionic-team/ionic-framework/blob/main/core/src/components/toolbar/toolbar.ios.vars.scss#L28-L32 */ - --padding-start: calc(var(--ios27-menu-width) + 4px); + --padding-start: calc(var(--ios-theme-menu-width, var(--ios26-menu-width)) + 4px); ion-title.title-default { /* * 90px: https://github.com/ionic-team/ionic-framework/blob/main/core/src/components/title/title.ios.scss#L8 */ - padding-left: calc(90px + var(--ios27-menu-width)); + padding-left: calc(90px + var(--ios-theme-menu-width, var(--ios26-menu-width))); } } ion-content { - --padding-start: var(--ios27-menu-width); + --padding-start: var(--ios-theme-menu-width, var(--ios26-menu-width)); ion-header ion-toolbar { --padding-start: 4px; } } ion-footer ion-toolbar { - --padding-start: var(--ios27-menu-width); + --padding-start: var(--ios-theme-menu-width, var(--ios26-menu-width)); } ion-tab-bar.ios:not(.ios-theme-disabled, .ios26-disabled) { &[slot='bottom'] { - left: calc(16px + var(--ion-safe-area-left, 0px) + var(--ios27-menu-width)); + left: calc(16px + var(--ion-safe-area-left, 0px) + var(--ios-theme-menu-width, var(--ios26-menu-width))); } } } @@ -56,22 +59,22 @@ ion-split-pane.ios:not(.ios-theme-disabled, .ios26-disabled).split-pane-visible: /* * 4px: https://github.com/ionic-team/ionic-framework/blob/main/core/src/components/toolbar/toolbar.ios.vars.scss#L28-L32 */ - --padding-end: calc(var(--ios27-menu-width) + 4px); + --padding-end: calc(var(--ios-theme-menu-width, var(--ios26-menu-width)) + 4px); ion-title.title-default { /* * 90px: https://github.com/ionic-team/ionic-framework/blob/main/core/src/components/title/title.ios.scss#L8 */ - padding-right: calc(90px + var(--ios27-menu-width)); + padding-right: calc(90px + var(--ios-theme-menu-width, var(--ios26-menu-width))); } } ion-content { - --padding-end: var(--ios27-menu-width); + --padding-end: var(--ios-theme-menu-width, var(--ios26-menu-width)); ion-header ion-toolbar { --padding-start: 4px; } } ion-footer ion-toolbar { - --padding-end: var(--ios27-menu-width); + --padding-end: var(--ios-theme-menu-width, var(--ios26-menu-width)); } } } @@ -80,7 +83,7 @@ ion-split-pane.ios:not(.ios-theme-disabled, .ios26-disabled).split-pane-visible: ion-menu.ios:not(.ios-theme-disabled, .ios26-disabled) { --border: none; --background: transparent; - --max-width: var(--ios27-menu-width); + --max-width: var(--ios-theme-menu-width, var(--ios26-menu-width)); position: absolute; top: 0; z-index: 999; @@ -89,7 +92,7 @@ ion-menu.ios:not(.ios-theme-disabled, .ios26-disabled) { left: 0; } &.menu-side-end { - left: calc(100vw - var(--ios27-menu-width)); + left: calc(100vw - var(--ios-theme-menu-width, var(--ios26-menu-width))); } &::part(backdrop) { @@ -98,11 +101,12 @@ ion-menu.ios:not(.ios-theme-disabled, .ios26-disabled) { ion-content { --background: transparent; - --ios27-content-box-shadow-rgb: transparent; + --ios26-content-box-shadow-rgb: transparent; &::part(scroll) { @include api.glass-background; - margin: calc(var(--ios27-floating-safe-area-top) + 6px) calc(16px + var(--ion-safe-area-right)) var(--ios27-floating-safe-area-bottom) + margin: calc(var(--ios-theme-floating-safe-area-top, var(--ios26-floating-safe-area-top)) + 6px) + calc(16px + var(--ion-safe-area-right)) var(--ios-theme-floating-safe-area-bottom, var(--ios26-floating-safe-area-bottom)) calc(12px + var(--ion-safe-area-left)); border-radius: 24px; } diff --git a/src/styles/components/ion-modal.scss b/src/styles/components/ion-modal.scss index d176ad0d..43205483 100644 --- a/src/styles/components/ion-modal.scss +++ b/src/styles/components/ion-modal.scss @@ -34,7 +34,7 @@ ion-modal.ios:not(.ios-theme-disabled, .ios26-disabled) { &.modal-sheet { --border-radius: 30px; - --background: rgba(var(--ios27-glass-background-rgb), 1); + --background: rgba(var(--ios-theme-glass-background-rgb, var(--ios26-glass-background-rgb)), 1); &::part(content) { @include api.glass-background($opacity: 1, $include-background: false); } diff --git a/src/styles/components/ion-popover.scss b/src/styles/components/ion-popover.scss index e0ea6871..ff287872 100644 --- a/src/styles/components/ion-popover.scss +++ b/src/styles/components/ion-popover.scss @@ -2,9 +2,10 @@ ion-popover.ios:not(.ios-theme-disabled, .ios26-disabled) { --backdrop-opacity: 0.2; - --background: rgba(var(--ios27-glass-background-rgb), 0.72); + --background: rgba(var(--ios-theme-glass-background-rgb, var(--ios26-glass-background-rgb)), 0.72); --box-shadow: - inset 0 0 8px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.2), 0 0 10px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.82); + inset 0 0 8px 0 rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), 0.2), + 0 0 10px 0 rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), 0.82); &::part(arrow) { display: none; ::after { diff --git a/src/styles/components/ion-range.scss b/src/styles/components/ion-range.scss index da866335..823ea48f 100644 --- a/src/styles/components/ion-range.scss +++ b/src/styles/components/ion-range.scss @@ -36,7 +36,7 @@ ion-range.ios:not(.ios-theme-disabled, .ios26-disabled) { } &:not(.range-dual-knobs).range-pressed { - --knob-background: rgba(var(--ios27-glass-background-rgb), 0.1); + --knob-background: rgba(var(--ios-theme-glass-background-rgb, var(--ios26-glass-background-rgb)), 0.1); --knob-box-shadow: 0 0.5px 4px rgba(0, 0, 0, 0.12), 0 6px 4px rgba(0, 0, 0, 0.05), inset 0.4px 0.4px 1px 0 var(--bar-background-active); &::part(knob) { diff --git a/src/styles/components/ion-segment.scss b/src/styles/components/ion-segment.scss index 5d838d7c..cdfa9f71 100644 --- a/src/styles/components/ion-segment.scss +++ b/src/styles/components/ion-segment.scss @@ -5,7 +5,7 @@ ion-segment.ios:not(.ios-theme-disabled, .ios26-disabled) { min-height: 48px; border-radius: 25px; - transition: transform var(--ios27-activated-transition-duration) ease-out; + transition: transform var(--ios-theme-activated-transition-duration, var(--ios26-activated-transition-duration)) ease-out; // will-change is optimized to only apply when needed for performance &.segment-activated, diff --git a/src/styles/components/ion-tabs.scss b/src/styles/components/ion-tabs.scss index ab5ed209..93b09d69 100644 --- a/src/styles/components/ion-tabs.scss +++ b/src/styles/components/ion-tabs.scss @@ -9,13 +9,13 @@ ion-tab-bar.ios:not(.ios-theme-disabled, .ios26-disabled) { &[slot='top'] { position: absolute; - top: var(--ios27-floating-safe-area-top); + top: var(--ios-theme-floating-safe-area-top, var(--ios26-floating-safe-area-top)); right: calc(16px + var(--ion-safe-area-right, 0px)); } &[slot='bottom'] { position: absolute; - bottom: var(--ios27-floating-safe-area-bottom); + bottom: var(--ios-theme-floating-safe-area-bottom, var(--ios26-floating-safe-area-bottom)); left: calc(16px + var(--ion-safe-area-left, 0px)); } @@ -31,7 +31,7 @@ ion-tab-bar.ios:not(.ios-theme-disabled, .ios26-disabled) { } padding: 2px 2px; - transition: transform var(--ios27-activated-transition-duration) ease-out; + transition: transform var(--ios-theme-activated-transition-duration, var(--ios26-activated-transition-duration)) ease-out; // will-change is optimized to only apply when needed for performance &:has(ion-tab-button.ion-activated) { @@ -55,7 +55,7 @@ ion-tab-bar.ios:not(.ios-theme-disabled, .ios26-disabled) { */ &.ios27-enable-gesture.ios27-animated { ion-tab-button.tab-selected::part(native) { - background: rgba(var(--ios27-button-color-selected-rgb), 0); + background: rgba(var(--ios-theme-button-color-selected-rgb, var(--ios26-button-color-selected-rgb)), 0); } ion-tab-button.ion-activated { ion-label, @@ -73,12 +73,12 @@ ion-tab-button.ios:not(.ios-theme-disabled, .ios26-disabled) { ion-label, ion-icon { transition: - filter var(--ios27-activated-transition-duration) ease, - color var(--ios27-activated-transition-duration) ease; + filter var(--ios-theme-activated-transition-duration, var(--ios26-activated-transition-duration)) ease, + color var(--ios-theme-activated-transition-duration, var(--ios26-activated-transition-duration)) ease; } - background: rgba(var(--ios27-glass-background-rgb), 0); + background: rgba(var(--ios-theme-glass-background-rgb, var(--ios26-glass-background-rgb)), 0); height: auto; - transition: transform var(--ios27-activated-transition-duration) ease; + transition: transform var(--ios-theme-activated-transition-duration, var(--ios26-activated-transition-duration)) ease; &::part(native) { overflow: visible; min-height: 56px; @@ -97,8 +97,8 @@ ion-tab-button.ios:not(.ios-theme-disabled, .ios26-disabled) { &.tab-selected { &::part(native) { - background: rgba(var(--ios27-button-color-selected-rgb), 0.095); - transition: background var(--ios27-activated-transition-duration) ease; + background: rgba(var(--ios-theme-button-color-selected-rgb, var(--ios26-button-color-selected-rgb)), 0.095); + transition: background var(--ios-theme-activated-transition-duration, var(--ios26-activated-transition-duration)) ease; } } diff --git a/src/styles/components/ion-toast.scss b/src/styles/components/ion-toast.scss index bdbdeecd..ba23f95b 100644 --- a/src/styles/components/ion-toast.scss +++ b/src/styles/components/ion-toast.scss @@ -1,21 +1,22 @@ @use '../utils/api'; ion-toast.ios:not(.ios-theme-disabled, .ios26-disabled) { - --background: rgba(var(--ios27-glass-background-rgb), 0.72); + --background: rgba(var(--ios-theme-glass-background-rgb, var(--ios26-glass-background-rgb)), 0.72); --border-radius: 24px; --border-style: solid; --border-width: 0.5px; --box-shadow: - inset 0 0 8px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.2), 0 0 10px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.82); + inset 0 0 8px 0 rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), 0.2), + 0 0 10px 0 rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), 0.82); --start: 16px; --end: 16px; &::part(wrapper) { @include api.glass-background($include-background: false, $include-box-shadow: false, $include-border: false); - border-top-color: rgba(var(--ios27-glass-border-color-rgb), 1); - border-right-color: rgba(var(--ios27-glass-border-color-rgb), 0.8); - border-bottom-color: rgba(var(--ios27-glass-border-color-rgb), 1); - border-left-color: rgba(var(--ios27-glass-border-color-rgb), 0.6); + border-top-color: rgba(var(--ios-theme-glass-border-color-rgb, var(--ios26-glass-border-color-rgb)), 1); + border-right-color: rgba(var(--ios-theme-glass-border-color-rgb, var(--ios26-glass-border-color-rgb)), 0.8); + border-bottom-color: rgba(var(--ios-theme-glass-border-color-rgb, var(--ios26-glass-border-color-rgb)), 1); + border-left-color: rgba(var(--ios-theme-glass-border-color-rgb, var(--ios26-glass-border-color-rgb)), 0.6); } &.ion-color { diff --git a/src/styles/components/ion-toggle.scss b/src/styles/components/ion-toggle.scss index a0007b6c..4560b713 100644 --- a/src/styles/components/ion-toggle.scss +++ b/src/styles/components/ion-toggle.scss @@ -48,8 +48,8 @@ ion-toggle.ios:not(.ios-theme-disabled, .ios26-disabled) { @include api.glass-background($opacity: 0.1, $blur: 0.5px, $saturate: 120%, $include-background: false, $include-box-shadow: false); } &.toggle-activated { - --handle-background: rgba(var(--ios27-glass-background-rgb), 0.1); - --handle-background-checked: rgba(var(--ios27-glass-background-rgb), 0.1); + --handle-background: rgba(var(--ios-theme-glass-background-rgb, var(--ios26-glass-background-rgb)), 0.1); + --handle-background-checked: rgba(var(--ios-theme-glass-background-rgb, var(--ios26-glass-background-rgb)), 0.1); --handle-box-shadow: inset 0 0 8px 0 var(--track-background); } &.ion-color.toggle-checked.toggle-activated { diff --git a/src/styles/default-variables.scss b/src/styles/default-variables.scss index 10cde2ed..f669e8b4 100644 --- a/src/styles/default-variables.scss +++ b/src/styles/default-variables.scss @@ -1,32 +1,33 @@ /** * @naming - * prefix: ios27 + * prefix: ios-theme * target-element: tab-button * target css property: color * status: selected * additional information: rgb */ +// Deprecated --ios26-* defaults back the --ios-theme-* fallbacks. :root { - --ios27-floating-safe-area-top: max(10px, var(--ion-safe-area-top, 0px)); - --ios27-floating-safe-area-bottom: max(10px, calc(var(--ion-safe-area-bottom, 0px) - 12px)); + --ios26-floating-safe-area-top: max(10px, var(--ion-safe-area-top, 0px)); + --ios26-floating-safe-area-bottom: max(10px, calc(var(--ion-safe-area-bottom, 0px) - 12px)); - --ios27-activated-transition-duration: 140ms; + --ios26-activated-transition-duration: 140ms; - --ios27-glass-background-rgb: 255, 255, 255; - --ios27-glass-box-shadow-color-rgb: 220, 220, 220; - --ios27-glass-border-color-rgb: 255, 255, 255; - --ios27-button-color-selected-rgb: 16, 16, 16; + --ios26-glass-background-rgb: 255, 255, 255; + --ios26-glass-box-shadow-color-rgb: 220, 220, 220; + --ios26-glass-border-color-rgb: 255, 255, 255; + --ios26-button-color-selected-rgb: 16, 16, 16; - --ios27-menu-width: 360px; + --ios26-menu-width: 360px; /** - * `--ios27-color-background-rgb` is deprecated. - * You should replace to '--ios27-content-box-shadow-rgb'. + * `--ios26-color-background-rgb` is deprecated. + * Use '--ios-theme-content-box-shadow-rgb'. * This variable can also be defined in root, but if you want to set multiple background colors individually, it is easier to set them as follows. - * ion-content { --ios27-content-box-shadow-rgb: var(--ion-color-base-rgb); } + * ion-content { --ios-theme-content-box-shadow-rgb: var(--ion-color-base-rgb); } */ - --ios27-content-box-shadow-rgb: var(--ion-color-base-rgb, var(--ion-background-color-rgb, 255, 255, 255)); + --ios26-content-box-shadow-rgb: var(--ion-color-base-rgb, var(--ion-background-color-rgb, 255, 255, 255)); /** * `--ion-color-**-brightness-rgb` is deprecated. diff --git a/src/styles/utils/api.scss b/src/styles/utils/api.scss index 6f09db5b..f6c4d695 100644 --- a/src/styles/utils/api.scss +++ b/src/styles/utils/api.scss @@ -22,8 +22,8 @@ $_glass-surface: linear-gradient( $opacity: 0.72, $blur: 2px, $saturate: 360%, - $background-rgb: var(--ios27-glass-background-rgb), - $border-color-rgb: var(--ios27-glass-border-color-rgb), + $background-rgb: var(--ios-theme-glass-background-rgb, var(--ios26-glass-background-rgb)), + $border-color-rgb: var(--ios-theme-glass-border-color-rgb, var(--ios26-glass-border-color-rgb)), $include-background: true, $include-box-shadow: true, $include-border: true, @@ -40,10 +40,10 @@ $_glass-surface: linear-gradient( @if $include-box-shadow { box-shadow: inset 0 0 0 0.5px rgba($border-color-rgb, 0.6), - inset 0 0 1px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.18), + inset 0 0 1px 0 rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), 0.18), inset 0 1px 2px 0 rgba($border-color-rgb, 0.8), inset 0 -1px 2px 0 rgba($border-color-rgb, 0.5), - 0 0.5px 1px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), $shadow-opacity); + 0 0.5px 1px 0 rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), $shadow-opacity); } @if $include-border { border: 0.5px solid; @@ -84,14 +84,14 @@ $_glass-surface: linear-gradient( } @mixin glass-background-button-activated { - background-color: rgba(var(--ios27-glass-background-rgb), 0.96); + background-color: rgba(var(--ios-theme-glass-background-rgb, var(--ios26-glass-background-rgb)), 0.96); border-color: rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.12) rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.32) rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.16) rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.28); box-shadow: - inset 0 0 0 0.5px rgba(var(--ios27-glass-border-color-rgb), 0.95), - inset 0 1px 3px 0 rgba(var(--ios27-glass-border-color-rgb), 0.85), - inset 0 -1px 2px 0 rgba(var(--ios27-glass-border-color-rgb), 0.6), - 0 0.5px 1px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.12); + inset 0 0 0 0.5px rgba(var(--ios-theme-glass-border-color-rgb, var(--ios26-glass-border-color-rgb)), 0.95), + inset 0 1px 3px 0 rgba(var(--ios-theme-glass-border-color-rgb, var(--ios26-glass-border-color-rgb)), 0.85), + inset 0 -1px 2px 0 rgba(var(--ios-theme-glass-border-color-rgb, var(--ios26-glass-border-color-rgb)), 0.6), + 0 0.5px 1px 0 rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), 0.12); } @mixin glass-background-button-activated-dark( @@ -102,18 +102,18 @@ $_glass-surface: linear-gradient( $include-box-shadow: true ) { @if $include-background { - background: rgba(var(--ios27-button-color-selected-rgb), $opacity); + background: rgba(var(--ios-theme-button-color-selected-rgb, var(--ios26-button-color-selected-rgb)), $opacity); } @else { - background-color: rgba(var(--ios27-button-color-selected-rgb), $opacity); + background-color: rgba(var(--ios-theme-button-color-selected-rgb, var(--ios26-button-color-selected-rgb)), $opacity); } backdrop-filter: blur($blur) saturate($saturate); @if $include-box-shadow { - box-shadow: inset 0 0 16px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.55); + box-shadow: inset 0 0 16px 0 rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), 0.55); } - border-top: 0.8px solid rgba(var(--ios27-button-color-selected-rgb), 0.8); - border-right: 0.8px solid rgba(var(--ios27-button-color-selected-rgb), 0.4); - border-bottom: 0.8px solid rgba(var(--ios27-button-color-selected-rgb), 0.8); - border-left: 0.8px solid rgba(var(--ios27-button-color-selected-rgb), 0.6); + border-top: 0.8px solid rgba(var(--ios-theme-button-color-selected-rgb, var(--ios26-button-color-selected-rgb)), 0.8); + border-right: 0.8px solid rgba(var(--ios-theme-button-color-selected-rgb, var(--ios26-button-color-selected-rgb)), 0.4); + border-bottom: 0.8px solid rgba(var(--ios-theme-button-color-selected-rgb, var(--ios26-button-color-selected-rgb)), 0.8); + border-left: 0.8px solid rgba(var(--ios-theme-button-color-selected-rgb, var(--ios26-button-color-selected-rgb)), 0.6); background-image: none; background-clip: border-box; background-origin: padding-box; diff --git a/src/styles/utils/dark/ion-button.scss b/src/styles/utils/dark/ion-button.scss index f4e8d582..661d60cb 100644 --- a/src/styles/utils/dark/ion-button.scss +++ b/src/styles/utils/dark/ion-button.scss @@ -28,10 +28,10 @@ @mixin theme-dark-button($is-back-button: false) { &.ion-activated:not(.button-solid):not(.button-outline):not(.button-clear) { - --background: rgba(var(--ios27-button-color-selected-rgb), 0.56); + --background: rgba(var(--ios-theme-button-color-selected-rgb, var(--ios26-button-color-selected-rgb)), 0.56); --color: rgba(var(--ion-text-color-rgb, 0, 0, 0), 1); @if not $is-back-button { - --box-shadow: inset 0 0 16px 0 rgba(var(--ios27-glass-box-shadow-color-rgb), 0.55); + --box-shadow: inset 0 0 16px 0 rgba(var(--ios-theme-glass-box-shadow-color-rgb, var(--ios26-glass-box-shadow-color-rgb)), 0.55); } &.ion-color { --color: rgba(var(--ion-color-base-rgb, var(--ion-text-color-rgb, 0, 0, 0)), 1); diff --git a/src/styles/utils/dark/ion-segment.scss b/src/styles/utils/dark/ion-segment.scss index 196d29f9..fffa521e 100644 --- a/src/styles/utils/dark/ion-segment.scss +++ b/src/styles/utils/dark/ion-segment.scss @@ -4,7 +4,7 @@ ion-segment-button.ios:not(.ios-theme-disabled, .ios26-disabled) { &.ion-cloned-element { &::part(native) { - --ios27-glass-border-color-rgb: 120, 120, 120; + --ios26-glass-border-color-rgb: 120, 120, 120; box-shadow: inset 0 0 8px 0 rgba(255, 255, 255, 0.2); } } diff --git a/src/styles/utils/dark/ion-tabs.scss b/src/styles/utils/dark/ion-tabs.scss index b7b8afc3..760cd1a0 100644 --- a/src/styles/utils/dark/ion-tabs.scss +++ b/src/styles/utils/dark/ion-tabs.scss @@ -13,7 +13,7 @@ } &.ion-cloned-element { &::part(native) { - --ios27-glass-border-color-rgb: 120, 120, 120; + --ios26-glass-border-color-rgb: 120, 120, 120; box-shadow: inset 0 0 8px 0 rgba(255, 255, 255, 0.2); } } diff --git a/src/styles/utils/theme-dark.scss b/src/styles/utils/theme-dark.scss index 99e32432..c162c761 100644 --- a/src/styles/utils/theme-dark.scss +++ b/src/styles/utils/theme-dark.scss @@ -8,13 +8,13 @@ @use 'dark/ion-segment' as *; @mixin default-variables { - //--ios27-glass-background-rgb: 35, 35, 35; - --ios27-glass-background-rgb: 62, 62, 62; - --ios27-glass-box-shadow-color-rgb: 0, 0, 0 / 0; - --ios27-glass-border-color-rgb: 68, 68, 68; - --ios27-button-color-selected-rgb: 255, 255, 255; + //--ios26-glass-background-rgb: 35, 35, 35; + --ios26-glass-background-rgb: 62, 62, 62; + --ios26-glass-box-shadow-color-rgb: 0, 0, 0 / 0; + --ios26-glass-border-color-rgb: 68, 68, 68; + --ios26-button-color-selected-rgb: 255, 255, 255; - --ios27-content-box-shadow-rgb: 0, 0, 0; + --ios26-content-box-shadow-rgb: 0, 0, 0; } @mixin theme-dark { diff --git a/src/styles/utils/translucent.scss b/src/styles/utils/translucent.scss index d8952748..fa3998c2 100644 --- a/src/styles/utils/translucent.scss +++ b/src/styles/utils/translucent.scss @@ -23,7 +23,10 @@ ion-footer.ios:not(.ios-theme-disabled, .ios26-disabled).footer-translucent { ion-header.ios:not(.ios-theme-disabled, .ios26-disabled).header-translucent:not(.header-collapse-condense) { &:has(> ion-toolbar.ios:not(.ios-theme-disabled, .ios26-disabled) > *)::before { height: 100%; - background: rgba(var(--ion-color-base-rgb, var(--ios27-content-box-shadow-rgb)), calc(0.2 * var(--opacity-scale, 1))); + background: rgba( + var(--ion-color-base-rgb, var(--ios-theme-content-box-shadow-rgb, var(--ios26-content-box-shadow-rgb))), + calc(0.2 * var(--opacity-scale, 1)) + ); backdrop-filter: blur(8px); } @@ -90,8 +93,8 @@ ion-header.ios:not(.ios-theme-disabled, .ios26-disabled).header-translucent::aft height: var(--offset-top, 0px); background: linear-gradient( in oklab, - rgba(var(--ios27-content-box-shadow-rgb), 0.5) 0%, - rgba(var(--ios27-content-box-shadow-rgb), 0.2) 50%, - rgba(var(--ios27-content-box-shadow-rgb), 0) 100% + rgba(var(--ios-theme-content-box-shadow-rgb, var(--ios26-content-box-shadow-rgb)), 0.5) 0%, + rgba(var(--ios-theme-content-box-shadow-rgb, var(--ios26-content-box-shadow-rgb)), 0.2) 50%, + rgba(var(--ios-theme-content-box-shadow-rgb, var(--ios26-content-box-shadow-rgb)), 0) 100% ); } From 25e3b9b45ed3fed29601c939ab423a5128449231 Mon Sep 17 00:00:00 2001 From: rdlabo Date: Thu, 10 Sep 2026 17:26:40 +0900 Subject: [PATCH 4/7] docs: describe adaptive iOS themes and animation imports --- README.md | 1 + demo/README.md | 4 +- docs/ios-18.md | 16 -------- docs/ios-adaptive.md | 90 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 93 insertions(+), 18 deletions(-) delete mode 100644 docs/ios-18.md create mode 100644 docs/ios-adaptive.md diff --git a/README.md b/README.md index 3855c6c3..996c37ff 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,7 @@ createApp(App) ## Documentation +- [Adaptive iOS themes](./docs/ios-adaptive.md) — conditionally load iOS 26 or iOS 27 styles. - [Using ion-item-group](./docs/using-ion-item-group.md) — required markup for inset lists. - [Special markup and classes](./docs/special-markup.md) — opt-in markup and utility classes used by the theme. - [ESLint](./docs/eslint.md) — check list structure with ESLint rules. diff --git a/demo/README.md b/demo/README.md index a846295a..d294d3d9 100644 --- a/demo/README.md +++ b/demo/README.md @@ -84,8 +84,8 @@ demo/ │ │ ├── pages/ # All page components │ │ └── index.routes.ts │ ├── theme/ -│ │ └── theme-ios27.scss # iOS27 theme -│ └── global.scss +│ │ └── variables.scss # Demo variables +│ └── global.scss # Imports the iOS 27 theme ├── playwright.config.ts # Playwright configuration └── package.json ``` diff --git a/docs/ios-18.md b/docs/ios-18.md deleted file mode 100644 index 677b55c1..00000000 --- a/docs/ios-18.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: Supporting iOS 18 ---- - -# Supporting iOS 18 - -## How to prevent loading the theme on iOS 18 - -If you want to load a theme file only when the user's device is running iOS 26 (and let users on iOS 18 use the default Ionic iOS theme), you can achieve this by adding a supports-condition to your `import`. - -```css -@import '@rdlabo/ionic-theme-ios27/dist/css/default-variables.css' supports(text-wrap: pretty); -@import '@rdlabo/ionic-theme-ios27/dist/css/ionic-theme-ios27.css' supports(text-wrap: pretty); -@import '@rdlabo/ionic-theme-ios27/dist/css/md-remove-ios-class-effect.css' supports(text-wrap: pretty); -@import '@rdlabo/ionic-theme-ios27/dist/css/md-ion-list-inset.css' supports(text-wrap: pretty); -``` diff --git a/docs/ios-adaptive.md b/docs/ios-adaptive.md new file mode 100644 index 00000000..45f3325a --- /dev/null +++ b/docs/ios-adaptive.md @@ -0,0 +1,90 @@ +--- +title: Adaptive iOS themes +--- + +# Adaptive iOS themes + +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/). + +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. + +## Load only the iOS 27 theme + +In your global Sass stylesheet, use `meta.load-css` inside the feature query. Unlike `@use`, it can emit the theme inside `@supports`. + +```scss +@use 'sass:meta'; + +@supports selector(:heading) { + @include meta.load-css('@rdlabo/ionic-theme-ios27/src/styles/default-variables'); + @include meta.load-css('@rdlabo/ionic-theme-ios27/src/styles/ionic-theme-ios27'); + @include meta.load-css('@rdlabo/ionic-theme-ios27/src/styles/ionic-theme-ios27-dark-class'); + @include meta.load-css('@rdlabo/ionic-theme-ios27/src/styles/md-remove-ios-class-effect'); +} +``` + +## Use the iOS 26 and iOS 27 themes together + +Install both packages: + +```bash +npm install @rdlabo/ionic-theme-ios26 @rdlabo/ionic-theme-ios27 +``` + +Use this global Sass configuration instead of unconditional theme imports: + +```scss +@use 'sass:meta'; + +@supports selector(:heading) { + @include meta.load-css('@rdlabo/ionic-theme-ios27/src/styles/default-variables'); + @include meta.load-css('@rdlabo/ionic-theme-ios27/src/styles/ionic-theme-ios27'); + @include meta.load-css('@rdlabo/ionic-theme-ios27/src/styles/ionic-theme-ios27-dark-class'); + @include meta.load-css('@rdlabo/ionic-theme-ios27/src/styles/md-remove-ios-class-effect'); +} + +@supports (text-wrap: pretty) and (not selector(:heading)) { + @include meta.load-css('@rdlabo/ionic-theme-ios26/src/styles/default-variables'); + @include meta.load-css('@rdlabo/ionic-theme-ios26/src/styles/ionic-theme-ios26'); + @include meta.load-css('@rdlabo/ionic-theme-ios26/src/styles/ionic-theme-ios26-dark-class'); + @include meta.load-css('@rdlabo/ionic-theme-ios26/src/styles/md-remove-ios-class-effect'); +} +``` + +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. + +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. + +## Select matching JavaScript animations + +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. + +```ts +async function loadIOSAnimations() { + if (typeof CSS === 'undefined') { + return {}; + } + + const theme = CSS.supports('selector(:heading)') + ? await import('@rdlabo/ionic-theme-ios27') + : CSS.supports('text-wrap: pretty') + ? await import('@rdlabo/ionic-theme-ios26') + : undefined; + + if (!theme) { + return {}; + } + + return { + navAnimation: theme.iosTransitionAnimation, + popoverEnter: theme.popoverEnterAnimation, + popoverLeave: theme.popoverLeaveAnimation, + }; +} + +// In your browser bootstrap, before initializing Ionic: +const animations = isPlatform('ios') ? await loadIOSAnimations() : {}; +provideIonicAngular({ ...animations }); +``` + +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. From 13ec3cf14e88b02c5a0c2c573e8485ae0c2f8d2e Mon Sep 17 00:00:00 2001 From: rdlabo Date: Thu, 10 Sep 2026 17:45:54 +0900 Subject: [PATCH 5/7] chore: defer visible demo package rename to separate PR --- demo/src/app/index/pages/accordion/accordion.page.html | 2 +- demo/src/app/index/pages/action-sheet/action-sheet.page.html | 2 +- demo/src/app/index/pages/alert/alert.page.html | 2 +- demo/src/app/index/pages/breadcrumbs/breadcrumbs.page.html | 2 +- demo/src/app/index/pages/button/button.page.html | 2 +- demo/src/app/index/pages/card/card.page.html | 2 +- demo/src/app/index/pages/checkbox/checkbox.page.html | 2 +- demo/src/app/index/pages/chip/chip.page.html | 2 +- .../pages/date-and-time-pickers/date-and-time-pickers.page.html | 2 +- .../floating-action-button-fixed.page.html | 2 +- .../floating-action-button/floating-action-button.page.html | 2 +- demo/src/app/index/pages/inputs/inputs.page.html | 2 +- demo/src/app/index/pages/modal/modal.page.html | 2 +- demo/src/app/index/pages/popover/popover.page.html | 2 +- .../pages/progress-indicators/progress-indicators.page.html | 2 +- demo/src/app/index/pages/radio/radio.page.html | 2 +- demo/src/app/index/pages/range/range.page.html | 2 +- demo/src/app/index/pages/reorder/reorder.page.html | 2 +- demo/src/app/index/pages/searchbar/searchbar.page.html | 2 +- demo/src/app/index/pages/segment/segment.page.html | 2 +- demo/src/app/index/pages/select/select.page.html | 2 +- demo/src/app/index/pages/tabs/tabs.page.html | 2 +- demo/src/app/index/pages/toast/toast.page.html | 2 +- demo/src/app/index/pages/toggle/toggle.page.html | 2 +- demo/src/app/index/pages/toolbar/toolbar.page.html | 2 +- 25 files changed, 25 insertions(+), 25 deletions(-) diff --git a/demo/src/app/index/pages/accordion/accordion.page.html b/demo/src/app/index/pages/accordion/accordion.page.html index edd2b9c7..2af94547 100644 --- a/demo/src/app/index/pages/accordion/accordion.page.html +++ b/demo/src/app/index/pages/accordion/accordion.page.html @@ -17,7 +17,7 @@

accordion

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/action-sheet/action-sheet.page.html b/demo/src/app/index/pages/action-sheet/action-sheet.page.html index d927095e..42399ea4 100644 --- a/demo/src/app/index/pages/action-sheet/action-sheet.page.html +++ b/demo/src/app/index/pages/action-sheet/action-sheet.page.html @@ -17,7 +17,7 @@

action-sheet

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/alert/alert.page.html b/demo/src/app/index/pages/alert/alert.page.html index 922f47e6..243076d4 100644 --- a/demo/src/app/index/pages/alert/alert.page.html +++ b/demo/src/app/index/pages/alert/alert.page.html @@ -17,7 +17,7 @@

alert

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/breadcrumbs/breadcrumbs.page.html b/demo/src/app/index/pages/breadcrumbs/breadcrumbs.page.html index d9be6eb3..5b86a800 100644 --- a/demo/src/app/index/pages/breadcrumbs/breadcrumbs.page.html +++ b/demo/src/app/index/pages/breadcrumbs/breadcrumbs.page.html @@ -17,7 +17,7 @@

breadcrumbs

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/button/button.page.html b/demo/src/app/index/pages/button/button.page.html index 4f0b0d9a..a34ce13f 100644 --- a/demo/src/app/index/pages/button/button.page.html +++ b/demo/src/app/index/pages/button/button.page.html @@ -30,7 +30,7 @@

button

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/card/card.page.html b/demo/src/app/index/pages/card/card.page.html index 7c011b78..040ebf65 100644 --- a/demo/src/app/index/pages/card/card.page.html +++ b/demo/src/app/index/pages/card/card.page.html @@ -17,7 +17,7 @@

card

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/checkbox/checkbox.page.html b/demo/src/app/index/pages/checkbox/checkbox.page.html index ce08ff44..a7ac85e3 100644 --- a/demo/src/app/index/pages/checkbox/checkbox.page.html +++ b/demo/src/app/index/pages/checkbox/checkbox.page.html @@ -17,7 +17,7 @@

checkbox

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/chip/chip.page.html b/demo/src/app/index/pages/chip/chip.page.html index 9640b69e..200be777 100644 --- a/demo/src/app/index/pages/chip/chip.page.html +++ b/demo/src/app/index/pages/chip/chip.page.html @@ -17,7 +17,7 @@

chip

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/date-and-time-pickers/date-and-time-pickers.page.html b/demo/src/app/index/pages/date-and-time-pickers/date-and-time-pickers.page.html index 61335526..3ad95e10 100644 --- a/demo/src/app/index/pages/date-and-time-pickers/date-and-time-pickers.page.html +++ b/demo/src/app/index/pages/date-and-time-pickers/date-and-time-pickers.page.html @@ -17,7 +17,7 @@

date-and-time-pickers

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/floating-action-button-fixed/floating-action-button-fixed.page.html b/demo/src/app/index/pages/floating-action-button-fixed/floating-action-button-fixed.page.html index acec65e4..e232d929 100644 --- a/demo/src/app/index/pages/floating-action-button-fixed/floating-action-button-fixed.page.html +++ b/demo/src/app/index/pages/floating-action-button-fixed/floating-action-button-fixed.page.html @@ -17,7 +17,7 @@

floating-action-button

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/floating-action-button/floating-action-button.page.html b/demo/src/app/index/pages/floating-action-button/floating-action-button.page.html index 8bd7ac08..bfec1ba9 100644 --- a/demo/src/app/index/pages/floating-action-button/floating-action-button.page.html +++ b/demo/src/app/index/pages/floating-action-button/floating-action-button.page.html @@ -17,7 +17,7 @@

floating-action-button

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/inputs/inputs.page.html b/demo/src/app/index/pages/inputs/inputs.page.html index d02a63d3..13c0bfbe 100644 --- a/demo/src/app/index/pages/inputs/inputs.page.html +++ b/demo/src/app/index/pages/inputs/inputs.page.html @@ -17,7 +17,7 @@

inputs

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/modal/modal.page.html b/demo/src/app/index/pages/modal/modal.page.html index 792af614..33f45d7d 100644 --- a/demo/src/app/index/pages/modal/modal.page.html +++ b/demo/src/app/index/pages/modal/modal.page.html @@ -26,7 +26,7 @@

modal

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/popover/popover.page.html b/demo/src/app/index/pages/popover/popover.page.html index 5b04510b..bf5a2012 100644 --- a/demo/src/app/index/pages/popover/popover.page.html +++ b/demo/src/app/index/pages/popover/popover.page.html @@ -17,7 +17,7 @@

popover

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/progress-indicators/progress-indicators.page.html b/demo/src/app/index/pages/progress-indicators/progress-indicators.page.html index 338e3fb6..50bfac83 100644 --- a/demo/src/app/index/pages/progress-indicators/progress-indicators.page.html +++ b/demo/src/app/index/pages/progress-indicators/progress-indicators.page.html @@ -17,7 +17,7 @@

progress-indicators

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/radio/radio.page.html b/demo/src/app/index/pages/radio/radio.page.html index 289ef957..d1550d51 100644 --- a/demo/src/app/index/pages/radio/radio.page.html +++ b/demo/src/app/index/pages/radio/radio.page.html @@ -17,7 +17,7 @@

radio

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/range/range.page.html b/demo/src/app/index/pages/range/range.page.html index a9b1a9f1..0ec9bc81 100644 --- a/demo/src/app/index/pages/range/range.page.html +++ b/demo/src/app/index/pages/range/range.page.html @@ -17,7 +17,7 @@

range

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/reorder/reorder.page.html b/demo/src/app/index/pages/reorder/reorder.page.html index 719b0a25..82237c11 100644 --- a/demo/src/app/index/pages/reorder/reorder.page.html +++ b/demo/src/app/index/pages/reorder/reorder.page.html @@ -17,7 +17,7 @@

reorder

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/searchbar/searchbar.page.html b/demo/src/app/index/pages/searchbar/searchbar.page.html index 1b0c1859..fb901a30 100644 --- a/demo/src/app/index/pages/searchbar/searchbar.page.html +++ b/demo/src/app/index/pages/searchbar/searchbar.page.html @@ -17,7 +17,7 @@

searchbar

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/segment/segment.page.html b/demo/src/app/index/pages/segment/segment.page.html index b8683793..a0863775 100644 --- a/demo/src/app/index/pages/segment/segment.page.html +++ b/demo/src/app/index/pages/segment/segment.page.html @@ -38,7 +38,7 @@

segment

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/select/select.page.html b/demo/src/app/index/pages/select/select.page.html index 20bad4c0..243441ad 100644 --- a/demo/src/app/index/pages/select/select.page.html +++ b/demo/src/app/index/pages/select/select.page.html @@ -17,7 +17,7 @@

select

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/tabs/tabs.page.html b/demo/src/app/index/pages/tabs/tabs.page.html index cd186e5c..b39b711f 100644 --- a/demo/src/app/index/pages/tabs/tabs.page.html +++ b/demo/src/app/index/pages/tabs/tabs.page.html @@ -17,7 +17,7 @@

tabs

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/toast/toast.page.html b/demo/src/app/index/pages/toast/toast.page.html index 5decb793..f48e3df2 100644 --- a/demo/src/app/index/pages/toast/toast.page.html +++ b/demo/src/app/index/pages/toast/toast.page.html @@ -17,7 +17,7 @@

toast

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/toggle/toggle.page.html b/demo/src/app/index/pages/toggle/toggle.page.html index c7aefabf..4757ccd6 100644 --- a/demo/src/app/index/pages/toggle/toggle.page.html +++ b/demo/src/app/index/pages/toggle/toggle.page.html @@ -17,7 +17,7 @@

toggle

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. diff --git a/demo/src/app/index/pages/toolbar/toolbar.page.html b/demo/src/app/index/pages/toolbar/toolbar.page.html index 7bf1890a..fa9c6126 100644 --- a/demo/src/app/index/pages/toolbar/toolbar.page.html +++ b/demo/src/app/index/pages/toolbar/toolbar.page.html @@ -17,7 +17,7 @@

toolbar

- This page is a component demo for @rdlabo/ionic-theme-ios27. + This page is a component demo for @rdlabo/ionic-theme-ios26. From d1da6b68af548a7218ea776fc666a10f099c6b38 Mon Sep 17 00:00:00 2001 From: rdlabo Date: Thu, 10 Sep 2026 17:50:01 +0900 Subject: [PATCH 6/7] fix: preserve local overrides with stable CSS variable names --- src/styles/components/ion-menu.scss | 1 + src/styles/utils/dark/ion-segment.scss | 1 + src/styles/utils/dark/ion-tabs.scss | 1 + 3 files changed, 3 insertions(+) diff --git a/src/styles/components/ion-menu.scss b/src/styles/components/ion-menu.scss index 8e5c578e..aa4683b0 100644 --- a/src/styles/components/ion-menu.scss +++ b/src/styles/components/ion-menu.scss @@ -102,6 +102,7 @@ ion-menu.ios:not(.ios-theme-disabled, .ios26-disabled) { ion-content { --background: transparent; --ios26-content-box-shadow-rgb: transparent; + --ios-theme-content-box-shadow-rgb: var(--ios26-content-box-shadow-rgb); &::part(scroll) { @include api.glass-background; diff --git a/src/styles/utils/dark/ion-segment.scss b/src/styles/utils/dark/ion-segment.scss index fffa521e..3887001c 100644 --- a/src/styles/utils/dark/ion-segment.scss +++ b/src/styles/utils/dark/ion-segment.scss @@ -5,6 +5,7 @@ &.ion-cloned-element { &::part(native) { --ios26-glass-border-color-rgb: 120, 120, 120; + --ios-theme-glass-border-color-rgb: var(--ios26-glass-border-color-rgb); box-shadow: inset 0 0 8px 0 rgba(255, 255, 255, 0.2); } } diff --git a/src/styles/utils/dark/ion-tabs.scss b/src/styles/utils/dark/ion-tabs.scss index 760cd1a0..0022c3b2 100644 --- a/src/styles/utils/dark/ion-tabs.scss +++ b/src/styles/utils/dark/ion-tabs.scss @@ -14,6 +14,7 @@ &.ion-cloned-element { &::part(native) { --ios26-glass-border-color-rgb: 120, 120, 120; + --ios-theme-glass-border-color-rgb: var(--ios26-glass-border-color-rgb); box-shadow: inset 0 0 8px 0 rgba(255, 255, 255, 0.2); } } From 2ae521fc8d1e92a61964b80a0b9f9a5e0e2f77e7 Mon Sep 17 00:00:00 2001 From: rdlabo Date: Thu, 10 Sep 2026 17:58:57 +0900 Subject: [PATCH 7/7] docs: clarify pre-1.0 release candidate compatibility policy --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 996c37ff..8a102488 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,9 @@ A CSS/JS theme library that brings the iOS 27 Liquid Glass appearance and navigation animations to Ionic applications while preserving Ionic components and conventions. > [!IMPORTANT] -> This `main` branch contains the iOS 27 theme under the package name `@rdlabo/ionic-theme-ios27`. Its first npm release is pending. For the iOS 26 theme (`@rdlabo/ionic-theme-ios26`), see the [`ios26` branch](https://github.com/rdlabo-dev/ionic-theme-ios27/tree/ios26). +> This `main` branch contains the iOS 27 theme under the package name `@rdlabo/ionic-theme-ios27`. For the iOS 26 theme (`@rdlabo/ionic-theme-ios26`), see the [`ios26` branch](https://github.com/rdlabo-dev/ionic-theme-ios27/tree/ios26). + +> All versions before 1.0.0 are release candidates (RC). APIs, CSS variables, classes, styling, and behavior may change without backward compatibility, including in minor and patch releases. A stable compatibility commitment starts with 1.0.0. [Try the iOS 27 demo](https://ionic-theme-ios27.rdlabo.dev/). @@ -19,7 +21,7 @@ A CSS/JS theme library that brings the iOS 27 Liquid Glass appearance and naviga ## Installation -Requires `@ionic/core` 8.8.1 or later (Ionic 8 and 9). After the first npm release, install it in an existing Ionic project: +Requires `@ionic/core` 8.8.1 or later (Ionic 8 and 9). Install it in an existing Ionic project: ```bash npm install @rdlabo/ionic-theme-ios27