@remix-run/ui 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +195 -2
- package/dist/animation/animate-layout-mixin.d.ts +12 -0
- package/dist/animation/animate-layout-mixin.js +214 -0
- package/dist/animation/animate-layout-mixin.js.map +1 -0
- package/dist/animation/animate-mixins.d.ts +29 -0
- package/dist/animation/animate-mixins.js +235 -0
- package/dist/animation/animate-mixins.js.map +1 -0
- package/dist/animation/index.d.ts +6 -0
- package/dist/animation/index.js +5 -0
- package/dist/animation/index.js.map +1 -0
- package/dist/animation/spring.d.ts +75 -0
- package/dist/animation/spring.js +183 -0
- package/dist/animation/spring.js.map +1 -0
- package/dist/animation/tween.d.ts +70 -0
- package/dist/animation/tween.js +93 -0
- package/dist/animation/tween.js.map +1 -0
- package/dist/components/accordion/accordion.d.ts +92 -0
- package/dist/components/accordion/accordion.js +337 -0
- package/dist/components/accordion/accordion.js.map +1 -0
- package/dist/components/anchor/anchor.d.ts +13 -0
- package/dist/components/anchor/anchor.js +558 -0
- package/dist/components/anchor/anchor.js.map +1 -0
- package/dist/components/breadcrumbs/breadcrumbs.d.ts +11 -0
- package/dist/components/breadcrumbs/breadcrumbs.js +78 -0
- package/dist/components/breadcrumbs/breadcrumbs.js.map +1 -0
- package/dist/components/button/button.d.ts +23 -0
- package/dist/components/button/button.js +147 -0
- package/dist/components/button/button.js.map +1 -0
- package/dist/components/combobox/combobox.d.ts +101 -0
- package/dist/components/combobox/combobox.js +708 -0
- package/dist/components/combobox/combobox.js.map +1 -0
- package/dist/components/glyph/glyph.d.ts +14 -0
- package/dist/components/glyph/glyph.js +65 -0
- package/dist/components/glyph/glyph.js.map +1 -0
- package/dist/components/listbox/listbox.d.ts +67 -0
- package/dist/components/listbox/listbox.js +340 -0
- package/dist/components/listbox/listbox.js.map +1 -0
- package/dist/components/menu/hover-aim.d.ts +5 -0
- package/dist/components/menu/hover-aim.js +308 -0
- package/dist/components/menu/hover-aim.js.map +1 -0
- package/dist/components/menu/menu.d.ts +164 -0
- package/dist/components/menu/menu.js +1106 -0
- package/dist/components/menu/menu.js.map +1 -0
- package/dist/components/popover/popover.d.ts +35 -0
- package/dist/components/popover/popover.js +138 -0
- package/dist/components/popover/popover.js.map +1 -0
- package/dist/components/select/select.d.ts +67 -0
- package/dist/components/select/select.js +397 -0
- package/dist/components/select/select.js.map +1 -0
- package/dist/components/separator/separator.d.ts +2 -0
- package/dist/components/separator/separator.js +15 -0
- package/dist/components/separator/separator.js.map +1 -0
- package/dist/components/tabs/tabs.d.ts +78 -0
- package/dist/components/tabs/tabs.js +341 -0
- package/dist/components/tabs/tabs.js.map +1 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/interactions/keydown/keydown.d.ts +1 -0
- package/dist/interactions/keydown/keydown.js +8 -0
- package/dist/interactions/keydown/keydown.js.map +1 -0
- package/dist/interactions/outside-click/outside-click-mixin.d.ts +2 -0
- package/dist/interactions/outside-click/outside-click-mixin.js +29 -0
- package/dist/interactions/outside-click/outside-click-mixin.js.map +1 -0
- package/dist/interactions/typeahead/typeahead-mixin.d.ts +8 -0
- package/dist/interactions/typeahead/typeahead-mixin.js +59 -0
- package/dist/interactions/typeahead/typeahead-mixin.js.map +1 -0
- package/dist/jsx-runtime.d.ts +2 -0
- package/dist/jsx-runtime.js +3 -0
- package/dist/jsx-runtime.js.map +1 -0
- package/dist/runtime/client-entries.d.ts +91 -0
- package/dist/runtime/client-entries.js +40 -0
- package/dist/runtime/client-entries.js.map +1 -0
- package/dist/runtime/component.d.ts +223 -0
- package/dist/runtime/component.js +152 -0
- package/dist/runtime/component.js.map +1 -0
- package/dist/runtime/create-element.d.ts +10 -0
- package/dist/runtime/create-element.js +29 -0
- package/dist/runtime/create-element.js.map +1 -0
- package/dist/runtime/diff-dom.d.ts +2 -0
- package/dist/runtime/diff-dom.js +364 -0
- package/dist/runtime/diff-dom.js.map +1 -0
- package/dist/runtime/diff-props.d.ts +9 -0
- package/dist/runtime/diff-props.js +195 -0
- package/dist/runtime/diff-props.js.map +1 -0
- package/dist/runtime/document-state.d.ts +11 -0
- package/dist/runtime/document-state.js +106 -0
- package/dist/runtime/document-state.js.map +1 -0
- package/dist/runtime/dom.d.ts +3189 -0
- package/dist/runtime/dom.js +2 -0
- package/dist/runtime/dom.js.map +1 -0
- package/dist/runtime/error-event.d.ts +20 -0
- package/dist/runtime/error-event.js +19 -0
- package/dist/runtime/error-event.js.map +1 -0
- package/dist/runtime/event-listeners.d.ts +50 -0
- package/dist/runtime/event-listeners.js +31 -0
- package/dist/runtime/event-listeners.js.map +1 -0
- package/dist/runtime/frame.d.ts +119 -0
- package/dist/runtime/frame.js +915 -0
- package/dist/runtime/frame.js.map +1 -0
- package/dist/runtime/invariant.d.ts +23 -0
- package/dist/runtime/invariant.js +33 -0
- package/dist/runtime/invariant.js.map +1 -0
- package/dist/runtime/jsx.d.ts +320 -0
- package/dist/runtime/jsx.js +31 -0
- package/dist/runtime/jsx.js.map +1 -0
- package/dist/runtime/mixins/attrs-mixin.d.ts +9 -0
- package/dist/runtime/mixins/attrs-mixin.js +23 -0
- package/dist/runtime/mixins/attrs-mixin.js.map +1 -0
- package/dist/runtime/mixins/link-mixin.d.ts +17 -0
- package/dist/runtime/mixins/link-mixin.js +101 -0
- package/dist/runtime/mixins/link-mixin.js.map +1 -0
- package/dist/runtime/mixins/mixin.d.ts +145 -0
- package/dist/runtime/mixins/mixin.js +570 -0
- package/dist/runtime/mixins/mixin.js.map +1 -0
- package/dist/runtime/mixins/on-mixin.d.ts +16 -0
- package/dist/runtime/mixins/on-mixin.js +49 -0
- package/dist/runtime/mixins/on-mixin.js.map +1 -0
- package/dist/runtime/mixins/ref-mixin.d.ts +9 -0
- package/dist/runtime/mixins/ref-mixin.js +21 -0
- package/dist/runtime/mixins/ref-mixin.js.map +1 -0
- package/dist/runtime/navigation.d.ts +22 -0
- package/dist/runtime/navigation.js +102 -0
- package/dist/runtime/navigation.js.map +1 -0
- package/dist/runtime/reconcile.d.ts +11 -0
- package/dist/runtime/reconcile.js +1240 -0
- package/dist/runtime/reconcile.js.map +1 -0
- package/dist/runtime/render.d.ts +54 -0
- package/dist/runtime/render.js +50 -0
- package/dist/runtime/render.js.map +1 -0
- package/dist/runtime/run.d.ts +45 -0
- package/dist/runtime/run.js +68 -0
- package/dist/runtime/run.js.map +1 -0
- package/dist/runtime/scheduler.d.ts +30 -0
- package/dist/runtime/scheduler.js +185 -0
- package/dist/runtime/scheduler.js.map +1 -0
- package/dist/runtime/svg-attributes.d.ts +5 -0
- package/dist/runtime/svg-attributes.js +124 -0
- package/dist/runtime/svg-attributes.js.map +1 -0
- package/dist/runtime/to-vnode.d.ts +3 -0
- package/dist/runtime/to-vnode.js +43 -0
- package/dist/runtime/to-vnode.js.map +1 -0
- package/dist/runtime/typed-event-target.d.ts +50 -0
- package/dist/runtime/typed-event-target.js +6 -0
- package/dist/runtime/typed-event-target.js.map +1 -0
- package/dist/runtime/vdom.d.ts +55 -0
- package/dist/runtime/vdom.js +198 -0
- package/dist/runtime/vdom.js.map +1 -0
- package/dist/runtime/vnode.d.ts +79 -0
- package/dist/runtime/vnode.js +38 -0
- package/dist/runtime/vnode.js.map +1 -0
- package/dist/server/stream.d.ts +57 -0
- package/dist/server/stream.js +1007 -0
- package/dist/server/stream.js.map +1 -0
- package/dist/style/css-mixin.d.ts +8 -0
- package/dist/style/css-mixin.js +54 -0
- package/dist/style/css-mixin.js.map +1 -0
- package/dist/style/index.d.ts +5 -0
- package/dist/style/index.js +4 -0
- package/dist/style/index.js.map +1 -0
- package/dist/style/style.d.ts +24 -0
- package/dist/style/style.js +269 -0
- package/dist/style/style.js.map +1 -0
- package/dist/style/stylesheet.d.ts +11 -0
- package/dist/style/stylesheet.js +174 -0
- package/dist/style/stylesheet.js.map +1 -0
- package/dist/test.d.ts +2 -0
- package/dist/test.js +2 -0
- package/dist/test.js.map +1 -0
- package/dist/theme/contract.d.ts +259 -0
- package/dist/theme/contract.js +131 -0
- package/dist/theme/contract.js.map +1 -0
- package/dist/theme/glyph-contract.d.ts +13 -0
- package/dist/theme/glyph-contract.js +34 -0
- package/dist/theme/glyph-contract.js.map +1 -0
- package/dist/theme/presets/rmx-01/glyphs.d.ts +2 -0
- package/dist/theme/presets/rmx-01/glyphs.js +252 -0
- package/dist/theme/presets/rmx-01/glyphs.js.map +1 -0
- package/dist/theme/presets/rmx-01/index.d.ts +2 -0
- package/dist/theme/presets/rmx-01/index.js +119 -0
- package/dist/theme/presets/rmx-01/index.js.map +1 -0
- package/dist/theme/runtime.d.ts +2 -0
- package/dist/theme/runtime.js +81 -0
- package/dist/theme/runtime.js.map +1 -0
- package/dist/theme/theme.d.ts +6 -0
- package/dist/theme/theme.js +5 -0
- package/dist/theme/theme.js.map +1 -0
- package/dist/utils/flash-attribute.d.ts +1 -0
- package/dist/utils/flash-attribute.js +11 -0
- package/dist/utils/flash-attribute.js.map +1 -0
- package/dist/utils/scroll-lock.d.ts +3 -0
- package/dist/utils/scroll-lock.js +69 -0
- package/dist/utils/scroll-lock.js.map +1 -0
- package/dist/utils/wait-for-css-transition.d.ts +1 -0
- package/dist/utils/wait-for-css-transition.js +58 -0
- package/dist/utils/wait-for-css-transition.js.map +1 -0
- package/dist/utils/wait.d.ts +1 -0
- package/dist/utils/wait.js +6 -0
- package/dist/utils/wait.js.map +1 -0
- package/package.json +125 -5
- package/src/animation/animate-layout-mixin.ts +266 -0
- package/src/animation/animate-mixins.ts +292 -0
- package/src/animation/index.ts +6 -0
- package/src/animation/spring.ts +299 -0
- package/src/animation/tween.ts +134 -0
- package/src/components/accordion/accordion.tsx +565 -0
- package/src/components/anchor/anchor.ts +904 -0
- package/src/components/breadcrumbs/breadcrumbs.tsx +124 -0
- package/src/components/button/README.md +44 -0
- package/src/components/button/button.tsx +188 -0
- package/src/components/combobox/README.md +145 -0
- package/src/components/combobox/combobox.tsx +1014 -0
- package/src/components/glyph/glyph.tsx +110 -0
- package/src/components/listbox/listbox.ts +447 -0
- package/src/components/menu/hover-aim.ts +428 -0
- package/src/components/menu/menu.tsx +1547 -0
- package/src/components/popover/README.md +122 -0
- package/src/components/popover/popover.ts +201 -0
- package/src/components/select/select.tsx +585 -0
- package/src/components/separator/separator.ts +19 -0
- package/src/components/tabs/README.md +105 -0
- package/src/components/tabs/tabs.tsx +499 -0
- package/src/index.ts +72 -0
- package/src/interactions/keydown/keydown.ts +14 -0
- package/src/interactions/outside-click/outside-click-mixin.ts +55 -0
- package/src/interactions/typeahead/typeahead-mixin.ts +89 -0
- package/src/jsx-runtime.ts +2 -0
- package/src/runtime/client-entries.ts +137 -0
- package/src/runtime/component.ts +402 -0
- package/src/runtime/create-element.ts +38 -0
- package/src/runtime/diff-dom.ts +404 -0
- package/src/runtime/diff-props.ts +209 -0
- package/src/runtime/document-state.ts +130 -0
- package/src/runtime/dom.ts +3971 -0
- package/src/runtime/error-event.ts +26 -0
- package/src/runtime/event-listeners.ts +171 -0
- package/src/runtime/frame.ts +1211 -0
- package/src/runtime/invariant.ts +31 -0
- package/src/runtime/jsx.ts +398 -0
- package/src/runtime/mixins/attrs-mixin.ts +35 -0
- package/src/runtime/mixins/link-mixin.ts +131 -0
- package/src/runtime/mixins/mixin.ts +908 -0
- package/src/runtime/mixins/on-mixin.ts +89 -0
- package/src/runtime/mixins/ref-mixin.ts +32 -0
- package/src/runtime/navigation.ts +136 -0
- package/src/runtime/reconcile.ts +1722 -0
- package/src/runtime/render.ts +101 -0
- package/src/runtime/run.ts +100 -0
- package/src/runtime/scheduler.ts +262 -0
- package/src/runtime/svg-attributes.ts +133 -0
- package/src/runtime/to-vnode.ts +50 -0
- package/src/runtime/typed-event-target.ts +67 -0
- package/src/runtime/vdom.ts +295 -0
- package/src/runtime/vnode.ts +137 -0
- package/src/server/stream.ts +1342 -0
- package/src/style/css-mixin.ts +82 -0
- package/src/style/index.ts +10 -0
- package/src/style/style.ts +312 -0
- package/src/style/stylesheet.ts +209 -0
- package/src/test/setup.ts +7 -0
- package/src/test/utils.ts +45 -0
- package/src/test.ts +2 -0
- package/src/theme/contract.ts +183 -0
- package/src/theme/glyph-contract.ts +57 -0
- package/src/theme/presets/rmx-01/glyphs.tsx +308 -0
- package/src/theme/presets/rmx-01/index.ts +121 -0
- package/src/theme/runtime.ts +116 -0
- package/src/theme/theme.ts +15 -0
- package/src/utils/flash-attribute.ts +11 -0
- package/src/utils/scroll-lock.ts +97 -0
- package/src/utils/wait-for-css-transition.ts +66 -0
- package/src/utils/wait.ts +5 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { RemixNode } from './jsx.ts'
|
|
2
|
+
import { createRoot, type VirtualRoot, type VirtualRootOptions } from './vdom.ts'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Options for {@link render}.
|
|
6
|
+
*/
|
|
7
|
+
export interface RenderOptions extends VirtualRootOptions {
|
|
8
|
+
/**
|
|
9
|
+
* The element to mount the component into. Defaults to a fresh `div` appended to
|
|
10
|
+
* `document.body`.
|
|
11
|
+
*/
|
|
12
|
+
container?: HTMLElement
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Result returned by {@link render}.
|
|
17
|
+
*/
|
|
18
|
+
export interface RenderResult {
|
|
19
|
+
/**
|
|
20
|
+
* The element the component is mounted into.
|
|
21
|
+
*/
|
|
22
|
+
container: HTMLElement
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The {@link VirtualRoot} the component is rendered in. Use it to access the
|
|
26
|
+
* underlying scheduler or dispatch lifecycle events.
|
|
27
|
+
*/
|
|
28
|
+
root: VirtualRoot
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Shorthand for `container.querySelector<HTMLElement>(selector)`.
|
|
32
|
+
*/
|
|
33
|
+
$: (selector: string) => HTMLElement | null
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Shorthand for `container.querySelectorAll<HTMLElement>(selector)`.
|
|
37
|
+
*/
|
|
38
|
+
$$: (selector: string) => NodeListOf<HTMLElement>
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Runs `fn` and then flushes any pending component updates so the DOM reflects them
|
|
42
|
+
* before the next assertion.
|
|
43
|
+
*/
|
|
44
|
+
act: (fn: () => unknown | Promise<unknown>) => Promise<void>
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Disposes the root and removes the container from the DOM. Pass to `t.after()` for
|
|
48
|
+
* automatic cleanup at the end of a test.
|
|
49
|
+
*/
|
|
50
|
+
cleanup: () => void
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Mounts a {@link RemixNode} into a DOM container for testing.
|
|
55
|
+
*
|
|
56
|
+
* @param node - The node to render
|
|
57
|
+
* @param opts - {@link RenderOptions}; pass `opts.container` to render into a specific
|
|
58
|
+
* element instead of a fresh `div` appended to `document.body`
|
|
59
|
+
* @returns A {@link RenderResult} with the container, root, and helpers for querying and
|
|
60
|
+
* interacting with the rendered output.
|
|
61
|
+
*/
|
|
62
|
+
export function render(node: RemixNode, opts: RenderOptions = {}): RenderResult {
|
|
63
|
+
let { container: userContainer, ...virtualRootOpts } = opts
|
|
64
|
+
|
|
65
|
+
let container: HTMLElement | undefined
|
|
66
|
+
if (userContainer) {
|
|
67
|
+
container = userContainer
|
|
68
|
+
} else {
|
|
69
|
+
container = document.createElement('div')
|
|
70
|
+
document.body.appendChild(container)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
let root: VirtualRoot | undefined = createRoot(container, virtualRootOpts)
|
|
74
|
+
root.render(node)
|
|
75
|
+
root.flush()
|
|
76
|
+
|
|
77
|
+
let ctx: RenderResult = {
|
|
78
|
+
get container() {
|
|
79
|
+
if (!container) throw new Error('Test container has already been cleaned up')
|
|
80
|
+
return container
|
|
81
|
+
},
|
|
82
|
+
get root() {
|
|
83
|
+
if (!root) throw new Error('Test root has already been cleaned up')
|
|
84
|
+
return root
|
|
85
|
+
},
|
|
86
|
+
$: (s: string) => ctx.container.querySelector<HTMLElement>(s),
|
|
87
|
+
$$: (s: string) => ctx.container.querySelectorAll<HTMLElement>(s),
|
|
88
|
+
async act(fn: () => unknown | Promise<unknown>) {
|
|
89
|
+
await fn()
|
|
90
|
+
ctx.root.flush()
|
|
91
|
+
},
|
|
92
|
+
cleanup() {
|
|
93
|
+
root?.dispose()
|
|
94
|
+
container?.remove()
|
|
95
|
+
container = undefined
|
|
96
|
+
root = undefined
|
|
97
|
+
},
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return ctx
|
|
101
|
+
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { createFrame, type Frame } from './frame.ts'
|
|
2
|
+
import { createScheduler } from './vdom.ts'
|
|
3
|
+
import { createStyleManager } from '../style/index.ts'
|
|
4
|
+
import type { FrameHandle } from './component.ts'
|
|
5
|
+
import { createComponentErrorEvent } from './error-event.ts'
|
|
6
|
+
import type { ComponentErrorEvent } from './error-event.ts'
|
|
7
|
+
import type { LoadModule, ResolveFrame } from './frame.ts'
|
|
8
|
+
import { startNavigationListener } from './navigation.ts'
|
|
9
|
+
import { TypedEventTarget } from './typed-event-target.ts'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Options for starting the client runtime with {@link run}.
|
|
13
|
+
*/
|
|
14
|
+
export type RunInit = {
|
|
15
|
+
loadModule: LoadModule
|
|
16
|
+
resolveFrame?: ResolveFrame
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Events emitted by the application runtime.
|
|
21
|
+
*/
|
|
22
|
+
export type AppRuntimeEventMap = {
|
|
23
|
+
error: ComponentErrorEvent
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Client runtime returned by {@link run}.
|
|
28
|
+
*/
|
|
29
|
+
export type AppRuntime = TypedEventTarget<AppRuntimeEventMap> & {
|
|
30
|
+
ready(): Promise<void>
|
|
31
|
+
flush(): void
|
|
32
|
+
dispose(): void
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
let topFrame: Frame
|
|
36
|
+
/**
|
|
37
|
+
* Returns the top-level frame handle for the running application.
|
|
38
|
+
*
|
|
39
|
+
* @returns The top-level frame handle.
|
|
40
|
+
*/
|
|
41
|
+
export function getTopFrame(): FrameHandle {
|
|
42
|
+
if (!topFrame) throw new Error('app runtime not initialized')
|
|
43
|
+
return topFrame.handle
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const namedFrames = new Map<string, FrameHandle>()
|
|
47
|
+
/**
|
|
48
|
+
* Returns a named frame handle, falling back to the top frame when not found.
|
|
49
|
+
*
|
|
50
|
+
* @param name Name of the frame to look up.
|
|
51
|
+
* @returns The matching frame handle or the top frame.
|
|
52
|
+
*/
|
|
53
|
+
export function getNamedFrame(name: string): FrameHandle {
|
|
54
|
+
return namedFrames.get(name) ?? getTopFrame()
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Starts the client-side Remix component runtime for the current document.
|
|
59
|
+
*
|
|
60
|
+
* @param init Runtime hooks for loading modules and resolving frames.
|
|
61
|
+
* @returns The running application runtime.
|
|
62
|
+
*/
|
|
63
|
+
export function run(init: RunInit): AppRuntime {
|
|
64
|
+
let styleManager = createStyleManager()
|
|
65
|
+
let errorTarget = new TypedEventTarget<AppRuntimeEventMap>()
|
|
66
|
+
let scheduler = createScheduler(document, errorTarget, styleManager)
|
|
67
|
+
|
|
68
|
+
let resolveFrame: ResolveFrame = init.resolveFrame ?? (() => '<p>resolve frame unimplemented</p>')
|
|
69
|
+
|
|
70
|
+
topFrame = createFrame(document, {
|
|
71
|
+
src: document.location.href,
|
|
72
|
+
errorTarget,
|
|
73
|
+
loadModule: init.loadModule,
|
|
74
|
+
resolveFrame,
|
|
75
|
+
pendingClientEntries: new Map(),
|
|
76
|
+
scheduler,
|
|
77
|
+
styleManager,
|
|
78
|
+
data: {},
|
|
79
|
+
moduleCache: new Map(),
|
|
80
|
+
moduleLoads: new Map(),
|
|
81
|
+
frameInstances: new WeakMap(),
|
|
82
|
+
namedFrames,
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
let appController = new AbortController()
|
|
86
|
+
startNavigationListener(appController.signal)
|
|
87
|
+
let readyPromise = topFrame.ready().catch((error) => {
|
|
88
|
+
errorTarget.dispatchEvent(createComponentErrorEvent(error))
|
|
89
|
+
throw error
|
|
90
|
+
})
|
|
91
|
+
|
|
92
|
+
return Object.assign(errorTarget, {
|
|
93
|
+
ready: () => readyPromise,
|
|
94
|
+
flush: () => topFrame.flush(),
|
|
95
|
+
dispose: () => {
|
|
96
|
+
appController.abort()
|
|
97
|
+
topFrame.dispose()
|
|
98
|
+
},
|
|
99
|
+
})
|
|
100
|
+
}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { createDocumentState } from './document-state.ts'
|
|
2
|
+
import { createComponentErrorEvent } from './error-event.ts'
|
|
3
|
+
import type { CommittedComponentNode, VNode } from './vnode.ts'
|
|
4
|
+
import { isCommittedComponentNode } from './vnode.ts'
|
|
5
|
+
import {
|
|
6
|
+
findNextSiblingDomAnchor,
|
|
7
|
+
renderComponent,
|
|
8
|
+
setActiveSchedulerUpdateParents,
|
|
9
|
+
} from './reconcile.ts'
|
|
10
|
+
import { defaultStyleManager } from './diff-props.ts'
|
|
11
|
+
import type { StyleManager } from '../style/index.ts'
|
|
12
|
+
|
|
13
|
+
type EmptyFn = () => void
|
|
14
|
+
type SchedulerPhaseType = 'beforeUpdate' | 'commit'
|
|
15
|
+
type SchedulerPhaseListener = EventListenerOrEventListenerObject | null
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Scheduler API used by the reconciler and frame runtime.
|
|
19
|
+
*/
|
|
20
|
+
export type Scheduler = ReturnType<typeof createScheduler>
|
|
21
|
+
|
|
22
|
+
// Protect against infinite cascading updates (e.g. handle.update() during render)
|
|
23
|
+
const MAX_CASCADING_UPDATES = 50
|
|
24
|
+
|
|
25
|
+
export type SchedulerPhaseEvent = Event & {
|
|
26
|
+
parents: ParentNode[]
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Creates the DOM update scheduler used by the component runtime.
|
|
31
|
+
*
|
|
32
|
+
* @param doc Document associated with the rendered tree.
|
|
33
|
+
* @param rootTarget Event target that receives runtime errors.
|
|
34
|
+
* @param styles Style manager used during reconciliation.
|
|
35
|
+
* @returns A scheduler instance.
|
|
36
|
+
*/
|
|
37
|
+
export function createScheduler(
|
|
38
|
+
doc: Document,
|
|
39
|
+
rootTarget: EventTarget,
|
|
40
|
+
styles: StyleManager = defaultStyleManager,
|
|
41
|
+
) {
|
|
42
|
+
let documentState = createDocumentState(doc)
|
|
43
|
+
let scheduled = new Map<CommittedComponentNode, ParentNode>()
|
|
44
|
+
let workTasks: EmptyFn[] = []
|
|
45
|
+
let commitPhaseTasks: EmptyFn[] = []
|
|
46
|
+
let postCommitTasks: EmptyFn[] = []
|
|
47
|
+
let flushScheduled = false
|
|
48
|
+
let flushing = false
|
|
49
|
+
let cascadingUpdateCount = 0
|
|
50
|
+
let resetScheduled = false
|
|
51
|
+
let phaseEvents = new EventTarget()
|
|
52
|
+
let scheduler: {
|
|
53
|
+
enqueue(vnode: CommittedComponentNode, domParent: ParentNode): void
|
|
54
|
+
enqueueWork(newTasks: EmptyFn[]): void
|
|
55
|
+
enqueueCommitPhase(newTasks: EmptyFn[]): void
|
|
56
|
+
enqueueTasks(newTasks: EmptyFn[]): void
|
|
57
|
+
addEventListener(
|
|
58
|
+
type: SchedulerPhaseType,
|
|
59
|
+
listener: SchedulerPhaseListener,
|
|
60
|
+
options?: AddEventListenerOptions | boolean,
|
|
61
|
+
): void
|
|
62
|
+
removeEventListener(
|
|
63
|
+
type: SchedulerPhaseType,
|
|
64
|
+
listener: SchedulerPhaseListener,
|
|
65
|
+
options?: EventListenerOptions | boolean,
|
|
66
|
+
): void
|
|
67
|
+
dequeue(): void
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function dispatchError(error: unknown) {
|
|
71
|
+
console.error(error)
|
|
72
|
+
rootTarget.dispatchEvent(createComponentErrorEvent(error))
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function scheduleCounterReset() {
|
|
76
|
+
if (resetScheduled) return
|
|
77
|
+
resetScheduled = true
|
|
78
|
+
// Reset when control returns to the event loop while still allowing
|
|
79
|
+
// microtask-driven flushes in the same turn to count as cascading.
|
|
80
|
+
setTimeout(() => {
|
|
81
|
+
cascadingUpdateCount = 0
|
|
82
|
+
resetScheduled = false
|
|
83
|
+
}, 0)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function getFrameStyleManager(vnode: CommittedComponentNode): StyleManager {
|
|
87
|
+
let runtime = vnode._handle?.frame.$runtime as { styleManager?: StyleManager } | undefined
|
|
88
|
+
return runtime?.styleManager ?? styles
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function flush() {
|
|
92
|
+
if (flushing) return
|
|
93
|
+
flushing = true
|
|
94
|
+
try {
|
|
95
|
+
while (true) {
|
|
96
|
+
flushScheduled = false
|
|
97
|
+
|
|
98
|
+
let batch = new Map(scheduled)
|
|
99
|
+
scheduled.clear()
|
|
100
|
+
|
|
101
|
+
let hasWork =
|
|
102
|
+
batch.size > 0 ||
|
|
103
|
+
workTasks.length > 0 ||
|
|
104
|
+
commitPhaseTasks.length > 0 ||
|
|
105
|
+
postCommitTasks.length > 0
|
|
106
|
+
if (!hasWork) return
|
|
107
|
+
|
|
108
|
+
cascadingUpdateCount++
|
|
109
|
+
scheduleCounterReset()
|
|
110
|
+
|
|
111
|
+
if (cascadingUpdateCount > MAX_CASCADING_UPDATES) {
|
|
112
|
+
let error = new Error('handle.update() infinite loop detected')
|
|
113
|
+
dispatchError(error)
|
|
114
|
+
return
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
documentState.capture()
|
|
118
|
+
|
|
119
|
+
let updateParents = batch.size > 0 ? Array.from(new Set(batch.values())) : []
|
|
120
|
+
setActiveSchedulerUpdateParents(updateParents)
|
|
121
|
+
dispatchPhaseEvent('beforeUpdate', updateParents)
|
|
122
|
+
|
|
123
|
+
if (batch.size > 0) {
|
|
124
|
+
let vnodes = Array.from(batch)
|
|
125
|
+
let noScheduledAncestor = new Set<VNode>()
|
|
126
|
+
|
|
127
|
+
for (let [vnode, domParent] of vnodes) {
|
|
128
|
+
if (ancestorIsScheduled(vnode, batch, noScheduledAncestor)) continue
|
|
129
|
+
let handle = vnode._handle
|
|
130
|
+
let curr = vnode._content
|
|
131
|
+
let vParent = vnode._parent!
|
|
132
|
+
// Calculate anchor at render time from current vdom position (never stale).
|
|
133
|
+
// Needed for fragment self-updates that add children - without this, new children
|
|
134
|
+
// would be appended after siblings. The keyed diff has placement logic, but unkeyed
|
|
135
|
+
// diff relies on anchor for correct positioning.
|
|
136
|
+
let anchor = findNextSiblingDomAnchor(vnode, vParent) || undefined
|
|
137
|
+
try {
|
|
138
|
+
let updateStyles = getFrameStyleManager(vnode)
|
|
139
|
+
renderComponent(
|
|
140
|
+
handle,
|
|
141
|
+
curr,
|
|
142
|
+
vnode,
|
|
143
|
+
domParent,
|
|
144
|
+
handle.frame,
|
|
145
|
+
scheduler,
|
|
146
|
+
updateStyles,
|
|
147
|
+
rootTarget,
|
|
148
|
+
vParent,
|
|
149
|
+
anchor,
|
|
150
|
+
)
|
|
151
|
+
} catch (error) {
|
|
152
|
+
dispatchError(error)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
flushTaskQueue(workTasks)
|
|
158
|
+
setActiveSchedulerUpdateParents(undefined)
|
|
159
|
+
|
|
160
|
+
// Restore selection before commit-phase lifecycle work so mixins see
|
|
161
|
+
// the final DOM state but still run before commit listeners and user tasks.
|
|
162
|
+
documentState.restore()
|
|
163
|
+
|
|
164
|
+
flushTaskQueue(commitPhaseTasks)
|
|
165
|
+
dispatchPhaseEvent('commit', updateParents)
|
|
166
|
+
flushTaskQueue(postCommitTasks)
|
|
167
|
+
}
|
|
168
|
+
} finally {
|
|
169
|
+
setActiveSchedulerUpdateParents(undefined)
|
|
170
|
+
flushing = false
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
function dispatchPhaseEvent(type: SchedulerPhaseType, parents: ParentNode[]) {
|
|
175
|
+
let event = new Event(type) as SchedulerPhaseEvent
|
|
176
|
+
event.parents = parents
|
|
177
|
+
phaseEvents.dispatchEvent(event)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
function flushTaskQueue(queue: EmptyFn[]) {
|
|
181
|
+
while (queue.length > 0) {
|
|
182
|
+
let task = queue.shift()
|
|
183
|
+
if (!task) continue
|
|
184
|
+
try {
|
|
185
|
+
task()
|
|
186
|
+
} catch (error) {
|
|
187
|
+
dispatchError(error)
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
function scheduleFlush() {
|
|
193
|
+
if (flushScheduled || flushing) return
|
|
194
|
+
flushScheduled = true
|
|
195
|
+
queueMicrotask(flush)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function ancestorIsScheduled(
|
|
199
|
+
vnode: VNode,
|
|
200
|
+
batch: Map<CommittedComponentNode, ParentNode>,
|
|
201
|
+
safe: Set<VNode>,
|
|
202
|
+
): boolean {
|
|
203
|
+
let path: VNode[] = []
|
|
204
|
+
let current = vnode._parent
|
|
205
|
+
|
|
206
|
+
while (current) {
|
|
207
|
+
// Already verified this node has no scheduled ancestor above it
|
|
208
|
+
if (safe.has(current)) {
|
|
209
|
+
for (let node of path) safe.add(node)
|
|
210
|
+
return false
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
path.push(current)
|
|
214
|
+
|
|
215
|
+
if (isCommittedComponentNode(current) && batch.has(current)) {
|
|
216
|
+
return true
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
current = current._parent
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
// Reached root - mark entire path as safe for future lookups
|
|
223
|
+
for (let node of path) safe.add(node)
|
|
224
|
+
return false
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
scheduler = {
|
|
228
|
+
enqueue(vnode: CommittedComponentNode, domParent: ParentNode): void {
|
|
229
|
+
scheduled.set(vnode, domParent)
|
|
230
|
+
scheduleFlush()
|
|
231
|
+
},
|
|
232
|
+
|
|
233
|
+
enqueueWork(newTasks: EmptyFn[]): void {
|
|
234
|
+
workTasks.push(...newTasks)
|
|
235
|
+
scheduleFlush()
|
|
236
|
+
},
|
|
237
|
+
|
|
238
|
+
enqueueCommitPhase(newTasks: EmptyFn[]): void {
|
|
239
|
+
commitPhaseTasks.push(...newTasks)
|
|
240
|
+
scheduleFlush()
|
|
241
|
+
},
|
|
242
|
+
|
|
243
|
+
enqueueTasks(newTasks: EmptyFn[]): void {
|
|
244
|
+
postCommitTasks.push(...newTasks)
|
|
245
|
+
scheduleFlush()
|
|
246
|
+
},
|
|
247
|
+
|
|
248
|
+
addEventListener(type, listener, options) {
|
|
249
|
+
phaseEvents.addEventListener(type, listener, options)
|
|
250
|
+
},
|
|
251
|
+
|
|
252
|
+
removeEventListener(type, listener, options) {
|
|
253
|
+
phaseEvents.removeEventListener(type, listener, options)
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
dequeue() {
|
|
257
|
+
flush()
|
|
258
|
+
},
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return scheduler
|
|
262
|
+
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
const XLINK_NS = 'http://www.w3.org/1999/xlink'
|
|
2
|
+
const XML_NS = 'http://www.w3.org/XML/1998/namespace'
|
|
3
|
+
|
|
4
|
+
const CANONICAL_CAMEL_SVG_ATTRS = new Set([
|
|
5
|
+
'accentHeight',
|
|
6
|
+
'attributeName',
|
|
7
|
+
'attributeType',
|
|
8
|
+
'baseFrequency',
|
|
9
|
+
'baseProfile',
|
|
10
|
+
'calcMode',
|
|
11
|
+
'viewBox',
|
|
12
|
+
'preserveAspectRatio',
|
|
13
|
+
'externalResourcesRequired',
|
|
14
|
+
'filterRes',
|
|
15
|
+
'gradientUnits',
|
|
16
|
+
'gradientTransform',
|
|
17
|
+
'glyphRef',
|
|
18
|
+
'kernelMatrix',
|
|
19
|
+
'kernelUnitLength',
|
|
20
|
+
'keyPoints',
|
|
21
|
+
'keySplines',
|
|
22
|
+
'keyTimes',
|
|
23
|
+
'lengthAdjust',
|
|
24
|
+
'limitingConeAngle',
|
|
25
|
+
'markerHeight',
|
|
26
|
+
'patternUnits',
|
|
27
|
+
'patternContentUnits',
|
|
28
|
+
'patternTransform',
|
|
29
|
+
'markerWidth',
|
|
30
|
+
'numOctaves',
|
|
31
|
+
'pathLength',
|
|
32
|
+
'pointsAtX',
|
|
33
|
+
'pointsAtY',
|
|
34
|
+
'pointsAtZ',
|
|
35
|
+
'preserveAlpha',
|
|
36
|
+
'clipPathUnits',
|
|
37
|
+
'maskUnits',
|
|
38
|
+
'maskContentUnits',
|
|
39
|
+
'filterUnits',
|
|
40
|
+
'primitiveUnits',
|
|
41
|
+
'refX',
|
|
42
|
+
'refY',
|
|
43
|
+
'requiredExtensions',
|
|
44
|
+
'requiredFeatures',
|
|
45
|
+
'specularConstant',
|
|
46
|
+
'specularExponent',
|
|
47
|
+
'spreadMethod',
|
|
48
|
+
'startOffset',
|
|
49
|
+
'stdDeviation',
|
|
50
|
+
'stitchTiles',
|
|
51
|
+
'surfaceScale',
|
|
52
|
+
'systemLanguage',
|
|
53
|
+
'tableValues',
|
|
54
|
+
'targetX',
|
|
55
|
+
'targetY',
|
|
56
|
+
'textLength',
|
|
57
|
+
'viewTarget',
|
|
58
|
+
'xChannelSelector',
|
|
59
|
+
'yChannelSelector',
|
|
60
|
+
'zoomAndPan',
|
|
61
|
+
'edgeMode',
|
|
62
|
+
'diffuseConstant',
|
|
63
|
+
'markerUnits',
|
|
64
|
+
])
|
|
65
|
+
|
|
66
|
+
const SVG_ATTR_ALIASES = new Map<string, string>()
|
|
67
|
+
for (let attr of CANONICAL_CAMEL_SVG_ATTRS) {
|
|
68
|
+
SVG_ATTR_ALIASES.set(camelToKebab(attr), attr)
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const NAMESPACED_SVG_ALIASES = new Map([
|
|
72
|
+
['xlinkHref', { ns: XLINK_NS, attr: 'xlink:href' }],
|
|
73
|
+
['xlink:href', { ns: XLINK_NS, attr: 'xlink:href' }],
|
|
74
|
+
['xlink-href', { ns: XLINK_NS, attr: 'xlink:href' }],
|
|
75
|
+
['xlinkActuate', { ns: XLINK_NS, attr: 'xlink:actuate' }],
|
|
76
|
+
['xlink:actuate', { ns: XLINK_NS, attr: 'xlink:actuate' }],
|
|
77
|
+
['xlink-actuate', { ns: XLINK_NS, attr: 'xlink:actuate' }],
|
|
78
|
+
['xlinkArcrole', { ns: XLINK_NS, attr: 'xlink:arcrole' }],
|
|
79
|
+
['xlink:arcrole', { ns: XLINK_NS, attr: 'xlink:arcrole' }],
|
|
80
|
+
['xlink-arcrole', { ns: XLINK_NS, attr: 'xlink:arcrole' }],
|
|
81
|
+
['xlinkRole', { ns: XLINK_NS, attr: 'xlink:role' }],
|
|
82
|
+
['xlink:role', { ns: XLINK_NS, attr: 'xlink:role' }],
|
|
83
|
+
['xlink-role', { ns: XLINK_NS, attr: 'xlink:role' }],
|
|
84
|
+
['xlinkShow', { ns: XLINK_NS, attr: 'xlink:show' }],
|
|
85
|
+
['xlink:show', { ns: XLINK_NS, attr: 'xlink:show' }],
|
|
86
|
+
['xlink-show', { ns: XLINK_NS, attr: 'xlink:show' }],
|
|
87
|
+
['xlinkTitle', { ns: XLINK_NS, attr: 'xlink:title' }],
|
|
88
|
+
['xlink:title', { ns: XLINK_NS, attr: 'xlink:title' }],
|
|
89
|
+
['xlink-title', { ns: XLINK_NS, attr: 'xlink:title' }],
|
|
90
|
+
['xlinkType', { ns: XLINK_NS, attr: 'xlink:type' }],
|
|
91
|
+
['xlink:type', { ns: XLINK_NS, attr: 'xlink:type' }],
|
|
92
|
+
['xlink-type', { ns: XLINK_NS, attr: 'xlink:type' }],
|
|
93
|
+
['xmlBase', { ns: XML_NS, attr: 'xml:base' }],
|
|
94
|
+
['xml:base', { ns: XML_NS, attr: 'xml:base' }],
|
|
95
|
+
['xml-base', { ns: XML_NS, attr: 'xml:base' }],
|
|
96
|
+
['xmlLang', { ns: XML_NS, attr: 'xml:lang' }],
|
|
97
|
+
['xml:lang', { ns: XML_NS, attr: 'xml:lang' }],
|
|
98
|
+
['xml-lang', { ns: XML_NS, attr: 'xml:lang' }],
|
|
99
|
+
['xmlSpace', { ns: XML_NS, attr: 'xml:space' }],
|
|
100
|
+
['xml:space', { ns: XML_NS, attr: 'xml:space' }],
|
|
101
|
+
['xml-space', { ns: XML_NS, attr: 'xml:space' }],
|
|
102
|
+
['xmlnsXlink', { attr: 'xmlns:xlink' }],
|
|
103
|
+
['xmlns:xlink', { attr: 'xmlns:xlink' }],
|
|
104
|
+
['xmlns-xlink', { attr: 'xmlns:xlink' }],
|
|
105
|
+
])
|
|
106
|
+
|
|
107
|
+
export function normalizeSvgAttributeName(name: string): string {
|
|
108
|
+
let alias = SVG_ATTR_ALIASES.get(name)
|
|
109
|
+
if (alias) return alias
|
|
110
|
+
|
|
111
|
+
if (CANONICAL_CAMEL_SVG_ATTRS.has(name)) return name
|
|
112
|
+
|
|
113
|
+
return camelToKebab(name)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function normalizeSvgAttribute(name: string): {
|
|
117
|
+
ns?: string
|
|
118
|
+
attr: string
|
|
119
|
+
} {
|
|
120
|
+
let namespaced = NAMESPACED_SVG_ALIASES.get(name)
|
|
121
|
+
if (namespaced) {
|
|
122
|
+
return namespaced
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return { attr: normalizeSvgAttributeName(name) }
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function camelToKebab(input: string): string {
|
|
129
|
+
return input
|
|
130
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1-$2')
|
|
131
|
+
.replace(/_/g, '-')
|
|
132
|
+
.toLowerCase()
|
|
133
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Fragment } from './component.ts'
|
|
2
|
+
import { invariant } from './invariant.ts'
|
|
3
|
+
import type { RemixElement, RemixNode } from './jsx.ts'
|
|
4
|
+
import { isRemixElement, TEXT_NODE, type VNode } from './vnode.ts'
|
|
5
|
+
|
|
6
|
+
function flatMapChildrenToVNodes(node: RemixElement): VNode[] {
|
|
7
|
+
return 'children' in node.props
|
|
8
|
+
? Array.isArray(node.props.children)
|
|
9
|
+
? node.props.children.flat(Infinity).map(toVNode)
|
|
10
|
+
: [toVNode(node.props.children)]
|
|
11
|
+
: []
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function flattenRemixNodeArray(nodes: RemixNode[], out: RemixNode[] = []): RemixNode[] {
|
|
15
|
+
for (let child of nodes) {
|
|
16
|
+
if (Array.isArray(child)) {
|
|
17
|
+
flattenRemixNodeArray(child, out)
|
|
18
|
+
} else {
|
|
19
|
+
out.push(child)
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return out
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function toVNode(node: RemixNode): VNode {
|
|
26
|
+
if (node === null || node === undefined || typeof node === 'boolean') {
|
|
27
|
+
return { type: TEXT_NODE, _text: '' }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (typeof node === 'string' || typeof node === 'number' || typeof node === 'bigint') {
|
|
31
|
+
return { type: TEXT_NODE, _text: String(node) }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (Array.isArray(node)) {
|
|
35
|
+
let flatChildren = flattenRemixNodeArray(node)
|
|
36
|
+
return { type: Fragment, _children: flatChildren.map(toVNode) }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (node.type === Fragment) {
|
|
40
|
+
return { type: Fragment, key: node.key, _children: flatMapChildrenToVNodes(node) }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (isRemixElement(node)) {
|
|
44
|
+
// When innerHTML is set, ignore children
|
|
45
|
+
let children = node.props.innerHTML != null ? [] : flatMapChildrenToVNodes(node)
|
|
46
|
+
return { type: node.type, key: node.key, props: node.props, _children: children }
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
invariant(false, 'Unexpected RemixNode')
|
|
50
|
+
}
|