voyager-ionic-core 8.0.1 → 8.1.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 (554) hide show
  1. package/components/checkbox.js +3 -3
  2. package/components/index2.js +119 -1
  3. package/components/ion-accordion-group.js +2 -2
  4. package/components/ion-content.js +6 -4
  5. package/components/ion-datetime-button.js +2 -2
  6. package/components/ion-datetime.js +17 -14
  7. package/components/ion-fab-button.js +2 -2
  8. package/components/ion-fab-list.js +2 -2
  9. package/components/ion-fab.js +2 -2
  10. package/components/ion-footer.js +2 -2
  11. package/components/ion-grid.js +2 -2
  12. package/components/ion-header.js +2 -2
  13. package/components/ion-img.js +1 -1
  14. package/components/ion-infinite-scroll-content.js +2 -2
  15. package/components/ion-infinite-scroll.js +1 -1
  16. package/components/ion-input-password-toggle.js +3 -3
  17. package/components/ion-input.js +8 -4
  18. package/components/ion-item-divider.js +2 -2
  19. package/components/ion-item-group.js +1 -1
  20. package/components/ion-item-option.js +2 -2
  21. package/components/ion-item-options.js +1 -1
  22. package/components/ion-item-sliding.js +1 -1
  23. package/components/ion-loading.js +2 -2
  24. package/components/ion-menu-button.js +2 -2
  25. package/components/ion-menu-toggle.js +2 -2
  26. package/components/ion-menu.js +2 -2
  27. package/components/ion-modal.js +10 -8
  28. package/components/ion-nav-link.js +1 -1
  29. package/components/ion-nav.js +1 -1
  30. package/components/ion-note.js +2 -2
  31. package/components/ion-picker-legacy.js +2 -2
  32. package/components/ion-progress-bar.js +1 -1
  33. package/components/ion-range.js +3 -3
  34. package/components/ion-refresher-content.js +1 -1
  35. package/components/ion-refresher.js +1 -1
  36. package/components/ion-reorder-group.js +1 -1
  37. package/components/ion-reorder.js +1 -1
  38. package/components/ion-router-link.js +2 -2
  39. package/components/ion-router-outlet.js +1 -1
  40. package/components/ion-row.js +1 -1
  41. package/components/ion-searchbar.js +4 -4
  42. package/components/ion-segment-button.js +3 -3
  43. package/components/ion-segment.js +2 -2
  44. package/components/ion-select-option.js +1 -1
  45. package/components/ion-select.js +2 -2
  46. package/components/ion-skeleton-text.js +2 -2
  47. package/components/ion-split-pane.js +2 -2
  48. package/components/ion-tab-bar.js +2 -2
  49. package/components/ion-tab-button.js +2 -2
  50. package/components/ion-tab.js +2 -2
  51. package/components/ion-tabs.js +1 -1
  52. package/components/ion-text.js +2 -2
  53. package/components/ion-textarea.js +2 -2
  54. package/components/ion-thumbnail.js +1 -1
  55. package/components/ion-title.js +2 -2
  56. package/components/ion-toast.js +2 -2
  57. package/components/ion-toggle.js +3 -3
  58. package/components/ion-toolbar.js +2 -2
  59. package/components/ios.transition.js +94 -67
  60. package/components/label.js +3 -3
  61. package/components/list-header.js +2 -2
  62. package/components/list.js +1 -1
  63. package/components/overlays.js +3 -2
  64. package/components/picker-column-option.js +2 -2
  65. package/components/picker-column.js +156 -4
  66. package/components/picker-column2.js +2 -2
  67. package/components/picker.js +2 -2
  68. package/components/popover.js +6 -4
  69. package/components/radio-group.js +1 -1
  70. package/components/radio.js +3 -3
  71. package/components/ripple-effect.js +1 -1
  72. package/components/select-popover.js +2 -2
  73. package/components/spinner.js +1 -1
  74. package/css/core.css +1 -1
  75. package/css/core.css.map +1 -1
  76. package/css/global.bundle.css.map +1 -1
  77. package/css/ionic.bundle.css +1 -1
  78. package/css/ionic.bundle.css.map +1 -1
  79. package/css/palettes/dark.always.css +1 -1
  80. package/css/palettes/dark.always.css.map +1 -1
  81. package/css/palettes/dark.class.css +1 -1
  82. package/css/palettes/dark.class.css.map +1 -1
  83. package/css/palettes/dark.system.css +1 -1
  84. package/css/palettes/dark.system.css.map +1 -1
  85. package/css/palettes/high-contrast-dark.always.css.map +1 -1
  86. package/css/palettes/high-contrast-dark.class.css.map +1 -1
  87. package/css/palettes/high-contrast-dark.system.css.map +1 -1
  88. package/css/palettes/high-contrast.always.css.map +1 -1
  89. package/css/palettes/high-contrast.class.css.map +1 -1
  90. package/css/palettes/high-contrast.system.css.map +1 -1
  91. package/css/typography.css.map +1 -1
  92. package/dist/cjs/{app-globals-542c4d91.js → app-globals-66b7dc06.js} +1 -1
  93. package/dist/cjs/{button-active-47528f4c.js → button-active-9135c809.js} +1 -1
  94. package/dist/cjs/{hardware-back-button-06ae4d9c.js → hardware-back-button-ed931127.js} +2 -2
  95. package/dist/cjs/index-8709af32.js +2234 -0
  96. package/dist/cjs/{index-c76a1d14.js → index-c0b7f8f4.js} +124 -6
  97. package/dist/cjs/{index-57b504ac.js → index-c54654c6.js} +2 -2
  98. package/dist/cjs/index.cjs.js +9 -9
  99. package/dist/cjs/ion-accordion_2.cjs.entry.js +4 -4
  100. package/dist/cjs/ion-action-sheet.cjs.entry.js +5 -5
  101. package/dist/cjs/ion-alert.cjs.entry.js +5 -5
  102. package/dist/cjs/ion-app_8.cjs.entry.js +20 -19
  103. package/dist/cjs/ion-avatar_3.cjs.entry.js +3 -3
  104. package/dist/cjs/ion-back-button.cjs.entry.js +2 -2
  105. package/dist/cjs/ion-backdrop.cjs.entry.js +2 -2
  106. package/dist/cjs/ion-breadcrumb_2.cjs.entry.js +2 -2
  107. package/dist/cjs/ion-button_2.cjs.entry.js +2 -2
  108. package/dist/cjs/ion-card_5.cjs.entry.js +2 -2
  109. package/dist/cjs/ion-checkbox.cjs.entry.js +5 -5
  110. package/dist/cjs/ion-chip.cjs.entry.js +2 -2
  111. package/dist/cjs/ion-col_3.cjs.entry.js +5 -5
  112. package/dist/cjs/ion-datetime-button.cjs.entry.js +4 -4
  113. package/dist/cjs/ion-datetime_3.cjs.entry.js +25 -22
  114. package/dist/cjs/ion-fab_3.cjs.entry.js +8 -8
  115. package/dist/cjs/ion-img.cjs.entry.js +3 -3
  116. package/dist/cjs/ion-infinite-scroll_2.cjs.entry.js +5 -5
  117. package/dist/cjs/ion-input-password-toggle.cjs.entry.js +5 -5
  118. package/dist/cjs/ion-input.cjs.entry.js +9 -6
  119. package/dist/cjs/ion-item-option_3.cjs.entry.js +6 -6
  120. package/dist/cjs/ion-item_8.cjs.entry.js +15 -15
  121. package/dist/cjs/ion-loading.cjs.entry.js +6 -6
  122. package/dist/cjs/ion-menu_3.cjs.entry.js +11 -11
  123. package/dist/cjs/ion-modal.cjs.entry.js +13 -12
  124. package/dist/cjs/ion-nav_2.cjs.entry.js +6 -5
  125. package/dist/cjs/ion-picker-column-option.cjs.entry.js +4 -4
  126. package/dist/cjs/ion-picker-column.cjs.entry.js +156 -6
  127. package/dist/cjs/ion-picker.cjs.entry.js +3 -3
  128. package/dist/cjs/ion-popover.cjs.entry.js +9 -8
  129. package/dist/cjs/ion-progress-bar.cjs.entry.js +3 -3
  130. package/dist/cjs/ion-radio_2.cjs.entry.js +6 -6
  131. package/dist/cjs/ion-range.cjs.entry.js +5 -5
  132. package/dist/cjs/ion-refresher_2.cjs.entry.js +4 -4
  133. package/dist/cjs/ion-reorder_2.cjs.entry.js +4 -4
  134. package/dist/cjs/ion-ripple-effect.cjs.entry.js +3 -3
  135. package/dist/cjs/ion-route_4.cjs.entry.js +4 -4
  136. package/dist/cjs/ion-searchbar.cjs.entry.js +6 -6
  137. package/dist/cjs/ion-segment_2.cjs.entry.js +7 -7
  138. package/dist/cjs/ion-select_3.cjs.entry.js +9 -9
  139. package/dist/cjs/ion-spinner.cjs.entry.js +3 -3
  140. package/dist/cjs/ion-split-pane.cjs.entry.js +4 -4
  141. package/dist/cjs/ion-tab-bar_2.cjs.entry.js +6 -6
  142. package/dist/cjs/ion-tab_2.cjs.entry.js +4 -4
  143. package/dist/cjs/ion-text.cjs.entry.js +4 -4
  144. package/dist/cjs/ion-textarea.cjs.entry.js +4 -4
  145. package/dist/cjs/ion-toast.cjs.entry.js +6 -6
  146. package/dist/cjs/ion-toggle.cjs.entry.js +5 -5
  147. package/dist/cjs/{ionic-global-f3622afe.js → ionic-global-35b86a09.js} +1 -1
  148. package/dist/cjs/ionic.cjs.js +5 -5
  149. package/dist/cjs/{ios.transition-288dfa83.js → ios.transition-5ddf92f1.js} +98 -69
  150. package/dist/cjs/loader.cjs.js +4 -4
  151. package/dist/cjs/{md.transition-6e5f6a8d.js → md.transition-047c18c5.js} +4 -2
  152. package/dist/cjs/{overlays-32cfd236.js → overlays-cb04d075.js} +5 -3
  153. package/dist/cjs/{status-tap-c47ff5f5.js → status-tap-5b2775cd.js} +1 -1
  154. package/dist/collection/collection-manifest.json +1 -1
  155. package/dist/collection/components/accordion-group/accordion-group.js +3 -3
  156. package/dist/collection/components/checkbox/checkbox.js +4 -4
  157. package/dist/collection/components/content/content.js +23 -4
  158. package/dist/collection/components/content/test/content.spec.js +27 -0
  159. package/dist/collection/components/datetime/datetime.js +18 -15
  160. package/dist/collection/components/datetime/test/overlay-roles/datetime.e2e.js +34 -0
  161. package/dist/collection/components/datetime-button/datetime-button.js +2 -2
  162. package/dist/collection/components/fab/fab.js +2 -2
  163. package/dist/collection/components/fab-button/fab-button.js +2 -2
  164. package/dist/collection/components/fab-list/fab-list.js +2 -2
  165. package/dist/collection/components/footer/footer.js +2 -2
  166. package/dist/collection/components/grid/grid.js +2 -2
  167. package/dist/collection/components/header/header.js +2 -2
  168. package/dist/collection/components/img/img.js +1 -1
  169. package/dist/collection/components/infinite-scroll/infinite-scroll.js +1 -1
  170. package/dist/collection/components/infinite-scroll-content/infinite-scroll-content.js +2 -2
  171. package/dist/collection/components/input/input.js +25 -5
  172. package/dist/collection/components/input/test/input.spec.js +13 -0
  173. package/dist/collection/components/input-password-toggle/input-password-toggle.js +3 -3
  174. package/dist/collection/components/item/test/a11y/item.e2e.js +24 -4
  175. package/dist/collection/components/item-divider/item-divider.js +2 -2
  176. package/dist/collection/components/item-group/item-group.js +1 -1
  177. package/dist/collection/components/item-option/item-option.js +2 -2
  178. package/dist/collection/components/item-options/item-options.js +1 -1
  179. package/dist/collection/components/item-sliding/item-sliding.js +1 -1
  180. package/dist/collection/components/label/label.ios.css +1 -1
  181. package/dist/collection/components/label/label.js +2 -2
  182. package/dist/collection/components/list/list.js +1 -1
  183. package/dist/collection/components/list-header/list-header.js +2 -2
  184. package/dist/collection/components/loading/loading.js +2 -2
  185. package/dist/collection/components/menu/menu.js +2 -2
  186. package/dist/collection/components/menu-button/menu-button.js +2 -2
  187. package/dist/collection/components/menu-toggle/menu-toggle.js +2 -2
  188. package/dist/collection/components/modal/gestures/sheet.js +3 -2
  189. package/dist/collection/components/modal/modal.js +25 -6
  190. package/dist/collection/components/modal/test/basic/modal.spec.js +19 -0
  191. package/dist/collection/components/nav/nav.js +1 -1
  192. package/dist/collection/components/nav-link/nav-link.js +1 -1
  193. package/dist/collection/components/note/note.js +2 -2
  194. package/dist/collection/components/picker/picker.js +2 -2
  195. package/dist/collection/components/picker-column/picker-column.css +19 -0
  196. package/dist/collection/components/picker-column/picker-column.js +159 -4
  197. package/dist/collection/components/picker-column/test/picker-column.spec.js +83 -0
  198. package/dist/collection/components/picker-column-option/picker-column-option.js +2 -2
  199. package/dist/collection/components/picker-legacy/picker.js +2 -2
  200. package/dist/collection/components/picker-legacy-column/picker-column.js +2 -2
  201. package/dist/collection/components/popover/popover.js +23 -4
  202. package/dist/collection/components/popover/test/basic/popover.spec.js +19 -0
  203. package/dist/collection/components/progress-bar/progress-bar.js +1 -1
  204. package/dist/collection/components/radio/radio.js +3 -3
  205. package/dist/collection/components/radio-group/radio-group.js +2 -2
  206. package/dist/collection/components/range/range.js +4 -4
  207. package/dist/collection/components/refresher/refresher.js +1 -1
  208. package/dist/collection/components/refresher-content/refresher-content.js +1 -1
  209. package/dist/collection/components/reorder/reorder.js +1 -1
  210. package/dist/collection/components/reorder-group/reorder-group.js +1 -1
  211. package/dist/collection/components/ripple-effect/ripple-effect.js +1 -1
  212. package/dist/collection/components/router-link/router-link.js +2 -2
  213. package/dist/collection/components/router-outlet/router-outlet.js +1 -1
  214. package/dist/collection/components/row/row.js +1 -1
  215. package/dist/collection/components/searchbar/searchbar.js +5 -5
  216. package/dist/collection/components/segment/segment.js +3 -3
  217. package/dist/collection/components/segment-button/segment-button.js +3 -3
  218. package/dist/collection/components/select/select.js +3 -3
  219. package/dist/collection/components/select/test/fill/select.e2e.js +25 -0
  220. package/dist/collection/components/select-option/select-option.js +1 -1
  221. package/dist/collection/components/select-popover/select-popover.js +1 -1
  222. package/dist/collection/components/select-popover/select-popover.md.css +8 -1
  223. package/dist/collection/components/skeleton-text/skeleton-text.js +2 -2
  224. package/dist/collection/components/spinner/spinner.js +1 -1
  225. package/dist/collection/components/split-pane/split-pane.js +2 -2
  226. package/dist/collection/components/tab/tab.js +2 -2
  227. package/dist/collection/components/tab-bar/tab-bar.js +2 -2
  228. package/dist/collection/components/tab-button/tab-button.js +2 -2
  229. package/dist/collection/components/tabs/tabs.js +1 -1
  230. package/dist/collection/components/text/text.js +2 -2
  231. package/dist/collection/components/textarea/textarea.js +3 -3
  232. package/dist/collection/components/thumbnail/thumbnail.js +1 -1
  233. package/dist/collection/components/title/title.js +2 -2
  234. package/dist/collection/components/toast/toast.js +2 -2
  235. package/dist/collection/components/toggle/toggle.js +4 -4
  236. package/dist/collection/components/toolbar/toolbar.js +2 -2
  237. package/dist/collection/utils/focus-controller/index.js +112 -0
  238. package/dist/collection/utils/focus-controller/test/generic/focus-controller.e2e.js +52 -0
  239. package/dist/collection/utils/focus-controller/test/ionic/focus-controller.e2e.js +52 -0
  240. package/dist/collection/utils/overlays.js +2 -1
  241. package/dist/collection/utils/transition/index.js +11 -1
  242. package/dist/collection/utils/transition/ios.transition.js +94 -67
  243. package/dist/docs.json +109 -14
  244. package/dist/esm/{app-globals-3cbaf9d9.js → app-globals-b99e6d29.js} +1 -1
  245. package/dist/esm/{button-active-9e3c1f3b.js → button-active-920addb8.js} +1 -1
  246. package/dist/esm/{hardware-back-button-804f43bb.js → hardware-back-button-2d9760b6.js} +2 -2
  247. package/dist/esm/{index-8dbae644.js → index-7ae7186a.js} +2 -2
  248. package/dist/esm/{index-f7fbe1fb.js → index-8e6b6a24.js} +122 -4
  249. package/dist/esm/index-9aab3bcf.js +2196 -0
  250. package/dist/esm/index.js +9 -9
  251. package/dist/esm/ion-accordion_2.entry.js +4 -4
  252. package/dist/esm/ion-action-sheet.entry.js +5 -5
  253. package/dist/esm/ion-alert.entry.js +5 -5
  254. package/dist/esm/ion-app_8.entry.js +20 -19
  255. package/dist/esm/ion-avatar_3.entry.js +3 -3
  256. package/dist/esm/ion-back-button.entry.js +2 -2
  257. package/dist/esm/ion-backdrop.entry.js +2 -2
  258. package/dist/esm/ion-breadcrumb_2.entry.js +2 -2
  259. package/dist/esm/ion-button_2.entry.js +2 -2
  260. package/dist/esm/ion-card_5.entry.js +2 -2
  261. package/dist/esm/ion-checkbox.entry.js +5 -5
  262. package/dist/esm/ion-chip.entry.js +2 -2
  263. package/dist/esm/ion-col_3.entry.js +5 -5
  264. package/dist/esm/ion-datetime-button.entry.js +4 -4
  265. package/dist/esm/ion-datetime_3.entry.js +25 -22
  266. package/dist/esm/ion-fab_3.entry.js +8 -8
  267. package/dist/esm/ion-img.entry.js +3 -3
  268. package/dist/esm/ion-infinite-scroll_2.entry.js +5 -5
  269. package/dist/esm/ion-input-password-toggle.entry.js +5 -5
  270. package/dist/esm/ion-input.entry.js +9 -6
  271. package/dist/esm/ion-item-option_3.entry.js +6 -6
  272. package/dist/esm/ion-item_8.entry.js +15 -15
  273. package/dist/esm/ion-loading.entry.js +6 -6
  274. package/dist/esm/ion-menu_3.entry.js +11 -11
  275. package/dist/esm/ion-modal.entry.js +13 -12
  276. package/dist/esm/ion-nav_2.entry.js +6 -5
  277. package/dist/esm/ion-picker-column-option.entry.js +4 -4
  278. package/dist/esm/ion-picker-column.entry.js +156 -6
  279. package/dist/esm/ion-picker.entry.js +3 -3
  280. package/dist/esm/ion-popover.entry.js +9 -8
  281. package/dist/esm/ion-progress-bar.entry.js +3 -3
  282. package/dist/esm/ion-radio_2.entry.js +6 -6
  283. package/dist/esm/ion-range.entry.js +5 -5
  284. package/dist/esm/ion-refresher_2.entry.js +4 -4
  285. package/dist/esm/ion-reorder_2.entry.js +4 -4
  286. package/dist/esm/ion-ripple-effect.entry.js +3 -3
  287. package/dist/esm/ion-route_4.entry.js +4 -4
  288. package/dist/esm/ion-searchbar.entry.js +6 -6
  289. package/dist/esm/ion-segment_2.entry.js +7 -7
  290. package/dist/esm/ion-select_3.entry.js +9 -9
  291. package/dist/esm/ion-spinner.entry.js +3 -3
  292. package/dist/esm/ion-split-pane.entry.js +4 -4
  293. package/dist/esm/ion-tab-bar_2.entry.js +6 -6
  294. package/dist/esm/ion-tab_2.entry.js +4 -4
  295. package/dist/esm/ion-text.entry.js +4 -4
  296. package/dist/esm/ion-textarea.entry.js +4 -4
  297. package/dist/esm/ion-toast.entry.js +6 -6
  298. package/dist/esm/ion-toggle.entry.js +5 -5
  299. package/dist/esm/{ionic-global-d2d8f882.js → ionic-global-4528d288.js} +1 -1
  300. package/dist/esm/ionic.js +6 -6
  301. package/dist/esm/{ios.transition-a0041e41.js → ios.transition-e35d0940.js} +98 -69
  302. package/dist/esm/loader.js +5 -5
  303. package/dist/esm/{md.transition-0c0602d9.js → md.transition-4b90a1f0.js} +4 -2
  304. package/dist/esm/{overlays-696d25f5.js → overlays-df2c06b2.js} +5 -4
  305. package/dist/esm/{status-tap-37a74d1c.js → status-tap-12c27922.js} +1 -1
  306. package/dist/esm-es5/app-globals-b99e6d29.js +4 -0
  307. package/dist/esm-es5/{button-active-9e3c1f3b.js → button-active-920addb8.js} +1 -1
  308. package/dist/esm-es5/{hardware-back-button-804f43bb.js → hardware-back-button-2d9760b6.js} +1 -1
  309. package/dist/esm-es5/{index-8dbae644.js → index-7ae7186a.js} +1 -1
  310. package/dist/esm-es5/index-8e6b6a24.js +4 -0
  311. package/dist/esm-es5/index-9aab3bcf.js +5 -0
  312. package/dist/esm-es5/index.js +1 -1
  313. package/dist/esm-es5/ion-accordion_2.entry.js +1 -1
  314. package/dist/esm-es5/ion-action-sheet.entry.js +1 -1
  315. package/dist/esm-es5/ion-alert.entry.js +1 -1
  316. package/dist/esm-es5/ion-app_8.entry.js +1 -1
  317. package/dist/esm-es5/ion-avatar_3.entry.js +1 -1
  318. package/dist/esm-es5/ion-back-button.entry.js +1 -1
  319. package/dist/esm-es5/ion-backdrop.entry.js +1 -1
  320. package/dist/esm-es5/ion-breadcrumb_2.entry.js +1 -1
  321. package/dist/esm-es5/ion-button_2.entry.js +1 -1
  322. package/dist/esm-es5/ion-card_5.entry.js +1 -1
  323. package/dist/esm-es5/ion-checkbox.entry.js +1 -1
  324. package/dist/esm-es5/ion-chip.entry.js +1 -1
  325. package/dist/esm-es5/ion-col_3.entry.js +1 -1
  326. package/dist/esm-es5/ion-datetime-button.entry.js +1 -1
  327. package/dist/esm-es5/ion-datetime_3.entry.js +1 -1
  328. package/dist/esm-es5/ion-fab_3.entry.js +1 -1
  329. package/dist/esm-es5/ion-img.entry.js +1 -1
  330. package/dist/esm-es5/ion-infinite-scroll_2.entry.js +1 -1
  331. package/dist/esm-es5/ion-input-password-toggle.entry.js +1 -1
  332. package/dist/esm-es5/ion-input.entry.js +1 -1
  333. package/dist/esm-es5/ion-item-option_3.entry.js +1 -1
  334. package/dist/esm-es5/ion-item_8.entry.js +1 -1
  335. package/dist/esm-es5/ion-loading.entry.js +1 -1
  336. package/dist/esm-es5/ion-menu_3.entry.js +1 -1
  337. package/dist/esm-es5/ion-modal.entry.js +1 -1
  338. package/dist/esm-es5/ion-nav_2.entry.js +1 -1
  339. package/dist/esm-es5/ion-picker-column-option.entry.js +1 -1
  340. package/dist/esm-es5/ion-picker-column.entry.js +1 -1
  341. package/dist/esm-es5/ion-picker.entry.js +1 -1
  342. package/dist/esm-es5/ion-popover.entry.js +1 -1
  343. package/dist/esm-es5/ion-progress-bar.entry.js +1 -1
  344. package/dist/esm-es5/ion-radio_2.entry.js +1 -1
  345. package/dist/esm-es5/ion-range.entry.js +1 -1
  346. package/dist/esm-es5/ion-refresher_2.entry.js +1 -1
  347. package/dist/esm-es5/ion-reorder_2.entry.js +1 -1
  348. package/dist/esm-es5/ion-ripple-effect.entry.js +1 -1
  349. package/dist/esm-es5/ion-route_4.entry.js +1 -1
  350. package/dist/esm-es5/ion-searchbar.entry.js +1 -1
  351. package/dist/esm-es5/ion-segment_2.entry.js +1 -1
  352. package/dist/esm-es5/ion-select_3.entry.js +1 -1
  353. package/dist/esm-es5/ion-spinner.entry.js +1 -1
  354. package/dist/esm-es5/ion-split-pane.entry.js +1 -1
  355. package/dist/esm-es5/ion-tab-bar_2.entry.js +1 -1
  356. package/dist/esm-es5/ion-tab_2.entry.js +1 -1
  357. package/dist/esm-es5/ion-text.entry.js +1 -1
  358. package/dist/esm-es5/ion-textarea.entry.js +1 -1
  359. package/dist/esm-es5/ion-toast.entry.js +1 -1
  360. package/dist/esm-es5/ion-toggle.entry.js +1 -1
  361. package/dist/esm-es5/{ionic-global-d2d8f882.js → ionic-global-4528d288.js} +1 -1
  362. package/dist/esm-es5/ionic.js +1 -1
  363. package/dist/esm-es5/ios.transition-e35d0940.js +4 -0
  364. package/dist/esm-es5/loader.js +1 -1
  365. package/dist/esm-es5/md.transition-4b90a1f0.js +4 -0
  366. package/dist/esm-es5/{overlays-696d25f5.js → overlays-df2c06b2.js} +1 -1
  367. package/dist/esm-es5/{status-tap-37a74d1c.js → status-tap-12c27922.js} +1 -1
  368. package/dist/html.html-data.json +24 -0
  369. package/dist/ionic/index.esm.js +1 -1
  370. package/dist/ionic/ionic.esm.js +1 -1
  371. package/dist/ionic/ionic.js +1 -1
  372. package/dist/ionic/{p-94731a92.system.entry.js → p-01a27023.system.entry.js} +1 -1
  373. package/dist/ionic/p-0395be73.entry.js +4 -0
  374. package/dist/ionic/p-03b86a5e.js +4 -0
  375. package/dist/ionic/{p-057b5866.entry.js → p-049d43bd.entry.js} +1 -1
  376. package/dist/ionic/p-0536574e.entry.js +4 -0
  377. package/dist/ionic/{p-e3005be4.system.entry.js → p-08ea3402.system.entry.js} +1 -1
  378. package/dist/ionic/{p-3f5b86b4.entry.js → p-09538818.entry.js} +1 -1
  379. package/dist/ionic/{p-470f73c4.entry.js → p-09b4e9ec.entry.js} +1 -1
  380. package/dist/ionic/{p-aa0ed22b.system.entry.js → p-0a6d801e.system.entry.js} +1 -1
  381. package/dist/ionic/{p-53a3b33c.system.entry.js → p-0b007acc.system.entry.js} +1 -1
  382. package/dist/ionic/{p-b76bcd9e.system.entry.js → p-10feef7e.system.entry.js} +1 -1
  383. package/dist/ionic/p-130299c9.entry.js +4 -0
  384. package/dist/ionic/p-15d1ddba.js +4 -0
  385. package/dist/ionic/{p-c3ca0292.system.entry.js → p-199f826f.system.entry.js} +1 -1
  386. package/dist/ionic/p-1b435d20.entry.js +4 -0
  387. package/dist/ionic/{p-c671b28e.js → p-1cc0b31f.js} +1 -1
  388. package/dist/ionic/{p-c4676693.entry.js → p-1eb63fa4.entry.js} +1 -1
  389. package/dist/ionic/{p-9b31ebfa.entry.js → p-207e11dc.entry.js} +1 -1
  390. package/dist/ionic/p-26bb6bb8.entry.js +4 -0
  391. package/dist/ionic/{p-5d3a8503.system.entry.js → p-279f3bac.system.entry.js} +1 -1
  392. package/dist/ionic/{p-e49099b0.entry.js → p-29de09dd.entry.js} +1 -1
  393. package/dist/ionic/{p-6730a2f1.entry.js → p-2c588aa2.entry.js} +1 -1
  394. package/dist/ionic/p-2ff0e0aa.system.js +4 -0
  395. package/dist/ionic/p-30baae57.system.js +4 -0
  396. package/dist/ionic/{p-806aad8f.system.js → p-31d27232.system.js} +1 -1
  397. package/dist/ionic/p-33e10509.system.js +4 -0
  398. package/dist/ionic/{p-a592f1b8.system.entry.js → p-380efbfa.system.entry.js} +1 -1
  399. package/dist/ionic/p-3c27be4a.entry.js +4 -0
  400. package/dist/ionic/p-3d015cdb.system.js +5 -0
  401. package/dist/ionic/{p-70181008.entry.js → p-3f53a0b1.entry.js} +1 -1
  402. package/dist/ionic/p-433157a4.entry.js +4 -0
  403. package/dist/ionic/{p-fc94e18f.entry.js → p-4824398b.entry.js} +1 -1
  404. package/dist/ionic/p-498eb648.system.entry.js +4 -0
  405. package/dist/ionic/{p-8caca06c.system.entry.js → p-4d8f408d.system.entry.js} +1 -1
  406. package/dist/ionic/{p-4c153abb.entry.js → p-5091f63c.entry.js} +1 -1
  407. package/dist/ionic/{p-42f00e72.system.entry.js → p-509620b8.system.entry.js} +1 -1
  408. package/dist/ionic/{p-d1a8f599.entry.js → p-5109a566.entry.js} +1 -1
  409. package/dist/ionic/{p-7f59064a.entry.js → p-52ce473d.entry.js} +1 -1
  410. package/dist/ionic/{p-33d926c3.entry.js → p-52f53904.entry.js} +1 -1
  411. package/dist/ionic/{p-4e548bd7.system.entry.js → p-55f99a39.system.entry.js} +1 -1
  412. package/dist/ionic/{p-1e4d7975.system.js → p-5734ac17.system.js} +1 -1
  413. package/dist/ionic/{p-2b1e669d.system.entry.js → p-57bc32e2.system.entry.js} +1 -1
  414. package/dist/ionic/{p-d11c336d.js → p-5cc6dcf5.js} +1 -1
  415. package/dist/ionic/p-5dc9f99a.entry.js +4 -0
  416. package/dist/ionic/p-5ec3bb70.system.entry.js +4 -0
  417. package/dist/ionic/{p-ebe0aa6d.entry.js → p-606f069c.entry.js} +1 -1
  418. package/dist/ionic/{p-93e43f42.system.entry.js → p-628967e3.system.entry.js} +1 -1
  419. package/dist/ionic/{p-5fbc2eae.system.entry.js → p-62e44e4a.system.entry.js} +1 -1
  420. package/dist/ionic/p-66ed603b.js +4 -0
  421. package/dist/ionic/{p-a801da4b.system.entry.js → p-670c9f57.system.entry.js} +1 -1
  422. package/dist/ionic/{p-fd392e7f.system.entry.js → p-6a2cf398.system.entry.js} +1 -1
  423. package/dist/ionic/{p-5a3a3373.entry.js → p-6c3666d5.entry.js} +1 -1
  424. package/dist/ionic/{p-1a5227b3.system.entry.js → p-6df12af0.system.entry.js} +1 -1
  425. package/dist/ionic/{p-bd6d9610.entry.js → p-6ec88301.entry.js} +1 -1
  426. package/dist/ionic/p-6f008ad2.js +4 -0
  427. package/dist/ionic/{p-2ab5db0d.system.entry.js → p-700567ab.system.entry.js} +1 -1
  428. package/dist/ionic/p-712d54ae.js +4 -0
  429. package/dist/ionic/{p-94180ecc.entry.js → p-7349de07.entry.js} +1 -1
  430. package/dist/ionic/p-7402fcdf.entry.js +4 -0
  431. package/dist/ionic/{p-5ff497dc.system.entry.js → p-77731f19.system.entry.js} +1 -1
  432. package/dist/ionic/{p-c07e7a5d.entry.js → p-78405458.entry.js} +1 -1
  433. package/dist/ionic/{p-748e6b2b.system.entry.js → p-7d6fd45f.system.entry.js} +1 -1
  434. package/dist/ionic/{p-720927ad.entry.js → p-7eb47906.entry.js} +1 -1
  435. package/dist/ionic/p-80265a58.entry.js +4 -0
  436. package/dist/ionic/{p-8627f783.system.entry.js → p-83d748f8.system.entry.js} +2 -2
  437. package/dist/ionic/p-842c9fca.system.js +4 -0
  438. package/dist/ionic/{p-c7e0b81a.entry.js → p-8a03fbee.entry.js} +1 -1
  439. package/dist/ionic/{p-576786c0.system.entry.js → p-8cb80f83.system.entry.js} +1 -1
  440. package/dist/ionic/{p-cdee3a44.system.entry.js → p-8d14ee8c.system.entry.js} +2 -2
  441. package/dist/ionic/p-90dfc454.system.entry.js +4 -0
  442. package/dist/ionic/{p-819e8479.system.entry.js → p-9213681c.system.entry.js} +1 -1
  443. package/dist/ionic/p-92d7e99d.system.js +4 -0
  444. package/dist/ionic/{p-d6229f05.system.entry.js → p-9664a1a2.system.entry.js} +1 -1
  445. package/dist/ionic/{p-b799a007.entry.js → p-9797f6eb.entry.js} +1 -1
  446. package/dist/ionic/{p-5d4d89e0.system.entry.js → p-9848d7be.system.entry.js} +1 -1
  447. package/dist/ionic/{p-9384565a.entry.js → p-98f6116f.entry.js} +1 -1
  448. package/dist/ionic/{p-c62571da.entry.js → p-99884813.entry.js} +1 -1
  449. package/dist/ionic/{p-48888af6.system.entry.js → p-99ca9787.system.entry.js} +1 -1
  450. package/dist/ionic/{p-45034312.system.entry.js → p-9bfd7cda.system.entry.js} +1 -1
  451. package/dist/ionic/p-9c6dcf78.system.entry.js +4 -0
  452. package/dist/ionic/{p-051d2d23.js → p-9da86308.js} +1 -1
  453. package/dist/ionic/{p-34511b1d.js → p-9ec42be0.js} +1 -1
  454. package/dist/ionic/{p-0d960144.system.entry.js → p-a2e94ade.system.entry.js} +1 -1
  455. package/dist/ionic/{p-1980c728.system.js → p-a39d3482.system.js} +1 -1
  456. package/dist/ionic/p-a488b7ab.system.js +4 -0
  457. package/dist/ionic/{p-5d80b741.entry.js → p-a4ab7449.entry.js} +1 -1
  458. package/dist/ionic/{p-2c3c7cb9.system.entry.js → p-a50f23bf.system.entry.js} +2 -2
  459. package/dist/ionic/{p-80f85095.system.entry.js → p-a76ab3ea.system.entry.js} +1 -1
  460. package/dist/ionic/{p-77ce6034.js → p-a953ef66.js} +1 -1
  461. package/dist/ionic/{p-08c4d048.entry.js → p-aaaaaea1.entry.js} +1 -1
  462. package/dist/ionic/{p-c23627c3.entry.js → p-b02eda30.entry.js} +1 -1
  463. package/dist/ionic/{p-49cdc4f2.entry.js → p-b04c27d8.entry.js} +1 -1
  464. package/dist/ionic/{p-0b12d1ee.system.entry.js → p-b07affd5.system.entry.js} +1 -1
  465. package/dist/ionic/{p-2f308f7f.system.entry.js → p-b28d3ccb.system.entry.js} +2 -2
  466. package/dist/ionic/{p-320cfcab.entry.js → p-b563b6ac.entry.js} +1 -1
  467. package/dist/ionic/p-b62ae60a.system.entry.js +4 -0
  468. package/dist/ionic/p-b9181033.system.entry.js +4 -0
  469. package/dist/ionic/{p-1930d8e7.entry.js → p-ba70039f.entry.js} +1 -1
  470. package/dist/ionic/{p-b571cab1.entry.js → p-bbbe869e.entry.js} +1 -1
  471. package/dist/ionic/{p-283fd4e1.system.entry.js → p-c41435e6.system.entry.js} +1 -1
  472. package/dist/ionic/p-cec8589b.system.js +4 -0
  473. package/dist/ionic/{p-bbbe3138.system.entry.js → p-d69b26d9.system.entry.js} +1 -1
  474. package/dist/ionic/p-d73a16e6.system.entry.js +4 -0
  475. package/dist/ionic/p-dba5cb84.js +5 -0
  476. package/dist/ionic/{p-63265e00.system.entry.js → p-dc0d9ff5.system.entry.js} +2 -2
  477. package/dist/ionic/{p-f5c42f72.entry.js → p-dc1e363a.entry.js} +1 -1
  478. package/dist/ionic/{p-c9ba1908.entry.js → p-df517d1f.entry.js} +1 -1
  479. package/dist/ionic/{p-2a3e98fb.system.entry.js → p-e0a8ffd0.system.entry.js} +1 -1
  480. package/dist/ionic/{p-e9ef13be.system.entry.js → p-e6e197f5.system.entry.js} +1 -1
  481. package/dist/ionic/{p-0af79ebd.entry.js → p-e6e88ab9.entry.js} +1 -1
  482. package/dist/ionic/{p-4e5288de.system.js → p-e81f22e3.system.js} +1 -1
  483. package/dist/ionic/{p-aa0f60b2.system.js → p-eb3023c9.system.js} +1 -1
  484. package/dist/ionic/p-ecbdbf25.system.entry.js +4 -0
  485. package/dist/ionic/{p-26d33af2.system.entry.js → p-ed5aebaa.system.entry.js} +1 -1
  486. package/dist/ionic/{p-23e440b6.entry.js → p-f357707e.entry.js} +1 -1
  487. package/dist/ionic/{p-e885f3c4.entry.js → p-f53bcebd.entry.js} +1 -1
  488. package/dist/ionic/p-f9baf25c.entry.js +4 -0
  489. package/dist/ionic/{p-ee3bbaf2.entry.js → p-fa8f2e62.entry.js} +1 -1
  490. package/dist/ionic/{p-6e9bd6ba.system.entry.js → p-fb21fd1c.system.entry.js} +1 -1
  491. package/dist/ionic/{p-bdd3053f.entry.js → p-fcecca8f.entry.js} +1 -1
  492. package/dist/types/components/accordion-group/accordion-group.d.ts +3 -4
  493. package/dist/types/components/checkbox/checkbox.d.ts +3 -4
  494. package/dist/types/components/content/content.d.ts +8 -0
  495. package/dist/types/components/datetime/datetime.d.ts +2 -0
  496. package/dist/types/components/input/input.d.ts +6 -0
  497. package/dist/types/components/modal/modal-interface.d.ts +1 -0
  498. package/dist/types/components/modal/modal.d.ts +18 -0
  499. package/dist/types/components/picker-column/picker-column.d.ts +37 -0
  500. package/dist/types/components/popover/popover-interface.d.ts +1 -0
  501. package/dist/types/components/popover/popover.d.ts +18 -0
  502. package/dist/types/components/radio-group/radio-group.d.ts +2 -0
  503. package/dist/types/components/range/range.d.ts +1 -1
  504. package/dist/types/components/searchbar/searchbar.d.ts +2 -0
  505. package/dist/types/components/segment/segment.d.ts +3 -2
  506. package/dist/types/components/select/select.d.ts +2 -0
  507. package/dist/types/components/textarea/textarea.d.ts +2 -0
  508. package/dist/types/components/toggle/toggle.d.ts +3 -2
  509. package/dist/types/components.d.ts +44 -12
  510. package/dist/types/utils/config.d.ts +9 -0
  511. package/dist/types/utils/focus-controller/index.d.ts +13 -0
  512. package/dist/types/utils/overlays.d.ts +1 -0
  513. package/hydrate/index.js +43566 -39256
  514. package/package.json +6 -6
  515. package/dist/cjs/index-1437d080.js +0 -11980
  516. package/dist/esm/index-5dc2b88e.js +0 -11942
  517. package/dist/esm-es5/app-globals-3cbaf9d9.js +0 -4
  518. package/dist/esm-es5/index-5dc2b88e.js +0 -18
  519. package/dist/esm-es5/index-f7fbe1fb.js +0 -4
  520. package/dist/esm-es5/ios.transition-a0041e41.js +0 -4
  521. package/dist/esm-es5/md.transition-0c0602d9.js +0 -4
  522. package/dist/ionic/p-06d5221c.js +0 -4
  523. package/dist/ionic/p-06fad524.system.js +0 -4
  524. package/dist/ionic/p-0d56dea9.entry.js +0 -4
  525. package/dist/ionic/p-13bfcef4.system.entry.js +0 -4
  526. package/dist/ionic/p-16016625.system.js +0 -4
  527. package/dist/ionic/p-20304962.js +0 -4
  528. package/dist/ionic/p-2dfdda15.system.entry.js +0 -4
  529. package/dist/ionic/p-2fa34b5c.entry.js +0 -4
  530. package/dist/ionic/p-32048e4c.system.js +0 -18
  531. package/dist/ionic/p-385964e6.entry.js +0 -4
  532. package/dist/ionic/p-4324e8a4.entry.js +0 -4
  533. package/dist/ionic/p-45664cb9.system.js +0 -4
  534. package/dist/ionic/p-4ad48ec9.system.entry.js +0 -4
  535. package/dist/ionic/p-4af0b730.js +0 -8
  536. package/dist/ionic/p-4fcef939.entry.js +0 -4
  537. package/dist/ionic/p-567a21a2.system.entry.js +0 -4
  538. package/dist/ionic/p-583f8865.system.entry.js +0 -4
  539. package/dist/ionic/p-58f89707.js +0 -4
  540. package/dist/ionic/p-7536b4b3.system.js +0 -4
  541. package/dist/ionic/p-7ef5bb32.entry.js +0 -4
  542. package/dist/ionic/p-8664c316.entry.js +0 -4
  543. package/dist/ionic/p-8c4fc85f.system.js +0 -4
  544. package/dist/ionic/p-8e031d97.entry.js +0 -4
  545. package/dist/ionic/p-8f48c966.system.entry.js +0 -4
  546. package/dist/ionic/p-adb896a0.entry.js +0 -4
  547. package/dist/ionic/p-b0093947.system.js +0 -4
  548. package/dist/ionic/p-cb4f96f3.system.js +0 -4
  549. package/dist/ionic/p-cc856712.entry.js +0 -4
  550. package/dist/ionic/p-cd1b9056.js +0 -4
  551. package/dist/ionic/p-d918e7ef.system.entry.js +0 -4
  552. package/dist/ionic/p-df062892.system.entry.js +0 -4
  553. package/dist/ionic/p-f0be340f.entry.js +0 -4
  554. package/dist/ionic/p-fdf40b09.js +0 -4
@@ -0,0 +1,112 @@
1
+ /*!
2
+ * (C) Ionic http://ionicframework.com - MIT License
3
+ */
4
+ import { config } from "../../global/config";
5
+ import { printIonWarning } from "../logging/index";
6
+ /**
7
+ * Moves focus to a specified element. Note that we do not remove the tabindex
8
+ * because that can result in an unintentional blur. Non-focusables can't be
9
+ * focused, so the body will get focused again.
10
+ */
11
+ const moveFocus = (el) => {
12
+ el.tabIndex = -1;
13
+ el.focus();
14
+ };
15
+ /**
16
+ * Elements that are hidden using `display: none` should not be focused even if
17
+ * they are present in the DOM.
18
+ */
19
+ const isVisible = (el) => {
20
+ return el.offsetParent !== null;
21
+ };
22
+ /**
23
+ * The focus controller allows us to manage focus within a view so assistive
24
+ * technologies can inform users of changes to the navigation state. Traditional
25
+ * native apps have a way of informing assistive technology about a navigation
26
+ * state change. Mobile browsers have this too, but only when doing a full page
27
+ * load. In a single page app we do not do that, so we need to build this
28
+ * integration ourselves.
29
+ */
30
+ export const createFocusController = () => {
31
+ const saveViewFocus = (referenceEl) => {
32
+ const focusManagerEnabled = config.get('focusManagerPriority', false);
33
+ /**
34
+ * When going back to a previously visited page focus should typically be moved
35
+ * back to the element that was last focused when the user was on this view.
36
+ */
37
+ if (focusManagerEnabled) {
38
+ const activeEl = document.activeElement;
39
+ if (activeEl !== null && (referenceEl === null || referenceEl === void 0 ? void 0 : referenceEl.contains(activeEl))) {
40
+ activeEl.setAttribute(LAST_FOCUS, 'true');
41
+ }
42
+ }
43
+ };
44
+ const setViewFocus = (referenceEl) => {
45
+ const focusManagerPriorities = config.get('focusManagerPriority', false);
46
+ /**
47
+ * If the focused element is a descendant of the referenceEl then it's possible
48
+ * that the app developer manually moved focus, so we do not want to override that.
49
+ * This can happen with inputs the are focused when a view transitions in.
50
+ */
51
+ if (Array.isArray(focusManagerPriorities) && !referenceEl.contains(document.activeElement)) {
52
+ /**
53
+ * When going back to a previously visited view focus should always be moved back
54
+ * to the element that the user was last focused on when they were on this view.
55
+ */
56
+ const lastFocus = referenceEl.querySelector(`[${LAST_FOCUS}]`);
57
+ if (lastFocus && isVisible(lastFocus)) {
58
+ moveFocus(lastFocus);
59
+ return;
60
+ }
61
+ for (const priority of focusManagerPriorities) {
62
+ /**
63
+ * For each recognized case (excluding the default case) make sure to return
64
+ * so that the fallback focus behavior does not run.
65
+ *
66
+ * We intentionally query for specific roles/semantic elements so that the
67
+ * transition manager can work with both Ionic and non-Ionic UI components.
68
+ *
69
+ * If new selectors are added, be sure to remove the outline ring by adding
70
+ * new selectors to rule in core.scss.
71
+ */
72
+ switch (priority) {
73
+ case 'content':
74
+ const content = referenceEl.querySelector('main, [role="main"]');
75
+ if (content && isVisible(content)) {
76
+ moveFocus(content);
77
+ return;
78
+ }
79
+ break;
80
+ case 'heading':
81
+ const headingOne = referenceEl.querySelector('h1, [role="heading"][aria-level="1"]');
82
+ if (headingOne && isVisible(headingOne)) {
83
+ moveFocus(headingOne);
84
+ return;
85
+ }
86
+ break;
87
+ case 'banner':
88
+ const header = referenceEl.querySelector('header, [role="banner"]');
89
+ if (header && isVisible(header)) {
90
+ moveFocus(header);
91
+ return;
92
+ }
93
+ break;
94
+ default:
95
+ printIonWarning(`Unrecognized focus manager priority value ${priority}`);
96
+ break;
97
+ }
98
+ }
99
+ /**
100
+ * If there is nothing to focus then focus the page so focus at least moves to
101
+ * the correct view. The browser will then determine where within the page to
102
+ * move focus to.
103
+ */
104
+ moveFocus(referenceEl);
105
+ }
106
+ };
107
+ return {
108
+ saveViewFocus,
109
+ setViewFocus,
110
+ };
111
+ };
112
+ const LAST_FOCUS = 'ion-last-focus';
@@ -0,0 +1,52 @@
1
+ /*!
2
+ * (C) Ionic http://ionicframework.com - MIT License
3
+ */
4
+ import { expect } from "@playwright/test";
5
+ import { configs, test } from "../../../test/playwright/index";
6
+ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
7
+ test.describe(title('focus controller: generic components'), () => {
8
+ test.beforeEach(async ({ page }) => {
9
+ await page.goto('/src/utils/focus-controller/test/generic', config);
10
+ });
11
+ test('should focus heading', async ({ page }) => {
12
+ const goToPageOneButton = page.locator('page-root button.page-one');
13
+ const nav = page.locator('ion-nav');
14
+ const ionNavDidChange = await nav.spyOnEvent('ionNavDidChange');
15
+ // Focus heading on Page One
16
+ await goToPageOneButton.click();
17
+ await ionNavDidChange.next();
18
+ const pageOneTitle = page.locator('page-one h1');
19
+ await expect(pageOneTitle).toBeFocused();
20
+ });
21
+ test('should focus banner', async ({ page }) => {
22
+ const goToPageThreeButton = page.locator('page-root button.page-three');
23
+ const nav = page.locator('ion-nav');
24
+ const ionNavDidChange = await nav.spyOnEvent('ionNavDidChange');
25
+ const pageThreeHeader = page.locator('page-three header');
26
+ await goToPageThreeButton.click();
27
+ await ionNavDidChange.next();
28
+ await expect(pageThreeHeader).toBeFocused();
29
+ });
30
+ test('should focus content', async ({ page }) => {
31
+ const goToPageTwoButton = page.locator('page-root button.page-two');
32
+ const nav = page.locator('ion-nav');
33
+ const ionNavDidChange = await nav.spyOnEvent('ionNavDidChange');
34
+ const pageTwoContent = page.locator('page-two main');
35
+ await goToPageTwoButton.click();
36
+ await ionNavDidChange.next();
37
+ await expect(pageTwoContent).toBeFocused();
38
+ });
39
+ test('should return focus when going back', async ({ page, browserName }) => {
40
+ test.skip(browserName === 'webkit', 'Desktop Safari does not consider buttons to be focusable');
41
+ const goToPageOneButton = page.locator('page-root button.page-one');
42
+ const nav = page.locator('ion-nav');
43
+ const ionNavDidChange = await nav.spyOnEvent('ionNavDidChange');
44
+ const pageOneBackButton = page.locator('page-one ion-back-button');
45
+ await goToPageOneButton.click();
46
+ await ionNavDidChange.next();
47
+ await pageOneBackButton.click();
48
+ await ionNavDidChange.next();
49
+ await expect(goToPageOneButton).toBeFocused();
50
+ });
51
+ });
52
+ });
@@ -0,0 +1,52 @@
1
+ /*!
2
+ * (C) Ionic http://ionicframework.com - MIT License
3
+ */
4
+ import { expect } from "@playwright/test";
5
+ import { configs, test } from "../../../test/playwright/index";
6
+ configs({ modes: ['md'], directions: ['ltr'] }).forEach(({ title, config }) => {
7
+ test.describe(title('focus controller: ionic components'), () => {
8
+ test.beforeEach(async ({ page }) => {
9
+ await page.goto('/src/utils/focus-controller/test/ionic', config);
10
+ });
11
+ test('should focus heading', async ({ page }) => {
12
+ const goToPageOneButton = page.locator('page-root ion-button.page-one');
13
+ const nav = page.locator('ion-nav');
14
+ const ionNavDidChange = await nav.spyOnEvent('ionNavDidChange');
15
+ // Focus heading on Page One
16
+ await goToPageOneButton.click();
17
+ await ionNavDidChange.next();
18
+ const pageOneTitle = page.locator('page-one ion-title');
19
+ await expect(pageOneTitle).toBeFocused();
20
+ });
21
+ test('should focus banner', async ({ page }) => {
22
+ const goToPageThreeButton = page.locator('page-root ion-button.page-three');
23
+ const nav = page.locator('ion-nav');
24
+ const ionNavDidChange = await nav.spyOnEvent('ionNavDidChange');
25
+ const pageThreeHeader = page.locator('page-three ion-header');
26
+ await goToPageThreeButton.click();
27
+ await ionNavDidChange.next();
28
+ await expect(pageThreeHeader).toBeFocused();
29
+ });
30
+ test('should focus content', async ({ page }) => {
31
+ const goToPageTwoButton = page.locator('page-root ion-button.page-two');
32
+ const nav = page.locator('ion-nav');
33
+ const ionNavDidChange = await nav.spyOnEvent('ionNavDidChange');
34
+ const pageTwoContent = page.locator('page-two ion-content');
35
+ await goToPageTwoButton.click();
36
+ await ionNavDidChange.next();
37
+ await expect(pageTwoContent).toBeFocused();
38
+ });
39
+ test('should return focus when going back', async ({ page, browserName }) => {
40
+ test.skip(browserName === 'webkit', 'Desktop Safari does not consider buttons to be focusable');
41
+ const goToPageOneButton = page.locator('page-root ion-button.page-one');
42
+ const nav = page.locator('ion-nav');
43
+ const ionNavDidChange = await nav.spyOnEvent('ionNavDidChange');
44
+ const pageOneBackButton = page.locator('page-one ion-back-button');
45
+ await goToPageOneButton.click();
46
+ await ionNavDidChange.next();
47
+ await pageOneBackButton.click();
48
+ await ionNavDidChange.next();
49
+ await expect(goToPageOneButton).toBeFocused();
50
+ });
51
+ });
52
+ });
@@ -152,7 +152,7 @@ const trapKeyboardFocus = (ev, doc) => {
152
152
  * behind the sheet should be focusable until
153
153
  * the backdrop is enabled.
154
154
  */
155
- if (lastOverlay.classList.contains('ion-disable-focus-trap')) {
155
+ if (lastOverlay.classList.contains(FOCUS_TRAP_DISABLE_CLASS)) {
156
156
  return;
157
157
  }
158
158
  const trapScopedFocus = () => {
@@ -827,3 +827,4 @@ const revealOverlaysToScreenReaders = () => {
827
827
  }
828
828
  }
829
829
  };
830
+ export const FOCUS_TRAP_DISABLE_CLASS = 'ion-disable-focus-trap';
@@ -1,11 +1,14 @@
1
1
  /*!
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
+ import { config } from "../../global/config";
4
5
  import { Build, writeTask } from "@stencil/core";
5
6
  import { LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_ENTER, LIFECYCLE_WILL_LEAVE, } from "../../components/nav/constants";
7
+ import { createFocusController } from "../focus-controller";
6
8
  import { raf } from "../helpers";
7
9
  const iosTransitionAnimation = () => import('./ios.transition');
8
10
  const mdTransitionAnimation = () => import('./md.transition');
11
+ const focusController = createFocusController();
9
12
  // TODO(FW-2832): types
10
13
  export const transition = (opts) => {
11
14
  return new Promise((resolve, reject) => {
@@ -27,6 +30,7 @@ export const transition = (opts) => {
27
30
  const beforeTransition = (opts) => {
28
31
  const enteringEl = opts.enteringEl;
29
32
  const leavingEl = opts.leavingEl;
33
+ focusController.saveViewFocus(leavingEl);
30
34
  setZIndex(enteringEl, leavingEl, opts.direction);
31
35
  if (opts.showGoBack) {
32
36
  enteringEl.classList.add('can-go-back');
@@ -61,6 +65,7 @@ const afterTransition = (opts) => {
61
65
  leavingEl.classList.remove('ion-page-invisible');
62
66
  leavingEl.style.removeProperty('pointer-events');
63
67
  }
68
+ focusController.setViewFocus(enteringEl);
64
69
  };
65
70
  const getAnimationBuilder = async (opts) => {
66
71
  if (!opts.leavingEl || !opts.animated || opts.duration === 0) {
@@ -93,7 +98,12 @@ const animation = async (animationBuilder, opts) => {
93
98
  const noAnimation = async (opts) => {
94
99
  const enteringEl = opts.enteringEl;
95
100
  const leavingEl = opts.leavingEl;
96
- await waitForReady(opts, false);
101
+ const focusManagerEnabled = config.get('focusManagerPriority', false);
102
+ /**
103
+ * If the focus manager is enabled then we need to wait for Ionic components to be
104
+ * rendered otherwise the component to focus may not be focused because it is hidden.
105
+ */
106
+ await waitForReady(opts, focusManagerEnabled);
97
107
  fireWillEvents(enteringEl, leavingEl);
98
108
  fireDidEvents(enteringEl, leavingEl);
99
109
  return {
@@ -55,20 +55,22 @@ const createLargeTitleTransition = (rootAnimation, rtl, backDirection, enteringE
55
55
  const leavingLargeTitleBox = leavingLargeTitle.getBoundingClientRect();
56
56
  const enteringBackButtonBox = enteringBackButton.getBoundingClientRect();
57
57
  const enteringBackButtonTextEl = shadow(enteringBackButton).querySelector('.button-text');
58
- const enteringBackButtonTextBox = enteringBackButtonTextEl.getBoundingClientRect();
58
+ // Text element not rendered if developers pass text="" to the back button
59
+ const enteringBackButtonTextBox = enteringBackButtonTextEl === null || enteringBackButtonTextEl === void 0 ? void 0 : enteringBackButtonTextEl.getBoundingClientRect();
59
60
  const leavingLargeTitleTextEl = shadow(leavingLargeTitle).querySelector('.toolbar-title');
60
61
  const leavingLargeTitleTextBox = leavingLargeTitleTextEl.getBoundingClientRect();
61
- animateLargeTitle(rootAnimation, rtl, backDirection, leavingLargeTitle, leavingLargeTitleBox, leavingLargeTitleTextBox, enteringBackButtonTextEl, enteringBackButtonTextBox);
62
+ animateLargeTitle(rootAnimation, rtl, backDirection, leavingLargeTitle, leavingLargeTitleBox, leavingLargeTitleTextBox, enteringBackButtonBox, enteringBackButtonTextEl, enteringBackButtonTextBox);
62
63
  animateBackButton(rootAnimation, rtl, backDirection, enteringBackButton, enteringBackButtonBox, enteringBackButtonTextEl, enteringBackButtonTextBox, leavingLargeTitle, leavingLargeTitleTextBox);
63
64
  }
64
65
  else if (shouldAnimationBackward) {
65
66
  const enteringLargeTitleBox = enteringLargeTitle.getBoundingClientRect();
66
67
  const leavingBackButtonBox = leavingBackButton.getBoundingClientRect();
67
68
  const leavingBackButtonTextEl = shadow(leavingBackButton).querySelector('.button-text');
68
- const leavingBackButtonTextBox = leavingBackButtonTextEl.getBoundingClientRect();
69
+ // Text element not rendered if developers pass text="" to the back button
70
+ const leavingBackButtonTextBox = leavingBackButtonTextEl === null || leavingBackButtonTextEl === void 0 ? void 0 : leavingBackButtonTextEl.getBoundingClientRect();
69
71
  const enteringLargeTitleTextEl = shadow(enteringLargeTitle).querySelector('.toolbar-title');
70
72
  const enteringLargeTitleTextBox = enteringLargeTitleTextEl.getBoundingClientRect();
71
- animateLargeTitle(rootAnimation, rtl, backDirection, enteringLargeTitle, enteringLargeTitleBox, enteringLargeTitleTextBox, leavingBackButtonTextEl, leavingBackButtonTextBox);
73
+ animateLargeTitle(rootAnimation, rtl, backDirection, enteringLargeTitle, enteringLargeTitleBox, enteringLargeTitleTextBox, leavingBackButtonBox, leavingBackButtonTextEl, leavingBackButtonTextBox);
72
74
  animateBackButton(rootAnimation, rtl, backDirection, leavingBackButton, leavingBackButtonBox, leavingBackButtonTextEl, leavingBackButtonTextBox, enteringLargeTitle, enteringLargeTitleTextBox);
73
75
  }
74
76
  return {
@@ -82,26 +84,31 @@ const animateBackButton = (rootAnimation, rtl, backDirection, backButtonEl, back
82
84
  const TEXT_ORIGIN_X = rtl ? 'right' : 'left';
83
85
  const ICON_ORIGIN_X = rtl ? 'left' : 'right';
84
86
  const CONTAINER_ORIGIN_X = rtl ? 'right' : 'left';
85
- /**
86
- * When the title and back button texts match
87
- * then they should overlap during the page transition.
88
- * If the texts do not match up then the back button text scale adjusts
89
- * to not perfectly match the large title text otherwise the
90
- * proportions will be incorrect.
91
- * When the texts match we scale both the width and height to account for
92
- * font weight differences between the title and back button.
93
- */
94
- const doTitleAndButtonTextsMatch = ((_a = backButtonTextEl.textContent) === null || _a === void 0 ? void 0 : _a.trim()) === ((_b = largeTitleEl.textContent) === null || _b === void 0 ? void 0 : _b.trim());
95
- const WIDTH_SCALE = largeTitleTextBox.width / backButtonTextBox.width;
96
- /**
97
- * We subtract an offset to account for slight sizing/padding
98
- * differences between the title and the back button.
99
- */
100
- const HEIGHT_SCALE = (largeTitleTextBox.height - LARGE_TITLE_SIZE_OFFSET) / backButtonTextBox.height;
101
- const TEXT_START_SCALE = doTitleAndButtonTextsMatch
102
- ? `scale(${WIDTH_SCALE}, ${HEIGHT_SCALE})`
103
- : `scale(${HEIGHT_SCALE})`;
87
+ let WIDTH_SCALE = 1;
88
+ let HEIGHT_SCALE = 1;
89
+ let TEXT_START_SCALE = `scale(${HEIGHT_SCALE})`;
104
90
  const TEXT_END_SCALE = 'scale(1)';
91
+ if (backButtonTextEl && backButtonTextBox) {
92
+ /**
93
+ * When the title and back button texts match then they should overlap during the
94
+ * page transition. If the texts do not match up then the back button text scale
95
+ * adjusts to not perfectly match the large title text otherwise the proportions
96
+ * will be incorrect. When the texts match we scale both the width and height to
97
+ * account for font weight differences between the title and back button.
98
+ */
99
+ const doTitleAndButtonTextsMatch = ((_a = backButtonTextEl.textContent) === null || _a === void 0 ? void 0 : _a.trim()) === ((_b = largeTitleEl.textContent) === null || _b === void 0 ? void 0 : _b.trim());
100
+ WIDTH_SCALE = largeTitleTextBox.width / backButtonTextBox.width;
101
+ /**
102
+ * Subtract an offset to account for slight sizing/padding differences between the
103
+ * title and the back button.
104
+ */
105
+ HEIGHT_SCALE = (largeTitleTextBox.height - LARGE_TITLE_SIZE_OFFSET) / backButtonTextBox.height;
106
+ /**
107
+ * Even though we set TEXT_START_SCALE to HEIGHT_SCALE above, we potentially need
108
+ * to re-compute this here since the HEIGHT_SCALE may have changed.
109
+ */
110
+ TEXT_START_SCALE = doTitleAndButtonTextsMatch ? `scale(${WIDTH_SCALE}, ${HEIGHT_SCALE})` : `scale(${HEIGHT_SCALE})`;
111
+ }
105
112
  const backButtonIconEl = shadow(backButtonEl).querySelector('ion-icon');
106
113
  const backButtonIconBox = backButtonIconEl.getBoundingClientRect();
107
114
  /**
@@ -198,11 +205,11 @@ const animateBackButton = (rootAnimation, rtl, backDirection, backButtonEl, back
198
205
  top: '0px',
199
206
  [CONTAINER_ORIGIN_X]: '0px',
200
207
  })
201
- .keyframes(CONTAINER_KEYFRAMES);
202
- enteringBackButtonTextAnimation
203
- .beforeStyles({
204
- 'transform-origin': `${TEXT_ORIGIN_X} top`,
205
- })
208
+ /**
209
+ * The write hooks must be set on this animation as it is guaranteed to run. Other
210
+ * animations such as the back button text animation will not run if the back button
211
+ * has no visible text.
212
+ */
206
213
  .beforeAddWrite(() => {
207
214
  backButtonEl.style.setProperty('display', 'none');
208
215
  clonedBackButtonEl.style.setProperty(TEXT_ORIGIN_X, BACK_BUTTON_START_OFFSET);
@@ -211,6 +218,11 @@ const animateBackButton = (rootAnimation, rtl, backDirection, backButtonEl, back
211
218
  backButtonEl.style.setProperty('display', '');
212
219
  clonedBackButtonEl.style.setProperty('display', 'none');
213
220
  clonedBackButtonEl.style.removeProperty(TEXT_ORIGIN_X);
221
+ })
222
+ .keyframes(CONTAINER_KEYFRAMES);
223
+ enteringBackButtonTextAnimation
224
+ .beforeStyles({
225
+ 'transform-origin': `${TEXT_ORIGIN_X} top`,
214
226
  })
215
227
  .keyframes(TEXT_KEYFRAMES);
216
228
  enteringBackButtonIconAnimation
@@ -224,7 +236,7 @@ const animateBackButton = (rootAnimation, rtl, backDirection, backButtonEl, back
224
236
  enteringBackButtonAnimation,
225
237
  ]);
226
238
  };
227
- const animateLargeTitle = (rootAnimation, rtl, backDirection, largeTitleEl, largeTitleBox, largeTitleTextBox, backButtonTextEl, backButtonTextBox) => {
239
+ const animateLargeTitle = (rootAnimation, rtl, backDirection, largeTitleEl, largeTitleBox, largeTitleTextBox, backButtonBox, backButtonTextEl, backButtonTextBox) => {
228
240
  var _a, _b;
229
241
  /**
230
242
  * The horizontal transform origin for the large title
@@ -244,52 +256,67 @@ const animateLargeTitle = (rootAnimation, rtl, backDirection, largeTitleEl, larg
244
256
  * title and the back button due to padding and font weight.
245
257
  */
246
258
  const LARGE_TITLE_TRANSLATION_OFFSET = 8;
259
+ let END_TRANSLATE_X = rtl
260
+ ? `-${window.innerWidth - backButtonBox.right - LARGE_TITLE_TRANSLATION_OFFSET}px`
261
+ : `${backButtonBox.x + LARGE_TITLE_TRANSLATION_OFFSET}px`;
247
262
  /**
248
- * The scaled title should (roughly) overlap the back button.
249
- * This ensures that the back button and title overlap during
250
- * the animation. Note that since both elements either fade in
251
- * or fade out over the course of the animation, neither element
252
- * will be fully visible on top of the other. As a result, the overlap
253
- * does not need to be perfect, so approximate values are acceptable here.
263
+ * How much to scale the large title up/down by.
254
264
  */
255
- const END_TRANSLATE_X = rtl
256
- ? `-${window.innerWidth - backButtonTextBox.right - LARGE_TITLE_TRANSLATION_OFFSET}px`
257
- : `${backButtonTextBox.x - LARGE_TITLE_TRANSLATION_OFFSET}px`;
265
+ let HEIGHT_SCALE = 0.5;
258
266
  /**
259
- * The top of the scaled large title
260
- * should match with the top of the
261
- * back button text element.
262
- * We subtract 2px to account for the top padding
263
- * on the large title element.
267
+ * The large title always starts full size.
264
268
  */
265
- const LARGE_TITLE_TOP_PADDING = 2;
266
- const END_TRANSLATE_Y = `${backButtonTextBox.y - LARGE_TITLE_TOP_PADDING}px`;
269
+ const START_SCALE = 'scale(1)';
267
270
  /**
268
- * In the forward direction, the large title should start at its
269
- * normal size and then scale down to be (roughly) the size of the
270
- * back button on the other view. In the backward direction, the
271
- * large title should start at (roughly) the size of the back button
272
- * and then scale up to its original size.
273
- *
274
- * Note that since both elements either fade in
275
- * or fade out over the course of the animation, neither element
276
- * will be fully visible on top of the other. As a result, the overlap
277
- * does not need to be perfect, so approximate values are acceptable here.
271
+ * By default, we don't worry about having the large title scaled to perfectly
272
+ * match the back button because we don't know if the back button's text matches
273
+ * the large title's text.
278
274
  */
275
+ let END_SCALE = `scale(${HEIGHT_SCALE})`;
276
+ // Text element not rendered if developers pass text="" to the back button
277
+ if (backButtonTextEl && backButtonTextBox) {
278
+ /**
279
+ * The scaled title should (roughly) overlap the back button. This ensures that
280
+ * the back button and title overlap during the animation. Note that since both
281
+ * elements either fade in or fade out over the course of the animation, neither
282
+ * element will be fully visible on top of the other. As a result, the overlap
283
+ * does not need to be perfect, so approximate values are acceptable here.
284
+ */
285
+ END_TRANSLATE_X = rtl
286
+ ? `-${window.innerWidth - backButtonTextBox.right - LARGE_TITLE_TRANSLATION_OFFSET}px`
287
+ : `${backButtonTextBox.x - LARGE_TITLE_TRANSLATION_OFFSET}px`;
288
+ /**
289
+ * In the forward direction, the large title should start at its normal size and
290
+ * then scale down to be (roughly) the size of the back button on the other view.
291
+ * In the backward direction, the large title should start at (roughly) the size
292
+ * of the back button and then scale up to its original size.
293
+ * Note that since both elements either fade in or fade out over the course of the
294
+ * animation, neither element will be fully visible on top of the other. As a result,
295
+ * the overlap does not need to be perfect, so approximate values are acceptable here.
296
+ */
297
+ /**
298
+ * When the title and back button texts match then they should overlap during the
299
+ * page transition. If the texts do not match up then the large title text scale
300
+ * adjusts to not perfectly match the back button text otherwise the proportions
301
+ * will be incorrect. When the texts match we scale both the width and height to
302
+ * account for font weight differences between the title and back button.
303
+ */
304
+ const doTitleAndButtonTextsMatch = ((_a = backButtonTextEl.textContent) === null || _a === void 0 ? void 0 : _a.trim()) === ((_b = largeTitleEl.textContent) === null || _b === void 0 ? void 0 : _b.trim());
305
+ const WIDTH_SCALE = backButtonTextBox.width / largeTitleTextBox.width;
306
+ HEIGHT_SCALE = backButtonTextBox.height / (largeTitleTextBox.height - LARGE_TITLE_SIZE_OFFSET);
307
+ /**
308
+ * Even though we set TEXT_START_SCALE to HEIGHT_SCALE above, we potentially need
309
+ * to re-compute this here since the HEIGHT_SCALE may have changed.
310
+ */
311
+ END_SCALE = doTitleAndButtonTextsMatch ? `scale(${WIDTH_SCALE}, ${HEIGHT_SCALE})` : `scale(${HEIGHT_SCALE})`;
312
+ }
279
313
  /**
280
- * When the title and back button texts match
281
- * then they should overlap during the page transition.
282
- * If the texts do not match up then the large title text scale adjusts
283
- * to not perfectly match the back button text otherwise the
284
- * proportions will be incorrect.
285
- * When the texts match we scale both the width and height to account for
286
- * font weight differences between the title and back button.
314
+ * The midpoints of the back button and the title should align such that the back
315
+ * button and title appear to be centered with each other.
287
316
  */
288
- const doTitleAndButtonTextsMatch = ((_a = backButtonTextEl.textContent) === null || _a === void 0 ? void 0 : _a.trim()) === ((_b = largeTitleEl.textContent) === null || _b === void 0 ? void 0 : _b.trim());
289
- const WIDTH_SCALE = backButtonTextBox.width / largeTitleTextBox.width;
290
- const HEIGHT_SCALE = backButtonTextBox.height / (largeTitleTextBox.height - LARGE_TITLE_SIZE_OFFSET);
291
- const START_SCALE = 'scale(1)';
292
- const END_SCALE = doTitleAndButtonTextsMatch ? `scale(${WIDTH_SCALE}, ${HEIGHT_SCALE})` : `scale(${HEIGHT_SCALE})`;
317
+ const backButtonMidPoint = backButtonBox.top + backButtonBox.height / 2;
318
+ const titleMidPoint = (largeTitleBox.height * HEIGHT_SCALE) / 2;
319
+ const END_TRANSLATE_Y = `${backButtonMidPoint - titleMidPoint}px`;
293
320
  const BACKWARDS_KEYFRAMES = [
294
321
  { offset: 0, opacity: 0, transform: `translate3d(${END_TRANSLATE_X}, ${END_TRANSLATE_Y}, 0) ${END_SCALE}` },
295
322
  { offset: 0.1, opacity: 0 },