@remix-run/ui 0.3.0 → 0.5.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 (434) hide show
  1. package/README.md +116 -157
  2. package/dist/accordion/index.d.ts +46 -0
  3. package/dist/accordion/index.js +142 -0
  4. package/dist/accordion/index.js.map +1 -0
  5. package/dist/accordion/primitives.d.ts +104 -0
  6. package/dist/accordion/primitives.js +312 -0
  7. package/dist/accordion/primitives.js.map +1 -0
  8. package/dist/{components/anchor/anchor.js → anchor/index.js} +1 -1
  9. package/dist/anchor/index.js.map +1 -0
  10. package/dist/animation/animate-layout-mixin.js +1 -1
  11. package/dist/animation/animate-layout-mixin.js.map +1 -1
  12. package/dist/animation/animate-mixins.js +2 -2
  13. package/dist/animation/animate-mixins.js.map +1 -1
  14. package/dist/animation/demos/color-interpolation.js +1 -1
  15. package/dist/animation/demos/color-interpolation.js.map +1 -1
  16. package/dist/animation/demos/drag-release.d.ts +1 -1
  17. package/dist/animation/demos/hold-to-confirm.d.ts +3 -3
  18. package/dist/animation/demos/material-ripple.js +1 -3
  19. package/dist/animation/demos/material-ripple.js.map +1 -1
  20. package/dist/animation/demos/reordering.js +9 -6
  21. package/dist/animation/demos/reordering.js.map +1 -1
  22. package/dist/animation/index.js +4 -4
  23. package/dist/animation/spring.js.map +1 -1
  24. package/dist/{components/breadcrumbs/breadcrumbs.js → breadcrumbs/index.js} +19 -19
  25. package/dist/breadcrumbs/index.js.map +1 -0
  26. package/dist/button/index.d.ts +15 -0
  27. package/dist/button/index.js +128 -0
  28. package/dist/button/index.js.map +1 -0
  29. package/dist/checkbox/index.d.ts +14 -0
  30. package/dist/checkbox/index.js +127 -0
  31. package/dist/checkbox/index.js.map +1 -0
  32. package/dist/combobox/index.d.ts +21 -0
  33. package/dist/combobox/index.js +58 -0
  34. package/dist/combobox/index.js.map +1 -0
  35. package/dist/{components/combobox/combobox.d.ts → combobox/primitives.d.ts} +4 -8
  36. package/dist/{components/combobox/combobox.js → combobox/primitives.js} +8 -61
  37. package/dist/combobox/primitives.js.map +1 -0
  38. package/dist/dev/refresh.d.ts +1 -0
  39. package/dist/dev/refresh.js +2 -0
  40. package/dist/dev/refresh.js.map +1 -0
  41. package/dist/index.d.ts +1 -1
  42. package/dist/index.js +14 -14
  43. package/dist/input/index.d.ts +13 -0
  44. package/dist/input/index.js +121 -0
  45. package/dist/input/index.js.map +1 -0
  46. package/dist/jsx-runtime.js +2 -2
  47. package/dist/listbox/flash-attribute.js.map +1 -0
  48. package/dist/{components/listbox/listbox.d.ts → listbox/index.d.ts} +2 -6
  49. package/dist/{components/listbox/listbox.js → listbox/index.js} +4 -82
  50. package/dist/listbox/index.js.map +1 -0
  51. package/dist/menu/hover-aim.js.map +1 -0
  52. package/dist/menu/index.d.ts +42 -0
  53. package/dist/menu/index.js +250 -0
  54. package/dist/menu/index.js.map +1 -0
  55. package/dist/{components/menu/menu.d.ts → menu/primitives.d.ts} +4 -33
  56. package/dist/{components/menu/menu.js → menu/primitives.js} +98 -315
  57. package/dist/menu/primitives.js.map +1 -0
  58. package/dist/{components/popover/popover.d.ts → popover/index.d.ts} +2 -4
  59. package/dist/{components/popover/popover.js → popover/index.js} +5 -48
  60. package/dist/popover/index.js.map +1 -0
  61. package/dist/{interactions/outside-click/outside-click-mixin.js → popover/outside-click.js} +1 -1
  62. package/dist/popover/outside-click.js.map +1 -0
  63. package/dist/popover/scroll-lock.d.ts +1 -0
  64. package/dist/{utils → popover}/scroll-lock.js +0 -18
  65. package/dist/popover/scroll-lock.js.map +1 -0
  66. package/dist/radio/index.d.ts +12 -0
  67. package/dist/radio/index.js +77 -0
  68. package/dist/radio/index.js.map +1 -0
  69. package/dist/runtime/client-entry-boundary.d.ts +14 -0
  70. package/dist/runtime/client-entry-boundary.js +29 -0
  71. package/dist/runtime/client-entry-boundary.js.map +1 -0
  72. package/dist/runtime/component.d.ts +19 -4
  73. package/dist/runtime/component.js +39 -9
  74. package/dist/runtime/component.js.map +1 -1
  75. package/dist/runtime/core/attributes.js +36 -3
  76. package/dist/runtime/core/attributes.js.map +1 -1
  77. package/dist/runtime/core/children.d.ts +2 -0
  78. package/dist/runtime/core/children.js +26 -2
  79. package/dist/runtime/core/children.js.map +1 -1
  80. package/dist/runtime/core/props.js +2 -2
  81. package/dist/runtime/core/vnode.d.ts +3 -3
  82. package/dist/runtime/core/vnode.js +22 -1
  83. package/dist/runtime/core/vnode.js.map +1 -1
  84. package/dist/runtime/create-element.d.ts +2 -2
  85. package/dist/runtime/create-element.js +3 -2
  86. package/dist/runtime/create-element.js.map +1 -1
  87. package/dist/runtime/diff-dom.js +294 -219
  88. package/dist/runtime/diff-dom.js.map +1 -1
  89. package/dist/runtime/diff-props.js +3 -3
  90. package/dist/runtime/dom.d.ts +12 -0
  91. package/dist/runtime/element-function.d.ts +3 -0
  92. package/dist/runtime/element-function.js +2 -0
  93. package/dist/runtime/element-function.js.map +1 -0
  94. package/dist/runtime/form-navigation.d.ts +25 -0
  95. package/dist/runtime/form-navigation.js +132 -0
  96. package/dist/runtime/form-navigation.js.map +1 -0
  97. package/dist/runtime/frame-resolution.d.ts +5 -0
  98. package/dist/runtime/frame-resolution.js +10 -0
  99. package/dist/runtime/frame-resolution.js.map +1 -0
  100. package/dist/runtime/frame.d.ts +58 -15
  101. package/dist/runtime/frame.js +367 -114
  102. package/dist/runtime/frame.js.map +1 -1
  103. package/dist/runtime/jsx.d.ts +1 -1
  104. package/dist/runtime/jsx.js +1 -1
  105. package/dist/runtime/jsx.js.map +1 -1
  106. package/dist/runtime/key.d.ts +1 -0
  107. package/dist/runtime/key.js +2 -0
  108. package/dist/runtime/key.js.map +1 -0
  109. package/dist/runtime/mixins/attrs-mixin.js +2 -2
  110. package/dist/runtime/mixins/link-mixin.js +4 -3
  111. package/dist/runtime/mixins/link-mixin.js.map +1 -1
  112. package/dist/runtime/mixins/mixin.d.ts +15 -10
  113. package/dist/runtime/mixins/mixin.js +4 -4
  114. package/dist/runtime/mixins/mixin.js.map +1 -1
  115. package/dist/runtime/mixins/on-mixin.js +1 -1
  116. package/dist/runtime/mixins/ref-mixin.js +1 -1
  117. package/dist/runtime/navigation.d.ts +4 -1
  118. package/dist/runtime/navigation.js +157 -32
  119. package/dist/runtime/navigation.js.map +1 -1
  120. package/dist/runtime/reconcile.d.ts +11 -10
  121. package/dist/runtime/reconcile.js +557 -423
  122. package/dist/runtime/reconcile.js.map +1 -1
  123. package/dist/runtime/refresh.d.ts +28 -0
  124. package/dist/runtime/refresh.js +31 -0
  125. package/dist/runtime/refresh.js.map +1 -0
  126. package/dist/runtime/render.js +1 -1
  127. package/dist/runtime/render.js.map +1 -1
  128. package/dist/runtime/run.d.ts +3 -1
  129. package/dist/runtime/run.js +15 -7
  130. package/dist/runtime/run.js.map +1 -1
  131. package/dist/runtime/scheduler.js +8 -16
  132. package/dist/runtime/scheduler.js.map +1 -1
  133. package/dist/runtime/to-vnode.d.ts +2 -2
  134. package/dist/runtime/to-vnode.js +68 -20
  135. package/dist/runtime/to-vnode.js.map +1 -1
  136. package/dist/runtime/vdom.d.ts +4 -2
  137. package/dist/runtime/vdom.js +89 -41
  138. package/dist/runtime/vdom.js.map +1 -1
  139. package/dist/runtime/vnode.d.ts +138 -67
  140. package/dist/runtime/vnode.js +17 -12
  141. package/dist/runtime/vnode.js.map +1 -1
  142. package/dist/select/index.d.ts +19 -0
  143. package/dist/select/index.js +95 -0
  144. package/dist/select/index.js.map +1 -0
  145. package/dist/select/keydown.js.map +1 -0
  146. package/dist/{components/select/select.d.ts → select/primitives.d.ts} +5 -7
  147. package/dist/{components/select/select.js → select/primitives.js} +11 -63
  148. package/dist/select/primitives.js.map +1 -0
  149. package/dist/server/stream.js +22 -29
  150. package/dist/server/stream.js.map +1 -1
  151. package/dist/shared/focus-styles.d.ts +1 -0
  152. package/dist/shared/focus-styles.js +2 -0
  153. package/dist/shared/focus-styles.js.map +1 -0
  154. package/dist/shared/icons.d.ts +9 -0
  155. package/dist/shared/icons.js +42 -0
  156. package/dist/shared/icons.js.map +1 -0
  157. package/dist/shared/listbox-popover-styles.d.ts +6 -0
  158. package/dist/shared/listbox-popover-styles.js +137 -0
  159. package/dist/shared/listbox-popover-styles.js.map +1 -0
  160. package/dist/shared/style-values.d.ts +78 -0
  161. package/dist/shared/style-values.js +88 -0
  162. package/dist/shared/style-values.js.map +1 -0
  163. package/dist/{interactions/typeahead/typeahead-mixin.js → shared/typeahead.js} +1 -1
  164. package/dist/shared/typeahead.js.map +1 -0
  165. package/dist/shared/wait-for-css-transition.js.map +1 -0
  166. package/dist/shared/wait.js.map +1 -0
  167. package/dist/style/css-mixin.js +3 -3
  168. package/dist/style/index.js +2 -2
  169. package/dist/style/style.js +25 -6
  170. package/dist/style/style.js.map +1 -1
  171. package/dist/style/stylesheet.d.ts +0 -1
  172. package/dist/style/stylesheet.js +13 -54
  173. package/dist/style/stylesheet.js.map +1 -1
  174. package/dist/tabs/index.d.ts +32 -0
  175. package/dist/tabs/index.js +157 -0
  176. package/dist/tabs/index.js.map +1 -0
  177. package/dist/tabs/primitives.d.ts +57 -0
  178. package/dist/tabs/primitives.js +238 -0
  179. package/dist/tabs/primitives.js.map +1 -0
  180. package/dist/test.js +1 -1
  181. package/dist/toggle/index.d.ts +9 -0
  182. package/dist/toggle/index.js +108 -0
  183. package/dist/toggle/index.js.map +1 -0
  184. package/dist/toggle/primitives.d.ts +29 -0
  185. package/dist/toggle/primitives.js +127 -0
  186. package/dist/toggle/primitives.js.map +1 -0
  187. package/package.json +81 -49
  188. package/src/{components/accordion → accordion}/README.md +50 -14
  189. package/src/accordion/index.tsx +285 -0
  190. package/src/accordion/primitives.tsx +512 -0
  191. package/src/{components/anchor → anchor}/README.md +37 -2
  192. package/src/animation/animate-mixins.ts +3 -3
  193. package/src/animation/demos/color-interpolation.tsx +1 -1
  194. package/src/animation/demos/reordering.tsx +9 -6
  195. package/src/{components/breadcrumbs → breadcrumbs}/README.md +4 -4
  196. package/src/{components/breadcrumbs/breadcrumbs.tsx → breadcrumbs/index.tsx} +18 -18
  197. package/src/button/README.md +44 -0
  198. package/src/button/index.ts +168 -0
  199. package/src/checkbox/README.md +59 -0
  200. package/src/checkbox/index.ts +164 -0
  201. package/src/{components/combobox → combobox}/README.md +58 -9
  202. package/src/combobox/index.tsx +112 -0
  203. package/src/{components/combobox/combobox.tsx → combobox/primitives.tsx} +5 -91
  204. package/src/dev/refresh.ts +1 -0
  205. package/src/index.ts +1 -1
  206. package/src/input/README.md +52 -0
  207. package/src/input/index.ts +147 -0
  208. package/src/{components/listbox → listbox}/README.md +9 -41
  209. package/src/{components/listbox/listbox.ts → listbox/index.ts} +2 -87
  210. package/src/{components/menu → menu}/README.md +55 -14
  211. package/src/menu/index.tsx +354 -0
  212. package/src/{components/menu/menu.tsx → menu/primitives.tsx} +99 -413
  213. package/src/{components/popover → popover}/README.md +20 -39
  214. package/src/{components/popover/popover.ts → popover/index.ts} +3 -57
  215. package/src/{utils → popover}/scroll-lock.ts +0 -28
  216. package/src/radio/README.md +53 -0
  217. package/src/radio/index.ts +101 -0
  218. package/src/runtime/client-entry-boundary.ts +54 -0
  219. package/src/runtime/component.ts +65 -16
  220. package/src/runtime/core/attributes.ts +35 -1
  221. package/src/runtime/core/children.ts +24 -2
  222. package/src/runtime/core/vnode.ts +25 -4
  223. package/src/runtime/create-element.ts +6 -5
  224. package/src/runtime/demos/readme.demo.tsx +20 -18
  225. package/src/runtime/diff-dom.ts +358 -243
  226. package/src/runtime/dom.ts +331 -214
  227. package/src/runtime/element-function.ts +1 -0
  228. package/src/runtime/event-listeners.ts +1 -1
  229. package/src/runtime/form-navigation.ts +184 -0
  230. package/src/runtime/frame-resolution.ts +13 -0
  231. package/src/runtime/frame.ts +482 -124
  232. package/src/runtime/jsx.ts +3 -5
  233. package/src/runtime/key.ts +1 -0
  234. package/src/runtime/mixins/link-mixin.ts +1 -0
  235. package/src/runtime/mixins/mixin.ts +21 -18
  236. package/src/runtime/navigation.ts +204 -30
  237. package/src/runtime/reconcile.ts +769 -760
  238. package/src/runtime/refresh.ts +46 -0
  239. package/src/runtime/run.ts +12 -2
  240. package/src/runtime/scheduler.ts +9 -29
  241. package/src/runtime/to-vnode.ts +85 -23
  242. package/src/runtime/vdom.ts +91 -69
  243. package/src/runtime/vnode.ts +192 -88
  244. package/src/{components/select → select}/README.md +29 -19
  245. package/src/select/index.tsx +159 -0
  246. package/src/{components/select/select.tsx → select/primitives.tsx} +10 -98
  247. package/src/server/stream.ts +25 -31
  248. package/src/shared/focus-styles.ts +2 -0
  249. package/src/shared/icons.tsx +62 -0
  250. package/src/shared/listbox-popover-styles.ts +146 -0
  251. package/src/shared/style-values.ts +165 -0
  252. package/src/style/style.ts +25 -6
  253. package/src/style/stylesheet.ts +32 -57
  254. package/src/tabs/README.md +141 -0
  255. package/src/tabs/index.tsx +245 -0
  256. package/src/tabs/primitives.ts +365 -0
  257. package/src/test/README.md +151 -60
  258. package/src/toggle/README.md +56 -0
  259. package/src/toggle/index.tsx +136 -0
  260. package/src/toggle/primitives.ts +192 -0
  261. package/dist/animation/demos/animation.demo.d.ts +0 -5
  262. package/dist/animation/demos/animation.demo.js +0 -92
  263. package/dist/animation/demos/animation.demo.js.map +0 -1
  264. package/dist/animation/demos/spring.demo.d.ts +0 -6
  265. package/dist/animation/demos/spring.demo.js +0 -304
  266. package/dist/animation/demos/spring.demo.js.map +0 -1
  267. package/dist/components/accordion/accordion.d.ts +0 -92
  268. package/dist/components/accordion/accordion.js +0 -335
  269. package/dist/components/accordion/accordion.js.map +0 -1
  270. package/dist/components/accordion/demos/card.demo.d.ts +0 -7
  271. package/dist/components/accordion/demos/card.demo.js +0 -59
  272. package/dist/components/accordion/demos/card.demo.js.map +0 -1
  273. package/dist/components/accordion/demos/multiple.demo.d.ts +0 -7
  274. package/dist/components/accordion/demos/multiple.demo.js +0 -20
  275. package/dist/components/accordion/demos/multiple.demo.js.map +0 -1
  276. package/dist/components/accordion/demos/overview.demo.d.ts +0 -7
  277. package/dist/components/accordion/demos/overview.demo.js +0 -20
  278. package/dist/components/accordion/demos/overview.demo.js.map +0 -1
  279. package/dist/components/anchor/anchor.js.map +0 -1
  280. package/dist/components/breadcrumbs/basic.demo.d.ts +0 -6
  281. package/dist/components/breadcrumbs/basic.demo.js +0 -15
  282. package/dist/components/breadcrumbs/basic.demo.js.map +0 -1
  283. package/dist/components/breadcrumbs/breadcrumbs.js.map +0 -1
  284. package/dist/components/breadcrumbs/separator.demo.d.ts +0 -6
  285. package/dist/components/breadcrumbs/separator.demo.js +0 -15
  286. package/dist/components/breadcrumbs/separator.demo.js.map +0 -1
  287. package/dist/components/button/button.d.ts +0 -105
  288. package/dist/components/button/button.js +0 -207
  289. package/dist/components/button/button.js.map +0 -1
  290. package/dist/components/button/demos/aliases.demo.d.ts +0 -7
  291. package/dist/components/button/demos/aliases.demo.js +0 -19
  292. package/dist/components/button/demos/aliases.demo.js.map +0 -1
  293. package/dist/components/button/demos/basic.demo.d.ts +0 -7
  294. package/dist/components/button/demos/basic.demo.js +0 -20
  295. package/dist/components/button/demos/basic.demo.js.map +0 -1
  296. package/dist/components/button/demos/states.demo.d.ts +0 -7
  297. package/dist/components/button/demos/states.demo.js +0 -30
  298. package/dist/components/button/demos/states.demo.js.map +0 -1
  299. package/dist/components/combobox/combobox.js.map +0 -1
  300. package/dist/components/combobox/overview.demo.d.ts +0 -7
  301. package/dist/components/combobox/overview.demo.js +0 -154
  302. package/dist/components/combobox/overview.demo.js.map +0 -1
  303. package/dist/components/glyph/glyph.d.ts +0 -14
  304. package/dist/components/glyph/glyph.js +0 -65
  305. package/dist/components/glyph/glyph.js.map +0 -1
  306. package/dist/components/listbox/listbox.js.map +0 -1
  307. package/dist/components/listbox/overview.demo.d.ts +0 -7
  308. package/dist/components/listbox/overview.demo.js +0 -65
  309. package/dist/components/listbox/overview.demo.js.map +0 -1
  310. package/dist/components/menu/demos/bubbling.demo.d.ts +0 -6
  311. package/dist/components/menu/demos/bubbling.demo.js +0 -16
  312. package/dist/components/menu/demos/bubbling.demo.js.map +0 -1
  313. package/dist/components/menu/demos/context-trigger.demo.d.ts +0 -7
  314. package/dist/components/menu/demos/context-trigger.demo.js +0 -87
  315. package/dist/components/menu/demos/context-trigger.demo.js.map +0 -1
  316. package/dist/components/menu/demos/overview.demo.d.ts +0 -7
  317. package/dist/components/menu/demos/overview.demo.js +0 -33
  318. package/dist/components/menu/demos/overview.demo.js.map +0 -1
  319. package/dist/components/menu/hover-aim.js.map +0 -1
  320. package/dist/components/menu/menu.js.map +0 -1
  321. package/dist/components/popover/overview.demo.d.ts +0 -7
  322. package/dist/components/popover/overview.demo.js +0 -65
  323. package/dist/components/popover/overview.demo.js.map +0 -1
  324. package/dist/components/popover/popover.js.map +0 -1
  325. package/dist/components/select/deconstructed.demo.d.ts +0 -7
  326. package/dist/components/select/deconstructed.demo.js +0 -54
  327. package/dist/components/select/deconstructed.demo.js.map +0 -1
  328. package/dist/components/select/overview.demo.d.ts +0 -6
  329. package/dist/components/select/overview.demo.js +0 -28
  330. package/dist/components/select/overview.demo.js.map +0 -1
  331. package/dist/components/select/select.js.map +0 -1
  332. package/dist/components/separator/separator.d.ts +0 -2
  333. package/dist/components/separator/separator.js +0 -15
  334. package/dist/components/separator/separator.js.map +0 -1
  335. package/dist/components/tabs/tabs.d.ts +0 -78
  336. package/dist/components/tabs/tabs.js +0 -339
  337. package/dist/components/tabs/tabs.js.map +0 -1
  338. package/dist/interactions/keydown/keydown.js.map +0 -1
  339. package/dist/interactions/outside-click/outside-click-mixin.js.map +0 -1
  340. package/dist/interactions/typeahead/typeahead-mixin.js.map +0 -1
  341. package/dist/runtime/demos/basic.demo.d.ts +0 -6
  342. package/dist/runtime/demos/basic.demo.js +0 -16
  343. package/dist/runtime/demos/basic.demo.js.map +0 -1
  344. package/dist/runtime/demos/controlled-uncontrolled-values.demo.d.ts +0 -6
  345. package/dist/runtime/demos/controlled-uncontrolled-values.demo.js +0 -77
  346. package/dist/runtime/demos/controlled-uncontrolled-values.demo.js.map +0 -1
  347. package/dist/runtime/demos/keyed-list.demo.d.ts +0 -6
  348. package/dist/runtime/demos/keyed-list.demo.js +0 -62
  349. package/dist/runtime/demos/keyed-list.demo.js.map +0 -1
  350. package/dist/runtime/demos/readme.demo.d.ts +0 -5
  351. package/dist/runtime/demos/readme.demo.js +0 -396
  352. package/dist/runtime/demos/readme.demo.js.map +0 -1
  353. package/dist/theme/contract.d.ts +0 -61
  354. package/dist/theme/contract.js +0 -131
  355. package/dist/theme/contract.js.map +0 -1
  356. package/dist/theme/glyph-contract.d.ts +0 -11
  357. package/dist/theme/glyph-contract.js +0 -34
  358. package/dist/theme/glyph-contract.js.map +0 -1
  359. package/dist/theme/presets/rmx-01/glyphs.d.ts +0 -2
  360. package/dist/theme/presets/rmx-01/glyphs.js +0 -252
  361. package/dist/theme/presets/rmx-01/glyphs.js.map +0 -1
  362. package/dist/theme/presets/rmx-01/index.d.ts +0 -4
  363. package/dist/theme/presets/rmx-01/index.js +0 -119
  364. package/dist/theme/presets/rmx-01/index.js.map +0 -1
  365. package/dist/theme/runtime.d.ts +0 -2
  366. package/dist/theme/runtime.js +0 -84
  367. package/dist/theme/runtime.js.map +0 -1
  368. package/dist/theme/theme.d.ts +0 -6
  369. package/dist/theme/theme.js +0 -5
  370. package/dist/theme/theme.js.map +0 -1
  371. package/dist/utils/flash-attribute.js.map +0 -1
  372. package/dist/utils/scroll-lock.d.ts +0 -3
  373. package/dist/utils/scroll-lock.js.map +0 -1
  374. package/dist/utils/wait-for-css-transition.js.map +0 -1
  375. package/dist/utils/wait.js.map +0 -1
  376. package/src/animation/demos/animation.demo.tsx +0 -194
  377. package/src/animation/demos/spring.demo.tsx +0 -385
  378. package/src/components/accordion/accordion.tsx +0 -565
  379. package/src/components/accordion/demos/card.demo.tsx +0 -114
  380. package/src/components/accordion/demos/multiple.demo.tsx +0 -57
  381. package/src/components/accordion/demos/overview.demo.tsx +0 -57
  382. package/src/components/breadcrumbs/basic.demo.tsx +0 -18
  383. package/src/components/breadcrumbs/separator.demo.tsx +0 -19
  384. package/src/components/button/README.md +0 -44
  385. package/src/components/button/button.tsx +0 -286
  386. package/src/components/button/demos/aliases.demo.tsx +0 -28
  387. package/src/components/button/demos/basic.demo.tsx +0 -31
  388. package/src/components/button/demos/states.demo.tsx +0 -53
  389. package/src/components/combobox/overview.demo.tsx +0 -200
  390. package/src/components/glyph/README.md +0 -72
  391. package/src/components/glyph/glyph.tsx +0 -110
  392. package/src/components/listbox/overview.demo.tsx +0 -102
  393. package/src/components/menu/demos/bubbling.demo.tsx +0 -35
  394. package/src/components/menu/demos/context-trigger.demo.tsx +0 -133
  395. package/src/components/menu/demos/overview.demo.tsx +0 -77
  396. package/src/components/popover/overview.demo.tsx +0 -144
  397. package/src/components/select/deconstructed.demo.tsx +0 -96
  398. package/src/components/select/overview.demo.tsx +0 -52
  399. package/src/components/separator/separator.ts +0 -19
  400. package/src/components/tabs/README.md +0 -105
  401. package/src/components/tabs/tabs.tsx +0 -504
  402. package/src/runtime/demos/basic.demo.tsx +0 -21
  403. package/src/runtime/demos/controlled-uncontrolled-values.demo.tsx +0 -177
  404. package/src/runtime/demos/keyed-list.demo.tsx +0 -94
  405. package/src/theme/README.md +0 -103
  406. package/src/theme/contract.ts +0 -215
  407. package/src/theme/glyph-contract.ts +0 -59
  408. package/src/theme/presets/rmx-01/glyphs.tsx +0 -308
  409. package/src/theme/presets/rmx-01/index.ts +0 -123
  410. package/src/theme/runtime.ts +0 -119
  411. package/src/theme/theme.ts +0 -15
  412. package/src/utils/scroll-lock/README.md +0 -33
  413. /package/dist/{components/anchor/anchor.d.ts → anchor/index.d.ts} +0 -0
  414. /package/dist/{components/breadcrumbs/breadcrumbs.d.ts → breadcrumbs/index.d.ts} +0 -0
  415. /package/dist/{utils → listbox}/flash-attribute.d.ts +0 -0
  416. /package/dist/{utils → listbox}/flash-attribute.js +0 -0
  417. /package/dist/{components/menu → menu}/hover-aim.d.ts +0 -0
  418. /package/dist/{components/menu → menu}/hover-aim.js +0 -0
  419. /package/dist/{interactions/outside-click/outside-click-mixin.d.ts → popover/outside-click.d.ts} +0 -0
  420. /package/dist/{interactions/keydown → select}/keydown.d.ts +0 -0
  421. /package/dist/{interactions/keydown → select}/keydown.js +0 -0
  422. /package/dist/{interactions/typeahead/typeahead-mixin.d.ts → shared/typeahead.d.ts} +0 -0
  423. /package/dist/{utils → shared}/wait-for-css-transition.d.ts +0 -0
  424. /package/dist/{utils → shared}/wait-for-css-transition.js +0 -0
  425. /package/dist/{utils → shared}/wait.d.ts +0 -0
  426. /package/dist/{utils → shared}/wait.js +0 -0
  427. /package/src/{components/anchor/anchor.ts → anchor/index.ts} +0 -0
  428. /package/src/{utils → listbox}/flash-attribute.ts +0 -0
  429. /package/src/{components/menu → menu}/hover-aim.ts +0 -0
  430. /package/src/{interactions/outside-click/outside-click-mixin.ts → popover/outside-click.ts} +0 -0
  431. /package/src/{interactions/keydown → select}/keydown.ts +0 -0
  432. /package/src/{interactions/typeahead/typeahead-mixin.ts → shared/typeahead.ts} +0 -0
  433. /package/src/{utils → shared}/wait-for-css-transition.ts +0 -0
  434. /package/src/{utils → shared}/wait.ts +0 -0
@@ -1,11 +1,8 @@
1
1
  import { invariant } from './invariant.ts'
2
2
  import type { FrameContext } from './frame.ts'
3
+ import { disposeClientEntryBoundary, getClientEntryBoundaryOwner } from './client-entry-boundary.ts'
3
4
 
4
- type HydratedVirtualRootStartMarker = Comment & {
5
- $rmx: {
6
- dispose(): void
7
- }
8
- }
5
+ type MarkerKind = 'frame-start' | 'frame-end' | 'virtual-root-start' | 'virtual-root-end'
9
6
 
10
7
  type CommentMarkerRangeReplacement = {
11
8
  currentStart: Comment
@@ -14,6 +11,25 @@ type CommentMarkerRangeReplacement = {
14
11
  nextEndIndex: number
15
12
  }
16
13
 
14
+ type NodeSiblingUnit = {
15
+ kind: 'node'
16
+ node: Node
17
+ startIndex: number
18
+ endIndex: number
19
+ }
20
+
21
+ type BoundarySiblingUnit = {
22
+ kind: 'frame' | 'hydration'
23
+ start: Comment
24
+ end: Comment
25
+ startIndex: number
26
+ endIndex: number
27
+ }
28
+
29
+ type SiblingUnit = NodeSiblingUnit | BoundarySiblingUnit
30
+
31
+ const REMIX_PRESERVE_DOM_ATTRIBUTE = 'rmx-preserve-dom'
32
+
17
33
  export function diffNodes(curr: Node[], next: Node[], context: FrameContext) {
18
34
  let parent = curr[0]?.parentNode ?? context.regionParent ?? null
19
35
  invariant(parent, 'Parent node not found')
@@ -24,70 +40,7 @@ export function diffNodes(curr: Node[], next: Node[], context: FrameContext) {
24
40
  context.regionTailRef ??
25
41
  (curr.length > 0 ? (curr[curr.length - 1].nextSibling as ChildNode | null) : null)
26
42
 
27
- let currentIndex = 0
28
- let nextIndex = 0
29
- while (currentIndex < curr.length || nextIndex < next.length) {
30
- let c = curr[currentIndex]
31
- let n = next[nextIndex]
32
-
33
- if (!c && n) {
34
- if (regionTailRef) {
35
- parent.insertBefore(n, regionTailRef)
36
- } else {
37
- parent.appendChild(n)
38
- }
39
- nextIndex++
40
- } else if (c && !n) {
41
- removeNode(c, parent, context)
42
- currentIndex++
43
- } else if (c && n) {
44
- let replacement = getCommentMarkerRangeReplacement(
45
- c,
46
- n,
47
- curr,
48
- next,
49
- currentIndex,
50
- nextIndex,
51
- context,
52
- )
53
- if (replacement) {
54
- replaceCommentMarkerRange(replacement, parent, context)
55
- currentIndex = replacement.currentEndIndex + 1
56
- nextIndex = replacement.nextEndIndex + 1
57
- continue
58
- }
59
-
60
- // Skip hydrated client-entry marker ranges; hydration pass re-renders
61
- // roots with new props from incoming payload
62
- if (isVirtualRootStartMarker(c) && isVirtualRootStartMarker(n)) {
63
- let currentEnd = findHydrationEndMarker(c)
64
- let nextEnd = findHydrationEndMarker(n)
65
- let nextData = n.data
66
- if (c.data !== nextData) c.data = nextData
67
-
68
- let currentEndIndex = curr.indexOf(currentEnd)
69
- let nextEndIndex = next.indexOf(nextEnd)
70
- currentIndex = currentEndIndex + 1
71
- nextIndex = nextEndIndex + 1
72
- continue
73
- }
74
-
75
- let cursor = diffNode(c, n, context)
76
- if (cursor) {
77
- let nextEndIndex = next.indexOf(cursor)
78
- let currentEndIndex =
79
- isFrameStartMarker(c) && isFrameEndMarker(cursor)
80
- ? findFrameEndIndex(curr, currentIndex)
81
- : currentIndex
82
- currentIndex = currentEndIndex + 1
83
- nextIndex = nextEndIndex + 1
84
- continue
85
- }
86
-
87
- currentIndex++
88
- nextIndex++
89
- }
90
- }
43
+ diffSiblingUnits(curr, next, parent, regionTailRef, context)
91
44
  }
92
45
 
93
46
  function diffNode(current: Node, next: Node, context: FrameContext): ChildNode | undefined {
@@ -111,45 +64,46 @@ function diffNode(current: Node, next: Node, context: FrameContext): ChildNode |
111
64
  }
112
65
 
113
66
  // Comment -> Comment
114
- if (isCommentNode(current) && isCommentNode(next)) {
67
+ if (isCommentNode(current) && isCommentNode(next) && markerKindsMatch(current, next)) {
115
68
  let newData = next.data
116
- if (current.data !== newData) {
117
- let updated = false
118
- if (isFrameStartMarker(current)) {
119
- if (shouldPreserveFrameStartMarker(current, next, context)) {
69
+ let updated = false
70
+ if (isFrameStartMarker(current)) {
71
+ if (shouldPreserveFrameStartMarker(current, next, context)) {
72
+ if (current.data !== newData) {
120
73
  current.data = newData
121
- updated = true
122
-
123
- let frame = context.frameInstances.get(current)
124
- let nextMarkerData = getFrameMarkerData(next, context)
125
- if (frame && nextMarkerData) {
126
- if (nextMarkerData.status === 'resolved') {
127
- let nextEnd = findFrameEndMarker(next)
128
- let nextContent = collectFrameContentFragment(current.ownerDocument, next, nextEnd)
129
- void frame.renderMarkerContent(
130
- { ...nextMarkerData, id: getFrameId(next) },
131
- nextContent,
132
- {
133
- signal: context.signal,
134
- },
135
- )
136
- return nextEnd
137
- }
138
-
139
- if (frame.isDisplayingResolvedContent()) {
140
- return findFrameEndMarker(next)
141
- }
74
+ }
75
+ updated = true
76
+
77
+ let frame = context.frameInstances.get(current)
78
+ let nextMarkerData = getFrameMarkerData(next, context)
79
+ if (frame && nextMarkerData) {
80
+ if (nextMarkerData.status === 'resolved') {
81
+ let nextEnd = findFrameEndMarker(next)
82
+ let nextContent = collectFrameContentFragment(current.ownerDocument, next, nextEnd)
83
+ void frame.renderMarkerContent(
84
+ { ...nextMarkerData, id: getFrameId(next) },
85
+ nextContent,
86
+ {
87
+ data: context.data,
88
+ signal: context.signal,
89
+ },
90
+ )
91
+ return nextEnd
92
+ }
93
+
94
+ if (frame.isDisplayingResolvedContent()) {
95
+ return findFrameEndMarker(next)
142
96
  }
143
- } else {
144
- disposeFrameStartMarker(current, context)
145
- current.data = newData
146
- updated = true
147
97
  }
148
- }
149
- if (!updated) {
98
+ } else if (current.data !== newData) {
99
+ disposeFrameStartMarker(current, context)
150
100
  current.data = newData
101
+ updated = true
151
102
  }
152
103
  }
104
+ if (!updated && current.data !== newData) {
105
+ current.data = newData
106
+ }
153
107
  return
154
108
  }
155
109
 
@@ -166,6 +120,7 @@ function diffNode(current: Node, next: Node, context: FrameContext): ChildNode |
166
120
  }
167
121
 
168
122
  // Same tag: update attributes then children
123
+ if (shouldPreserveDomElement(current, next)) return
169
124
  diffElementAttributes(current, next)
170
125
  if (shouldPreserveElementChildren(current, next)) return
171
126
  diffElementChildren(current, next, context)
@@ -205,6 +160,14 @@ function diffElementAttributes(current: Element, next: Element): void {
205
160
  }
206
161
  }
207
162
 
163
+ function shouldPreserveDomElement(current: Element, next: Element): boolean {
164
+ if (!next.hasAttribute(REMIX_PRESERVE_DOM_ATTRIBUTE)) return false
165
+ if (!current.hasAttribute(REMIX_PRESERVE_DOM_ATTRIBUTE)) {
166
+ current.setAttribute(REMIX_PRESERVE_DOM_ATTRIBUTE, '')
167
+ }
168
+ return true
169
+ }
170
+
208
171
  function shouldPreserveLiveAttribute(current: Element, next: Element, name: string): boolean {
209
172
  if (name === 'open') {
210
173
  if (current instanceof HTMLDetailsElement && next instanceof HTMLDetailsElement) {
@@ -276,47 +239,57 @@ function isPopoverOpen(element: Element): boolean {
276
239
  function diffElementChildren(current: Element, next: Element, context: FrameContext): void {
277
240
  let currentChildren = Array.from(current.childNodes)
278
241
  let nextChildren = Array.from(next.childNodes)
242
+ diffSiblingUnits(currentChildren, nextChildren, current, null, context)
243
+ }
279
244
 
280
- // Keyed map by data-key for current children
245
+ function diffSiblingUnits(
246
+ currentNodes: Node[],
247
+ nextNodes: Node[],
248
+ parent: ParentNode,
249
+ regionTailRef: ChildNode | null,
250
+ context: FrameContext,
251
+ ): void {
252
+ let currentUnits = parseSiblingUnits(currentNodes)
253
+ let nextUnits = parseSiblingUnits(nextNodes)
281
254
  let keyToIndex = new Map<string, number>()
282
- for (let i = 0; i < currentChildren.length; i++) {
283
- let node = currentChildren[i]
284
- if (isElement(node)) {
285
- let key = node.getAttribute('data-key')
286
- if (key != null) keyToIndex.set(key, i)
287
- }
255
+
256
+ for (let i = 0; i < currentUnits.length; i++) {
257
+ let key = getSiblingUnitKey(currentUnits[i])
258
+ if (key !== undefined) keyToIndex.set(key, i)
288
259
  }
289
260
 
290
- let used = new Array<boolean>(currentChildren.length).fill(false)
291
- let matchIndexForNext = new Array<number>(nextChildren.length).fill(-1)
261
+ let used = new Array<boolean>(currentUnits.length).fill(false)
262
+ let matchIndexForNext = new Array<number>(nextUnits.length).fill(-1)
292
263
 
293
- for (let i = 0; i < nextChildren.length; i++) {
294
- let nextChild = nextChildren[i]
264
+ // Reserve globally matched keyed elements and semantic boundaries before
265
+ // positionally pairing the remaining ordinary siblings.
266
+ for (let i = 0; i < nextUnits.length; i++) {
267
+ let nextUnit = nextUnits[i]
295
268
  let matchIndex = -1
269
+ let key = getSiblingUnitKey(nextUnit)
296
270
 
297
- if (isFrameEndMarker(nextChild)) {
298
- for (let j = 0; j < currentChildren.length; j++) {
299
- if (!used[j] && isFrameEndMarker(currentChildren[j])) {
300
- matchIndex = j
301
- break
302
- }
303
- }
304
- } else if (isElement(nextChild)) {
305
- let key = nextChild.getAttribute('data-key')
306
- if (key != null && keyToIndex.has(key)) {
307
- let idx = keyToIndex.get(key)!
308
- if (!used[idx]) matchIndex = idx
271
+ if (key !== undefined) {
272
+ let keyedIndex = keyToIndex.get(key)
273
+ if (
274
+ keyedIndex !== undefined &&
275
+ !used[keyedIndex] &&
276
+ siblingUnitsComparable(currentUnits[keyedIndex], nextUnit)
277
+ ) {
278
+ matchIndex = keyedIndex
309
279
  }
310
280
  }
311
281
 
312
- if (matchIndex === -1) {
313
- let candidateIndex = i
314
- if (
315
- candidateIndex < currentChildren.length &&
316
- !used[candidateIndex] &&
317
- nodeTypesComparable(currentChildren[candidateIndex], nextChild)
318
- ) {
319
- matchIndex = candidateIndex
282
+ // Boundary identities behave like implicit keys. Repeated boundaries with
283
+ // the same identity are paired in source order because server markers do
284
+ // not carry a separate application key.
285
+ if (matchIndex === -1 && nextUnit.kind !== 'node') {
286
+ for (let j = 0; j < currentUnits.length; j++) {
287
+ let currentUnit = currentUnits[j]
288
+ if (used[j] || currentUnit.kind !== nextUnit.kind) continue
289
+ if (shouldPreserveBoundaryUnit(currentUnit, nextUnit, context)) {
290
+ matchIndex = j
291
+ break
292
+ }
320
293
  }
321
294
  }
322
295
 
@@ -324,136 +297,229 @@ function diffElementChildren(current: Element, next: Element, context: FrameCont
324
297
  matchIndexForNext[i] = matchIndex
325
298
  }
326
299
 
327
- // Forward pass: update matched, collect committed
328
- let committed: Array<Node | undefined> = new Array(nextChildren.length)
329
- for (let i = 0; i < nextChildren.length; i++) {
330
- let mi = matchIndexForNext[i]
331
- if (mi !== -1) {
332
- let curChild = currentChildren[mi]
333
- let nextChild = nextChildren[i]
334
-
335
- let replacement = getCommentMarkerRangeReplacement(
336
- curChild,
337
- nextChild,
338
- currentChildren,
339
- nextChildren,
340
- mi,
341
- i,
342
- context,
343
- )
344
- if (replacement) {
345
- replaceCommentMarkerRange(replacement, current, context)
300
+ let remainingCurrentIndexes: number[] = []
301
+ for (let i = 0; i < currentUnits.length; i++) {
302
+ if (!used[i]) remainingCurrentIndexes.push(i)
303
+ }
346
304
 
347
- for (let k = mi; k <= replacement.currentEndIndex; k++) used[k] = true
305
+ let remainingNextIndexes: number[] = []
306
+ for (let i = 0; i < nextUnits.length; i++) {
307
+ if (matchIndexForNext[i] === -1) remainingNextIndexes.push(i)
308
+ }
348
309
 
349
- committed[i] = replacement.nextStart
350
- committed[replacement.nextEndIndex] = nextChildren[replacement.nextEndIndex]
351
- for (let j = i + 1; j < replacement.nextEndIndex; j++) committed[j] = undefined
310
+ let remainingLength = Math.min(remainingCurrentIndexes.length, remainingNextIndexes.length)
311
+ for (let i = 0; i < remainingLength; i++) {
312
+ let currentIndex = remainingCurrentIndexes[i]
313
+ let nextIndex = remainingNextIndexes[i]
314
+ let currentUnit = currentUnits[currentIndex]
315
+ let nextUnit = nextUnits[nextIndex]
352
316
 
353
- i = replacement.nextEndIndex
354
- continue
355
- }
317
+ if (
318
+ currentUnit.kind !== 'node' ||
319
+ nextUnit.kind !== 'node' ||
320
+ getSiblingUnitKey(currentUnit) !== undefined ||
321
+ getSiblingUnitKey(nextUnit) !== undefined ||
322
+ !siblingUnitsComparable(currentUnit, nextUnit)
323
+ ) {
324
+ continue
325
+ }
356
326
 
357
- let cursor = diffNode(curChild, nextChild, context)
358
- if (cursor) {
359
- // `diffNode` can preserve hydration and frame marker ranges by returning
360
- // the next end marker, so skip the owned interior nodes here.
361
- let nextEndIdx = nextChildren.indexOf(cursor)
362
- let currEndIdx =
363
- isFrameStartMarker(curChild) && isFrameEndMarker(cursor)
364
- ? findFrameEndIndex(currentChildren, mi)
365
- : findHydrationEndIndex(currentChildren, mi)
366
-
367
- // Adjacent marker ranges can pre-match into the next range and leave an
368
- // orphaned end marker behind. Clear those stale matches first.
369
- for (let j = i + 1; j <= nextEndIdx; j++) {
370
- let matchedIndex = matchIndexForNext[j]
371
- if (matchedIndex > currEndIdx) {
372
- used[matchedIndex] = false
373
- }
374
- matchIndexForNext[j] = -1
375
- }
327
+ used[currentIndex] = true
328
+ matchIndexForNext[nextIndex] = currentIndex
329
+ }
376
330
 
377
- // Mark the entire current region as used to avoid removals.
378
- for (let k = mi; k <= currEndIdx; k++) used[k] = true
331
+ let committed = new Array<SiblingUnit>(nextUnits.length)
332
+ for (let i = 0; i < nextUnits.length; i++) {
333
+ let matchIndex = matchIndexForNext[i]
334
+ let nextUnit = nextUnits[i]
335
+ if (matchIndex === -1) {
336
+ committed[i] = nextUnit
337
+ continue
338
+ }
379
339
 
380
- // Preserve both comment markers in committed; skip interior in reorder pass.
381
- committed[i] = curChild // start marker
382
- committed[nextEndIdx] = currentChildren[currEndIdx] // end marker
383
- for (let j = i + 1; j < nextEndIdx; j++) committed[j] = undefined
340
+ let currentUnit = currentUnits[matchIndex]
341
+ if (currentUnit.kind === 'node' && nextUnit.kind === 'node') {
342
+ diffNode(currentUnit.node, nextUnit.node, context)
343
+ committed[i] = currentUnit
344
+ continue
345
+ }
384
346
 
385
- // Jump to end of region.
386
- i = nextEndIdx
387
- continue
388
- }
389
- committed[i] = curChild
390
- } else {
391
- committed[i] = nextChildren[i]
347
+ invariant(currentUnit.kind !== 'node' && nextUnit.kind !== 'node', 'Expected boundaries')
348
+
349
+ let replacement = getCommentMarkerRangeReplacement(
350
+ currentUnit.start,
351
+ nextUnit.start,
352
+ currentNodes,
353
+ nextNodes,
354
+ currentUnit.startIndex,
355
+ nextUnit.startIndex,
356
+ context,
357
+ )
358
+ if (replacement) {
359
+ replaceCommentMarkerRange(replacement, parent, context)
360
+ committed[i] = nextUnit
361
+ continue
392
362
  }
363
+
364
+ let cursor = diffNode(currentUnit.start, nextUnit.start, context)
365
+ if (!cursor && currentUnit.kind === 'frame' && nextUnit.kind === 'frame') {
366
+ diffNodes(
367
+ collectNodesBetween(currentUnit.start, currentUnit.end),
368
+ nextNodes.slice(nextUnit.startIndex + 1, nextUnit.endIndex),
369
+ {
370
+ ...context,
371
+ regionParent: parent,
372
+ regionTailRef: currentUnit.end,
373
+ },
374
+ )
375
+ }
376
+ committed[i] = currentUnit
393
377
  }
394
378
 
395
- // Backward pass: reorder via inserts while avoiding redundant moves
396
- let anchor: Node | undefined = undefined
379
+ let anchor: Node | null = regionTailRef
397
380
  for (let i = committed.length - 1; i >= 0; i--) {
398
- let node = committed[i]
399
- if (!node) continue
400
-
401
- // Use only an anchor that is actually a child of the current parent
402
- let ref = anchor && anchor.parentNode === current ? anchor : null
381
+ let unit = committed[i]
382
+ let first = getSiblingUnitFirstNode(unit)
383
+ let ref = anchor?.parentNode === parent ? anchor : null
403
384
 
404
- // Existing comment markers delimit live ranges, so do not reorder them
405
- // independently from their contents. New markers still need to be inserted
406
- // before they can be used as anchors.
407
385
  if (
408
- isVirtualRootStartMarker(node) ||
409
- isVirtualRootEndMarker(node) ||
410
- isFrameStartMarker(node) ||
411
- isFrameEndMarker(node)
386
+ unit.kind === 'node' &&
387
+ isPreservedDomElement(unit.node) &&
388
+ unit.node.parentNode === parent
412
389
  ) {
413
- if (node.parentNode !== current) {
414
- current.insertBefore(node, ref)
415
- }
416
- anchor = node
390
+ anchor = unit.node
417
391
  continue
418
392
  }
419
393
 
420
- if (node.parentNode === current) {
421
- // Node already in parent: move only if its nextSibling is not the desired ref.
422
- let targetNext = ref
423
- let alreadyInPlace =
424
- (targetNext === null && node.nextSibling === null) || node.nextSibling === targetNext
425
- if (!alreadyInPlace) {
426
- current.insertBefore(node, targetNext)
427
- }
428
- } else {
429
- // New node: insert relative to a valid ref or append
430
- current.insertBefore(node, ref)
394
+ placeSiblingUnitBefore(unit, parent, ref)
395
+ if (first.parentNode === parent) anchor = first
396
+ }
397
+
398
+ for (let i = 0; i < currentUnits.length; i++) {
399
+ if (!used[i]) removeSiblingUnit(currentUnits[i], parent, context)
400
+ }
401
+ }
402
+
403
+ function parseSiblingUnits(nodes: Node[]): SiblingUnit[] {
404
+ let units: SiblingUnit[] = []
405
+
406
+ for (let i = 0; i < nodes.length; i++) {
407
+ let node = nodes[i]
408
+ if (isVirtualRootStartMarker(node)) {
409
+ let endIndex = findHydrationEndIndex(nodes, i)
410
+ invariant(endIndex > i, 'Hydration end marker not found')
411
+ let end = nodes[endIndex]
412
+ invariant(isVirtualRootEndMarker(end), 'Expected hydration end marker')
413
+ units.push({ kind: 'hydration', start: node, end, startIndex: i, endIndex })
414
+ i = endIndex
415
+ continue
431
416
  }
432
417
 
433
- // Advance anchor only after the node is placed in the correct parent
434
- if (node.parentNode === current) {
435
- anchor = node
418
+ if (isFrameStartMarker(node)) {
419
+ let endIndex = findFrameEndIndex(nodes, i)
420
+ invariant(endIndex > i, 'Frame end marker not found')
421
+ let end = nodes[endIndex]
422
+ invariant(isFrameEndMarker(end), 'Expected frame end marker')
423
+ units.push({ kind: 'frame', start: node, end, startIndex: i, endIndex })
424
+ i = endIndex
425
+ continue
436
426
  }
427
+
428
+ invariant(!isVirtualRootEndMarker(node), 'Unexpected hydration end marker')
429
+ invariant(!isFrameEndMarker(node), 'Unexpected frame end marker')
430
+ units.push({ kind: 'node', node, startIndex: i, endIndex: i })
437
431
  }
438
432
 
439
- // Remove any current children not used
440
- for (let i = 0; i < currentChildren.length; i++) {
441
- if (!used[i]) {
442
- let nodeToRemove = currentChildren[i]
443
- removeNode(nodeToRemove, current, context)
433
+ return units
434
+ }
435
+
436
+ function getSiblingUnitKey(unit: SiblingUnit): string | undefined {
437
+ if (unit.kind !== 'node' || !isElement(unit.node)) return
438
+ return unit.node.getAttribute('data-key') ?? undefined
439
+ }
440
+
441
+ function siblingUnitsComparable(current: SiblingUnit, next: SiblingUnit): boolean {
442
+ if (current.kind !== next.kind) return false
443
+ if (current.kind !== 'node' || next.kind !== 'node') return true
444
+ return nodeTypesComparable(current.node, next.node)
445
+ }
446
+
447
+ function shouldPreserveBoundaryUnit(
448
+ current: BoundarySiblingUnit,
449
+ next: BoundarySiblingUnit,
450
+ context: FrameContext,
451
+ ): boolean {
452
+ if (current.kind !== next.kind) return false
453
+ return current.kind === 'frame'
454
+ ? shouldPreserveFrameStartMarker(current.start, next.start, context)
455
+ : shouldPreserveHydrationStartMarker(current.start, next.start, context)
456
+ }
457
+
458
+ function getSiblingUnitFirstNode(unit: SiblingUnit): Node {
459
+ return unit.kind === 'node' ? unit.node : unit.start
460
+ }
461
+
462
+ function placeSiblingUnitBefore(unit: SiblingUnit, parent: ParentNode, ref: Node | null): void {
463
+ if (unit.kind === 'node') {
464
+ if (unit.node.parentNode !== parent || unit.node.nextSibling !== ref) {
465
+ parent.insertBefore(unit.node, ref)
444
466
  }
467
+ return
468
+ }
469
+
470
+ let nodes = collectNodeRange(unit.start, unit.end)
471
+ if (unit.start.parentNode === parent && unit.end.nextSibling === ref) return
472
+
473
+ let fragment = unit.start.ownerDocument.createDocumentFragment()
474
+ for (let node of nodes) fragment.appendChild(node)
475
+ parent.insertBefore(fragment, ref)
476
+ }
477
+
478
+ function removeSiblingUnit(unit: SiblingUnit, parent: ParentNode, context: FrameContext): void {
479
+ if (unit.kind === 'node') {
480
+ removeNode(unit.node, parent, context)
481
+ return
482
+ }
483
+
484
+ for (let node of collectNodeRange(unit.start, unit.end)) {
485
+ removeNode(node, parent, context)
445
486
  }
446
487
  }
447
488
 
489
+ function collectNodesBetween(start: Comment, end: Comment): Node[] {
490
+ let nodes: Node[] = []
491
+ let node = start.nextSibling
492
+ while (node && node !== end) {
493
+ nodes.push(node)
494
+ node = node.nextSibling
495
+ }
496
+ return nodes
497
+ }
498
+
499
+ function isPreservedDomElement(node: Node): node is Element {
500
+ return isElement(node) && node.hasAttribute(REMIX_PRESERVE_DOM_ATTRIBUTE)
501
+ }
502
+
448
503
  function nodeTypesComparable(a: Node, b: Node): boolean {
449
504
  if (isTextNode(a) && isTextNode(b)) return true
450
505
  if (isElement(a) && isElement(b)) return a.tagName === b.tagName
451
- if (isVirtualRootStartMarker(a) && isVirtualRootStartMarker(b)) return true
452
- if (isVirtualRootEndMarker(a) && isVirtualRootEndMarker(b)) return true
453
- if (isCommentNode(a) && isCommentNode(b)) return true
506
+ if (isCommentNode(a) && isCommentNode(b)) return markerKindsMatch(a, b)
454
507
  return false
455
508
  }
456
509
 
510
+ function getMarkerKind(node: Node): MarkerKind | undefined {
511
+ if (!isCommentNode(node)) return undefined
512
+ if (isFrameStartMarker(node)) return 'frame-start'
513
+ if (isFrameEndMarker(node)) return 'frame-end'
514
+ if (isVirtualRootStartMarker(node)) return 'virtual-root-start'
515
+ if (isVirtualRootEndMarker(node)) return 'virtual-root-end'
516
+ return undefined
517
+ }
518
+
519
+ function markerKindsMatch(a: Node, b: Node): boolean {
520
+ return getMarkerKind(a) === getMarkerKind(b)
521
+ }
522
+
457
523
  function isHydrationEndComment(node: Node): node is Comment {
458
524
  return isCommentNode(node) && node.data.trim() === '/rmx:h'
459
525
  }
@@ -477,8 +543,15 @@ function findHydrationEndMarker(start: Comment): Comment {
477
543
  }
478
544
 
479
545
  function findHydrationEndIndex(nodes: Node[], startIdx: number): number {
546
+ let depth = 1
547
+
480
548
  for (let j = startIdx + 1; j < nodes.length; j++) {
481
- if (isHydrationEndComment(nodes[j])) return j
549
+ let node = nodes[j]
550
+ if (isVirtualRootStartMarker(node)) depth++
551
+ if (isHydrationEndComment(node)) {
552
+ depth--
553
+ if (depth === 0) return j
554
+ }
482
555
  }
483
556
  return startIdx
484
557
  }
@@ -541,14 +614,31 @@ function shouldPreserveFrameStartMarker(
541
614
  ): boolean {
542
615
  if (!isFrameStartMarker(next)) return false
543
616
 
544
- let currentData = getFrameMarkerData(current, context)
545
617
  let nextData = getFrameMarkerData(next, context)
618
+ let currentFrame = context.frameInstances.get(current)
546
619
 
547
620
  return (
548
- currentData !== undefined &&
621
+ currentFrame !== undefined &&
549
622
  nextData !== undefined &&
550
- currentData.src === nextData.src &&
551
- currentData.name === nextData.name
623
+ currentFrame.matchesIdentity(nextData.src, nextData.name)
624
+ )
625
+ }
626
+
627
+ function shouldPreserveHydrationStartMarker(
628
+ current: Comment,
629
+ next: Comment,
630
+ context: FrameContext,
631
+ ): boolean {
632
+ if (!isVirtualRootStartMarker(next)) return false
633
+
634
+ let currentOwner = getClientEntryBoundaryOwner(current)
635
+ let nextData = getHydrationMarkerData(next, context)
636
+
637
+ return (
638
+ currentOwner !== undefined &&
639
+ nextData !== undefined &&
640
+ currentOwner.identity.moduleUrl === nextData.moduleUrl &&
641
+ currentOwner.identity.exportName === nextData.exportName
552
642
  )
553
643
  }
554
644
 
@@ -576,6 +666,30 @@ function getCommentMarkerRangeReplacement(
576
666
  nextEndIndex: findFrameEndIndex(nextNodes, nextIndex),
577
667
  }
578
668
  }
669
+
670
+ if (
671
+ isVirtualRootStartMarker(current) &&
672
+ isVirtualRootStartMarker(next) &&
673
+ !shouldPreserveHydrationStartMarker(current, next, context)
674
+ ) {
675
+ return {
676
+ currentStart: current,
677
+ nextStart: next,
678
+ currentEndIndex: findHydrationEndIndex(currentNodes, currentIndex),
679
+ nextEndIndex: findHydrationEndIndex(nextNodes, nextIndex),
680
+ }
681
+ }
682
+ }
683
+
684
+ function getHydrationMarkerData(marker: Comment, context: FrameContext) {
685
+ let id = getHydrationId(marker)
686
+ return context.data.h?.[id]
687
+ }
688
+
689
+ function getHydrationId(marker: Comment): string {
690
+ let trimmed = marker.data.trim()
691
+ invariant(trimmed.startsWith('rmx:h:'), 'Invalid hydration start marker')
692
+ return trimmed.slice('rmx:h:'.length)
579
693
  }
580
694
 
581
695
  function getFrameMarkerData(marker: Comment, context: FrameContext) {
@@ -594,8 +708,8 @@ function replaceCommentMarkerRange(
594
708
  parent: ParentNode,
595
709
  context: FrameContext,
596
710
  ): void {
597
- let currentEnd = findFrameEndMarker(replacement.currentStart)
598
- let nextEnd = findFrameEndMarker(replacement.nextStart)
711
+ let currentEnd = findCommentMarkerRangeEnd(replacement.currentStart)
712
+ let nextEnd = findCommentMarkerRangeEnd(replacement.nextStart)
599
713
  let nextNodes = collectNodeRange(replacement.nextStart, nextEnd)
600
714
  let currentNodes = collectNodeRange(replacement.currentStart, currentEnd)
601
715
 
@@ -608,6 +722,12 @@ function replaceCommentMarkerRange(
608
722
  }
609
723
  }
610
724
 
725
+ function findCommentMarkerRangeEnd(start: Comment): Comment {
726
+ if (isFrameStartMarker(start)) return findFrameEndMarker(start)
727
+ if (isVirtualRootStartMarker(start)) return findHydrationEndMarker(start)
728
+ throw new Error('Comment marker range start not found')
729
+ }
730
+
611
731
  function collectNodeRange(start: Node, end: Node): Node[] {
612
732
  let nodes: Node[] = []
613
733
  let node: Node | null = start
@@ -653,8 +773,7 @@ function disposeRemovedVirtualRoots(node: Node): void {
653
773
  let next = stack.pop()
654
774
  if (!next) continue
655
775
 
656
- if (isHydratedVirtualRootStartMarker(next)) {
657
- next.$rmx.dispose()
776
+ if (isVirtualRootStartMarker(next) && disposeClientEntryBoundary(next)) {
658
777
  continue
659
778
  }
660
779
 
@@ -692,10 +811,6 @@ function isVirtualRootStartMarker(node: Node): node is Comment {
692
811
  return isCommentNode(node) && node.data.trim().startsWith('rmx:h:')
693
812
  }
694
813
 
695
- function isHydratedVirtualRootStartMarker(node: Node): node is HydratedVirtualRootStartMarker {
696
- return isVirtualRootStartMarker(node) && '$rmx' in node
697
- }
698
-
699
814
  function isVirtualRootEndMarker(node: Node): node is Comment {
700
815
  return isCommentNode(node) && node.data.trim() === '/rmx:h'
701
816
  }