@rdlabo/ionic-theme-ios27 1.2.1-beta.pr275.shad339e7688db7 → 2.0.0-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (248) hide show
  1. package/README.md +24 -280
  2. package/dist/css/components/ion-toolbar.css +1 -1
  3. package/dist/css/ionic-theme-ios27.css +1 -1
  4. package/dist/css/vertical-bars.css +1 -1
  5. package/dist/index.d.ts +3 -2
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +3 -2
  8. package/dist/index.js.map +1 -1
  9. package/dist/layout/index.d.ts +18 -0
  10. package/dist/layout/index.d.ts.map +1 -0
  11. package/dist/layout/index.js +26 -0
  12. package/dist/layout/index.js.map +1 -0
  13. package/dist/segment/index.js +3 -3
  14. package/dist/segment/index.js.map +1 -1
  15. package/dist/sheets-of-glass/index.js +7 -7
  16. package/dist/sheets-of-glass/index.js.map +1 -1
  17. package/dist/tab-bar-searchable/dismiss-button.js +53 -3
  18. package/dist/tab-bar-searchable/dismiss-button.js.map +1 -1
  19. package/dist/tab-bar-searchable/index.js +18 -3
  20. package/dist/tab-bar-searchable/index.js.map +1 -1
  21. package/dist/transition/ios.transition.d.ts.map +1 -1
  22. package/dist/transition/ios.transition.js +7 -4
  23. package/dist/transition/ios.transition.js.map +1 -1
  24. package/dist/transition/native-ui.d.ts +6 -0
  25. package/dist/transition/native-ui.d.ts.map +1 -0
  26. package/dist/{native-integration/index.js → transition/native-ui.js} +16 -30
  27. package/dist/transition/native-ui.js.map +1 -0
  28. package/docs/adaptive-themes.md +161 -0
  29. package/docs/add-native-ui.md +53 -0
  30. package/docs/animation.md +19 -3
  31. package/docs/eslint.md +3 -1
  32. package/docs/features.md +9 -5
  33. package/docs/iphone-duo.md +62 -35
  34. package/docs/migration.md +17 -26
  35. package/docs/setup.md +92 -0
  36. package/docs/special-markup.md +41 -10
  37. package/docs/using-ion-item-group.md +2 -2
  38. package/docs/vertical-bars-layout.md +67 -0
  39. package/package.json +12 -42
  40. package/src/index.ts +3 -1
  41. package/src/layout/index.ts +29 -0
  42. package/src/segment/index.ts +3 -3
  43. package/src/sheets-of-glass/index.ts +7 -7
  44. package/src/styles/components/ion-toolbar.scss +1 -1
  45. package/src/styles/vertical-bars.scss +15 -18
  46. package/src/tab-bar-searchable/dismiss-button.ts +73 -4
  47. package/src/tab-bar-searchable/index.ts +20 -3
  48. package/src/transition/ios.transition.ts +7 -4
  49. package/src/{native-integration/index.ts → transition/native-ui.ts} +17 -46
  50. package/Package.swift +0 -21
  51. package/dist/_virtual/_rolldown/runtime.js +0 -13
  52. package/dist/native/components/index.d.ts +0 -19
  53. package/dist/native/components/index.d.ts.map +0 -1
  54. package/dist/native/components/index.js +0 -40
  55. package/dist/native/components/index.js.map +0 -1
  56. package/dist/native/components/ion-back-button.d.ts +0 -9
  57. package/dist/native/components/ion-back-button.d.ts.map +0 -1
  58. package/dist/native/components/ion-back-button.js +0 -20
  59. package/dist/native/components/ion-back-button.js.map +0 -1
  60. package/dist/native/components/ion-button.d.ts +0 -10
  61. package/dist/native/components/ion-button.d.ts.map +0 -1
  62. package/dist/native/components/ion-button.js +0 -23
  63. package/dist/native/components/ion-button.js.map +0 -1
  64. package/dist/native/components/ion-buttons.d.ts +0 -11
  65. package/dist/native/components/ion-buttons.d.ts.map +0 -1
  66. package/dist/native/components/ion-buttons.js +0 -30
  67. package/dist/native/components/ion-buttons.js.map +0 -1
  68. package/dist/native/components/ion-fab.d.ts +0 -10
  69. package/dist/native/components/ion-fab.d.ts.map +0 -1
  70. package/dist/native/components/ion-fab.js +0 -132
  71. package/dist/native/components/ion-fab.js.map +0 -1
  72. package/dist/native/components/ion-menu-button.d.ts +0 -13
  73. package/dist/native/components/ion-menu-button.d.ts.map +0 -1
  74. package/dist/native/components/ion-menu-button.js +0 -31
  75. package/dist/native/components/ion-menu-button.js.map +0 -1
  76. package/dist/native/components/ion-segment.d.ts +0 -11
  77. package/dist/native/components/ion-segment.d.ts.map +0 -1
  78. package/dist/native/components/ion-segment.js +0 -30
  79. package/dist/native/components/ion-segment.js.map +0 -1
  80. package/dist/native/components/ion-tab-bar.d.ts +0 -11
  81. package/dist/native/components/ion-tab-bar.d.ts.map +0 -1
  82. package/dist/native/components/ion-tab-bar.js +0 -50
  83. package/dist/native/components/ion-tab-bar.js.map +0 -1
  84. package/dist/native/components/searchable-tabs.d.ts +0 -20
  85. package/dist/native/components/searchable-tabs.d.ts.map +0 -1
  86. package/dist/native/components/searchable-tabs.js +0 -383
  87. package/dist/native/components/searchable-tabs.js.map +0 -1
  88. package/dist/native/definitions.d.ts +0 -191
  89. package/dist/native/definitions.d.ts.map +0 -1
  90. package/dist/native/definitions.js +0 -0
  91. package/dist/native/foldable/fold-state.d.ts +0 -5
  92. package/dist/native/foldable/fold-state.d.ts.map +0 -1
  93. package/dist/native/foldable/fold-state.js +0 -14
  94. package/dist/native/foldable/fold-state.js.map +0 -1
  95. package/dist/native/foldable/types.d.ts +0 -12
  96. package/dist/native/foldable/types.d.ts.map +0 -1
  97. package/dist/native/foldable/types.js +0 -0
  98. package/dist/native/index.d.ts +0 -11
  99. package/dist/native/index.d.ts.map +0 -1
  100. package/dist/native/index.js +0 -267
  101. package/dist/native/index.js.map +0 -1
  102. package/dist/native/overlays/content.d.ts +0 -4
  103. package/dist/native/overlays/content.d.ts.map +0 -1
  104. package/dist/native/overlays/content.js +0 -51
  105. package/dist/native/overlays/content.js.map +0 -1
  106. package/dist/native/overlays/controller.d.ts +0 -8
  107. package/dist/native/overlays/controller.d.ts.map +0 -1
  108. package/dist/native/overlays/controller.js +0 -285
  109. package/dist/native/overlays/controller.js.map +0 -1
  110. package/dist/native/overlays/dialog-animation.d.ts +0 -9
  111. package/dist/native/overlays/dialog-animation.d.ts.map +0 -1
  112. package/dist/native/overlays/dialog-animation.js +0 -53
  113. package/dist/native/overlays/dialog-animation.js.map +0 -1
  114. package/dist/native/overlays/dismiss-animation.d.ts +0 -4
  115. package/dist/native/overlays/dismiss-animation.d.ts.map +0 -1
  116. package/dist/native/overlays/dismiss-animation.js +0 -18
  117. package/dist/native/overlays/dismiss-animation.js.map +0 -1
  118. package/dist/native/overlays/focus.d.ts +0 -5
  119. package/dist/native/overlays/focus.d.ts.map +0 -1
  120. package/dist/native/overlays/focus.js +0 -59
  121. package/dist/native/overlays/focus.js.map +0 -1
  122. package/dist/native/overlays/popover.d.ts +0 -12
  123. package/dist/native/overlays/popover.d.ts.map +0 -1
  124. package/dist/native/overlays/popover.js +0 -110
  125. package/dist/native/overlays/popover.js.map +0 -1
  126. package/dist/native/overlays/styles.d.ts +0 -11
  127. package/dist/native/overlays/styles.d.ts.map +0 -1
  128. package/dist/native/overlays/styles.js +0 -167
  129. package/dist/native/overlays/styles.js.map +0 -1
  130. package/dist/native/prehide.d.ts +0 -7
  131. package/dist/native/prehide.d.ts.map +0 -1
  132. package/dist/native/prehide.js +0 -230
  133. package/dist/native/prehide.js.map +0 -1
  134. package/dist/native/runtime.d.ts +0 -7
  135. package/dist/native/runtime.d.ts.map +0 -1
  136. package/dist/native/runtime.js +0 -710
  137. package/dist/native/runtime.js.map +0 -1
  138. package/dist/native/shared/bridge.d.ts +0 -6
  139. package/dist/native/shared/bridge.d.ts.map +0 -1
  140. package/dist/native/shared/bridge.js +0 -18
  141. package/dist/native/shared/bridge.js.map +0 -1
  142. package/dist/native/shared/candidate.d.ts +0 -21
  143. package/dist/native/shared/candidate.d.ts.map +0 -1
  144. package/dist/native/shared/candidate.js +0 -98
  145. package/dist/native/shared/candidate.js.map +0 -1
  146. package/dist/native/shared/crossfade.d.ts +0 -12
  147. package/dist/native/shared/crossfade.d.ts.map +0 -1
  148. package/dist/native/shared/crossfade.js +0 -67
  149. package/dist/native/shared/crossfade.js.map +0 -1
  150. package/dist/native/shared/dom.d.ts +0 -46
  151. package/dist/native/shared/dom.d.ts.map +0 -1
  152. package/dist/native/shared/dom.js +0 -172
  153. package/dist/native/shared/dom.js.map +0 -1
  154. package/dist/native/shared/events.d.ts +0 -11
  155. package/dist/native/shared/events.d.ts.map +0 -1
  156. package/dist/native/shared/events.js +0 -13
  157. package/dist/native/shared/events.js.map +0 -1
  158. package/dist/native/shared/icons.d.ts +0 -8
  159. package/dist/native/shared/icons.d.ts.map +0 -1
  160. package/dist/native/shared/icons.js +0 -61
  161. package/dist/native/shared/icons.js.map +0 -1
  162. package/dist/native/shared/modal.d.ts +0 -10
  163. package/dist/native/shared/modal.d.ts.map +0 -1
  164. package/dist/native/shared/modal.js +0 -160
  165. package/dist/native/shared/modal.js.map +0 -1
  166. package/dist/native/shared/projection-id.d.ts +0 -4
  167. package/dist/native/shared/projection-id.d.ts.map +0 -1
  168. package/dist/native/shared/projection-id.js +0 -7
  169. package/dist/native/shared/projection-id.js.map +0 -1
  170. package/dist/native/shared/vertical-bars-geometry.d.ts +0 -10
  171. package/dist/native/shared/vertical-bars-geometry.d.ts.map +0 -1
  172. package/dist/native/shared/vertical-bars-geometry.js +0 -85
  173. package/dist/native/shared/vertical-bars-geometry.js.map +0 -1
  174. package/dist/native/vertical-bars-web-search.d.ts +0 -10
  175. package/dist/native/vertical-bars-web-search.d.ts.map +0 -1
  176. package/dist/native/vertical-bars-web-search.js +0 -90
  177. package/dist/native/vertical-bars-web-search.js.map +0 -1
  178. package/dist/native/vertical-bars-web.d.ts +0 -5
  179. package/dist/native/vertical-bars-web.d.ts.map +0 -1
  180. package/dist/native/vertical-bars-web.js +0 -411
  181. package/dist/native/vertical-bars-web.js.map +0 -1
  182. package/dist/native-integration/index.d.ts +0 -23
  183. package/dist/native-integration/index.d.ts.map +0 -1
  184. package/dist/native-integration/index.js.map +0 -1
  185. package/dist/native-integration/transition.d.ts +0 -5
  186. package/dist/native-integration/transition.d.ts.map +0 -1
  187. package/dist/native-integration/transition.js +0 -16
  188. package/dist/native-integration/transition.js.map +0 -1
  189. package/dist/vertical-bars.d.ts +0 -5
  190. package/dist/vertical-bars.js +0 -4
  191. package/docs/e2e-testing.md +0 -51
  192. package/docs/feedback.md +0 -65
  193. package/docs/iphone-duo-with-original-theme.md +0 -158
  194. package/docs/native-ui-shell.md +0 -325
  195. package/docs/vertical-bars.md +0 -300
  196. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellButton.swift +0 -71
  197. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellButtons.swift +0 -24
  198. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellComponents.swift +0 -18
  199. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellFab.swift +0 -80
  200. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellSearchController.swift +0 -432
  201. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellSegment.swift +0 -91
  202. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellTabBar.swift +0 -218
  203. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellVerticalBars.swift +0 -565
  204. package/ios/Sources/IonicNativeUIShellPlugin/Components/ShellVerticalSearch.swift +0 -118
  205. package/ios/Sources/IonicNativeUIShellPlugin/IonicNativeUIShellPlugin.swift +0 -502
  206. package/ios/Sources/IonicNativeUIShellPlugin/Overlays/ShellOverlayController.swift +0 -119
  207. package/ios/Sources/IonicNativeUIShellPlugin/Overlays/ShellOverlayHost.swift +0 -75
  208. package/ios/Sources/IonicNativeUIShellPlugin/Shared/ShellCrossfade.swift +0 -35
  209. package/ios/Sources/IonicNativeUIShellPlugin/Shared/ShellHost.swift +0 -8
  210. package/ios/Sources/IonicNativeUIShellPlugin/Shared/ShellRendering.swift +0 -27
  211. package/ios/Sources/IonicNativeUIShellPlugin/Shared/ShellSnapshot.swift +0 -135
  212. package/ios/Sources/IonicNativeUIShellPlugin/Shared/ShellVerticalBarsGeometry.swift +0 -52
  213. package/ios/Tests/IonicNativeUIShellPluginTests/ShellSnapshotTests.swift +0 -788
  214. package/src/native/components/index.ts +0 -53
  215. package/src/native/components/ion-back-button.ts +0 -19
  216. package/src/native/components/ion-button.ts +0 -24
  217. package/src/native/components/ion-buttons.ts +0 -38
  218. package/src/native/components/ion-fab.ts +0 -151
  219. package/src/native/components/ion-menu-button.ts +0 -24
  220. package/src/native/components/ion-segment.ts +0 -27
  221. package/src/native/components/ion-tab-bar.ts +0 -50
  222. package/src/native/components/searchable-tabs.ts +0 -459
  223. package/src/native/definitions.ts +0 -218
  224. package/src/native/foldable/fold-state.ts +0 -9
  225. package/src/native/foldable/types.ts +0 -4
  226. package/src/native/index.ts +0 -315
  227. package/src/native/overlays/content.ts +0 -51
  228. package/src/native/overlays/controller.ts +0 -349
  229. package/src/native/overlays/dialog-animation.ts +0 -53
  230. package/src/native/overlays/dismiss-animation.ts +0 -15
  231. package/src/native/overlays/focus.ts +0 -64
  232. package/src/native/overlays/popover.ts +0 -120
  233. package/src/native/overlays/styles.ts +0 -181
  234. package/src/native/prehide.ts +0 -265
  235. package/src/native/runtime.ts +0 -885
  236. package/src/native/shared/bridge.ts +0 -18
  237. package/src/native/shared/candidate.ts +0 -150
  238. package/src/native/shared/crossfade.ts +0 -67
  239. package/src/native/shared/dom.ts +0 -286
  240. package/src/native/shared/events.ts +0 -8
  241. package/src/native/shared/icons.ts +0 -57
  242. package/src/native/shared/modal.ts +0 -157
  243. package/src/native/shared/projection-id.ts +0 -2
  244. package/src/native/shared/vertical-bars-geometry.ts +0 -80
  245. package/src/native/vertical-bars-web-search.ts +0 -86
  246. package/src/native/vertical-bars-web.ts +0 -485
  247. package/src/native-integration/transition.ts +0 -15
  248. package/src/vertical-bars.ts +0 -11
@@ -1 +0,0 @@
1
- {"version":3,"file":"vertical-bars-web.js","names":[],"sources":["../../src/native/vertical-bars-web.ts"],"sourcesContent":["import { createCrossfade, fadeMarker } from './shared/crossfade';\nimport { alignVerticalBarClone, verticalBarFrame } from './shared/vertical-bars-geometry';\nimport { createVerticalBarsWebSearch, searchProjectionClass } from './vertical-bars-web-search';\nimport { inVerticalBarsSurface, topModal } from './shared/modal';\nimport type { NativeUIShellHandle, NativeUIShellOptions, NativeUIShellStatus } from './definitions';\nimport { VERTICAL_BARS_TRANSITION_CANCELED } from '../native-integration';\nimport {\n activateProjectedElement,\n createVerticalBarsPageState,\n verticalBarsActionCandidate,\n verticalBarsBackCandidate,\n verticalBarsEnteringPage,\n verticalBarsToolbarActions,\n isExcluded,\n isShellDisabled,\n isVerticalBarsToolbarGroup,\n preferredVerticalBarsBack,\n verticalBarsOwned,\n marker,\n syncToolbarText,\n toolbarTextMarker,\n prehideOnlyMutation,\n prehiddenClass,\n unprojected,\n withoutPrehide,\n} from './shared/dom';\n\nconst backProjectionClass = 'ios-theme-vertical-bars-back-button-projection';\nconst toolbarProjectionClass = 'ios-theme-vertical-bars-toolbar-projection';\nconst readyClass = 'ios-theme-vertical-bars-toolbar-ready';\nconst toolbarControlSize = 46;\nconst toolbarControlGap = 10;\n\ninterface ToolbarProjection {\n source: HTMLIonButtonsElement;\n projection: HTMLElement;\n actions: { source: HTMLElement; projection: HTMLElement; previousAriaHidden: string | null }[];\n}\n\ninterface ToolbarSource {\n group: HTMLIonButtonsElement;\n actions: HTMLElement[];\n}\n\nexport const createVerticalBarsWebProjection = (\n doc: Document,\n options: NativeUIShellOptions,\n enabled: () => boolean = () => true,\n): NativeUIShellHandle => {\n const win = doc.defaultView!;\n const crossfade = createCrossfade(win);\n let incomingInstant: boolean | undefined;\n const toolbarEnabled = options.controls === undefined || options.controls.toolbar === true;\n let root: HTMLElement | undefined;\n let backSource: HTMLIonBackButtonElement | undefined;\n let backProjection: HTMLIonBackButtonElement | undefined;\n let previousBackAriaHidden: string | null = null;\n let toolbarProjections: ToolbarProjection[] = [];\n let suspended = 0;\n let stopped = false;\n let frame = 0;\n let updates = 0;\n let observingVerticalBars = false;\n const verticalBarsPages = createVerticalBarsPageState();\n let sourceObserver: MutationObserver | undefined;\n let waiters: (() => void)[] = [];\n const listeners = new AbortController();\n const verticalBarsRoot = () => doc.querySelector<HTMLElement>('ion-app.ios-theme-vertical-bars');\n const projectedSources = () =>\n [backSource, search.source, ...toolbarProjections.flatMap(({ actions }) => actions.map(({ source }) => source))].filter(\n (source): source is HTMLElement => !!source,\n );\n const isRendered = (element: HTMLElement) =>\n withoutPrehide(element, () => {\n const style = getComputedStyle(element);\n const rect = element.getBoundingClientRect();\n return element.isConnected && style.display !== 'none' && style.visibility === 'visible' && rect.width > 0 && rect.height > 0;\n });\n const search = createVerticalBarsWebSearch(\n doc,\n (element) =>\n (options.controls === undefined || options.controls.tabs === true) &&\n !!verticalBarsRoot()?.contains(element) &&\n inVerticalBarsSurface(element) &&\n !isExcluded(element, verticalBarsEnteringPage(element)) &&\n !isShellDisabled(element) &&\n !verticalBarsPages.isDeparted(element) &&\n isRendered(element),\n () => {\n void schedule();\n },\n );\n const inEligibleToolbar = (element: HTMLElement) =>\n !!verticalBarsRoot()?.contains(element) &&\n inVerticalBarsSurface(element) &&\n verticalBarsActionCandidate(element) &&\n !isExcluded(element, verticalBarsEnteringPage(element)) &&\n !verticalBarsPages.isDeparted(element);\n const isEligibleBack = (element: HTMLIonBackButtonElement) =>\n !!verticalBarsRoot()?.contains(element) &&\n inVerticalBarsSurface(element) &&\n verticalBarsOwned(element) &&\n verticalBarsBackCandidate(element) &&\n !isExcluded(element, verticalBarsEnteringPage(element)) &&\n !verticalBarsPages.isDeparted(element) &&\n unprojected(projectedSources(), () => isRendered(element));\n const pageOrder = (element: Element) => Array.from(doc.querySelectorAll('.ion-page')).indexOf(element.closest('.ion-page')!);\n const findBack = () => {\n const candidates = Array.from(doc.querySelectorAll<HTMLIonBackButtonElement>(`ion-back-button:not(.${backProjectionClass})`)).filter(\n isEligibleBack,\n );\n return preferredVerticalBarsBack(candidates, doc);\n };\n const findToolbarGroups = () => {\n const candidates = Array.from(doc.querySelectorAll<HTMLIonButtonsElement>(`ion-buttons:not(.${toolbarProjectionClass})`)).flatMap(\n (group): ToolbarSource[] => {\n const actions = verticalBarsToolbarActions(group).filter((action) => unprojected(projectedSources(), () => isRendered(action)));\n if (!actions.length) return [];\n if (!isVerticalBarsToolbarGroup(group)) return actions.filter(inEligibleToolbar).map((action) => ({ group, actions: [action] }));\n return inEligibleToolbar(group) && unprojected(projectedSources(), () => isRendered(group)) ? [{ group, actions }] : [];\n },\n );\n const highestPage = Math.max(...candidates.map(({ group }) => pageOrder(group)));\n return candidates.filter(({ group }) => pageOrder(group) === highestPage);\n };\n const isCurrentToolbarAction = (source: HTMLElement) => findToolbarGroups().some(({ actions }) => actions.includes(source));\n const restore = (retire?: (surface: HTMLElement) => void) => {\n search.restore(retire);\n if (backProjection) {\n if (retire) retire(backProjection);\n else backProjection.remove();\n }\n backProjection = undefined;\n if (backSource) {\n backSource.removeAttribute(marker);\n if (previousBackAriaHidden === null) backSource.removeAttribute('aria-hidden');\n else backSource.setAttribute('aria-hidden', previousBackAriaHidden);\n backSource.dispatchEvent(new CustomEvent('nativeUIShellChange'));\n }\n backSource = undefined;\n previousBackAriaHidden = null;\n for (const { projection, actions } of toolbarProjections) {\n if (retire) retire(projection);\n else projection.remove();\n for (const { source, previousAriaHidden } of actions) {\n source.removeAttribute(marker);\n if (previousAriaHidden === null) source.removeAttribute('aria-hidden');\n else source.setAttribute('aria-hidden', previousAriaHidden);\n source.dispatchEvent(new CustomEvent('nativeUIShellChange'));\n }\n }\n toolbarProjections = [];\n sourceObserver?.disconnect();\n sourceObserver = undefined;\n root?.classList.remove(readyClass);\n root = undefined;\n };\n const copyAttributes = (target: HTMLElement, original: HTMLElement) => {\n for (const name of ['id', 'slot', marker, 'aria-hidden']) target.removeAttribute(name);\n for (const attribute of Array.from(target.attributes))\n if (!['class', marker, fadeMarker].includes(attribute.name) && !original.hasAttribute(attribute.name))\n target.removeAttribute(attribute.name);\n for (const attribute of Array.from(original.attributes))\n if (!['id', 'slot', marker, 'aria-hidden'].includes(attribute.name)) target.setAttribute(attribute.name, attribute.value);\n target.classList.remove(prehiddenClass);\n };\n const syncBack = (target: HTMLIonBackButtonElement, original: HTMLIonBackButtonElement) => {\n copyAttributes(target, original);\n target.classList.add(backProjectionClass, 'ion-cloned-element');\n target.disabled = original.disabled;\n target.defaultHref = original.defaultHref;\n target.icon = original.icon;\n target.color = original.color;\n target.mode = original.mode;\n target.text = '';\n if (root) alignVerticalBarClone(target, original, root);\n };\n const syncAction = (target: HTMLElement, original: HTMLElement) => {\n copyAttributes(target, original);\n target.classList.add('ios-theme-vertical-bars-toolbar-action', 'ion-cloned-element');\n const label =\n original.getAttribute('aria-label') ??\n original.shadowRoot?.querySelector('[part~=native]')?.getAttribute('aria-label') ??\n original.textContent?.trim();\n if (label) target.setAttribute('aria-label', label);\n if ('disabled' in original) (target as HTMLIonButtonElement).disabled = (original as HTMLIonButtonElement).disabled;\n if (original.matches('ion-button')) {\n const icon = original.querySelector<HTMLElement>('ion-icon, svg');\n const clonedIcon = icon?.cloneNode(true) as HTMLElement | undefined;\n clonedIcon?.setAttribute('slot', 'icon-only');\n target.replaceChildren(...(clonedIcon ? [clonedIcon] : []));\n }\n };\n const sameSources = (back: HTMLIonBackButtonElement | undefined, groups: ToolbarSource[]) =>\n back === backSource &&\n groups.length === toolbarProjections.length &&\n groups.every(({ group, actions }, index) => {\n const current = toolbarProjections[index];\n return (\n group === current.source &&\n actions.length === current.actions.length &&\n actions.every((action, actionIndex) => action === current.actions[actionIndex].source)\n );\n });\n const syncExisting = () => {\n if (backSource && backProjection) syncBack(backProjection, backSource);\n let topOffset = backSource ? toolbarControlSize + toolbarControlGap : 0;\n for (const { projection, source, actions } of toolbarProjections) {\n if (actions.length === 1 && !projection.matches('ion-buttons')) syncAction(projection, actions[0].source);\n else copyAttributes(projection, source);\n projection.classList.add(toolbarProjectionClass, 'ion-cloned-element');\n projection.style.setProperty('--ios-theme-vertical-bars-toolbar-offset', `${topOffset}px`);\n if (projection.matches('ion-buttons')) actions.forEach(({ source: action, projection: clone }) => syncAction(clone, action));\n const frames = actions.map(({ source }) => verticalBarFrame(source));\n if (root && frames.every((frame) => !!frame)) {\n if (actions.length === 1) alignVerticalBarClone(projection, actions[0].source, root);\n else {\n const left = Math.min(...frames.map((frame) => frame!.x));\n const top = Math.min(...frames.map((frame) => frame!.y));\n const right = Math.max(...frames.map((frame) => frame!.x + frame!.width));\n const bottom = Math.max(...frames.map((frame) => frame!.y + frame!.height));\n const origin = root.getBoundingClientRect();\n Object.assign(projection.style, {\n left: `${left - origin.left}px`,\n top: `${top - origin.top}px`,\n right: 'auto',\n bottom: 'auto',\n width: `${right - left}px`,\n height: `${bottom - top}px`,\n padding: '0',\n });\n actions.forEach(({ source, projection: clone }) => alignVerticalBarClone(clone, source, projection));\n }\n }\n topOffset += actions.length * toolbarControlSize + toolbarControlGap;\n }\n };\n const project = (nextBack: HTMLIonBackButtonElement | undefined, groups: ToolbarSource[]) => {\n root = topModal(doc) ?? verticalBarsRoot()!;\n let topOffset = 0;\n if (nextBack) {\n backSource = nextBack;\n previousBackAriaHidden = nextBack.getAttribute('aria-hidden');\n backProjection = nextBack.cloneNode(false) as HTMLIonBackButtonElement;\n syncBack(backProjection, nextBack);\n backProjection.addEventListener(\n 'click',\n (event) => {\n event.preventDefault();\n event.stopImmediatePropagation();\n if (backSource && backSource === findBack()) activateProjectedElement(backSource);\n },\n { capture: true },\n );\n root.append(backProjection);\n nextBack.setAttribute(marker, '');\n nextBack.setAttribute('aria-hidden', 'true');\n nextBack.dispatchEvent(new CustomEvent('nativeUIShellChange'));\n topOffset = toolbarControlSize + toolbarControlGap;\n }\n for (const { group, actions: sources } of groups) {\n const projection = (sources.length === 1 ? sources[0] : group).cloneNode(false) as HTMLElement;\n if (sources.length === 1) syncAction(projection, sources[0]);\n else copyAttributes(projection, group);\n projection.classList.add(toolbarProjectionClass, 'ion-cloned-element');\n projection.style.setProperty('--ios-theme-vertical-bars-toolbar-offset', `${topOffset}px`);\n const actions = sources.map((source) => {\n const clone = sources.length === 1 ? projection : (source.cloneNode(false) as HTMLElement);\n if (sources.length > 1) syncAction(clone, source);\n clone.addEventListener(\n 'click',\n (event) => {\n event.preventDefault();\n event.stopImmediatePropagation();\n if (isCurrentToolbarAction(source)) activateProjectedElement(source);\n },\n { capture: true },\n );\n if (sources.length > 1) projection.append(clone);\n const previousAriaHidden = source.getAttribute('aria-hidden');\n source.setAttribute(marker, '');\n source.setAttribute('aria-hidden', 'true');\n source.dispatchEvent(new CustomEvent('nativeUIShellChange'));\n return { source, projection: clone, previousAriaHidden };\n });\n root.append(projection);\n toolbarProjections.push({ source: group, projection, actions });\n topOffset += actions.length * toolbarControlSize + toolbarControlGap;\n }\n syncExisting();\n if (nextBack || toolbarProjections.length) root.classList.add(readyClass);\n sourceObserver = new MutationObserver((records) => {\n if (\n records.some(\n (record) =>\n record.type !== 'attributes' || (![marker, 'aria-hidden'].includes(record.attributeName ?? '') && !prehideOnlyMutation(record)),\n )\n )\n schedule();\n });\n if (nextBack?.shadowRoot)\n sourceObserver.observe(nextBack.shadowRoot, { subtree: true, childList: true, attributes: true, attributeOldValue: true });\n for (const { group } of groups)\n sourceObserver.observe(group, { subtree: true, childList: true, attributes: true, attributeOldValue: true });\n };\n const reveal = () => {\n if (incomingInstant === undefined) return;\n for (const surface of [backProjection, ...toolbarProjections.map(({ projection }) => projection), search.surface])\n if (surface) crossfade.play(surface, false, incomingInstant);\n incomingInstant = undefined;\n };\n const performUpdate = () => {\n frame = 0;\n syncToolbarText(doc);\n const currentRoot = verticalBarsRoot();\n if (observingVerticalBars !== !!currentRoot) {\n observingVerticalBars = !!currentRoot;\n observer.disconnect();\n observer.observe(doc.documentElement, {\n subtree: true,\n childList: true,\n characterData: observingVerticalBars,\n attributes: true,\n attributeOldValue: true,\n attributeFilter: observingVerticalBars ? undefined : ['class'],\n });\n }\n if (stopped || suspended || !currentRoot || !enabled()) return restore();\n const nextBack = toolbarEnabled ? findBack() : undefined;\n const groups = toolbarEnabled ? findToolbarGroups() : [];\n const projectionRoot = topModal(doc) ?? currentRoot;\n search.update(projectionRoot);\n if (!nextBack && !groups.length && !search.source) return restore();\n if (root === (topModal(doc) ?? currentRoot) && sameSources(nextBack, groups)) {\n syncExisting();\n reveal();\n return;\n }\n restore();\n project(nextBack, groups);\n search.update(projectionRoot);\n reveal();\n updates++;\n };\n const update = () => {\n try {\n performUpdate();\n } catch {\n restore();\n } finally {\n const pending = waiters;\n waiters = [];\n pending.forEach((resolve) => resolve());\n }\n };\n const schedule = (): Promise<void> => {\n if (stopped) return Promise.resolve();\n // Release Web ownership before the native runtime can acknowledge its next frame.\n if (!enabled()) restore();\n const done = new Promise<void>((resolve) => waiters.push(resolve));\n if (!frame) frame = win.requestAnimationFrame(update);\n return done;\n };\n const observer = new MutationObserver((records) => {\n const insideProjection = (target: Node) => {\n const element = target instanceof Element ? target : target.parentNode instanceof Element ? target.parentNode : undefined;\n const rootNode = target.getRootNode();\n const shadowHost = rootNode instanceof ShadowRoot ? rootNode.host : undefined;\n return !![element, shadowHost].some((candidate) =>\n candidate?.closest(`.${backProjectionClass}, .${toolbarProjectionClass}, .${searchProjectionClass}`),\n );\n };\n const verticalBarsChanged = records.some(\n (record) =>\n (record.type === 'attributes' && (record.target as Element).matches('ion-app')) ||\n (record.type === 'childList' &&\n Array.from(record.addedNodes).some(\n (node) =>\n node instanceof Element &&\n (node.matches('ion-app.ios-theme-vertical-bars') || !!node.querySelector('ion-app.ios-theme-vertical-bars')),\n )),\n );\n if (\n (observingVerticalBars &&\n records.some(\n (record) =>\n record.attributeName !== marker &&\n record.attributeName !== toolbarTextMarker &&\n !prehideOnlyMutation(record) &&\n !insideProjection(record.target),\n )) ||\n (!observingVerticalBars && verticalBarsChanged && records.some((record) => !prehideOnlyMutation(record)))\n )\n schedule();\n });\n observer.observe(doc.documentElement, {\n subtree: true,\n childList: true,\n attributes: true,\n attributeOldValue: true,\n attributeFilter: ['class'],\n });\n const pageLifecycle = (event: Event) => {\n const page = event.target;\n if (!(page instanceof HTMLElement) || !page.matches('.ion-page')) return;\n if (event.type === VERTICAL_BARS_TRANSITION_CANCELED) {\n const entering = (event as CustomEvent<{ entering?: HTMLElement }>).detail?.entering;\n verticalBarsPages.cancel(entering, page);\n } else verticalBarsPages.lifecycle(event);\n if (verticalBarsRoot()) schedule();\n };\n for (const name of ['ionViewWillEnter', 'ionViewWillLeave', 'ionViewDidEnter', 'ionViewDidLeave'])\n doc.addEventListener(name, pageLifecycle, { capture: true, signal: listeners.signal });\n doc.addEventListener(VERTICAL_BARS_TRANSITION_CANCELED, pageLifecycle, { capture: true, signal: listeners.signal });\n for (const name of ['ionModalWillPresent', 'ionModalDidDismiss'])\n doc.addEventListener(name, schedule, { capture: true, signal: listeners.signal });\n win.addEventListener(\n 'nativeUIShellVerticalBarsAcquire',\n (event) => {\n const instant = (event as CustomEvent<{ instant: boolean }>).detail?.instant ?? true;\n incomingInstant = undefined;\n restore((surface) => {\n // Keep only the outgoing visual at its last rectangle after Web ownership\n // is released. The native acknowledgement transfers input exactly once.\n const box = surface.getBoundingClientRect();\n surface.style.setProperty('position', 'fixed', 'important');\n surface.style.setProperty('display', 'block', 'important');\n surface.style.setProperty('left', `${box.left}px`, 'important');\n surface.style.setProperty('top', `${box.top}px`, 'important');\n surface.style.setProperty('right', 'auto', 'important');\n surface.style.setProperty('bottom', 'auto', 'important');\n surface.style.setProperty('width', `${box.width}px`, 'important');\n surface.style.setProperty('height', `${box.height}px`, 'important');\n crossfade.retire(surface, instant);\n });\n },\n { signal: listeners.signal },\n );\n win.addEventListener(\n 'nativeUIShellVerticalBarsRelease',\n (event) => {\n incomingInstant = (event as CustomEvent<{ instant: boolean }>).detail.instant;\n void schedule();\n },\n { signal: listeners.signal },\n );\n win.addEventListener('resize', schedule, { signal: listeners.signal });\n win.addEventListener('nativeUIShellRefresh', schedule, { signal: listeners.signal });\n schedule();\n\n return {\n getStatus: (): NativeUIShellStatus => ({\n state: stopped ? 'stopped' : 'web',\n projected:\n Number(!!backSource) + Number(!!search.source) + toolbarProjections.reduce((count, group) => count + group.actions.length, 0),\n updates,\n }),\n async suspend() {\n suspended++;\n restore();\n let resumed = false;\n return {\n async resume() {\n if (resumed) return;\n resumed = true;\n suspended = Math.max(0, suspended - 1);\n if (!suspended) await schedule();\n },\n };\n },\n async destroy() {\n if (stopped) return;\n stopped = true;\n win.cancelAnimationFrame(frame);\n frame = 0;\n waiters.forEach((resolve) => resolve());\n waiters = [];\n observer.disconnect();\n sourceObserver?.disconnect();\n listeners.abort();\n crossfade.destroy();\n restore();\n },\n };\n};\n"],"mappings":"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"}
@@ -1,23 +0,0 @@
1
- import { Animation } from "@ionic/core/components";
2
- //#region src/native-integration/index.d.ts
3
- export interface NativeUIShellIntegration {
4
- suspend(scopes: HTMLElement[]): Promise<(canceled?: boolean) => void>;
5
- search?(binding: NativeSearchBinding, active: boolean, focus?: boolean): Promise<boolean>;
6
- }
7
- export interface NativeSearchBinding {
8
- tabBar: HTMLElement;
9
- trigger: HTMLElement;
10
- footer: HTMLElement;
11
- active: boolean;
12
- focused: boolean;
13
- }
14
- export declare const registerNativeSearch: (tabBar: HTMLElement, trigger: HTMLElement, footer: HTMLElement) => NativeSearchBinding;
15
- export declare const getNativeSearchBindings: (doc: Document) => NativeSearchBinding[];
16
- export declare const requestNativeSearch: (binding: NativeSearchBinding, active: boolean, focus?: boolean) => Promise<boolean>;
17
- export declare const VERTICAL_BARS_TRANSITION_CANCELED = "iosThemeVerticalBarsTransitionCanceled";
18
- export declare const setNativeUIShellIntegration: (doc: Document, runtime?: NativeUIShellIntegration) => void;
19
- export declare const isNativeUIShell: (element: HTMLElement) => boolean;
20
- export declare const suspendNativeUIShell: (scopes: HTMLElement[]) => Promise<(canceled?: boolean) => void>;
21
- export declare const connectNativeUIShellTransition: (animation: Animation, entering: HTMLElement, leaving?: HTMLElement) => void;
22
- //#endregion
23
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../../src/native-integration/index.ts"],"mappings":";;iBAGiB;EACf,QAAQ,QAAQ,gBAAgB,SAAS;EACzC,QAAQ,SAAS,qBAAqB,iBAAiB,kBAAkB;;iBAG1D;EACf,QAAQ;EACR,SAAS;EACT,QAAQ;EACR;EACA;;qBAKW,uBAAwB,QAAQ,aAAa,SAAS,aAAa,QAAQ,gBAAc;qBASzF,0BAA2B,KAAK,aAAW;qBAG3C,sBAA6B,SAAS,qBAAqB,iBAAiB,oBAAkB;qBAI9F;qBAEA,8BAA+B,KAAK,UAAU,UAAU;qBAKxD,kBAAmB,SAAS;qBAE5B,uBAA8B,QAAQ,kBAAgB,SAAS;qBAO/D,iCAAkC,WAAW,WAAW,UAAU,aAAa,UAAU"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../../src/native-integration/index.ts"],"sourcesContent":["/// <reference lib=\"es2021.weakref\" />\nimport type { Animation } from '@ionic/core/components';\n\nexport interface NativeUIShellIntegration {\n suspend(scopes: HTMLElement[]): Promise<(canceled?: boolean) => void>;\n search?(binding: NativeSearchBinding, active: boolean, focus?: boolean): Promise<boolean>;\n}\n\nexport interface NativeSearchBinding {\n tabBar: HTMLElement;\n trigger: HTMLElement;\n footer: HTMLElement;\n active: boolean;\n focused: boolean;\n}\n\nconst searches = new WeakMap<Document, WeakRef<NativeSearchBinding>[]>();\n\nexport const registerNativeSearch = (tabBar: HTMLElement, trigger: HTMLElement, footer: HTMLElement): NativeSearchBinding => {\n const binding = { tabBar, trigger, footer, active: false, focused: false };\n const entries = (searches.get(tabBar.ownerDocument) ?? []).filter((entry) => entry.deref() && entry.deref()?.footer !== footer);\n entries.push(new WeakRef(binding));\n searches.set(tabBar.ownerDocument, entries);\n tabBar.ownerDocument.defaultView?.dispatchEvent(new Event('nativeUIShellRefresh'));\n return binding;\n};\n\nexport const getNativeSearchBindings = (doc: Document): NativeSearchBinding[] =>\n (searches.get(doc) ?? []).flatMap((entry) => entry.deref() ?? []);\n\nexport const requestNativeSearch = async (binding: NativeSearchBinding, active: boolean, focus?: boolean): Promise<boolean> =>\n (await runtimes.get(binding.tabBar.ownerDocument)?.search?.(binding, active, focus)) ?? false;\n\nconst runtimes = new WeakMap<Document, NativeUIShellIntegration>();\nexport const VERTICAL_BARS_TRANSITION_CANCELED = 'iosThemeVerticalBarsTransitionCanceled';\n\nexport const setNativeUIShellIntegration = (doc: Document, runtime?: NativeUIShellIntegration) => {\n if (runtime) runtimes.set(doc, runtime);\n else runtimes.delete(doc);\n};\n\nexport const isNativeUIShell = (element: HTMLElement) => element.hasAttribute('data-native-ui-shell');\n\nexport const suspendNativeUIShell = async (scopes: HTMLElement[]): Promise<(canceled?: boolean) => void> =>\n (await runtimes.get(scopes[0]?.ownerDocument)?.suspend(scopes)) ?? (() => {});\n\nconst connectedTransitions = new WeakSet<Animation>();\nconst cancellationTransitions = new WeakSet<Animation>();\n\n/** Ionic write hooks cannot await the bridge. Gate playback, including interactive playback. */\nexport const connectNativeUIShellTransition = (animation: Animation, entering: HTMLElement, leaving?: HTMLElement) => {\n if (leaving && !cancellationTransitions.has(animation)) {\n cancellationTransitions.add(animation);\n animation.onFinish((step) => {\n if (step === 0) leaving.dispatchEvent(new CustomEvent(VERTICAL_BARS_TRANSITION_CANCELED, { bubbles: true, detail: { entering } }));\n });\n }\n if (connectedTransitions.has(animation) || !runtimes.has(entering.ownerDocument)) return;\n connectedTransitions.add(animation);\n const scopes = leaving ? [entering, leaving] : [entering];\n const play = animation.play.bind(animation);\n const progressStart = animation.progressStart.bind(animation);\n const progressStep = animation.progressStep.bind(animation);\n const progressEnd = animation.progressEnd.bind(animation);\n const destroy = animation.destroy.bind(animation);\n let release: ((canceled?: boolean) => void) | undefined;\n let preparation: Promise<void> | undefined;\n let disposed = false;\n let interactiveReady = false;\n let step: number | undefined;\n let end: Parameters<Animation['progressEnd']> | undefined;\n const prepare = () =>\n (preparation ??= suspendNativeUIShell(scopes).then((resume) => {\n if (disposed) resume(true);\n else release = resume;\n }));\n const finish = (canceled = false) => {\n release?.(canceled);\n release = undefined;\n preparation = undefined;\n };\n animation.onFinish((step) => finish(step === 0));\n animation.play = async (options) => {\n await prepare();\n if (disposed) return;\n try {\n await play(options);\n } finally {\n finish();\n }\n };\n animation.progressStart = (...args) => {\n interactiveReady = false;\n step = undefined;\n end = undefined;\n void prepare().then(() => {\n if (disposed) return;\n progressStart(...args);\n interactiveReady = true;\n if (step !== undefined) progressStep(step);\n if (end) progressEnd(...end);\n });\n return animation;\n };\n animation.progressStep = (value) => {\n step = value;\n if (interactiveReady) progressStep(value);\n return animation;\n };\n animation.progressEnd = (...args) => {\n end = args;\n if (interactiveReady) progressEnd(...args);\n return animation;\n };\n animation.destroy = (...args) => {\n disposed = true;\n finish(true);\n return destroy(...args);\n };\n};\n"],"mappings":"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"}
@@ -1,5 +0,0 @@
1
- import { AnimationBuilder } from "@ionic/core/components";
2
- //#region src/native-integration/transition.d.ts
3
- export declare const withNativeUIShellTransition: (builder: AnimationBuilder) => AnimationBuilder;
4
- //#endregion
5
- //# sourceMappingURL=transition.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"transition.d.ts","names":[],"sources":["../../src/native-integration/transition.ts"],"mappings":";;qBAQa,8BACV,SAAS,qBAAmB"}
@@ -1,16 +0,0 @@
1
- import { connectNativeUIShellTransition } from "./index.js";
2
- //#region src/native-integration/transition.ts
3
- /**
4
- * Keeps an existing Ionic navigation animation and coordinates native control handoff.
5
- * Register the returned builder as navAnimation. Do not use it for overlay animations.
6
- * The builder must return a fresh Animation for each navigation; Ionic destroys it afterward.
7
- */
8
- const withNativeUIShellTransition = (builder) => (baseEl, opts) => {
9
- const animation = builder(baseEl, opts);
10
- if (opts?.enteringEl) connectNativeUIShellTransition(animation, opts.enteringEl, opts.leavingEl);
11
- return animation;
12
- };
13
- //#endregion
14
- export { withNativeUIShellTransition };
15
-
16
- //# sourceMappingURL=transition.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"transition.js","names":[],"sources":["../../src/native-integration/transition.ts"],"sourcesContent":["import type { AnimationBuilder } from '@ionic/core/components';\nimport { connectNativeUIShellTransition } from './index';\n\n/**\n * Keeps an existing Ionic navigation animation and coordinates native control handoff.\n * Register the returned builder as navAnimation. Do not use it for overlay animations.\n * The builder must return a fresh Animation for each navigation; Ionic destroys it afterward.\n */\nexport const withNativeUIShellTransition =\n (builder: AnimationBuilder): AnimationBuilder =>\n (baseEl, opts) => {\n const animation = builder(baseEl, opts);\n if (opts?.enteringEl) connectNativeUIShellTransition(animation, opts.enteringEl, opts.leavingEl);\n return animation;\n };\n"],"mappings":";;;;;;;AAQA,MAAa,+BACV,aACA,QAAQ,SAAS;CAChB,MAAM,YAAY,QAAQ,QAAQ,IAAI;CACtC,IAAI,MAAM,YAAY,+BAA+B,WAAW,KAAK,YAAY,KAAK,SAAS;CAC/F,OAAO;AACT"}
@@ -1,5 +0,0 @@
1
- import { withNativeUIShellTransition } from "./native-integration/transition.js";
2
- import { NativeUIShellStatus, NativeUIShellSuspension, VerticalBarEdge, VerticalControlAreaHandle, VerticalControlAreaOptions } from "./native/definitions.js";
3
- import { applyFoldStateClasses } from "./native/foldable/fold-state.js";
4
- import { IonicNativeUIShell, enableVerticalControlArea, setVerticalControlAreaPlacement } from "./native/index.js";
5
- export { IonicNativeUIShell, type NativeUIShellStatus, type NativeUIShellSuspension, type VerticalBarEdge, type VerticalControlAreaHandle, type VerticalControlAreaOptions, applyFoldStateClasses, enableVerticalControlArea, setVerticalControlAreaPlacement, withNativeUIShellTransition };
@@ -1,4 +0,0 @@
1
- import { withNativeUIShellTransition } from "./native-integration/transition.js";
2
- import { IonicNativeUIShell, enableVerticalControlArea, setVerticalControlAreaPlacement } from "./native/index.js";
3
- import { applyFoldStateClasses } from "./native/foldable/fold-state.js";
4
- export { IonicNativeUIShell, applyFoldStateClasses, enableVerticalControlArea, setVerticalControlAreaPlacement, withNativeUIShellTransition };
@@ -1,51 +0,0 @@
1
- # E2E screenshot testing
2
-
3
- This maintainer guide explains how to run the Playwright visual-regression suite for the iOS26 demo. The suite covers every entry declared in `demo/e2e/screenshot.spec.ts` in both light and dark modes. Overlay variants are generated from the shared arrays in `demo/src/app/overlay-types.ts`.
4
-
5
- ## Run the suite
6
-
7
- Install the demo dependencies first:
8
-
9
- ```bash
10
- cd demo
11
- npm install
12
- ```
13
-
14
- Then choose the command that matches the task:
15
-
16
- ```bash
17
- npm run test:e2e # Run the suite
18
- npm run test:e2e:ui # Open Playwright UI mode
19
- npm run test:e2e:debug # Run with the Playwright debugger
20
- npm run test:e2e:update # Regenerate intentional baseline changes
21
- ```
22
-
23
- To reproduce the Linux environment used by CI, run the Docker variants from `demo/`:
24
-
25
- ```bash
26
- npm run test:e2e:docker
27
- npm run test:e2e:docker:update
28
- ```
29
-
30
- The Docker commands use the Playwright image pinned in `demo/package.json`.
31
-
32
- ## Review a failure
33
-
34
- A screenshot mismatch can be a regression or an intentional visual change. Before updating a baseline:
35
-
36
- 1. Inspect the actual, expected, and diff images in `demo/test-results/`.
37
- 2. Check the affected route in both light and dark modes.
38
- 3. Confirm that the component change is intentional.
39
- 4. Regenerate the baseline with `npm run test:e2e:update`, or use the Docker variant when matching CI rendering.
40
-
41
- The HTML report is written to `demo/playwright-report/` and can be opened with:
42
-
43
- ```bash
44
- npx playwright show-report
45
- ```
46
-
47
- ## Add coverage
48
-
49
- When adding a demo route or overlay variant, update `demo/e2e/screenshot.spec.ts` and regenerate the relevant baselines. Commit baseline changes only after reviewing the visual diff.
50
-
51
- Pull requests targeting `main` or `ios26` run the E2E workflow in `.github/workflows/e2e-pull_request.yml`; pushes to either branch run `.github/workflows/e2e-main.yml`. GitHub builds the pull-request merge ref against its target branch, so an `ios26` pull request starts with the iOS 26 snapshots. Snapshot changes intentionally committed by the pull request are then tested as part of that merge result. The `/update-screenshots` command loads its update procedure from the pull request's target branch and commits the regenerated screenshots to the pull request branch.
package/docs/feedback.md DELETED
@@ -1,65 +0,0 @@
1
- # Feature requests for Ionic Framework
2
-
3
- ## feat(): change `--knob-handle-size` to `--knob-handle-width` / `--knob-handle-height`
4
-
5
- Currently, only square sizes are taken into consideration.
6
- Overwriting the `knob` itself is possible, but `--knob-handle-size` cannot be ignored as it plays a crucial role in determining the `top` and `margin-inline-start` of `div.range-knob-handle`.
7
-
8
- ## feat(): ion-config new property for `collapse`
9
-
10
- Currently, `collapse` behavior is automatically enabled in iOS mode, but this should be configurable through `ion-config` for better control.
11
-
12
- ex:
13
-
14
- ```typescript
15
- export interface IonicConfig {
16
- ...,
17
- collapseLargeTitle: {
18
- ios: boolean;
19
- md: boolean;
20
- ionic: boolean;
21
- },
22
- collapseBackButtonAnimation: {
23
- ios: boolean;
24
- md: boolean;
25
- ionic: boolean;
26
- },
27
- }
28
- ```
29
-
30
- ## feat(): add native shadow-part for design
31
-
32
- ### native-inner(or item-inner) part to ion-item
33
-
34
- The styling for `ion-item[lines=inset]` is applied to `.item-inner`, which cannot be styled directly. This limitation means that for iOS 27 styling, I can only modify the border-bottom style through `::part(native)` with padding-right, preventing me from utilizing the full right side of `ion-item`. Adding `::part(native-inner)` would increase styling flexibility.
35
-
36
- ```diff
37
- <ion-item>
38
- <button type="button" class="item-native" part="native">
39
- - <div class="item-inner">
40
- + <div class="item-inner" part="native-inner">
41
- ...
42
- </div>
43
- </button>
44
- </ion-item>
45
- ```
46
-
47
- ### native part to ion-toast
48
-
49
- Resolved: https://github.com/ionic-team/ionic-framework/pull/30992#event-23306774962
50
-
51
- ## docs(): Naming conventions for Ionic theme classes
52
-
53
- Resolved.
54
-
55
- ### should disable ion-back-button Animation
56
-
57
- Resolved: by created https://github.com/rdlabo-dev/ionic-theme-ios27/tree/main/src/transition
58
-
59
- ## feat(): ion-content[fullscreen=true] will have .content-fullscreen class
60
-
61
- Resolved: https://github.com/ionic-team/ionic-framework/pull/30926
62
-
63
- ## feat(): add .range-knob-min and .range-knob-max directly to ion-range
64
-
65
- Resolved: https://github.com/ionic-team/ionic-framework/pull/30932
@@ -1,158 +0,0 @@
1
- ---
2
- title: iPhone Duo with your existing theme (preview)
3
- ---
4
-
5
- # iPhone Duo with your existing theme (preview)
6
-
7
- Add a vertical navigation area to your Ionic app while keeping its existing theme. Tabs and supported toolbar actions move to the side of the screen; your content and horizontal controls keep their current appearance. Both Ionic `ios` and `md` modes are supported.
8
-
9
- **Try it in Chrome first.** You can preview the layout with Web controls before setting up an iPhone Duo or an iOS build. On supported Capacitor iOS, the same Ionic markup supplies native SwiftUI controls in the system rail.
10
-
11
- Available in `1.2.0` as a **preview** feature. APIs and supported behavior may change.
12
-
13
- ## Try it in your existing Ionic app
14
-
15
- ### 1. Install and load the standalone stylesheet
16
-
17
- This guide assumes an existing Ionic app with Ionic `>=8.8.1 <10` and Capacitor Core `>=8 <9`. Keep your existing Capacitor 8 installation. If your app uses another Capacitor major, migrate its Core, CLI, and platform packages together before following this guide. For a Web-only app without Capacitor, also install `@capacitor/core@^8`; the JavaScript entry point needs it even in Chrome.
18
-
19
- ```bash
20
- npm install @rdlabo/ionic-theme-ios27@1.2.0
21
- ```
22
-
23
- Keep your existing theme imports. Add this to your global Sass file:
24
-
25
- ```scss
26
- @use '@rdlabo/ionic-theme-ios27/dist/css/vertical-bars.css';
27
- ```
28
-
29
- The standalone JavaScript entry point needs `@capacitor/core` even in Chrome. The iOS 27 theme stylesheets are not required.
30
-
31
- ### 2. Opt your app into the side layout
32
-
33
- Add the class to your existing app root and keep the content inside it:
34
-
35
- ```html
36
- <ion-app class="ios-theme-vertical-bars">
37
- <!-- Keep your existing pages, tabs, and toolbar controls here. -->
38
- </ion-app>
39
- ```
40
-
41
- The preview reserves `80px` on the physical right. To preview the left side, also add `ios-theme-vertical-bars-left`.
42
-
43
- ### 3. Connect your navigation animation
44
-
45
- Configure `navAnimation` before Ionic initializes. Starting the rail runtime does not register this option. The adapter waits for native control retirement and coordinates swipe progress and cancellation while keeping your existing animation.
46
-
47
- #### Keep Ionic's default animation
48
-
49
- If you have not configured `navAnimation`, wrap Ionic's standard builders. Select the builder from Ionic's transition `mode` so both `ios` and `md` keep their usual animation:
50
-
51
- ```ts
52
- import { iosTransitionAnimation, mdTransitionAnimation, type AnimationBuilder } from '@ionic/core';
53
- import { withNativeUIShellTransition } from '@rdlabo/ionic-theme-ios27/vertical-bars';
54
-
55
- const defaultTransition: AnimationBuilder = (baseEl, opts) =>
56
- (opts.mode === 'ios' ? iosTransitionAnimation : mdTransitionAnimation)(baseEl, opts);
57
-
58
- const ionicConfig = {
59
- navAnimation: withNativeUIShellTransition(defaultTransition),
60
- };
61
- ```
62
-
63
- Merge this option into your existing Ionic configuration before initialization: pass it to Angular's `provideIonicAngular()`, React's `setupIonicReact()`, or Vue's `IonicVue` plugin options. Keep your existing theme stylesheet imports. No iOS 27 theme stylesheet is required.
64
-
65
- #### Use this package's iOS animation
66
-
67
- If you already use the iOS 27 transition, keep this configuration. It includes the native adapter and excludes the horizontal back-button effect in vertical layouts; no additional wrapper is needed. Importing this JavaScript entry point does not load the theme stylesheets.
68
-
69
- ```ts
70
- import { iosTransitionAnimation } from '@rdlabo/ionic-theme-ios27';
71
-
72
- const ionicConfig = {
73
- navAnimation: iosTransitionAnimation,
74
- };
75
- ```
76
-
77
- Apply this option to your existing iOS-mode configuration and keep your MD configuration.
78
-
79
- #### Keep your custom animation
80
-
81
- If your app uses another builder for `navAnimation`, wrap it:
82
-
83
- ```ts
84
- import type { AnimationBuilder } from '@ionic/core';
85
- import { withNativeUIShellTransition } from '@rdlabo/ionic-theme-ios27/vertical-bars';
86
-
87
- // Pass the animation builder your app already uses.
88
- const configureNavigation = (existingTransition: AnimationBuilder) => ({
89
- navAnimation: withNativeUIShellTransition(existingTransition),
90
- });
91
- ```
92
-
93
- The adapter returns the original `Animation`, preserving its effects, duration, and easing. Use it only for navigation, not modal or popover animations. The builder must return a fresh `Animation` for each navigation; Ionic destroys it after the transition. Keep lifecycle events for control registration and transitions without animation.
94
-
95
- The adapter keeps the builder's animation targets, including any horizontal back-button effect. If you need the iOS 27 transition with that effect excluded in vertical layouts, use `iosTransitionAnimation` from `@rdlabo/ionic-theme-ios27` as your `navAnimation` instead. It already includes the adapter, so no wrapper is needed.
96
-
97
- ### 4. Start the controls after the app root is mounted
98
-
99
- Call this once from your application startup after `ion-app` exists in the DOM:
100
-
101
- ```ts
102
- import { enableVerticalControlArea } from '@rdlabo/ionic-theme-ios27/vertical-bars';
103
-
104
- const rail = await enableVerticalControlArea();
105
- ```
106
-
107
- **What you should see:** your existing tab bar moves to the side, and fixed-toolbar buttons with an `ion-icon` or SVG using `slot="icon-only"` appear there too. Content keeps its existing theme and leaves room for the controls. The Web tab rail displays icons; pressing and dragging reveals tab labels.
108
-
109
- Use your existing Ionic click handlers, routing, and form associations. All button fills (`default`, `clear`, `solid`, and `outline`) use the same `icon-only` rule, including submit buttons. Actions without that slot remain horizontal. Add `.ios-theme-horizontal-only` to an `ion-buttons` group or individual `ion-button` to keep an action in the horizontal toolbar.
110
-
111
- When the application owner is disposed, call `await rail.destroy()` to restore the original controls and release the runtime. If you already use `enableNativeUIShell()`, keep that runtime and follow the [shared placement guide](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/iphone-duo#project-controls-into-the-rail).
112
-
113
- ### Optional: choose native button appearance
114
-
115
- `buttonProjection` and local projection settings are available in `1.2.0`. See [Choose button appearance](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/vertical-bars#choose-button-appearance) for availability and migration details.
116
-
117
- The new default is `system`: SwiftUI styles vertical buttons and tints their icons. If your existing theme should supply their fill and colors, use:
118
-
119
- ```ts
120
- const rail = await enableVerticalControlArea({ buttonProjection: 'source', buttonDefaultFill: 'solid' });
121
- ```
122
-
123
- The `solid` default suits ordinary Ionic buttons. Buttons inside `ion-buttons` still default to clear; set `fill="solid"` explicitly to project their background. For one-off exceptions, use the [local projection settings](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/vertical-bars#override-individual-buttons-or-groups). These settings affect native vertical buttons only; Web clones keep their existing appearance.
124
-
125
- ### If the preview does not appear
126
-
127
- | What you see | What to check |
128
- | --- | --- |
129
- | No space at the side | Load `vertical-bars.css` and put the class on `ion-app`. |
130
- | Space appears, but controls stay horizontal | Start `enableVerticalControlArea()` after mounting the app root. Use existing tabs or `slot="icon-only"` actions in a fixed header/footer toolbar. |
131
- | One action stays horizontal | Check for `slot="icon-only"` on the icon and a fixed toolbar outside scrolling content. Explicitly excluded controls and controls in centered modals stay horizontal; `fill` and `type="submit"` do not prevent movement. See [control requirements](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/vertical-bars#toolbar-actions). |
132
-
133
- ## Connect an iPhone Duo
134
-
135
- Install [`@erkamyaman/capacitor-foldable`](https://github.com/erkamyaman/capacitor-foldable) for device state:
136
-
137
- ```bash
138
- npm install @erkamyaman/capacitor-foldable
139
- npx cap sync ios
140
- ```
141
-
142
- Use Capacitor 8.5 or later and build with Xcode 27.1 or newer for actual rail placement and hinge posture on iOS 27.1. Native UI Shell uses Swift Package Manager; existing CocoaPods apps can follow [Native UI Shell setup](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/native-ui-shell#enable-the-shell). Keep this package's `vertical-bars.css`; the device plugin's `ionic-tabs.css` is not needed with our rail projection.
143
-
144
- Replace the browser-only startup with the [device placement setup](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/iphone-duo#project-controls-into-the-rail). That setup sends initial values and `barPlacementChange` events to `setVerticalControlAreaPlacement({ edge: verticalBarEdge, nativeEdge: verticalBarEdge, inset })`, with subscriptions and cleanup kept in your application.
145
-
146
- Pass both the requested and native edge with Foldable's measured inset. The placement API resolves RTL. A null edge restores the ordinary layout.
147
-
148
- On supported iOS, controls in the rail use native SwiftUI rendering; your custom Web styling still applies to ordinary content and horizontal controls. Web and Android use Web clones.
149
-
150
- ## Use hinge posture without projecting controls
151
-
152
- If your existing theme needs only a posture-driven split pane or a layout switch, do not start a projection runtime or add `.ios-theme-vertical-bars`. Pass `Foldable.getFoldState()` results and `foldStateChange` events to `applyFoldStateClasses(root, fold)`, removing the listener when finished. There is no separate start/stop monitoring call.
153
-
154
- See [Read the device layout](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/iphone-duo#read-the-device-layout) for the subscription example, null values, and monitoring lifetime. See [Adapt the split pane](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/iphone-duo#adapt-the-split-pane) for the opt-in width rules and half-open state.
155
-
156
- ## Shared layout rules and API
157
-
158
- Safe-area handling, overlays, RTL, control eligibility, Web simulation, and the handle API are documented in [Vertical Bars](https://docs.rdlabo.dev/projects/ionic-theme-ios27/docs/vertical-bars). Those rules apply to this standalone setup too.