@nativescript/core 9.1.0-alpha.9 → 9.1.0-dev.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 (403) hide show
  1. package/animation-frame/animation-native.windows.d.ts +1 -0
  2. package/animation-frame/animation-native.windows.js +4 -0
  3. package/animation-frame/animation-native.windows.js.map +1 -0
  4. package/application/application-common.d.ts +2 -1
  5. package/application/application-common.js +4 -0
  6. package/application/application-common.js.map +1 -1
  7. package/application/application.android.d.ts +0 -16
  8. package/application/application.android.js +1 -6
  9. package/application/application.android.js.map +1 -1
  10. package/application/application.d.ts +9 -0
  11. package/application/application.ios.d.ts +1 -2
  12. package/application/application.ios.js +9 -88
  13. package/application/application.ios.js.map +1 -1
  14. package/application/application.windows.d.ts +27 -0
  15. package/application/application.windows.js +331 -0
  16. package/application/application.windows.js.map +1 -0
  17. package/application/helpers.windows.d.ts +8 -0
  18. package/application/helpers.windows.js +12 -0
  19. package/application/helpers.windows.js.map +1 -0
  20. package/application/index.windows.d.ts +2 -0
  21. package/application/index.windows.js +3 -0
  22. package/application/index.windows.js.map +1 -0
  23. package/application/window-helper.windows.d.ts +29 -0
  24. package/application/window-helper.windows.js +159 -0
  25. package/application/window-helper.windows.js.map +1 -0
  26. package/application-settings/index.windows.d.ts +11 -0
  27. package/application-settings/index.windows.js +93 -0
  28. package/application-settings/index.windows.js.map +1 -0
  29. package/color/index.d.ts +5 -0
  30. package/color/index.windows.d.ts +8 -0
  31. package/color/index.windows.js +19 -0
  32. package/color/index.windows.js.map +1 -0
  33. package/connectivity/index.windows.d.ts +11 -0
  34. package/connectivity/index.windows.js +50 -0
  35. package/connectivity/index.windows.js.map +1 -0
  36. package/debugger/webinspector-network.windows.d.ts +79 -0
  37. package/debugger/webinspector-network.windows.js +307 -0
  38. package/debugger/webinspector-network.windows.js.map +1 -0
  39. package/file-system/file-system-access.windows.d.ts +76 -0
  40. package/file-system/file-system-access.windows.js +476 -0
  41. package/file-system/file-system-access.windows.js.map +1 -0
  42. package/fps-meter/fps-native.windows.d.ts +8 -0
  43. package/fps-meter/fps-native.windows.js +40 -0
  44. package/fps-meter/fps-native.windows.js.map +1 -0
  45. package/global-types.d.ts +1 -0
  46. package/globals/index.js +1 -4
  47. package/globals/index.js.map +1 -1
  48. package/http/http-request/index.android.js.map +1 -1
  49. package/http/http-request/index.ios.js.map +1 -1
  50. package/http/http-request/index.windows.d.ts +2 -0
  51. package/http/http-request/index.windows.js +41 -0
  52. package/http/http-request/index.windows.js.map +1 -0
  53. package/http/http-request-internal/index.android.d.ts +1 -7
  54. package/http/http-request-internal/index.android.js.map +1 -1
  55. package/http/http-request-internal/index.ios.d.ts +1 -7
  56. package/http/http-request-internal/index.ios.js.map +1 -1
  57. package/http/http-request-internal/index.windows.d.ts +4 -0
  58. package/http/http-request-internal/index.windows.js +134 -0
  59. package/http/http-request-internal/index.windows.js.map +1 -0
  60. package/image-asset/index.windows.d.ts +9 -0
  61. package/image-asset/index.windows.js +34 -0
  62. package/image-asset/index.windows.js.map +1 -0
  63. package/image-source/index.android.d.ts +1 -0
  64. package/image-source/index.android.js.map +1 -1
  65. package/image-source/index.d.ts +5 -0
  66. package/image-source/index.ios.d.ts +1 -0
  67. package/image-source/index.ios.js.map +1 -1
  68. package/image-source/index.windows.d.ts +52 -0
  69. package/image-source/index.windows.js +498 -0
  70. package/image-source/index.windows.js.map +1 -0
  71. package/package.json +6 -4
  72. package/platform/common.d.ts +2 -0
  73. package/platform/common.js +2 -0
  74. package/platform/common.js.map +1 -1
  75. package/platform/device/index.windows.d.ts +18 -0
  76. package/platform/device/index.windows.js +94 -0
  77. package/platform/device/index.windows.js.map +1 -0
  78. package/platform/screen/index.windows.d.ts +13 -0
  79. package/platform/screen/index.windows.js +25 -0
  80. package/platform/screen/index.windows.js.map +1 -0
  81. package/platforms/windows/arm64/NativeScript.Widgets.dll +0 -0
  82. package/platforms/windows/arm64/NativeScript.Widgets.winmd +0 -0
  83. package/platforms/windows/x64/NativeScript.Widgets.dll +0 -0
  84. package/platforms/windows/x64/NativeScript.Widgets.winmd +0 -0
  85. package/plugin.props +12 -0
  86. package/plugin.targets +71 -0
  87. package/references.d.ts +4 -0
  88. package/text/index.windows.d.ts +9 -0
  89. package/text/index.windows.js +12 -0
  90. package/text/index.windows.js.map +1 -0
  91. package/timer/index.windows.d.ts +4 -0
  92. package/timer/index.windows.js +14 -0
  93. package/timer/index.windows.js.map +1 -0
  94. package/ui/action-bar/index.ios.js +1 -0
  95. package/ui/action-bar/index.ios.js.map +1 -1
  96. package/ui/action-bar/index.windows.d.ts +12 -0
  97. package/ui/action-bar/index.windows.js +36 -0
  98. package/ui/action-bar/index.windows.js.map +1 -0
  99. package/ui/activity-indicator/index.windows.d.ts +15 -0
  100. package/ui/activity-indicator/index.windows.js +65 -0
  101. package/ui/activity-indicator/index.windows.js.map +1 -0
  102. package/ui/animation/index.windows.d.ts +19 -0
  103. package/ui/animation/index.windows.js +603 -0
  104. package/ui/animation/index.windows.js.map +1 -0
  105. package/ui/builder/index.d.ts +1 -0
  106. package/ui/builder/index.js +2 -1
  107. package/ui/builder/index.js.map +1 -1
  108. package/ui/button/index.android.d.ts +9 -2
  109. package/ui/button/index.android.js +24 -7
  110. package/ui/button/index.android.js.map +1 -1
  111. package/ui/button/index.ios.d.ts +9 -2
  112. package/ui/button/index.ios.js +72 -17
  113. package/ui/button/index.ios.js.map +1 -1
  114. package/ui/button/index.windows.d.ts +13 -0
  115. package/ui/button/index.windows.js +73 -0
  116. package/ui/button/index.windows.js.map +1 -0
  117. package/ui/core/bindable/index.js +1 -2
  118. package/ui/core/bindable/index.js.map +1 -1
  119. package/ui/core/control-state-change/index.windows.d.ts +4 -0
  120. package/ui/core/control-state-change/index.windows.js +6 -0
  121. package/ui/core/control-state-change/index.windows.js.map +1 -0
  122. package/ui/core/view/index.android.d.ts +0 -1
  123. package/ui/core/view/index.android.js +8 -17
  124. package/ui/core/view/index.android.js.map +1 -1
  125. package/ui/core/view/index.ios.d.ts +0 -1
  126. package/ui/core/view/index.ios.js +4 -17
  127. package/ui/core/view/index.ios.js.map +1 -1
  128. package/ui/core/view/index.windows.d.ts +120 -0
  129. package/ui/core/view/index.windows.js +2178 -0
  130. package/ui/core/view/index.windows.js.map +1 -0
  131. package/ui/core/view/view-common.d.ts +2 -0
  132. package/ui/core/view/view-common.js +6 -1
  133. package/ui/core/view/view-common.js.map +1 -1
  134. package/ui/core/view/view-helper/index.d.ts +0 -1
  135. package/ui/core/view/view-helper/index.ios.d.ts +0 -24
  136. package/ui/core/view/view-helper/index.ios.js +5 -54
  137. package/ui/core/view/view-helper/index.ios.js.map +1 -1
  138. package/ui/core/view/view-helper/index.windows.d.ts +3 -0
  139. package/ui/core/view/view-helper/index.windows.js +4 -0
  140. package/ui/core/view/view-helper/index.windows.js.map +1 -0
  141. package/ui/core/view-base/index.d.ts +10 -24
  142. package/ui/core/view-base/index.js +32 -50
  143. package/ui/core/view-base/index.js.map +1 -1
  144. package/ui/date-picker/index.windows.d.ts +22 -0
  145. package/ui/date-picker/index.windows.js +97 -0
  146. package/ui/date-picker/index.windows.js.map +1 -0
  147. package/ui/dialogs/index.windows.d.ts +17 -0
  148. package/ui/dialogs/index.windows.js +471 -0
  149. package/ui/dialogs/index.windows.js.map +1 -0
  150. package/ui/editable-text-base/index.windows.d.ts +27 -0
  151. package/ui/editable-text-base/index.windows.js +165 -0
  152. package/ui/editable-text-base/index.windows.js.map +1 -0
  153. package/ui/embedding/index.windows.d.ts +1 -0
  154. package/ui/embedding/index.windows.js +4 -0
  155. package/ui/embedding/index.windows.js.map +1 -0
  156. package/ui/frame/fragment.transitions.android.d.ts +13 -13
  157. package/ui/frame/fragment.transitions.android.js.map +1 -1
  158. package/ui/frame/frame-common.d.ts +1 -2
  159. package/ui/frame/frame-common.js +0 -10
  160. package/ui/frame/frame-common.js.map +1 -1
  161. package/ui/frame/frame-helper-for-android.d.ts +4 -4
  162. package/ui/frame/frame-helper-for-android.js +8 -17
  163. package/ui/frame/frame-helper-for-android.js.map +1 -1
  164. package/ui/frame/index.android.d.ts +11 -6
  165. package/ui/frame/index.android.js +59 -18
  166. package/ui/frame/index.android.js.map +1 -1
  167. package/ui/frame/index.d.ts +21 -12
  168. package/ui/frame/index.ios.d.ts +2 -2
  169. package/ui/frame/index.ios.js.map +1 -1
  170. package/ui/frame/index.windows.d.ts +52 -0
  171. package/ui/frame/index.windows.js +778 -0
  172. package/ui/frame/index.windows.js.map +1 -0
  173. package/ui/gestures/index.windows.d.ts +35 -0
  174. package/ui/gestures/index.windows.js +483 -0
  175. package/ui/gestures/index.windows.js.map +1 -0
  176. package/ui/html-view/index.windows.d.ts +18 -0
  177. package/ui/html-view/index.windows.js +191 -0
  178. package/ui/html-view/index.windows.js.map +1 -0
  179. package/ui/image/index.windows.d.ts +17 -0
  180. package/ui/image/index.windows.js +132 -0
  181. package/ui/image/index.windows.js.map +1 -0
  182. package/ui/image/symbol-effects.windows.d.ts +5 -0
  183. package/ui/image/symbol-effects.windows.js +8 -0
  184. package/ui/image/symbol-effects.windows.js.map +1 -0
  185. package/ui/image-cache/index.windows.d.ts +11 -0
  186. package/ui/image-cache/index.windows.js +48 -0
  187. package/ui/image-cache/index.windows.js.map +1 -0
  188. package/ui/label/index.ios.d.ts +5 -2
  189. package/ui/label/index.ios.js +44 -12
  190. package/ui/label/index.ios.js.map +1 -1
  191. package/ui/label/index.windows.d.ts +15 -0
  192. package/ui/label/index.windows.js +66 -0
  193. package/ui/label/index.windows.js.map +1 -0
  194. package/ui/layouts/absolute-layout/index.ios.js +1 -5
  195. package/ui/layouts/absolute-layout/index.ios.js.map +1 -1
  196. package/ui/layouts/absolute-layout/index.windows.d.ts +8 -0
  197. package/ui/layouts/absolute-layout/index.windows.js +47 -0
  198. package/ui/layouts/absolute-layout/index.windows.js.map +1 -0
  199. package/ui/layouts/dock-layout/index.ios.js +1 -5
  200. package/ui/layouts/dock-layout/index.ios.js.map +1 -1
  201. package/ui/layouts/dock-layout/index.windows.d.ts +19 -0
  202. package/ui/layouts/dock-layout/index.windows.js +202 -0
  203. package/ui/layouts/dock-layout/index.windows.js.map +1 -0
  204. package/ui/layouts/flexbox-layout/flexbox-layout-common.d.ts +17 -2
  205. package/ui/layouts/flexbox-layout/flexbox-layout-common.js +73 -2
  206. package/ui/layouts/flexbox-layout/flexbox-layout-common.js.map +1 -1
  207. package/ui/layouts/flexbox-layout/index.ios.js +1 -5
  208. package/ui/layouts/flexbox-layout/index.ios.js.map +1 -1
  209. package/ui/layouts/flexbox-layout/index.windows.d.ts +27 -0
  210. package/ui/layouts/flexbox-layout/index.windows.js +188 -0
  211. package/ui/layouts/flexbox-layout/index.windows.js.map +1 -0
  212. package/ui/layouts/grid-layout/index.ios.js +1 -5
  213. package/ui/layouts/grid-layout/index.ios.js.map +1 -1
  214. package/ui/layouts/grid-layout/index.windows.d.ts +20 -0
  215. package/ui/layouts/grid-layout/index.windows.js +130 -0
  216. package/ui/layouts/grid-layout/index.windows.js.map +1 -0
  217. package/ui/layouts/layout-base.android.d.ts +10 -3
  218. package/ui/layouts/layout-base.android.js +24 -7
  219. package/ui/layouts/layout-base.android.js.map +1 -1
  220. package/ui/layouts/layout-base.ios.js.map +1 -1
  221. package/ui/layouts/layout-base.windows.d.ts +4 -0
  222. package/ui/layouts/layout-base.windows.js +5 -0
  223. package/ui/layouts/layout-base.windows.js.map +1 -0
  224. package/ui/layouts/liquid-glass/index.windows.d.ts +4 -0
  225. package/ui/layouts/liquid-glass/index.windows.js +5 -0
  226. package/ui/layouts/liquid-glass/index.windows.js.map +1 -0
  227. package/ui/layouts/liquid-glass-container/index.windows.d.ts +4 -0
  228. package/ui/layouts/liquid-glass-container/index.windows.js +5 -0
  229. package/ui/layouts/liquid-glass-container/index.windows.js.map +1 -0
  230. package/ui/layouts/root-layout/index.windows.d.ts +13 -0
  231. package/ui/layouts/root-layout/index.windows.js +160 -0
  232. package/ui/layouts/root-layout/index.windows.js.map +1 -0
  233. package/ui/layouts/stack-layout/index.ios.js +1 -5
  234. package/ui/layouts/stack-layout/index.ios.js.map +1 -1
  235. package/ui/layouts/stack-layout/index.windows.d.ts +13 -0
  236. package/ui/layouts/stack-layout/index.windows.js +63 -0
  237. package/ui/layouts/stack-layout/index.windows.js.map +1 -0
  238. package/ui/layouts/wrap-layout/index.ios.js +1 -5
  239. package/ui/layouts/wrap-layout/index.ios.js.map +1 -1
  240. package/ui/layouts/wrap-layout/index.windows.d.ts +20 -0
  241. package/ui/layouts/wrap-layout/index.windows.js +182 -0
  242. package/ui/layouts/wrap-layout/index.windows.js.map +1 -0
  243. package/ui/list-picker/index.windows.d.ts +19 -0
  244. package/ui/list-picker/index.windows.js +75 -0
  245. package/ui/list-picker/index.windows.js.map +1 -0
  246. package/ui/list-view/index.d.ts +1 -13
  247. package/ui/list-view/index.ios.d.ts +1 -3
  248. package/ui/list-view/index.ios.js +10 -48
  249. package/ui/list-view/index.ios.js.map +1 -1
  250. package/ui/list-view/index.windows.d.ts +60 -0
  251. package/ui/list-view/index.windows.js +842 -0
  252. package/ui/list-view/index.windows.js.map +1 -0
  253. package/ui/list-view/list-view-common.d.ts +0 -14
  254. package/ui/list-view/list-view-common.js +0 -4
  255. package/ui/list-view/list-view-common.js.map +1 -1
  256. package/ui/page/index.d.ts +1 -1
  257. package/ui/page/index.ios.d.ts +0 -1
  258. package/ui/page/index.ios.js +1 -15
  259. package/ui/page/index.ios.js.map +1 -1
  260. package/ui/page/index.windows.d.ts +12 -0
  261. package/ui/page/index.windows.js +42 -0
  262. package/ui/page/index.windows.js.map +1 -0
  263. package/ui/page/page-common.d.ts +2 -5
  264. package/ui/page/page-common.js.map +1 -1
  265. package/ui/progress/index.windows.d.ts +20 -0
  266. package/ui/progress/index.windows.js +65 -0
  267. package/ui/progress/index.windows.js.map +1 -0
  268. package/ui/repeater/index.d.ts +1 -2
  269. package/ui/repeater/index.js.map +1 -1
  270. package/ui/scroll-view/index.d.ts +0 -13
  271. package/ui/scroll-view/index.ios.js +7 -21
  272. package/ui/scroll-view/index.ios.js.map +1 -1
  273. package/ui/scroll-view/index.windows.d.ts +29 -0
  274. package/ui/scroll-view/index.windows.js +192 -0
  275. package/ui/scroll-view/index.windows.js.map +1 -0
  276. package/ui/scroll-view/scroll-view-common.d.ts +0 -6
  277. package/ui/scroll-view/scroll-view-common.js +0 -8
  278. package/ui/scroll-view/scroll-view-common.js.map +1 -1
  279. package/ui/search-bar/index.windows.d.ts +19 -0
  280. package/ui/search-bar/index.windows.js +91 -0
  281. package/ui/search-bar/index.windows.js.map +1 -0
  282. package/ui/segmented-bar/index.windows.d.ts +23 -0
  283. package/ui/segmented-bar/index.windows.js +117 -0
  284. package/ui/segmented-bar/index.windows.js.map +1 -0
  285. package/ui/segmented-bar/segmented-bar-common.d.ts +1 -5
  286. package/ui/segmented-bar/segmented-bar-common.js.map +1 -1
  287. package/ui/slider/index.windows.d.ts +25 -0
  288. package/ui/slider/index.windows.js +134 -0
  289. package/ui/slider/index.windows.js.map +1 -0
  290. package/ui/split-view/index.windows.d.ts +49 -0
  291. package/ui/split-view/index.windows.js +549 -0
  292. package/ui/split-view/index.windows.js.map +1 -0
  293. package/ui/styling/background.windows.d.ts +2 -0
  294. package/ui/styling/background.windows.js +2 -0
  295. package/ui/styling/background.windows.js.map +1 -0
  296. package/ui/styling/font.d.ts +4 -0
  297. package/ui/styling/font.windows.d.ts +25 -0
  298. package/ui/styling/font.windows.js +213 -0
  299. package/ui/styling/font.windows.js.map +1 -0
  300. package/ui/styling/style/index.d.ts +0 -1
  301. package/ui/styling/style/index.js.map +1 -1
  302. package/ui/styling/style-properties.d.ts +0 -1
  303. package/ui/styling/style-properties.js +32 -41
  304. package/ui/styling/style-properties.js.map +1 -1
  305. package/ui/styling/style-scope.js +9 -1
  306. package/ui/styling/style-scope.js.map +1 -1
  307. package/ui/switch/index.windows.d.ts +20 -0
  308. package/ui/switch/index.windows.js +97 -0
  309. package/ui/switch/index.windows.js.map +1 -0
  310. package/ui/tab-view/index.ios.d.ts +1 -10
  311. package/ui/tab-view/index.ios.js +4 -21
  312. package/ui/tab-view/index.ios.js.map +1 -1
  313. package/ui/tab-view/index.windows.d.ts +29 -0
  314. package/ui/tab-view/index.windows.js +268 -0
  315. package/ui/tab-view/index.windows.js.map +1 -0
  316. package/ui/tab-view/tab-view-common.d.ts +1 -5
  317. package/ui/tab-view/tab-view-common.js.map +1 -1
  318. package/ui/text-base/index.android.d.ts +9 -2
  319. package/ui/text-base/index.android.js +24 -7
  320. package/ui/text-base/index.android.js.map +1 -1
  321. package/ui/text-base/index.windows.d.ts +47 -0
  322. package/ui/text-base/index.windows.js +639 -0
  323. package/ui/text-base/index.windows.js.map +1 -0
  324. package/ui/text-field/index.ios.d.ts +9 -2
  325. package/ui/text-field/index.ios.js +23 -2
  326. package/ui/text-field/index.ios.js.map +1 -1
  327. package/ui/text-field/index.windows.d.ts +23 -0
  328. package/ui/text-field/index.windows.js +186 -0
  329. package/ui/text-field/index.windows.js.map +1 -0
  330. package/ui/text-view/index.ios.d.ts +9 -2
  331. package/ui/text-view/index.ios.js +72 -20
  332. package/ui/text-view/index.ios.js.map +1 -1
  333. package/ui/text-view/index.windows.d.ts +12 -0
  334. package/ui/text-view/index.windows.js +47 -0
  335. package/ui/text-view/index.windows.js.map +1 -0
  336. package/ui/time-picker/index.windows.d.ts +18 -0
  337. package/ui/time-picker/index.windows.js +77 -0
  338. package/ui/time-picker/index.windows.js.map +1 -0
  339. package/ui/transition/fade-transition.windows.d.ts +3 -0
  340. package/ui/transition/fade-transition.windows.js +4 -0
  341. package/ui/transition/fade-transition.windows.js.map +1 -0
  342. package/ui/transition/index.d.ts +1 -2
  343. package/ui/transition/index.windows.d.ts +20 -0
  344. package/ui/transition/index.windows.js +30 -0
  345. package/ui/transition/index.windows.js.map +1 -0
  346. package/ui/transition/modal-transition.ios.js +5 -33
  347. package/ui/transition/modal-transition.ios.js.map +1 -1
  348. package/ui/transition/modal-transition.windows.d.ts +3 -0
  349. package/ui/transition/modal-transition.windows.js +4 -0
  350. package/ui/transition/modal-transition.windows.js.map +1 -0
  351. package/ui/transition/page-transition.ios.d.ts +0 -5
  352. package/ui/transition/page-transition.ios.js +33 -296
  353. package/ui/transition/page-transition.ios.js.map +1 -1
  354. package/ui/transition/page-transition.windows.d.ts +3 -0
  355. package/ui/transition/page-transition.windows.js +4 -0
  356. package/ui/transition/page-transition.windows.js.map +1 -0
  357. package/ui/transition/shared-transition-helper.android.d.ts +0 -3
  358. package/ui/transition/shared-transition-helper.android.js +0 -9
  359. package/ui/transition/shared-transition-helper.android.js.map +1 -1
  360. package/ui/transition/shared-transition-helper.d.ts +0 -7
  361. package/ui/transition/shared-transition-helper.ios.d.ts +0 -36
  362. package/ui/transition/shared-transition-helper.ios.js +89 -765
  363. package/ui/transition/shared-transition-helper.ios.js.map +1 -1
  364. package/ui/transition/shared-transition-helper.windows.d.ts +30 -0
  365. package/ui/transition/shared-transition-helper.windows.js +155 -0
  366. package/ui/transition/shared-transition-helper.windows.js.map +1 -0
  367. package/ui/transition/shared-transition.d.ts +0 -66
  368. package/ui/transition/shared-transition.js +2 -57
  369. package/ui/transition/shared-transition.js.map +1 -1
  370. package/ui/transition/slide-transition.windows.d.ts +3 -0
  371. package/ui/transition/slide-transition.windows.js +4 -0
  372. package/ui/transition/slide-transition.windows.js.map +1 -0
  373. package/ui/utils.windows.d.ts +9 -0
  374. package/ui/utils.windows.js +21 -0
  375. package/ui/utils.windows.js.map +1 -0
  376. package/ui/web-view/index.windows.d.ts +23 -0
  377. package/ui/web-view/index.windows.js +115 -0
  378. package/ui/web-view/index.windows.js.map +1 -0
  379. package/utils/constants.windows.d.ts +2 -0
  380. package/utils/constants.windows.js +5 -0
  381. package/utils/constants.windows.js.map +1 -0
  382. package/utils/debug-source.js +3 -0
  383. package/utils/debug-source.js.map +1 -1
  384. package/utils/index.windows.d.ts +20 -0
  385. package/utils/index.windows.js +94 -0
  386. package/utils/index.windows.js.map +1 -0
  387. package/utils/layout-helper/index.windows.d.ts +25 -0
  388. package/utils/layout-helper/index.windows.js +74 -0
  389. package/utils/layout-helper/index.windows.js.map +1 -0
  390. package/utils/mainthread-helper.windows.d.ts +3 -0
  391. package/utils/mainthread-helper.windows.js +18 -0
  392. package/utils/mainthread-helper.windows.js.map +1 -0
  393. package/utils/native-helper.android.d.ts +2 -66
  394. package/utils/native-helper.android.js.map +1 -1
  395. package/utils/native-helper.ios.d.ts +2 -105
  396. package/utils/native-helper.ios.js +4 -15
  397. package/utils/native-helper.ios.js.map +1 -1
  398. package/utils/native-helper.windows.d.ts +8 -0
  399. package/utils/native-helper.windows.js +101 -0
  400. package/utils/native-helper.windows.js.map +1 -0
  401. package/utils/platform-check.d.ts +1 -1
  402. package/utils/platform-check.js.map +1 -1
  403. package/utils/native-helper.types.d.ts +0 -2
@@ -3,115 +3,6 @@ import { isNumber } from '../../utils/types';
3
3
  import { Screen } from '../../platform';
4
4
  import { CORE_ANIMATION_DEFAULTS } from '../../utils/animation-helpers';
5
5
  import { ios as iOSUtils } from '../../utils/native-helper';
6
- import { Color } from '../../color';
7
- /**
8
- * Apply a drop shadow behind the destination view during an interactive
9
- * dismiss so it looks elevated above the source (Apple Music–style).
10
- *
11
- * Shadow + rounded corners can't coexist on the same CALayer on iOS — both
12
- * `masksToBounds = true` and `layer.mask` clip the shadow as part of the
13
- * compositing pipeline. So the shadow lives on a SIBLING CALayer inserted
14
- * below the modal's layer in its superlayer (the same pattern NS uses for
15
- * box-shadow via `outerShadowContainerLayer`). The modal keeps its own
16
- * `cornerRadius` + `masksToBounds` so subviews still clip to the rounded
17
- * shape.
18
- *
19
- * Because the shadow layer is a sibling (not a child), it doesn't inherit
20
- * the modal's transform automatically — `syncInteractiveDismissShadow`
21
- * mirrors transform/position/bounds during the drag.
22
- *
23
- * Falsy `shadowConfig` is a no-op.
24
- */
25
- export function applyInteractiveDismissShadow(presentedView, shadowConfig) {
26
- if (!presentedView?.layer || !shadowConfig)
27
- return;
28
- const layer = presentedView.layer;
29
- const superlayer = layer.superlayer;
30
- if (!superlayer)
31
- return;
32
- const bounds = layer.bounds;
33
- if (bounds.size.width <= 0 || bounds.size.height <= 0)
34
- return;
35
- // Idempotent.
36
- if (presentedView.__sharedTransitionShadowLayer)
37
- return;
38
- const cfg = shadowConfig === true ? {} : shadowConfig;
39
- const colorInput = cfg.color ?? '#000';
40
- let cgColor;
41
- try {
42
- const nsColor = typeof colorInput === 'string' ? new Color(colorInput) : colorInput;
43
- cgColor = nsColor.ios?.CGColor || nsColor.CGColor || UIColor.blackColor.CGColor;
44
- }
45
- catch (_) {
46
- cgColor = UIColor.blackColor.CGColor;
47
- }
48
- const opacity = isNumber(cfg.opacity) ? cfg.opacity : 0.3;
49
- const radius = isNumber(cfg.radius) ? cfg.radius : 30;
50
- const offsetX = isNumber(cfg.offset?.x) ? cfg.offset.x : 0;
51
- const offsetY = isNumber(cfg.offset?.y) ? cfg.offset.y : 8;
52
- const cornerRadius = layer.cornerRadius || 0;
53
- const roundedRectPath = UIBezierPath.bezierPathWithRoundedRectCornerRadius(CGRectMake(0, 0, bounds.size.width, bounds.size.height), cornerRadius).CGPath;
54
- const shadowLayer = CALayer.layer();
55
- // Match the modal's geometry so shadow tracks 1:1.
56
- shadowLayer.anchorPoint = layer.anchorPoint;
57
- shadowLayer.bounds = bounds;
58
- shadowLayer.position = layer.position;
59
- shadowLayer.transform = layer.transform;
60
- shadowLayer.shadowColor = cgColor;
61
- shadowLayer.shadowOpacity = opacity;
62
- shadowLayer.shadowRadius = radius;
63
- shadowLayer.shadowOffset = CGSizeMake(offsetX, offsetY);
64
- // Explicit shadowPath = shadow renders from this shape outward;
65
- // the layer itself stays fully transparent.
66
- shadowLayer.shadowPath = roundedRectPath;
67
- CATransaction.begin();
68
- CATransaction.setDisableActions(true);
69
- superlayer.insertSublayerBelow(shadowLayer, layer);
70
- CATransaction.commit();
71
- presentedView.__sharedTransitionShadowLayer = shadowLayer;
72
- }
73
- /**
74
- * Mirror the modal layer's geometry onto the sibling shadow layer so the
75
- * shadow tracks the interactive drag. Called from the gesture handlers
76
- * after the modal's state has been updated (either via direct transform
77
- * in morph mode, or via `interactiveController.updateInteractiveTransition`
78
- * for the non-morph modal/page case driven by UIViewPropertyAnimator).
79
- *
80
- * Reads the layer's **presentation** values when an animation is in flight
81
- * — model values would point at the animation's end state and snap the
82
- * shadow there. Falls back to model values when no animation is running.
83
- */
84
- export function syncInteractiveDismissShadow(presentedView) {
85
- const shadowLayer = presentedView?.__sharedTransitionShadowLayer;
86
- if (!shadowLayer || !presentedView?.layer)
87
- return;
88
- const layer = presentedView.layer;
89
- const pres = typeof layer.presentationLayer === 'function' ? layer.presentationLayer() : null;
90
- const src = pres || layer;
91
- const b = src.bounds;
92
- CATransaction.begin();
93
- CATransaction.setDisableActions(true);
94
- shadowLayer.bounds = b;
95
- shadowLayer.position = src.position;
96
- shadowLayer.anchorPoint = src.anchorPoint;
97
- shadowLayer.transform = src.transform;
98
- shadowLayer.shadowPath = UIBezierPath.bezierPathWithRoundedRectCornerRadius(CGRectMake(0, 0, b.size.width, b.size.height), src.cornerRadius || 0).CGPath;
99
- CATransaction.commit();
100
- }
101
- /**
102
- * Remove the sibling shadow layer. Safe to call repeatedly / when no
103
- * shadow was applied.
104
- */
105
- export function removeInteractiveDismissShadow(presentedView) {
106
- const shadowLayer = presentedView?.__sharedTransitionShadowLayer;
107
- if (!shadowLayer)
108
- return;
109
- CATransaction.begin();
110
- CATransaction.setDisableActions(true);
111
- shadowLayer.removeFromSuperlayer();
112
- CATransaction.commit();
113
- presentedView.__sharedTransitionShadowLayer = null;
114
- }
115
6
  export class SharedTransitionHelper {
116
7
  static animate(state, transitionContext, type) {
117
8
  const transition = state.instance;
@@ -143,10 +34,6 @@ export class SharedTransitionHelper {
143
34
  independent: [],
144
35
  };
145
36
  }
146
- // Track every matched source view so cleanup can restore alpha,
147
- // including duplicates (same album surfacing in multiple lists)
148
- // that we hide but don't create a snapshot for.
149
- transition.sharedElements._allPresentingViews = sharedElements.slice();
150
37
  if (SharedTransition.DEBUG) {
151
38
  console.log(` ${type}: Present`);
152
39
  console.log(`1. Found sharedTransitionTags to animate:`, sharedElementTags);
@@ -159,22 +46,12 @@ export class SharedTransitionHelper {
159
46
  const pageEndTags = pageEnd?.sharedTransitionTags || {};
160
47
  // console.log('pageEndIndependentTags:', pageEndIndependentTags);
161
48
  const positionSharedTags = async () => {
162
- const processedTags = new Set();
163
49
  for (const presentingView of sharedElements) {
164
50
  const presentingSharedElement = presentingView.ios;
165
- const tag = presentingView.sharedTransitionTag;
166
- if (processedTags.has(tag)) {
167
- // The same item can appear in multiple lists on the source page
168
- // (e.g., a featured album also surfacing in "Recently Played").
169
- // Each instance has the same sharedTransitionTag. Only the first
170
- // one becomes the snapshot origin; the rest must still be hidden
171
- // so they don't show through behind the animating snapshot.
172
- if (presentingSharedElement) {
173
- presentingSharedElement.alpha = 0;
174
- }
175
- continue;
176
- }
177
- processedTags.add(tag);
51
+ // console.log('fromTarget instanceof UIImageView:', fromTarget instanceof UIImageView)
52
+ // TODO: discuss whether we should check if UIImage/UIImageView type to always snapshot images or if other view types could be duped/added vs. snapshotted
53
+ // Note: snapshot may be most efficient/simple
54
+ // console.log('---> ', presentingView.sharedTransitionTag, ': ', presentingSharedElement)
178
55
  const presentedView = presented.find((v) => v.sharedTransitionTag === presentingView.sharedTransitionTag);
179
56
  const presentedSharedElement = presentedView.ios;
180
57
  const pageEndProps = pageEndTags[presentingView.sharedTransitionTag];
@@ -183,25 +60,15 @@ export class SharedTransitionHelper {
183
60
  await pageEndProps?.callback(presentedView, 'present');
184
61
  }
185
62
  // treat images differently...
186
- let imageSourceChangeListener;
187
63
  if (presentedSharedElement instanceof UIImageView) {
188
- // In case the image is loaded async, keep the snapshot's image in sync with
189
- // the destination view's image. We hold a ref so we can detach the listener
190
- // on cleanup (the View would otherwise hold a strong ref via the observers
191
- // map and the snapshot closure would leak).
192
- imageSourceChangeListener = () => {
64
+ // in case the image is loaded async, we need to update the snapshot when it changes
65
+ // todo: remove listener on transition end
66
+ presentedView.on('imageSourceChange', () => {
193
67
  snapshot.image = iOSUtils.snapshotView(presentedSharedElement, Screen.mainScreen.scale);
194
68
  snapshot.tintColor = presentedSharedElement.tintColor;
195
- };
196
- presentedView.on('imageSourceChange', imageSourceChangeListener);
69
+ });
197
70
  snapshot.tintColor = presentedSharedElement.tintColor;
198
71
  snapshot.contentMode = presentedSharedElement.contentMode;
199
- // Seed the snapshot with the source's already-loaded image so the very
200
- // first frame of the animation isn't blank if the destination image is
201
- // still loading.
202
- if (presentingSharedElement instanceof UIImageView) {
203
- snapshot.image = presentingSharedElement.image;
204
- }
205
72
  }
206
73
  iOSUtils.copyLayerProperties(snapshot, presentingSharedElement, pageEndProps?.propertiesToMatch);
207
74
  snapshot.clipsToBounds = true;
@@ -229,115 +96,86 @@ export class SharedTransitionHelper {
229
96
  startOpacity: presentedView.opacity,
230
97
  endOpacity: presentingView.opacity,
231
98
  propertiesToMatch: pageEndProps?.propertiesToMatch,
232
- imageSourceChangeListener,
233
99
  });
234
100
  // set initial opacity to match the source view opacity
235
101
  snapshot.alpha = presentingView.opacity;
236
- // Hide both while animating in the transition context.
237
- //
238
- // We mutate native alpha directly rather than NS `opacity` so the NS-side
239
- // style remains the user's intended value (typically 1). If we instead set
240
- // `view.opacity = 0` and then a transition was interrupted before cleanup
241
- // (or the page was reused), `startOpacity` here could capture 0 from a prior
242
- // run and the cleanup below would leave the destination invisible.
243
- presentingSharedElement.alpha = 0;
244
- presentedSharedElement.alpha = 0;
102
+ // hide both while animating within the transition context
103
+ presentingView.opacity = 0;
104
+ presentedView.opacity = 0;
245
105
  }
246
106
  };
247
107
  const positionIndependentTags = async () => {
248
- // "Independent" tags appear on only one of the two pages (or were
249
- // explicitly enumerated in pageEnd.sharedTransitionTags). We auto-discover
250
- // them so authors don't have to enumerate every tag manually:
251
- // - source-only (orphan on presenting): fade *out* on present, fade
252
- // back in on dismiss. e.g., a "FEATURED ALBUM" label on a hero card
253
- // that has no counterpart on the destination page.
254
- // - destination-only (orphan on presented): fade *in* on present, fade
255
- // back out on dismiss. e.g., metadata that only exists on the detail
256
- // page.
257
- // Authors can override per-tag via pageStart / pageEnd `sharedTransitionTags`
258
- // (e.g. add `y: -20` to slide while fading), or opt a view out entirely
259
- // with `sharedTransitionIgnore`.
260
- const orphanTags = [];
261
- const seenOrphan = new Set();
262
- const addOrphan = (tag) => {
263
- if (!tag || seenOrphan.has(tag) || sharedElementTags.includes(tag))
264
- return;
265
- seenOrphan.add(tag);
266
- orphanTags.push(tag);
267
- };
268
- for (const v of presenting)
269
- addOrphan(v.sharedTransitionTag);
270
- for (const v of presented)
271
- addOrphan(v.sharedTransitionTag);
272
- // Tags the user listed in pageEnd.sharedTransitionTags but that don't
273
- // match a real view are silently skipped further down — keep them in
274
- // the iteration so per-tag config still applies to existing orphans.
275
- for (const tag in pageEndTags)
276
- addOrphan(tag);
277
- for (const tag of orphanTags) {
278
- const pageStartIndependentProps = pageStart?.sharedTransitionTags ? pageStart?.sharedTransitionTags[tag] : null;
279
- const pageEndProps = pageEndTags[tag];
280
- let independentView = presenting.find((v) => v.sharedTransitionTag === tag);
281
- let isPresented = false;
282
- if (!independentView) {
283
- independentView = presented.find((v) => v.sharedTransitionTag === tag);
108
+ // independent tags
109
+ for (const tag in pageEndTags) {
110
+ // only handle if independent (otherwise it's shared between both pages and handled above)
111
+ if (!sharedElementTags.includes(tag)) {
112
+ // only consider start when there's a matching end
113
+ const pageStartIndependentProps = pageStart?.sharedTransitionTags ? pageStart?.sharedTransitionTags[tag] : null;
114
+ // console.log('start:', tag, pageStartIndependentProps);
115
+ const pageEndProps = pageEndTags[tag];
116
+ let independentView = presenting.find((v) => v.sharedTransitionTag === tag);
117
+ let isPresented = false;
284
118
  if (!independentView) {
285
- // Tag declared in config but no matching view; skip (don't
286
- // break — later tags might still resolve).
287
- continue;
119
+ independentView = presented.find((v) => v.sharedTransitionTag === tag);
120
+ if (!independentView) {
121
+ break;
122
+ }
123
+ isPresented = true;
288
124
  }
289
- isPresented = true;
290
- }
291
- const independentSharedElement = independentView.ios;
292
- if (pageEndProps?.callback) {
293
- await pageEndProps?.callback(independentView, 'present');
294
- }
295
- const snapshot = UIImageView.alloc().initWithImage(iOSUtils.snapshotView(independentSharedElement, Screen.mainScreen.scale));
296
- if (independentSharedElement instanceof UIImageView) {
297
- snapshot.tintColor = independentSharedElement.tintColor;
298
- snapshot.contentMode = independentSharedElement.contentMode;
299
- }
300
- snapshot.clipsToBounds = true;
301
- // Copy layer properties (cornerRadius, borderWidth/Color)
302
- // from the source view so the snapshot renders with the
303
- // same rounded corners. Without this, source-side
304
- // thumbnails/buttons appear with sharp square corners
305
- // during a non-morph interactive dismiss — the snapshot
306
- // is what the user sees through the dismissing modal,
307
- // and its layer is freshly created with cornerRadius 0.
308
- iOSUtils.copyLayerProperties(snapshot, independentSharedElement, pageEndProps?.propertiesToMatch);
309
- const startFrame = independentSharedElement.convertRectToView(independentSharedElement.bounds, transitionContext.containerView);
310
- snapshot.frame = startFrame;
311
- if (SharedTransition.DEBUG) {
312
- console.log('---> ', independentView.sharedTransitionTag, ' frame:', iOSUtils.printCGRect(snapshot.frame));
125
+ const independentSharedElement = independentView.ios;
126
+ if (pageEndProps?.callback) {
127
+ await pageEndProps?.callback(independentView, 'present');
128
+ }
129
+ // let snapshot: UIImageView;
130
+ // if (isPresented) {
131
+ // snapshot = UIImageView.alloc().init();
132
+ // } else {
133
+ const snapshot = UIImageView.alloc().initWithImage(iOSUtils.snapshotView(independentSharedElement, Screen.mainScreen.scale));
134
+ // }
135
+ if (independentSharedElement instanceof UIImageView) {
136
+ // in case the image is loaded async, we need to update the snapshot when it changes
137
+ // todo: remove listener on transition end
138
+ // if (isPresented) {
139
+ // independentView.on('imageSourceChange', () => {
140
+ // snapshot.image = iOSNativeHelper.snapshotView(independentSharedElement, Screen.mainScreen.scale);
141
+ // snapshot.tintColor = independentSharedElement.tintColor;
142
+ // });
143
+ // }
144
+ snapshot.tintColor = independentSharedElement.tintColor;
145
+ snapshot.contentMode = independentSharedElement.contentMode;
146
+ }
147
+ snapshot.clipsToBounds = true;
148
+ const startFrame = independentSharedElement.convertRectToView(independentSharedElement.bounds, transitionContext.containerView);
149
+ const startFrameRect = getRectFromProps(pageStartIndependentProps);
150
+ // adjust for any specified start positions
151
+ const startFrameAdjusted = CGRectMake(startFrame.origin.x + startFrameRect.x, startFrame.origin.y + startFrameRect.y, startFrame.size.width, startFrame.size.height);
152
+ // console.log('startFrameAdjusted:', tag, iOSNativeHelper.printCGRect(startFrameAdjusted));
153
+ // if (pageStartIndependentProps?.scale) {
154
+ // snapshot.transform = CGAffineTransformConcat(CGAffineTransformMakeTranslation(startFrameAdjusted.origin.x, startFrameAdjusted.origin.y), CGAffineTransformMakeScale(pageStartIndependentProps.scale.x, pageStartIndependentProps.scale.y))
155
+ // } else {
156
+ snapshot.frame = startFrame; //startFrameAdjusted;
157
+ // }
158
+ if (SharedTransition.DEBUG) {
159
+ console.log('---> ', independentView.sharedTransitionTag, ' frame:', iOSUtils.printCGRect(snapshot.frame));
160
+ }
161
+ const endFrameRect = getRectFromProps(pageEndProps);
162
+ const endFrame = CGRectMake(startFrame.origin.x + endFrameRect.x, startFrame.origin.y + endFrameRect.y, startFrame.size.width, startFrame.size.height);
163
+ // console.log('endFrame:', tag, iOSNativeHelper.printCGRect(endFrame));
164
+ transition.sharedElements.independent.push({
165
+ view: independentView,
166
+ isPresented,
167
+ startFrame,
168
+ snapshot,
169
+ endFrame,
170
+ startTransform: independentSharedElement.transform,
171
+ scale: pageEndProps.scale,
172
+ startOpacity: independentView.opacity,
173
+ endOpacity: isNumber(pageEndProps.opacity) ? pageEndProps.opacity : 0,
174
+ propertiesToMatch: pageEndProps?.propertiesToMatch,
175
+ zIndex: isNumber(pageEndProps?.zIndex) ? pageEndProps.zIndex : 0,
176
+ });
177
+ independentView.opacity = 0;
313
178
  }
314
- const endFrameRect = getRectFromProps(pageEndProps);
315
- const endFrame = CGRectMake(startFrame.origin.x + (endFrameRect.x || 0), startFrame.origin.y + (endFrameRect.y || 0), startFrame.size.width, startFrame.size.height);
316
- // Opacity defaults are side-aware: source-only orphans fade out (1 → 0),
317
- // destination-only orphans fade in (0 → 1). The values are read back
318
- // during dismiss as `endOpacity → startOpacity` so the return phase is
319
- // automatically symmetric. Author-supplied opacity always wins.
320
- const startOpacity = isNumber(pageStartIndependentProps?.opacity) ? pageStartIndependentProps.opacity : isPresented ? 0 : independentView.opacity;
321
- const endOpacity = isNumber(pageEndProps?.opacity) ? pageEndProps.opacity : isPresented ? independentView.opacity : 0;
322
- // Snapshot's initial visible alpha. Default UIImageView alpha is 1;
323
- // destination-only orphans need to start at 0 so the fade-in is
324
- // visible, hence we always set it explicitly.
325
- snapshot.alpha = startOpacity;
326
- transition.sharedElements.independent.push({
327
- view: independentView,
328
- isPresented,
329
- startFrame,
330
- snapshot,
331
- endFrame,
332
- startTransform: independentSharedElement.transform,
333
- scale: pageEndProps?.scale,
334
- startOpacity,
335
- endOpacity,
336
- propertiesToMatch: pageEndProps?.propertiesToMatch,
337
- zIndex: isNumber(pageEndProps?.zIndex) ? pageEndProps.zIndex : 0,
338
- });
339
- // Native alpha; see comment in positionSharedTags.
340
- independentSharedElement.alpha = 0;
341
179
  }
342
180
  };
343
181
  // position all sharedTransitionTag elements
@@ -345,7 +183,7 @@ export class SharedTransitionHelper {
345
183
  await positionIndependentTags();
346
184
  // combine to order by zIndex and add to transition context
347
185
  const snapshotData = transition.sharedElements.presenting.concat(transition.sharedElements.independent);
348
- snapshotData.sort((a, b) => (a.zIndex || 0) - (b.zIndex || 0));
186
+ snapshotData.sort((a, b) => (a.zIndex > b.zIndex ? 1 : -1));
349
187
  if (SharedTransition.DEBUG) {
350
188
  console.log(`zIndex settings:`, snapshotData.map((s) => {
351
189
  return {
@@ -361,41 +199,9 @@ export class SharedTransitionHelper {
361
199
  // Important: always set after above shared element positions have had their start positions set
362
200
  transition.presented.view.alpha = isNumber(pageStart?.opacity) ? pageStart?.opacity : 0;
363
201
  transition.presented.view.frame = CGRectMake(startFrame.x, startFrame.y, startFrame.width, startFrame.height);
364
- // Optional top-corner rounding for sheet-style transitions (e.g.
365
- // a modal that's rounded at the bottom of the screen and flattens
366
- // as it slides up). Setting maskedCorners and masksToBounds here
367
- // (before the animation) so they're stable during the animated
368
- // cornerRadius change.
369
- if (isNumber(pageStart?.cornerRadius) || isNumber(pageEnd?.cornerRadius)) {
370
- const layer = transition.presented.view.layer;
371
- // top-left | top-right | bottom-left | bottom-right (CACornerMask bits)
372
- layer.maskedCorners = 15;
373
- layer.masksToBounds = true;
374
- if (isNumber(pageStart?.cornerRadius)) {
375
- layer.cornerRadius = pageStart.cornerRadius;
376
- }
377
- }
378
202
  const cleanupPresent = () => {
379
203
  for (const presented of transition.sharedElements.presented) {
380
- // Detach the per-transition imageSourceChange listener registered
381
- // during positionSharedTags so it doesn't leak (the snapshot is gone).
382
- if (presented.imageSourceChangeListener) {
383
- presented.view.off('imageSourceChange', presented.imageSourceChangeListener);
384
- presented.imageSourceChangeListener = null;
385
- }
386
- // Restore the destination native alpha from the NS opacity (the source
387
- // of truth). NS opacity wasn't modified during the transition, so this
388
- // reflects the user's intended visibility (typically 1).
389
- presented.view.ios.alpha = presented.view.opacity;
390
- }
391
- // Restore native alpha on every source view we touched — including
392
- // duplicates that share a sharedTransitionTag and were hidden without
393
- // a snapshot. Even though the source page is being removed, the View
394
- // instances may be reused on subsequent navigations.
395
- for (const sourceView of transition.sharedElements._allPresentingViews || []) {
396
- if (sourceView?.ios) {
397
- sourceView.ios.alpha = sourceView.opacity;
398
- }
204
+ presented.view.opacity = presented.startOpacity;
399
205
  }
400
206
  for (const presenting of transition.sharedElements.presenting) {
401
207
  presenting.snapshot.removeFromSuperview();
@@ -403,7 +209,7 @@ export class SharedTransitionHelper {
403
209
  for (const independent of transition.sharedElements.independent) {
404
210
  independent.snapshot.removeFromSuperview();
405
211
  if (independent.isPresented) {
406
- independent.view.ios.alpha = independent.view.opacity;
212
+ independent.view.opacity = independent.startOpacity;
407
213
  }
408
214
  }
409
215
  SharedTransition.updateState(transition.id, {
@@ -426,12 +232,6 @@ export class SharedTransitionHelper {
426
232
  transition.presented.view.alpha = isNumber(pageEnd?.opacity) ? pageEnd?.opacity : 1;
427
233
  const endFrame = getRectFromProps(pageEnd);
428
234
  transition.presented.view.frame = CGRectMake(endFrame.x, endFrame.y, endFrame.width, endFrame.height);
429
- // Animate cornerRadius alongside the page frame. Implicit animation
430
- // of cornerRadius is supported on iOS 11+, both inside
431
- // UIView.animateWith… and UIViewPropertyAnimator's animations block.
432
- if (isNumber(pageEnd?.cornerRadius)) {
433
- transition.presented.view.layer.cornerRadius = pageEnd.cornerRadius;
434
- }
435
235
  if (pageOut) {
436
236
  if (isNumber(pageOut.opacity)) {
437
237
  transition.presenting.view.alpha = pageOut?.opacity;
@@ -510,23 +310,6 @@ export class SharedTransitionHelper {
510
310
  });
511
311
  if (type === 'page') {
512
312
  transitionContext.containerView.insertSubviewBelowSubview(transition.presenting.view, transition.presented.view);
513
- // UIKit's standard pop places the incoming source view off to the
514
- // left so it can slide into position; for custom shared transitions
515
- // (where the destination either slides down or morphs to source) we
516
- // don't want that lateral slide. Pin the source to its fullscreen
517
- // frame so it stays put underneath the animating destination.
518
- // Users can still opt into a custom source animation via `pageOut`.
519
- const sourceDefaults = getRectFromProps(null);
520
- transition.presenting.view.frame = CGRectMake(0, 0, sourceDefaults.width, sourceDefaults.height);
521
- }
522
- // Morph + interactive dismiss: the gesture handler drives the
523
- // animation via transforms and finalizes by calling cancel/finish
524
- // on the transitionContext. Running the standard snapshot + spring
525
- // rig here would race that and frequently call completeTransition(true)
526
- // *before* the user's gesture ended — causing the dismiss to commit
527
- // even on a cancel. Skip the rest of the dismiss setup entirely.
528
- if (state.interactive?.dismiss?.morph && state.interactiveBegan) {
529
- return;
530
313
  }
531
314
  // console.log('transitionContext.containerView.subviews.count:', transitionContext.containerView.subviews.count);
532
315
  if (SharedTransition.DEBUG) {
@@ -539,21 +322,11 @@ export class SharedTransitionHelper {
539
322
  const pageEndTags = pageEnd?.sharedTransitionTags || {};
540
323
  const pageReturn = state.pageReturn;
541
324
  for (const p of transition.sharedElements.presented) {
542
- // Use native alpha (not NS opacity) so we don't pollute the NS-side
543
- // value if the dismiss is interrupted; cleanup restores from NS opacity.
544
- p.view.ios.alpha = 0;
545
- }
546
- // Ensure top-corner masking + clipping is in place before we animate
547
- // cornerRadius back toward the start value. If the present pass already
548
- // set these, this is a harmless no-op.
549
- if (isNumber(pageReturn?.cornerRadius)) {
550
- const layer = transition.presented.view.layer;
551
- layer.maskedCorners = 15; // top-left | top-right | bottom-left | bottom-right
552
- layer.masksToBounds = true;
325
+ p.view.opacity = 0;
553
326
  }
554
327
  // combine to order by zIndex and add to transition context
555
328
  const snapshotData = transition.sharedElements.presenting.concat(transition.sharedElements.independent);
556
- snapshotData.sort((a, b) => (a.zIndex || 0) - (b.zIndex || 0));
329
+ snapshotData.sort((a, b) => (a.zIndex > b.zIndex ? 1 : -1));
557
330
  if (SharedTransition.DEBUG) {
558
331
  console.log(`zIndex settings:`, snapshotData.map((s) => {
559
332
  return {
@@ -592,43 +365,13 @@ export class SharedTransitionHelper {
592
365
  // add snapshot to animate
593
366
  transitionContext.containerView.addSubview(data.snapshot);
594
367
  }
595
- // Hide every source-side shared element now that snapshots have been
596
- // captured. The animating snapshot covers them; without this, the user
597
- // sees a "double image" — the real source element AND the snapshot
598
- // animating over it back to its position. Use the full list (not just
599
- // the deduped `presenting`) so duplicates from sister lists are hidden
600
- // too. Restored in cleanupDismiss below.
601
- for (const sourceView of transition.sharedElements._allPresentingViews || []) {
602
- if (sourceView?.ios) {
603
- sourceView.ios.alpha = 0;
604
- }
605
- }
606
368
  const cleanupDismiss = () => {
607
- // Restore alpha on every source view we hid — including duplicate
608
- // sources with the same sharedTransitionTag — using NS opacity as
609
- // the source of truth.
610
- for (const sourceView of transition.sharedElements._allPresentingViews || []) {
611
- if (sourceView?.ios) {
612
- sourceView.ios.alpha = sourceView.opacity;
613
- }
614
- }
615
369
  for (const presenting of transition.sharedElements.presenting) {
370
+ presenting.view.opacity = presenting.startOpacity;
616
371
  presenting.snapshot.removeFromSuperview();
617
372
  }
618
- for (const presented of transition.sharedElements.presented) {
619
- // Detach the imageSourceChange listener and restore alpha. Even though
620
- // the destination page is being torn down, NS Views can outlive their
621
- // nativeView and we shouldn't leak observers.
622
- if (presented.imageSourceChangeListener) {
623
- presented.view.off('imageSourceChange', presented.imageSourceChangeListener);
624
- presented.imageSourceChangeListener = null;
625
- }
626
- if (presented.view.ios) {
627
- presented.view.ios.alpha = presented.view.opacity;
628
- }
629
- }
630
373
  for (const independent of transition.sharedElements.independent) {
631
- independent.view.ios.alpha = independent.view.opacity;
374
+ independent.view.opacity = independent.startOpacity;
632
375
  independent.snapshot.removeFromSuperview();
633
376
  }
634
377
  SharedTransition.finishState(transition.id);
@@ -647,11 +390,6 @@ export class SharedTransitionHelper {
647
390
  transition.presented.view.alpha = isNumber(pageReturn?.opacity) ? pageReturn?.opacity : 0;
648
391
  const endFrame = getRectFromProps(pageReturn, getPageStartDefaultsForType(type));
649
392
  transition.presented.view.frame = CGRectMake(endFrame.x, endFrame.y, endFrame.width, endFrame.height);
650
- // Animate cornerRadius back toward the start value (e.g. a sheet
651
- // re-rounds as it slides offscreen).
652
- if (isNumber(pageReturn?.cornerRadius)) {
653
- transition.presented.view.layer.cornerRadius = pageReturn.cornerRadius;
654
- }
655
393
  if (pageOut) {
656
394
  // always return to defaults if pageOut had been used
657
395
  transition.presenting.view.alpha = 1;
@@ -712,78 +450,20 @@ export class SharedTransitionHelper {
712
450
  switch (type) {
713
451
  case 'page':
714
452
  interactiveState.transitionContext.containerView.insertSubviewBelowSubview(state.instance.presenting.view, state.instance.presented.view);
715
- // Pin the source view to its fullscreen frame so it doesn't slide
716
- // in from off-left as the user drags. The default UIKit pop expects
717
- // to animate the source from off-left; for shared-element / morph
718
- // transitions we want the source to stay put underneath the
719
- // animating destination so the visuals feel connected.
720
- {
721
- const sourceDefaults = getRectFromProps(null);
722
- state.instance.presenting.view.frame = CGRectMake(0, 0, sourceDefaults.width, sourceDefaults.height);
723
- }
724
453
  break;
725
454
  }
726
- // Apply the dismiss shadow here, not from the gesture handler. UIKit
727
- // reparents the presented view into the transition containerView as
728
- // part of starting the interactive transition; applying earlier would
729
- // attach the shadow to the now-orphaned old superlayer.
730
- if (state.interactive?.dismiss?.shadow && state.instance?.presented?.view) {
731
- applyInteractiveDismissShadow(state.instance.presented.view, state.interactive.dismiss.shadow);
732
- }
733
455
  }
734
456
  static interactiveUpdate(state, interactiveState, type, percent) {
735
457
  if (interactiveState) {
736
- if (state.interactive?.dismiss?.morph) {
737
- // Morph mode: the gesture handler drives the destination view's
738
- // transform directly. We only forward the event so observers can
739
- // react to the gesture's percentage.
740
- SharedTransition.notifyEvent(SharedTransition.interactiveUpdateEvent, {
741
- id: state?.instance?.id,
742
- type,
743
- percent,
744
- });
745
- return;
746
- }
747
458
  if (!interactiveState.added) {
748
- // Defer setup until the gesture has clearly committed to a horizontal
749
- // dismiss motion. A vertical scroll on a descendant scroll view also
750
- // triggers the page-level pan gesture (NS pan recognizers don't yield
751
- // to scroll-view pans by default), producing near-zero percent values.
752
- // Without this guard we'd mount the dismiss snapshots and hide the
753
- // destination during a scroll, making the image look "stuck" until the
754
- // cancel animation runs.
755
- if (Math.abs(percent) < 0.05) {
756
- return;
757
- }
758
459
  interactiveState.added = true;
759
460
  for (const p of state.instance.sharedElements.presented) {
760
- // Native alpha (not NS opacity) for the same reason as the dismiss path:
761
- // if the user lets go without crossing the threshold, cancel uses NS
762
- // opacity as source of truth to restore.
763
- p.view.ios.alpha = 0;
461
+ p.view.opacity = 0;
764
462
  }
765
463
  for (const p of state.instance.sharedElements.presenting) {
766
464
  p.snapshot.alpha = p.endOpacity;
767
465
  interactiveState.transitionContext.containerView.addSubview(p.snapshot);
768
466
  }
769
- // Re-mount independent (orphan) snapshots so they're available to
770
- // animate alongside the gesture. They were removed in present cleanup
771
- // but the records (including their snapshots) live on transition.sharedElements.
772
- // Source-only orphans were left at alpha 0 since present; their snapshots
773
- // pick up where the present animation left off (endOpacity).
774
- for (const ind of state.instance.sharedElements.independent) {
775
- ind.snapshot.alpha = ind.endOpacity;
776
- interactiveState.transitionContext.containerView.addSubview(ind.snapshot);
777
- }
778
- // Hide every source-side shared element (including duplicates that share
779
- // a sharedTransitionTag in sister lists) so the user only sees the
780
- // animating snapshot — not the snapshot AND the real source element
781
- // simultaneously ("double image" during interactive dismissal).
782
- for (const sourceView of state.instance.sharedElements._allPresentingViews || []) {
783
- if (sourceView?.ios) {
784
- sourceView.ios.alpha = 0;
785
- }
786
- }
787
467
  const pageStart = state.pageStart;
788
468
  const startFrame = getRectFromProps(pageStart, getPageStartDefaultsForType(type));
789
469
  interactiveState.propertyAnimator = UIViewPropertyAnimator.alloc().initWithDurationDampingRatioAnimations(1, 1, () => {
@@ -792,25 +472,8 @@ export class SharedTransitionHelper {
792
472
  iOSUtils.copyLayerProperties(p.snapshot, p.view.ios, p.propertiesToMatch);
793
473
  p.snapshot.alpha = 1;
794
474
  }
795
- // Animate orphan snapshots back toward their start state alongside
796
- // the rest of the dismiss. For source-only orphans this is the
797
- // fade-back-in that mirrors the fade-out of present.
798
- for (const ind of state.instance.sharedElements.independent) {
799
- ind.snapshot.alpha = ind.startOpacity;
800
- if (ind.scale) {
801
- ind.snapshot.transform = ind.startTransform;
802
- }
803
- else {
804
- ind.snapshot.frame = ind.startFrame;
805
- }
806
- }
807
475
  state.instance.presented.view.alpha = isNumber(state.pageReturn?.opacity) ? state.pageReturn?.opacity : 0;
808
476
  state.instance.presented.view.frame = CGRectMake(startFrame.x, startFrame.y, state.instance.presented.view.bounds.size.width, state.instance.presented.view.bounds.size.height);
809
- // Drive cornerRadius via the same percent the user controls — round
810
- // the page back up as they pan it offscreen.
811
- if (isNumber(state.pageReturn?.cornerRadius)) {
812
- state.instance.presented.view.layer.cornerRadius = state.pageReturn.cornerRadius;
813
- }
814
477
  });
815
478
  }
816
479
  interactiveState.propertyAnimator.fractionComplete = percent;
@@ -822,108 +485,17 @@ export class SharedTransitionHelper {
822
485
  }
823
486
  }
824
487
  static interactiveCancel(state, interactiveState, type) {
825
- if (state?.instance && interactiveState && state.interactive?.dismiss?.morph) {
826
- // Morph mode cancel — spring the destination view back to identity.
827
- const view = state.instance.presented?.view;
828
- let didFinalize = false;
829
- const finalize = () => {
830
- if (didFinalize)
831
- return;
832
- didFinalize = true;
833
- if (view)
834
- view.transform = CGAffineTransformIdentity;
835
- // Restore the source-side element alphas that the gesture hid on
836
- // engagement so the source page is correct when shown again.
837
- for (const v of state.instance.sharedElements?._allPresentingViews || []) {
838
- if (v?.ios)
839
- v.ios.alpha = v.opacity;
840
- }
841
- if (interactiveState.transitionContext) {
842
- interactiveState.transitionContext.cancelInteractiveTransition();
843
- interactiveState.transitionContext.completeTransition(false);
844
- }
845
- SharedTransition.updateState(state?.instance?.id, {
846
- interactiveBegan: false,
847
- interactiveCancelled: true,
848
- });
849
- SharedTransition.notifyEvent(SharedTransition.interactiveCancelledEvent, {
850
- id: state?.instance?.id,
851
- type,
852
- });
853
- };
854
- if (view) {
855
- iOSUtils.animateWithSpring({
856
- animations: () => {
857
- view.transform = CGAffineTransformIdentity;
858
- // Cross-fade sources back IN PARALLEL with the spring so
859
- // they're visible from frame one of the snap-back. This
860
- // also makes the source restoration robust to a new
861
- // gesture interrupting our completion callback.
862
- for (const v of state.instance.sharedElements?._allPresentingViews || []) {
863
- if (v?.ios)
864
- v.ios.alpha = v.opacity;
865
- }
866
- },
867
- completion: () => finalize(),
868
- });
869
- // Safety: ensure finalize runs even if the animation completion
870
- // is dropped (e.g. interrupted by another gesture).
871
- setTimeout(finalize, 800);
872
- }
873
- else {
874
- finalize();
875
- }
876
- return;
877
- }
878
- if (state?.instance && interactiveState && !interactiveState.added) {
879
- // The gesture engaged the interactive transition but never crossed the
880
- // motion threshold in interactiveUpdate (e.g., the user was scrolling
881
- // vertically). Nothing was visually set up — just tell UIKit we're
882
- // cancelling and clear the flags.
883
- if (interactiveState.transitionContext) {
884
- interactiveState.transitionContext.cancelInteractiveTransition();
885
- interactiveState.transitionContext.completeTransition(false);
886
- }
887
- SharedTransition.updateState(state?.instance?.id, {
888
- interactiveBegan: false,
889
- interactiveCancelled: true,
890
- });
891
- SharedTransition.notifyEvent(SharedTransition.interactiveCancelledEvent, {
892
- id: state?.instance?.id,
893
- type,
894
- });
895
- return;
896
- }
897
488
  if (state?.instance && interactiveState?.added && interactiveState?.propertyAnimator) {
898
489
  interactiveState.propertyAnimator.reversed = true;
899
490
  const duration = isNumber(state.pageEnd?.duration) ? state.pageEnd?.duration / 1000 : CORE_ANIMATION_DEFAULTS.duration;
900
491
  interactiveState.propertyAnimator.continueAnimationWithTimingParametersDurationFactor(null, duration);
901
492
  setTimeout(() => {
902
493
  for (const p of state.instance.sharedElements.presented) {
903
- // Restore native alpha from NS opacity (the user-intended value).
904
- p.view.ios.alpha = p.view.opacity;
905
- }
906
- // Restore alpha on every source view we hid during interactiveUpdate
907
- // (including duplicates from sister lists).
908
- for (const sourceView of state.instance.sharedElements._allPresentingViews || []) {
909
- if (sourceView?.ios) {
910
- sourceView.ios.alpha = sourceView.opacity;
911
- }
494
+ p.view.opacity = 1;
912
495
  }
913
496
  for (const p of state.instance.sharedElements.presenting) {
914
497
  p.snapshot.removeFromSuperview();
915
498
  }
916
- // Tear down orphan snapshots that interactiveUpdate re-mounted. The
917
- // source-only orphans' view.alpha stays at 0 — we're returning to the
918
- // presented (modal-on-top) state, so they should remain hidden until
919
- // a real dismiss completes. Cancel/finish for the next dismiss owns
920
- // the eventual restore.
921
- for (const ind of state.instance.sharedElements.independent) {
922
- ind.snapshot.removeFromSuperview();
923
- // Reset snapshot alpha to its post-present end state so a subsequent
924
- // interactiveUpdate picks up from the right place.
925
- ind.snapshot.alpha = ind.endOpacity;
926
- }
927
499
  state.instance.presented.view.alpha = 1;
928
500
  interactiveState.propertyAnimator = null;
929
501
  interactiveState.added = false;
@@ -941,263 +513,15 @@ export class SharedTransitionHelper {
941
513
  }
942
514
  }
943
515
  static interactiveFinish(state, interactiveState, type) {
944
- if (state?.instance && interactiveState && state.interactive?.dismiss?.morph) {
945
- // Morph mode finish — animate the destination view to the matching
946
- // source element's frame and fade it out, then complete.
947
- const view = state.instance.presented?.view;
948
- const destPresented = state.instance.sharedElements?.presented?.[0];
949
- const destTag = destPresented?.view?.sharedTransitionTag;
950
- const matchingSource = state.instance.sharedElements?.presenting?.find?.((p) => p.view.sharedTransitionTag === destTag);
951
- const srcIos = matchingSource?.view?.ios;
952
- const destSharedIos = destPresented?.view?.ios;
953
- const containerView = interactiveState.transitionContext?.containerView;
954
- let targetTransform = null;
955
- if (view && srcIos && containerView) {
956
- const sourceFrame = srcIos.convertRectToView(srcIos.bounds, containerView);
957
- const bounds = view.bounds;
958
- if (bounds.size.width > 0 && bounds.size.height > 0 && sourceFrame.size.width > 0 && sourceFrame.size.height > 0) {
959
- // Anchor the modal's transform on the *internal* matched
960
- // element (e.g. the album art inside the modal) so that the
961
- // modal and the matched element converge along the same
962
- // trajectory to the source thumbnail. Without this, the modal
963
- // scales around its own center while the matched-element
964
- // snapshot flies separately to source — making the two visibly
965
- // drift apart mid-spring.
966
- //
967
- // Pick a uniform scale that takes the modal's matched element
968
- // to the source's size. For square album art (both sides) this
969
- // is exact; for slightly off-square sources (e.g. 360×380) we
970
- // match width and let the small remainder be hidden by the
971
- // fade-out.
972
- const destSharedFrameInModal = destSharedIos ? destSharedIos.convertRectToView(destSharedIos.bounds, view) : null;
973
- const sx = sourceFrame.size.width / bounds.size.width;
974
- const sy = sourceFrame.size.height / bounds.size.height;
975
- const targetCx = sourceFrame.origin.x + sourceFrame.size.width / 2;
976
- const targetCy = sourceFrame.origin.y + sourceFrame.size.height / 2;
977
- const modalCx = bounds.size.width / 2;
978
- const modalCy = bounds.size.height / 2;
979
- let tx;
980
- let ty;
981
- if (destSharedFrameInModal && destSharedFrameInModal.size.width > 0 && destSharedFrameInModal.size.height > 0) {
982
- // Place the internal album art's center on the source's
983
- // center. After scaling around modal center, internal art's
984
- // visual center = modalCenter + (internalArtCenter - modalCenter) * scale + translation.
985
- const internalCx = destSharedFrameInModal.origin.x + destSharedFrameInModal.size.width / 2;
986
- const internalCy = destSharedFrameInModal.origin.y + destSharedFrameInModal.size.height / 2;
987
- tx = targetCx - modalCx - (internalCx - modalCx) * sx;
988
- ty = targetCy - modalCy - (internalCy - modalCy) * sy;
989
- }
990
- else {
991
- // Fallback: align modal center on source center.
992
- tx = targetCx - modalCx;
993
- ty = targetCy - modalCy;
994
- }
995
- targetTransform = CGAffineTransformConcat(CGAffineTransformMakeTranslation(tx, ty), CGAffineTransformMakeScale(sx, sy));
996
- }
997
- }
998
- // Build a snapshot fly-back for each shared element so the album
999
- // art (etc.) does a real shared-element transition to its source
1000
- // frame in parallel with the destination view's shrink+fade.
1001
- // Without this, the image rides along with the morphing view and
1002
- // lands at a visually offset position rather than precisely back
1003
- // at the source thumbnail.
1004
- const sharedSnapshots = [];
1005
- if (containerView) {
1006
- for (const presented of state.instance.sharedElements?.presented || []) {
1007
- const destSharedView = presented.view?.ios;
1008
- const tag = presented.view?.sharedTransitionTag;
1009
- if (!destSharedView || !tag)
1010
- continue;
1011
- const sourceShared = state.instance.sharedElements?.presenting?.find?.((p) => p.view.sharedTransitionTag === tag);
1012
- const srcSharedView = sourceShared?.view?.ios;
1013
- if (!srcSharedView)
1014
- continue;
1015
- const startFrame = destSharedView.convertRectToView(destSharedView.bounds, containerView);
1016
- const endFrame = srcSharedView.convertRectToView(srcSharedView.bounds, containerView);
1017
- if (startFrame.size.width <= 0 || endFrame.size.width <= 0)
1018
- continue;
1019
- const snap = UIImageView.alloc().init();
1020
- if (destSharedView instanceof UIImageView && destSharedView.image) {
1021
- snap.image = destSharedView.image;
1022
- snap.contentMode = destSharedView.contentMode;
1023
- snap.tintColor = destSharedView.tintColor;
1024
- }
1025
- else {
1026
- try {
1027
- snap.image = iOSUtils.snapshotView(presented.view.ios, Screen.mainScreen.scale);
1028
- }
1029
- catch (e) {
1030
- continue;
1031
- }
1032
- }
1033
- snap.clipsToBounds = true;
1034
- snap.layer.cornerRadius = destSharedView.layer?.cornerRadius || 0;
1035
- snap.frame = startFrame;
1036
- containerView.addSubview(snap);
1037
- // Hide the destination shared element so we don't see it
1038
- // shrinking inside the morphing view at the same time the
1039
- // snapshot is flying back to source — that would double up.
1040
- destSharedView.alpha = 0;
1041
- sharedSnapshots.push({
1042
- snap,
1043
- endFrame,
1044
- endCornerRadius: srcSharedView.layer?.cornerRadius || 0,
1045
- srcSharedView,
1046
- });
1047
- }
1048
- }
1049
- // Identify which source NS views have a matching fly-back snapshot.
1050
- // Those sources stay at alpha 0 through the spring and are restored
1051
- // inside finalize(), so the snapshot doesn't overlay an already-
1052
- // visible source mid-flight (which looks like two images for a beat).
1053
- const snapshottedSources = new Set();
1054
- for (const entry of sharedSnapshots) {
1055
- if (entry.srcSharedView)
1056
- snapshottedSources.add(entry.srcSharedView);
1057
- }
1058
- // Source-only orphan views (album thumbnails, badges, etc.) were
1059
- // already restored to their opacity by the gesture handler at morph
1060
- // engagement, so we don't need fade-in snapshots here — they're
1061
- // already visible behind the morphing modal.
1062
- let didFinalize = false;
1063
- const finalize = () => {
1064
- if (didFinalize)
1065
- return;
1066
- didFinalize = true;
1067
- // Detach the imageSourceChange listeners that were attached during
1068
- // PRESENT — the destination View is about to be torn down.
1069
- for (const presented of state.instance.sharedElements?.presented || []) {
1070
- if (presented.imageSourceChangeListener) {
1071
- presented.view.off('imageSourceChange', presented.imageSourceChangeListener);
1072
- presented.imageSourceChangeListener = null;
1073
- }
1074
- }
1075
- // Restore the snapshotted sources (held at alpha 0 through the
1076
- // spring) immediately before removing the snapshot, so the
1077
- // snapshot's last frame and the source's first visible frame
1078
- // coincide exactly — no double-image, no gap.
1079
- for (const entry of sharedSnapshots) {
1080
- const srcSharedView = entry.srcSharedView;
1081
- if (srcSharedView) {
1082
- const nsView = state.instance.sharedElements?.presenting?.find?.((p) => p.view?.ios === srcSharedView)?.view;
1083
- srcSharedView.alpha = nsView ? nsView.opacity : 1;
1084
- }
1085
- }
1086
- for (const { snap } of sharedSnapshots) {
1087
- snap.removeFromSuperview();
1088
- }
1089
- // Independent (orphan) views were restored at gesture engagement,
1090
- // so they're already visible. Just tear down any leftover present-
1091
- // phase snapshots that weren't removed in present cleanup, and
1092
- // ensure alpha is set from NS opacity for safety in case the
1093
- // engagement code path was bypassed.
1094
- for (const independent of state.instance?.sharedElements?.independent || []) {
1095
- if (independent.view?.ios) {
1096
- independent.view.ios.alpha = independent.view.opacity;
1097
- }
1098
- independent.snapshot?.removeFromSuperview();
1099
- }
1100
- if (view) {
1101
- view.transform = CGAffineTransformIdentity;
1102
- view.alpha = 1;
1103
- }
1104
- // Remove the sibling shadow view if interactive engagement added one.
1105
- removeInteractiveDismissShadow(view);
1106
- SharedTransition.finishState(state.instance.id);
1107
- if (interactiveState.transitionContext) {
1108
- interactiveState.transitionContext.finishInteractiveTransition();
1109
- interactiveState.transitionContext.completeTransition(true);
1110
- }
1111
- SharedTransition.notifyEvent(SharedTransition.finishedEvent, {
1112
- id: state?.instance?.id,
1113
- type,
1114
- action: 'interactiveFinish',
1115
- });
1116
- };
1117
- if (view && targetTransform) {
1118
- const shadowViewToAnimate = view.__sharedTransitionShadowView;
1119
- iOSUtils.animateWithSpring({
1120
- animations: () => {
1121
- view.transform = targetTransform;
1122
- view.alpha = 0;
1123
- // Drive the sibling shadow view through the same spring so it
1124
- // shrinks + translates with the modal as it morphs to the
1125
- // source. Also fade it out so it doesn't linger behind the
1126
- // finalizing snapshot.
1127
- if (shadowViewToAnimate) {
1128
- shadowViewToAnimate.transform = targetTransform;
1129
- shadowViewToAnimate.alpha = 0;
1130
- }
1131
- // Restore source-side element alphas IN PARALLEL with the
1132
- // destination's morph + fade — but skip sources that have
1133
- // a flying snapshot. Those are held at alpha 0 and
1134
- // revealed by finalize() right before the snapshot is
1135
- // removed, so the user never sees both the snapshot AND
1136
- // the source visible at the same time.
1137
- for (const v of state.instance.sharedElements?._allPresentingViews || []) {
1138
- if (v?.ios && !snapshottedSources.has(v.ios)) {
1139
- v.ios.alpha = v.opacity;
1140
- }
1141
- }
1142
- // Source-only orphan views were already restored at
1143
- // engagement; nothing more to do for them here.
1144
- // Fly each shared-element snapshot to its source frame.
1145
- // Rides the same spring so the image lands precisely back
1146
- // at the source position as the destination view fades.
1147
- for (const { snap, endFrame, endCornerRadius } of sharedSnapshots) {
1148
- snap.frame = endFrame;
1149
- snap.layer.cornerRadius = endCornerRadius;
1150
- }
1151
- },
1152
- completion: () => finalize(),
1153
- });
1154
- // Safety: ensure finalize runs even if the animation completion
1155
- // is dropped (e.g. interrupted by another gesture).
1156
- setTimeout(finalize, 800);
1157
- }
1158
- else {
1159
- // No target transform; ensure sources are still restored.
1160
- for (const v of state.instance.sharedElements?._allPresentingViews || []) {
1161
- if (v?.ios)
1162
- v.ios.alpha = v.opacity;
1163
- }
1164
- finalize();
1165
- }
1166
- return;
1167
- }
1168
516
  if (state?.instance && interactiveState?.added && interactiveState?.propertyAnimator) {
1169
517
  interactiveState.propertyAnimator.reversed = false;
1170
518
  const duration = isNumber(state.pageReturn?.duration) ? state.pageReturn?.duration / 1000 : CORE_ANIMATION_DEFAULTS.duration;
1171
519
  interactiveState.propertyAnimator.continueAnimationWithTimingParametersDurationFactor(null, duration);
1172
520
  setTimeout(() => {
1173
- // Restore alpha on every source view we hid (including duplicates) so
1174
- // the source page is visible if shown again.
1175
- for (const sourceView of state.instance.sharedElements._allPresentingViews || []) {
1176
- if (sourceView?.ios) {
1177
- sourceView.ios.alpha = sourceView.opacity;
1178
- }
1179
- }
1180
521
  for (const presenting of state.instance.sharedElements.presenting) {
522
+ presenting.view.opacity = presenting.startOpacity;
1181
523
  presenting.snapshot.removeFromSuperview();
1182
524
  }
1183
- for (const presented of state.instance.sharedElements.presented) {
1184
- if (presented.imageSourceChangeListener) {
1185
- presented.view.off('imageSourceChange', presented.imageSourceChangeListener);
1186
- presented.imageSourceChangeListener = null;
1187
- }
1188
- }
1189
- // Restore alpha on independent (orphan) source views and tear down
1190
- // their snapshots. Without this, source-only orphans (any non-matched
1191
- // sharedTransitionTag on the source page) stay at alpha 0 forever,
1192
- // leaving the page visibly blank where they used to be. The non-morph
1193
- // interactive path drives a propertyAnimator instead of running the
1194
- // dismiss snapshot/animation rig, so the standard cleanup doesn't run.
1195
- for (const ind of state.instance.sharedElements.independent) {
1196
- if (ind.view?.ios) {
1197
- ind.view.ios.alpha = ind.view.opacity;
1198
- }
1199
- ind.snapshot?.removeFromSuperview();
1200
- }
1201
525
  SharedTransition.finishState(state.instance.id);
1202
526
  interactiveState.propertyAnimator = null;
1203
527
  interactiveState.added = false;