@remix-run/ui 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +116 -157
- package/dist/accordion/index.d.ts +46 -0
- package/dist/accordion/index.js +142 -0
- package/dist/accordion/index.js.map +1 -0
- package/dist/accordion/primitives.d.ts +104 -0
- package/dist/accordion/primitives.js +312 -0
- package/dist/accordion/primitives.js.map +1 -0
- package/dist/{components/anchor/anchor.js → anchor/index.js} +1 -1
- package/dist/anchor/index.js.map +1 -0
- package/dist/animation/animate-layout-mixin.js +1 -1
- package/dist/animation/animate-layout-mixin.js.map +1 -1
- package/dist/animation/animate-mixins.js +2 -2
- package/dist/animation/animate-mixins.js.map +1 -1
- package/dist/animation/demos/color-interpolation.js +1 -1
- package/dist/animation/demos/color-interpolation.js.map +1 -1
- package/dist/animation/demos/drag-release.d.ts +1 -1
- package/dist/animation/demos/hold-to-confirm.d.ts +3 -3
- package/dist/animation/demos/material-ripple.js +1 -3
- package/dist/animation/demos/material-ripple.js.map +1 -1
- package/dist/animation/demos/reordering.js +9 -6
- package/dist/animation/demos/reordering.js.map +1 -1
- package/dist/animation/index.js +4 -4
- package/dist/animation/spring.js.map +1 -1
- package/dist/{components/breadcrumbs/breadcrumbs.js → breadcrumbs/index.js} +19 -19
- package/dist/breadcrumbs/index.js.map +1 -0
- package/dist/button/index.d.ts +15 -0
- package/dist/button/index.js +128 -0
- package/dist/button/index.js.map +1 -0
- package/dist/checkbox/index.d.ts +14 -0
- package/dist/checkbox/index.js +127 -0
- package/dist/checkbox/index.js.map +1 -0
- package/dist/combobox/index.d.ts +21 -0
- package/dist/combobox/index.js +58 -0
- package/dist/combobox/index.js.map +1 -0
- package/dist/{components/combobox/combobox.d.ts → combobox/primitives.d.ts} +4 -8
- package/dist/{components/combobox/combobox.js → combobox/primitives.js} +8 -61
- package/dist/combobox/primitives.js.map +1 -0
- package/dist/dev/refresh.d.ts +1 -0
- package/dist/dev/refresh.js +2 -0
- package/dist/dev/refresh.js.map +1 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +14 -14
- package/dist/input/index.d.ts +13 -0
- package/dist/input/index.js +121 -0
- package/dist/input/index.js.map +1 -0
- package/dist/jsx-runtime.js +2 -2
- package/dist/listbox/flash-attribute.js.map +1 -0
- package/dist/{components/listbox/listbox.d.ts → listbox/index.d.ts} +2 -6
- package/dist/{components/listbox/listbox.js → listbox/index.js} +4 -82
- package/dist/listbox/index.js.map +1 -0
- package/dist/menu/hover-aim.js.map +1 -0
- package/dist/menu/index.d.ts +42 -0
- package/dist/menu/index.js +250 -0
- package/dist/menu/index.js.map +1 -0
- package/dist/{components/menu/menu.d.ts → menu/primitives.d.ts} +4 -33
- package/dist/{components/menu/menu.js → menu/primitives.js} +98 -315
- package/dist/menu/primitives.js.map +1 -0
- package/dist/{components/popover/popover.d.ts → popover/index.d.ts} +2 -4
- package/dist/{components/popover/popover.js → popover/index.js} +5 -48
- package/dist/popover/index.js.map +1 -0
- package/dist/{interactions/outside-click/outside-click-mixin.js → popover/outside-click.js} +1 -1
- package/dist/popover/outside-click.js.map +1 -0
- package/dist/popover/scroll-lock.d.ts +1 -0
- package/dist/{utils → popover}/scroll-lock.js +0 -18
- package/dist/popover/scroll-lock.js.map +1 -0
- package/dist/radio/index.d.ts +12 -0
- package/dist/radio/index.js +77 -0
- package/dist/radio/index.js.map +1 -0
- package/dist/runtime/client-entry-boundary.d.ts +14 -0
- package/dist/runtime/client-entry-boundary.js +29 -0
- package/dist/runtime/client-entry-boundary.js.map +1 -0
- package/dist/runtime/component.d.ts +19 -4
- package/dist/runtime/component.js +39 -9
- package/dist/runtime/component.js.map +1 -1
- package/dist/runtime/core/attributes.js +36 -3
- package/dist/runtime/core/attributes.js.map +1 -1
- package/dist/runtime/core/children.d.ts +2 -0
- package/dist/runtime/core/children.js +26 -2
- package/dist/runtime/core/children.js.map +1 -1
- package/dist/runtime/core/props.js +2 -2
- package/dist/runtime/core/vnode.d.ts +3 -3
- package/dist/runtime/core/vnode.js +22 -1
- package/dist/runtime/core/vnode.js.map +1 -1
- package/dist/runtime/create-element.d.ts +2 -2
- package/dist/runtime/create-element.js +3 -2
- package/dist/runtime/create-element.js.map +1 -1
- package/dist/runtime/diff-dom.js +294 -219
- package/dist/runtime/diff-dom.js.map +1 -1
- package/dist/runtime/diff-props.js +3 -3
- package/dist/runtime/dom.d.ts +12 -0
- package/dist/runtime/element-function.d.ts +3 -0
- package/dist/runtime/element-function.js +2 -0
- package/dist/runtime/element-function.js.map +1 -0
- package/dist/runtime/form-navigation.d.ts +25 -0
- package/dist/runtime/form-navigation.js +132 -0
- package/dist/runtime/form-navigation.js.map +1 -0
- package/dist/runtime/frame-resolution.d.ts +5 -0
- package/dist/runtime/frame-resolution.js +10 -0
- package/dist/runtime/frame-resolution.js.map +1 -0
- package/dist/runtime/frame.d.ts +58 -15
- package/dist/runtime/frame.js +367 -114
- package/dist/runtime/frame.js.map +1 -1
- package/dist/runtime/jsx.d.ts +1 -1
- package/dist/runtime/jsx.js +1 -1
- package/dist/runtime/jsx.js.map +1 -1
- package/dist/runtime/key.d.ts +1 -0
- package/dist/runtime/key.js +2 -0
- package/dist/runtime/key.js.map +1 -0
- package/dist/runtime/mixins/attrs-mixin.js +2 -2
- package/dist/runtime/mixins/link-mixin.js +4 -3
- package/dist/runtime/mixins/link-mixin.js.map +1 -1
- package/dist/runtime/mixins/mixin.d.ts +15 -10
- package/dist/runtime/mixins/mixin.js +4 -4
- package/dist/runtime/mixins/mixin.js.map +1 -1
- package/dist/runtime/mixins/on-mixin.js +1 -1
- package/dist/runtime/mixins/ref-mixin.js +1 -1
- package/dist/runtime/navigation.d.ts +4 -1
- package/dist/runtime/navigation.js +157 -32
- package/dist/runtime/navigation.js.map +1 -1
- package/dist/runtime/reconcile.d.ts +11 -10
- package/dist/runtime/reconcile.js +557 -423
- package/dist/runtime/reconcile.js.map +1 -1
- package/dist/runtime/refresh.d.ts +28 -0
- package/dist/runtime/refresh.js +31 -0
- package/dist/runtime/refresh.js.map +1 -0
- package/dist/runtime/render.js +1 -1
- package/dist/runtime/render.js.map +1 -1
- package/dist/runtime/run.d.ts +3 -1
- package/dist/runtime/run.js +15 -7
- package/dist/runtime/run.js.map +1 -1
- package/dist/runtime/scheduler.js +8 -16
- package/dist/runtime/scheduler.js.map +1 -1
- package/dist/runtime/to-vnode.d.ts +2 -2
- package/dist/runtime/to-vnode.js +68 -20
- package/dist/runtime/to-vnode.js.map +1 -1
- package/dist/runtime/vdom.d.ts +4 -2
- package/dist/runtime/vdom.js +89 -41
- package/dist/runtime/vdom.js.map +1 -1
- package/dist/runtime/vnode.d.ts +138 -67
- package/dist/runtime/vnode.js +17 -12
- package/dist/runtime/vnode.js.map +1 -1
- package/dist/select/index.d.ts +19 -0
- package/dist/select/index.js +95 -0
- package/dist/select/index.js.map +1 -0
- package/dist/select/keydown.js.map +1 -0
- package/dist/{components/select/select.d.ts → select/primitives.d.ts} +5 -7
- package/dist/{components/select/select.js → select/primitives.js} +11 -63
- package/dist/select/primitives.js.map +1 -0
- package/dist/server/stream.js +22 -29
- package/dist/server/stream.js.map +1 -1
- package/dist/shared/focus-styles.d.ts +1 -0
- package/dist/shared/focus-styles.js +2 -0
- package/dist/shared/focus-styles.js.map +1 -0
- package/dist/shared/icons.d.ts +9 -0
- package/dist/shared/icons.js +42 -0
- package/dist/shared/icons.js.map +1 -0
- package/dist/shared/listbox-popover-styles.d.ts +6 -0
- package/dist/shared/listbox-popover-styles.js +137 -0
- package/dist/shared/listbox-popover-styles.js.map +1 -0
- package/dist/shared/style-values.d.ts +78 -0
- package/dist/shared/style-values.js +88 -0
- package/dist/shared/style-values.js.map +1 -0
- package/dist/{interactions/typeahead/typeahead-mixin.js → shared/typeahead.js} +1 -1
- package/dist/shared/typeahead.js.map +1 -0
- package/dist/shared/wait-for-css-transition.js.map +1 -0
- package/dist/shared/wait.js.map +1 -0
- package/dist/style/css-mixin.js +3 -3
- package/dist/style/index.js +2 -2
- package/dist/style/style.js +25 -6
- package/dist/style/style.js.map +1 -1
- package/dist/style/stylesheet.d.ts +0 -1
- package/dist/style/stylesheet.js +13 -54
- package/dist/style/stylesheet.js.map +1 -1
- package/dist/tabs/index.d.ts +32 -0
- package/dist/tabs/index.js +157 -0
- package/dist/tabs/index.js.map +1 -0
- package/dist/tabs/primitives.d.ts +57 -0
- package/dist/tabs/primitives.js +238 -0
- package/dist/tabs/primitives.js.map +1 -0
- package/dist/test.js +1 -1
- package/dist/toggle/index.d.ts +9 -0
- package/dist/toggle/index.js +108 -0
- package/dist/toggle/index.js.map +1 -0
- package/dist/toggle/primitives.d.ts +29 -0
- package/dist/toggle/primitives.js +127 -0
- package/dist/toggle/primitives.js.map +1 -0
- package/package.json +81 -49
- package/src/{components/accordion → accordion}/README.md +50 -14
- package/src/accordion/index.tsx +285 -0
- package/src/accordion/primitives.tsx +512 -0
- package/src/{components/anchor → anchor}/README.md +37 -2
- package/src/animation/animate-mixins.ts +3 -3
- package/src/animation/demos/color-interpolation.tsx +1 -1
- package/src/animation/demos/reordering.tsx +9 -6
- package/src/{components/breadcrumbs → breadcrumbs}/README.md +4 -4
- package/src/{components/breadcrumbs/breadcrumbs.tsx → breadcrumbs/index.tsx} +18 -18
- package/src/button/README.md +44 -0
- package/src/button/index.ts +168 -0
- package/src/checkbox/README.md +59 -0
- package/src/checkbox/index.ts +164 -0
- package/src/{components/combobox → combobox}/README.md +58 -9
- package/src/combobox/index.tsx +112 -0
- package/src/{components/combobox/combobox.tsx → combobox/primitives.tsx} +5 -91
- package/src/dev/refresh.ts +1 -0
- package/src/index.ts +1 -1
- package/src/input/README.md +52 -0
- package/src/input/index.ts +147 -0
- package/src/{components/listbox → listbox}/README.md +9 -41
- package/src/{components/listbox/listbox.ts → listbox/index.ts} +2 -87
- package/src/{components/menu → menu}/README.md +55 -14
- package/src/menu/index.tsx +354 -0
- package/src/{components/menu/menu.tsx → menu/primitives.tsx} +99 -413
- package/src/{components/popover → popover}/README.md +20 -39
- package/src/{components/popover/popover.ts → popover/index.ts} +3 -57
- package/src/{utils → popover}/scroll-lock.ts +0 -28
- package/src/radio/README.md +53 -0
- package/src/radio/index.ts +101 -0
- package/src/runtime/client-entry-boundary.ts +54 -0
- package/src/runtime/component.ts +65 -16
- package/src/runtime/core/attributes.ts +35 -1
- package/src/runtime/core/children.ts +24 -2
- package/src/runtime/core/vnode.ts +25 -4
- package/src/runtime/create-element.ts +6 -5
- package/src/runtime/demos/readme.demo.tsx +20 -18
- package/src/runtime/diff-dom.ts +358 -243
- package/src/runtime/dom.ts +331 -214
- package/src/runtime/element-function.ts +1 -0
- package/src/runtime/event-listeners.ts +1 -1
- package/src/runtime/form-navigation.ts +184 -0
- package/src/runtime/frame-resolution.ts +13 -0
- package/src/runtime/frame.ts +482 -124
- package/src/runtime/jsx.ts +3 -5
- package/src/runtime/key.ts +1 -0
- package/src/runtime/mixins/link-mixin.ts +1 -0
- package/src/runtime/mixins/mixin.ts +21 -18
- package/src/runtime/navigation.ts +204 -30
- package/src/runtime/reconcile.ts +769 -760
- package/src/runtime/refresh.ts +46 -0
- package/src/runtime/run.ts +12 -2
- package/src/runtime/scheduler.ts +9 -29
- package/src/runtime/to-vnode.ts +85 -23
- package/src/runtime/vdom.ts +91 -69
- package/src/runtime/vnode.ts +192 -88
- package/src/{components/select → select}/README.md +29 -19
- package/src/select/index.tsx +159 -0
- package/src/{components/select/select.tsx → select/primitives.tsx} +10 -98
- package/src/server/stream.ts +25 -31
- package/src/shared/focus-styles.ts +2 -0
- package/src/shared/icons.tsx +62 -0
- package/src/shared/listbox-popover-styles.ts +146 -0
- package/src/shared/style-values.ts +165 -0
- package/src/style/style.ts +25 -6
- package/src/style/stylesheet.ts +32 -57
- package/src/tabs/README.md +141 -0
- package/src/tabs/index.tsx +245 -0
- package/src/tabs/primitives.ts +365 -0
- package/src/test/README.md +151 -60
- package/src/toggle/README.md +56 -0
- package/src/toggle/index.tsx +136 -0
- package/src/toggle/primitives.ts +192 -0
- package/dist/animation/demos/animation.demo.d.ts +0 -5
- package/dist/animation/demos/animation.demo.js +0 -92
- package/dist/animation/demos/animation.demo.js.map +0 -1
- package/dist/animation/demos/spring.demo.d.ts +0 -6
- package/dist/animation/demos/spring.demo.js +0 -304
- package/dist/animation/demos/spring.demo.js.map +0 -1
- package/dist/components/accordion/accordion.d.ts +0 -92
- package/dist/components/accordion/accordion.js +0 -335
- package/dist/components/accordion/accordion.js.map +0 -1
- package/dist/components/accordion/demos/card.demo.d.ts +0 -7
- package/dist/components/accordion/demos/card.demo.js +0 -59
- package/dist/components/accordion/demos/card.demo.js.map +0 -1
- package/dist/components/accordion/demos/multiple.demo.d.ts +0 -7
- package/dist/components/accordion/demos/multiple.demo.js +0 -20
- package/dist/components/accordion/demos/multiple.demo.js.map +0 -1
- package/dist/components/accordion/demos/overview.demo.d.ts +0 -7
- package/dist/components/accordion/demos/overview.demo.js +0 -20
- package/dist/components/accordion/demos/overview.demo.js.map +0 -1
- package/dist/components/anchor/anchor.js.map +0 -1
- package/dist/components/breadcrumbs/basic.demo.d.ts +0 -6
- package/dist/components/breadcrumbs/basic.demo.js +0 -15
- package/dist/components/breadcrumbs/basic.demo.js.map +0 -1
- package/dist/components/breadcrumbs/breadcrumbs.js.map +0 -1
- package/dist/components/breadcrumbs/separator.demo.d.ts +0 -6
- package/dist/components/breadcrumbs/separator.demo.js +0 -15
- package/dist/components/breadcrumbs/separator.demo.js.map +0 -1
- package/dist/components/button/button.d.ts +0 -105
- package/dist/components/button/button.js +0 -207
- package/dist/components/button/button.js.map +0 -1
- package/dist/components/button/demos/aliases.demo.d.ts +0 -7
- package/dist/components/button/demos/aliases.demo.js +0 -19
- package/dist/components/button/demos/aliases.demo.js.map +0 -1
- package/dist/components/button/demos/basic.demo.d.ts +0 -7
- package/dist/components/button/demos/basic.demo.js +0 -20
- package/dist/components/button/demos/basic.demo.js.map +0 -1
- package/dist/components/button/demos/states.demo.d.ts +0 -7
- package/dist/components/button/demos/states.demo.js +0 -30
- package/dist/components/button/demos/states.demo.js.map +0 -1
- package/dist/components/combobox/combobox.js.map +0 -1
- package/dist/components/combobox/overview.demo.d.ts +0 -7
- package/dist/components/combobox/overview.demo.js +0 -154
- package/dist/components/combobox/overview.demo.js.map +0 -1
- package/dist/components/glyph/glyph.d.ts +0 -14
- package/dist/components/glyph/glyph.js +0 -65
- package/dist/components/glyph/glyph.js.map +0 -1
- package/dist/components/listbox/listbox.js.map +0 -1
- package/dist/components/listbox/overview.demo.d.ts +0 -7
- package/dist/components/listbox/overview.demo.js +0 -65
- package/dist/components/listbox/overview.demo.js.map +0 -1
- package/dist/components/menu/demos/bubbling.demo.d.ts +0 -6
- package/dist/components/menu/demos/bubbling.demo.js +0 -16
- package/dist/components/menu/demos/bubbling.demo.js.map +0 -1
- package/dist/components/menu/demos/context-trigger.demo.d.ts +0 -7
- package/dist/components/menu/demos/context-trigger.demo.js +0 -87
- package/dist/components/menu/demos/context-trigger.demo.js.map +0 -1
- package/dist/components/menu/demos/overview.demo.d.ts +0 -7
- package/dist/components/menu/demos/overview.demo.js +0 -33
- package/dist/components/menu/demos/overview.demo.js.map +0 -1
- package/dist/components/menu/hover-aim.js.map +0 -1
- package/dist/components/menu/menu.js.map +0 -1
- package/dist/components/popover/overview.demo.d.ts +0 -7
- package/dist/components/popover/overview.demo.js +0 -65
- package/dist/components/popover/overview.demo.js.map +0 -1
- package/dist/components/popover/popover.js.map +0 -1
- package/dist/components/select/deconstructed.demo.d.ts +0 -7
- package/dist/components/select/deconstructed.demo.js +0 -54
- package/dist/components/select/deconstructed.demo.js.map +0 -1
- package/dist/components/select/overview.demo.d.ts +0 -6
- package/dist/components/select/overview.demo.js +0 -28
- package/dist/components/select/overview.demo.js.map +0 -1
- package/dist/components/select/select.js.map +0 -1
- package/dist/components/separator/separator.d.ts +0 -2
- package/dist/components/separator/separator.js +0 -15
- package/dist/components/separator/separator.js.map +0 -1
- package/dist/components/tabs/tabs.d.ts +0 -78
- package/dist/components/tabs/tabs.js +0 -339
- package/dist/components/tabs/tabs.js.map +0 -1
- package/dist/interactions/keydown/keydown.js.map +0 -1
- package/dist/interactions/outside-click/outside-click-mixin.js.map +0 -1
- package/dist/interactions/typeahead/typeahead-mixin.js.map +0 -1
- package/dist/runtime/demos/basic.demo.d.ts +0 -6
- package/dist/runtime/demos/basic.demo.js +0 -16
- package/dist/runtime/demos/basic.demo.js.map +0 -1
- package/dist/runtime/demos/controlled-uncontrolled-values.demo.d.ts +0 -6
- package/dist/runtime/demos/controlled-uncontrolled-values.demo.js +0 -77
- package/dist/runtime/demos/controlled-uncontrolled-values.demo.js.map +0 -1
- package/dist/runtime/demos/keyed-list.demo.d.ts +0 -6
- package/dist/runtime/demos/keyed-list.demo.js +0 -62
- package/dist/runtime/demos/keyed-list.demo.js.map +0 -1
- package/dist/runtime/demos/readme.demo.d.ts +0 -5
- package/dist/runtime/demos/readme.demo.js +0 -396
- package/dist/runtime/demos/readme.demo.js.map +0 -1
- package/dist/theme/contract.d.ts +0 -61
- package/dist/theme/contract.js +0 -131
- package/dist/theme/contract.js.map +0 -1
- package/dist/theme/glyph-contract.d.ts +0 -11
- package/dist/theme/glyph-contract.js +0 -34
- package/dist/theme/glyph-contract.js.map +0 -1
- package/dist/theme/presets/rmx-01/glyphs.d.ts +0 -2
- package/dist/theme/presets/rmx-01/glyphs.js +0 -252
- package/dist/theme/presets/rmx-01/glyphs.js.map +0 -1
- package/dist/theme/presets/rmx-01/index.d.ts +0 -4
- package/dist/theme/presets/rmx-01/index.js +0 -119
- package/dist/theme/presets/rmx-01/index.js.map +0 -1
- package/dist/theme/runtime.d.ts +0 -2
- package/dist/theme/runtime.js +0 -84
- package/dist/theme/runtime.js.map +0 -1
- package/dist/theme/theme.d.ts +0 -6
- package/dist/theme/theme.js +0 -5
- package/dist/theme/theme.js.map +0 -1
- package/dist/utils/flash-attribute.js.map +0 -1
- package/dist/utils/scroll-lock.d.ts +0 -3
- package/dist/utils/scroll-lock.js.map +0 -1
- package/dist/utils/wait-for-css-transition.js.map +0 -1
- package/dist/utils/wait.js.map +0 -1
- package/src/animation/demos/animation.demo.tsx +0 -194
- package/src/animation/demos/spring.demo.tsx +0 -385
- package/src/components/accordion/accordion.tsx +0 -565
- package/src/components/accordion/demos/card.demo.tsx +0 -114
- package/src/components/accordion/demos/multiple.demo.tsx +0 -57
- package/src/components/accordion/demos/overview.demo.tsx +0 -57
- package/src/components/breadcrumbs/basic.demo.tsx +0 -18
- package/src/components/breadcrumbs/separator.demo.tsx +0 -19
- package/src/components/button/README.md +0 -44
- package/src/components/button/button.tsx +0 -286
- package/src/components/button/demos/aliases.demo.tsx +0 -28
- package/src/components/button/demos/basic.demo.tsx +0 -31
- package/src/components/button/demos/states.demo.tsx +0 -53
- package/src/components/combobox/overview.demo.tsx +0 -200
- package/src/components/glyph/README.md +0 -72
- package/src/components/glyph/glyph.tsx +0 -110
- package/src/components/listbox/overview.demo.tsx +0 -102
- package/src/components/menu/demos/bubbling.demo.tsx +0 -35
- package/src/components/menu/demos/context-trigger.demo.tsx +0 -133
- package/src/components/menu/demos/overview.demo.tsx +0 -77
- package/src/components/popover/overview.demo.tsx +0 -144
- package/src/components/select/deconstructed.demo.tsx +0 -96
- package/src/components/select/overview.demo.tsx +0 -52
- package/src/components/separator/separator.ts +0 -19
- package/src/components/tabs/README.md +0 -105
- package/src/components/tabs/tabs.tsx +0 -504
- package/src/runtime/demos/basic.demo.tsx +0 -21
- package/src/runtime/demos/controlled-uncontrolled-values.demo.tsx +0 -177
- package/src/runtime/demos/keyed-list.demo.tsx +0 -94
- package/src/theme/README.md +0 -103
- package/src/theme/contract.ts +0 -215
- package/src/theme/glyph-contract.ts +0 -59
- package/src/theme/presets/rmx-01/glyphs.tsx +0 -308
- package/src/theme/presets/rmx-01/index.ts +0 -123
- package/src/theme/runtime.ts +0 -119
- package/src/theme/theme.ts +0 -15
- package/src/utils/scroll-lock/README.md +0 -33
- /package/dist/{components/anchor/anchor.d.ts → anchor/index.d.ts} +0 -0
- /package/dist/{components/breadcrumbs/breadcrumbs.d.ts → breadcrumbs/index.d.ts} +0 -0
- /package/dist/{utils → listbox}/flash-attribute.d.ts +0 -0
- /package/dist/{utils → listbox}/flash-attribute.js +0 -0
- /package/dist/{components/menu → menu}/hover-aim.d.ts +0 -0
- /package/dist/{components/menu → menu}/hover-aim.js +0 -0
- /package/dist/{interactions/outside-click/outside-click-mixin.d.ts → popover/outside-click.d.ts} +0 -0
- /package/dist/{interactions/keydown → select}/keydown.d.ts +0 -0
- /package/dist/{interactions/keydown → select}/keydown.js +0 -0
- /package/dist/{interactions/typeahead/typeahead-mixin.d.ts → shared/typeahead.d.ts} +0 -0
- /package/dist/{utils → shared}/wait-for-css-transition.d.ts +0 -0
- /package/dist/{utils → shared}/wait-for-css-transition.js +0 -0
- /package/dist/{utils → shared}/wait.d.ts +0 -0
- /package/dist/{utils → shared}/wait.js +0 -0
- /package/src/{components/anchor/anchor.ts → anchor/index.ts} +0 -0
- /package/src/{utils → listbox}/flash-attribute.ts +0 -0
- /package/src/{components/menu → menu}/hover-aim.ts +0 -0
- /package/src/{interactions/outside-click/outside-click-mixin.ts → popover/outside-click.ts} +0 -0
- /package/src/{interactions/keydown → select}/keydown.ts +0 -0
- /package/src/{interactions/typeahead/typeahead-mixin.ts → shared/typeahead.ts} +0 -0
- /package/src/{utils → shared}/wait-for-css-transition.ts +0 -0
- /package/src/{utils → shared}/wait.ts +0 -0
package/src/runtime/frame.ts
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import { jsx } from './jsx.ts'
|
|
2
|
-
import { Frame, createFrameHandle, type FrameContent } from './component.ts'
|
|
2
|
+
import { Frame, createFrameHandle, type FrameContent, type FrameResolution } from './component.ts'
|
|
3
3
|
import { createComponentErrorEvent, getComponentError } from './error-event.ts'
|
|
4
4
|
import { invariant } from './invariant.ts'
|
|
5
5
|
import type { RemixElement, RemixNode } from './jsx.ts'
|
|
6
|
+
import type { ElementFunction } from './element-function.ts'
|
|
6
7
|
import type { FrameHandle } from './component.ts'
|
|
7
8
|
import type { Scheduler, VirtualRoot } from './vdom.ts'
|
|
8
9
|
import { createRangeRoot, createRoot } from './vdom.ts'
|
|
9
10
|
import { diffNodes } from './diff-dom.ts'
|
|
10
11
|
import { createStyleManager, type StyleManager } from '../style/index.ts'
|
|
11
12
|
import { findFlushMarker, type FlushKind } from './stream-protocol.ts'
|
|
13
|
+
import { unwrapFrameResolution } from './frame-resolution.ts'
|
|
14
|
+
import {
|
|
15
|
+
disposeClientEntryBoundary,
|
|
16
|
+
getClientEntryBoundaryOwner,
|
|
17
|
+
setClientEntryBoundaryOwner,
|
|
18
|
+
type ClientEntryIdentity,
|
|
19
|
+
} from './client-entry-boundary.ts'
|
|
12
20
|
|
|
13
21
|
type FrameRoot = [Comment, Comment] | Element | Document | DocumentFragment
|
|
14
22
|
|
|
@@ -62,24 +70,71 @@ export type LoadModule = (moduleUrl: string, exportName: string) => Promise<Func
|
|
|
62
70
|
* Resolves content for a browser-loaded frame.
|
|
63
71
|
*
|
|
64
72
|
* @param src Source string from the `<Frame src>` prop.
|
|
65
|
-
* @param
|
|
66
|
-
* @
|
|
67
|
-
* @returns HTML, a stream of HTML bytes, or Remix node content to render into the frame.
|
|
73
|
+
* @param options Information about the active frame load or form submission.
|
|
74
|
+
* @returns Frame content or a response whose body should be rendered into the frame.
|
|
68
75
|
*/
|
|
69
76
|
export type ResolveFrame = (
|
|
70
77
|
src: string,
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
78
|
+
options?: ResolveFrameOptions,
|
|
79
|
+
) => Promise<FrameResolution> | FrameResolution
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Information available while resolving browser-loaded frame content.
|
|
83
|
+
*/
|
|
84
|
+
export interface ResolveFrameOptions {
|
|
85
|
+
/** Optional name of the frame being loaded or reloaded. */
|
|
86
|
+
target?: string
|
|
87
|
+
/** Form values submitted to the frame source for a non-GET submission. */
|
|
88
|
+
formData?: FormData
|
|
89
|
+
/** HTTP method selected by the form and its submitter. */
|
|
90
|
+
method?: string
|
|
91
|
+
/** Form encoding selected by the form and its submitter. */
|
|
92
|
+
encType?: string
|
|
93
|
+
/** Aborts the reload when the navigation that started it is cancelled. */
|
|
94
|
+
signal?: AbortSignal
|
|
95
|
+
}
|
|
74
96
|
|
|
75
97
|
type InternalFrameContent = FrameContent | DocumentFragment
|
|
76
98
|
|
|
99
|
+
type FrameReloadOptions = Omit<ResolveFrameOptions, 'target'>
|
|
100
|
+
|
|
101
|
+
type FrameReloadResult = {
|
|
102
|
+
signal: AbortSignal
|
|
103
|
+
redirectedTo?: string
|
|
104
|
+
}
|
|
105
|
+
|
|
77
106
|
type FrameTemplateListener = (fragment: DocumentFragment) => void
|
|
78
107
|
|
|
79
108
|
const bufferedFrameTemplates = new Map<string, DocumentFragment[]>()
|
|
80
109
|
const frameTemplateListeners = new Map<string, Set<FrameTemplateListener>>()
|
|
81
110
|
const DOCTYPE_PATTERN = /<!doctype(?:\s[^>]*)?>/gi
|
|
82
111
|
|
|
112
|
+
function createLinkedAbortController(
|
|
113
|
+
first: AbortSignal,
|
|
114
|
+
second?: AbortSignal,
|
|
115
|
+
): { controller: AbortController; disconnect: () => void } {
|
|
116
|
+
let controller = new AbortController()
|
|
117
|
+
let signals = second ? [first, second] : [first]
|
|
118
|
+
let abort = () => controller.abort()
|
|
119
|
+
|
|
120
|
+
for (let signal of signals) {
|
|
121
|
+
if (signal.aborted) {
|
|
122
|
+
controller.abort()
|
|
123
|
+
break
|
|
124
|
+
}
|
|
125
|
+
signal.addEventListener('abort', abort, { once: true })
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return {
|
|
129
|
+
controller,
|
|
130
|
+
disconnect() {
|
|
131
|
+
for (let signal of signals) {
|
|
132
|
+
signal.removeEventListener('abort', abort)
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
83
138
|
function stripDoctypeMarkup(html: string): string {
|
|
84
139
|
return html.replace(DOCTYPE_PATTERN, '')
|
|
85
140
|
}
|
|
@@ -98,7 +153,11 @@ function syncElementAttributes(target: Element, source: Element) {
|
|
|
98
153
|
}
|
|
99
154
|
}
|
|
100
155
|
|
|
156
|
+
const FRAME_RUNTIME = Symbol('FrameRuntime')
|
|
157
|
+
|
|
101
158
|
export type FrameRuntime = {
|
|
159
|
+
[FRAME_RUNTIME]: true
|
|
160
|
+
canResolveFrames?: boolean
|
|
102
161
|
topFrame?: FrameHandle
|
|
103
162
|
errorTarget: EventTarget
|
|
104
163
|
loadModule: LoadModule
|
|
@@ -106,11 +165,34 @@ export type FrameRuntime = {
|
|
|
106
165
|
pendingClientEntries: PendingClientEntries
|
|
107
166
|
scheduler: Scheduler
|
|
108
167
|
styleManager: StyleManager
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
moduleLoads: Map<string, Promise<Function | undefined>>
|
|
168
|
+
moduleCache: Map<string, ElementFunction>
|
|
169
|
+
moduleLoads: Map<string, Promise<ElementFunction | undefined>>
|
|
112
170
|
frameInstances: WeakMap<Comment, Frame>
|
|
113
171
|
namedFrames: Map<string, FrameHandle>
|
|
172
|
+
serverFrameReload: { signal: AbortSignal } | undefined
|
|
173
|
+
reloadForNavigation?: (options?: FrameReloadOptions) => Promise<FrameReloadResult>
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
export function isFrameRuntime(value: unknown): value is FrameRuntime {
|
|
177
|
+
return isRecord(value) && Reflect.get(value, FRAME_RUNTIME) === true
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Reloads a frame and returns response metadata used by the navigation runtime.
|
|
182
|
+
*
|
|
183
|
+
* @param frame Frame handle to reload.
|
|
184
|
+
* @param options Form submission metadata and cancellation signal.
|
|
185
|
+
* @returns The reload signal and final response URL, when redirected.
|
|
186
|
+
*/
|
|
187
|
+
export function reloadFrameForNavigation(
|
|
188
|
+
frame: FrameHandle,
|
|
189
|
+
options?: FrameReloadOptions,
|
|
190
|
+
): Promise<FrameReloadResult> {
|
|
191
|
+
let runtime = frame.$runtime
|
|
192
|
+
invariant(isFrameRuntime(runtime), 'Expected a frame runtime')
|
|
193
|
+
let reload = runtime.reloadForNavigation
|
|
194
|
+
invariant(reload, 'Expected frame runtime to support navigation reloads')
|
|
195
|
+
return reload(options)
|
|
114
196
|
}
|
|
115
197
|
|
|
116
198
|
export type FrameContext = {
|
|
@@ -123,10 +205,11 @@ export type FrameContext = {
|
|
|
123
205
|
frame: FrameHandle
|
|
124
206
|
styleManager: StyleManager
|
|
125
207
|
data: RmxData
|
|
126
|
-
moduleCache: Map<string,
|
|
127
|
-
moduleLoads: Map<string, Promise<
|
|
208
|
+
moduleCache: Map<string, ElementFunction>
|
|
209
|
+
moduleLoads: Map<string, Promise<ElementFunction | undefined>>
|
|
128
210
|
frameInstances: WeakMap<Comment, Frame>
|
|
129
211
|
namedFrames: Map<string, FrameHandle>
|
|
212
|
+
lifecycleSignal: AbortSignal
|
|
130
213
|
regionTailRef?: ChildNode | null
|
|
131
214
|
regionParent?: ParentNode | null
|
|
132
215
|
signal?: AbortSignal
|
|
@@ -144,8 +227,8 @@ type FrameInit = {
|
|
|
144
227
|
styleManager?: StyleManager
|
|
145
228
|
marker?: FrameMarkerData
|
|
146
229
|
data: RmxData
|
|
147
|
-
moduleCache: Map<string,
|
|
148
|
-
moduleLoads: Map<string, Promise<
|
|
230
|
+
moduleCache: Map<string, ElementFunction>
|
|
231
|
+
moduleLoads: Map<string, Promise<ElementFunction | undefined>>
|
|
149
232
|
frameInstances: WeakMap<Comment, Frame>
|
|
150
233
|
namedFrames: Map<string, FrameHandle>
|
|
151
234
|
}
|
|
@@ -156,6 +239,11 @@ export type Frame = {
|
|
|
156
239
|
flush: () => void
|
|
157
240
|
clearPendingTemplateWatch: () => void
|
|
158
241
|
isDisplayingResolvedContent: () => boolean
|
|
242
|
+
beginClientFrameReloadForAncestorReload: (signal: AbortSignal) => {
|
|
243
|
+
controller: AbortController
|
|
244
|
+
complete: () => void
|
|
245
|
+
}
|
|
246
|
+
cancelReload: () => void
|
|
159
247
|
startInheritedReload: (signal?: AbortSignal) => void
|
|
160
248
|
updateMarker: (marker: FrameMarkerData, options?: RenderOptions) => Promise<void>
|
|
161
249
|
renderMarkerContent: (
|
|
@@ -163,6 +251,7 @@ export type Frame = {
|
|
|
163
251
|
content: InternalFrameContent,
|
|
164
252
|
options?: RenderOptions,
|
|
165
253
|
) => Promise<void>
|
|
254
|
+
matchesIdentity: (src: string, name: string | undefined) => boolean
|
|
166
255
|
dispose: () => void
|
|
167
256
|
handle: FrameHandle
|
|
168
257
|
}
|
|
@@ -172,12 +261,22 @@ type RenderOptions = {
|
|
|
172
261
|
initialHydrationTracker?: InitialHydrationTracker
|
|
173
262
|
signal?: AbortSignal
|
|
174
263
|
contentStatus?: 'pending' | 'resolved'
|
|
264
|
+
data?: RmxData
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
type ActiveRenderOptions = RenderOptions & {
|
|
268
|
+
data: RmxData
|
|
175
269
|
}
|
|
176
270
|
|
|
177
271
|
export function createFrame(root: FrameRoot, init: FrameInit): Frame {
|
|
178
272
|
let container = createContainer(root)
|
|
179
273
|
let contentRoot: VirtualRoot | undefined
|
|
180
274
|
let reloadController: AbortController | undefined
|
|
275
|
+
// The style registry is document-level and shared by every frame; only the
|
|
276
|
+
// frame that created it (the runtime root) disposes it.
|
|
277
|
+
let ownsStyleManager = !init.styleManager
|
|
278
|
+
let reloadAbortUnsubscribe: (() => void) | undefined
|
|
279
|
+
let reloadKind: 'direct' | 'ancestor' | undefined
|
|
181
280
|
let styleManager = init.styleManager ?? createStyleManager()
|
|
182
281
|
let currentMarker = init.marker
|
|
183
282
|
let displayedContentStatus: 'pending' | 'resolved' = init.marker?.status ?? 'resolved'
|
|
@@ -186,36 +285,18 @@ export function createFrame(root: FrameRoot, init: FrameInit): Frame {
|
|
|
186
285
|
let pendingTemplateUnsubscribe: (() => void) | undefined
|
|
187
286
|
let inheritedReloadPending = false
|
|
188
287
|
let inheritedReloadAbortUnsubscribe: (() => void) | undefined
|
|
288
|
+
let disposed = false
|
|
289
|
+
let lifecycleController = new AbortController()
|
|
189
290
|
|
|
190
291
|
// Merge any rmx-data found in the current document once at startup.
|
|
191
292
|
mergeRmxDataFromDocument(init.data, container.doc)
|
|
192
293
|
|
|
193
|
-
let runtime = createFrameRuntime({ ...init, styleManager })
|
|
294
|
+
let runtime = createFrameRuntime({ ...init, styleManager, reloadForNavigation: reload })
|
|
194
295
|
|
|
195
296
|
let frame = createFrameHandle({
|
|
196
297
|
src: init.src,
|
|
197
298
|
$runtime: runtime,
|
|
198
|
-
reload: async () =>
|
|
199
|
-
reloadController?.abort()
|
|
200
|
-
let controller = new AbortController()
|
|
201
|
-
reloadController = controller
|
|
202
|
-
frame.dispatchEvent(new Event('reloadStart'))
|
|
203
|
-
startSubFrameInheritedReloads(getContentNodes(), controller.signal)
|
|
204
|
-
try {
|
|
205
|
-
let content = await init.resolveFrame(frame.src, controller.signal, frameName)
|
|
206
|
-
if (reloadController !== controller || controller.signal.aborted) return controller.signal
|
|
207
|
-
await render(content, { signal: controller.signal })
|
|
208
|
-
return controller.signal
|
|
209
|
-
} catch (error) {
|
|
210
|
-
if (reloadController !== controller || controller.signal.aborted) return controller.signal
|
|
211
|
-
init.errorTarget.dispatchEvent(createComponentErrorEvent(error))
|
|
212
|
-
throw error
|
|
213
|
-
} finally {
|
|
214
|
-
if (reloadController === controller) {
|
|
215
|
-
frame.dispatchEvent(new Event('reloadComplete'))
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
},
|
|
299
|
+
reload: async () => (await reload()).signal,
|
|
219
300
|
replace: async (content: FrameContent) => {
|
|
220
301
|
await render(content)
|
|
221
302
|
},
|
|
@@ -241,18 +322,47 @@ export function createFrame(root: FrameRoot, init: FrameInit): Frame {
|
|
|
241
322
|
moduleLoads: init.moduleLoads,
|
|
242
323
|
frameInstances: init.frameInstances,
|
|
243
324
|
namedFrames: init.namedFrames,
|
|
325
|
+
lifecycleSignal: lifecycleController.signal,
|
|
244
326
|
regionTailRef: container.regionTailRef,
|
|
245
327
|
regionParent: container.regionParent,
|
|
246
328
|
}
|
|
247
329
|
|
|
248
330
|
async function render(content: InternalFrameContent, options?: RenderOptions): Promise<void> {
|
|
249
|
-
if (options?.signal?.aborted) return
|
|
331
|
+
if (disposed || lifecycleController.signal.aborted || options?.signal?.aborted) return
|
|
332
|
+
let ownsData = options?.data === undefined
|
|
333
|
+
let renderOptions: ActiveRenderOptions = {
|
|
334
|
+
...options,
|
|
335
|
+
data: options?.data ?? {},
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
try {
|
|
339
|
+
await renderContent(content, renderOptions)
|
|
340
|
+
} finally {
|
|
341
|
+
if (ownsData) clearRmxData(renderOptions.data)
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
async function renderContent(
|
|
346
|
+
content: InternalFrameContent,
|
|
347
|
+
options: ActiveRenderOptions,
|
|
348
|
+
): Promise<void> {
|
|
349
|
+
if (isRenderAborted(options.signal)) return
|
|
250
350
|
|
|
251
351
|
if (content instanceof ReadableStream) {
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
await
|
|
255
|
-
|
|
352
|
+
let linkedAbort = createLinkedAbortController(lifecycleController.signal, options.signal)
|
|
353
|
+
try {
|
|
354
|
+
await renderFrameStream(
|
|
355
|
+
content,
|
|
356
|
+
container.doc,
|
|
357
|
+
async (html, flushKind) => {
|
|
358
|
+
if (isRenderAborted(options.signal)) return
|
|
359
|
+
await render(html, { ...options, flushKind })
|
|
360
|
+
},
|
|
361
|
+
linkedAbort.controller.signal,
|
|
362
|
+
)
|
|
363
|
+
} finally {
|
|
364
|
+
linkedAbort.disconnect()
|
|
365
|
+
}
|
|
256
366
|
return
|
|
257
367
|
}
|
|
258
368
|
|
|
@@ -265,9 +375,9 @@ export function createFrame(root: FrameRoot, init: FrameInit): Frame {
|
|
|
265
375
|
contentRoot = createFrameContentRoot()
|
|
266
376
|
}
|
|
267
377
|
|
|
268
|
-
if (options
|
|
378
|
+
if (isRenderAborted(options.signal)) return
|
|
269
379
|
contentRoot.render(content)
|
|
270
|
-
displayedContentStatus = options
|
|
380
|
+
displayedContentStatus = options.contentStatus ?? 'resolved'
|
|
271
381
|
return
|
|
272
382
|
}
|
|
273
383
|
|
|
@@ -293,61 +403,81 @@ export function createFrame(root: FrameRoot, init: FrameInit): Frame {
|
|
|
293
403
|
let isFullDocumentReload =
|
|
294
404
|
container.root instanceof Document &&
|
|
295
405
|
htmlContent !== undefined &&
|
|
296
|
-
options
|
|
406
|
+
options.flushKind === 'document'
|
|
297
407
|
|
|
298
408
|
if (isFullDocumentReload && htmlContent !== undefined) {
|
|
299
409
|
let parsed = new DOMParser().parseFromString(htmlContent, 'text/html')
|
|
300
|
-
|
|
301
|
-
|
|
410
|
+
let responseData = options.data
|
|
411
|
+
mergeRmxDataFromDocument(responseData, parsed)
|
|
412
|
+
let responseContext = { ...context, data: responseData }
|
|
413
|
+
context.styleManager.adoptServerStyles(
|
|
302
414
|
collectFrameServerStyleTags(createElementContainer(parsed)),
|
|
303
415
|
)
|
|
304
416
|
|
|
305
417
|
syncElementAttributes(container.doc.documentElement, parsed.documentElement)
|
|
306
418
|
|
|
307
419
|
diffNodes([container.doc.head], [parsed.head], {
|
|
308
|
-
...
|
|
420
|
+
...responseContext,
|
|
309
421
|
regionParent: container.doc.documentElement,
|
|
310
422
|
regionTailRef: null,
|
|
311
|
-
signal: options
|
|
423
|
+
signal: options.signal,
|
|
312
424
|
})
|
|
313
425
|
diffNodes([container.doc.body], [parsed.body], {
|
|
314
|
-
...
|
|
426
|
+
...responseContext,
|
|
315
427
|
regionParent: container.doc.documentElement,
|
|
316
428
|
regionTailRef: null,
|
|
317
|
-
signal: options
|
|
429
|
+
signal: options.signal,
|
|
318
430
|
})
|
|
319
431
|
|
|
320
432
|
let bodyContainer = createElementContainer(container.doc.body)
|
|
321
|
-
if (options
|
|
322
|
-
scheduleHydrationInContainer(
|
|
323
|
-
|
|
324
|
-
|
|
433
|
+
if (isRenderAborted(options.signal)) return
|
|
434
|
+
scheduleHydrationInContainer(
|
|
435
|
+
bodyContainer,
|
|
436
|
+
responseContext,
|
|
437
|
+
options.initialHydrationTracker,
|
|
438
|
+
options.signal,
|
|
439
|
+
)
|
|
440
|
+
await createSubFrames(bodyContainer.childNodes, responseContext, options)
|
|
441
|
+
if (isRenderAborted(options.signal)) return
|
|
442
|
+
displayedContentStatus = options.contentStatus ?? 'resolved'
|
|
325
443
|
return
|
|
326
444
|
}
|
|
327
445
|
|
|
328
446
|
let fragment =
|
|
329
447
|
htmlContent !== undefined ? createFragmentFromString(container.doc, htmlContent) : content
|
|
330
|
-
context.styleManager.
|
|
448
|
+
context.styleManager.adoptServerStyles(
|
|
331
449
|
collectFrameServerStyleTags(createElementContainer(fragment)),
|
|
332
450
|
)
|
|
333
451
|
removeEmptyHeads(fragment)
|
|
334
|
-
|
|
452
|
+
let responseData = options.data
|
|
453
|
+
mergeRmxDataFromFragment(responseData, fragment)
|
|
454
|
+
let responseContext = { ...context, data: responseData }
|
|
335
455
|
|
|
336
456
|
let nextContainer = createContainer(fragment)
|
|
337
457
|
|
|
338
|
-
if (options
|
|
458
|
+
if (isRenderAborted(options.signal)) return
|
|
339
459
|
|
|
340
460
|
diffNodes(container.childNodes, Array.from(nextContainer.childNodes), {
|
|
341
|
-
...
|
|
461
|
+
...responseContext,
|
|
342
462
|
regionTailRef: container.regionTailRef,
|
|
343
463
|
regionParent: container.regionParent,
|
|
344
|
-
signal: options
|
|
464
|
+
signal: options.signal,
|
|
345
465
|
})
|
|
346
466
|
|
|
347
|
-
if (options
|
|
348
|
-
scheduleHydrationInContainer(
|
|
349
|
-
|
|
350
|
-
|
|
467
|
+
if (isRenderAborted(options.signal)) return
|
|
468
|
+
scheduleHydrationInContainer(
|
|
469
|
+
container,
|
|
470
|
+
responseContext,
|
|
471
|
+
options.initialHydrationTracker,
|
|
472
|
+
options.signal,
|
|
473
|
+
)
|
|
474
|
+
await createSubFrames(container.childNodes, responseContext, options)
|
|
475
|
+
if (isRenderAborted(options.signal)) return
|
|
476
|
+
displayedContentStatus = options.contentStatus ?? 'resolved'
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
function isRenderAborted(signal?: AbortSignal): boolean {
|
|
480
|
+
return disposed || lifecycleController.signal.aborted || signal?.aborted === true
|
|
351
481
|
}
|
|
352
482
|
|
|
353
483
|
function createFrameContentRoot(): VirtualRoot {
|
|
@@ -390,21 +520,36 @@ export function createFrame(root: FrameRoot, init: FrameInit): Frame {
|
|
|
390
520
|
async function hydrateInitial(): Promise<void> {
|
|
391
521
|
let initialHydrationTracker = createInitialHydrationTracker()
|
|
392
522
|
|
|
393
|
-
context.styleManager.
|
|
394
|
-
|
|
523
|
+
context.styleManager.adoptServerStyles(collectFrameServerStyleTags(container))
|
|
524
|
+
let subFramesReady = createSubFrames(container.childNodes, context)
|
|
395
525
|
scheduleHydrationInContainer(container, context, initialHydrationTracker)
|
|
396
526
|
|
|
397
|
-
|
|
398
|
-
await
|
|
399
|
-
|
|
527
|
+
try {
|
|
528
|
+
await subFramesReady
|
|
529
|
+
|
|
530
|
+
if (disposed || context.lifecycleSignal.aborted) return
|
|
531
|
+
|
|
532
|
+
if (currentMarker?.status === 'pending') {
|
|
533
|
+
await watchPendingFrameTemplate(currentMarker, initialHydrationTracker)
|
|
534
|
+
}
|
|
400
535
|
|
|
401
|
-
|
|
402
|
-
|
|
536
|
+
initialHydrationTracker.finalize()
|
|
537
|
+
await initialHydrationTracker.ready()
|
|
538
|
+
} finally {
|
|
539
|
+
clearRmxData(context.data)
|
|
540
|
+
}
|
|
403
541
|
}
|
|
404
542
|
|
|
405
543
|
function dispose(): void {
|
|
544
|
+
if (disposed) return
|
|
545
|
+
disposed = true
|
|
546
|
+
lifecycleController.abort()
|
|
547
|
+
clearRmxData(context.data)
|
|
406
548
|
reloadController?.abort()
|
|
407
549
|
reloadController = undefined
|
|
550
|
+
reloadAbortUnsubscribe?.()
|
|
551
|
+
reloadAbortUnsubscribe = undefined
|
|
552
|
+
reloadKind = undefined
|
|
408
553
|
contentRoot?.dispose()
|
|
409
554
|
contentRoot = undefined
|
|
410
555
|
clearPendingFrameTemplateWatch()
|
|
@@ -414,7 +559,9 @@ export function createFrame(root: FrameRoot, init: FrameInit): Frame {
|
|
|
414
559
|
|
|
415
560
|
// Dispose sub-frames recursively.
|
|
416
561
|
disposeSubFrames(container.childNodes, context)
|
|
417
|
-
|
|
562
|
+
if (ownsStyleManager) {
|
|
563
|
+
context.styleManager.dispose()
|
|
564
|
+
}
|
|
418
565
|
|
|
419
566
|
if (frameName) {
|
|
420
567
|
if (init.namedFrames.get(frameName) === frame) {
|
|
@@ -431,15 +578,18 @@ export function createFrame(root: FrameRoot, init: FrameInit): Frame {
|
|
|
431
578
|
flush: () => context.scheduler.dequeue(),
|
|
432
579
|
clearPendingTemplateWatch: clearPendingFrameTemplateWatch,
|
|
433
580
|
isDisplayingResolvedContent: () => displayedContentStatus === 'resolved',
|
|
581
|
+
beginClientFrameReloadForAncestorReload,
|
|
582
|
+
cancelReload,
|
|
434
583
|
startInheritedReload,
|
|
435
584
|
updateMarker,
|
|
436
585
|
renderMarkerContent,
|
|
586
|
+
matchesIdentity: (src, name) => !disposed && frame.src === src && frameName === name,
|
|
437
587
|
dispose,
|
|
438
588
|
handle: frame,
|
|
439
589
|
}
|
|
440
590
|
|
|
441
591
|
async function updateMarker(marker: FrameMarkerData, options?: RenderOptions): Promise<void> {
|
|
442
|
-
if (options?.signal?.aborted) return
|
|
592
|
+
if (disposed || context.lifecycleSignal.aborted || options?.signal?.aborted) return
|
|
443
593
|
let previousMarker = currentMarker
|
|
444
594
|
let isInheritedReload = previousMarker !== undefined && previousMarker.id !== marker.id
|
|
445
595
|
currentMarker = marker
|
|
@@ -472,7 +622,7 @@ export function createFrame(root: FrameRoot, init: FrameInit): Frame {
|
|
|
472
622
|
content: InternalFrameContent,
|
|
473
623
|
options?: RenderOptions,
|
|
474
624
|
): Promise<void> {
|
|
475
|
-
if (options?.signal?.aborted) return
|
|
625
|
+
if (disposed || context.lifecycleSignal.aborted || options?.signal?.aborted) return
|
|
476
626
|
let previousMarker = currentMarker
|
|
477
627
|
let isInheritedReload = previousMarker !== undefined && previousMarker.id !== marker.id
|
|
478
628
|
currentMarker = marker
|
|
@@ -484,11 +634,119 @@ export function createFrame(root: FrameRoot, init: FrameInit): Frame {
|
|
|
484
634
|
clearPendingFrameTemplateWatch()
|
|
485
635
|
await render(content, { ...options, contentStatus: 'resolved' })
|
|
486
636
|
|
|
487
|
-
if (
|
|
637
|
+
if (
|
|
638
|
+
isInheritedReload &&
|
|
639
|
+
!disposed &&
|
|
640
|
+
!context.lifecycleSignal.aborted &&
|
|
641
|
+
!options?.signal?.aborted
|
|
642
|
+
) {
|
|
488
643
|
completeInheritedReload()
|
|
489
644
|
}
|
|
490
645
|
}
|
|
491
646
|
|
|
647
|
+
async function reload(options?: FrameReloadOptions): Promise<FrameReloadResult> {
|
|
648
|
+
let controller = startReload(options?.signal)
|
|
649
|
+
return await resolveAndRenderReload(controller, options)
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
function startReload(signal?: AbortSignal): AbortController {
|
|
653
|
+
let controller = replaceReloadController(signal)
|
|
654
|
+
reloadKind = 'direct'
|
|
655
|
+
frame.dispatchEvent(new Event('reloadStart'))
|
|
656
|
+
startSubFrameInheritedReloads(getContentNodes(), controller.signal)
|
|
657
|
+
return controller
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
function beginClientFrameReloadForAncestorReload(signal: AbortSignal): {
|
|
661
|
+
controller: AbortController
|
|
662
|
+
complete: () => void
|
|
663
|
+
} {
|
|
664
|
+
let inheritedReloadStarted = reuseInheritedReloadStart()
|
|
665
|
+
let continuingAncestorReload = reloadKind === 'ancestor'
|
|
666
|
+
let controller = replaceReloadController(signal)
|
|
667
|
+
reloadKind = 'ancestor'
|
|
668
|
+
|
|
669
|
+
if (!inheritedReloadStarted && !continuingAncestorReload) {
|
|
670
|
+
frame.dispatchEvent(new Event('reloadStart'))
|
|
671
|
+
startSubFrameInheritedReloads(getContentNodes(), controller.signal)
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
return {
|
|
675
|
+
controller,
|
|
676
|
+
complete: () => completeReload(controller),
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
function cancelReload(): void {
|
|
681
|
+
let controller = reloadController
|
|
682
|
+
if (!controller) return
|
|
683
|
+
controller.abort()
|
|
684
|
+
completeReload(controller)
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
function replaceReloadController(signal?: AbortSignal): AbortController {
|
|
688
|
+
reloadController?.abort()
|
|
689
|
+
reloadAbortUnsubscribe?.()
|
|
690
|
+
reloadAbortUnsubscribe = undefined
|
|
691
|
+
|
|
692
|
+
let controller = new AbortController()
|
|
693
|
+
reloadController = controller
|
|
694
|
+
|
|
695
|
+
if (signal) {
|
|
696
|
+
if (signal.aborted) {
|
|
697
|
+
controller.abort()
|
|
698
|
+
} else {
|
|
699
|
+
let abort = () => controller.abort()
|
|
700
|
+
signal.addEventListener('abort', abort, { once: true })
|
|
701
|
+
reloadAbortUnsubscribe = () => signal.removeEventListener('abort', abort)
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
return controller
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
async function resolveAndRenderReload(
|
|
709
|
+
controller: AbortController,
|
|
710
|
+
options?: FrameReloadOptions,
|
|
711
|
+
): Promise<FrameReloadResult> {
|
|
712
|
+
try {
|
|
713
|
+
let resolution = await init.resolveFrame(frame.src, {
|
|
714
|
+
...options,
|
|
715
|
+
signal: controller.signal,
|
|
716
|
+
target: frameName,
|
|
717
|
+
})
|
|
718
|
+
if (reloadController !== controller || controller.signal.aborted) {
|
|
719
|
+
return { signal: controller.signal }
|
|
720
|
+
}
|
|
721
|
+
let { content, redirectedTo } = await unwrapFrameResolution(resolution)
|
|
722
|
+
if (reloadController !== controller || controller.signal.aborted) {
|
|
723
|
+
return { signal: controller.signal }
|
|
724
|
+
}
|
|
725
|
+
await render(content, { signal: controller.signal })
|
|
726
|
+
return {
|
|
727
|
+
signal: controller.signal,
|
|
728
|
+
redirectedTo:
|
|
729
|
+
reloadController === controller && !controller.signal.aborted ? redirectedTo : undefined,
|
|
730
|
+
}
|
|
731
|
+
} catch (error) {
|
|
732
|
+
if (reloadController !== controller || controller.signal.aborted) {
|
|
733
|
+
return { signal: controller.signal }
|
|
734
|
+
}
|
|
735
|
+
init.errorTarget.dispatchEvent(createComponentErrorEvent(error))
|
|
736
|
+
throw error
|
|
737
|
+
} finally {
|
|
738
|
+
completeReload(controller)
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
function completeReload(controller: AbortController): void {
|
|
743
|
+
if (reloadController !== controller || reloadKind === undefined) return
|
|
744
|
+
reloadAbortUnsubscribe?.()
|
|
745
|
+
reloadAbortUnsubscribe = undefined
|
|
746
|
+
reloadKind = undefined
|
|
747
|
+
frame.dispatchEvent(new Event('reloadComplete'))
|
|
748
|
+
}
|
|
749
|
+
|
|
492
750
|
function startInheritedReload(signal?: AbortSignal): void {
|
|
493
751
|
if (signal?.aborted) return
|
|
494
752
|
if (!inheritedReloadPending) {
|
|
@@ -508,6 +766,14 @@ export function createFrame(root: FrameRoot, init: FrameInit): Frame {
|
|
|
508
766
|
}
|
|
509
767
|
}
|
|
510
768
|
|
|
769
|
+
function reuseInheritedReloadStart(): boolean {
|
|
770
|
+
if (!inheritedReloadPending) return false
|
|
771
|
+
inheritedReloadPending = false
|
|
772
|
+
inheritedReloadAbortUnsubscribe?.()
|
|
773
|
+
inheritedReloadAbortUnsubscribe = undefined
|
|
774
|
+
return true
|
|
775
|
+
}
|
|
776
|
+
|
|
511
777
|
function completeInheritedReload(): void {
|
|
512
778
|
if (!inheritedReloadPending) return
|
|
513
779
|
inheritedReloadPending = false
|
|
@@ -525,7 +791,7 @@ export function createFrame(root: FrameRoot, init: FrameInit): Frame {
|
|
|
525
791
|
if (isFrameStart(node)) {
|
|
526
792
|
let end = findEndMarker(node, isFrameStart, isFrameEnd)
|
|
527
793
|
context.frameInstances.get(node)?.startInheritedReload(signal)
|
|
528
|
-
i = nodes
|
|
794
|
+
i = findMarkerRangeEndIndex(nodes, end, i)
|
|
529
795
|
continue
|
|
530
796
|
}
|
|
531
797
|
|
|
@@ -549,7 +815,7 @@ export function createFrame(root: FrameRoot, init: FrameInit): Frame {
|
|
|
549
815
|
signal?: AbortSignal,
|
|
550
816
|
onResolved?: () => void,
|
|
551
817
|
): Promise<void> {
|
|
552
|
-
if (signal?.aborted) return
|
|
818
|
+
if (disposed || context.lifecycleSignal.aborted || signal?.aborted) return
|
|
553
819
|
if (pendingTemplateMarkerId === marker.id) return
|
|
554
820
|
|
|
555
821
|
clearPendingFrameTemplateWatch()
|
|
@@ -559,11 +825,11 @@ export function createFrame(root: FrameRoot, init: FrameInit): Frame {
|
|
|
559
825
|
if (early) {
|
|
560
826
|
clearPendingFrameTemplateWatch()
|
|
561
827
|
await render(early, { initialHydrationTracker, signal, contentStatus: 'resolved' })
|
|
562
|
-
if (!signal?.aborted) onResolved?.()
|
|
828
|
+
if (!disposed && !context.lifecycleSignal.aborted && !signal?.aborted) onResolved?.()
|
|
563
829
|
return
|
|
564
830
|
}
|
|
565
831
|
|
|
566
|
-
if (signal?.aborted) {
|
|
832
|
+
if (disposed || context.lifecycleSignal.aborted || signal?.aborted) {
|
|
567
833
|
clearPendingFrameTemplateWatch()
|
|
568
834
|
return
|
|
569
835
|
}
|
|
@@ -571,11 +837,11 @@ export function createFrame(root: FrameRoot, init: FrameInit): Frame {
|
|
|
571
837
|
let observer = setupTemplateObserver()
|
|
572
838
|
pendingTemplateObserver = observer
|
|
573
839
|
let unsubscribe = subscribeFrameTemplate(marker.id, async (fragment) => {
|
|
574
|
-
if (signal?.aborted) return
|
|
840
|
+
if (disposed || context.lifecycleSignal.aborted || signal?.aborted) return
|
|
575
841
|
if (pendingTemplateMarkerId !== marker.id) return
|
|
576
842
|
clearPendingFrameTemplateWatch()
|
|
577
843
|
await render(fragment, { signal, contentStatus: 'resolved' })
|
|
578
|
-
if (!signal?.aborted) onResolved?.()
|
|
844
|
+
if (!disposed && !context.lifecycleSignal.aborted && !signal?.aborted) onResolved?.()
|
|
579
845
|
})
|
|
580
846
|
pendingTemplateUnsubscribe = unsubscribe
|
|
581
847
|
|
|
@@ -593,7 +859,7 @@ export function createFrame(root: FrameRoot, init: FrameInit): Frame {
|
|
|
593
859
|
if (buffered) {
|
|
594
860
|
clearPendingFrameTemplateWatch()
|
|
595
861
|
await render(buffered, { initialHydrationTracker, signal, contentStatus: 'resolved' })
|
|
596
|
-
if (!signal?.aborted) onResolved?.()
|
|
862
|
+
if (!disposed && !context.lifecycleSignal.aborted && !signal?.aborted) onResolved?.()
|
|
597
863
|
}
|
|
598
864
|
}
|
|
599
865
|
}
|
|
@@ -606,13 +872,14 @@ export function createFrameRuntime(init: {
|
|
|
606
872
|
pendingClientEntries: PendingClientEntries
|
|
607
873
|
scheduler: Scheduler
|
|
608
874
|
styleManager: StyleManager
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
moduleLoads: Map<string, Promise<Function | undefined>>
|
|
875
|
+
moduleCache: Map<string, ElementFunction>
|
|
876
|
+
moduleLoads: Map<string, Promise<ElementFunction | undefined>>
|
|
612
877
|
frameInstances: WeakMap<Comment, Frame>
|
|
613
878
|
namedFrames: Map<string, FrameHandle>
|
|
879
|
+
reloadForNavigation?: (options?: FrameReloadOptions) => Promise<FrameReloadResult>
|
|
614
880
|
}): FrameRuntime {
|
|
615
881
|
return {
|
|
882
|
+
[FRAME_RUNTIME]: true,
|
|
616
883
|
topFrame: init.topFrame,
|
|
617
884
|
errorTarget: init.errorTarget,
|
|
618
885
|
loadModule: init.loadModule,
|
|
@@ -620,11 +887,12 @@ export function createFrameRuntime(init: {
|
|
|
620
887
|
pendingClientEntries: init.pendingClientEntries,
|
|
621
888
|
scheduler: init.scheduler,
|
|
622
889
|
styleManager: init.styleManager,
|
|
623
|
-
data: init.data,
|
|
624
890
|
moduleCache: init.moduleCache,
|
|
625
891
|
moduleLoads: init.moduleLoads,
|
|
626
892
|
frameInstances: init.frameInstances,
|
|
627
893
|
namedFrames: init.namedFrames,
|
|
894
|
+
serverFrameReload: undefined,
|
|
895
|
+
reloadForNavigation: init.reloadForNavigation,
|
|
628
896
|
}
|
|
629
897
|
}
|
|
630
898
|
|
|
@@ -689,6 +957,11 @@ function mergeRmxDataFromFragment(into: RmxData, fragment: DocumentFragment): vo
|
|
|
689
957
|
}
|
|
690
958
|
}
|
|
691
959
|
|
|
960
|
+
function clearRmxData(data: RmxData): void {
|
|
961
|
+
delete data.h
|
|
962
|
+
delete data.f
|
|
963
|
+
}
|
|
964
|
+
|
|
692
965
|
function removeEmptyHeads(fragment: DocumentFragment): void {
|
|
693
966
|
let heads = Array.from(fragment.querySelectorAll('head'))
|
|
694
967
|
for (let head of heads) {
|
|
@@ -715,7 +988,7 @@ function collectOwnedServerStyleTags(nodes: Node[], styles: HTMLStyleElement[]):
|
|
|
715
988
|
|
|
716
989
|
if (isFrameStart(node)) {
|
|
717
990
|
let end = findEndMarker(node, isFrameStart, isFrameEnd)
|
|
718
|
-
i = nodes
|
|
991
|
+
i = findMarkerRangeEndIndex(nodes, end, i)
|
|
719
992
|
continue
|
|
720
993
|
}
|
|
721
994
|
|
|
@@ -724,7 +997,7 @@ function collectOwnedServerStyleTags(nodes: Node[], styles: HTMLStyleElement[]):
|
|
|
724
997
|
continue
|
|
725
998
|
}
|
|
726
999
|
|
|
727
|
-
if (node
|
|
1000
|
+
if (node.childNodes.length > 0) {
|
|
728
1001
|
collectOwnedServerStyleTags(Array.from(node.childNodes), styles)
|
|
729
1002
|
}
|
|
730
1003
|
}
|
|
@@ -763,6 +1036,7 @@ function scheduleHydrationInContainer(
|
|
|
763
1036
|
container: FrameContainer,
|
|
764
1037
|
context: FrameContext,
|
|
765
1038
|
initialHydrationTracker?: InitialHydrationTracker,
|
|
1039
|
+
signal?: AbortSignal,
|
|
766
1040
|
): void {
|
|
767
1041
|
let hydrationMarkers = findHydrationMarkers(container)
|
|
768
1042
|
if (hydrationMarkers.length === 0) return
|
|
@@ -773,7 +1047,7 @@ function scheduleHydrationInContainer(
|
|
|
773
1047
|
for (let marker of hydrationMarkers) {
|
|
774
1048
|
let entry = hydrationData[marker.id]
|
|
775
1049
|
if (!entry) continue
|
|
776
|
-
scheduleHydrationMarker(marker, entry, context, initialHydrationTracker)
|
|
1050
|
+
scheduleHydrationMarker(marker, entry, context, initialHydrationTracker, signal)
|
|
777
1051
|
}
|
|
778
1052
|
}
|
|
779
1053
|
|
|
@@ -782,49 +1056,74 @@ function scheduleHydrationMarker(
|
|
|
782
1056
|
entry: HydrationData,
|
|
783
1057
|
context: FrameContext,
|
|
784
1058
|
initialHydrationTracker?: InitialHydrationTracker,
|
|
1059
|
+
signal?: AbortSignal,
|
|
785
1060
|
): void {
|
|
1061
|
+
if (signal?.aborted || context.lifecycleSignal.aborted) return
|
|
1062
|
+
|
|
786
1063
|
let done = initialHydrationTracker?.track()
|
|
787
1064
|
let key = `${entry.moduleUrl}#${entry.exportName}`
|
|
1065
|
+
let identity: ClientEntryIdentity = {
|
|
1066
|
+
moduleUrl: entry.moduleUrl,
|
|
1067
|
+
exportName: entry.exportName,
|
|
1068
|
+
}
|
|
1069
|
+
let props: Record<string, unknown> | undefined = entry.props
|
|
1070
|
+
let completed = false
|
|
1071
|
+
|
|
1072
|
+
let complete = () => {
|
|
1073
|
+
if (completed) return
|
|
1074
|
+
completed = true
|
|
1075
|
+
props = undefined
|
|
1076
|
+
signal?.removeEventListener('abort', complete)
|
|
1077
|
+
context.lifecycleSignal.removeEventListener('abort', complete)
|
|
1078
|
+
done?.()
|
|
1079
|
+
}
|
|
1080
|
+
|
|
1081
|
+
signal?.addEventListener('abort', complete, { once: true })
|
|
1082
|
+
context.lifecycleSignal.addEventListener('abort', complete, { once: true })
|
|
788
1083
|
|
|
789
|
-
let hydrateWithComponent = (component:
|
|
1084
|
+
let hydrateWithComponent = (component: ElementFunction) => {
|
|
1085
|
+
if (signal?.aborted || context.lifecycleSignal.aborted) return
|
|
790
1086
|
if (!isHydrationMarkerLive(marker, context)) return
|
|
791
|
-
|
|
1087
|
+
if (!props) return
|
|
1088
|
+
let vElement = createElement(component, props)
|
|
792
1089
|
context.pendingClientEntries.set(marker.start, [marker.end, vElement])
|
|
793
|
-
hydrateRegion(vElement, marker.start, marker.end, context)
|
|
1090
|
+
hydrateRegion(vElement, marker.start, marker.end, identity, context, signal)
|
|
794
1091
|
}
|
|
795
1092
|
|
|
796
1093
|
let cached = context.moduleCache.get(key)
|
|
797
1094
|
if (cached) {
|
|
798
1095
|
hydrateWithComponent(cached)
|
|
799
|
-
|
|
1096
|
+
complete()
|
|
800
1097
|
return
|
|
801
1098
|
}
|
|
802
1099
|
|
|
803
|
-
getOrStartModuleLoad(key,
|
|
1100
|
+
getOrStartModuleLoad(key, identity, marker.id, context)
|
|
804
1101
|
.then((component) => {
|
|
805
1102
|
if (component) {
|
|
806
1103
|
hydrateWithComponent(component)
|
|
807
1104
|
}
|
|
808
1105
|
})
|
|
809
1106
|
.finally(() => {
|
|
810
|
-
|
|
1107
|
+
complete()
|
|
811
1108
|
})
|
|
812
1109
|
}
|
|
813
1110
|
|
|
814
1111
|
function getOrStartModuleLoad(
|
|
815
1112
|
key: string,
|
|
816
|
-
|
|
1113
|
+
identity: ClientEntryIdentity,
|
|
817
1114
|
markerId: string,
|
|
818
1115
|
context: FrameContext,
|
|
819
|
-
): Promise<
|
|
1116
|
+
): Promise<ElementFunction | undefined> {
|
|
820
1117
|
let inFlight = context.moduleLoads.get(key)
|
|
821
1118
|
if (inFlight) return inFlight
|
|
822
1119
|
|
|
823
1120
|
let loadPromise = (async () => {
|
|
824
1121
|
try {
|
|
825
|
-
let mod = await context.loadModule(
|
|
826
|
-
if (
|
|
827
|
-
throw new Error(
|
|
1122
|
+
let mod = await context.loadModule(identity.moduleUrl, identity.exportName)
|
|
1123
|
+
if (!isElementFunction(mod)) {
|
|
1124
|
+
throw new Error(
|
|
1125
|
+
`Export "${identity.exportName}" from "${identity.moduleUrl}" is not a function`,
|
|
1126
|
+
)
|
|
828
1127
|
}
|
|
829
1128
|
context.moduleCache.set(key, mod)
|
|
830
1129
|
return mod
|
|
@@ -840,9 +1139,14 @@ function getOrStartModuleLoad(
|
|
|
840
1139
|
return loadPromise
|
|
841
1140
|
}
|
|
842
1141
|
|
|
843
|
-
function createElement(component:
|
|
1142
|
+
function createElement(component: ElementFunction, props: Record<string, unknown>): RemixElement {
|
|
844
1143
|
let revivedProps = reviveSerializedValue(props)
|
|
845
|
-
|
|
1144
|
+
invariant(isRecord(revivedProps), 'Expected revived component props to be an object')
|
|
1145
|
+
return jsx(component, revivedProps)
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
function isElementFunction(value: unknown): value is ElementFunction {
|
|
1149
|
+
return typeof value === 'function'
|
|
846
1150
|
}
|
|
847
1151
|
|
|
848
1152
|
function reviveSerializedValue(value: unknown): unknown {
|
|
@@ -853,18 +1157,19 @@ function reviveSerializedValue(value: unknown): unknown {
|
|
|
853
1157
|
return value.map((item) => reviveSerializedValue(item))
|
|
854
1158
|
}
|
|
855
1159
|
|
|
856
|
-
|
|
1160
|
+
if (!isRecord(value)) return value
|
|
1161
|
+
let record = value
|
|
857
1162
|
|
|
858
1163
|
if (record.$rmxFrame === true) {
|
|
859
1164
|
let props = reviveSerializedObject(record.props)
|
|
860
1165
|
let key = reviveSerializedValue(record.key)
|
|
861
|
-
return jsx(Frame
|
|
1166
|
+
return jsx(Frame, props, key)
|
|
862
1167
|
}
|
|
863
1168
|
|
|
864
1169
|
if (record.$rmx === true && typeof record.type === 'string') {
|
|
865
1170
|
let props = reviveSerializedObject(record.props)
|
|
866
1171
|
let key = reviveSerializedValue(record.key)
|
|
867
|
-
return jsx(record.type
|
|
1172
|
+
return jsx(record.type, props, key)
|
|
868
1173
|
}
|
|
869
1174
|
|
|
870
1175
|
let revived: Record<string, unknown> = {}
|
|
@@ -878,22 +1183,49 @@ function reviveSerializedObject(value: unknown): Record<string, unknown> {
|
|
|
878
1183
|
if (!value || typeof value !== 'object' || Array.isArray(value)) return {}
|
|
879
1184
|
let revived = reviveSerializedValue(value)
|
|
880
1185
|
if (!revived || typeof revived !== 'object' || Array.isArray(revived)) return {}
|
|
881
|
-
return revived
|
|
1186
|
+
return isRecord(revived) ? revived : {}
|
|
1187
|
+
}
|
|
1188
|
+
|
|
1189
|
+
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
1190
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
882
1191
|
}
|
|
883
1192
|
|
|
884
1193
|
function hydrateRegion(
|
|
885
1194
|
vElement: RemixElement,
|
|
886
1195
|
start: Comment,
|
|
887
1196
|
end: Comment,
|
|
1197
|
+
identity: ClientEntryIdentity,
|
|
888
1198
|
context: FrameContext,
|
|
1199
|
+
signal?: AbortSignal,
|
|
889
1200
|
): void {
|
|
1201
|
+
if (signal?.aborted) return
|
|
1202
|
+
|
|
890
1203
|
context.pendingClientEntries.delete(start)
|
|
891
1204
|
|
|
892
1205
|
// The same marker can be discovered by overlapping hydration passes
|
|
893
1206
|
// (for example, document root + nested frame root). Reuse the existing
|
|
894
1207
|
// virtual root instead of redefining the marker property.
|
|
895
|
-
|
|
896
|
-
|
|
1208
|
+
let owner = getClientEntryBoundaryOwner(start)
|
|
1209
|
+
if (owner) {
|
|
1210
|
+
if (!signal) {
|
|
1211
|
+
owner.root.render(vElement)
|
|
1212
|
+
return
|
|
1213
|
+
}
|
|
1214
|
+
|
|
1215
|
+
let frameRuntime = context.frame.$runtime
|
|
1216
|
+
invariant(
|
|
1217
|
+
isFrameRuntime(frameRuntime),
|
|
1218
|
+
'Expected frame runtime while rendering a preserved client entry',
|
|
1219
|
+
)
|
|
1220
|
+
|
|
1221
|
+
let previousServerFrameReload = frameRuntime.serverFrameReload
|
|
1222
|
+
|
|
1223
|
+
frameRuntime.serverFrameReload = { signal }
|
|
1224
|
+
try {
|
|
1225
|
+
owner.root.render(vElement)
|
|
1226
|
+
} finally {
|
|
1227
|
+
frameRuntime.serverFrameReload = previousServerFrameReload
|
|
1228
|
+
}
|
|
897
1229
|
return
|
|
898
1230
|
}
|
|
899
1231
|
|
|
@@ -907,7 +1239,7 @@ function hydrateRegion(
|
|
|
907
1239
|
context.errorTarget.dispatchEvent(createComponentErrorEvent(getComponentError(event)))
|
|
908
1240
|
})
|
|
909
1241
|
|
|
910
|
-
|
|
1242
|
+
setClientEntryBoundaryOwner(start, identity, root)
|
|
911
1243
|
root.render(vElement)
|
|
912
1244
|
}
|
|
913
1245
|
|
|
@@ -948,6 +1280,7 @@ async function createSubFrames(
|
|
|
948
1280
|
resolveFrame: context.resolveFrame,
|
|
949
1281
|
pendingClientEntries: context.pendingClientEntries,
|
|
950
1282
|
scheduler: context.scheduler,
|
|
1283
|
+
styleManager: context.styleManager,
|
|
951
1284
|
data: context.data,
|
|
952
1285
|
moduleCache: context.moduleCache,
|
|
953
1286
|
moduleLoads: context.moduleLoads,
|
|
@@ -958,7 +1291,7 @@ async function createSubFrames(
|
|
|
958
1291
|
}
|
|
959
1292
|
}
|
|
960
1293
|
|
|
961
|
-
i = nodes
|
|
1294
|
+
i = findMarkerRangeEndIndex(nodes, end, i)
|
|
962
1295
|
continue
|
|
963
1296
|
}
|
|
964
1297
|
|
|
@@ -996,10 +1329,9 @@ function removeVirtualRoots(nodes: Node[]): void {
|
|
|
996
1329
|
for (let i = 0; i < nodes.length; i++) {
|
|
997
1330
|
let node = nodes[i]
|
|
998
1331
|
|
|
999
|
-
if (
|
|
1000
|
-
node.$rmx.dispose()
|
|
1332
|
+
if (isCommentNode(node) && isHydrationStart(node) && disposeClientEntryBoundary(node)) {
|
|
1001
1333
|
let end = findEndMarker(node, isHydrationStart, isHydrationEnd)
|
|
1002
|
-
i = nodes
|
|
1334
|
+
i = findMarkerRangeEndIndex(nodes, end, i)
|
|
1003
1335
|
continue
|
|
1004
1336
|
}
|
|
1005
1337
|
|
|
@@ -1020,7 +1352,7 @@ function disposeSubFrames(nodes: Node[], context: FrameContext): void {
|
|
|
1020
1352
|
subFrame.dispose()
|
|
1021
1353
|
context.frameInstances.delete(node)
|
|
1022
1354
|
}
|
|
1023
|
-
i = nodes
|
|
1355
|
+
i = findMarkerRangeEndIndex(nodes, end, i)
|
|
1024
1356
|
continue
|
|
1025
1357
|
}
|
|
1026
1358
|
|
|
@@ -1087,7 +1419,9 @@ export function publishFrameTemplate(id: string, fragment: DocumentFragment): vo
|
|
|
1087
1419
|
}
|
|
1088
1420
|
|
|
1089
1421
|
for (let listener of listeners) {
|
|
1090
|
-
|
|
1422
|
+
let clone = fragment.cloneNode(true)
|
|
1423
|
+
invariant(isDocumentFragmentNode(clone), 'Expected cloned frame template fragment')
|
|
1424
|
+
listener(clone)
|
|
1091
1425
|
}
|
|
1092
1426
|
}
|
|
1093
1427
|
|
|
@@ -1186,12 +1520,22 @@ async function renderFrameStream(
|
|
|
1186
1520
|
stream: ReadableStream<Uint8Array>,
|
|
1187
1521
|
doc: Document,
|
|
1188
1522
|
applyHtml: (html: string, flushKind: FlushKind) => Promise<void>,
|
|
1523
|
+
signal?: AbortSignal,
|
|
1189
1524
|
): Promise<void> {
|
|
1190
1525
|
let reader = stream.getReader()
|
|
1191
1526
|
let decoder = new TextDecoder()
|
|
1192
1527
|
let buffer = ''
|
|
1193
1528
|
let html = ''
|
|
1194
1529
|
let appliedOnce = false
|
|
1530
|
+
let abort = () => {
|
|
1531
|
+
void reader.cancel().catch(() => {})
|
|
1532
|
+
}
|
|
1533
|
+
if (signal?.aborted) {
|
|
1534
|
+
await reader.cancel()
|
|
1535
|
+
reader.releaseLock()
|
|
1536
|
+
return
|
|
1537
|
+
}
|
|
1538
|
+
signal?.addEventListener('abort', abort, { once: true })
|
|
1195
1539
|
|
|
1196
1540
|
try {
|
|
1197
1541
|
while (true) {
|
|
@@ -1230,6 +1574,7 @@ async function renderFrameStream(
|
|
|
1230
1574
|
await applyHtml('', 'fragment')
|
|
1231
1575
|
}
|
|
1232
1576
|
} finally {
|
|
1577
|
+
signal?.removeEventListener('abort', abort)
|
|
1233
1578
|
reader.releaseLock()
|
|
1234
1579
|
}
|
|
1235
1580
|
}
|
|
@@ -1312,7 +1657,7 @@ function createFragmentFromString(doc: Document, content: string): DocumentFragm
|
|
|
1312
1657
|
function isRemixNodeFrameContent(content: InternalFrameContent): content is RemixNode {
|
|
1313
1658
|
return !(
|
|
1314
1659
|
content instanceof ReadableStream ||
|
|
1315
|
-
content
|
|
1660
|
+
isDocumentFragmentNode(content) ||
|
|
1316
1661
|
typeof content === 'string'
|
|
1317
1662
|
)
|
|
1318
1663
|
}
|
|
@@ -1350,11 +1695,11 @@ function walkCommentsInNodes(nodes: Node[], cb: (comment: Comment) => void): voi
|
|
|
1350
1695
|
// are discovered and hydrated by the nested frame instance only.
|
|
1351
1696
|
if (isFrameStart(node)) {
|
|
1352
1697
|
let end = findEndMarker(node, isFrameStart, isFrameEnd)
|
|
1353
|
-
i = nodes
|
|
1698
|
+
i = findMarkerRangeEndIndex(nodes, end, i)
|
|
1354
1699
|
continue
|
|
1355
1700
|
}
|
|
1356
1701
|
|
|
1357
|
-
if (node
|
|
1702
|
+
if (isCommentNode(node)) cb(node)
|
|
1358
1703
|
if (node.childNodes && node.childNodes.length > 0) {
|
|
1359
1704
|
walkCommentsInNodes(Array.from(node.childNodes), cb)
|
|
1360
1705
|
}
|
|
@@ -1369,12 +1714,8 @@ function isHydrationEnd(node: Comment): boolean {
|
|
|
1369
1714
|
return node.data.trim() === '/rmx:h'
|
|
1370
1715
|
}
|
|
1371
1716
|
|
|
1372
|
-
function isHydratedVirtualRootMarker(node: Node): node is VirtualRootMarker {
|
|
1373
|
-
return node instanceof Comment && '$rmx' in node
|
|
1374
|
-
}
|
|
1375
|
-
|
|
1376
1717
|
function isFrameStart(node: Node): node is Comment {
|
|
1377
|
-
return node
|
|
1718
|
+
return isCommentNode(node) && node.data.trim().startsWith('rmx:f:')
|
|
1378
1719
|
}
|
|
1379
1720
|
|
|
1380
1721
|
function isFrameEnd(node: Comment): boolean {
|
|
@@ -1387,6 +1728,11 @@ function getFrameId(start: Comment): string {
|
|
|
1387
1728
|
return trimmed.slice('rmx:f:'.length)
|
|
1388
1729
|
}
|
|
1389
1730
|
|
|
1731
|
+
function findMarkerRangeEndIndex(nodes: Node[], end: Comment, startIndex: number): number {
|
|
1732
|
+
// The snapshot may not contain an end marker moved by a DOM update.
|
|
1733
|
+
return Math.max(startIndex, nodes.indexOf(end))
|
|
1734
|
+
}
|
|
1735
|
+
|
|
1390
1736
|
function findEndMarker(
|
|
1391
1737
|
start: Comment,
|
|
1392
1738
|
isStart: (node: Comment) => boolean,
|
|
@@ -1396,8 +1742,8 @@ function findEndMarker(
|
|
|
1396
1742
|
let depth = 1
|
|
1397
1743
|
|
|
1398
1744
|
while (node) {
|
|
1399
|
-
if (node
|
|
1400
|
-
let comment = node
|
|
1745
|
+
if (isCommentNode(node)) {
|
|
1746
|
+
let comment = node
|
|
1401
1747
|
if (isStart(comment)) depth++
|
|
1402
1748
|
else if (isEnd(comment)) {
|
|
1403
1749
|
depth--
|
|
@@ -1409,3 +1755,15 @@ function findEndMarker(
|
|
|
1409
1755
|
|
|
1410
1756
|
throw new Error('End marker not found')
|
|
1411
1757
|
}
|
|
1758
|
+
|
|
1759
|
+
function isCommentNode(node: Node | null | undefined): node is Comment {
|
|
1760
|
+
return node?.nodeType === Node.COMMENT_NODE
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
function isDocumentFragmentNode(value: unknown): value is DocumentFragment {
|
|
1764
|
+
return (
|
|
1765
|
+
typeof value === 'object' &&
|
|
1766
|
+
value !== null &&
|
|
1767
|
+
Reflect.get(value, 'nodeType') === Node.DOCUMENT_FRAGMENT_NODE
|
|
1768
|
+
)
|
|
1769
|
+
}
|