@rdlabo/ionic-theme-ios27 0.1.0-0

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 (158) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +241 -0
  3. package/dist/css/components/ion-action-sheet.css +1 -0
  4. package/dist/css/components/ion-alert.css +1 -0
  5. package/dist/css/components/ion-button.css +1 -0
  6. package/dist/css/components/ion-card.css +1 -0
  7. package/dist/css/components/ion-content.css +1 -0
  8. package/dist/css/components/ion-datetime.css +1 -0
  9. package/dist/css/components/ion-fab.css +1 -0
  10. package/dist/css/components/ion-inputs.css +1 -0
  11. package/dist/css/components/ion-list.css +1 -0
  12. package/dist/css/components/ion-loading.css +1 -0
  13. package/dist/css/components/ion-menu.css +1 -0
  14. package/dist/css/components/ion-modal.css +1 -0
  15. package/dist/css/components/ion-picker.css +1 -0
  16. package/dist/css/components/ion-popover.css +1 -0
  17. package/dist/css/components/ion-range.css +1 -0
  18. package/dist/css/components/ion-searchbar.css +1 -0
  19. package/dist/css/components/ion-segment.css +1 -0
  20. package/dist/css/components/ion-tabs.css +1 -0
  21. package/dist/css/components/ion-toast.css +1 -0
  22. package/dist/css/components/ion-toggle.css +1 -0
  23. package/dist/css/components/ion-toolbar.css +1 -0
  24. package/dist/css/default-variables.css +1 -0
  25. package/dist/css/ionic-theme-ios26-dark-always.css +1 -0
  26. package/dist/css/ionic-theme-ios26-dark-class.css +1 -0
  27. package/dist/css/ionic-theme-ios26-dark-system.css +1 -0
  28. package/dist/css/ionic-theme-ios26.css +1 -0
  29. package/dist/css/md-ion-list-inset.css +1 -0
  30. package/dist/css/md-remove-ios-class-effect.css +1 -0
  31. package/dist/css/utils/api.css +1 -0
  32. package/dist/css/utils/dark/ion-button.css +1 -0
  33. package/dist/css/utils/dark/ion-fab.css +1 -0
  34. package/dist/css/utils/dark/ion-segment.css +1 -0
  35. package/dist/css/utils/dark/ion-tabs.css +1 -0
  36. package/dist/css/utils/searchable.css +1 -0
  37. package/dist/css/utils/structured-list.css +1 -0
  38. package/dist/css/utils/theme-dark.css +1 -0
  39. package/dist/css/utils/translucent.css +1 -0
  40. package/dist/docs.json +234 -0
  41. package/dist/focus-controller/index.d.ts +6 -0
  42. package/dist/focus-controller/index.d.ts.map +1 -0
  43. package/dist/focus-controller/index.js +62 -0
  44. package/dist/focus-controller /index.d.ts +6 -0
  45. package/dist/focus-controller /index.d.ts.map +1 -0
  46. package/dist/focus-controller /index.js +62 -0
  47. package/dist/index.d.ts +9 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +30 -0
  50. package/dist/popover/animations/ios.enter.d.ts +4 -0
  51. package/dist/popover/animations/ios.enter.d.ts.map +1 -0
  52. package/dist/popover/animations/ios.enter.js +97 -0
  53. package/dist/popover/animations/ios.leave.d.ts +3 -0
  54. package/dist/popover/animations/ios.leave.d.ts.map +1 -0
  55. package/dist/popover/animations/ios.leave.js +60 -0
  56. package/dist/popover/popover-interface.d.ts +38 -0
  57. package/dist/popover/popover-interface.d.ts.map +1 -0
  58. package/dist/popover/popover-interface.js +1 -0
  59. package/dist/popover/utils.d.ts +37 -0
  60. package/dist/popover/utils.d.ts.map +1 -0
  61. package/dist/popover/utils.js +377 -0
  62. package/dist/sheets-of-glass/animations.d.ts +8 -0
  63. package/dist/sheets-of-glass/animations.d.ts.map +1 -0
  64. package/dist/sheets-of-glass/animations.js +97 -0
  65. package/dist/sheets-of-glass/index.d.ts +3 -0
  66. package/dist/sheets-of-glass/index.d.ts.map +1 -0
  67. package/dist/sheets-of-glass/index.js +174 -0
  68. package/dist/sheets-of-glass/interfaces.d.ts +16 -0
  69. package/dist/sheets-of-glass/interfaces.d.ts.map +1 -0
  70. package/dist/sheets-of-glass/interfaces.js +1 -0
  71. package/dist/tab-bar-searchable/animations/enter.d.ts +8 -0
  72. package/dist/tab-bar-searchable/animations/enter.d.ts.map +1 -0
  73. package/dist/tab-bar-searchable/animations/enter.js +73 -0
  74. package/dist/tab-bar-searchable/animations/leave.d.ts +8 -0
  75. package/dist/tab-bar-searchable/animations/leave.d.ts.map +1 -0
  76. package/dist/tab-bar-searchable/animations/leave.js +66 -0
  77. package/dist/tab-bar-searchable/index.d.ts +4 -0
  78. package/dist/tab-bar-searchable/index.d.ts.map +1 -0
  79. package/dist/tab-bar-searchable/index.js +75 -0
  80. package/dist/tab-bar-searchable/interfaces.d.ts +41 -0
  81. package/dist/tab-bar-searchable/interfaces.d.ts.map +1 -0
  82. package/dist/tab-bar-searchable/interfaces.js +5 -0
  83. package/dist/tab-bar-searchable/utils.d.ts +12 -0
  84. package/dist/tab-bar-searchable/utils.d.ts.map +1 -0
  85. package/dist/tab-bar-searchable/utils.js +60 -0
  86. package/dist/transition/index.d.ts +19 -0
  87. package/dist/transition/index.d.ts.map +1 -0
  88. package/dist/transition/index.js +219 -0
  89. package/dist/transition/ios.transition.d.ts +5 -0
  90. package/dist/transition/ios.transition.d.ts.map +1 -0
  91. package/dist/transition/ios.transition.js +609 -0
  92. package/dist/utils.d.ts +17 -0
  93. package/dist/utils.d.ts.map +1 -0
  94. package/dist/utils.js +69 -0
  95. package/docs/e2e-testing.md +51 -0
  96. package/docs/eslint.md +73 -0
  97. package/docs/experimental-animation.md +85 -0
  98. package/docs/features.md +88 -0
  99. package/docs/feedback.md +65 -0
  100. package/docs/ios-18.md +16 -0
  101. package/docs/migration.md +94 -0
  102. package/docs/special-markup.md +145 -0
  103. package/docs/using-ion-item-group.md +47 -0
  104. package/package.json +63 -0
  105. package/src/focus-controller/index.ts +123 -0
  106. package/src/index.ts +33 -0
  107. package/src/popover/animations/ios.enter.ts +144 -0
  108. package/src/popover/animations/ios.leave.ts +76 -0
  109. package/src/popover/popover-interface.ts +44 -0
  110. package/src/popover/utils.ts +696 -0
  111. package/src/sheets-of-glass/animations.ts +120 -0
  112. package/src/sheets-of-glass/index.ts +214 -0
  113. package/src/sheets-of-glass/interfaces.ts +17 -0
  114. package/src/styles/components/ion-action-sheet.scss +85 -0
  115. package/src/styles/components/ion-alert.scss +66 -0
  116. package/src/styles/components/ion-button.scss +443 -0
  117. package/src/styles/components/ion-card.scss +7 -0
  118. package/src/styles/components/ion-content.scss +22 -0
  119. package/src/styles/components/ion-datetime.scss +9 -0
  120. package/src/styles/components/ion-fab.scss +104 -0
  121. package/src/styles/components/ion-inputs.scss +82 -0
  122. package/src/styles/components/ion-list.scss +44 -0
  123. package/src/styles/components/ion-loading.scss +11 -0
  124. package/src/styles/components/ion-menu.scss +110 -0
  125. package/src/styles/components/ion-modal.scss +42 -0
  126. package/src/styles/components/ion-picker.scss +4 -0
  127. package/src/styles/components/ion-popover.scss +33 -0
  128. package/src/styles/components/ion-range.scss +90 -0
  129. package/src/styles/components/ion-searchbar.scss +68 -0
  130. package/src/styles/components/ion-segment.scss +150 -0
  131. package/src/styles/components/ion-tabs.scss +118 -0
  132. package/src/styles/components/ion-toast.scss +35 -0
  133. package/src/styles/components/ion-toggle.scss +65 -0
  134. package/src/styles/components/ion-toolbar.scss +76 -0
  135. package/src/styles/default-variables.scss +38 -0
  136. package/src/styles/ionic-theme-ios26-dark-always.scss +6 -0
  137. package/src/styles/ionic-theme-ios26-dark-class.scss +6 -0
  138. package/src/styles/ionic-theme-ios26-dark-system.scss +8 -0
  139. package/src/styles/ionic-theme-ios26.scss +23 -0
  140. package/src/styles/md-ion-list-inset.scss +22 -0
  141. package/src/styles/md-remove-ios-class-effect.scss +14 -0
  142. package/src/styles/utils/api.scss +146 -0
  143. package/src/styles/utils/dark/ion-button.scss +58 -0
  144. package/src/styles/utils/dark/ion-fab.scss +18 -0
  145. package/src/styles/utils/dark/ion-segment.scss +12 -0
  146. package/src/styles/utils/dark/ion-tabs.scss +21 -0
  147. package/src/styles/utils/searchable.scss +0 -0
  148. package/src/styles/utils/structured-list.scss +170 -0
  149. package/src/styles/utils/theme-dark.scss +25 -0
  150. package/src/styles/utils/translucent.scss +95 -0
  151. package/src/tab-bar-searchable/animations/enter.ts +92 -0
  152. package/src/tab-bar-searchable/animations/leave.ts +89 -0
  153. package/src/tab-bar-searchable/index.ts +141 -0
  154. package/src/tab-bar-searchable/interfaces.ts +28 -0
  155. package/src/tab-bar-searchable/utils.ts +75 -0
  156. package/src/transition/index.ts +369 -0
  157. package/src/transition/ios.transition.ts +966 -0
  158. package/src/utils.ts +91 -0
@@ -0,0 +1,443 @@
1
+ @use '../utils/api';
2
+
3
+ /**
4
+ * Note: ion-back-button should not put inner ion-button.
5
+ * feat(): ion-config new property for disable ion-back-button Animation
6
+ */
7
+
8
+ $scaleup-small: 1.12;
9
+ $scaleup-small-icon-only: api.$button-scaleup-small-icon-only;
10
+ $scaleup-default: 1.25;
11
+ $scaleup-default-icon-only: api.$button-scaleup-default-icon-only;
12
+ $scaleup-large: 1.12;
13
+ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only;
14
+
15
+ @mixin theme-buttons {
16
+ @include api.glass-background($shadow-opacity: 0.08);
17
+ border-radius: 25px;
18
+ overflow: hidden;
19
+ &:not(:has(.ion-activated)):hover {
20
+ opacity: 0.72;
21
+ }
22
+
23
+ /**
24
+ * compare .header-collapse-main ion-toolbar.in-toolbar ion-title, .header-collapse-main ion-toolbar.in-toolbar ion-buttons
25
+ */
26
+ transition: transform var(--ios26-activated-transition-duration) ease-out;
27
+
28
+ z-index: 0;
29
+
30
+ &:has(.ion-activated) {
31
+ z-index: 5;
32
+ @include api.glass-background-button-activated;
33
+
34
+ // Hardware acceleration optimization for scale transforms
35
+ transform: scale($scaleup-default-icon-only) translateZ(0);
36
+ -webkit-transform: scale($scaleup-default-icon-only) translateZ(0);
37
+ &:has(:not(.button-has-icon-only):not(.back-button-has-icon-only)),
38
+ &:has(ion-button:nth-child(n + 2)) {
39
+ transform: scale($scaleup-default) translateZ(0);
40
+ -webkit-transform: scale($scaleup-default) translateZ(0);
41
+ }
42
+ &:has(.button-small) {
43
+ transform: scale($scaleup-small-icon-only) translateZ(0);
44
+ -webkit-transform: scale($scaleup-small-icon-only) translateZ(0);
45
+ &:has(:not(.button-has-icon-only):not(.back-button-has-icon-only)),
46
+ &:has(ion-button:nth-child(n + 2)) {
47
+ transform: scale($scaleup-small) translateZ(0);
48
+ -webkit-transform: scale($scaleup-small) translateZ(0);
49
+ }
50
+ }
51
+ &:has(.button-large) {
52
+ transform: scale($scaleup-large-icon-only) translateZ(0);
53
+ -webkit-transform: scale($scaleup-large-icon-only) translateZ(0);
54
+ &:has(:not(.button-has-icon-only):not(.back-button-has-icon-only)),
55
+ &:has(ion-button:nth-child(n + 2)) {
56
+ transform: scale($scaleup-large) translateZ(0);
57
+ -webkit-transform: scale($scaleup-large) translateZ(0);
58
+ }
59
+ }
60
+ }
61
+
62
+ &:has(ion-button:not(.ios26-disabled).button-clear.button-large) {
63
+ border-radius: 30px;
64
+ }
65
+
66
+ ion-button:not(.ios26-disabled).button-clear {
67
+ --background: transparent;
68
+ --border-style: none;
69
+ --border-width: 0;
70
+ --box-shadow: none;
71
+ transform: none;
72
+
73
+ font-weight: 500;
74
+ &.button-small {
75
+ min-height: calc(24px - 2px);
76
+ --padding-top: 1px;
77
+ --padding-bottom: 1px;
78
+ --padding-start: 0.5em;
79
+ --padding-end: 0.5em;
80
+ }
81
+ &.button-default {
82
+ --padding-bottom: 0;
83
+ --padding-end: 12px;
84
+ --padding-start: 12px;
85
+ --padding-top: 0;
86
+ &::part(native) {
87
+ min-height: calc(44px - 2px); // reduce for border 2px;
88
+ }
89
+ }
90
+ &.button-large {
91
+ min-height: calc(62px - 2px);
92
+ --padding-top: 17px;
93
+ --padding-start: 1em;
94
+ --padding-end: 1em;
95
+ --padding-bottom: 17px;
96
+ }
97
+ color: rgb(var(--ion-text-color-rgb, 0, 0, 0));
98
+ &.ion-color {
99
+ color: rgb(var(--ion-color-base-rgb, var(--ion-text-color-rgb, 0, 0, 0)));
100
+ }
101
+ &.ion-activated {
102
+ color: rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.1);
103
+ &.ion-color {
104
+ color: rgba(var(--ion-color-base-rgb, var(--ion-text-color-rgb, 0, 0, 0)), 0.1);
105
+ }
106
+ }
107
+
108
+ &:not(.button-disabled) {
109
+ opacity: 1;
110
+ }
111
+
112
+ &.ion-activated {
113
+ --color: rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.1);
114
+ &.ion-color {
115
+ --color: rgba(var(--ion-color-base-rgb, var(--ion-text-color-rgb, 0, 0, 0)), 0.1);
116
+ }
117
+ }
118
+
119
+ &::part(native) {
120
+ backdrop-filter: none;
121
+ }
122
+ }
123
+
124
+ ion-button:not(.ios26-disabled) {
125
+ margin: 0;
126
+ }
127
+
128
+ ion-menu-button:not(.ios26-disabled) {
129
+ width: 44px;
130
+ height: 44px;
131
+ padding: 2px;
132
+ }
133
+ }
134
+
135
+ @mixin theme-button($is-back-button: false) {
136
+ max-height: inherit;
137
+ z-index: 0;
138
+ &.ion-activated {
139
+ z-index: 10;
140
+ }
141
+
142
+ transition:
143
+ transform var(--ios26-activated-transition-duration) ease-out,
144
+ color 50ms ease;
145
+
146
+ &.in-toolbar:not(.ion-color):not(.in-toolbar-color) {
147
+ --ion-toolbar-color: currentColor;
148
+
149
+ &.button-solid {
150
+ --ion-toolbar-color: var(--background);
151
+ --ion-toolbar-background: currentColor;
152
+ }
153
+ }
154
+
155
+ // will-change is optimized to only apply when needed for performance
156
+ &:not(.ios26-disabled):hover,
157
+ &:not(.ios26-disabled):active,
158
+ &:not(.ios26-disabled).ion-activated {
159
+ will-change: transform;
160
+ }
161
+
162
+ &:not(.ios26-disabled):not(:hover):not(:active):not(.ion-activated) {
163
+ will-change: auto;
164
+ }
165
+
166
+ // button size default
167
+ &:not(.button-small):not(.button-large) {
168
+ font-size: 1.05rem;
169
+ &:not(.button-has-icon-only):not(.back-button-has-icon-only) {
170
+ --padding-bottom: 0;
171
+ --padding-end: 12px;
172
+ --padding-start: 12px;
173
+ --padding-top: 0;
174
+ @if $is-back-button {
175
+ --min-height: 44px;
176
+ } @else {
177
+ &::part(native) {
178
+ min-height: 44px;
179
+ }
180
+ }
181
+ ion-icon[slot='start'] {
182
+ margin-inline-start: -0.15em;
183
+ margin-inline-end: 0.15em;
184
+ }
185
+ ion-icon[slot='end'] {
186
+ margin-inline-start: 0.15em;
187
+ margin-inline-end: -0.15em;
188
+ }
189
+ }
190
+ }
191
+
192
+ &:not(.button-round) {
193
+ --border-radius: 24px;
194
+ &.button-large {
195
+ --border-radius: 30px;
196
+ }
197
+ }
198
+
199
+ /*
200
+ * fill=solid && type=submit button has edge brightness.
201
+ */
202
+ &.button-solid[type='submit'],
203
+ &.button-solid.button-submit {
204
+ /*
205
+ * If not set ion-color-**, button color set primary.
206
+ * https://github.com/ionic-team/ionic-framework/blob/main/core/src/components/button/button.scss#L78-L81
207
+ */
208
+ --background-activated: var(--ion-color-primary-shade, #004acd);
209
+ --background-focused: var(--ion-color-primary-shade, #004acd);
210
+ --background-hover: var(--ion-color-primary-tint, #1a65eb);
211
+ --border-width: 0.5px;
212
+ --border-style: solid;
213
+
214
+ &:not(.button-disabled):not([disabled]) {
215
+ --color: var(--ion-color-primary-brightness, var(--ion-color-contrast));
216
+ --color-activated: var(--ion-color-primary-brightness);
217
+ --border-color: var(--ion-color-primary-brightness, transparent);
218
+
219
+ @each $item in primary, secondary, tertiary, success, warning, danger, light, medium, dark {
220
+ &.ion-color-#{$item} {
221
+ --color: var(--ion-color-#{$item}-brightness, var(--ion-color-#{$item}-contrast, var(--ion-color-contrast)));
222
+ --color-activated: var(--ion-color-#{$item}-brightness);
223
+ --border-color: var(--ion-color-#{$item}-brightness, transparent);
224
+ --border-width: 0.5px;
225
+ --border-style: solid;
226
+ }
227
+ }
228
+ }
229
+ --background-color: #fff;
230
+ --background-activated-opacity: 1;
231
+ &:not(.button-has-icon-only):not(.back-button-has-icon-only) {
232
+ &:not(.button-small):not(.button-large) {
233
+ min-height: 44px;
234
+ }
235
+ }
236
+ &::part(native) {
237
+ position: relative;
238
+ z-index: 0;
239
+ }
240
+ &.ion-color::part(native) {
241
+ color: var(--color);
242
+ }
243
+ &.ion-activated {
244
+ --border-width: 0.78px;
245
+ @if $is-back-button {
246
+ &::part(native) {
247
+ @include api.glass-background-button-activated;
248
+ }
249
+ } @else {
250
+ --box-shadow:
251
+ inset 0 0 8px 0 rgba(var(--ios26-glass-box-shadow-color-rgb), 0.2),
252
+ 0 0 8px -4px rgba(var(--ios26-glass-box-shadow-color-rgb), 0.92);
253
+ }
254
+ &::part(native)::before {
255
+ content: '';
256
+ z-index: 1;
257
+ width: 100%;
258
+ height: 100%;
259
+ position: absolute;
260
+ top: 0;
261
+ left: 0;
262
+ border-radius: inherit;
263
+ pointer-events: none;
264
+ backdrop-filter: brightness(144%);
265
+ }
266
+ &.ion-activated.button-has-icon-only,
267
+ &.ion-activated.back-button-has-icon-only {
268
+ transform: scale($scaleup-default-icon-only);
269
+ &.button-small {
270
+ transform: scale($scaleup-small-icon-only);
271
+ }
272
+ &.button-large {
273
+ transform: scale($scaleup-large-icon-only);
274
+ }
275
+ }
276
+
277
+ &:not(.button-has-icon-only):not(.back-button-has-icon-only) {
278
+ transform: scale($scaleup-default);
279
+ &.button-small {
280
+ transform: scale($scaleup-small);
281
+ }
282
+ &.button-large {
283
+ transform: scale($scaleup-large);
284
+ }
285
+ }
286
+ }
287
+ &.button-disabled {
288
+ --background: var(--ion-background-color-step-200, #cccccc);
289
+ opacity: 1;
290
+
291
+ &.ion-color {
292
+ --background: var(--ion-color-base);
293
+ --color: var(--ion-color-contrast);
294
+ opacity: 0.38;
295
+ }
296
+
297
+ &::part(native) {
298
+ color: var(--color);
299
+ }
300
+ &.ion-color::part(native) {
301
+ background: var(--background);
302
+ }
303
+ @if $is-back-button {
304
+ &::part(native) {
305
+ border: none;
306
+ }
307
+ } @else {
308
+ --border-style: none;
309
+ --border-width: 0;
310
+ }
311
+ }
312
+ }
313
+
314
+ // fill:default only
315
+ &:not(.button-solid):not(.button-outline):not(.button-clear) {
316
+ --background: rgba(var(--ios26-glass-background-rgb), 0.72);
317
+ --background-hover: transparent;
318
+ --background-activated: transparent;
319
+ @if not $is-back-button {
320
+ --box-shadow:
321
+ inset 0 0 8px 0 rgba(var(--ios26-glass-box-shadow-color-rgb), 0.2),
322
+ 0 0.5px 1px 0 rgba(var(--ios26-glass-box-shadow-color-rgb), 0.08);
323
+ }
324
+
325
+ &:not(.button-has-icon-only):not(.back-button-has-icon-only) {
326
+ &:not(.button-small):not(.button-large) {
327
+ min-height: 44px;
328
+ }
329
+ }
330
+
331
+ &::part(native) {
332
+ @include api.glass-background($include-background: false, $include-box-shadow: $is-back-button, $shadow-opacity: 0.08);
333
+ }
334
+
335
+ &:not(.button-disabled) {
336
+ opacity: 1; // for ion-back-button
337
+ }
338
+ &:not(.ion-activated):hover {
339
+ opacity: 0.72;
340
+ }
341
+ --color: rgb(var(--ion-text-color-rgb, 0, 0, 0));
342
+ &.ion-color {
343
+ --color: rgba(var(--ion-color-base-rgb, var(--ion-text-color-rgb, 0, 0, 0)), 1);
344
+ }
345
+ &.ion-activated {
346
+ &::part(native) {
347
+ @include api.glass-background-button-activated;
348
+ opacity: 1;
349
+ color: var(--color);
350
+ }
351
+ --color: rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.1);
352
+ &.ion-color {
353
+ --color: rgba(var(--ion-color-base-rgb, var(--ion-text-color-rgb, 0, 0, 0)), 0.1);
354
+ }
355
+ &.ion-activated.button-has-icon-only,
356
+ &.ion-activated.back-button-has-icon-only {
357
+ transform: scale($scaleup-default-icon-only);
358
+ &.button-small {
359
+ transform: scale($scaleup-small-icon-only);
360
+ }
361
+ &.button-large {
362
+ transform: scale($scaleup-large-icon-only);
363
+ }
364
+ }
365
+
366
+ &:not(.button-has-icon-only):not(.back-button-has-icon-only) {
367
+ transform: scale($scaleup-default);
368
+ &.button-small {
369
+ transform: scale($scaleup-small);
370
+ }
371
+ &.button-large {
372
+ transform: scale($scaleup-large);
373
+ }
374
+ }
375
+ }
376
+ &.button-disabled {
377
+ opacity: 1;
378
+ --color: rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.5);
379
+ &.ion-color {
380
+ --color: rgba(var(--ion-color-base-rgb, var(--ion-text-color-rgb, 0, 0, 0)), 0.5);
381
+ }
382
+ }
383
+ }
384
+
385
+ &.button-has-icon-only,
386
+ &.back-button-has-icon-only {
387
+ &:not(.button-small):not(.button-large) {
388
+ --padding-bottom: 2px;
389
+ --padding-end: 2px;
390
+ --padding-start: 2px;
391
+ --padding-top: 2px;
392
+ @if $is-back-button {
393
+ --min-height: 44px;
394
+ --min-width: 44px;
395
+ } @else {
396
+ &::part(native) {
397
+ width: 44px;
398
+ height: 44px;
399
+ }
400
+ }
401
+ }
402
+
403
+ ion-icon {
404
+ font-size: 1.4rem;
405
+ &[name='close-outline'] {
406
+ font-size: 2rem;
407
+ }
408
+ }
409
+ }
410
+ }
411
+
412
+ ion-buttons.ios:not(.ios26-disabled):not(:has(ion-back-button, ion-button:not(.button-clear), ion-menu-button.menu-button-hidden)) {
413
+ @include theme-buttons;
414
+ }
415
+
416
+ // Ionic's collapsing-header transition has a more specific contextual selector.
417
+ .header-collapse-main
418
+ :where(ion-toolbar.in-toolbar)
419
+ ion-buttons.ios:not(.ios26-disabled):not(:has(ion-back-button, ion-button:not(.button-clear), ion-menu-button.menu-button-hidden)) {
420
+ transition: transform var(--ios26-activated-transition-duration) ease-out;
421
+ }
422
+
423
+ ion-buttons.ios:not(.ios26-disabled):not(:has(ion-back-button, ion-button.button-clear)) {
424
+ ion-button {
425
+ margin: 0 6px;
426
+ &:first-child {
427
+ margin-left: 0;
428
+ }
429
+ &:last-child {
430
+ margin-right: 0;
431
+ }
432
+ &:only-child {
433
+ margin: 0;
434
+ }
435
+ }
436
+ }
437
+
438
+ ion-button.ios:not(.ios26-disabled) {
439
+ @include theme-button;
440
+ }
441
+ ion-back-button.ios:not(.ios26-disabled) {
442
+ @include theme-button($is-back-button: true);
443
+ }
@@ -0,0 +1,7 @@
1
+ ion-card.ios:not(.ios26-disabled) {
2
+ border-radius: 24px;
3
+
4
+ ion-list ion-item {
5
+ --padding-start: 0;
6
+ }
7
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Since iOS26, content is now displayed to the full extent of the top and bottom safe areas,
3
+ * so we adjust the margin and padding of the content.
4
+ * Also supports virtual scrolling using .ion-content-scroll-host.
5
+ */
6
+ .ion-page.ios:not(.ios26-disabled):has(ion-header.header-translucent)
7
+ ion-content.ios:not(.ios26-disabled).content-fullscreen:has(.ion-content-scroll-host) {
8
+ --padding-top: calc(var(--offset-top) * -1);
9
+ > *:not(.ion-content-scroll-host, ion-fab) {
10
+ transform: translateY(var(--offset-top));
11
+ }
12
+ .ion-content-scroll-host {
13
+ padding-top: var(--offset-top);
14
+ }
15
+ }
16
+ .ion-page.ios:not(.ios26-disabled):not(:has(ion-footer)) ion-content.ios:not(.ios26-disabled).content-fullscreen .ion-content-scroll-host {
17
+ margin-bottom: calc(calc(60px + var(--ios26-floating-safe-area-bottom)) * -1);
18
+ padding-bottom: calc(60px + var(--ios26-floating-safe-area-bottom));
19
+ }
20
+ ion-content.ios:not(.ios26-disabled).content-fullscreen:not(:has(.ion-content-scroll-host)) {
21
+ --padding-bottom: calc(60px + var(--ios26-floating-safe-area-bottom));
22
+ }
@@ -0,0 +1,9 @@
1
+ @use '../utils/api';
2
+
3
+ ion-datetime.ios:not(.ios26-disabled) {
4
+ @include api.glass-background-overlay;
5
+ border-radius: 24px;
6
+
7
+ --wheel-highlight-background: transparent;
8
+ --wheel-highlight-border-radius: 24px;
9
+ }
@@ -0,0 +1,104 @@
1
+ @use '../utils/api';
2
+
3
+ $scaleup-small-icon-only: api.$button-scaleup-small-icon-only;
4
+ $scaleup-default-icon-only: api.$button-scaleup-default-icon-only;
5
+ $scaleup-large-icon-only: api.$button-scaleup-large-icon-only;
6
+
7
+ ion-fab.ios:not(.ios26-disabled) {
8
+ --transform-value: 2.5px;
9
+ &:has(> ion-fab-button.fab-button-small) {
10
+ --transform-value: 4px;
11
+ }
12
+
13
+ ion-fab-button {
14
+ --background: rgba(var(--ios26-glass-background-rgb), 0.72);
15
+ --box-shadow:
16
+ 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);
17
+ --transition:
18
+ var(--ios26-activated-transition-duration) transform cubic-bezier(0.25, 1.11, 0.78, 1.59),
19
+ var(--ios26-activated-transition-duration) color ease;
20
+ --background-activated-opacity: 0;
21
+ --background-focused-opacity: 0;
22
+ --background-hover-opacity: 0;
23
+
24
+ --color: rgb(var(--ion-text-color-rgb, 0, 0, 0));
25
+
26
+ /**
27
+ * 60px + border0.5px + 0.5px
28
+ */
29
+ width: 61px;
30
+ height: 61px;
31
+
32
+ &.fab-button-in-list,
33
+ &.fab-button-small {
34
+ width: 48px;
35
+ height: 48px;
36
+ }
37
+
38
+ &.ion-activated {
39
+ --color: rgba(var(--ion-text-color-rgb, 0, 0, 0), 0.1);
40
+ &::part(native) {
41
+ @include api.glass-background-button-activated;
42
+ transform: scale($scaleup-default-icon-only) translateZ(0);
43
+ -webkit-transform: scale($scaleup-default-icon-only) translateZ(0);
44
+ }
45
+ &.fab-button-large {
46
+ &::part(native) {
47
+ transform: scale($scaleup-large-icon-only) translateZ(0);
48
+ -webkit-transform: scale($scaleup-large-icon-only) translateZ(0);
49
+ }
50
+ }
51
+ &.fab-button-small {
52
+ &::part(native) {
53
+ transform: scale($scaleup-small-icon-only) translateZ(0);
54
+ -webkit-transform: scale($scaleup-small-icon-only) translateZ(0);
55
+ }
56
+ }
57
+ &.ion-color {
58
+ --color: rgba(var(--ion-color-base-rgb, var(--ion-text-color-rgb, 0, 0, 0)), 0.1);
59
+ }
60
+ }
61
+
62
+ &::part(native) {
63
+ background-clip: border-box;
64
+ @include api.glass-background($include-background: false, $include-box-shadow: false);
65
+ }
66
+ }
67
+
68
+ ion-fab-list {
69
+ &.fab-list-side-top,
70
+ &.fab-list-side-bottom {
71
+ transform: translateX(var(--transform-value));
72
+ }
73
+ &.fab-list-side-start,
74
+ &.fab-list-side-end {
75
+ transform: translateY(var(--transform-value));
76
+ }
77
+ }
78
+
79
+ &.fab-vertical-top {
80
+ top: var(--ios26-floating-safe-area-top);
81
+ }
82
+
83
+ &.fab-vertical-bottom {
84
+ bottom: var(--ios26-floating-safe-area-bottom);
85
+ }
86
+
87
+ &.fab-horizontal-start {
88
+ left: calc(16px + var(--ios26-menu-width, var(--ion-safe-area-left), 0px));
89
+ }
90
+
91
+ &.fab-horizontal-end {
92
+ right: calc(16px + var(--ion-safe-area-right, 0px));
93
+ }
94
+
95
+ &:has(.fab-button-small) {
96
+ &.fab-horizontal-start {
97
+ left: calc(10px + var(--ios26-menu-width, var(--ion-safe-area-left), 0px));
98
+ }
99
+
100
+ &.fab-horizontal-end {
101
+ right: calc(10px + var(--ion-safe-area-right, 0px));
102
+ }
103
+ }
104
+ }
@@ -0,0 +1,82 @@
1
+ @mixin outline-field($control) {
2
+ --placeholder-opacity: 1;
3
+ --padding-top: 12px;
4
+ --padding-bottom: 0;
5
+ margin-bottom: 12px;
6
+
7
+ .#{$control}-control,
8
+ .#{$control}-wrapper {
9
+ flex-direction: column;
10
+ }
11
+
12
+ .label-text-wrapper {
13
+ max-width: 100%;
14
+ margin: 0 2px 4px;
15
+ padding: 0;
16
+ font-size: 0.875rem;
17
+ line-height: 1.25rem;
18
+ transform: none;
19
+ }
20
+
21
+ .native-wrapper {
22
+ min-height: 48px;
23
+ border: 1px solid
24
+ var(--ion-item-border-color, var(--ion-border-color, var(--ion-color-step-250, var(--ion-background-color-step-250, #c8c7cc))));
25
+ border-radius: 10px;
26
+ background: var(--ion-background-color, #fff);
27
+ transition: border-color 150ms ease;
28
+ }
29
+
30
+ .#{$control}-bottom {
31
+ inset-inline: 0;
32
+ padding: 4px 2px 0;
33
+ border: 0;
34
+ font-size: 0.75rem;
35
+ line-height: 1rem;
36
+ }
37
+
38
+ &.has-focus {
39
+ .label-text-wrapper {
40
+ color: var(--highlight-color-focused);
41
+ }
42
+
43
+ .native-wrapper {
44
+ border-color: var(--highlight-color-focused);
45
+ }
46
+ }
47
+
48
+ &.ion-touched.ion-invalid .native-wrapper {
49
+ border-color: var(--highlight-color-invalid);
50
+ }
51
+
52
+ &.has-focus.ion-touched.ion-invalid .label-text-wrapper {
53
+ color: var(--highlight-color-invalid);
54
+ }
55
+ }
56
+
57
+ ion-input.ios:not(.ios26-disabled) {
58
+ &.input-fill-outline {
59
+ @include outline-field('input');
60
+
61
+ .native-input {
62
+ min-height: 46px;
63
+ padding-inline: 12px;
64
+ }
65
+ }
66
+ }
67
+
68
+ ion-textarea.ios:not(.ios26-disabled) {
69
+ &.textarea-fill-outline {
70
+ @include outline-field('textarea');
71
+
72
+ .native-wrapper {
73
+ min-height: 88px;
74
+ }
75
+
76
+ .native-textarea {
77
+ min-height: 86px;
78
+ padding-block: 12px;
79
+ padding-inline: 12px;
80
+ }
81
+ }
82
+ }
@@ -0,0 +1,44 @@
1
+ @use '../utils/structured-list';
2
+
3
+ ion-list.ios:not(.ios26-disabled) {
4
+ @include structured-list.support-text;
5
+ ion-item {
6
+ --background-hover-opacity: 0;
7
+ --background-focused-opacity: 0;
8
+ }
9
+ }
10
+
11
+ ion-list.list-inset.ios:not(.ios26-disabled) {
12
+ @include structured-list.layout(20px, 24px);
13
+
14
+ ion-radio-group,
15
+ ion-reorder-group {
16
+ display: block;
17
+ }
18
+
19
+ ion-radio-group > .radio-group-top {
20
+ padding-inline-start: calc(var(--ion-safe-area-left, 0) + 20px);
21
+ padding-inline-end: calc(var(--ion-safe-area-right, 0) + 20px);
22
+ }
23
+
24
+ > :is(#{structured-list.$groups}) {
25
+ ion-item {
26
+ // To draw lines inside
27
+ --inner-padding-end: 0;
28
+
29
+ &::part(native) {
30
+ padding-right: calc(var(--ion-safe-area-right, 0px) + 18px);
31
+ }
32
+
33
+ --min-height: 52px;
34
+
35
+ & > ion-input[labelplacement='floating'] {
36
+ transition: transform 200ms ease;
37
+
38
+ &:not(.label-floating) {
39
+ transform: translateY(-2px);
40
+ }
41
+ }
42
+ }
43
+ }
44
+ }