@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,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An `EventTarget` subclass with typed event maps.
|
|
3
|
+
*/
|
|
4
|
+
export class TypedEventTarget<eventMap> extends EventTarget {
|
|
5
|
+
/**
|
|
6
|
+
* Phantom property that carries the event map type on instances.
|
|
7
|
+
*/
|
|
8
|
+
declare readonly __eventMap?: eventMap
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Interface surface for {@link TypedEventTarget} with typed listener overloads.
|
|
13
|
+
*/
|
|
14
|
+
export interface TypedEventTarget<eventMap> {
|
|
15
|
+
/**
|
|
16
|
+
* Adds a listener for a typed event name from the event map.
|
|
17
|
+
*
|
|
18
|
+
* @param type Event name to listen for.
|
|
19
|
+
* @param listener Listener to invoke when the event fires.
|
|
20
|
+
* @param options Listener registration options.
|
|
21
|
+
*/
|
|
22
|
+
addEventListener<type extends Extract<keyof eventMap, string>>(
|
|
23
|
+
type: type,
|
|
24
|
+
listener: TypedEventListener<eventMap>[type],
|
|
25
|
+
options?: AddEventListenerOptions,
|
|
26
|
+
): void
|
|
27
|
+
/**
|
|
28
|
+
* Adds a listener using the standard untyped `EventTarget` signature.
|
|
29
|
+
*
|
|
30
|
+
* @param type Event name to listen for.
|
|
31
|
+
* @param listener Listener to invoke when the event fires.
|
|
32
|
+
* @param options Listener registration options.
|
|
33
|
+
*/
|
|
34
|
+
addEventListener(
|
|
35
|
+
type: string,
|
|
36
|
+
listener: EventListenerOrEventListenerObject | null,
|
|
37
|
+
options?: boolean | AddEventListenerOptions,
|
|
38
|
+
): void
|
|
39
|
+
/**
|
|
40
|
+
* Removes a listener for a typed event name from the event map.
|
|
41
|
+
*
|
|
42
|
+
* @param type Event name to stop listening for.
|
|
43
|
+
* @param listener Previously registered listener.
|
|
44
|
+
* @param options Listener removal options.
|
|
45
|
+
*/
|
|
46
|
+
removeEventListener<type extends Extract<keyof eventMap, string>>(
|
|
47
|
+
type: type,
|
|
48
|
+
listener: TypedEventListener<eventMap>[type],
|
|
49
|
+
options?: EventListenerOptions,
|
|
50
|
+
): void
|
|
51
|
+
/**
|
|
52
|
+
* Removes a listener using the standard untyped `EventTarget` signature.
|
|
53
|
+
*
|
|
54
|
+
* @param type Event name to stop listening for.
|
|
55
|
+
* @param listener Previously registered listener.
|
|
56
|
+
* @param options Listener removal options.
|
|
57
|
+
*/
|
|
58
|
+
removeEventListener(
|
|
59
|
+
type: string,
|
|
60
|
+
listener: EventListenerOrEventListenerObject | null,
|
|
61
|
+
options?: EventListenerOptions,
|
|
62
|
+
): void
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
type TypedEventListener<eventMap> = {
|
|
66
|
+
[key in keyof eventMap]: (event: eventMap[key]) => void
|
|
67
|
+
}
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import type { FrameContent, FrameHandle } from './component.ts'
|
|
2
|
+
import { createFrameHandle } from './component.ts'
|
|
3
|
+
import { invariant } from './invariant.ts'
|
|
4
|
+
import type { RemixNode } from './jsx.ts'
|
|
5
|
+
import {
|
|
6
|
+
createComponentErrorEvent,
|
|
7
|
+
getComponentError,
|
|
8
|
+
type ComponentErrorEvent,
|
|
9
|
+
} from './error-event.ts'
|
|
10
|
+
import { createScheduler, type Scheduler } from './scheduler.ts'
|
|
11
|
+
import { diffVNodes, remove as removeVNode } from './reconcile.ts'
|
|
12
|
+
import { toVNode } from './to-vnode.ts'
|
|
13
|
+
import { TypedEventTarget } from './typed-event-target.ts'
|
|
14
|
+
import { ROOT_VNODE, type VNode } from './vnode.ts'
|
|
15
|
+
import { resetStyleState, defaultStyleManager } from './diff-props.ts'
|
|
16
|
+
import type { StyleManager } from '../style/index.ts'
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Events emitted by virtual roots.
|
|
20
|
+
*/
|
|
21
|
+
export type VirtualRootEventMap = {
|
|
22
|
+
error: ComponentErrorEvent
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Root controller returned by {@link createRoot} and {@link createRangeRoot}.
|
|
27
|
+
*/
|
|
28
|
+
export type VirtualRoot = TypedEventTarget<VirtualRootEventMap> & {
|
|
29
|
+
render: (element: RemixNode) => void
|
|
30
|
+
dispose: () => void
|
|
31
|
+
flush: () => void
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Options for creating a virtual DOM root with {@link createRoot} or {@link createRangeRoot}.
|
|
36
|
+
*/
|
|
37
|
+
export type VirtualRootOptions = {
|
|
38
|
+
frame?: FrameHandle
|
|
39
|
+
scheduler?: Scheduler
|
|
40
|
+
styleManager?: StyleManager
|
|
41
|
+
frameInit?: {
|
|
42
|
+
src?: string
|
|
43
|
+
resolveFrame: (
|
|
44
|
+
src: string,
|
|
45
|
+
signal?: AbortSignal,
|
|
46
|
+
target?: string,
|
|
47
|
+
) => Promise<FrameContent> | FrameContent
|
|
48
|
+
loadModule?: (moduleUrl: string, exportName: string) => Promise<Function> | Function
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export { createScheduler, type Scheduler }
|
|
53
|
+
export { diffVNodes, toVNode }
|
|
54
|
+
export { resetStyleState }
|
|
55
|
+
|
|
56
|
+
function getHydrationComponentIdFromRangeStart(start: Node): string | undefined {
|
|
57
|
+
if (!(start instanceof Comment)) return undefined
|
|
58
|
+
let marker = start.data.trim()
|
|
59
|
+
if (!marker.startsWith('rmx:h:')) return undefined
|
|
60
|
+
let id = marker.slice('rmx:h:'.length)
|
|
61
|
+
return id.length > 0 ? id : undefined
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Creates a virtual root bounded by two DOM nodes.
|
|
66
|
+
*
|
|
67
|
+
* @param boundaries Start and end marker nodes that define the render region.
|
|
68
|
+
* @param options Root configuration.
|
|
69
|
+
* @returns A virtual root controller.
|
|
70
|
+
*/
|
|
71
|
+
export function createRangeRoot(
|
|
72
|
+
boundaries: [Node, Node],
|
|
73
|
+
options: VirtualRootOptions = {},
|
|
74
|
+
): VirtualRoot {
|
|
75
|
+
let [start, end] = boundaries
|
|
76
|
+
let vroot: VNode | null = null
|
|
77
|
+
let styles = options.styleManager ?? defaultStyleManager
|
|
78
|
+
|
|
79
|
+
let container = end.parentNode
|
|
80
|
+
invariant(container, 'Expected parent node')
|
|
81
|
+
invariant(start.parentNode === container, 'Boundaries must share parent')
|
|
82
|
+
let parent = container
|
|
83
|
+
|
|
84
|
+
let hydrationCursor = start.nextSibling
|
|
85
|
+
|
|
86
|
+
let eventTarget = new TypedEventTarget<VirtualRootEventMap>()
|
|
87
|
+
let scheduler =
|
|
88
|
+
options.scheduler ?? createScheduler(parent.ownerDocument ?? document, eventTarget, styles)
|
|
89
|
+
let frameStub =
|
|
90
|
+
options.frame ??
|
|
91
|
+
createRootFrameHandle({
|
|
92
|
+
src: options.frameInit?.src,
|
|
93
|
+
resolveFrame: options.frameInit?.resolveFrame,
|
|
94
|
+
loadModule: options.frameInit?.loadModule,
|
|
95
|
+
errorTarget: eventTarget,
|
|
96
|
+
scheduler,
|
|
97
|
+
styleManager: styles,
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
let isErrorForwardingAttached = false
|
|
101
|
+
function forwardDomError(event: Event) {
|
|
102
|
+
eventTarget.dispatchEvent(createComponentErrorEvent(getComponentError(event)))
|
|
103
|
+
}
|
|
104
|
+
function attachDomErrorForwarding() {
|
|
105
|
+
if (isErrorForwardingAttached) return
|
|
106
|
+
parent.addEventListener('error', forwardDomError)
|
|
107
|
+
isErrorForwardingAttached = true
|
|
108
|
+
}
|
|
109
|
+
function detachDomErrorForwarding() {
|
|
110
|
+
if (!isErrorForwardingAttached) return
|
|
111
|
+
parent.removeEventListener('error', forwardDomError)
|
|
112
|
+
isErrorForwardingAttached = false
|
|
113
|
+
}
|
|
114
|
+
attachDomErrorForwarding()
|
|
115
|
+
|
|
116
|
+
return Object.assign(eventTarget, {
|
|
117
|
+
render(element: RemixNode) {
|
|
118
|
+
attachDomErrorForwarding()
|
|
119
|
+
|
|
120
|
+
let vnode = toVNode(element)
|
|
121
|
+
let vParent: VNode = {
|
|
122
|
+
type: ROOT_VNODE,
|
|
123
|
+
_svg: false,
|
|
124
|
+
_rangeStart: start,
|
|
125
|
+
_rangeEnd: end,
|
|
126
|
+
_pendingHydrationComponentId: getHydrationComponentIdFromRangeStart(start),
|
|
127
|
+
}
|
|
128
|
+
scheduler.enqueueWork([
|
|
129
|
+
() => {
|
|
130
|
+
diffVNodes(
|
|
131
|
+
vroot,
|
|
132
|
+
vnode,
|
|
133
|
+
parent,
|
|
134
|
+
frameStub,
|
|
135
|
+
scheduler,
|
|
136
|
+
styles,
|
|
137
|
+
vParent,
|
|
138
|
+
eventTarget,
|
|
139
|
+
end,
|
|
140
|
+
hydrationCursor,
|
|
141
|
+
)
|
|
142
|
+
vroot = vnode
|
|
143
|
+
hydrationCursor = null
|
|
144
|
+
},
|
|
145
|
+
])
|
|
146
|
+
scheduler.dequeue()
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
dispose() {
|
|
150
|
+
detachDomErrorForwarding()
|
|
151
|
+
|
|
152
|
+
if (!vroot) return
|
|
153
|
+
let current = vroot
|
|
154
|
+
vroot = null
|
|
155
|
+
scheduler.enqueueWork([() => removeVNode(current, parent, scheduler, styles)])
|
|
156
|
+
scheduler.dequeue()
|
|
157
|
+
},
|
|
158
|
+
|
|
159
|
+
flush() {
|
|
160
|
+
scheduler.dequeue()
|
|
161
|
+
},
|
|
162
|
+
})
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Creates a virtual root for a host container element.
|
|
167
|
+
*
|
|
168
|
+
* @param container Host element to render into.
|
|
169
|
+
* @param options Root configuration.
|
|
170
|
+
* @returns A virtual root controller.
|
|
171
|
+
*/
|
|
172
|
+
export function createRoot(container: HTMLElement, options: VirtualRootOptions = {}): VirtualRoot {
|
|
173
|
+
let vroot: VNode | null = null
|
|
174
|
+
let styles = options.styleManager ?? defaultStyleManager
|
|
175
|
+
let hydrationCursor = container.innerHTML.trim() !== '' ? container.firstChild : undefined
|
|
176
|
+
|
|
177
|
+
let eventTarget = new TypedEventTarget<VirtualRootEventMap>()
|
|
178
|
+
let scheduler =
|
|
179
|
+
options.scheduler ?? createScheduler(container.ownerDocument ?? document, eventTarget, styles)
|
|
180
|
+
let frameStub =
|
|
181
|
+
options.frame ??
|
|
182
|
+
createRootFrameHandle({
|
|
183
|
+
src: options.frameInit?.src,
|
|
184
|
+
resolveFrame: options.frameInit?.resolveFrame,
|
|
185
|
+
loadModule: options.frameInit?.loadModule,
|
|
186
|
+
errorTarget: eventTarget,
|
|
187
|
+
scheduler,
|
|
188
|
+
styleManager: styles,
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
let isErrorForwardingAttached = false
|
|
192
|
+
function forwardDomError(event: Event) {
|
|
193
|
+
eventTarget.dispatchEvent(createComponentErrorEvent(getComponentError(event)))
|
|
194
|
+
}
|
|
195
|
+
function attachDomErrorForwarding() {
|
|
196
|
+
if (isErrorForwardingAttached) return
|
|
197
|
+
container.addEventListener('error', forwardDomError)
|
|
198
|
+
isErrorForwardingAttached = true
|
|
199
|
+
}
|
|
200
|
+
function detachDomErrorForwarding() {
|
|
201
|
+
if (!isErrorForwardingAttached) return
|
|
202
|
+
container.removeEventListener('error', forwardDomError)
|
|
203
|
+
isErrorForwardingAttached = false
|
|
204
|
+
}
|
|
205
|
+
attachDomErrorForwarding()
|
|
206
|
+
|
|
207
|
+
return Object.assign(eventTarget, {
|
|
208
|
+
render(element: RemixNode) {
|
|
209
|
+
attachDomErrorForwarding()
|
|
210
|
+
|
|
211
|
+
let vnode = toVNode(element)
|
|
212
|
+
let vParent: VNode = { type: ROOT_VNODE, _svg: false }
|
|
213
|
+
scheduler.enqueueWork([
|
|
214
|
+
() => {
|
|
215
|
+
diffVNodes(
|
|
216
|
+
vroot,
|
|
217
|
+
vnode,
|
|
218
|
+
container,
|
|
219
|
+
frameStub,
|
|
220
|
+
scheduler,
|
|
221
|
+
styles,
|
|
222
|
+
vParent,
|
|
223
|
+
eventTarget,
|
|
224
|
+
undefined,
|
|
225
|
+
hydrationCursor,
|
|
226
|
+
)
|
|
227
|
+
vroot = vnode
|
|
228
|
+
hydrationCursor = undefined
|
|
229
|
+
},
|
|
230
|
+
])
|
|
231
|
+
scheduler.dequeue()
|
|
232
|
+
},
|
|
233
|
+
|
|
234
|
+
dispose() {
|
|
235
|
+
detachDomErrorForwarding()
|
|
236
|
+
|
|
237
|
+
if (!vroot) return
|
|
238
|
+
let current = vroot
|
|
239
|
+
vroot = null
|
|
240
|
+
scheduler.enqueueWork([() => removeVNode(current, container, scheduler, styles)])
|
|
241
|
+
scheduler.dequeue()
|
|
242
|
+
},
|
|
243
|
+
|
|
244
|
+
flush() {
|
|
245
|
+
scheduler.dequeue()
|
|
246
|
+
},
|
|
247
|
+
})
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function createRootFrameHandle(init: {
|
|
251
|
+
src?: string
|
|
252
|
+
resolveFrame?: (
|
|
253
|
+
src: string,
|
|
254
|
+
signal?: AbortSignal,
|
|
255
|
+
target?: string,
|
|
256
|
+
) => Promise<FrameContent> | FrameContent
|
|
257
|
+
loadModule?: (moduleUrl: string, exportName: string) => Promise<Function> | Function
|
|
258
|
+
errorTarget: EventTarget
|
|
259
|
+
scheduler: Scheduler
|
|
260
|
+
styleManager: StyleManager
|
|
261
|
+
}): FrameHandle {
|
|
262
|
+
let resolveFrame =
|
|
263
|
+
init.resolveFrame ??
|
|
264
|
+
(() => {
|
|
265
|
+
throw new Error(
|
|
266
|
+
'Cannot render <Frame /> without frame runtime. Use run() or pass frameInit to createRoot/createRangeRoot.',
|
|
267
|
+
)
|
|
268
|
+
})
|
|
269
|
+
|
|
270
|
+
let frame = createFrameHandle({
|
|
271
|
+
src: init.src ?? '/',
|
|
272
|
+
$runtime: {
|
|
273
|
+
canResolveFrames: !!init.resolveFrame,
|
|
274
|
+
topFrame: undefined,
|
|
275
|
+
loadModule:
|
|
276
|
+
init.loadModule ??
|
|
277
|
+
(() => {
|
|
278
|
+
throw new Error('loadModule is required to hydrate client entries inside <Frame />')
|
|
279
|
+
}),
|
|
280
|
+
resolveFrame,
|
|
281
|
+
errorTarget: init.errorTarget,
|
|
282
|
+
pendingClientEntries: new Map(),
|
|
283
|
+
scheduler: init.scheduler,
|
|
284
|
+
styleManager: init.styleManager,
|
|
285
|
+
data: {},
|
|
286
|
+
moduleCache: new Map(),
|
|
287
|
+
moduleLoads: new Map(),
|
|
288
|
+
frameInstances: new WeakMap(),
|
|
289
|
+
namedFrames: new Map(),
|
|
290
|
+
},
|
|
291
|
+
})
|
|
292
|
+
let runtime = frame.$runtime as { topFrame?: FrameHandle } | undefined
|
|
293
|
+
if (runtime) runtime.topFrame = frame
|
|
294
|
+
return frame
|
|
295
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import type { ComponentHandle, Component } from './component.ts'
|
|
2
|
+
import { Fragment, Frame } from './component.ts'
|
|
3
|
+
import type { ElementProps, RemixElement, RemixNode } from './jsx.ts'
|
|
4
|
+
|
|
5
|
+
export const TEXT_NODE = Symbol('TEXT_NODE')
|
|
6
|
+
export const ROOT_VNODE = Symbol('ROOT_VNODE')
|
|
7
|
+
|
|
8
|
+
export type VNodeType =
|
|
9
|
+
| typeof ROOT_VNODE
|
|
10
|
+
| string // host element
|
|
11
|
+
| Function // component
|
|
12
|
+
| typeof TEXT_NODE
|
|
13
|
+
| typeof Fragment
|
|
14
|
+
| typeof Frame
|
|
15
|
+
|
|
16
|
+
export type VNode<T extends VNodeType = VNodeType> = {
|
|
17
|
+
type: T
|
|
18
|
+
props?: ElementProps
|
|
19
|
+
_mixedProps?: ElementProps
|
|
20
|
+
key?: string
|
|
21
|
+
|
|
22
|
+
// _prefixes assigned during reconciliation
|
|
23
|
+
_parent?: VNode
|
|
24
|
+
_children?: VNode[]
|
|
25
|
+
_dom?: unknown
|
|
26
|
+
_controller?: AbortController
|
|
27
|
+
_mixState?: unknown
|
|
28
|
+
_controlledState?: unknown
|
|
29
|
+
_svg?: boolean
|
|
30
|
+
// Range roots render between comment boundary markers
|
|
31
|
+
_rangeStart?: Node
|
|
32
|
+
_rangeEnd?: Node
|
|
33
|
+
_pendingHydrationComponentId?: string
|
|
34
|
+
_frameInstance?: unknown
|
|
35
|
+
_frameFallbackRoot?: { render: (element: RemixNode) => void; dispose: () => void }
|
|
36
|
+
_frameResolveToken?: number
|
|
37
|
+
_frameResolveController?: AbortController
|
|
38
|
+
_frameResolved?: boolean
|
|
39
|
+
|
|
40
|
+
// Internal diffing fields
|
|
41
|
+
_index?: number
|
|
42
|
+
_flags?: number
|
|
43
|
+
|
|
44
|
+
// TEXT_NODE
|
|
45
|
+
_text?: string
|
|
46
|
+
|
|
47
|
+
// Component
|
|
48
|
+
_handle?: ComponentHandle
|
|
49
|
+
_id?: string
|
|
50
|
+
_content?: VNode
|
|
51
|
+
|
|
52
|
+
// Mixin-persisted node removal state
|
|
53
|
+
_persistedByMixins?: boolean
|
|
54
|
+
_persistedParentByMixins?: ParentNode
|
|
55
|
+
_persistedRemovalToken?: number
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export type FragmentNode = VNode & {
|
|
59
|
+
type: typeof Fragment
|
|
60
|
+
_children: VNode[]
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type TextNode = VNode & {
|
|
64
|
+
type: typeof TEXT_NODE
|
|
65
|
+
_text: string
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export type CommittedTextNode = TextNode & {
|
|
69
|
+
_dom: Text
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export type HostNode = VNode & {
|
|
73
|
+
type: string
|
|
74
|
+
props: ElementProps
|
|
75
|
+
_children: VNode[]
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export type CommittedHostNode = HostNode & {
|
|
79
|
+
_dom: Element
|
|
80
|
+
_controller?: AbortController
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export type ComponentNode = VNode & {
|
|
84
|
+
type: Function
|
|
85
|
+
props: ElementProps
|
|
86
|
+
_handle: ComponentHandle
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export type CommittedComponentNode = VNode & {
|
|
90
|
+
type: Function
|
|
91
|
+
props: ElementProps
|
|
92
|
+
_content: VNode
|
|
93
|
+
_handle: ComponentHandle
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function isFragmentNode(node: VNode): node is FragmentNode {
|
|
97
|
+
return node.type === Fragment
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function isTextNode(node: VNode): node is TextNode {
|
|
101
|
+
return node.type === TEXT_NODE
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function isCommittedTextNode(node: VNode): node is CommittedTextNode {
|
|
105
|
+
return isTextNode(node) && node._dom instanceof Text
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export function isHostNode(node: VNode): node is HostNode {
|
|
109
|
+
return typeof node.type === 'string'
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export function isCommittedHostNode(node: VNode): node is CommittedHostNode {
|
|
113
|
+
return isHostNode(node) && node._dom instanceof Element
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export function isComponentNode(node: VNode): node is ComponentNode {
|
|
117
|
+
return typeof node.type === 'function' && node.type !== Frame
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function isCommittedComponentNode(node: VNode): node is CommittedComponentNode {
|
|
121
|
+
return isComponentNode(node) && node._content !== undefined
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function isRemixElement(node: RemixNode): node is RemixElement {
|
|
125
|
+
return typeof node === 'object' && node !== null && '$rmx' in node
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function findContextFromAncestry(node: VNode, type: Component): unknown {
|
|
129
|
+
let current: VNode | undefined = node
|
|
130
|
+
while (current) {
|
|
131
|
+
if (current.type === type && isComponentNode(current)) {
|
|
132
|
+
return current._handle.getContextValue()
|
|
133
|
+
}
|
|
134
|
+
current = current._parent
|
|
135
|
+
}
|
|
136
|
+
return undefined
|
|
137
|
+
}
|