@rdlabo/ionic-theme-ios26 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (141) hide show
  1. package/.github/workflows/lint.yml +40 -0
  2. package/FEEDBACK.md +100 -7
  3. package/FEEDBACK2.md +45 -0
  4. package/README.md +101 -40
  5. package/USING_ION_ITEM_GROUP.md +7 -9
  6. package/demo/eslint.config.js +2 -0
  7. package/demo/src/app/album/album-page.component.html +3 -3
  8. package/demo/src/app/album/album-page.component.scss +0 -14
  9. package/demo/src/app/album/album-page.component.spec.ts +1 -1
  10. package/demo/src/app/health/health-page.component.html +3 -3
  11. package/demo/src/app/health/health-page.component.spec.ts +2 -2
  12. package/demo/src/app/index/index-page.component.html +9 -1
  13. package/demo/src/app/index/index-page.component.spec.ts +6 -6
  14. package/demo/src/app/index/index-page.component.ts +24 -26
  15. package/demo/src/app/index/index.routes.ts +64 -0
  16. package/demo/src/app/index/pages/action-sheet/action-sheet.page.spec.ts +5 -1
  17. package/demo/src/app/index/pages/action-sheet/action-sheet.page.ts +3 -5
  18. package/demo/src/app/index/pages/alert/alert.page.spec.ts +5 -1
  19. package/demo/src/app/index/pages/alert/alert.page.ts +0 -2
  20. package/demo/src/app/index/pages/breadcrumbs/breadcrumbs.page.html +41 -0
  21. package/demo/src/app/index/pages/breadcrumbs/breadcrumbs.page.scss +0 -0
  22. package/demo/src/app/index/pages/breadcrumbs/breadcrumbs.page.spec.ts +21 -0
  23. package/demo/src/app/index/pages/breadcrumbs/breadcrumbs.page.ts +47 -0
  24. package/demo/src/app/index/pages/button/button.page.html +41 -19
  25. package/demo/src/app/index/pages/button/button.page.scss +3 -0
  26. package/demo/src/app/index/pages/button/button.page.spec.ts +5 -1
  27. package/demo/src/app/index/pages/button/button.page.ts +0 -2
  28. package/demo/src/app/index/pages/card/card.page.html +171 -0
  29. package/demo/src/app/index/pages/card/card.page.scss +0 -0
  30. package/demo/src/app/index/pages/card/card.page.spec.ts +21 -0
  31. package/demo/src/app/index/pages/card/card.page.ts +57 -0
  32. package/demo/src/app/index/pages/checkbox/checkbox.page.spec.ts +5 -1
  33. package/demo/src/app/index/pages/checkbox/checkbox.page.ts +0 -2
  34. package/demo/src/app/index/pages/chip/chip.page.html +72 -0
  35. package/demo/src/app/index/pages/chip/chip.page.scss +0 -0
  36. package/demo/src/app/index/pages/chip/chip.page.spec.ts +21 -0
  37. package/demo/src/app/index/pages/chip/chip.page.ts +47 -0
  38. package/demo/src/app/index/pages/date-and-time-pickers/date-and-time-pickers.page.html +48 -0
  39. package/demo/src/app/index/pages/date-and-time-pickers/date-and-time-pickers.page.scss +0 -0
  40. package/demo/src/app/index/pages/date-and-time-pickers/date-and-time-pickers.page.spec.ts +21 -0
  41. package/demo/src/app/index/pages/date-and-time-pickers/date-and-time-pickers.page.ts +55 -0
  42. package/demo/src/app/index/pages/floating-action-button/floating-action-button.page.html +106 -0
  43. package/demo/src/app/index/pages/floating-action-button/floating-action-button.page.scss +0 -0
  44. package/demo/src/app/index/pages/floating-action-button/floating-action-button.page.spec.ts +21 -0
  45. package/demo/src/app/index/pages/floating-action-button/floating-action-button.page.ts +49 -0
  46. package/demo/src/app/index/pages/menu/menu.page.html +13 -0
  47. package/demo/src/app/index/pages/menu/menu.page.scss +0 -0
  48. package/demo/src/app/index/pages/menu/menu.page.spec.ts +21 -0
  49. package/demo/src/app/index/pages/menu/menu.page.ts +17 -0
  50. package/demo/src/app/index/pages/modal/modal.page.html +37 -0
  51. package/demo/src/app/index/pages/modal/modal.page.scss +0 -0
  52. package/demo/src/app/index/pages/modal/modal.page.spec.ts +21 -0
  53. package/demo/src/app/index/pages/modal/modal.page.ts +77 -0
  54. package/demo/src/app/index/pages/popover/popover.page.html +34 -0
  55. package/demo/src/app/index/pages/popover/popover.page.scss +0 -0
  56. package/demo/src/app/index/pages/popover/popover.page.spec.ts +21 -0
  57. package/demo/src/app/index/pages/popover/popover.page.ts +47 -0
  58. package/demo/src/app/index/pages/progress-indicators/progress-indicators.page.html +28 -0
  59. package/demo/src/app/index/pages/progress-indicators/progress-indicators.page.scss +0 -0
  60. package/demo/src/app/index/pages/progress-indicators/progress-indicators.page.spec.ts +21 -0
  61. package/demo/src/app/index/pages/progress-indicators/progress-indicators.page.ts +47 -0
  62. package/demo/src/app/index/pages/radio/radio.page.html +39 -0
  63. package/demo/src/app/index/pages/radio/radio.page.scss +0 -0
  64. package/demo/src/app/index/pages/radio/radio.page.spec.ts +21 -0
  65. package/demo/src/app/index/pages/radio/radio.page.ts +47 -0
  66. package/demo/src/app/index/pages/range/range.page.html +58 -0
  67. package/demo/src/app/index/pages/range/range.page.scss +0 -0
  68. package/demo/src/app/index/pages/range/range.page.spec.ts +21 -0
  69. package/demo/src/app/index/pages/range/range.page.ts +49 -0
  70. package/demo/src/app/index/pages/searchbar/searchbar.page.html +33 -0
  71. package/demo/src/app/index/pages/searchbar/searchbar.page.scss +0 -0
  72. package/demo/src/app/index/pages/searchbar/searchbar.page.spec.ts +21 -0
  73. package/demo/src/app/index/pages/searchbar/searchbar.page.ts +45 -0
  74. package/demo/src/app/index/pages/segment/segment.page.html +102 -0
  75. package/demo/src/app/index/pages/segment/segment.page.scss +0 -0
  76. package/demo/src/app/index/pages/segment/segment.page.spec.ts +21 -0
  77. package/demo/src/app/index/pages/segment/segment.page.ts +51 -0
  78. package/demo/src/app/index/pages/select/select.page.html +74 -0
  79. package/demo/src/app/index/pages/select/select.page.scss +0 -0
  80. package/demo/src/app/index/pages/select/select.page.spec.ts +21 -0
  81. package/demo/src/app/index/pages/select/select.page.ts +50 -0
  82. package/demo/src/app/index/pages/toast/toast.page.html +32 -0
  83. package/demo/src/app/index/pages/toast/toast.page.scss +0 -0
  84. package/demo/src/app/index/pages/toast/toast.page.spec.ts +21 -0
  85. package/demo/src/app/index/pages/toast/toast.page.ts +66 -0
  86. package/demo/src/app/index/pages/toggle/toggle.page.html +45 -0
  87. package/demo/src/app/index/pages/toggle/toggle.page.scss +0 -0
  88. package/demo/src/app/index/pages/toggle/toggle.page.spec.ts +21 -0
  89. package/demo/src/app/index/pages/toggle/toggle.page.ts +49 -0
  90. package/demo/src/app/settings/settings-page.component.html +4 -7
  91. package/demo/src/app/settings/settings-page.component.spec.ts +2 -2
  92. package/demo/src/app/tabs/tabs.page.html +4 -4
  93. package/demo/src/app/tabs/tabs.page.spec.ts +1 -1
  94. package/demo/src/app/tabs/tabs.routes.ts +0 -1
  95. package/demo/src/global.scss +28 -10
  96. package/demo/src/index.html +1 -1
  97. package/demo/src/test.ts +7 -0
  98. package/demo/src/theme/variables.scss +18 -0
  99. package/demo/util/mocks/angular/angular-delegate.ts +18 -0
  100. package/demo/util/mocks/angular/ion-router-outlet.ts +39 -0
  101. package/demo/util/mocks/angular/modal-controller.ts +7 -0
  102. package/demo/util/mocks/angular/nav-controller.ts +22 -0
  103. package/demo/util/mocks/angular/popover-controller.ts +7 -0
  104. package/demo/util/mocks/util/base.mock.ts +13 -0
  105. package/demo/util/mocks/util/overlay.ts +13 -0
  106. package/demo/util/test.config.ts +54 -0
  107. package/package.json +3 -2
  108. package/src/components/ion-action-sheet.scss +23 -4
  109. package/src/components/ion-alert.scss +17 -2
  110. package/src/components/ion-breadcrumbs.scss +24 -0
  111. package/src/components/ion-button.scss +105 -62
  112. package/src/components/ion-card.scss +5 -1
  113. package/src/components/ion-chip.scss +10 -0
  114. package/src/components/ion-content.scss +13 -0
  115. package/src/components/ion-datetime.scss +9 -0
  116. package/src/components/ion-fab.scss +10 -4
  117. package/src/components/ion-list.scss +7 -2
  118. package/src/components/ion-loading.scss +9 -0
  119. package/src/components/ion-modal.scss +26 -1
  120. package/src/components/ion-picker.scss +4 -0
  121. package/src/components/ion-popover.scss +8 -16
  122. package/src/components/ion-range.scss +21 -0
  123. package/src/components/ion-searchbar.scss +2 -2
  124. package/src/components/ion-segment.scss +40 -5
  125. package/src/components/ion-tabs.scss +2 -2
  126. package/src/components/ion-toast.scss +11 -2
  127. package/src/components/ion-toggle.scss +37 -28
  128. package/src/components/ion-toolbar.scss +27 -0
  129. package/src/{utils/default-variables.scss → default-variables.scss} +3 -1
  130. package/src/ionic-theme-ios26-dark-always.scss +6 -0
  131. package/src/{ionic-theme-dark-class.scss → ionic-theme-ios26-dark-class.scss} +1 -1
  132. package/src/{ionic-theme-dark-system.scss → ionic-theme-ios26-dark-system.scss} +1 -1
  133. package/src/ionic-theme-ios26.scss +8 -17
  134. package/src/utils/api.scss +9 -8
  135. package/src/utils/dark/ion-button.scss +45 -0
  136. package/src/{components-dark → utils}/theme-dark.scss +5 -3
  137. package/src/utils/theme-list-inset.scss +23 -19
  138. package/src/utils/translucent.scss +59 -58
  139. package/build-sass.js +0 -25
  140. package/demo/src/theme/theme-ios26.scss +0 -25
  141. package/src/components-dark/ion-button.scss +0 -28
@@ -0,0 +1,40 @@
1
+ name: Lint
2
+ on:
3
+ push:
4
+ branches:
5
+ - '**'
6
+ pull_request:
7
+ types: [opened]
8
+ jobs:
9
+ prettier:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v4
13
+ - uses: actions/setup-node@v4
14
+ with:
15
+ node-version: 22
16
+ - uses: actions/cache@v4
17
+ with:
18
+ path: node_modules
19
+ key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
20
+ restore-keys: |
21
+ ${{ runner.os }}-node-
22
+ - run: npm install
23
+ - run: npm run lint
24
+ lint:
25
+ runs-on: ubuntu-latest
26
+ steps:
27
+ - uses: actions/checkout@v4
28
+ - uses: actions/setup-node@v4
29
+ with:
30
+ node-version: 22
31
+ - uses: actions/cache@v4
32
+ with:
33
+ path: node_modules
34
+ key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
35
+ restore-keys: |
36
+ ${{ runner.os }}-node-
37
+ - run: npm install
38
+ working-directory: './demo'
39
+ - run: npm run lint
40
+ working-directory: './demo'
package/FEEDBACK.md CHANGED
@@ -1,18 +1,58 @@
1
- ## feat(): ion-config new property for disable ion-back-button Animation
1
+ # Feature Requests for Ionic Framework
2
2
 
3
- 遷移前画面で `collapse` を使っており、遷移後画面で `ion-buttons ion-back-button` を指定している場合、iOS18以前のアニメーション処理が行われます。これは、iOS26以降では不要なので、無効化できるプロパティが必要です。
3
+ ## docs(): Naming conventions for Ionic theme classes
4
+
5
+ After the Ionic Modular release, I expect many themes to be distributed through community activities. Therefore, I would like to establish naming conventions for theme application classes. I would appreciate the Ionic team's opinion on this matter.
6
+
7
+ - Classes for manually applying themes
8
+ - .theme-[theme-name] (ex: .theme-ios26)
9
+ - .theme-[theme-name]-enabled (ex: .theme-ios26-enabled)
10
+ - .[theme-name]-enabled (ex: .ios26-enabled)
11
+ - .ion-[theme-name]-enabled (ex: .ion-ios26-enabled)
12
+ - Classes for manually removing themes
13
+ - .theme-no-[theme-name] (ex: .theme-no-ios26)
14
+ - .theme-[theme-name]-disabled (ex: .theme-ios26-disabled)
15
+ - .[theme-name]-disabled (ex: .ios26-disabled)
16
+ - .ion-[theme-name]-disabled (ex: .ion-ios26-disabled)
17
+
18
+
19
+ ## feat(): ion-config new property for `collapse`
20
+
21
+ Currently, `collapse` behavior is automatically enabled in iOS mode, but this should be configurable through `ion-config` for better control.
22
+
23
+ ex:
24
+ ```typescript
25
+ export interface IonicConfig {
26
+ ...,
27
+ collapseLargeTitle: {
28
+ ios: boolean;
29
+ md: boolean;
30
+ ionic: boolean;
31
+ },
32
+ collapseBackButtonAnimation: {
33
+ ios: boolean;
34
+ md: boolean;
35
+ ionic: boolean;
36
+ },
37
+ }
38
+ ```
39
+
40
+ ### should disable ion-back-button Animation
41
+
42
+ When using `collapse` on the previous screen and specifying `ion-buttons ion-back-button` on the next screen, iOS 18 and earlier animation processing occurs. Since this is unnecessary for iOS 26+, a property to disable this would be beneficial.
4
43
 
5
44
  https://github.com/ionic-team/ionic-framework/blob/3b80473f2fd5ad4da5a9f5d66f783a69909c8965/core/src/utils/transition/ios.transition.ts#L333C31-L337
6
45
  - enteringBackButtonTextAnimation
7
46
  - enteringBackButtonIconAnimation
8
47
  - enteringBackButtonAnimation
9
48
 
10
- 現在、 `ion-buttons > ion-back-button` をセレクタする関係上、 `ion-back-button` `ion-buttons` の中にいれない対応をとっています。。
49
+ Currently, I work around this by not placing `ion-back-button` inside `ion-buttons` due to the selector relationship `ion-buttons > ion-back-button`.
50
+
11
51
 
12
- # feat(): ion-content[fullscreen=true] will have .content-fullscreen class
52
+ ## feat(): ion-content[fullscreen=true] will have .content-fullscreen class
13
53
 
14
- iOS26の上下セーフエリアのぼかしを入れるため、ion-contentfullscreen設定されているかのclassが必要です。
15
- 以下のようなセレクターの指定を行いたいです。
54
+ For implementing iOS 26's blurred safe area effects, a class indicating whether `ion-content` has fullscreen configuration is needed.
55
+ I would like to use selectors like the following:
16
56
 
17
57
  ```css
18
58
  .ion-page:has(ion-header.header-translucent) ion-content.content-fullscreen {
@@ -22,4 +62,57 @@ iOS26の上下セーフエリアのぼかしを入れるため、ion-contentがf
22
62
  }
23
63
  ```
24
64
 
25
- 現在、 `translucent` な要素を使っている場合はfullscreenを指定している前提で実装していますが、これは確実ではありません。
65
+ Currently, I assume fullscreen is specified when using `translucent` elements, but this is not guaranteed.
66
+
67
+
68
+ ## feat(): add .range-knob-min and .range-knob-max directly to ion-range
69
+
70
+ Currently, `.range-knob-min` and `.range-knob-max` are applied to DOM elements inside ShadowDOM, but since these represent the state of `ion-range` itself, they should be applied directly to the component.
71
+ This would provide more flexibility for knob styling.
72
+
73
+ Current:
74
+ ```html
75
+ <ion-range>
76
+ #shadow-root
77
+ ...
78
+ <div class="range-knob-handle ... range-knob-min">...</div>
79
+ </ion-range>
80
+ ```
81
+
82
+ After:
83
+ ```html
84
+ <ion-range class="range-knob-min">
85
+ #shadow-root
86
+ ...
87
+ <div class="range-knob-handle ... range-knob-min">...</div>
88
+ </ion-range>
89
+ ```
90
+
91
+
92
+ ## feat(): add native shadow-part for design
93
+
94
+ ### native-inner(or item-inner) part to ion-item
95
+ The styling for `ion-item[lines=inset]` is applied to `.item-inner`, which cannot be styled directly. This limitation means that for iOS 26 styling, I can only modify the border-bottom style through `::part(native)` with padding-right, preventing me from utilizing the full right side of `ion-item`. Adding `::part(native-inner)` would increase styling flexibility.
96
+
97
+ ```diff
98
+ <ion-item>
99
+ <button type="button" class="item-native" part="native">
100
+ - <div class="item-inner">
101
+ + <div class="item-inner" part="native-inner">
102
+ ...
103
+ </div>
104
+ </button>
105
+ </ion-item>
106
+ ```
107
+
108
+ ### native part to ion-toast
109
+ The default styling for `ion-toast` is applied to `div.toast-wrapper`, and CSS Custom Properties overrides work similarly. However, there's no way to directly override `div.toast-wrapper`. Currently, I disable this styling using CSS Custom Properties and then apply new styles to `::part(container)`. This is not ideal for styling, so adding `::part(native)` to allow direct override of `div.toast-wrapper` would be preferable.
110
+
111
+ ```diff
112
+ <ion-toast>
113
+ - <div class="toast-wrapper">...</div>
114
+ + <div class="toast-wrapper" part="native">...</div>
115
+ </ion-toast>
116
+ ```
117
+
118
+
package/FEEDBACK2.md ADDED
@@ -0,0 +1,45 @@
1
+ # Feature Requests for Ionic Framework
2
+ ## feat(): native container add at ion-segment
3
+
4
+ 現在、`ion-segment` はShadowDOMであるにもかかわらず、container DOMをもっていない。このため、 `ion-segment` にスタイルをあてるためには、`ion-segment` 自身にあてるしか方法がない。このため、子孫要素である `ion-segment-button` のタップエフェクトを、 `ion-segment` の外に表示することができない。
5
+
6
+ Current:
7
+
8
+ ```html
9
+ <ion-segment>
10
+ ::shadow-root
11
+ // Put child element
12
+ <ion-segment-button></ion-segment-button>
13
+ <ion-segment-button></ion-segment-button>
14
+ </ion-segment>
15
+ ```
16
+
17
+ After:
18
+
19
+ ```html
20
+ <ion-segment>
21
+ ::shadow-root
22
+ <div class="segment-container" part="container">
23
+ // Put child element
24
+ <ion-segment-button></ion-segment-button>
25
+ <ion-segment-button></ion-segment-button>
26
+ </div>
27
+ </ion-segment>
28
+ ```
29
+
30
+ このことで、以下のようにスタイリングしたい。
31
+
32
+ ```scss
33
+ ion-segment {
34
+ &::part(container) {
35
+ overflow: visible;
36
+ margin: 12px; // Enable Effect Area
37
+ background: var(255, 255, 255, 0.7);
38
+ }
39
+ ion-segment-button {
40
+ &.segment-button-checked {
41
+ transform: scale(1.1); // Enable overflow effect
42
+ }
43
+ }
44
+ }
45
+ ```
package/README.md CHANGED
@@ -27,41 +27,31 @@ Sponsoring means you directly contribute to new features, improvements, and main
27
27
  npm install @rdlabo/ionic-theme-ios26
28
28
  ```
29
29
 
30
- And import the theme in your project's main CSS file (e.g., `src/styles.scss`) and set the `--ios26-floating-safe-area-bottom` variable:
30
+ And import the theme in your project's main CSS file (e.g., `src/styles.scss`).
31
31
 
32
- ```scss
32
+ ```css
33
+ @import '@rdlabo/ionic-theme-ios26/dist/css/default-variables.css';
33
34
  @import '@rdlabo/ionic-theme-ios26/dist/css/ionic-theme-ios26.min.css';
34
35
 
35
- :root {
36
- /*
37
- * This is default value. If you should change value, update this variable.
38
- * ex) Using admob banner ad.
39
- * --ios26-floating-safe-area-bottom: calc(max(10px, var(--ion-safe-area-bottom, 0px)) + var(--admob-safe-area, 0px));
40
- */
41
- --ios26-floating-safe-area-bottom: max(10px, var(--ion-safe-area-bottom, 0px));
42
- }
36
+ /*
37
+ * Support Dark Mode
38
+ * We support Ionic Dark Mode. More information is here: https://ionicframework.com/docs/theming/dark-mode
39
+ * use Always: @import '@rdlabo/ionic-theme-ios26/dist/css/ionic-theme-dark-always.min.css'
40
+ * use System: @import '@rdlabo/ionic-theme-ios26/dist/css/ionic-theme-dark-system.min.css'
41
+ * use CSS Class: @import '@rdlabo/ionic-theme-ios26/dist/css/ionic-theme-dark-class.min.css'
42
+ */
43
43
  ```
44
44
 
45
45
  ## Important Notes
46
46
 
47
- ### Support Dark Mode
48
-
49
- We support Ionic Dark Mode. More information is here: https://ionicframework.com/docs/theming/dark-mode
50
-
51
- | Mode | Code |
52
- |-----------|------------------------------------------------------------------------------|
53
- | Always | Overwrite library colors on the :root selector. |
54
- | System | @import '@rdlabo/ionic-theme-ios26/dist/css/ionic-theme-dark-system.min.css' |
55
- | CSS Class | @import '@rdlabo/ionic-theme-ios26/dist/css/ionic-theme-dark-class.min.css' |
47
+ ### `ion-back-button` must be used without `ion-buttons`
56
48
 
57
- ### `ion-back-button` は `ion-buttons` に入れないで使う必要があります
49
+ When the following conditions are met, the Ionic Framework programmatically generates and animates the `ion-back-button`:
58
50
 
59
- 以下の条件を満たす時、Ionic Frameworkは `ion-back-button` をプログラムで生成して、アニメーションで表示します。
51
+ - The previous page uses `ion-header[collapse='condense']`
52
+ - The navigated page has `ion-buttons ion-back-button`
60
53
 
61
- - 遷移前のページに `ion-header[collapse='condense']` を使用している
62
- - 遷移後のページに、 `ion-buttons ion-back-button` がある
63
-
64
- これはiOS26のUIではなく、このプログラムを避けるために以下の実装を行う必要があります。
54
+ This is not the iOS26 UI behavior. To avoid this programmatic behavior, you need to implement it as follows:
65
55
 
66
56
  ```diff
67
57
  <ion-header>
@@ -74,7 +64,19 @@ We support Ionic Dark Mode. More information is here: https://ionicframework.com
74
64
 
75
65
  ### Using `ion-item-group`
76
66
 
77
- Under specific conditions, you need to use `ion-item-group`. For details, please refer to [USING_ION_ITEM_GROUP.md](./USING_ION_ITEM_GROUP.md).
67
+ Under specific conditions, you need to use `ion-item-group`.
68
+
69
+ ```diff
70
+ <ion-list inset=true>
71
+ <ion-list-header><ion-label>Label</ion-label></ion-list-header>
72
+ + <ion-item-group>
73
+ <ion-item>...</ion-item>
74
+ <ion-item>...</ion-item>
75
+ + </ion-item-group>
76
+ </ion-list>
77
+ ```
78
+
79
+ For details, please refer to [USING_ION_ITEM_GROUP.md](./USING_ION_ITEM_GROUP.md).
78
80
 
79
81
  ### You can also use the liquid glass mixin
80
82
 
@@ -88,23 +90,82 @@ ion-textarea label.textarea-wrapper {
88
90
  }
89
91
  ```
90
92
 
91
- ## CSS Utility Classes
93
+ ## Selective Theme Application
92
94
 
93
- ### .ios26-liquid-glass
95
+ You may want to apply the iOS26 theme to your Ionic project but find it difficult to apply it to all components. We provide two approaches to selectively control theme application.
94
96
 
95
- Apply this class to components where you want to use the iOS26 design that is not automatically applied. Supported selectors are as follows:
97
+ You can use `1. Import Components Individually` or `2. Using the .ios26-disabled Class`
96
98
 
97
- - `ion-button`
98
- - `ion-buttons.ios26-liquid-glass ion-button`
99
- - `ion-button.ios26-liquid-glass`
99
+ ### 1. Import Components Individually
100
100
 
101
- ### .ios26-no-liquid-glass
101
+ **Recommended for**: When you want to apply the iOS26 theme only to specific components, or when you want to minimize bundle size.
102
+
103
+ While `@import '@rdlabo/ionic-theme-ios26/dist/css/ionic-theme-ios26.min.css'` applies styling to all components at once, you can also import them individually.
104
+
105
+ ```css
106
+ @import '@rdlabo/ionic-theme-ios26/dist/css/utils/translucent';
107
+ @import '@rdlabo/ionic-theme-ios26/dist/css/components/ion-action-sheet';
108
+ @import '@rdlabo/ionic-theme-ios26/dist/css/components/ion-alert';
109
+ @import '@rdlabo/ionic-theme-ios26/dist/css/components/ion-breadcrumbs';
110
+ @import '@rdlabo/ionic-theme-ios26/dist/css/components/ion-button';
111
+ ...
112
+ ```
113
+
114
+ #### Individual Import for Dark Mode Components
115
+
116
+ If you're using dark mode, you need to use SCSS because the selectors differ between `Always`, `System`, and `Class` modes, which cannot be handled with CSS files alone.
117
+
118
+ > **Note**: Currently, only `ion-button` has separate dark mode styling applied.
119
+
120
+ Always (Always Dark Mode):
121
+ ```scss
122
+ @use '@rdlabo/ionic-theme-ios26/src/utils/theme-dark';
123
+
124
+ :root {
125
+ @include theme-dark.default-variables;
126
+ }
127
+ @include theme-dark.ion-button;
128
+ ```
129
+
130
+ System (Follow System Settings):
131
+ ```scss
132
+ @use '@rdlabo/ionic-theme-ios26/src/utils/theme-dark';
133
+
134
+ @media (prefers-color-scheme: dark) {
135
+ :root {
136
+ @include theme-dark.default-variables;
137
+ }
138
+ @include theme-dark.ion-button;
139
+ }
140
+ ```
141
+
142
+ Class (Toggle with CSS Class):
143
+ ```scss
144
+ @use '@rdlabo/ionic-theme-ios26/src/utils/theme-dark';
145
+
146
+ .ion-palette-dark {
147
+ @include theme-dark.default-variables;
148
+ @include theme-dark.ion-button;
149
+ }
150
+ ```
151
+
152
+
153
+ ### 2. Using the `.ios26-disabled` Class
154
+
155
+ **Recommended for**: When you want to apply the iOS26 theme to all components in general, but use standard Ionic styling in specific places.
156
+
157
+ After importing all components, you can disable the iOS26 theme for specific component instances by adding the `.ios26-disabled` class.
158
+
159
+ ```html
160
+ <!-- iOS26 theme applied -->
161
+ <ion-button>iOS26 Design</ion-button>
162
+
163
+ <!-- Standard Ionic styling -->
164
+ <ion-button class="ios26-disabled">Standard Ionic Design</ion-button>
165
+ ```
102
166
 
103
- Many components automatically have the iOS26 design applied, but apply this class when you don't want it. Supported selectors are as follows:
167
+ This method is useful in the following scenarios:
104
168
 
105
- - `ion-button`
106
- - `ion-header > ion-toolbar > ion-buttons.ios26-no-liquid-glass > ion-button`
107
- - `ion-header > ion-toolbar > ion-buttons.ios26-no-liquid-glass > ion-back-button`
108
- - `ion-header > ion-toolbar > ion-buttons > ion-button.ios26-no-liquid-glass`
109
- - `ion-header > ion-toolbar > ion-buttons > ion-back-button.ios26-no-liquid-glass`
110
- - `ion-popover.ios26-no-liquid-glass`
169
+ - When you want to use standard styling only within specific modals or popovers
170
+ - When you want to perform a gradual migration (add `.ios26-disabled` to some screens and remove it later)
171
+ - When you want to conduct A/B testing for designs
@@ -13,15 +13,13 @@ Only when these conditions apply, you need to wrap your list items with `ion-ite
13
13
  ## Implementation Example
14
14
 
15
15
  ```diff
16
- <ion-content color="light">
17
- <ion-list inset=true>
18
- <ion-list-header><ion-label>Label</ion-label></ion-list-header>
19
- + <ion-item-group>
20
- <ion-item>...</ion-item>
21
- <ion-item>...</ion-item>
22
- + </ion-item-group>
23
- </ion-list>
24
- </ion-content>
16
+ <ion-list inset=true>
17
+ <ion-list-header><ion-label>Label</ion-label></ion-list-header>
18
+ + <ion-item-group>
19
+ <ion-item>...</ion-item>
20
+ <ion-item>...</ion-item>
21
+ + </ion-item-group>
22
+ </ion-list>
25
23
  ```
26
24
 
27
25
  ## Why is this change necessary?
@@ -22,6 +22,8 @@ module.exports = tseslint.config(
22
22
  "@typescript-eslint/no-unused-vars": "off",
23
23
  "@angular-eslint/directive-selector": "off",
24
24
  "@angular-eslint/component-selector": "off",
25
+ "@angular-eslint/no-empty-lifecycle-method": "off",
26
+ "@typescript-eslint/no-empty-function": "off",
25
27
  '@rdlabo/rules/deny-constructor-di': 'error',
26
28
  '@rdlabo/rules/deny-import-from-ionic-module': 'error',
27
29
  '@rdlabo/rules/implements-ionic-lifecycle': 'error',
@@ -1,8 +1,8 @@
1
- <ion-header [translucent]="true" class="ion-palette-dark">
1
+ <ion-header [translucent]="true">
2
2
  <ion-toolbar>
3
3
  <ion-title size="large" style="margin-top: 8px">Library</ion-title>
4
- <ion-buttons slot="end">
5
- <ion-button fill="default" href="https://github.com/rdlabo-team/ionic-theme-ios26"
4
+ <ion-buttons class="ios26-disabled" slot="end" style="margin-top: 6px">
5
+ <ion-button fill="default" href="https://github.com/rdlabo-team/ionic-theme-ios26" style="margin-right: 8px"
6
6
  ><ion-icon name="logo-github" slot="icon-only"></ion-icon
7
7
  ></ion-button>
8
8
  <ion-button fill="default">Select</ion-button>
@@ -1,21 +1,7 @@
1
- :host {
2
- --ios26-color-background-rgb: var(--ion-color-dark-rgb);
3
- }
4
-
5
1
  ion-header {
6
2
  position: absolute;
7
3
  top: 0;
8
4
  left: 0;
9
- ion-title,
10
- ion-button::part(native) {
11
- color: var(--ion-text-color, #fff);
12
- }
13
- &.header-translucent::after {
14
- // Overwrite default settings
15
- box-shadow:
16
- inset 0 0 0 0 rgba(0, 0, 0, 0),
17
- inset 0 calc(66px + var(--ion-safe-area-top)) 20px -20px rgba(0, 0, 0, 0.4);
18
- }
19
5
  }
20
6
 
21
7
  ion-content {
@@ -1,6 +1,6 @@
1
1
  import { ComponentFixture, TestBed } from '@angular/core/testing';
2
2
  import { AlbumPage } from './album-page.component';
3
- import { testConfig } from '../../../../util/test.config';
3
+ import { testConfig } from '../../../util/test.config';
4
4
 
5
5
  describe('ScrollHeaderPage', () => {
6
6
  let component: AlbumPage;
@@ -2,15 +2,15 @@
2
2
  <ion-toolbar>
3
3
  <ion-title>Health</ion-title>
4
4
  <ion-buttons slot="end">
5
- <ion-button fill="default" color="dark" href="https://github.com/rdlabo-team/ionic-theme-ios26"
5
+ <ion-button fill="default" href="https://github.com/rdlabo-team/ionic-theme-ios26"
6
6
  ><ion-icon name="logo-github" slot="icon-only"></ion-icon
7
7
  ></ion-button>
8
8
  </ion-buttons>
9
9
  </ion-toolbar>
10
10
  </ion-header>
11
- <ion-content [fullscreen]="true">
11
+ <ion-content [fullscreen]="true" color="light">
12
12
  <ion-header collapse="condense">
13
- <ion-toolbar>
13
+ <ion-toolbar color="light">
14
14
  <ion-title size="large">Health(WIP)</ion-title>
15
15
  </ion-toolbar>
16
16
  </ion-header>
@@ -1,8 +1,8 @@
1
1
  import { ComponentFixture, TestBed } from '@angular/core/testing';
2
2
  import { HealthPage } from './health-page.component';
3
- import { testConfig } from '../../../../util/test.config';
3
+ import { testConfig } from '../../../util/test.config';
4
4
 
5
- describe('VirtualScrollHeaderPage', () => {
5
+ describe('HealthPage', () => {
6
6
  let component: HealthPage;
7
7
  let fixture: ComponentFixture<HealthPage>;
8
8
 
@@ -2,9 +2,10 @@
2
2
  <ion-toolbar>
3
3
  <ion-title>Index</ion-title>
4
4
  <ion-buttons slot="end">
5
- <ion-button color="dark" fill="default" href="https://github.com/rdlabo-team/ionic-theme-ios26"
5
+ <ion-button href="https://github.com/rdlabo-team/ionic-theme-ios26"
6
6
  ><ion-icon name="logo-github" slot="icon-only"></ion-icon
7
7
  ></ion-button>
8
+ <ion-button href="https://ionicframework.com/"><ion-icon name="logo-ionic" slot="icon-only"></ion-icon></ion-button>
8
9
  </ion-buttons>
9
10
  </ion-toolbar>
10
11
  </ion-header>
@@ -14,6 +15,13 @@
14
15
  <ion-title size="large">Index</ion-title>
15
16
  </ion-toolbar>
16
17
  </ion-header>
18
+ <ion-list [inset]="true">
19
+ <ion-list-header><ion-label>Settings</ion-label></ion-list-header>
20
+ <ion-item-group>
21
+ <ion-item><ion-toggle (ionChange)="changeColorMode($event)">Dark Mode</ion-toggle></ion-item>
22
+ </ion-item-group>
23
+ </ion-list>
24
+
17
25
  <ion-list [inset]="true">
18
26
  <ion-list-header><ion-label>Enable Demo</ion-label></ion-list-header>
19
27
  <ion-item-group>
@@ -1,16 +1,16 @@
1
1
  import { ComponentFixture, TestBed } from '@angular/core/testing';
2
- import { DemoPhotoEditorPage } from './index-page.component';
3
- import { testConfig } from '../../../../util/test.config';
2
+ import { IndexPageComponent } from './index-page.component';
3
+ import { testConfig } from '../../../util/test.config';
4
4
 
5
- describe('PhotoEditorPage', () => {
6
- let component: DemoPhotoEditorPage;
7
- let fixture: ComponentFixture<DemoPhotoEditorPage>;
5
+ describe('IndexPageComponent', () => {
6
+ let component: IndexPageComponent;
7
+ let fixture: ComponentFixture<IndexPageComponent>;
8
8
 
9
9
  beforeEach(async () => {
10
10
  await TestBed.configureTestingModule({
11
11
  providers: testConfig.providers,
12
12
  }).compileComponents();
13
- fixture = TestBed.createComponent(DemoPhotoEditorPage);
13
+ fixture = TestBed.createComponent(IndexPageComponent);
14
14
  component = fixture.componentInstance;
15
15
  fixture.detectChanges();
16
16
  });
@@ -1,4 +1,4 @@
1
- import { ChangeDetectionStrategy, Component, computed, inject, signal } from '@angular/core';
1
+ import { ChangeDetectionStrategy, Component, computed, DOCUMENT, inject, signal } from '@angular/core';
2
2
  import { CommonModule } from '@angular/common';
3
3
  import { FormsModule } from '@angular/forms';
4
4
  import {
@@ -15,7 +15,9 @@ import {
15
15
  IonNote,
16
16
  IonText,
17
17
  IonTitle,
18
+ IonToggle,
18
19
  IonToolbar,
20
+ ToggleCustomEvent,
19
21
  } from '@ionic/angular/standalone';
20
22
  import { ActivatedRoute, Router } from '@angular/router';
21
23
 
@@ -45,6 +47,7 @@ interface IComponent {
45
47
  IonItemGroup,
46
48
  IonText,
47
49
  IonNote,
50
+ IonToggle,
48
51
  ],
49
52
  changeDetection: ChangeDetectionStrategy.OnPush,
50
53
  })
@@ -53,45 +56,36 @@ export class IndexPageComponent {
53
56
  { name: 'accordion', enable: false },
54
57
  { name: 'action-sheet', enable: true },
55
58
  { name: 'alert', enable: true },
56
- { name: 'badge', enable: false },
57
- { name: 'breadcrumbs', enable: false },
59
+ { name: 'breadcrumbs', enable: true },
58
60
  { name: 'button', enable: true },
59
- { name: 'card', enable: false },
61
+ { name: 'card', enable: true },
60
62
  { name: 'checkbox', enable: true },
61
- { name: 'chip', enable: false },
62
- { name: 'content', enable: false },
63
- { name: 'date-and-time-pickers', enable: false },
64
- { name: 'floating-action-button', enable: false },
65
- { name: 'grid', enable: false },
66
- { name: 'icons', enable: false },
67
- { name: 'infinite-scroll', enable: false },
63
+ { name: 'chip', enable: true },
64
+ { name: 'date-and-time-pickers', enable: true },
65
+ { name: 'floating-action-button', enable: true },
68
66
  { name: 'inputs', enable: false },
69
67
  { name: 'item-list', enable: false },
70
- { name: 'media', enable: false },
71
68
  { name: 'menu', enable: false },
72
- { name: 'modal', enable: false },
73
- { name: 'navigate', enable: false },
74
- { name: 'popover', enable: false },
75
- { name: 'progress-indicators', enable: false },
76
- { name: 'radio', enable: false },
77
- { name: 'range', enable: false },
78
- { name: 'refresher', enable: false },
69
+ { name: 'modal', enable: true },
70
+ { name: 'popover', enable: true },
71
+ { name: 'progress-indicators', enable: true },
72
+ { name: 'radio', enable: true },
73
+ { name: 'range', enable: true },
79
74
  { name: 'reorder', enable: false },
80
- { name: 'routing', enable: false },
81
- { name: 'searchbar', enable: false },
82
- { name: 'segment', enable: false },
83
- { name: 'select', enable: false },
75
+ { name: 'searchbar', enable: true },
76
+ { name: 'segment', enable: true },
77
+ { name: 'select', enable: true },
84
78
  { name: 'tabs', enable: false },
85
- { name: 'toast', enable: false },
86
- { name: 'toggle', enable: false },
79
+ { name: 'toast', enable: true },
80
+ { name: 'toggle', enable: true },
87
81
  { name: 'toolbar', enable: false },
88
- { name: 'typography', enable: false },
89
82
  ]);
90
83
  readonly enableComponents = computed(() => this.components().filter((c) => c.enable));
91
84
  readonly disableComponents = computed(() => this.components().filter((c) => !c.enable));
92
85
 
93
86
  readonly #router = inject(Router);
94
87
  readonly #route = inject(ActivatedRoute);
88
+ readonly #document = inject(DOCUMENT);
95
89
 
96
90
  async navigateComponent(item: IComponent) {
97
91
  if (!item.enable) {
@@ -99,4 +93,8 @@ export class IndexPageComponent {
99
93
  }
100
94
  await this.#router.navigate([item.name], { relativeTo: this.#route });
101
95
  }
96
+
97
+ changeColorMode(event: ToggleCustomEvent) {
98
+ this.#document.documentElement.classList.toggle('ion-palette-dark', event.detail.checked);
99
+ }
102
100
  }