@remix-run/ui 0.0.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (272) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +195 -2
  3. package/dist/animation/animate-layout-mixin.d.ts +12 -0
  4. package/dist/animation/animate-layout-mixin.js +214 -0
  5. package/dist/animation/animate-layout-mixin.js.map +1 -0
  6. package/dist/animation/animate-mixins.d.ts +29 -0
  7. package/dist/animation/animate-mixins.js +235 -0
  8. package/dist/animation/animate-mixins.js.map +1 -0
  9. package/dist/animation/index.d.ts +6 -0
  10. package/dist/animation/index.js +5 -0
  11. package/dist/animation/index.js.map +1 -0
  12. package/dist/animation/spring.d.ts +75 -0
  13. package/dist/animation/spring.js +183 -0
  14. package/dist/animation/spring.js.map +1 -0
  15. package/dist/animation/tween.d.ts +70 -0
  16. package/dist/animation/tween.js +93 -0
  17. package/dist/animation/tween.js.map +1 -0
  18. package/dist/components/accordion/accordion.d.ts +92 -0
  19. package/dist/components/accordion/accordion.js +337 -0
  20. package/dist/components/accordion/accordion.js.map +1 -0
  21. package/dist/components/anchor/anchor.d.ts +13 -0
  22. package/dist/components/anchor/anchor.js +558 -0
  23. package/dist/components/anchor/anchor.js.map +1 -0
  24. package/dist/components/breadcrumbs/breadcrumbs.d.ts +11 -0
  25. package/dist/components/breadcrumbs/breadcrumbs.js +78 -0
  26. package/dist/components/breadcrumbs/breadcrumbs.js.map +1 -0
  27. package/dist/components/button/button.d.ts +23 -0
  28. package/dist/components/button/button.js +147 -0
  29. package/dist/components/button/button.js.map +1 -0
  30. package/dist/components/combobox/combobox.d.ts +101 -0
  31. package/dist/components/combobox/combobox.js +708 -0
  32. package/dist/components/combobox/combobox.js.map +1 -0
  33. package/dist/components/glyph/glyph.d.ts +14 -0
  34. package/dist/components/glyph/glyph.js +65 -0
  35. package/dist/components/glyph/glyph.js.map +1 -0
  36. package/dist/components/listbox/listbox.d.ts +67 -0
  37. package/dist/components/listbox/listbox.js +340 -0
  38. package/dist/components/listbox/listbox.js.map +1 -0
  39. package/dist/components/menu/hover-aim.d.ts +5 -0
  40. package/dist/components/menu/hover-aim.js +308 -0
  41. package/dist/components/menu/hover-aim.js.map +1 -0
  42. package/dist/components/menu/menu.d.ts +164 -0
  43. package/dist/components/menu/menu.js +1106 -0
  44. package/dist/components/menu/menu.js.map +1 -0
  45. package/dist/components/popover/popover.d.ts +35 -0
  46. package/dist/components/popover/popover.js +138 -0
  47. package/dist/components/popover/popover.js.map +1 -0
  48. package/dist/components/select/select.d.ts +67 -0
  49. package/dist/components/select/select.js +397 -0
  50. package/dist/components/select/select.js.map +1 -0
  51. package/dist/components/separator/separator.d.ts +2 -0
  52. package/dist/components/separator/separator.js +15 -0
  53. package/dist/components/separator/separator.js.map +1 -0
  54. package/dist/components/tabs/tabs.d.ts +78 -0
  55. package/dist/components/tabs/tabs.js +341 -0
  56. package/dist/components/tabs/tabs.js.map +1 -0
  57. package/dist/index.d.ts +28 -0
  58. package/dist/index.js +21 -0
  59. package/dist/index.js.map +1 -0
  60. package/dist/interactions/keydown/keydown.d.ts +1 -0
  61. package/dist/interactions/keydown/keydown.js +8 -0
  62. package/dist/interactions/keydown/keydown.js.map +1 -0
  63. package/dist/interactions/outside-click/outside-click-mixin.d.ts +2 -0
  64. package/dist/interactions/outside-click/outside-click-mixin.js +29 -0
  65. package/dist/interactions/outside-click/outside-click-mixin.js.map +1 -0
  66. package/dist/interactions/typeahead/typeahead-mixin.d.ts +8 -0
  67. package/dist/interactions/typeahead/typeahead-mixin.js +59 -0
  68. package/dist/interactions/typeahead/typeahead-mixin.js.map +1 -0
  69. package/dist/jsx-runtime.d.ts +2 -0
  70. package/dist/jsx-runtime.js +3 -0
  71. package/dist/jsx-runtime.js.map +1 -0
  72. package/dist/runtime/client-entries.d.ts +91 -0
  73. package/dist/runtime/client-entries.js +40 -0
  74. package/dist/runtime/client-entries.js.map +1 -0
  75. package/dist/runtime/component.d.ts +223 -0
  76. package/dist/runtime/component.js +152 -0
  77. package/dist/runtime/component.js.map +1 -0
  78. package/dist/runtime/create-element.d.ts +10 -0
  79. package/dist/runtime/create-element.js +29 -0
  80. package/dist/runtime/create-element.js.map +1 -0
  81. package/dist/runtime/diff-dom.d.ts +2 -0
  82. package/dist/runtime/diff-dom.js +364 -0
  83. package/dist/runtime/diff-dom.js.map +1 -0
  84. package/dist/runtime/diff-props.d.ts +9 -0
  85. package/dist/runtime/diff-props.js +195 -0
  86. package/dist/runtime/diff-props.js.map +1 -0
  87. package/dist/runtime/document-state.d.ts +11 -0
  88. package/dist/runtime/document-state.js +106 -0
  89. package/dist/runtime/document-state.js.map +1 -0
  90. package/dist/runtime/dom.d.ts +3189 -0
  91. package/dist/runtime/dom.js +2 -0
  92. package/dist/runtime/dom.js.map +1 -0
  93. package/dist/runtime/error-event.d.ts +20 -0
  94. package/dist/runtime/error-event.js +19 -0
  95. package/dist/runtime/error-event.js.map +1 -0
  96. package/dist/runtime/event-listeners.d.ts +50 -0
  97. package/dist/runtime/event-listeners.js +31 -0
  98. package/dist/runtime/event-listeners.js.map +1 -0
  99. package/dist/runtime/frame.d.ts +119 -0
  100. package/dist/runtime/frame.js +920 -0
  101. package/dist/runtime/frame.js.map +1 -0
  102. package/dist/runtime/invariant.d.ts +23 -0
  103. package/dist/runtime/invariant.js +33 -0
  104. package/dist/runtime/invariant.js.map +1 -0
  105. package/dist/runtime/jsx.d.ts +320 -0
  106. package/dist/runtime/jsx.js +32 -0
  107. package/dist/runtime/jsx.js.map +1 -0
  108. package/dist/runtime/mixins/attrs-mixin.d.ts +9 -0
  109. package/dist/runtime/mixins/attrs-mixin.js +23 -0
  110. package/dist/runtime/mixins/attrs-mixin.js.map +1 -0
  111. package/dist/runtime/mixins/link-mixin.d.ts +17 -0
  112. package/dist/runtime/mixins/link-mixin.js +101 -0
  113. package/dist/runtime/mixins/link-mixin.js.map +1 -0
  114. package/dist/runtime/mixins/mixin.d.ts +145 -0
  115. package/dist/runtime/mixins/mixin.js +570 -0
  116. package/dist/runtime/mixins/mixin.js.map +1 -0
  117. package/dist/runtime/mixins/on-mixin.d.ts +16 -0
  118. package/dist/runtime/mixins/on-mixin.js +49 -0
  119. package/dist/runtime/mixins/on-mixin.js.map +1 -0
  120. package/dist/runtime/mixins/ref-mixin.d.ts +9 -0
  121. package/dist/runtime/mixins/ref-mixin.js +21 -0
  122. package/dist/runtime/mixins/ref-mixin.js.map +1 -0
  123. package/dist/runtime/navigation.d.ts +28 -0
  124. package/dist/runtime/navigation.js +107 -0
  125. package/dist/runtime/navigation.js.map +1 -0
  126. package/dist/runtime/reconcile.d.ts +11 -0
  127. package/dist/runtime/reconcile.js +1262 -0
  128. package/dist/runtime/reconcile.js.map +1 -0
  129. package/dist/runtime/render.d.ts +54 -0
  130. package/dist/runtime/render.js +50 -0
  131. package/dist/runtime/render.js.map +1 -0
  132. package/dist/runtime/run.d.ts +45 -0
  133. package/dist/runtime/run.js +68 -0
  134. package/dist/runtime/run.js.map +1 -0
  135. package/dist/runtime/scheduler.d.ts +30 -0
  136. package/dist/runtime/scheduler.js +195 -0
  137. package/dist/runtime/scheduler.js.map +1 -0
  138. package/dist/runtime/svg-attributes.d.ts +5 -0
  139. package/dist/runtime/svg-attributes.js +124 -0
  140. package/dist/runtime/svg-attributes.js.map +1 -0
  141. package/dist/runtime/to-vnode.d.ts +3 -0
  142. package/dist/runtime/to-vnode.js +46 -0
  143. package/dist/runtime/to-vnode.js.map +1 -0
  144. package/dist/runtime/typed-event-target.d.ts +50 -0
  145. package/dist/runtime/typed-event-target.js +6 -0
  146. package/dist/runtime/typed-event-target.js.map +1 -0
  147. package/dist/runtime/vdom.d.ts +55 -0
  148. package/dist/runtime/vdom.js +198 -0
  149. package/dist/runtime/vdom.js.map +1 -0
  150. package/dist/runtime/vnode.d.ts +79 -0
  151. package/dist/runtime/vnode.js +38 -0
  152. package/dist/runtime/vnode.js.map +1 -0
  153. package/dist/server/stream.d.ts +57 -0
  154. package/dist/server/stream.js +1011 -0
  155. package/dist/server/stream.js.map +1 -0
  156. package/dist/style/css-mixin.d.ts +8 -0
  157. package/dist/style/css-mixin.js +54 -0
  158. package/dist/style/css-mixin.js.map +1 -0
  159. package/dist/style/index.d.ts +5 -0
  160. package/dist/style/index.js +4 -0
  161. package/dist/style/index.js.map +1 -0
  162. package/dist/style/style.d.ts +24 -0
  163. package/dist/style/style.js +269 -0
  164. package/dist/style/style.js.map +1 -0
  165. package/dist/style/stylesheet.d.ts +11 -0
  166. package/dist/style/stylesheet.js +174 -0
  167. package/dist/style/stylesheet.js.map +1 -0
  168. package/dist/test.d.ts +2 -0
  169. package/dist/test.js +2 -0
  170. package/dist/test.js.map +1 -0
  171. package/dist/theme/contract.d.ts +259 -0
  172. package/dist/theme/contract.js +131 -0
  173. package/dist/theme/contract.js.map +1 -0
  174. package/dist/theme/glyph-contract.d.ts +13 -0
  175. package/dist/theme/glyph-contract.js +34 -0
  176. package/dist/theme/glyph-contract.js.map +1 -0
  177. package/dist/theme/presets/rmx-01/glyphs.d.ts +2 -0
  178. package/dist/theme/presets/rmx-01/glyphs.js +252 -0
  179. package/dist/theme/presets/rmx-01/glyphs.js.map +1 -0
  180. package/dist/theme/presets/rmx-01/index.d.ts +2 -0
  181. package/dist/theme/presets/rmx-01/index.js +119 -0
  182. package/dist/theme/presets/rmx-01/index.js.map +1 -0
  183. package/dist/theme/runtime.d.ts +2 -0
  184. package/dist/theme/runtime.js +81 -0
  185. package/dist/theme/runtime.js.map +1 -0
  186. package/dist/theme/theme.d.ts +6 -0
  187. package/dist/theme/theme.js +5 -0
  188. package/dist/theme/theme.js.map +1 -0
  189. package/dist/utils/flash-attribute.d.ts +1 -0
  190. package/dist/utils/flash-attribute.js +11 -0
  191. package/dist/utils/flash-attribute.js.map +1 -0
  192. package/dist/utils/scroll-lock.d.ts +3 -0
  193. package/dist/utils/scroll-lock.js +69 -0
  194. package/dist/utils/scroll-lock.js.map +1 -0
  195. package/dist/utils/wait-for-css-transition.d.ts +1 -0
  196. package/dist/utils/wait-for-css-transition.js +58 -0
  197. package/dist/utils/wait-for-css-transition.js.map +1 -0
  198. package/dist/utils/wait.d.ts +1 -0
  199. package/dist/utils/wait.js +6 -0
  200. package/dist/utils/wait.js.map +1 -0
  201. package/package.json +124 -5
  202. package/src/animation/animate-layout-mixin.ts +266 -0
  203. package/src/animation/animate-mixins.ts +292 -0
  204. package/src/animation/index.ts +6 -0
  205. package/src/animation/spring.ts +299 -0
  206. package/src/animation/tween.ts +134 -0
  207. package/src/components/accordion/accordion.tsx +565 -0
  208. package/src/components/anchor/anchor.ts +904 -0
  209. package/src/components/breadcrumbs/breadcrumbs.tsx +124 -0
  210. package/src/components/button/README.md +44 -0
  211. package/src/components/button/button.tsx +188 -0
  212. package/src/components/combobox/README.md +145 -0
  213. package/src/components/combobox/combobox.tsx +1014 -0
  214. package/src/components/glyph/glyph.tsx +110 -0
  215. package/src/components/listbox/listbox.ts +447 -0
  216. package/src/components/menu/hover-aim.ts +428 -0
  217. package/src/components/menu/menu.tsx +1547 -0
  218. package/src/components/popover/README.md +122 -0
  219. package/src/components/popover/popover.ts +201 -0
  220. package/src/components/select/select.tsx +585 -0
  221. package/src/components/separator/separator.ts +19 -0
  222. package/src/components/tabs/README.md +105 -0
  223. package/src/components/tabs/tabs.tsx +499 -0
  224. package/src/index.ts +72 -0
  225. package/src/interactions/keydown/keydown.ts +14 -0
  226. package/src/interactions/outside-click/outside-click-mixin.ts +55 -0
  227. package/src/interactions/typeahead/typeahead-mixin.ts +89 -0
  228. package/src/jsx-runtime.ts +2 -0
  229. package/src/runtime/client-entries.ts +137 -0
  230. package/src/runtime/component.ts +402 -0
  231. package/src/runtime/create-element.ts +38 -0
  232. package/src/runtime/diff-dom.ts +404 -0
  233. package/src/runtime/diff-props.ts +209 -0
  234. package/src/runtime/document-state.ts +130 -0
  235. package/src/runtime/dom.ts +3971 -0
  236. package/src/runtime/error-event.ts +26 -0
  237. package/src/runtime/event-listeners.ts +171 -0
  238. package/src/runtime/frame.ts +1218 -0
  239. package/src/runtime/invariant.ts +31 -0
  240. package/src/runtime/jsx.ts +397 -0
  241. package/src/runtime/mixins/attrs-mixin.ts +35 -0
  242. package/src/runtime/mixins/link-mixin.ts +131 -0
  243. package/src/runtime/mixins/mixin.ts +908 -0
  244. package/src/runtime/mixins/on-mixin.ts +89 -0
  245. package/src/runtime/mixins/ref-mixin.ts +32 -0
  246. package/src/runtime/navigation.ts +148 -0
  247. package/src/runtime/reconcile.ts +1757 -0
  248. package/src/runtime/render.ts +101 -0
  249. package/src/runtime/run.ts +100 -0
  250. package/src/runtime/scheduler.ts +269 -0
  251. package/src/runtime/svg-attributes.ts +133 -0
  252. package/src/runtime/to-vnode.ts +51 -0
  253. package/src/runtime/typed-event-target.ts +67 -0
  254. package/src/runtime/vdom.ts +295 -0
  255. package/src/runtime/vnode.ts +137 -0
  256. package/src/server/stream.ts +1347 -0
  257. package/src/style/css-mixin.ts +82 -0
  258. package/src/style/index.ts +10 -0
  259. package/src/style/style.ts +312 -0
  260. package/src/style/stylesheet.ts +209 -0
  261. package/src/test/utils.ts +45 -0
  262. package/src/test.ts +2 -0
  263. package/src/theme/contract.ts +183 -0
  264. package/src/theme/glyph-contract.ts +57 -0
  265. package/src/theme/presets/rmx-01/glyphs.tsx +308 -0
  266. package/src/theme/presets/rmx-01/index.ts +121 -0
  267. package/src/theme/runtime.ts +116 -0
  268. package/src/theme/theme.ts +15 -0
  269. package/src/utils/flash-attribute.ts +11 -0
  270. package/src/utils/scroll-lock.ts +97 -0
  271. package/src/utils/wait-for-css-transition.ts +66 -0
  272. package/src/utils/wait.ts +5 -0
@@ -0,0 +1,920 @@
1
+ import { jsx } from "./jsx.js";
2
+ import { Frame, createFrameHandle } from "./component.js";
3
+ import { createComponentErrorEvent, getComponentError } from "./error-event.js";
4
+ import { invariant } from "./invariant.js";
5
+ import { createRangeRoot, createRoot } from "./vdom.js";
6
+ import { diffNodes } from "./diff-dom.js";
7
+ import { createStyleManager } from "../style/index.js";
8
+ const bufferedFrameTemplates = new Map();
9
+ const frameTemplateListeners = new Map();
10
+ const DOCTYPE_PATTERN = /<!doctype(?:\s[^>]*)?>/gi;
11
+ function stripDoctypeMarkup(html) {
12
+ return html.replace(DOCTYPE_PATTERN, '');
13
+ }
14
+ function syncElementAttributes(target, source) {
15
+ for (let attribute of Array.from(target.attributes)) {
16
+ if (!source.hasAttribute(attribute.name)) {
17
+ target.removeAttribute(attribute.name);
18
+ }
19
+ }
20
+ for (let attribute of Array.from(source.attributes)) {
21
+ if (target.getAttribute(attribute.name) !== attribute.value) {
22
+ target.setAttribute(attribute.name, attribute.value);
23
+ }
24
+ }
25
+ }
26
+ export function createFrame(root, init) {
27
+ let container = createContainer(root);
28
+ let observers = [];
29
+ let subscriptions = [];
30
+ let contentRoot;
31
+ let reloadController;
32
+ let styleManager = init.styleManager ?? createStyleManager();
33
+ // Merge any rmx-data found in the current document once at startup.
34
+ mergeRmxDataFromDocument(init.data, container.doc);
35
+ let runtime = createFrameRuntime({ ...init, styleManager });
36
+ let frame = createFrameHandle({
37
+ src: init.src,
38
+ $runtime: runtime,
39
+ reload: async () => {
40
+ reloadController?.abort();
41
+ let controller = new AbortController();
42
+ reloadController = controller;
43
+ frame.dispatchEvent(new Event('reloadStart'));
44
+ try {
45
+ let content = await init.resolveFrame(frame.src, controller.signal, frameName);
46
+ if (reloadController !== controller || controller.signal.aborted)
47
+ return controller.signal;
48
+ await render(content, { signal: controller.signal });
49
+ return controller.signal;
50
+ }
51
+ catch (error) {
52
+ if (reloadController !== controller || controller.signal.aborted)
53
+ return controller.signal;
54
+ init.errorTarget.dispatchEvent(createComponentErrorEvent(error));
55
+ throw error;
56
+ }
57
+ finally {
58
+ if (reloadController === controller) {
59
+ frame.dispatchEvent(new Event('reloadComplete'));
60
+ }
61
+ }
62
+ },
63
+ replace: async (content) => {
64
+ await render(content);
65
+ },
66
+ });
67
+ runtime.topFrame = runtime.topFrame ?? init.topFrame ?? frame;
68
+ let frameName = init.marker?.name ?? init.name;
69
+ if (frameName) {
70
+ init.namedFrames.set(frameName, frame);
71
+ }
72
+ let context = {
73
+ topFrame: runtime.topFrame,
74
+ errorTarget: init.errorTarget,
75
+ loadModule: init.loadModule,
76
+ resolveFrame: init.resolveFrame,
77
+ pendingClientEntries: init.pendingClientEntries,
78
+ scheduler: init.scheduler,
79
+ frame,
80
+ styleManager,
81
+ data: init.data,
82
+ moduleCache: init.moduleCache,
83
+ moduleLoads: init.moduleLoads,
84
+ frameInstances: init.frameInstances,
85
+ namedFrames: init.namedFrames,
86
+ regionTailRef: container.regionTailRef,
87
+ regionParent: container.regionParent,
88
+ };
89
+ async function render(content, options) {
90
+ if (options?.signal?.aborted)
91
+ return;
92
+ if (content instanceof ReadableStream) {
93
+ await renderFrameStream(content, container.doc, async (html) => {
94
+ if (options?.signal?.aborted)
95
+ return;
96
+ await render(html, options);
97
+ });
98
+ return;
99
+ }
100
+ if (isRemixNodeFrameContent(content)) {
101
+ if (!contentRoot) {
102
+ let currentNodes = getContentNodes();
103
+ removeVirtualRoots(currentNodes);
104
+ disposeSubFrames(currentNodes, context);
105
+ clearFrameContent();
106
+ contentRoot = createFrameContentRoot();
107
+ }
108
+ if (options?.signal?.aborted)
109
+ return;
110
+ contentRoot.render(content);
111
+ return;
112
+ }
113
+ if (contentRoot) {
114
+ contentRoot.dispose();
115
+ contentRoot = undefined;
116
+ }
117
+ let htmlContent = typeof content === 'string' ? stripDoctypeMarkup(content) : undefined;
118
+ let isFullDocumentReload = container.root instanceof Document &&
119
+ htmlContent !== undefined &&
120
+ isFullDocumentHtml(htmlContent);
121
+ if (isFullDocumentReload && htmlContent !== undefined) {
122
+ // Full-document reload should tear down existing hydrated roots and subframes
123
+ // before diffing fresh HTML, otherwise stale component instances can survive
124
+ // on detached DOM nodes.
125
+ let previousBodyNodes = Array.from(container.doc.body.childNodes);
126
+ removeVirtualRoots(previousBodyNodes);
127
+ disposeSubFrames(previousBodyNodes, context);
128
+ let parsed = new DOMParser().parseFromString(htmlContent, 'text/html');
129
+ mergeRmxDataFromDocument(context.data, parsed);
130
+ context.styleManager.reset();
131
+ context.styleManager.adoptServerStyles(collectFrameServerStyleTags(createElementContainer(parsed)));
132
+ syncElementAttributes(container.doc.documentElement, parsed.documentElement);
133
+ syncElementAttributes(container.doc.head, parsed.head);
134
+ syncElementAttributes(container.doc.body, parsed.body);
135
+ diffNodes(Array.from(container.doc.head.childNodes), Array.from(parsed.head.childNodes), {
136
+ ...context,
137
+ regionParent: container.doc.head,
138
+ regionTailRef: null,
139
+ });
140
+ diffNodes(Array.from(container.doc.body.childNodes), Array.from(parsed.body.childNodes), {
141
+ ...context,
142
+ regionParent: container.doc.body,
143
+ regionTailRef: null,
144
+ });
145
+ let bodyContainer = createElementContainer(container.doc.body);
146
+ if (options?.signal?.aborted)
147
+ return;
148
+ scheduleHydrationInContainer(bodyContainer, context, options?.initialHydrationTracker);
149
+ createSubFrames(bodyContainer.childNodes, context);
150
+ return;
151
+ }
152
+ let fragment = htmlContent !== undefined ? createFragmentFromString(container.doc, htmlContent) : content;
153
+ context.styleManager.reset();
154
+ context.styleManager.adoptServerStyles(collectFrameServerStyleTags(createElementContainer(fragment)));
155
+ removeEmptyHeads(fragment);
156
+ mergeRmxDataFromFragment(context.data, fragment);
157
+ let nextContainer = createContainer(fragment);
158
+ if (options?.signal?.aborted)
159
+ return;
160
+ diffNodes(container.childNodes, Array.from(nextContainer.childNodes), {
161
+ ...context,
162
+ regionTailRef: container.regionTailRef,
163
+ regionParent: container.regionParent,
164
+ });
165
+ if (options?.signal?.aborted)
166
+ return;
167
+ scheduleHydrationInContainer(container, context, options?.initialHydrationTracker);
168
+ createSubFrames(container.childNodes, context);
169
+ }
170
+ function createFrameContentRoot() {
171
+ let virtualRoot;
172
+ if (container.root instanceof Document) {
173
+ virtualRoot = createRoot(container.doc.body, {
174
+ scheduler: context.scheduler,
175
+ frame,
176
+ styleManager: context.styleManager,
177
+ });
178
+ }
179
+ else {
180
+ invariant(Array.isArray(root), 'Expected comment-bounded frame root');
181
+ virtualRoot = createRangeRoot(root, {
182
+ scheduler: context.scheduler,
183
+ frame,
184
+ styleManager: context.styleManager,
185
+ });
186
+ }
187
+ virtualRoot.addEventListener('error', (event) => {
188
+ if (context.errorTarget === virtualRoot)
189
+ return;
190
+ context.errorTarget.dispatchEvent(createComponentErrorEvent(getComponentError(event)));
191
+ });
192
+ return virtualRoot;
193
+ }
194
+ function getContentNodes() {
195
+ return container.root instanceof Document
196
+ ? Array.from(container.doc.body.childNodes)
197
+ : container.childNodes;
198
+ }
199
+ function clearFrameContent() {
200
+ for (let node of getContentNodes()) {
201
+ node.parentNode?.removeChild(node);
202
+ }
203
+ }
204
+ async function hydrateInitial() {
205
+ let initialHydrationTracker = createInitialHydrationTracker();
206
+ context.styleManager.reset();
207
+ context.styleManager.adoptServerStyles(collectFrameServerStyleTags(container));
208
+ createSubFrames(container.childNodes, context);
209
+ scheduleHydrationInContainer(container, context, initialHydrationTracker);
210
+ if (init.marker?.status === 'pending') {
211
+ let markerId = init.marker.id;
212
+ let early = consumeFrameTemplate(markerId) ?? getEarlyFrameContent(markerId);
213
+ if (early) {
214
+ await render(early, { initialHydrationTracker });
215
+ }
216
+ else {
217
+ let observer = setupTemplateObserver();
218
+ let unsubscribe = subscribeFrameTemplate(markerId, async (fragment) => {
219
+ unsubscribe();
220
+ await render(fragment);
221
+ observer.disconnect();
222
+ });
223
+ subscriptions.push(unsubscribe);
224
+ let buffered = consumeFrameTemplate(markerId);
225
+ if (buffered) {
226
+ unsubscribe();
227
+ await render(buffered);
228
+ observer.disconnect();
229
+ }
230
+ observers.push(observer);
231
+ }
232
+ }
233
+ initialHydrationTracker.finalize();
234
+ await initialHydrationTracker.ready();
235
+ }
236
+ function dispose() {
237
+ reloadController?.abort();
238
+ reloadController = undefined;
239
+ contentRoot?.dispose();
240
+ contentRoot = undefined;
241
+ // Disconnect any MutationObservers waiting for templates.
242
+ for (let observer of observers) {
243
+ observer.disconnect();
244
+ }
245
+ observers.length = 0;
246
+ for (let unsubscribe of subscriptions) {
247
+ unsubscribe();
248
+ }
249
+ subscriptions.length = 0;
250
+ // Remove hydrated virtual roots in this frame's region.
251
+ removeVirtualRoots(container.childNodes);
252
+ // Dispose sub-frames recursively.
253
+ disposeSubFrames(container.childNodes, context);
254
+ context.styleManager.dispose();
255
+ if (frameName) {
256
+ if (init.namedFrames.get(frameName) === frame) {
257
+ init.namedFrames.delete(frameName);
258
+ }
259
+ }
260
+ }
261
+ let readyPromise = hydrateInitial();
262
+ return {
263
+ render,
264
+ ready: () => readyPromise,
265
+ flush: () => context.scheduler.dequeue(),
266
+ dispose,
267
+ handle: frame,
268
+ };
269
+ }
270
+ export function createFrameRuntime(init) {
271
+ return {
272
+ topFrame: init.topFrame,
273
+ errorTarget: init.errorTarget,
274
+ loadModule: init.loadModule,
275
+ resolveFrame: init.resolveFrame,
276
+ pendingClientEntries: init.pendingClientEntries,
277
+ scheduler: init.scheduler,
278
+ styleManager: init.styleManager,
279
+ data: init.data,
280
+ moduleCache: init.moduleCache,
281
+ moduleLoads: init.moduleLoads,
282
+ frameInstances: init.frameInstances,
283
+ namedFrames: init.namedFrames,
284
+ };
285
+ }
286
+ function createInitialHydrationTracker() {
287
+ let pending = 0;
288
+ let finalized = false;
289
+ let resolveReady;
290
+ let readyPromise = new Promise((resolve) => {
291
+ resolveReady = resolve;
292
+ });
293
+ function maybeResolve() {
294
+ if (finalized && pending === 0) {
295
+ resolveReady?.();
296
+ resolveReady = undefined;
297
+ }
298
+ }
299
+ return {
300
+ track() {
301
+ pending++;
302
+ let completed = false;
303
+ return () => {
304
+ if (completed)
305
+ return;
306
+ completed = true;
307
+ pending--;
308
+ maybeResolve();
309
+ };
310
+ },
311
+ finalize() {
312
+ finalized = true;
313
+ maybeResolve();
314
+ },
315
+ ready() {
316
+ return readyPromise;
317
+ },
318
+ };
319
+ }
320
+ function mergeRmxDataFromDocument(into, doc) {
321
+ let scripts = Array.from(doc.querySelectorAll('script#rmx-data'));
322
+ for (let script of scripts) {
323
+ if (!(script instanceof HTMLScriptElement))
324
+ continue;
325
+ mergeRmxData(into, parseRmxDataScript(script));
326
+ script.remove();
327
+ }
328
+ }
329
+ function mergeRmxDataFromFragment(into, fragment) {
330
+ let scripts = Array.from(fragment.querySelectorAll('script#rmx-data'));
331
+ for (let script of scripts) {
332
+ if (!(script instanceof HTMLScriptElement))
333
+ continue;
334
+ mergeRmxData(into, parseRmxDataScript(script));
335
+ script.remove();
336
+ }
337
+ }
338
+ function removeEmptyHeads(fragment) {
339
+ let heads = Array.from(fragment.querySelectorAll('head'));
340
+ for (let head of heads) {
341
+ if (!head.childNodes.length) {
342
+ head.remove();
343
+ }
344
+ }
345
+ }
346
+ function collectFrameServerStyleTags(container) {
347
+ let styles = [];
348
+ let nodes = container.root instanceof Document
349
+ ? [...Array.from(container.doc.head.childNodes), ...Array.from(container.doc.body.childNodes)]
350
+ : container.childNodes;
351
+ collectOwnedServerStyleTags(nodes, styles);
352
+ return styles;
353
+ }
354
+ function collectOwnedServerStyleTags(nodes, styles) {
355
+ for (let i = 0; i < nodes.length; i++) {
356
+ let node = nodes[i];
357
+ if (isFrameStart(node)) {
358
+ let end = findEndMarker(node, isFrameStart, isFrameEnd);
359
+ i = nodes.indexOf(end);
360
+ continue;
361
+ }
362
+ if (node instanceof HTMLStyleElement && node.matches('style[data-rmx]')) {
363
+ styles.push(node);
364
+ continue;
365
+ }
366
+ if (node instanceof Element || node instanceof Document || node instanceof DocumentFragment) {
367
+ collectOwnedServerStyleTags(Array.from(node.childNodes), styles);
368
+ }
369
+ }
370
+ }
371
+ function parseRmxDataScript(script) {
372
+ try {
373
+ return JSON.parse(script.textContent || '{}');
374
+ }
375
+ catch {
376
+ console.error('[createFrame] Failed to parse rmx-data script');
377
+ return {};
378
+ }
379
+ }
380
+ function mergeRmxData(into, from) {
381
+ if (from.h) {
382
+ if (!into.h)
383
+ into.h = {};
384
+ copyOwnRmxEntries(into.h, from.h);
385
+ }
386
+ if (from.f) {
387
+ if (!into.f)
388
+ into.f = {};
389
+ copyOwnRmxEntries(into.f, from.f);
390
+ }
391
+ }
392
+ function copyOwnRmxEntries(target, source) {
393
+ for (let key of Object.keys(source)) {
394
+ if (key === '__proto__' || key === 'constructor' || key === 'prototype')
395
+ continue;
396
+ if (!Object.hasOwn(source, key))
397
+ continue;
398
+ target[key] = source[key];
399
+ }
400
+ }
401
+ function scheduleHydrationInContainer(container, context, initialHydrationTracker) {
402
+ let hydrationMarkers = findHydrationMarkers(container);
403
+ if (hydrationMarkers.length === 0)
404
+ return;
405
+ let hydrationData = context.data.h;
406
+ if (!hydrationData)
407
+ return;
408
+ for (let marker of hydrationMarkers) {
409
+ let entry = hydrationData[marker.id];
410
+ if (!entry)
411
+ continue;
412
+ scheduleHydrationMarker(marker, entry, context, initialHydrationTracker);
413
+ }
414
+ }
415
+ function scheduleHydrationMarker(marker, entry, context, initialHydrationTracker) {
416
+ let done = initialHydrationTracker?.track();
417
+ let key = `${entry.moduleUrl}#${entry.exportName}`;
418
+ let hydrateWithComponent = (component) => {
419
+ if (!isHydrationMarkerLive(marker, context))
420
+ return;
421
+ let vElement = createElement(component, entry.props);
422
+ context.pendingClientEntries.set(marker.start, [marker.end, vElement]);
423
+ hydrateRegion(vElement, marker.start, marker.end, context);
424
+ };
425
+ let cached = context.moduleCache.get(key);
426
+ if (cached) {
427
+ hydrateWithComponent(cached);
428
+ done?.();
429
+ return;
430
+ }
431
+ getOrStartModuleLoad(key, entry, marker.id, context)
432
+ .then((component) => {
433
+ if (component) {
434
+ hydrateWithComponent(component);
435
+ }
436
+ })
437
+ .finally(() => {
438
+ done?.();
439
+ });
440
+ }
441
+ function getOrStartModuleLoad(key, entry, markerId, context) {
442
+ let inFlight = context.moduleLoads.get(key);
443
+ if (inFlight)
444
+ return inFlight;
445
+ let loadPromise = (async () => {
446
+ try {
447
+ let mod = await context.loadModule(entry.moduleUrl, entry.exportName);
448
+ if (typeof mod !== 'function') {
449
+ throw new Error(`Export "${entry.exportName}" from "${entry.moduleUrl}" is not a function`);
450
+ }
451
+ context.moduleCache.set(key, mod);
452
+ return mod;
453
+ }
454
+ catch (error) {
455
+ console.error(`[createFrame] Failed to load module for ${markerId}:`, error);
456
+ return undefined;
457
+ }
458
+ finally {
459
+ context.moduleLoads.delete(key);
460
+ }
461
+ })();
462
+ context.moduleLoads.set(key, loadPromise);
463
+ return loadPromise;
464
+ }
465
+ function createElement(component, props) {
466
+ let revivedProps = reviveSerializedValue(props);
467
+ return jsx(component, revivedProps);
468
+ }
469
+ function reviveSerializedValue(value) {
470
+ if (value === null || value === undefined)
471
+ return value;
472
+ if (typeof value !== 'object')
473
+ return value;
474
+ if (Array.isArray(value)) {
475
+ return value.map((item) => reviveSerializedValue(item));
476
+ }
477
+ let record = value;
478
+ if (record.$rmxFrame === true) {
479
+ let props = reviveSerializedObject(record.props);
480
+ let key = reviveSerializedValue(record.key);
481
+ return jsx(Frame, props, key);
482
+ }
483
+ if (record.$rmx === true && typeof record.type === 'string') {
484
+ let props = reviveSerializedObject(record.props);
485
+ let key = reviveSerializedValue(record.key);
486
+ return jsx(record.type, props, key);
487
+ }
488
+ let revived = {};
489
+ for (let key in record) {
490
+ revived[key] = reviveSerializedValue(record[key]);
491
+ }
492
+ return revived;
493
+ }
494
+ function reviveSerializedObject(value) {
495
+ if (!value || typeof value !== 'object' || Array.isArray(value))
496
+ return {};
497
+ let revived = reviveSerializedValue(value);
498
+ if (!revived || typeof revived !== 'object' || Array.isArray(revived))
499
+ return {};
500
+ return revived;
501
+ }
502
+ function hydrateRegion(vElement, start, end, context) {
503
+ context.pendingClientEntries.delete(start);
504
+ // The same marker can be discovered by overlapping hydration passes
505
+ // (for example, document root + nested frame root). Reuse the existing
506
+ // virtual root instead of redefining the marker property.
507
+ if (isHydratedVirtualRootMarker(start)) {
508
+ start.$rmx.render(vElement);
509
+ return;
510
+ }
511
+ let root = createRangeRoot([start, end], {
512
+ scheduler: context.scheduler,
513
+ frame: context.frame,
514
+ styleManager: context.styleManager,
515
+ });
516
+ root.addEventListener('error', (event) => {
517
+ if (context.errorTarget === root)
518
+ return;
519
+ context.errorTarget.dispatchEvent(createComponentErrorEvent(getComponentError(event)));
520
+ });
521
+ Object.defineProperty(start, '$rmx', { value: root, enumerable: false });
522
+ root.render(vElement);
523
+ }
524
+ function createSubFrames(nodes, context) {
525
+ for (let i = 0; i < nodes.length; i++) {
526
+ let node = nodes[i];
527
+ if (isFrameStart(node)) {
528
+ let end = findEndMarker(node, isFrameStart, isFrameEnd);
529
+ if (!context.frameInstances.has(node)) {
530
+ let id = getFrameId(node);
531
+ let marker = context.data.f?.[id];
532
+ if (marker) {
533
+ let frameMarker = { ...marker, id };
534
+ let subFrame = createFrame([node, end], {
535
+ src: frameMarker.src,
536
+ marker: frameMarker,
537
+ topFrame: context.topFrame,
538
+ errorTarget: context.errorTarget,
539
+ loadModule: context.loadModule,
540
+ resolveFrame: context.resolveFrame,
541
+ pendingClientEntries: context.pendingClientEntries,
542
+ scheduler: context.scheduler,
543
+ data: context.data,
544
+ moduleCache: context.moduleCache,
545
+ moduleLoads: context.moduleLoads,
546
+ frameInstances: context.frameInstances,
547
+ namedFrames: context.namedFrames,
548
+ });
549
+ context.frameInstances.set(node, subFrame);
550
+ }
551
+ }
552
+ i = nodes.indexOf(end);
553
+ continue;
554
+ }
555
+ if (node.childNodes && node.childNodes.length > 0) {
556
+ createSubFrames(Array.from(node.childNodes), context);
557
+ }
558
+ }
559
+ }
560
+ function isHydrationMarkerLive(marker, context) {
561
+ if (!marker.start.isConnected || !marker.end.isConnected)
562
+ return false;
563
+ if (marker.start.parentNode !== marker.end.parentNode)
564
+ return false;
565
+ let startText = marker.start.data.trim();
566
+ if (startText !== `rmx:h:${marker.id}`)
567
+ return false;
568
+ if (marker.end.data.trim() !== '/rmx:h')
569
+ return false;
570
+ let parent = marker.start.parentNode;
571
+ if (!parent)
572
+ return false;
573
+ if (context.regionTailRef) {
574
+ let startPosition = marker.start.compareDocumentPosition(context.regionTailRef);
575
+ let endPosition = marker.end.compareDocumentPosition(context.regionTailRef);
576
+ let tailFollowsStart = (startPosition & Node.DOCUMENT_POSITION_FOLLOWING) !== 0;
577
+ let tailFollowsEnd = (endPosition & Node.DOCUMENT_POSITION_FOLLOWING) !== 0;
578
+ if (!tailFollowsStart || !tailFollowsEnd)
579
+ return false;
580
+ }
581
+ return true;
582
+ }
583
+ function removeVirtualRoots(nodes) {
584
+ for (let i = 0; i < nodes.length; i++) {
585
+ let node = nodes[i];
586
+ if (isHydratedVirtualRootMarker(node)) {
587
+ node.$rmx.dispose();
588
+ let end = findEndMarker(node, isHydrationStart, isHydrationEnd);
589
+ i = nodes.indexOf(end);
590
+ continue;
591
+ }
592
+ if (node.childNodes && node.childNodes.length > 0) {
593
+ removeVirtualRoots(Array.from(node.childNodes));
594
+ }
595
+ }
596
+ }
597
+ function disposeSubFrames(nodes, context) {
598
+ for (let i = 0; i < nodes.length; i++) {
599
+ let node = nodes[i];
600
+ if (isFrameStart(node)) {
601
+ let end = findEndMarker(node, isFrameStart, isFrameEnd);
602
+ let subFrame = context.frameInstances.get(node);
603
+ if (subFrame) {
604
+ subFrame.dispose();
605
+ context.frameInstances.delete(node);
606
+ }
607
+ i = nodes.indexOf(end);
608
+ continue;
609
+ }
610
+ if (node.childNodes && node.childNodes.length > 0) {
611
+ disposeSubFrames(Array.from(node.childNodes), context);
612
+ }
613
+ }
614
+ }
615
+ function getEarlyFrameContent(id) {
616
+ let template = document.querySelector(`template#${id}`);
617
+ if (template instanceof HTMLTemplateElement) {
618
+ let fragment = template.content;
619
+ template.remove();
620
+ return fragment;
621
+ }
622
+ return null;
623
+ }
624
+ function setupTemplateObserver() {
625
+ let root = document.body ?? document.documentElement ?? document;
626
+ let observer = new MutationObserver((mutations) => {
627
+ for (let mutation of mutations) {
628
+ for (let node of mutation.addedNodes) {
629
+ collectAndPublishTemplates(node);
630
+ }
631
+ }
632
+ });
633
+ observer.observe(root, { childList: true, subtree: true });
634
+ return observer;
635
+ }
636
+ function collectAndPublishTemplates(node) {
637
+ if (node instanceof HTMLTemplateElement) {
638
+ publishFrameTemplateElement(node);
639
+ return;
640
+ }
641
+ if (!(node instanceof Element))
642
+ return;
643
+ let templates = Array.from(node.querySelectorAll('template'));
644
+ for (let template of templates) {
645
+ if (!(template instanceof HTMLTemplateElement))
646
+ continue;
647
+ publishFrameTemplateElement(template);
648
+ }
649
+ }
650
+ function publishFrameTemplateElement(template) {
651
+ if (!template.id)
652
+ return;
653
+ template.remove();
654
+ publishFrameTemplate(template.id, template.content);
655
+ }
656
+ export function publishFrameTemplate(id, fragment) {
657
+ let listeners = frameTemplateListeners.get(id);
658
+ if (!listeners || listeners.size === 0) {
659
+ let queue = bufferedFrameTemplates.get(id);
660
+ if (!queue) {
661
+ queue = [];
662
+ bufferedFrameTemplates.set(id, queue);
663
+ }
664
+ queue.push(fragment);
665
+ return;
666
+ }
667
+ for (let listener of listeners) {
668
+ listener(fragment.cloneNode(true));
669
+ }
670
+ }
671
+ export function consumeFrameTemplate(id) {
672
+ let queue = bufferedFrameTemplates.get(id);
673
+ if (!queue || queue.length === 0)
674
+ return null;
675
+ let fragment = queue.shift() ?? null;
676
+ if (queue.length === 0) {
677
+ bufferedFrameTemplates.delete(id);
678
+ }
679
+ return fragment;
680
+ }
681
+ function subscribeFrameTemplate(id, listener) {
682
+ let listeners = frameTemplateListeners.get(id);
683
+ if (!listeners) {
684
+ listeners = new Set();
685
+ frameTemplateListeners.set(id, listeners);
686
+ }
687
+ listeners.add(listener);
688
+ return () => {
689
+ let current = frameTemplateListeners.get(id);
690
+ if (!current)
691
+ return;
692
+ current.delete(listener);
693
+ if (current.size === 0) {
694
+ frameTemplateListeners.delete(id);
695
+ }
696
+ };
697
+ }
698
+ const COMPLETE_TEMPLATE_WITH_ID_PATTERN = /<template\b[^>]*\bid=(?:"([^"]+)"|'([^']+)')[^>]*>[\s\S]*?<\/template>/gi;
699
+ function extractTemplatesFromBuffer(doc, buffer, onTemplate) {
700
+ let html = '';
701
+ let cursor = 0;
702
+ let hadMatch = false;
703
+ COMPLETE_TEMPLATE_WITH_ID_PATTERN.lastIndex = 0;
704
+ let match = COMPLETE_TEMPLATE_WITH_ID_PATTERN.exec(buffer);
705
+ while (match) {
706
+ hadMatch = true;
707
+ let index = match.index;
708
+ let fullMatch = match[0];
709
+ let id = match[1] ?? match[2];
710
+ let matchEnd = index + fullMatch.length;
711
+ html += buffer.slice(cursor, index);
712
+ if (id) {
713
+ let parsed = createFragmentFromString(doc, fullMatch);
714
+ let template = parsed.querySelector('template');
715
+ if (template instanceof HTMLTemplateElement && template.id) {
716
+ onTemplate(template.id, template.content);
717
+ }
718
+ }
719
+ cursor = matchEnd;
720
+ match = COMPLETE_TEMPLATE_WITH_ID_PATTERN.exec(buffer);
721
+ }
722
+ let tail = buffer.slice(cursor);
723
+ if (tail === '')
724
+ return { html, remainder: '' };
725
+ let tailStart = tail.toLowerCase().lastIndexOf('<template');
726
+ if (tailStart === -1) {
727
+ return { html: html + tail, remainder: '' };
728
+ }
729
+ if (!hadMatch) {
730
+ return {
731
+ html: buffer.slice(0, tailStart),
732
+ remainder: buffer.slice(tailStart),
733
+ };
734
+ }
735
+ return {
736
+ html: html + tail.slice(0, tailStart),
737
+ remainder: tail.slice(tailStart),
738
+ };
739
+ }
740
+ async function renderFrameStream(stream, doc, applyHtml) {
741
+ let reader = stream.getReader();
742
+ let decoder = new TextDecoder();
743
+ let buffer = '';
744
+ let html = '';
745
+ let appliedLength = 0;
746
+ let appliedOnce = false;
747
+ try {
748
+ while (true) {
749
+ let { done, value } = await reader.read();
750
+ if (done)
751
+ break;
752
+ buffer += decoder.decode(value, { stream: true });
753
+ let parsed = extractTemplatesFromBuffer(doc, buffer, publishFrameTemplate);
754
+ buffer = parsed.remainder;
755
+ if (parsed.html !== '') {
756
+ html += parsed.html;
757
+ let htmlMarkers = collectHtmlMarkerSummary(html);
758
+ if (!hasBalancedMarkerSummary(htmlMarkers)) {
759
+ continue;
760
+ }
761
+ await applyHtml(html);
762
+ appliedLength = html.length;
763
+ appliedOnce = true;
764
+ }
765
+ }
766
+ buffer += decoder.decode();
767
+ let parsed = extractTemplatesFromBuffer(doc, buffer, publishFrameTemplate);
768
+ html += parsed.html;
769
+ buffer = parsed.remainder;
770
+ if (buffer !== '') {
771
+ html += buffer;
772
+ buffer = '';
773
+ }
774
+ if (html !== '' && html.length > appliedLength) {
775
+ await applyHtml(html);
776
+ appliedOnce = true;
777
+ }
778
+ // A frame stream can legitimately resolve to empty content. Ensure the
779
+ // existing frame region is cleared instead of treated as a no-op.
780
+ if (html === '' && !appliedOnce) {
781
+ await applyHtml('');
782
+ }
783
+ }
784
+ finally {
785
+ reader.releaseLock();
786
+ }
787
+ }
788
+ function createContainer(root) {
789
+ return Array.isArray(root) ? createCommentContainer(root) : createElementContainer(root);
790
+ }
791
+ function createElementContainer(root) {
792
+ let doc = root instanceof Document ? root : (root.ownerDocument ?? document);
793
+ return {
794
+ doc,
795
+ root,
796
+ get childNodes() {
797
+ return Array.from(root.childNodes);
798
+ },
799
+ };
800
+ }
801
+ function createCommentContainer([start, end]) {
802
+ let parent = end.parentNode;
803
+ invariant(parent, 'Invalid comment container');
804
+ invariant(start.parentNode === parent, 'Boundaries must share parent');
805
+ let doc = parent.ownerDocument ?? document;
806
+ let getChildNodesBetween = () => {
807
+ let nodes = [];
808
+ let node = start.nextSibling;
809
+ while (node && node !== end) {
810
+ nodes.push(node);
811
+ node = node.nextSibling;
812
+ }
813
+ return nodes;
814
+ };
815
+ return {
816
+ doc,
817
+ root: parent,
818
+ get childNodes() {
819
+ return getChildNodesBetween();
820
+ },
821
+ regionTailRef: end,
822
+ regionParent: parent,
823
+ };
824
+ }
825
+ function createFragmentFromString(doc, content) {
826
+ let template = doc.createElement('template');
827
+ template.innerHTML = stripDoctypeMarkup(content).trim();
828
+ return template.content;
829
+ }
830
+ function isRemixNodeFrameContent(content) {
831
+ return !(content instanceof ReadableStream ||
832
+ content instanceof DocumentFragment ||
833
+ typeof content === 'string');
834
+ }
835
+ function isFullDocumentHtml(content) {
836
+ let trimmed = content.trimStart();
837
+ return /^<!doctype html\b/i.test(trimmed) || /^<html[\s>]/i.test(trimmed);
838
+ }
839
+ function findHydrationMarkers(container) {
840
+ let results = [];
841
+ forEachComment(container, (comment) => {
842
+ let trimmed = comment.data.trim();
843
+ if (!trimmed.startsWith('rmx:h:'))
844
+ return;
845
+ let id = trimmed.slice('rmx:h:'.length);
846
+ let end = findEndMarker(comment, isHydrationStart, isHydrationEnd);
847
+ results.push({ id, start: comment, end });
848
+ });
849
+ return results;
850
+ }
851
+ function forEachComment(container, cb) {
852
+ walkCommentsInNodes(container.childNodes, cb);
853
+ }
854
+ function walkCommentsInNodes(nodes, cb) {
855
+ for (let i = 0; i < nodes.length; i++) {
856
+ let node = nodes[i];
857
+ // Frame ownership boundary: hydration markers inside nested frame regions
858
+ // are discovered and hydrated by the nested frame instance only.
859
+ if (isFrameStart(node)) {
860
+ let end = findEndMarker(node, isFrameStart, isFrameEnd);
861
+ i = nodes.indexOf(end);
862
+ continue;
863
+ }
864
+ if (node.nodeType === Node.COMMENT_NODE)
865
+ cb(node);
866
+ if (node.childNodes && node.childNodes.length > 0) {
867
+ walkCommentsInNodes(Array.from(node.childNodes), cb);
868
+ }
869
+ }
870
+ }
871
+ function isHydrationStart(node) {
872
+ return node.data.trim().startsWith('rmx:h:');
873
+ }
874
+ function isHydrationEnd(node) {
875
+ return node.data.trim() === '/rmx:h';
876
+ }
877
+ function isHydratedVirtualRootMarker(node) {
878
+ return node instanceof Comment && '$rmx' in node;
879
+ }
880
+ function isFrameStart(node) {
881
+ return node instanceof Comment && node.data.trim().startsWith('rmx:f:');
882
+ }
883
+ function isFrameEnd(node) {
884
+ return node.data.trim() === '/rmx:f';
885
+ }
886
+ function getFrameId(start) {
887
+ let trimmed = start.data.trim();
888
+ invariant(trimmed.startsWith('rmx:f:'), 'Invalid frame start marker');
889
+ return trimmed.slice('rmx:f:'.length);
890
+ }
891
+ function findEndMarker(start, isStart, isEnd) {
892
+ let node = start.nextSibling;
893
+ let depth = 1;
894
+ while (node) {
895
+ if (node.nodeType === Node.COMMENT_NODE) {
896
+ let comment = node;
897
+ if (isStart(comment))
898
+ depth++;
899
+ else if (isEnd(comment)) {
900
+ depth--;
901
+ if (depth === 0)
902
+ return comment;
903
+ }
904
+ }
905
+ node = node.nextSibling;
906
+ }
907
+ throw new Error('End marker not found');
908
+ }
909
+ function collectHtmlMarkerSummary(html) {
910
+ return {
911
+ frameStarts: html.match(/<!--\s*rmx:f:/g)?.length ?? 0,
912
+ frameEnds: html.match(/<!--\s*\/rmx:f\s*-->/g)?.length ?? 0,
913
+ hydrationStarts: html.match(/<!--\s*rmx:h:/g)?.length ?? 0,
914
+ hydrationEnds: html.match(/<!--\s*\/rmx:h\s*-->/g)?.length ?? 0,
915
+ };
916
+ }
917
+ function hasBalancedMarkerSummary(summary) {
918
+ return (summary.frameStarts === summary.frameEnds && summary.hydrationStarts === summary.hydrationEnds);
919
+ }
920
+ //# sourceMappingURL=frame.js.map