@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/reconcile.ts
CHANGED
|
@@ -1,33 +1,43 @@
|
|
|
1
1
|
import type { Component, ComponentHandle, FrameContent, FrameHandle } from './component.ts'
|
|
2
|
-
import { createComponent
|
|
3
|
-
import type {
|
|
4
|
-
import { createFrame } from './frame.ts'
|
|
2
|
+
import { createComponent } from './component.ts'
|
|
3
|
+
import type { FrameRuntime } from './frame.ts'
|
|
4
|
+
import { createFrame, isFrameRuntime } from './frame.ts'
|
|
5
|
+
import { unwrapFrameResolution } from './frame-resolution.ts'
|
|
5
6
|
import { createRangeRoot } from './vdom.ts'
|
|
6
7
|
import type {
|
|
8
|
+
CommittedFragmentNode,
|
|
9
|
+
CommittedFrameNode,
|
|
10
|
+
CommittedNonRenderNode,
|
|
7
11
|
ComponentNode,
|
|
8
12
|
CommittedComponentNode,
|
|
9
13
|
CommittedHostNode,
|
|
10
14
|
CommittedTextNode,
|
|
15
|
+
ControlledReflectionState,
|
|
16
|
+
DirectEventBinding,
|
|
17
|
+
DirectEventState,
|
|
18
|
+
FrameNode,
|
|
11
19
|
HostNode,
|
|
20
|
+
MountingComponentNode,
|
|
21
|
+
ReconcileContext,
|
|
22
|
+
RuntimeHostProps,
|
|
12
23
|
TextNode,
|
|
13
|
-
|
|
14
|
-
|
|
24
|
+
VNodeInput,
|
|
25
|
+
VNodeParent,
|
|
26
|
+
CommittedVNode,
|
|
15
27
|
} from './vnode.ts'
|
|
16
28
|
import {
|
|
17
29
|
isCommittedComponentNode,
|
|
18
|
-
isComponentNode,
|
|
19
30
|
isCommittedHostNode,
|
|
20
31
|
isCommittedTextNode,
|
|
21
32
|
isFragmentNode,
|
|
22
33
|
isHostNode,
|
|
23
|
-
isNonRenderNode,
|
|
24
|
-
isTextNode,
|
|
25
34
|
findContextFromAncestry,
|
|
26
35
|
} from './vnode.ts'
|
|
27
36
|
import { invariant } from './invariant.ts'
|
|
28
37
|
import { patchHostProps } from './core/props.ts'
|
|
29
38
|
import type { StyleManager } from '../style/index.ts'
|
|
30
|
-
import type {
|
|
39
|
+
import type { ElementFunction } from './element-function.ts'
|
|
40
|
+
import type { Key } from './key.ts'
|
|
31
41
|
import { skipComments, logHydrationMismatch } from './client-entries.ts'
|
|
32
42
|
import type { Scheduler } from './scheduler.ts'
|
|
33
43
|
import { toVNode } from './to-vnode.ts'
|
|
@@ -44,6 +54,8 @@ import {
|
|
|
44
54
|
type MixinRuntimeState,
|
|
45
55
|
} from './mixins/mixin.ts'
|
|
46
56
|
import { isOnMixinDescriptor, type OnMixinDescriptor } from './mixins/on-mixin.ts'
|
|
57
|
+
import { createComponentErrorEvent } from './error-event.ts'
|
|
58
|
+
import { componentStalenessCheck } from './refresh.ts'
|
|
47
59
|
|
|
48
60
|
const SVG_NS = 'http://www.w3.org/2000/svg'
|
|
49
61
|
|
|
@@ -54,45 +66,41 @@ let activeSchedulerUpdateParents: ParentNode[] | undefined
|
|
|
54
66
|
|
|
55
67
|
// Compute SVG context for a node based on its parent and type.
|
|
56
68
|
// Returns true if the node is within an SVG subtree, false otherwise.
|
|
57
|
-
function getSvgContext(vParent:
|
|
69
|
+
function getSvgContext(vParent: VNodeParent, node: VNodeInput): boolean {
|
|
58
70
|
// Only host elements (strings) can affect SVG context
|
|
59
|
-
if (
|
|
71
|
+
if (node.kind === 'host') {
|
|
60
72
|
// svg element creates SVG context
|
|
61
|
-
if (
|
|
73
|
+
if (node.type === 'svg') return true
|
|
62
74
|
// foreignObject switches back to HTML context
|
|
63
|
-
if (
|
|
75
|
+
if (node.type === 'foreignObject') return false
|
|
64
76
|
}
|
|
65
77
|
// Otherwise inherit from parent
|
|
66
|
-
return vParent._svg
|
|
78
|
+
return vParent._svg
|
|
67
79
|
}
|
|
68
80
|
|
|
69
|
-
function getHostProps(node: HostNode | CommittedHostNode):
|
|
70
|
-
return node._mixedProps
|
|
81
|
+
function getHostProps(node: HostNode | CommittedHostNode): RuntimeHostProps {
|
|
82
|
+
return '_mixedProps' in node ? node._mixedProps : node.props
|
|
71
83
|
}
|
|
72
84
|
|
|
73
85
|
function markNodePersistedByMixins(node: CommittedHostNode, domParent: ParentNode, token: number) {
|
|
74
|
-
node.
|
|
75
|
-
node._persistedParentByMixins = domParent
|
|
76
|
-
node._persistedRemovalToken = token
|
|
86
|
+
node._persistence = { parent: domParent, token }
|
|
77
87
|
persistedMixinNodes.add(node)
|
|
78
|
-
bindMixinRuntime(node._mixState
|
|
88
|
+
bindMixinRuntime(node._mixState, undefined)
|
|
79
89
|
}
|
|
80
90
|
|
|
81
91
|
function unmarkNodePersistedByMixins(node: CommittedHostNode) {
|
|
82
|
-
node.
|
|
83
|
-
node._persistedParentByMixins = undefined
|
|
84
|
-
node._persistedRemovalToken = undefined
|
|
92
|
+
node._persistence = undefined
|
|
85
93
|
persistedMixinNodes.delete(node)
|
|
86
94
|
}
|
|
87
95
|
|
|
88
96
|
function findMatchingPersistedMixinNode(
|
|
89
97
|
type: string,
|
|
90
|
-
key:
|
|
98
|
+
key: Key | undefined,
|
|
91
99
|
domParent: ParentNode,
|
|
92
100
|
): CommittedHostNode | null {
|
|
93
101
|
if (key == null) return null
|
|
94
102
|
for (let node of persistedMixinNodes) {
|
|
95
|
-
if (node.
|
|
103
|
+
if (node._persistence?.parent !== domParent) continue
|
|
96
104
|
if (node.type !== type) continue
|
|
97
105
|
if (node.key !== key) continue
|
|
98
106
|
return node
|
|
@@ -100,33 +108,10 @@ function findMatchingPersistedMixinNode(
|
|
|
100
108
|
return null
|
|
101
109
|
}
|
|
102
110
|
|
|
103
|
-
type ControlledReflectionState = {
|
|
104
|
-
disposed: boolean
|
|
105
|
-
listenersAttached: boolean
|
|
106
|
-
pendingRestoreVersion: number
|
|
107
|
-
managesValue: boolean
|
|
108
|
-
managesChecked: boolean
|
|
109
|
-
hasControlledValue: boolean
|
|
110
|
-
controlledValue: unknown
|
|
111
|
-
hasControlledChecked: boolean
|
|
112
|
-
controlledChecked: unknown
|
|
113
|
-
onInput: () => void
|
|
114
|
-
onChange: () => void
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
type DirectEventBinding = {
|
|
118
|
-
type: string
|
|
119
|
-
handler: (event: Event, signal: AbortSignal) => void | Promise<void>
|
|
120
|
-
capture: boolean
|
|
121
|
-
stableHandler: ((event: Event) => void) | null
|
|
122
|
-
reentry: AbortController | null
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
type DirectEventState = {
|
|
126
|
-
bindings: DirectEventBinding[]
|
|
127
|
-
}
|
|
128
|
-
|
|
129
111
|
const EMPTY_DIRECT_EVENT_DESCRIPTORS: OnMixinDescriptor[] = []
|
|
112
|
+
const EMPTY_COMMITTED_CHILDREN: CommittedVNode[] = []
|
|
113
|
+
|
|
114
|
+
type HydrationCursor = { current: Node | null | undefined }
|
|
130
115
|
|
|
131
116
|
function shouldRestoreControlledReflectionOnInput(
|
|
132
117
|
node: CommittedHostNode,
|
|
@@ -144,7 +129,7 @@ function ensureControlledReflection(
|
|
|
144
129
|
node: CommittedHostNode,
|
|
145
130
|
scheduler: Scheduler,
|
|
146
131
|
): ControlledReflectionState {
|
|
147
|
-
let existing = node._controlledState
|
|
132
|
+
let existing = node._controlledState
|
|
148
133
|
if (existing) return existing
|
|
149
134
|
|
|
150
135
|
let state: ControlledReflectionState = {
|
|
@@ -178,8 +163,8 @@ function ensureControlledReflection(
|
|
|
178
163
|
return state
|
|
179
164
|
}
|
|
180
165
|
|
|
181
|
-
function syncControlledReflection(node: CommittedHostNode, props:
|
|
182
|
-
let state = node._controlledState
|
|
166
|
+
function syncControlledReflection(node: CommittedHostNode, props: RuntimeHostProps): void {
|
|
167
|
+
let state = node._controlledState
|
|
183
168
|
if (!state || state.disposed) return
|
|
184
169
|
|
|
185
170
|
state.managesValue = canManageValue(node.type, node._dom)
|
|
@@ -191,7 +176,7 @@ function syncControlledReflection(node: CommittedHostNode, props: ElementProps):
|
|
|
191
176
|
state.pendingRestoreVersion++
|
|
192
177
|
}
|
|
193
178
|
|
|
194
|
-
function shouldTrackControlledReflection(props:
|
|
179
|
+
function shouldTrackControlledReflection(props: RuntimeHostProps): boolean {
|
|
195
180
|
return hasControlledValueProp(props) || hasControlledCheckedProp(props)
|
|
196
181
|
}
|
|
197
182
|
|
|
@@ -222,7 +207,7 @@ function restoreControlledReflections(
|
|
|
222
207
|
}
|
|
223
208
|
|
|
224
209
|
function teardownControlledReflection(node: CommittedHostNode): void {
|
|
225
|
-
let state = node._controlledState
|
|
210
|
+
let state = node._controlledState
|
|
226
211
|
if (!state) return
|
|
227
212
|
state.disposed = true
|
|
228
213
|
state.pendingRestoreVersion++
|
|
@@ -233,16 +218,25 @@ function teardownControlledReflection(node: CommittedHostNode): void {
|
|
|
233
218
|
}
|
|
234
219
|
}
|
|
235
220
|
|
|
221
|
+
// See abandonDirectEventListeners: skips removeEventListener for discarded subtrees.
|
|
222
|
+
function abandonControlledReflection(node: CommittedHostNode): void {
|
|
223
|
+
let state = node._controlledState
|
|
224
|
+
if (!state) return
|
|
225
|
+
state.disposed = true
|
|
226
|
+
state.pendingRestoreVersion++
|
|
227
|
+
state.listenersAttached = false
|
|
228
|
+
}
|
|
229
|
+
|
|
236
230
|
function canManageValue(type: string, element: Element): boolean {
|
|
237
231
|
if (type === 'progress') return false
|
|
238
232
|
return canReflectProperty(element, 'value')
|
|
239
233
|
}
|
|
240
234
|
|
|
241
|
-
function hasControlledValueProp(props:
|
|
235
|
+
function hasControlledValueProp(props: RuntimeHostProps): boolean {
|
|
242
236
|
return 'value' in props && props.value !== undefined
|
|
243
237
|
}
|
|
244
238
|
|
|
245
|
-
function hasControlledCheckedProp(props:
|
|
239
|
+
function hasControlledCheckedProp(props: RuntimeHostProps): boolean {
|
|
246
240
|
return 'checked' in props && props.checked !== undefined
|
|
247
241
|
}
|
|
248
242
|
|
|
@@ -263,29 +257,28 @@ function setPropertyReflection(element: Element, key: string, value: unknown): v
|
|
|
263
257
|
element[key] = value == null ? '' : value
|
|
264
258
|
}
|
|
265
259
|
|
|
260
|
+
type ResolvedHostProps = {
|
|
261
|
+
props: RuntimeHostProps
|
|
262
|
+
mixState?: MixinRuntimeState
|
|
263
|
+
directEventDescriptors?: OnMixinDescriptor[]
|
|
264
|
+
}
|
|
265
|
+
|
|
266
266
|
function resolveNodeMixProps(
|
|
267
|
-
node: HostNode,
|
|
267
|
+
node: HostNode | CommittedHostNode,
|
|
268
|
+
parent: VNodeParent,
|
|
268
269
|
frame: FrameHandle,
|
|
269
270
|
scheduler: Scheduler,
|
|
270
271
|
state?: MixinRuntimeState,
|
|
271
|
-
):
|
|
272
|
+
): ResolvedHostProps {
|
|
272
273
|
let mix = node.props.mix
|
|
273
274
|
let directEventDescriptors = resolveDirectEventDescriptors(mix)
|
|
274
275
|
if (directEventDescriptors) {
|
|
275
|
-
if (state)
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
node._mixState = undefined
|
|
279
|
-
node._mixedProps = node.props
|
|
280
|
-
node._directEventDescriptors = directEventDescriptors
|
|
281
|
-
return node.props
|
|
276
|
+
if (state) teardownMixins(state)
|
|
277
|
+
return { props: node.props, directEventDescriptors }
|
|
282
278
|
}
|
|
283
279
|
|
|
284
|
-
node._directEventDescriptors = undefined
|
|
285
280
|
if (state == null && (mix == null || (Array.isArray(mix) && mix.length === 0))) {
|
|
286
|
-
node.
|
|
287
|
-
node._mixedProps = node.props
|
|
288
|
-
return node.props
|
|
281
|
+
return { props: node.props }
|
|
289
282
|
}
|
|
290
283
|
|
|
291
284
|
let resolved = resolveMixedProps({
|
|
@@ -297,17 +290,21 @@ function resolveNodeMixProps(
|
|
|
297
290
|
return undefined
|
|
298
291
|
}
|
|
299
292
|
|
|
300
|
-
return findContextFromAncestry(
|
|
293
|
+
return findContextFromAncestry(parent, type)
|
|
301
294
|
},
|
|
302
295
|
props: node.props,
|
|
303
296
|
state,
|
|
304
297
|
})
|
|
305
|
-
|
|
298
|
+
return { props: resolved.props, mixState: resolved.state }
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function applyResolvedHostProps(node: CommittedHostNode, resolved: ResolvedHostProps): void {
|
|
306
302
|
node._mixedProps = resolved.props
|
|
307
|
-
|
|
303
|
+
node._mixState = resolved.mixState
|
|
304
|
+
node._directEventDescriptors = resolved.directEventDescriptors
|
|
308
305
|
}
|
|
309
306
|
|
|
310
|
-
function resolveDirectEventDescriptors(mix:
|
|
307
|
+
function resolveDirectEventDescriptors(mix: RuntimeHostProps['mix']): OnMixinDescriptor[] | null {
|
|
311
308
|
if (!mix) return EMPTY_DIRECT_EVENT_DESCRIPTORS
|
|
312
309
|
if (!Array.isArray(mix)) {
|
|
313
310
|
return isOnMixinDescriptor(mix) ? [mix] : null
|
|
@@ -317,18 +314,18 @@ function resolveDirectEventDescriptors(mix: ElementProps['mix']): OnMixinDescrip
|
|
|
317
314
|
}
|
|
318
315
|
|
|
319
316
|
function areOnMixinDescriptors(descriptors: unknown[]): descriptors is OnMixinDescriptor[] {
|
|
320
|
-
for (let
|
|
321
|
-
if (!isOnMixinDescriptor(
|
|
317
|
+
for (let i = 0; i < descriptors.length; i++) {
|
|
318
|
+
if (!isOnMixinDescriptor(descriptors[i])) return false
|
|
322
319
|
}
|
|
323
320
|
return true
|
|
324
321
|
}
|
|
325
322
|
|
|
326
323
|
function enqueueMixinBindingUpdate(
|
|
327
|
-
this: MixinRuntimeBinding
|
|
324
|
+
this: MixinRuntimeBinding<CommittedHostNode>,
|
|
328
325
|
done: (signal: AbortSignal) => void,
|
|
329
326
|
): void {
|
|
330
|
-
let node = this.target
|
|
331
|
-
let state = node._mixState
|
|
327
|
+
let node = this.target
|
|
328
|
+
let state = node._mixState
|
|
332
329
|
this.scheduler.enqueueWork([
|
|
333
330
|
() => {
|
|
334
331
|
if (state?.aborted) {
|
|
@@ -338,8 +335,13 @@ function enqueueMixinBindingUpdate(
|
|
|
338
335
|
|
|
339
336
|
dispatchMixinBeforeUpdate(state)
|
|
340
337
|
let prevProps = getHostProps(node)
|
|
341
|
-
let
|
|
342
|
-
|
|
338
|
+
let resolved = resolveNodeMixProps(node, node._parent, this.frame, this.scheduler, state)
|
|
339
|
+
applyResolvedHostProps(node, resolved)
|
|
340
|
+
patchHostProps(prevProps, resolved.props, this.node)
|
|
341
|
+
if (node._controlledState || shouldTrackControlledReflection(resolved.props)) {
|
|
342
|
+
ensureControlledReflection(node, this.scheduler)
|
|
343
|
+
syncControlledReflection(node, resolved.props)
|
|
344
|
+
}
|
|
343
345
|
|
|
344
346
|
dispatchMixinCommit(state)
|
|
345
347
|
done(state ? getMixinRuntimeSignal(state) : AbortSignal.abort())
|
|
@@ -355,12 +357,12 @@ function bindNodeMixRuntime(
|
|
|
355
357
|
reclaimed: boolean = false,
|
|
356
358
|
parent?: ParentNode,
|
|
357
359
|
) {
|
|
358
|
-
let state = node._mixState
|
|
360
|
+
let state = node._mixState
|
|
359
361
|
bindMixinRuntime(
|
|
360
362
|
state,
|
|
361
363
|
{
|
|
362
364
|
node: node._dom,
|
|
363
|
-
parent: parent ?? (node._dom
|
|
365
|
+
parent: parent ?? getRequiredDomParent(node._dom),
|
|
364
366
|
key: node.key,
|
|
365
367
|
target: node,
|
|
366
368
|
frame,
|
|
@@ -371,12 +373,18 @@ function bindNodeMixRuntime(
|
|
|
371
373
|
)
|
|
372
374
|
}
|
|
373
375
|
|
|
374
|
-
function isHeadHostNode(node: HostNode): boolean {
|
|
376
|
+
function isHeadHostNode(node: HostNode | CommittedHostNode): boolean {
|
|
375
377
|
if (node.type === 'head') return true
|
|
376
378
|
if (node.type.length !== 4) return false
|
|
377
379
|
return node.type.toLowerCase() === 'head'
|
|
378
380
|
}
|
|
379
381
|
|
|
382
|
+
function getRequiredDomParent(node: Node): ParentNode {
|
|
383
|
+
let parent = node.parentNode
|
|
384
|
+
invariant(parent, 'Expected mounted host node to have a DOM parent')
|
|
385
|
+
return parent
|
|
386
|
+
}
|
|
387
|
+
|
|
380
388
|
function getDocumentHead(domParent: ParentNode): HTMLHeadElement | null {
|
|
381
389
|
if (domParent instanceof Document) {
|
|
382
390
|
return domParent.head
|
|
@@ -387,126 +395,199 @@ function getDocumentHead(domParent: ParentNode): HTMLHeadElement | null {
|
|
|
387
395
|
return null
|
|
388
396
|
}
|
|
389
397
|
|
|
398
|
+
function commitNonRenderNode(
|
|
399
|
+
node: VNodeInput & { kind: 'empty' },
|
|
400
|
+
parent: VNodeParent,
|
|
401
|
+
svg: boolean,
|
|
402
|
+
): CommittedNonRenderNode {
|
|
403
|
+
let committed = node as unknown as CommittedNonRenderNode
|
|
404
|
+
committed._parent = parent
|
|
405
|
+
committed._svg = svg
|
|
406
|
+
return committed
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function commitTextNode(
|
|
410
|
+
node: TextNode,
|
|
411
|
+
parent: VNodeParent,
|
|
412
|
+
svg: boolean,
|
|
413
|
+
dom: Text,
|
|
414
|
+
): CommittedTextNode {
|
|
415
|
+
let committed = node as unknown as CommittedTextNode
|
|
416
|
+
committed._parent = parent
|
|
417
|
+
committed._svg = svg
|
|
418
|
+
committed._dom = dom
|
|
419
|
+
return committed
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function beginFragmentNode(
|
|
423
|
+
node: VNodeInput & { kind: 'fragment' },
|
|
424
|
+
parent: VNodeParent,
|
|
425
|
+
svg: boolean,
|
|
426
|
+
): CommittedFragmentNode {
|
|
427
|
+
let committed = node as unknown as CommittedFragmentNode
|
|
428
|
+
committed._parent = parent
|
|
429
|
+
committed._svg = svg
|
|
430
|
+
committed._children = EMPTY_COMMITTED_CHILDREN
|
|
431
|
+
return committed
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
function commitHostNode(
|
|
435
|
+
node: HostNode,
|
|
436
|
+
parent: VNodeParent,
|
|
437
|
+
svg: boolean,
|
|
438
|
+
dom: Element,
|
|
439
|
+
resolved: ResolvedHostProps,
|
|
440
|
+
children: CommittedVNode[] = EMPTY_COMMITTED_CHILDREN,
|
|
441
|
+
): CommittedHostNode {
|
|
442
|
+
let committed = node as unknown as CommittedHostNode
|
|
443
|
+
committed._parent = parent
|
|
444
|
+
committed._svg = svg
|
|
445
|
+
committed._dom = dom
|
|
446
|
+
committed._children = children
|
|
447
|
+
committed._mixedProps = resolved.props
|
|
448
|
+
committed._mixState = resolved.mixState
|
|
449
|
+
committed._directEventDescriptors = resolved.directEventDescriptors
|
|
450
|
+
return committed
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
function beginComponentNode(
|
|
454
|
+
node: ComponentNode,
|
|
455
|
+
parent: VNodeParent,
|
|
456
|
+
svg: boolean,
|
|
457
|
+
handle: ComponentHandle,
|
|
458
|
+
context: ReconcileContext,
|
|
459
|
+
): MountingComponentNode {
|
|
460
|
+
let mounting = node as unknown as MountingComponentNode
|
|
461
|
+
mounting._parent = parent
|
|
462
|
+
mounting._svg = svg
|
|
463
|
+
mounting._handle = handle
|
|
464
|
+
mounting._context = context
|
|
465
|
+
return mounting
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function commitComponentNode(
|
|
469
|
+
node: MountingComponentNode,
|
|
470
|
+
content: CommittedVNode,
|
|
471
|
+
): CommittedComponentNode {
|
|
472
|
+
let committed = node as CommittedComponentNode
|
|
473
|
+
committed._content = content
|
|
474
|
+
return committed
|
|
475
|
+
}
|
|
476
|
+
|
|
390
477
|
export function diffVNodes(
|
|
391
|
-
curr:
|
|
392
|
-
next:
|
|
478
|
+
curr: CommittedVNode | null,
|
|
479
|
+
next: VNodeInput,
|
|
393
480
|
domParent: ParentNode,
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
styles: StyleManager,
|
|
397
|
-
vParent: VNode,
|
|
398
|
-
rootTarget: EventTarget,
|
|
481
|
+
vParent: VNodeParent,
|
|
482
|
+
context: ReconcileContext,
|
|
399
483
|
anchor?: Node,
|
|
400
|
-
|
|
401
|
-
):
|
|
402
|
-
next._parent = vParent // set parent for initial render context lookups
|
|
403
|
-
next._svg = getSvgContext(vParent, next.type)
|
|
404
|
-
|
|
405
|
-
// new
|
|
484
|
+
cursor?: HydrationCursor,
|
|
485
|
+
): CommittedVNode {
|
|
406
486
|
if (curr === null) {
|
|
407
|
-
return insert(
|
|
408
|
-
next,
|
|
409
|
-
domParent,
|
|
410
|
-
frame,
|
|
411
|
-
scheduler,
|
|
412
|
-
styles,
|
|
413
|
-
vParent,
|
|
414
|
-
rootTarget,
|
|
415
|
-
anchor,
|
|
416
|
-
rootCursor,
|
|
417
|
-
)
|
|
487
|
+
return insert(next, domParent, vParent, context, anchor, cursor)
|
|
418
488
|
}
|
|
419
489
|
|
|
420
|
-
if (
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
return
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
if (isCommittedTextNode(curr) && isTextNode(next)) {
|
|
430
|
-
diffText(curr, next, vParent)
|
|
431
|
-
return rootCursor
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
if (isCommittedHostNode(curr) && isHostNode(next)) {
|
|
435
|
-
diffHost(curr, next, frame, scheduler, styles, vParent, rootTarget)
|
|
436
|
-
return rootCursor
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
if (isCommittedComponentNode(curr) && isComponentNode(next)) {
|
|
440
|
-
diffComponent(curr, next, frame, scheduler, styles, domParent, vParent, rootTarget)
|
|
441
|
-
return rootCursor
|
|
490
|
+
if (
|
|
491
|
+
componentStalenessCheck !== null &&
|
|
492
|
+
curr.kind === 'component' &&
|
|
493
|
+
next.kind === 'component' &&
|
|
494
|
+
componentStalenessCheck(curr.type) === true
|
|
495
|
+
) {
|
|
496
|
+
return replace(curr, next, domParent, vParent, context, anchor)
|
|
442
497
|
}
|
|
443
498
|
|
|
444
|
-
if (
|
|
445
|
-
|
|
446
|
-
curr._children,
|
|
447
|
-
next._children,
|
|
448
|
-
domParent,
|
|
449
|
-
frame,
|
|
450
|
-
scheduler,
|
|
451
|
-
styles,
|
|
452
|
-
next,
|
|
453
|
-
rootTarget,
|
|
454
|
-
undefined,
|
|
455
|
-
anchor,
|
|
456
|
-
)
|
|
457
|
-
return rootCursor
|
|
499
|
+
if (curr.kind !== next.kind || curr.type !== next.type) {
|
|
500
|
+
return replace(curr, next, domParent, vParent, context, anchor)
|
|
458
501
|
}
|
|
459
502
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
503
|
+
switch (next.kind) {
|
|
504
|
+
case 'host': {
|
|
505
|
+
return diffHost(curr as CommittedHostNode, next, vParent, context)
|
|
506
|
+
}
|
|
507
|
+
case 'text': {
|
|
508
|
+
return diffText(curr as CommittedTextNode, next, vParent, getSvgContext(vParent, next))
|
|
509
|
+
}
|
|
510
|
+
case 'empty': {
|
|
511
|
+
return commitNonRenderNode(next, vParent, getSvgContext(vParent, next))
|
|
512
|
+
}
|
|
513
|
+
case 'fragment': {
|
|
514
|
+
let childInputs = next._children
|
|
515
|
+
let committed = beginFragmentNode(next, vParent, getSvgContext(vParent, next))
|
|
516
|
+
committed._children = diffChildren(
|
|
517
|
+
(curr as CommittedFragmentNode)._children,
|
|
518
|
+
childInputs,
|
|
519
|
+
domParent,
|
|
520
|
+
committed,
|
|
521
|
+
context,
|
|
522
|
+
undefined,
|
|
523
|
+
anchor,
|
|
524
|
+
)
|
|
525
|
+
return committed
|
|
526
|
+
}
|
|
527
|
+
case 'frame': {
|
|
528
|
+
return diffFrame(
|
|
529
|
+
curr as CommittedFrameNode,
|
|
530
|
+
next,
|
|
531
|
+
domParent,
|
|
532
|
+
vParent,
|
|
533
|
+
context,
|
|
534
|
+
getSvgContext(vParent, next),
|
|
535
|
+
anchor,
|
|
536
|
+
)
|
|
537
|
+
}
|
|
538
|
+
case 'component': {
|
|
539
|
+
return diffComponent(
|
|
540
|
+
curr as CommittedComponentNode,
|
|
541
|
+
next,
|
|
542
|
+
domParent,
|
|
543
|
+
vParent,
|
|
544
|
+
context,
|
|
545
|
+
getSvgContext(vParent, next),
|
|
546
|
+
anchor,
|
|
547
|
+
cursor,
|
|
548
|
+
)
|
|
549
|
+
}
|
|
463
550
|
}
|
|
464
|
-
|
|
465
|
-
invariant(false, 'Unexpected diff case')
|
|
466
551
|
}
|
|
467
552
|
|
|
468
553
|
function replace(
|
|
469
|
-
curr:
|
|
470
|
-
next:
|
|
554
|
+
curr: CommittedVNode,
|
|
555
|
+
next: VNodeInput,
|
|
471
556
|
domParent: ParentNode,
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
styles: StyleManager,
|
|
475
|
-
vParent: VNode,
|
|
476
|
-
rootTarget: EventTarget,
|
|
557
|
+
vParent: VNodeParent,
|
|
558
|
+
context: ReconcileContext,
|
|
477
559
|
anchor?: Node,
|
|
478
|
-
) {
|
|
560
|
+
): CommittedVNode {
|
|
479
561
|
let currAnchor = findFirstDomAnchor(curr)
|
|
480
562
|
if (currAnchor && currAnchor.parentNode === domParent) {
|
|
481
563
|
let replacementAnchor = document.createComment('rmx:replace')
|
|
482
564
|
domParent.insertBefore(replacementAnchor, currAnchor)
|
|
483
565
|
try {
|
|
484
|
-
remove(curr, domParent,
|
|
485
|
-
insert(next, domParent,
|
|
566
|
+
remove(curr, domParent, context)
|
|
567
|
+
return insert(next, domParent, vParent, context, replacementAnchor)
|
|
486
568
|
} finally {
|
|
487
569
|
replacementAnchor.parentNode?.removeChild(replacementAnchor)
|
|
488
570
|
}
|
|
489
|
-
return
|
|
490
571
|
}
|
|
491
572
|
|
|
492
573
|
let replacementAnchor = findNextSiblingDomAnchor(curr) ?? anchor
|
|
493
|
-
remove(curr, domParent,
|
|
494
|
-
insert(next, domParent,
|
|
574
|
+
remove(curr, domParent, context)
|
|
575
|
+
return insert(next, domParent, vParent, context, replacementAnchor)
|
|
495
576
|
}
|
|
496
577
|
|
|
497
578
|
function diffHost(
|
|
498
579
|
curr: CommittedHostNode,
|
|
499
580
|
next: HostNode,
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
) {
|
|
506
|
-
let mixState = curr._mixState as MixinRuntimeState | undefined
|
|
581
|
+
vParent: VNodeParent,
|
|
582
|
+
context: ReconcileContext,
|
|
583
|
+
): CommittedHostNode {
|
|
584
|
+
let { frame, scheduler, styles } = context
|
|
585
|
+
let mixState = curr._mixState
|
|
507
586
|
let currProps = getHostProps(curr)
|
|
508
|
-
let
|
|
509
|
-
let
|
|
587
|
+
let resolved = resolveNodeMixProps(next, vParent, frame, scheduler, mixState)
|
|
588
|
+
let childInputs = next._children
|
|
589
|
+
let nextProps = resolved.props
|
|
590
|
+
let nextMixState = resolved.mixState
|
|
510
591
|
let shouldDispatchMixinLifecycle =
|
|
511
592
|
(nextMixState?.runners.length ?? 0) > 0 && shouldDispatchInlineMixinLifecycle(curr._dom)
|
|
512
593
|
if (shouldDispatchMixinLifecycle) {
|
|
@@ -517,62 +598,49 @@ function diffHost(
|
|
|
517
598
|
if (nextProps.innerHTML != null) {
|
|
518
599
|
// innerHTML is set, update it if changed
|
|
519
600
|
if (currProps.innerHTML !== nextProps.innerHTML) {
|
|
520
|
-
curr._dom.innerHTML = nextProps.innerHTML
|
|
601
|
+
curr._dom.innerHTML = nextProps.innerHTML
|
|
521
602
|
}
|
|
522
603
|
} else if (currProps.innerHTML != null) {
|
|
523
604
|
// innerHTML was removed, clear it before adding children
|
|
524
605
|
curr._dom.innerHTML = ''
|
|
525
606
|
}
|
|
526
607
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
frame,
|
|
532
|
-
scheduler,
|
|
533
|
-
styles,
|
|
534
|
-
next,
|
|
535
|
-
rootTarget,
|
|
536
|
-
)
|
|
608
|
+
let committed = commitHostNode(next, vParent, getSvgContext(vParent, next), curr._dom, resolved)
|
|
609
|
+
committed._directEventState = curr._directEventState
|
|
610
|
+
committed._controlledState = curr._controlledState
|
|
611
|
+
committed._children = diffChildren(curr._children, childInputs, curr._dom, committed, context)
|
|
537
612
|
patchHostProps(currProps, nextProps, curr._dom)
|
|
538
613
|
|
|
539
|
-
|
|
540
|
-
next._parent = vParent
|
|
541
|
-
next._controller = curr._controller
|
|
542
|
-
next._directEventState = curr._directEventState
|
|
543
|
-
next._controlledState = curr._controlledState
|
|
544
|
-
syncDirectEventListeners(next as CommittedHostNode)
|
|
614
|
+
syncDirectEventListeners(committed)
|
|
545
615
|
|
|
546
|
-
if (
|
|
547
|
-
ensureControlledReflection(
|
|
548
|
-
syncControlledReflection(
|
|
616
|
+
if (committed._controlledState || shouldTrackControlledReflection(nextProps)) {
|
|
617
|
+
ensureControlledReflection(committed, scheduler)
|
|
618
|
+
syncControlledReflection(committed, nextProps)
|
|
549
619
|
}
|
|
550
620
|
|
|
551
|
-
if (
|
|
552
|
-
bindNodeMixRuntime(
|
|
621
|
+
if (committed._mixState) {
|
|
622
|
+
bindNodeMixRuntime(committed, frame, scheduler, styles)
|
|
553
623
|
}
|
|
554
624
|
if (shouldDispatchMixinLifecycle) {
|
|
555
625
|
scheduler.enqueueCommitPhase([() => dispatchMixinCommit(nextMixState)])
|
|
556
626
|
}
|
|
557
627
|
|
|
558
|
-
return
|
|
628
|
+
return committed
|
|
559
629
|
}
|
|
560
630
|
|
|
561
|
-
function setupHostNode(node:
|
|
562
|
-
node._dom = dom
|
|
631
|
+
function setupHostNode(node: CommittedHostNode, scheduler: Scheduler): void {
|
|
563
632
|
let props = getHostProps(node)
|
|
564
|
-
let committedNode = node as CommittedHostNode
|
|
565
633
|
|
|
566
|
-
syncDirectEventListeners(
|
|
634
|
+
syncDirectEventListeners(node)
|
|
567
635
|
|
|
568
636
|
if (shouldTrackControlledReflection(props)) {
|
|
569
|
-
ensureControlledReflection(
|
|
570
|
-
syncControlledReflection(
|
|
637
|
+
ensureControlledReflection(node, scheduler)
|
|
638
|
+
syncControlledReflection(node, props)
|
|
571
639
|
}
|
|
572
640
|
}
|
|
573
641
|
|
|
574
642
|
function syncDirectEventListeners(node: CommittedHostNode): void {
|
|
575
|
-
let descriptors = node._directEventDescriptors
|
|
643
|
+
let descriptors = node._directEventDescriptors
|
|
576
644
|
if (!descriptors) {
|
|
577
645
|
teardownDirectEventListeners(node)
|
|
578
646
|
return
|
|
@@ -582,7 +650,7 @@ function syncDirectEventListeners(node: CommittedHostNode): void {
|
|
|
582
650
|
return
|
|
583
651
|
}
|
|
584
652
|
|
|
585
|
-
let state = node._directEventState
|
|
653
|
+
let state = node._directEventState
|
|
586
654
|
if (!state) {
|
|
587
655
|
state = { bindings: [] }
|
|
588
656
|
node._directEventState = state
|
|
@@ -590,8 +658,12 @@ function syncDirectEventListeners(node: CommittedHostNode): void {
|
|
|
590
658
|
|
|
591
659
|
let bindings = state.bindings
|
|
592
660
|
for (let index = 0; index < descriptors.length; index++) {
|
|
593
|
-
|
|
594
|
-
|
|
661
|
+
// Indexed access instead of array destructuring: destructuring goes through
|
|
662
|
+
// the iterator protocol and allocates on every host-node update.
|
|
663
|
+
let args = descriptors[index].args
|
|
664
|
+
let type = args[0]
|
|
665
|
+
let handler = args[1]
|
|
666
|
+
let captureBoolean = args[2] ?? false
|
|
595
667
|
let binding = bindings[index]
|
|
596
668
|
|
|
597
669
|
if (!binding) {
|
|
@@ -655,7 +727,7 @@ function removeDirectEventBinding(dom: Element, binding: DirectEventBinding): vo
|
|
|
655
727
|
}
|
|
656
728
|
|
|
657
729
|
function teardownDirectEventListeners(node: CommittedHostNode): void {
|
|
658
|
-
let state = node._directEventState
|
|
730
|
+
let state = node._directEventState
|
|
659
731
|
if (!state) return
|
|
660
732
|
|
|
661
733
|
for (let binding of state.bindings) {
|
|
@@ -666,334 +738,337 @@ function teardownDirectEventListeners(node: CommittedHostNode): void {
|
|
|
666
738
|
node._directEventState = undefined
|
|
667
739
|
}
|
|
668
740
|
|
|
741
|
+
// Teardown for a node whose DOM subtree is being discarded wholesale: abort
|
|
742
|
+
// pending handler work but skip removeEventListener — the listeners die with
|
|
743
|
+
// the detached node, and removing them one-by-one dominates large teardowns.
|
|
744
|
+
function abandonDirectEventListeners(node: CommittedHostNode): void {
|
|
745
|
+
let state = node._directEventState
|
|
746
|
+
if (!state) return
|
|
747
|
+
|
|
748
|
+
for (let binding of state.bindings) {
|
|
749
|
+
binding.reentry?.abort(new DOMException('', 'AbortError'))
|
|
750
|
+
binding.reentry = null
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
state.bindings.length = 0
|
|
754
|
+
node._directEventState = undefined
|
|
755
|
+
}
|
|
756
|
+
|
|
669
757
|
function invokeDirectEventBinding(binding: DirectEventBinding, event: Event): void {
|
|
670
758
|
binding.reentry?.abort(new DOMException('', 'EventReentry'))
|
|
671
759
|
binding.reentry = new AbortController()
|
|
672
760
|
void binding.handler(event, binding.reentry.signal)
|
|
673
761
|
}
|
|
674
762
|
|
|
675
|
-
function diffText(
|
|
763
|
+
function diffText(
|
|
764
|
+
curr: CommittedTextNode,
|
|
765
|
+
next: TextNode,
|
|
766
|
+
vParent: VNodeParent,
|
|
767
|
+
svg: boolean,
|
|
768
|
+
): CommittedTextNode {
|
|
676
769
|
if (curr._text !== next._text) {
|
|
677
770
|
curr._dom.textContent = next._text
|
|
678
771
|
}
|
|
679
|
-
next
|
|
680
|
-
next._parent = vParent
|
|
772
|
+
return commitTextNode(next, vParent, svg, curr._dom)
|
|
681
773
|
}
|
|
682
774
|
|
|
683
775
|
function insert(
|
|
684
|
-
node:
|
|
776
|
+
node: VNodeInput,
|
|
685
777
|
domParent: ParentNode,
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
styles: StyleManager,
|
|
689
|
-
vParent: VNode,
|
|
690
|
-
rootTarget: EventTarget,
|
|
778
|
+
vParent: VNodeParent,
|
|
779
|
+
context: ReconcileContext,
|
|
691
780
|
anchor?: Node,
|
|
692
|
-
cursor?:
|
|
693
|
-
):
|
|
694
|
-
|
|
695
|
-
|
|
781
|
+
cursor?: HydrationCursor,
|
|
782
|
+
): CommittedVNode {
|
|
783
|
+
let { frame, scheduler, styles } = context
|
|
784
|
+
let svg = getSvgContext(vParent, node)
|
|
785
|
+
let hydrationNode = cursor?.current
|
|
696
786
|
|
|
697
787
|
// Stop hydration if cursor has reached the anchor (end boundary)
|
|
698
788
|
// Check BEFORE skipComments to prevent escaping range root markers
|
|
699
|
-
if (
|
|
700
|
-
|
|
789
|
+
if (hydrationNode && anchor && hydrationNode === anchor) {
|
|
790
|
+
hydrationNode = null
|
|
701
791
|
}
|
|
702
792
|
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
793
|
+
// Preserve frame-start markers for non-Frame nodes too, so a following <Frame>
|
|
794
|
+
// (e.g. the first child of a bare Fragment at a clientEntry boundary) can still
|
|
795
|
+
// claim its rmx:f marker during hydration instead of being re-inserted fresh.
|
|
796
|
+
// A rmx:f marker always belongs to a <Frame>, so no non-Frame node should
|
|
797
|
+
// consume one.
|
|
798
|
+
hydrationNode = skipCommentsExceptFrameStart(hydrationNode ?? null)
|
|
707
799
|
|
|
708
800
|
// Also check after skipComments in case we skipped past the anchor
|
|
709
|
-
if (
|
|
710
|
-
|
|
801
|
+
if (hydrationNode && anchor && hydrationNode === anchor) {
|
|
802
|
+
hydrationNode = null
|
|
711
803
|
}
|
|
804
|
+
if (cursor) cursor.current = hydrationNode
|
|
712
805
|
|
|
713
806
|
let doInsert = anchor
|
|
714
807
|
? (dom: Node) => domParent.insertBefore(dom, anchor)
|
|
715
808
|
: (dom: Node) => domParent.appendChild(dom)
|
|
716
809
|
|
|
717
|
-
if (
|
|
718
|
-
return
|
|
810
|
+
if (node.kind === 'empty') {
|
|
811
|
+
return commitNonRenderNode(node, vParent, svg)
|
|
719
812
|
}
|
|
720
813
|
|
|
721
|
-
if (
|
|
722
|
-
if (
|
|
723
|
-
node._parent = vParent
|
|
814
|
+
if (node.kind === 'text') {
|
|
815
|
+
if (hydrationNode instanceof Text) {
|
|
724
816
|
// Handle text node consolidation: server renders adjacent text as single node
|
|
725
817
|
// e.g., <span>Hello {world}</span> → server: "Hello world", client: ["Hello ", "world"]
|
|
726
|
-
if (
|
|
727
|
-
if (
|
|
818
|
+
if (hydrationNode.data !== node._text) {
|
|
819
|
+
if (
|
|
820
|
+
hydrationNode.data.startsWith(node._text) &&
|
|
821
|
+
node._text.length < hydrationNode.data.length
|
|
822
|
+
) {
|
|
728
823
|
// Consolidation case: split the text node at the boundary
|
|
729
824
|
// cursor becomes the first part (node._text), remainder is returned for next vnode
|
|
730
|
-
let remainder =
|
|
731
|
-
|
|
732
|
-
return
|
|
825
|
+
let remainder = hydrationNode.splitText(node._text.length)
|
|
826
|
+
if (cursor) cursor.current = remainder
|
|
827
|
+
return commitTextNode(node, vParent, svg, hydrationNode)
|
|
733
828
|
}
|
|
734
829
|
// Genuine mismatch - correct it
|
|
735
|
-
logHydrationMismatch('text mismatch',
|
|
736
|
-
|
|
830
|
+
logHydrationMismatch('text mismatch', hydrationNode.data, node._text)
|
|
831
|
+
hydrationNode.data = node._text
|
|
737
832
|
}
|
|
738
|
-
|
|
739
|
-
return
|
|
833
|
+
if (cursor) cursor.current = hydrationNode.nextSibling
|
|
834
|
+
return commitTextNode(node, vParent, svg, hydrationNode)
|
|
740
835
|
}
|
|
741
836
|
let dom = document.createTextNode(node._text)
|
|
742
|
-
node._dom = dom
|
|
743
|
-
node._parent = vParent
|
|
744
837
|
doInsert(dom)
|
|
745
|
-
return
|
|
838
|
+
return commitTextNode(node, vParent, svg, dom)
|
|
746
839
|
}
|
|
747
840
|
|
|
748
|
-
if (
|
|
749
|
-
let
|
|
841
|
+
if (node.kind === 'host') {
|
|
842
|
+
let resolved = resolveNodeMixProps(node, vParent, frame, scheduler)
|
|
843
|
+
let hostProps = resolved.props
|
|
844
|
+
let childInputs = node._children
|
|
750
845
|
|
|
751
846
|
if (isHeadHostNode(node)) {
|
|
752
847
|
let targetHead = getDocumentHead(domParent)
|
|
753
848
|
if (targetHead) {
|
|
754
|
-
let childCursor = cursor
|
|
755
|
-
if (
|
|
756
|
-
childCursor =
|
|
757
|
-
let nextCursor =
|
|
758
|
-
if (
|
|
759
|
-
while (
|
|
760
|
-
targetHead.appendChild(
|
|
849
|
+
let childCursor = cursor ? { current: hydrationNode } : undefined
|
|
850
|
+
if (hydrationNode instanceof Element && hydrationNode.tagName.toLowerCase() === 'head') {
|
|
851
|
+
if (childCursor) childCursor.current = hydrationNode.firstChild
|
|
852
|
+
let nextCursor = hydrationNode.nextSibling
|
|
853
|
+
if (hydrationNode !== targetHead) {
|
|
854
|
+
while (hydrationNode.firstChild) {
|
|
855
|
+
targetHead.appendChild(hydrationNode.firstChild)
|
|
761
856
|
}
|
|
762
|
-
|
|
857
|
+
hydrationNode.remove()
|
|
763
858
|
}
|
|
764
|
-
cursor = nextCursor
|
|
859
|
+
if (cursor) cursor.current = nextCursor
|
|
765
860
|
}
|
|
766
861
|
|
|
862
|
+
let committed = commitHostNode(node, vParent, svg, targetHead, resolved)
|
|
767
863
|
// Render explicit <head> children directly into document.head.
|
|
768
|
-
diffChildren(
|
|
864
|
+
committed._children = diffChildren(
|
|
769
865
|
null,
|
|
770
|
-
|
|
866
|
+
childInputs,
|
|
771
867
|
targetHead,
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
styles,
|
|
775
|
-
node,
|
|
776
|
-
rootTarget,
|
|
868
|
+
committed,
|
|
869
|
+
context,
|
|
777
870
|
childCursor,
|
|
778
871
|
)
|
|
779
872
|
patchHostProps({}, hostProps, targetHead)
|
|
780
|
-
setupHostNode(
|
|
781
|
-
if (
|
|
782
|
-
bindNodeMixRuntime(
|
|
873
|
+
setupHostNode(committed, scheduler)
|
|
874
|
+
if (committed._mixState) {
|
|
875
|
+
bindNodeMixRuntime(committed, frame, scheduler, styles)
|
|
783
876
|
}
|
|
784
|
-
return
|
|
877
|
+
return committed
|
|
785
878
|
}
|
|
786
879
|
}
|
|
787
880
|
|
|
788
881
|
// Check for matching mixin-persisted node that can be reclaimed
|
|
789
882
|
let persistedNode = findMatchingPersistedMixinNode(node.type, node.key, domParent)
|
|
790
883
|
if (persistedNode) {
|
|
791
|
-
reclaimPersistedMixinNode(persistedNode, node,
|
|
792
|
-
return cursor
|
|
884
|
+
return reclaimPersistedMixinNode(persistedNode, node, vParent, context)
|
|
793
885
|
}
|
|
794
886
|
|
|
795
|
-
if (
|
|
887
|
+
if (hydrationNode instanceof Element) {
|
|
796
888
|
// SVG elements have case-sensitive tag names (e.g. linearGradient, clipPath)
|
|
797
889
|
// HTML elements are case-insensitive, so we lowercase for comparison
|
|
798
|
-
let cursorTag =
|
|
890
|
+
let cursorTag = svg ? hydrationNode.tagName : hydrationNode.tagName.toLowerCase()
|
|
799
891
|
if (cursorTag === node.type) {
|
|
800
|
-
let nextCursor =
|
|
801
|
-
patchHostProps({}, hostProps,
|
|
892
|
+
let nextCursor = hydrationNode.nextSibling
|
|
893
|
+
patchHostProps({}, hostProps, hydrationNode)
|
|
894
|
+
let committed = commitHostNode(node, vParent, svg, hydrationNode, resolved)
|
|
802
895
|
|
|
803
896
|
// Handle innerHTML prop
|
|
804
897
|
if (hostProps.innerHTML != null) {
|
|
805
|
-
|
|
898
|
+
hydrationNode.innerHTML = hostProps.innerHTML
|
|
806
899
|
} else {
|
|
807
|
-
let childCursor =
|
|
900
|
+
let childCursor = { current: hydrationNode.firstChild }
|
|
808
901
|
// Ignore excess nodes - browser extensions may inject content
|
|
809
|
-
diffChildren(
|
|
902
|
+
committed._children = diffChildren(
|
|
810
903
|
null,
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
styles,
|
|
816
|
-
node,
|
|
817
|
-
rootTarget,
|
|
904
|
+
childInputs,
|
|
905
|
+
hydrationNode,
|
|
906
|
+
committed,
|
|
907
|
+
context,
|
|
818
908
|
childCursor,
|
|
819
909
|
)
|
|
820
910
|
}
|
|
821
911
|
|
|
822
|
-
setupHostNode(
|
|
823
|
-
if (
|
|
824
|
-
bindNodeMixRuntime(
|
|
912
|
+
setupHostNode(committed, scheduler)
|
|
913
|
+
if (committed._mixState) {
|
|
914
|
+
bindNodeMixRuntime(committed, frame, scheduler, styles)
|
|
825
915
|
}
|
|
826
|
-
|
|
916
|
+
if (cursor) cursor.current = nextCursor
|
|
917
|
+
return committed
|
|
827
918
|
} else {
|
|
828
919
|
// Type mismatch - try single-advance retry to handle browser extension injections
|
|
829
920
|
// at the start of containers. Skip this node and try the next sibling once.
|
|
830
|
-
let nextSibling = skipComments(
|
|
921
|
+
let nextSibling = skipComments(hydrationNode.nextSibling)
|
|
831
922
|
if (nextSibling instanceof Element) {
|
|
832
|
-
let nextTag =
|
|
923
|
+
let nextTag = svg ? nextSibling.tagName : nextSibling.tagName.toLowerCase()
|
|
833
924
|
if (nextTag === node.type) {
|
|
834
925
|
let nextCursor = nextSibling.nextSibling
|
|
835
926
|
// Found a match after skipping - adopt it and leave skipped node in place
|
|
836
927
|
patchHostProps({}, hostProps, nextSibling)
|
|
928
|
+
let committed = commitHostNode(node, vParent, svg, nextSibling, resolved)
|
|
837
929
|
|
|
838
930
|
if (hostProps.innerHTML != null) {
|
|
839
|
-
nextSibling.innerHTML = hostProps.innerHTML
|
|
931
|
+
nextSibling.innerHTML = hostProps.innerHTML
|
|
840
932
|
} else {
|
|
841
|
-
let childCursor = nextSibling.firstChild
|
|
842
|
-
diffChildren(
|
|
933
|
+
let childCursor = { current: nextSibling.firstChild }
|
|
934
|
+
committed._children = diffChildren(
|
|
843
935
|
null,
|
|
844
|
-
|
|
936
|
+
childInputs,
|
|
845
937
|
nextSibling,
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
styles,
|
|
849
|
-
node,
|
|
850
|
-
rootTarget,
|
|
938
|
+
committed,
|
|
939
|
+
context,
|
|
851
940
|
childCursor,
|
|
852
941
|
)
|
|
853
942
|
}
|
|
854
943
|
|
|
855
|
-
setupHostNode(
|
|
856
|
-
if (
|
|
857
|
-
bindNodeMixRuntime(
|
|
944
|
+
setupHostNode(committed, scheduler)
|
|
945
|
+
if (committed._mixState) {
|
|
946
|
+
bindNodeMixRuntime(committed, frame, scheduler, styles)
|
|
858
947
|
}
|
|
859
|
-
|
|
948
|
+
if (cursor) cursor.current = nextCursor
|
|
949
|
+
return committed
|
|
860
950
|
}
|
|
861
951
|
}
|
|
862
952
|
// Retry failed - log mismatch and create new element (don't remove mismatched nodes)
|
|
863
953
|
logHydrationMismatch('tag', cursorTag, node.type)
|
|
864
|
-
cursor = undefined // stop hydration for this tree
|
|
954
|
+
if (cursor) cursor.current = undefined // stop hydration for this tree
|
|
865
955
|
}
|
|
866
956
|
}
|
|
867
|
-
let dom = node.
|
|
868
|
-
? document.createElementNS(SVG_NS, node.type)
|
|
869
|
-
: document.createElement(node.type)
|
|
957
|
+
let dom = svg ? document.createElementNS(SVG_NS, node.type) : document.createElement(node.type)
|
|
870
958
|
patchHostProps({}, hostProps, dom)
|
|
959
|
+
let committed = commitHostNode(node, vParent, svg, dom, resolved)
|
|
871
960
|
|
|
872
961
|
// Handle innerHTML prop
|
|
873
962
|
if (hostProps.innerHTML != null) {
|
|
874
|
-
dom.innerHTML = hostProps.innerHTML
|
|
963
|
+
dom.innerHTML = hostProps.innerHTML
|
|
875
964
|
} else {
|
|
876
|
-
diffChildren(null,
|
|
965
|
+
committed._children = diffChildren(null, childInputs, dom, committed, context)
|
|
877
966
|
}
|
|
878
967
|
|
|
879
|
-
setupHostNode(
|
|
880
|
-
if (
|
|
881
|
-
bindNodeMixRuntime(
|
|
968
|
+
setupHostNode(committed, scheduler)
|
|
969
|
+
if (committed._mixState) {
|
|
970
|
+
bindNodeMixRuntime(committed, frame, scheduler, styles, false, domParent)
|
|
882
971
|
}
|
|
883
972
|
doInsert(dom)
|
|
884
|
-
return
|
|
973
|
+
return committed
|
|
885
974
|
}
|
|
886
975
|
|
|
887
|
-
if (
|
|
976
|
+
if (node.kind === 'fragment') {
|
|
977
|
+
let childInputs = node._children
|
|
978
|
+
let committed = beginFragmentNode(node, vParent, svg)
|
|
979
|
+
let children: Array<VNodeInput | CommittedVNode> = childInputs
|
|
888
980
|
// Insert fragment children in order before the same anchor
|
|
889
|
-
for (let
|
|
890
|
-
|
|
981
|
+
for (let i = 0; i < childInputs.length; i++) {
|
|
982
|
+
children[i] = insert(childInputs[i], domParent, committed, context, anchor, cursor)
|
|
891
983
|
}
|
|
892
|
-
|
|
984
|
+
committed._children = children as CommittedVNode[]
|
|
985
|
+
return committed
|
|
893
986
|
}
|
|
894
987
|
|
|
895
|
-
if (
|
|
896
|
-
return diffComponent(
|
|
897
|
-
null,
|
|
898
|
-
node,
|
|
899
|
-
frame,
|
|
900
|
-
scheduler,
|
|
901
|
-
styles,
|
|
902
|
-
domParent,
|
|
903
|
-
vParent,
|
|
904
|
-
rootTarget,
|
|
905
|
-
anchor,
|
|
906
|
-
cursor,
|
|
907
|
-
)
|
|
988
|
+
if (node.kind === 'component') {
|
|
989
|
+
return diffComponent(null, node, domParent, vParent, context, svg, anchor, cursor)
|
|
908
990
|
}
|
|
909
991
|
|
|
910
|
-
if (node.
|
|
911
|
-
return insertFrame(
|
|
912
|
-
node,
|
|
913
|
-
domParent,
|
|
914
|
-
frame,
|
|
915
|
-
scheduler,
|
|
916
|
-
styles,
|
|
917
|
-
vParent,
|
|
918
|
-
rootTarget,
|
|
919
|
-
anchor,
|
|
920
|
-
cursor,
|
|
921
|
-
)
|
|
992
|
+
if (node.kind === 'frame') {
|
|
993
|
+
return insertFrame(node, domParent, vParent, context, svg, anchor, cursor)
|
|
922
994
|
}
|
|
923
995
|
|
|
924
996
|
invariant(false, 'Unexpected node type')
|
|
925
997
|
}
|
|
926
998
|
|
|
927
999
|
function diffFrame(
|
|
928
|
-
curr:
|
|
929
|
-
next:
|
|
1000
|
+
curr: CommittedFrameNode,
|
|
1001
|
+
next: FrameNode,
|
|
930
1002
|
domParent: ParentNode,
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
vParent: VNode,
|
|
935
|
-
rootTarget: EventTarget,
|
|
1003
|
+
vParent: VNodeParent,
|
|
1004
|
+
context: ReconcileContext,
|
|
1005
|
+
svg: boolean,
|
|
936
1006
|
anchor?: Node,
|
|
937
|
-
):
|
|
1007
|
+
): CommittedFrameNode {
|
|
1008
|
+
let { frame } = context
|
|
938
1009
|
let currSrc = getFrameSrc(curr)
|
|
939
1010
|
let nextSrc = getFrameSrc(next)
|
|
940
1011
|
let currName = getFrameName(curr)
|
|
941
1012
|
let nextName = getFrameName(next)
|
|
942
1013
|
|
|
943
1014
|
if (currName !== nextName) {
|
|
944
|
-
let replaceAnchor = curr._rangeEnd
|
|
945
|
-
remove(curr, domParent,
|
|
946
|
-
|
|
947
|
-
return
|
|
1015
|
+
let replaceAnchor = curr._rangeEnd.nextSibling ?? anchor
|
|
1016
|
+
remove(curr, domParent, context)
|
|
1017
|
+
return insertFrame(next, domParent, vParent, context, svg, replaceAnchor)
|
|
948
1018
|
}
|
|
949
1019
|
|
|
950
1020
|
// If the frame hasn't resolved yet, preserve existing cancel/remount behavior
|
|
951
1021
|
// so pending streams from the old src cannot take over the new src.
|
|
952
|
-
if (currSrc !== nextSrc && !curr.
|
|
953
|
-
let replaceAnchor = curr._rangeEnd
|
|
954
|
-
remove(curr, domParent,
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
1022
|
+
if (currSrc !== nextSrc && !curr._state.resolved) {
|
|
1023
|
+
let replaceAnchor = curr._rangeEnd.nextSibling ?? anchor
|
|
1024
|
+
remove(curr, domParent, context)
|
|
1025
|
+
return insertFrame(next, domParent, vParent, context, svg, replaceAnchor)
|
|
1026
|
+
}
|
|
1027
|
+
|
|
1028
|
+
let committed = next as unknown as CommittedFrameNode
|
|
1029
|
+
Object.assign(committed, {
|
|
1030
|
+
_rangeStart: curr._rangeStart,
|
|
1031
|
+
_rangeEnd: curr._rangeEnd,
|
|
1032
|
+
_state: curr._state,
|
|
1033
|
+
_parent: vParent,
|
|
1034
|
+
_svg: svg,
|
|
1035
|
+
})
|
|
958
1036
|
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
next._frameFallbackRoot = curr._frameFallbackRoot
|
|
963
|
-
next._frameResolveToken = curr._frameResolveToken
|
|
964
|
-
next._frameResolved = curr._frameResolved
|
|
965
|
-
next._parent = vParent
|
|
1037
|
+
let frameRuntime = getFrameRuntime(frame)
|
|
1038
|
+
let frameInstance = committed._state.instance
|
|
1039
|
+
let serverFrameReload = frameRuntime?.serverFrameReload
|
|
966
1040
|
|
|
967
1041
|
if (currSrc !== nextSrc) {
|
|
968
|
-
let frameInstance = next._frameInstance as FrameInstance | undefined
|
|
969
1042
|
if (frameInstance) {
|
|
970
1043
|
frameInstance.handle.src = nextSrc
|
|
971
1044
|
}
|
|
972
1045
|
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
resolveClientFrame(next, runtime)
|
|
1046
|
+
if (frameRuntime) {
|
|
1047
|
+
resolveClientFrame(committed, frameRuntime, serverFrameReload)
|
|
976
1048
|
}
|
|
1049
|
+
} else if (frameRuntime && frameInstance && serverFrameReload) {
|
|
1050
|
+
// Reload client frames that have the same src during a render triggered by an ancestor frame reload
|
|
1051
|
+
resolveClientFrame(committed, frameRuntime, serverFrameReload)
|
|
977
1052
|
}
|
|
978
1053
|
|
|
979
|
-
if (!
|
|
980
|
-
|
|
1054
|
+
if (!committed._state.resolved && committed._state.fallbackRoot) {
|
|
1055
|
+
committed._state.fallbackRoot.render(committed.props.fallback ?? null)
|
|
981
1056
|
}
|
|
1057
|
+
return committed
|
|
982
1058
|
}
|
|
983
1059
|
|
|
984
1060
|
function insertFrame(
|
|
985
|
-
node:
|
|
1061
|
+
node: FrameNode,
|
|
986
1062
|
domParent: ParentNode,
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
vParent: VNode,
|
|
991
|
-
rootTarget: EventTarget,
|
|
1063
|
+
vParent: VNodeParent,
|
|
1064
|
+
context: ReconcileContext,
|
|
1065
|
+
svg: boolean,
|
|
992
1066
|
anchor?: Node,
|
|
993
|
-
cursor?:
|
|
994
|
-
):
|
|
1067
|
+
cursor?: HydrationCursor,
|
|
1068
|
+
): CommittedFrameNode {
|
|
1069
|
+
let { frame, styles } = context
|
|
995
1070
|
let runtime = getFrameRuntime(frame)
|
|
996
|
-
if (!runtime ||
|
|
1071
|
+
if (!runtime || runtime.canResolveFrames === false) {
|
|
997
1072
|
throw new Error(
|
|
998
1073
|
'Cannot render <Frame /> without frame runtime. Use run() or pass frameInit to createRoot/createRangeRoot.',
|
|
999
1074
|
)
|
|
@@ -1001,33 +1076,23 @@ function insertFrame(
|
|
|
1001
1076
|
|
|
1002
1077
|
// Hydration path: adopt server-rendered frame markers and reuse the existing
|
|
1003
1078
|
// frame instance created during createSubFrames().
|
|
1004
|
-
if (isFrameStartComment(cursor)) {
|
|
1005
|
-
let start = cursor
|
|
1079
|
+
if (isFrameStartComment(cursor?.current)) {
|
|
1080
|
+
let start = cursor.current
|
|
1006
1081
|
let end = findFrameEndComment(start)
|
|
1007
1082
|
if (end) {
|
|
1008
|
-
node._rangeStart = start
|
|
1009
|
-
node._rangeEnd = end
|
|
1010
|
-
node._parent = vParent
|
|
1011
|
-
node._frameResolveToken = 0
|
|
1012
|
-
node._frameResolveController = undefined
|
|
1013
|
-
node._frameFallbackRoot = undefined
|
|
1014
|
-
node._frameResolved = true
|
|
1015
|
-
|
|
1016
|
-
let frameId = getFrameIdFromComment(start)
|
|
1017
|
-
let marker = frameId ? runtime.data.f?.[frameId] : undefined
|
|
1018
|
-
let src = marker?.src ?? getFrameSrc(node)
|
|
1019
1083
|
let instance = runtime.frameInstances.get(start)
|
|
1084
|
+
let src = instance?.handle.src ?? getFrameSrc(node)
|
|
1020
1085
|
if (!instance) {
|
|
1021
1086
|
instance = createFrame([start, end], {
|
|
1022
1087
|
name: getFrameName(node),
|
|
1023
1088
|
src,
|
|
1024
|
-
marker: frameId && marker ? { ...marker, id: frameId } : undefined,
|
|
1025
1089
|
errorTarget: runtime.errorTarget,
|
|
1026
1090
|
loadModule: runtime.loadModule,
|
|
1027
1091
|
resolveFrame: runtime.resolveFrame,
|
|
1028
1092
|
pendingClientEntries: runtime.pendingClientEntries,
|
|
1029
1093
|
scheduler: runtime.scheduler,
|
|
1030
|
-
|
|
1094
|
+
styleManager: runtime.styleManager,
|
|
1095
|
+
data: {},
|
|
1031
1096
|
moduleCache: runtime.moduleCache,
|
|
1032
1097
|
moduleLoads: runtime.moduleLoads,
|
|
1033
1098
|
frameInstances: runtime.frameInstances,
|
|
@@ -1036,9 +1101,20 @@ function insertFrame(
|
|
|
1036
1101
|
runtime.frameInstances.set(start, instance)
|
|
1037
1102
|
}
|
|
1038
1103
|
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1104
|
+
cursor.current = end.nextSibling
|
|
1105
|
+
return Object.assign(node as unknown as CommittedFrameNode, {
|
|
1106
|
+
_rangeStart: start,
|
|
1107
|
+
_rangeEnd: end,
|
|
1108
|
+
_parent: vParent,
|
|
1109
|
+
_svg: svg,
|
|
1110
|
+
_state: {
|
|
1111
|
+
instance,
|
|
1112
|
+
resolveToken: 0,
|
|
1113
|
+
resolveController: undefined,
|
|
1114
|
+
fallbackRoot: undefined,
|
|
1115
|
+
resolved: true,
|
|
1116
|
+
},
|
|
1117
|
+
})
|
|
1042
1118
|
}
|
|
1043
1119
|
}
|
|
1044
1120
|
|
|
@@ -1051,18 +1127,11 @@ function insertFrame(
|
|
|
1051
1127
|
doInsert(start)
|
|
1052
1128
|
doInsert(end)
|
|
1053
1129
|
|
|
1054
|
-
node._rangeStart = start
|
|
1055
|
-
node._rangeEnd = end
|
|
1056
|
-
node._parent = vParent
|
|
1057
|
-
|
|
1058
1130
|
let fallbackRoot = createRangeRoot([start, end], {
|
|
1059
1131
|
frame,
|
|
1060
1132
|
styleManager: styles,
|
|
1061
1133
|
})
|
|
1062
|
-
fallbackRoot.render(node.props
|
|
1063
|
-
node._frameFallbackRoot = fallbackRoot
|
|
1064
|
-
node._frameResolved = false
|
|
1065
|
-
node._frameResolveToken = 0
|
|
1134
|
+
fallbackRoot.render(node.props.fallback ?? null)
|
|
1066
1135
|
|
|
1067
1136
|
let instance = createFrame([start, end], {
|
|
1068
1137
|
name: getFrameName(node),
|
|
@@ -1072,61 +1141,94 @@ function insertFrame(
|
|
|
1072
1141
|
resolveFrame: runtime.resolveFrame,
|
|
1073
1142
|
pendingClientEntries: runtime.pendingClientEntries,
|
|
1074
1143
|
scheduler: runtime.scheduler,
|
|
1075
|
-
|
|
1144
|
+
styleManager: runtime.styleManager,
|
|
1145
|
+
data: {},
|
|
1076
1146
|
moduleCache: runtime.moduleCache,
|
|
1077
1147
|
moduleLoads: runtime.moduleLoads,
|
|
1078
1148
|
frameInstances: runtime.frameInstances,
|
|
1079
1149
|
namedFrames: runtime.namedFrames,
|
|
1080
1150
|
})
|
|
1081
|
-
node._frameInstance = instance
|
|
1082
1151
|
runtime.frameInstances.set(start, instance)
|
|
1083
1152
|
|
|
1084
|
-
|
|
1153
|
+
let committed = Object.assign(node as unknown as CommittedFrameNode, {
|
|
1154
|
+
_rangeStart: start,
|
|
1155
|
+
_rangeEnd: end,
|
|
1156
|
+
_parent: vParent,
|
|
1157
|
+
_svg: svg,
|
|
1158
|
+
_state: {
|
|
1159
|
+
instance,
|
|
1160
|
+
fallbackRoot,
|
|
1161
|
+
resolved: false,
|
|
1162
|
+
resolveToken: 0,
|
|
1163
|
+
resolveController: undefined,
|
|
1164
|
+
},
|
|
1165
|
+
})
|
|
1166
|
+
resolveClientFrame(committed, runtime)
|
|
1085
1167
|
|
|
1086
|
-
return
|
|
1168
|
+
return committed
|
|
1087
1169
|
}
|
|
1088
1170
|
|
|
1089
|
-
function resolveClientFrame(
|
|
1171
|
+
function resolveClientFrame(
|
|
1172
|
+
node: CommittedFrameNode,
|
|
1173
|
+
runtime: FrameRuntime,
|
|
1174
|
+
serverFrameReload?: { signal: AbortSignal },
|
|
1175
|
+
): void {
|
|
1090
1176
|
let frameSrc = getFrameSrc(node)
|
|
1091
|
-
let
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
let token =
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
let
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
.
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1177
|
+
let state = node._state
|
|
1178
|
+
let instance = state.instance
|
|
1179
|
+
|
|
1180
|
+
let token = state.resolveToken + 1
|
|
1181
|
+
state.resolveToken = token
|
|
1182
|
+
state.resolveController?.abort()
|
|
1183
|
+
let reload = serverFrameReload
|
|
1184
|
+
? instance.beginClientFrameReloadForAncestorReload(serverFrameReload.signal)
|
|
1185
|
+
: undefined
|
|
1186
|
+
if (!reload) {
|
|
1187
|
+
instance.cancelReload()
|
|
1188
|
+
}
|
|
1189
|
+
let resolveController = reload?.controller ?? new AbortController()
|
|
1190
|
+
state.resolveController = resolveController
|
|
1191
|
+
|
|
1192
|
+
Promise.resolve()
|
|
1193
|
+
.then(() =>
|
|
1194
|
+
runtime.resolveFrame(frameSrc, {
|
|
1195
|
+
signal: resolveController.signal,
|
|
1196
|
+
target: getFrameName(node),
|
|
1197
|
+
}),
|
|
1198
|
+
)
|
|
1199
|
+
.then(async (resolution) => {
|
|
1200
|
+
if (state.resolveToken !== token || resolveController.signal.aborted) return
|
|
1201
|
+
let { content } = await unwrapFrameResolution(resolution)
|
|
1202
|
+
if (state.resolveToken !== token || resolveController.signal.aborted) return
|
|
1203
|
+
state.fallbackRoot?.dispose()
|
|
1204
|
+
state.fallbackRoot = undefined
|
|
1105
1205
|
let nextContent = asAbortableFrameContent(content, resolveController.signal)
|
|
1106
1206
|
await instance.render(nextContent, { signal: resolveController.signal })
|
|
1107
|
-
if (
|
|
1108
|
-
|
|
1207
|
+
if (state.resolveToken !== token || resolveController.signal.aborted) return
|
|
1208
|
+
state.resolved = true
|
|
1209
|
+
})
|
|
1210
|
+
.catch((error) => {
|
|
1211
|
+
if (reload && state.resolveToken === token && !resolveController.signal.aborted) {
|
|
1212
|
+
runtime.errorTarget.dispatchEvent(createComponentErrorEvent(error))
|
|
1213
|
+
}
|
|
1109
1214
|
})
|
|
1110
|
-
.catch(() => {})
|
|
1111
1215
|
.finally(() => {
|
|
1112
|
-
|
|
1113
|
-
|
|
1216
|
+
reload?.complete()
|
|
1217
|
+
if (state.resolveController === resolveController) {
|
|
1218
|
+
state.resolveController = undefined
|
|
1114
1219
|
}
|
|
1115
1220
|
})
|
|
1116
1221
|
}
|
|
1117
1222
|
|
|
1118
|
-
function disposeFrameResources(node:
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1223
|
+
function disposeFrameResources(node: CommittedFrameNode): void {
|
|
1224
|
+
let state = node._state
|
|
1225
|
+
state.resolveToken++
|
|
1226
|
+
state.resolveController?.abort()
|
|
1227
|
+
state.resolveController = undefined
|
|
1228
|
+
state.fallbackRoot?.dispose()
|
|
1229
|
+
state.fallbackRoot = undefined
|
|
1124
1230
|
|
|
1125
|
-
|
|
1126
|
-
if (frameInstance) {
|
|
1127
|
-
frameInstance.dispose()
|
|
1128
|
-
node._frameInstance = undefined
|
|
1129
|
-
}
|
|
1231
|
+
state.instance.dispose()
|
|
1130
1232
|
}
|
|
1131
1233
|
|
|
1132
1234
|
function asAbortableFrameContent(content: FrameContent, signal: AbortSignal): FrameContent {
|
|
@@ -1157,26 +1259,26 @@ function createAbortableReadableStream(
|
|
|
1157
1259
|
}
|
|
1158
1260
|
|
|
1159
1261
|
let removeAbortReadListener: undefined | (() => void)
|
|
1160
|
-
let abortRead = new Promise<
|
|
1262
|
+
let abortRead = new Promise<{ done: true; value: undefined }>((resolve) => {
|
|
1161
1263
|
if (signal.aborted) {
|
|
1162
|
-
resolve({ done: true, value: undefined
|
|
1264
|
+
resolve({ done: true, value: undefined })
|
|
1163
1265
|
return
|
|
1164
1266
|
}
|
|
1165
1267
|
let onAbortRead = () => {
|
|
1166
|
-
resolve({ done: true, value: undefined
|
|
1268
|
+
resolve({ done: true, value: undefined })
|
|
1167
1269
|
}
|
|
1168
1270
|
removeAbortReadListener = () => signal.removeEventListener('abort', onAbortRead)
|
|
1169
1271
|
signal.addEventListener('abort', onAbortRead, { once: true })
|
|
1170
1272
|
})
|
|
1171
1273
|
|
|
1172
|
-
let
|
|
1274
|
+
let result = await Promise.race([reader.read(), abortRead])
|
|
1173
1275
|
removeAbortReadListener?.()
|
|
1174
1276
|
|
|
1175
|
-
if (done) {
|
|
1277
|
+
if (result.done) {
|
|
1176
1278
|
controller.close()
|
|
1177
1279
|
return
|
|
1178
1280
|
}
|
|
1179
|
-
controller.enqueue(value)
|
|
1281
|
+
controller.enqueue(result.value)
|
|
1180
1282
|
},
|
|
1181
1283
|
cancel(reason) {
|
|
1182
1284
|
signal.removeEventListener('abort', onAbort)
|
|
@@ -1185,11 +1287,9 @@ function createAbortableReadableStream(
|
|
|
1185
1287
|
})
|
|
1186
1288
|
}
|
|
1187
1289
|
|
|
1188
|
-
function removeFrameDomRange(node:
|
|
1290
|
+
function removeFrameDomRange(node: CommittedFrameNode, domParent: ParentNode): void {
|
|
1189
1291
|
let start = node._rangeStart
|
|
1190
1292
|
let end = node._rangeEnd
|
|
1191
|
-
if (!(start instanceof Comment) || !(end instanceof Comment)) return
|
|
1192
|
-
|
|
1193
1293
|
let cursor: Node | null = start
|
|
1194
1294
|
while (cursor) {
|
|
1195
1295
|
let nextSibling: Node | null = cursor.nextSibling
|
|
@@ -1199,23 +1299,19 @@ function removeFrameDomRange(node: VNode, domParent: ParentNode): void {
|
|
|
1199
1299
|
if (cursor === end) break
|
|
1200
1300
|
cursor = nextSibling
|
|
1201
1301
|
}
|
|
1202
|
-
|
|
1203
|
-
node._rangeStart = undefined
|
|
1204
|
-
node._rangeEnd = undefined
|
|
1205
1302
|
}
|
|
1206
1303
|
|
|
1207
1304
|
function getFrameRuntime(frame: FrameHandle): FrameRuntime | undefined {
|
|
1208
|
-
|
|
1305
|
+
let runtime = frame.$runtime
|
|
1306
|
+
return isFrameRuntime(runtime) ? runtime : undefined
|
|
1209
1307
|
}
|
|
1210
1308
|
|
|
1211
|
-
function getFrameSrc(node:
|
|
1212
|
-
|
|
1213
|
-
invariant(typeof src === 'string' && src.length > 0, '<Frame /> requires a src prop')
|
|
1214
|
-
return src
|
|
1309
|
+
function getFrameSrc(node: FrameNode | CommittedFrameNode): string {
|
|
1310
|
+
return node.props.src
|
|
1215
1311
|
}
|
|
1216
1312
|
|
|
1217
|
-
function getFrameName(node:
|
|
1218
|
-
let name = node.props
|
|
1313
|
+
function getFrameName(node: FrameNode | CommittedFrameNode): string | undefined {
|
|
1314
|
+
let name = node.props.name
|
|
1219
1315
|
return typeof name === 'string' && name.length > 0 ? name : undefined
|
|
1220
1316
|
}
|
|
1221
1317
|
|
|
@@ -1232,17 +1328,15 @@ function skipCommentsExceptFrameStart(cursor: Node | null): Node | null {
|
|
|
1232
1328
|
}
|
|
1233
1329
|
|
|
1234
1330
|
function isFrameStartComment(node: Node | null | undefined): node is Comment {
|
|
1235
|
-
return node
|
|
1331
|
+
return isCommentNode(node) && node.data.trim().startsWith('rmx:f:')
|
|
1236
1332
|
}
|
|
1237
1333
|
|
|
1238
1334
|
function isFrameEndComment(node: Node | null | undefined): node is Comment {
|
|
1239
|
-
return node
|
|
1335
|
+
return isCommentNode(node) && node.data.trim() === '/rmx:f'
|
|
1240
1336
|
}
|
|
1241
1337
|
|
|
1242
|
-
function
|
|
1243
|
-
|
|
1244
|
-
if (!text.startsWith('rmx:f:')) return undefined
|
|
1245
|
-
return text.slice('rmx:f:'.length)
|
|
1338
|
+
function isCommentNode(node: Node | null | undefined): node is Comment {
|
|
1339
|
+
return node?.nodeType === Node.COMMENT_NODE
|
|
1246
1340
|
}
|
|
1247
1341
|
|
|
1248
1342
|
function findFrameEndComment(start: Comment): Comment | null {
|
|
@@ -1262,72 +1356,53 @@ function findFrameEndComment(start: Comment): Comment | null {
|
|
|
1262
1356
|
}
|
|
1263
1357
|
|
|
1264
1358
|
export function renderComponent(
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
next: ComponentNode,
|
|
1359
|
+
currContent: CommittedVNode | null,
|
|
1360
|
+
next: MountingComponentNode | CommittedComponentNode,
|
|
1268
1361
|
domParent: ParentNode,
|
|
1269
|
-
|
|
1270
|
-
scheduler: Scheduler,
|
|
1271
|
-
styles: StyleManager,
|
|
1272
|
-
rootTarget: EventTarget,
|
|
1273
|
-
vParent?: VNode,
|
|
1362
|
+
context: ReconcileContext,
|
|
1274
1363
|
anchor?: Node,
|
|
1275
|
-
cursor?:
|
|
1276
|
-
):
|
|
1277
|
-
|
|
1364
|
+
cursor?: HydrationCursor,
|
|
1365
|
+
): CommittedComponentNode {
|
|
1366
|
+
let { scheduler } = context
|
|
1367
|
+
let handle = next._handle
|
|
1368
|
+
if (handle.isRemoved()) {
|
|
1369
|
+
invariant('_content' in next, 'Expected removed component to be committed')
|
|
1370
|
+
return next
|
|
1371
|
+
}
|
|
1278
1372
|
|
|
1279
1373
|
let [element, tasks] = handle.render(next.props)
|
|
1280
|
-
let content = toVNode(element)
|
|
1281
|
-
let
|
|
1282
|
-
|
|
1283
|
-
content,
|
|
1284
|
-
domParent,
|
|
1285
|
-
frame,
|
|
1286
|
-
scheduler,
|
|
1287
|
-
styles,
|
|
1288
|
-
next,
|
|
1289
|
-
rootTarget,
|
|
1290
|
-
anchor,
|
|
1291
|
-
cursor,
|
|
1292
|
-
)
|
|
1293
|
-
next._content = content
|
|
1294
|
-
next._handle = handle
|
|
1295
|
-
next._parent = vParent
|
|
1296
|
-
|
|
1297
|
-
let committed = next as CommittedComponentNode
|
|
1298
|
-
handle.setScheduleUpdate(() => {
|
|
1299
|
-
scheduler.enqueue(committed, domParent)
|
|
1300
|
-
})
|
|
1374
|
+
let content = diffVNodes(currContent, toVNode(element), domParent, next, context, anchor, cursor)
|
|
1375
|
+
let committed = commitComponentNode(next, content)
|
|
1376
|
+
handle.setScheduleUpdate(scheduler, committed, domParent)
|
|
1301
1377
|
|
|
1302
1378
|
scheduler.enqueueTasks(tasks)
|
|
1303
1379
|
|
|
1304
|
-
return
|
|
1380
|
+
return committed
|
|
1305
1381
|
}
|
|
1306
1382
|
|
|
1307
1383
|
function diffComponent(
|
|
1308
1384
|
curr: CommittedComponentNode | null,
|
|
1309
1385
|
next: ComponentNode,
|
|
1310
|
-
frame: FrameHandle,
|
|
1311
|
-
scheduler: Scheduler,
|
|
1312
|
-
styles: StyleManager,
|
|
1313
1386
|
domParent: ParentNode,
|
|
1314
|
-
vParent:
|
|
1315
|
-
|
|
1387
|
+
vParent: VNodeParent,
|
|
1388
|
+
context: ReconcileContext,
|
|
1389
|
+
svg: boolean,
|
|
1316
1390
|
anchor?: Node,
|
|
1317
|
-
cursor?:
|
|
1318
|
-
):
|
|
1391
|
+
cursor?: HydrationCursor,
|
|
1392
|
+
): CommittedComponentNode {
|
|
1393
|
+
let { frame } = context
|
|
1319
1394
|
if (curr === null) {
|
|
1320
|
-
let componentId = vParent._pendingHydrationComponentId
|
|
1395
|
+
let componentId = vParent.kind === 'root' ? vParent._pendingHydrationComponentId : undefined
|
|
1321
1396
|
if (componentId) {
|
|
1322
|
-
vParent._pendingHydrationComponentId = undefined
|
|
1397
|
+
if (vParent.kind === 'root') vParent._pendingHydrationComponentId = undefined
|
|
1323
1398
|
} else {
|
|
1324
1399
|
componentId = `c${++idCounter}`
|
|
1325
1400
|
}
|
|
1326
|
-
|
|
1401
|
+
let handle = createComponent({
|
|
1327
1402
|
id: componentId,
|
|
1328
1403
|
frame,
|
|
1329
1404
|
type: next.type,
|
|
1330
|
-
getContext: (type:
|
|
1405
|
+
getContext: (type: ElementFunction) => findContextFromAncestry(vParent, type),
|
|
1331
1406
|
getFrameByName(name: string) {
|
|
1332
1407
|
let runtime = getFrameRuntime(frame)
|
|
1333
1408
|
return runtime?.namedFrames.get(name)
|
|
@@ -1337,123 +1412,102 @@ function diffComponent(
|
|
|
1337
1412
|
return runtime?.topFrame
|
|
1338
1413
|
},
|
|
1339
1414
|
})
|
|
1415
|
+
let mounting = beginComponentNode(next, vParent, svg, handle, context)
|
|
1340
1416
|
|
|
1341
|
-
return renderComponent(
|
|
1342
|
-
next._handle,
|
|
1343
|
-
null,
|
|
1344
|
-
next,
|
|
1345
|
-
domParent,
|
|
1346
|
-
frame,
|
|
1347
|
-
scheduler,
|
|
1348
|
-
styles,
|
|
1349
|
-
rootTarget,
|
|
1350
|
-
vParent,
|
|
1351
|
-
anchor,
|
|
1352
|
-
cursor,
|
|
1353
|
-
)
|
|
1417
|
+
return renderComponent(null, mounting, domParent, context, anchor, cursor)
|
|
1354
1418
|
}
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
return renderComponent(
|
|
1358
|
-
_handle,
|
|
1359
|
-
_content,
|
|
1360
|
-
next,
|
|
1361
|
-
domParent,
|
|
1362
|
-
frame,
|
|
1363
|
-
scheduler,
|
|
1364
|
-
styles,
|
|
1365
|
-
rootTarget,
|
|
1366
|
-
vParent,
|
|
1367
|
-
anchor,
|
|
1368
|
-
cursor,
|
|
1369
|
-
)
|
|
1419
|
+
let mounting = beginComponentNode(next, vParent, svg, curr._handle, context)
|
|
1420
|
+
return renderComponent(curr._content, mounting, domParent, context, anchor, cursor)
|
|
1370
1421
|
}
|
|
1371
1422
|
|
|
1372
1423
|
// Cleanup without DOM removal - used for descendants when parent DOM node is removed
|
|
1373
|
-
function cleanupDescendants(node:
|
|
1424
|
+
function cleanupDescendants(node: CommittedVNode, context: ReconcileContext): void {
|
|
1425
|
+
let { scheduler } = context
|
|
1374
1426
|
if (isCommittedTextNode(node)) {
|
|
1375
1427
|
return
|
|
1376
1428
|
}
|
|
1377
1429
|
|
|
1378
1430
|
if (isCommittedHostNode(node)) {
|
|
1379
|
-
|
|
1380
|
-
|
|
1431
|
+
let children = node._children
|
|
1432
|
+
for (let i = 0; i < children.length; i++) {
|
|
1433
|
+
cleanupDescendants(children[i], context)
|
|
1381
1434
|
}
|
|
1382
1435
|
|
|
1383
|
-
teardownMixins(node._mixState
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
if (node._controller) node._controller.abort()
|
|
1436
|
+
teardownMixins(node._mixState)
|
|
1437
|
+
abandonDirectEventListeners(node)
|
|
1438
|
+
abandonControlledReflection(node)
|
|
1387
1439
|
return
|
|
1388
1440
|
}
|
|
1389
1441
|
|
|
1390
1442
|
if (isFragmentNode(node)) {
|
|
1391
|
-
|
|
1392
|
-
|
|
1443
|
+
let children = node._children
|
|
1444
|
+
for (let i = 0; i < children.length; i++) {
|
|
1445
|
+
cleanupDescendants(children[i], context)
|
|
1393
1446
|
}
|
|
1394
1447
|
return
|
|
1395
1448
|
}
|
|
1396
1449
|
|
|
1397
1450
|
if (isCommittedComponentNode(node)) {
|
|
1398
|
-
cleanupDescendants(node._content,
|
|
1451
|
+
cleanupDescendants(node._content, context)
|
|
1399
1452
|
let tasks = node._handle.remove()
|
|
1400
1453
|
scheduler.enqueueTasks(tasks)
|
|
1401
1454
|
return
|
|
1402
1455
|
}
|
|
1403
1456
|
|
|
1404
|
-
if (node.
|
|
1457
|
+
if (node.kind === 'frame') {
|
|
1405
1458
|
disposeFrameResources(node)
|
|
1406
1459
|
return
|
|
1407
1460
|
}
|
|
1408
1461
|
}
|
|
1409
1462
|
|
|
1410
1463
|
export function remove(
|
|
1411
|
-
node:
|
|
1464
|
+
node: CommittedVNode,
|
|
1412
1465
|
domParent: ParentNode,
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1466
|
+
context: ReconcileContext,
|
|
1467
|
+
): void {
|
|
1468
|
+
let { scheduler } = context
|
|
1416
1469
|
if (isCommittedTextNode(node)) {
|
|
1417
1470
|
node._dom.parentNode?.removeChild(node._dom)
|
|
1418
1471
|
return
|
|
1419
1472
|
}
|
|
1420
1473
|
|
|
1421
1474
|
if (isCommittedHostNode(node)) {
|
|
1422
|
-
if (node.
|
|
1475
|
+
if (node._persistence) return
|
|
1423
1476
|
|
|
1424
|
-
let persistedRemoval = prepareMixinRemoval(node._mixState
|
|
1477
|
+
let persistedRemoval = prepareMixinRemoval(node._mixState)
|
|
1425
1478
|
if (persistedRemoval) {
|
|
1426
1479
|
let token = ++persistedRemovalToken
|
|
1427
1480
|
markNodePersistedByMixins(node, domParent, token)
|
|
1428
1481
|
void persistedRemoval
|
|
1429
1482
|
.catch(() => {})
|
|
1430
1483
|
.finally(() => {
|
|
1431
|
-
if (!node.
|
|
1432
|
-
if (node.
|
|
1484
|
+
if (!node._persistence) return
|
|
1485
|
+
if (node._persistence.token !== token) return
|
|
1433
1486
|
unmarkNodePersistedByMixins(node)
|
|
1434
|
-
performHostNodeRemoval(node, domParent,
|
|
1487
|
+
performHostNodeRemoval(node, domParent, context)
|
|
1435
1488
|
})
|
|
1436
1489
|
return
|
|
1437
1490
|
}
|
|
1438
|
-
performHostNodeRemoval(node, domParent,
|
|
1491
|
+
performHostNodeRemoval(node, domParent, context)
|
|
1439
1492
|
return
|
|
1440
1493
|
}
|
|
1441
1494
|
|
|
1442
1495
|
if (isFragmentNode(node)) {
|
|
1443
|
-
|
|
1444
|
-
|
|
1496
|
+
let children = node._children
|
|
1497
|
+
for (let i = 0; i < children.length; i++) {
|
|
1498
|
+
remove(children[i], domParent, context)
|
|
1445
1499
|
}
|
|
1446
1500
|
return
|
|
1447
1501
|
}
|
|
1448
1502
|
|
|
1449
1503
|
if (isCommittedComponentNode(node)) {
|
|
1450
|
-
remove(node._content, domParent,
|
|
1504
|
+
remove(node._content, domParent, context)
|
|
1451
1505
|
let tasks = node._handle.remove()
|
|
1452
1506
|
scheduler.enqueueTasks(tasks)
|
|
1453
1507
|
return
|
|
1454
1508
|
}
|
|
1455
1509
|
|
|
1456
|
-
if (node.
|
|
1510
|
+
if (node.kind === 'frame') {
|
|
1457
1511
|
disposeFrameResources(node)
|
|
1458
1512
|
removeFrameDomRange(node, domParent)
|
|
1459
1513
|
return
|
|
@@ -1464,63 +1518,53 @@ export function remove(
|
|
|
1464
1518
|
function performHostNodeRemoval(
|
|
1465
1519
|
node: CommittedHostNode,
|
|
1466
1520
|
domParent: ParentNode,
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1521
|
+
context: ReconcileContext,
|
|
1522
|
+
): void {
|
|
1523
|
+
let children = node._children
|
|
1470
1524
|
if (isHeadHostNode(node)) {
|
|
1471
|
-
for (let
|
|
1472
|
-
remove(
|
|
1525
|
+
for (let i = 0; i < children.length; i++) {
|
|
1526
|
+
remove(children[i], node._dom, context)
|
|
1473
1527
|
}
|
|
1474
1528
|
} else {
|
|
1475
1529
|
// Clean up all descendants first (before removing DOM subtree)
|
|
1476
|
-
for (let
|
|
1477
|
-
cleanupDescendants(
|
|
1530
|
+
for (let i = 0; i < children.length; i++) {
|
|
1531
|
+
cleanupDescendants(children[i], context)
|
|
1478
1532
|
}
|
|
1479
1533
|
}
|
|
1480
1534
|
|
|
1481
|
-
teardownMixins(node._mixState
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1535
|
+
teardownMixins(node._mixState)
|
|
1536
|
+
// Never remove the real document.head node when reconciling a <head> vnode,
|
|
1537
|
+
// and since it stays alive, detach its listeners for real.
|
|
1538
|
+
if (isHeadHostNode(node)) {
|
|
1539
|
+
teardownDirectEventListeners(node)
|
|
1540
|
+
teardownControlledReflection(node)
|
|
1541
|
+
} else {
|
|
1542
|
+
abandonDirectEventListeners(node)
|
|
1543
|
+
abandonControlledReflection(node)
|
|
1486
1544
|
node._dom.parentNode?.removeChild(node._dom)
|
|
1487
1545
|
}
|
|
1488
|
-
if (node._controller) node._controller.abort()
|
|
1489
1546
|
}
|
|
1490
1547
|
|
|
1491
1548
|
function diffChildren(
|
|
1492
|
-
curr:
|
|
1493
|
-
next:
|
|
1549
|
+
curr: CommittedVNode[] | null,
|
|
1550
|
+
next: VNodeInput[],
|
|
1494
1551
|
domParent: ParentNode,
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
vParent: VNode,
|
|
1499
|
-
rootTarget: EventTarget,
|
|
1500
|
-
cursor?: Node | null,
|
|
1552
|
+
vParent: VNodeParent,
|
|
1553
|
+
context: ReconcileContext,
|
|
1554
|
+
cursor?: HydrationCursor,
|
|
1501
1555
|
anchor?: Node,
|
|
1502
|
-
) {
|
|
1556
|
+
): CommittedVNode[] {
|
|
1503
1557
|
let hasKeys = hasKeyedChildren(next)
|
|
1558
|
+
let committed: Array<VNodeInput | CommittedVNode> = next
|
|
1504
1559
|
|
|
1505
1560
|
if (curr === null) {
|
|
1506
1561
|
if (hasKeys) {
|
|
1507
1562
|
warnDuplicateKeys(next)
|
|
1508
1563
|
}
|
|
1509
|
-
for (let
|
|
1510
|
-
|
|
1511
|
-
node,
|
|
1512
|
-
domParent,
|
|
1513
|
-
frame,
|
|
1514
|
-
scheduler,
|
|
1515
|
-
styles,
|
|
1516
|
-
vParent,
|
|
1517
|
-
rootTarget,
|
|
1518
|
-
anchor,
|
|
1519
|
-
cursor,
|
|
1520
|
-
)
|
|
1564
|
+
for (let i = 0; i < next.length; i++) {
|
|
1565
|
+
committed[i] = insert(next[i], domParent, vParent, context, anchor, cursor)
|
|
1521
1566
|
}
|
|
1522
|
-
|
|
1523
|
-
return cursor
|
|
1567
|
+
return committed as CommittedVNode[]
|
|
1524
1568
|
}
|
|
1525
1569
|
|
|
1526
1570
|
if (
|
|
@@ -1529,78 +1573,49 @@ function diffChildren(
|
|
|
1529
1573
|
!parentUsesInnerHTML(vParent) &&
|
|
1530
1574
|
canBulkClearChildren(curr)
|
|
1531
1575
|
) {
|
|
1532
|
-
for (let
|
|
1533
|
-
cleanupDescendants(
|
|
1576
|
+
for (let i = 0; i < curr.length; i++) {
|
|
1577
|
+
cleanupDescendants(curr[i], context)
|
|
1534
1578
|
}
|
|
1535
1579
|
domParent.textContent = ''
|
|
1536
|
-
|
|
1537
|
-
return
|
|
1580
|
+
return EMPTY_COMMITTED_CHILDREN
|
|
1538
1581
|
}
|
|
1539
1582
|
|
|
1540
1583
|
if (!hasKeys) {
|
|
1541
1584
|
for (let i = 0; i < next.length; i++) {
|
|
1542
1585
|
let currentNode = i < curr.length ? curr[i] : null
|
|
1543
|
-
diffVNodes(
|
|
1544
|
-
currentNode,
|
|
1545
|
-
next[i],
|
|
1546
|
-
domParent,
|
|
1547
|
-
frame,
|
|
1548
|
-
scheduler,
|
|
1549
|
-
styles,
|
|
1550
|
-
vParent,
|
|
1551
|
-
rootTarget,
|
|
1552
|
-
anchor,
|
|
1553
|
-
cursor,
|
|
1554
|
-
)
|
|
1586
|
+
committed[i] = diffVNodes(currentNode, next[i], domParent, vParent, context, anchor, cursor)
|
|
1555
1587
|
}
|
|
1556
1588
|
|
|
1557
1589
|
if (curr.length > next.length) {
|
|
1558
1590
|
for (let i = next.length; i < curr.length; i++) {
|
|
1559
1591
|
let node = curr[i]
|
|
1560
|
-
if (node) remove(node, domParent,
|
|
1592
|
+
if (node) remove(node, domParent, context)
|
|
1561
1593
|
}
|
|
1562
1594
|
}
|
|
1563
1595
|
|
|
1564
|
-
|
|
1565
|
-
return
|
|
1596
|
+
return committed as CommittedVNode[]
|
|
1566
1597
|
}
|
|
1567
1598
|
|
|
1568
|
-
patchKeyedChildren(
|
|
1569
|
-
curr,
|
|
1570
|
-
next,
|
|
1571
|
-
domParent,
|
|
1572
|
-
frame,
|
|
1573
|
-
scheduler,
|
|
1574
|
-
styles,
|
|
1575
|
-
vParent,
|
|
1576
|
-
rootTarget,
|
|
1577
|
-
cursor,
|
|
1578
|
-
anchor,
|
|
1579
|
-
)
|
|
1580
|
-
|
|
1581
|
-
return
|
|
1599
|
+
return patchKeyedChildren(curr, next, domParent, vParent, context, cursor, anchor)
|
|
1582
1600
|
}
|
|
1583
1601
|
|
|
1584
|
-
function parentUsesInnerHTML(parent:
|
|
1602
|
+
function parentUsesInnerHTML(parent: VNodeParent): boolean {
|
|
1585
1603
|
return isHostNode(parent) && getHostProps(parent).innerHTML != null
|
|
1586
1604
|
}
|
|
1587
1605
|
|
|
1588
|
-
function canBulkClearChildren(children:
|
|
1589
|
-
for (let
|
|
1590
|
-
if (!canBulkClearNode(
|
|
1606
|
+
function canBulkClearChildren(children: CommittedVNode[]): boolean {
|
|
1607
|
+
for (let i = 0; i < children.length; i++) {
|
|
1608
|
+
if (!canBulkClearNode(children[i])) return false
|
|
1591
1609
|
}
|
|
1592
1610
|
return true
|
|
1593
1611
|
}
|
|
1594
1612
|
|
|
1595
|
-
function canBulkClearNode(node:
|
|
1613
|
+
function canBulkClearNode(node: CommittedVNode): boolean {
|
|
1596
1614
|
if (isCommittedTextNode(node)) return true
|
|
1597
1615
|
|
|
1598
1616
|
if (isCommittedHostNode(node)) {
|
|
1599
1617
|
if (node._mixState) return false
|
|
1600
|
-
|
|
1601
|
-
if (!canBulkClearNode(child)) return false
|
|
1602
|
-
}
|
|
1603
|
-
return true
|
|
1618
|
+
return canBulkClearChildren(node._children)
|
|
1604
1619
|
}
|
|
1605
1620
|
|
|
1606
1621
|
if (isFragmentNode(node)) {
|
|
@@ -1614,16 +1629,16 @@ function canBulkClearNode(node: VNode): boolean {
|
|
|
1614
1629
|
return false
|
|
1615
1630
|
}
|
|
1616
1631
|
|
|
1617
|
-
function hasKeyedChildren(children:
|
|
1618
|
-
for (let
|
|
1619
|
-
if (
|
|
1632
|
+
function hasKeyedChildren(children: Array<{ key?: Key }>): boolean {
|
|
1633
|
+
for (let i = 0; i < children.length; i++) {
|
|
1634
|
+
if (children[i].key != null) return true
|
|
1620
1635
|
}
|
|
1621
1636
|
return false
|
|
1622
1637
|
}
|
|
1623
1638
|
|
|
1624
|
-
function warnDuplicateKeys(children:
|
|
1625
|
-
let seenKeys: Set<
|
|
1626
|
-
let duplicateKeys: Set<
|
|
1639
|
+
function warnDuplicateKeys(children: Array<{ key?: Key }>): void {
|
|
1640
|
+
let seenKeys: Set<Key> | undefined
|
|
1641
|
+
let duplicateKeys: Set<Key> | undefined
|
|
1627
1642
|
|
|
1628
1643
|
for (let node of children) {
|
|
1629
1644
|
if (node.key == null) continue
|
|
@@ -1642,7 +1657,7 @@ function warnDuplicateKeys(children: VNode[]): void {
|
|
|
1642
1657
|
}
|
|
1643
1658
|
|
|
1644
1659
|
if (duplicateKeys?.size) {
|
|
1645
|
-
let quotedKeys = Array.from(duplicateKeys, (key) => `"${key}"`)
|
|
1660
|
+
let quotedKeys = Array.from(duplicateKeys, (key) => `"${String(key)}"`)
|
|
1646
1661
|
console.warn(
|
|
1647
1662
|
`Duplicate keys detected in siblings: ${quotedKeys.join(', ')}. Keys should be unique.`,
|
|
1648
1663
|
)
|
|
@@ -1650,17 +1665,14 @@ function warnDuplicateKeys(children: VNode[]): void {
|
|
|
1650
1665
|
}
|
|
1651
1666
|
|
|
1652
1667
|
function patchKeyedChildren(
|
|
1653
|
-
curr:
|
|
1654
|
-
next:
|
|
1668
|
+
curr: CommittedVNode[],
|
|
1669
|
+
next: VNodeInput[],
|
|
1655
1670
|
domParent: ParentNode,
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
vParent: VNode,
|
|
1660
|
-
rootTarget: EventTarget,
|
|
1661
|
-
cursor?: Node | null,
|
|
1671
|
+
vParent: VNodeParent,
|
|
1672
|
+
context: ReconcileContext,
|
|
1673
|
+
cursor?: HydrationCursor,
|
|
1662
1674
|
anchor?: Node,
|
|
1663
|
-
):
|
|
1675
|
+
): CommittedVNode[] {
|
|
1664
1676
|
let matches =
|
|
1665
1677
|
matchKeyedChildrenInOrder(curr, next) ??
|
|
1666
1678
|
matchKeyedChildrenAfterSingleRemoval(curr, next) ??
|
|
@@ -1669,46 +1681,36 @@ function patchKeyedChildren(
|
|
|
1669
1681
|
warnDuplicateKeys(next)
|
|
1670
1682
|
matches = matchKeyedChildren(curr, next)
|
|
1671
1683
|
}
|
|
1684
|
+
let committed: Array<VNodeInput | CommittedVNode> = next
|
|
1672
1685
|
|
|
1673
1686
|
let matchAnalysis = analyzeKeyedChildMatches(curr.length, matches)
|
|
1674
1687
|
if (matchAnalysis.hasRemovals) {
|
|
1675
1688
|
let usedOldIndexes = new Uint8Array(curr.length)
|
|
1676
1689
|
|
|
1677
|
-
for (let
|
|
1678
|
-
|
|
1679
|
-
|
|
1690
|
+
for (let index = 0; index < matches.length; index++) {
|
|
1691
|
+
let oldIndex = matches[index]
|
|
1692
|
+
if (oldIndex >= 0) {
|
|
1693
|
+
usedOldIndexes[oldIndex] = 1
|
|
1680
1694
|
}
|
|
1681
1695
|
}
|
|
1682
1696
|
|
|
1683
1697
|
for (let oldIndex = 0; oldIndex < curr.length; oldIndex++) {
|
|
1684
1698
|
if (usedOldIndexes[oldIndex] === 0) {
|
|
1685
|
-
remove(curr[oldIndex], domParent,
|
|
1699
|
+
remove(curr[oldIndex], domParent, context)
|
|
1686
1700
|
}
|
|
1687
1701
|
}
|
|
1688
1702
|
}
|
|
1689
1703
|
|
|
1690
|
-
vParent._children = next
|
|
1691
|
-
|
|
1692
1704
|
for (let index = 0; index < next.length; index++) {
|
|
1693
|
-
let
|
|
1694
|
-
let oldNode =
|
|
1705
|
+
let oldIndex = matches[index]
|
|
1706
|
+
let oldNode = oldIndex >= 0 ? curr[oldIndex] : null
|
|
1695
1707
|
|
|
1696
|
-
diffVNodes(
|
|
1697
|
-
oldNode,
|
|
1698
|
-
next[index],
|
|
1699
|
-
domParent,
|
|
1700
|
-
frame,
|
|
1701
|
-
scheduler,
|
|
1702
|
-
styles,
|
|
1703
|
-
vParent,
|
|
1704
|
-
rootTarget,
|
|
1705
|
-
anchor,
|
|
1706
|
-
cursor,
|
|
1707
|
-
)
|
|
1708
|
+
committed[index] = diffVNodes(oldNode, next[index], domParent, vParent, context, anchor, cursor)
|
|
1708
1709
|
}
|
|
1710
|
+
let committedChildren = committed as CommittedVNode[]
|
|
1709
1711
|
|
|
1710
1712
|
if (matchAnalysis.canSkipPlacement) {
|
|
1711
|
-
return
|
|
1713
|
+
return committedChildren
|
|
1712
1714
|
}
|
|
1713
1715
|
|
|
1714
1716
|
let stableIndexes = lisMatches(matches)
|
|
@@ -1716,7 +1718,7 @@ function patchKeyedChildren(
|
|
|
1716
1718
|
let placementAnchor: Node | null = anchor ?? null
|
|
1717
1719
|
|
|
1718
1720
|
for (let index = next.length - 1; index >= 0; index--) {
|
|
1719
|
-
let nextNode =
|
|
1721
|
+
let nextNode = committedChildren[index]
|
|
1720
1722
|
let isStable = stableIndexes[stableCursor] === index
|
|
1721
1723
|
|
|
1722
1724
|
if (isStable) {
|
|
@@ -1727,10 +1729,14 @@ function patchKeyedChildren(
|
|
|
1727
1729
|
|
|
1728
1730
|
placementAnchor = findFirstDomAnchor(nextNode) ?? placementAnchor
|
|
1729
1731
|
}
|
|
1732
|
+
return committedChildren
|
|
1730
1733
|
}
|
|
1731
1734
|
|
|
1732
|
-
|
|
1733
|
-
|
|
1735
|
+
// Keyed child matches are arrays of old indexes (-1 = no match / new node),
|
|
1736
|
+
// parallel to `next`. Plain numbers instead of wrapper objects keep large
|
|
1737
|
+
// keyed diffs (1000-row tables) allocation-free.
|
|
1738
|
+
function matchKeyedChildren(curr: CommittedVNode[], next: VNodeInput[]): number[] {
|
|
1739
|
+
let oldKeyMap = new Map<Key, number>()
|
|
1734
1740
|
let usedOldIndexes = new Set<number>()
|
|
1735
1741
|
let unkeyedSearchStart = 0
|
|
1736
1742
|
|
|
@@ -1739,7 +1745,9 @@ function matchKeyedChildren(curr: VNode[], next: VNode[]): Array<{ oldIndex: num
|
|
|
1739
1745
|
if (key != null) oldKeyMap.set(key, index)
|
|
1740
1746
|
}
|
|
1741
1747
|
|
|
1742
|
-
|
|
1748
|
+
let matches: number[] = []
|
|
1749
|
+
for (let nextIndex = 0; nextIndex < next.length; nextIndex++) {
|
|
1750
|
+
let nextNode = next[nextIndex]
|
|
1743
1751
|
let oldIndex = -1
|
|
1744
1752
|
|
|
1745
1753
|
if (nextNode.key != null) {
|
|
@@ -1764,16 +1772,15 @@ function matchKeyedChildren(curr: VNode[], next: VNode[]): Array<{ oldIndex: num
|
|
|
1764
1772
|
}
|
|
1765
1773
|
|
|
1766
1774
|
if (oldIndex >= 0) usedOldIndexes.add(oldIndex)
|
|
1767
|
-
|
|
1768
|
-
}
|
|
1775
|
+
matches.push(oldIndex)
|
|
1776
|
+
}
|
|
1777
|
+
|
|
1778
|
+
return matches
|
|
1769
1779
|
}
|
|
1770
1780
|
|
|
1771
|
-
function matchKeyedChildrenInOrder(
|
|
1772
|
-
curr: VNode[],
|
|
1773
|
-
next: VNode[],
|
|
1774
|
-
): Array<{ oldIndex: number }> | null {
|
|
1781
|
+
function matchKeyedChildrenInOrder(curr: CommittedVNode[], next: VNodeInput[]): number[] | null {
|
|
1775
1782
|
let length = Math.min(curr.length, next.length)
|
|
1776
|
-
let matches:
|
|
1783
|
+
let matches: number[] = []
|
|
1777
1784
|
|
|
1778
1785
|
for (let index = 0; index < length; index++) {
|
|
1779
1786
|
let nextNode = next[index]
|
|
@@ -1784,24 +1791,24 @@ function matchKeyedChildrenInOrder(
|
|
|
1784
1791
|
return null
|
|
1785
1792
|
}
|
|
1786
1793
|
|
|
1787
|
-
matches.push(
|
|
1794
|
+
matches.push(index)
|
|
1788
1795
|
}
|
|
1789
1796
|
|
|
1790
1797
|
for (let index = length; index < next.length; index++) {
|
|
1791
1798
|
if (next[index].key == null) return null
|
|
1792
|
-
matches.push(
|
|
1799
|
+
matches.push(-1)
|
|
1793
1800
|
}
|
|
1794
1801
|
|
|
1795
1802
|
return matches
|
|
1796
1803
|
}
|
|
1797
1804
|
|
|
1798
1805
|
function matchKeyedChildrenAfterSingleRemoval(
|
|
1799
|
-
curr:
|
|
1800
|
-
next:
|
|
1801
|
-
):
|
|
1806
|
+
curr: CommittedVNode[],
|
|
1807
|
+
next: VNodeInput[],
|
|
1808
|
+
): number[] | null {
|
|
1802
1809
|
if (curr.length !== next.length + 1) return null
|
|
1803
1810
|
|
|
1804
|
-
let matches:
|
|
1811
|
+
let matches: number[] = []
|
|
1805
1812
|
let oldIndex = 0
|
|
1806
1813
|
let skippedOldNode = false
|
|
1807
1814
|
|
|
@@ -1811,7 +1818,7 @@ function matchKeyedChildrenAfterSingleRemoval(
|
|
|
1811
1818
|
|
|
1812
1819
|
let oldNode = curr[oldIndex]
|
|
1813
1820
|
if (oldNode.key === nextNode.key && oldNode.type === nextNode.type) {
|
|
1814
|
-
matches.push(
|
|
1821
|
+
matches.push(oldIndex)
|
|
1815
1822
|
oldIndex++
|
|
1816
1823
|
continue
|
|
1817
1824
|
}
|
|
@@ -1825,7 +1832,7 @@ function matchKeyedChildrenAfterSingleRemoval(
|
|
|
1825
1832
|
return null
|
|
1826
1833
|
}
|
|
1827
1834
|
|
|
1828
|
-
matches.push(
|
|
1835
|
+
matches.push(oldIndex)
|
|
1829
1836
|
oldIndex++
|
|
1830
1837
|
}
|
|
1831
1838
|
|
|
@@ -1833,12 +1840,12 @@ function matchKeyedChildrenAfterSingleRemoval(
|
|
|
1833
1840
|
}
|
|
1834
1841
|
|
|
1835
1842
|
function matchKeyedChildrenAfterPairSwap(
|
|
1836
|
-
curr:
|
|
1837
|
-
next:
|
|
1838
|
-
):
|
|
1843
|
+
curr: CommittedVNode[],
|
|
1844
|
+
next: VNodeInput[],
|
|
1845
|
+
): number[] | null {
|
|
1839
1846
|
if (curr.length !== next.length) return null
|
|
1840
1847
|
|
|
1841
|
-
let matches:
|
|
1848
|
+
let matches: number[] = []
|
|
1842
1849
|
let firstMismatch = -1
|
|
1843
1850
|
let secondMismatch = -1
|
|
1844
1851
|
|
|
@@ -1848,7 +1855,7 @@ function matchKeyedChildrenAfterPairSwap(
|
|
|
1848
1855
|
|
|
1849
1856
|
let oldNode = curr[index]
|
|
1850
1857
|
if (oldNode.key === nextNode.key && oldNode.type === nextNode.type) {
|
|
1851
|
-
matches.push(
|
|
1858
|
+
matches.push(index)
|
|
1852
1859
|
continue
|
|
1853
1860
|
}
|
|
1854
1861
|
|
|
@@ -1859,7 +1866,7 @@ function matchKeyedChildrenAfterPairSwap(
|
|
|
1859
1866
|
} else {
|
|
1860
1867
|
return null
|
|
1861
1868
|
}
|
|
1862
|
-
matches.push(
|
|
1869
|
+
matches.push(-1)
|
|
1863
1870
|
}
|
|
1864
1871
|
|
|
1865
1872
|
if (firstMismatch === -1) return matches
|
|
@@ -1879,42 +1886,43 @@ function matchKeyedChildrenAfterPairSwap(
|
|
|
1879
1886
|
return null
|
|
1880
1887
|
}
|
|
1881
1888
|
|
|
1882
|
-
matches[firstMismatch] =
|
|
1883
|
-
matches[secondMismatch] =
|
|
1889
|
+
matches[firstMismatch] = secondMismatch
|
|
1890
|
+
matches[secondMismatch] = firstMismatch
|
|
1884
1891
|
return matches
|
|
1885
1892
|
}
|
|
1886
1893
|
|
|
1887
1894
|
function analyzeKeyedChildMatches(
|
|
1888
1895
|
currentLength: number,
|
|
1889
|
-
matches:
|
|
1896
|
+
matches: readonly number[],
|
|
1890
1897
|
): { hasRemovals: boolean; canSkipPlacement: boolean } {
|
|
1891
1898
|
let hasRemovals = matches.length !== currentLength
|
|
1892
1899
|
let canSkipPlacement = true
|
|
1893
1900
|
let lastOldIndex = -1
|
|
1894
1901
|
let sawNewNode = false
|
|
1895
1902
|
|
|
1896
|
-
for (let
|
|
1897
|
-
|
|
1903
|
+
for (let index = 0; index < matches.length; index++) {
|
|
1904
|
+
let oldIndex = matches[index]
|
|
1905
|
+
if (oldIndex < 0) {
|
|
1898
1906
|
hasRemovals = true
|
|
1899
1907
|
sawNewNode = true
|
|
1900
1908
|
continue
|
|
1901
1909
|
}
|
|
1902
1910
|
|
|
1903
|
-
if (sawNewNode ||
|
|
1911
|
+
if (sawNewNode || oldIndex < lastOldIndex) {
|
|
1904
1912
|
canSkipPlacement = false
|
|
1905
1913
|
}
|
|
1906
|
-
lastOldIndex =
|
|
1914
|
+
lastOldIndex = oldIndex
|
|
1907
1915
|
}
|
|
1908
1916
|
|
|
1909
1917
|
return { hasRemovals, canSkipPlacement }
|
|
1910
1918
|
}
|
|
1911
1919
|
|
|
1912
|
-
function lisMatches(matches:
|
|
1920
|
+
function lisMatches(matches: readonly number[]): number[] {
|
|
1913
1921
|
let predecessors = Array.from<number>({ length: matches.length })
|
|
1914
1922
|
let tails: number[] = []
|
|
1915
1923
|
|
|
1916
1924
|
for (let index = 0; index < matches.length; index++) {
|
|
1917
|
-
let value = matches[index]
|
|
1925
|
+
let value = matches[index] + 1
|
|
1918
1926
|
if (value === 0) continue
|
|
1919
1927
|
|
|
1920
1928
|
let low = 0
|
|
@@ -1923,7 +1931,7 @@ function lisMatches(matches: ReadonlyArray<{ oldIndex: number }>): number[] {
|
|
|
1923
1931
|
while (low < high) {
|
|
1924
1932
|
let middle = (low + high) >> 1
|
|
1925
1933
|
|
|
1926
|
-
if (matches[tails[middle]]
|
|
1934
|
+
if (matches[tails[middle]] + 1 < value) {
|
|
1927
1935
|
low = middle + 1
|
|
1928
1936
|
} else {
|
|
1929
1937
|
high = middle
|
|
@@ -1944,7 +1952,7 @@ function lisMatches(matches: ReadonlyArray<{ oldIndex: number }>): number[] {
|
|
|
1944
1952
|
return tails
|
|
1945
1953
|
}
|
|
1946
1954
|
|
|
1947
|
-
function placeVNode(node:
|
|
1955
|
+
function placeVNode(node: CommittedVNode, domParent: ParentNode, anchor: Node | null): void {
|
|
1948
1956
|
let firstDom = findFirstDomAnchor(node)
|
|
1949
1957
|
if (!firstDom || firstDom.parentNode !== domParent) return
|
|
1950
1958
|
|
|
@@ -1956,27 +1964,28 @@ function placeVNode(node: VNode, domParent: ParentNode, anchor: Node | null): vo
|
|
|
1956
1964
|
moveDomRange(domParent, firstDom, lastDom, anchor)
|
|
1957
1965
|
}
|
|
1958
1966
|
|
|
1959
|
-
export function findFirstDomAnchor(node:
|
|
1967
|
+
export function findFirstDomAnchor(node: CommittedVNode | null | undefined): Node | null {
|
|
1960
1968
|
if (!node) return null
|
|
1961
1969
|
if (isCommittedTextNode(node)) return node._dom
|
|
1962
1970
|
if (isCommittedHostNode(node)) return node._dom
|
|
1963
1971
|
if (isCommittedComponentNode(node)) return findFirstDomAnchor(node._content)
|
|
1964
|
-
if (node.
|
|
1972
|
+
if (node.kind === 'frame') return node._rangeStart
|
|
1965
1973
|
if (isFragmentNode(node)) {
|
|
1966
|
-
|
|
1967
|
-
|
|
1974
|
+
let children = node._children
|
|
1975
|
+
for (let i = 0; i < children.length; i++) {
|
|
1976
|
+
let dom = findFirstDomAnchor(children[i])
|
|
1968
1977
|
if (dom) return dom
|
|
1969
1978
|
}
|
|
1970
1979
|
}
|
|
1971
1980
|
return null
|
|
1972
1981
|
}
|
|
1973
1982
|
|
|
1974
|
-
export function findLastDomAnchor(node:
|
|
1983
|
+
export function findLastDomAnchor(node: CommittedVNode | null | undefined): Node | null {
|
|
1975
1984
|
if (!node) return null
|
|
1976
1985
|
if (isCommittedTextNode(node)) return node._dom
|
|
1977
1986
|
if (isCommittedHostNode(node)) return node._dom
|
|
1978
1987
|
if (isCommittedComponentNode(node)) return findLastDomAnchor(node._content)
|
|
1979
|
-
if (node.
|
|
1988
|
+
if (node.kind === 'frame') return node._rangeEnd
|
|
1980
1989
|
if (isFragmentNode(node)) {
|
|
1981
1990
|
for (let i = node._children.length - 1; i >= 0; i--) {
|
|
1982
1991
|
let dom = findLastDomAnchor(node._children[i])
|
|
@@ -2014,20 +2023,27 @@ function shouldDispatchInlineMixinLifecycle(node: Node): boolean {
|
|
|
2014
2023
|
let parents = activeSchedulerUpdateParents
|
|
2015
2024
|
if (!parents?.length) return true
|
|
2016
2025
|
for (let parent of parents) {
|
|
2017
|
-
|
|
2026
|
+
if (!(parent instanceof Node)) continue
|
|
2027
|
+
let parentNode = parent
|
|
2018
2028
|
if (parentNode === node) return false
|
|
2019
2029
|
if (parentNode.contains(node)) return false
|
|
2020
2030
|
}
|
|
2021
2031
|
return true
|
|
2022
2032
|
}
|
|
2023
2033
|
|
|
2024
|
-
export function findNextSiblingDomAnchor(
|
|
2034
|
+
export function findNextSiblingDomAnchor(
|
|
2035
|
+
curr: CommittedVNode | MountingComponentNode,
|
|
2036
|
+
): Node | null {
|
|
2025
2037
|
let vParent = curr._parent
|
|
2026
|
-
if (
|
|
2038
|
+
if (vParent.kind === 'component') return findNextSiblingDomAnchor(vParent)
|
|
2027
2039
|
let children = vParent._children
|
|
2028
|
-
if (children.length === 0)
|
|
2040
|
+
if (children.length === 0) {
|
|
2041
|
+
if (vParent.kind === 'root') return vParent._rangeEnd ?? null
|
|
2042
|
+
if (vParent.kind === 'fragment') return findNextSiblingDomAnchor(vParent)
|
|
2043
|
+
return null
|
|
2044
|
+
}
|
|
2029
2045
|
|
|
2030
|
-
let idx = children.indexOf(curr)
|
|
2046
|
+
let idx = children.indexOf(curr as CommittedVNode)
|
|
2031
2047
|
if (idx === -1) return null
|
|
2032
2048
|
for (let i = idx + 1; i < children.length; i++) {
|
|
2033
2049
|
let dom = findFirstDomAnchor(children[i])
|
|
@@ -2038,60 +2054,53 @@ export function findNextSiblingDomAnchor(curr: VNode): Node | null {
|
|
|
2038
2054
|
return findNextSiblingDomAnchor(vParent)
|
|
2039
2055
|
}
|
|
2040
2056
|
|
|
2041
|
-
return null
|
|
2057
|
+
return vParent.kind === 'root' ? (vParent._rangeEnd ?? null) : null
|
|
2042
2058
|
}
|
|
2043
2059
|
|
|
2044
2060
|
function reclaimPersistedMixinNode(
|
|
2045
2061
|
persistedNode: CommittedHostNode,
|
|
2046
2062
|
newNode: HostNode,
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
): void {
|
|
2053
|
-
cancelPendingMixinRemoval(persistedNode._mixState as MixinRuntimeState | undefined)
|
|
2063
|
+
vParent: VNodeParent,
|
|
2064
|
+
context: ReconcileContext,
|
|
2065
|
+
): CommittedHostNode {
|
|
2066
|
+
let { frame, scheduler, styles } = context
|
|
2067
|
+
cancelPendingMixinRemoval(persistedNode._mixState)
|
|
2054
2068
|
unmarkNodePersistedByMixins(persistedNode)
|
|
2055
2069
|
|
|
2056
|
-
newNode._dom = persistedNode._dom
|
|
2057
|
-
newNode._parent = vParent
|
|
2058
|
-
newNode._controller = persistedNode._controller
|
|
2059
|
-
newNode._mixState = persistedNode._mixState
|
|
2060
|
-
newNode._directEventState = persistedNode._directEventState
|
|
2061
|
-
newNode._controlledState = persistedNode._controlledState
|
|
2062
|
-
|
|
2063
2070
|
let prevProps = getHostProps(persistedNode)
|
|
2064
|
-
let
|
|
2071
|
+
let childInputs = newNode._children
|
|
2072
|
+
let resolved = resolveNodeMixProps(newNode, vParent, frame, scheduler, persistedNode._mixState)
|
|
2073
|
+
let nextProps = resolved.props
|
|
2074
|
+
let committed = commitHostNode(
|
|
2065
2075
|
newNode,
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2076
|
+
vParent,
|
|
2077
|
+
getSvgContext(vParent, newNode),
|
|
2078
|
+
persistedNode._dom,
|
|
2079
|
+
resolved,
|
|
2069
2080
|
)
|
|
2081
|
+
committed._directEventState = persistedNode._directEventState
|
|
2082
|
+
committed._controlledState = persistedNode._controlledState
|
|
2070
2083
|
if (shouldDispatchInlineMixinLifecycle(persistedNode._dom)) {
|
|
2071
|
-
dispatchMixinBeforeUpdate(
|
|
2084
|
+
dispatchMixinBeforeUpdate(committed._mixState)
|
|
2072
2085
|
}
|
|
2073
2086
|
patchHostProps(prevProps, nextProps, persistedNode._dom)
|
|
2074
|
-
syncDirectEventListeners(
|
|
2075
|
-
ensureControlledReflection(
|
|
2076
|
-
syncControlledReflection(
|
|
2087
|
+
syncDirectEventListeners(committed)
|
|
2088
|
+
ensureControlledReflection(committed, scheduler)
|
|
2089
|
+
syncControlledReflection(committed, nextProps)
|
|
2077
2090
|
|
|
2078
|
-
diffChildren(
|
|
2091
|
+
committed._children = diffChildren(
|
|
2079
2092
|
persistedNode._children,
|
|
2080
|
-
|
|
2093
|
+
childInputs,
|
|
2081
2094
|
persistedNode._dom,
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
styles,
|
|
2085
|
-
newNode,
|
|
2086
|
-
rootTarget,
|
|
2095
|
+
committed,
|
|
2096
|
+
context,
|
|
2087
2097
|
)
|
|
2088
2098
|
|
|
2089
|
-
if (
|
|
2090
|
-
bindNodeMixRuntime(
|
|
2099
|
+
if (committed._mixState) {
|
|
2100
|
+
bindNodeMixRuntime(committed, frame, scheduler, styles, true)
|
|
2091
2101
|
}
|
|
2092
2102
|
if (shouldDispatchInlineMixinLifecycle(persistedNode._dom)) {
|
|
2093
|
-
scheduler.enqueueCommitPhase([
|
|
2094
|
-
() => dispatchMixinCommit(newNode._mixState as MixinRuntimeState | undefined),
|
|
2095
|
-
])
|
|
2103
|
+
scheduler.enqueueCommitPhase([() => dispatchMixinCommit(committed._mixState)])
|
|
2096
2104
|
}
|
|
2105
|
+
return committed
|
|
2097
2106
|
}
|