ripple 0.3.128 → 0.4.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/CHANGELOG.md +267 -0
- package/package.json +10 -4
- package/src/runtime/element.js +23 -6
- package/src/runtime/index-client.js +81 -41
- package/src/runtime/index-server.js +1 -0
- package/src/runtime/internal/client/blocks.js +173 -91
- package/src/runtime/internal/client/component.js +4 -30
- package/src/runtime/internal/client/composite.js +12 -13
- package/src/runtime/internal/client/constants.js +9 -0
- package/src/runtime/internal/client/context.js +12 -19
- package/src/runtime/internal/client/css.js +7 -9
- package/src/runtime/internal/client/events.js +178 -90
- package/src/runtime/internal/client/expression.js +45 -25
- package/src/runtime/internal/client/for.js +409 -129
- package/src/runtime/internal/client/head.js +10 -5
- package/src/runtime/internal/client/html.js +1 -0
- package/src/runtime/internal/client/hydration.js +152 -10
- package/src/runtime/internal/client/if.js +239 -50
- package/src/runtime/internal/client/index.js +4 -12
- package/src/runtime/internal/client/operations.js +40 -61
- package/src/runtime/internal/client/portal.js +163 -85
- package/src/runtime/internal/client/render.js +39 -39
- package/src/runtime/internal/client/rpc.js +3 -3
- package/src/runtime/internal/client/runtime.js +592 -433
- package/src/runtime/internal/client/selector.js +5 -2
- package/src/runtime/internal/client/template.js +133 -158
- package/src/runtime/internal/client/transport.js +38 -0
- package/src/runtime/internal/client/try.js +465 -426
- package/src/runtime/internal/client/types.d.ts +56 -23
- package/src/runtime/internal/client/utils.js +1 -3
- package/src/runtime/internal/server/dynamic.js +20 -21
- package/src/runtime/internal/server/index.js +325 -275
- package/src/runtime/internal/server/rpc.js +3 -2
- package/src/runtime/internal/server/transport.js +16 -0
- package/src/runtime/transport.js +21 -0
- package/tests/client/__snapshots__/for.test.tsrx.snap +0 -5
- package/tests/client/array/array.copy-within.test.tsrx +12 -12
- package/tests/client/array/array.derived.test.tsrx +46 -46
- package/tests/client/array/array.iteration.test.tsrx +10 -10
- package/tests/client/array/array.mutations.test.tsrx +20 -20
- package/tests/client/array/array.static.test.tsrx +11 -11
- package/tests/client/array/array.to-methods.test.tsrx +6 -6
- package/tests/client/async-suspend.test.tsrx +74 -75
- package/tests/client/basic/basic.attributes.test.tsrx +86 -83
- package/tests/client/basic/basic.collections.test.tsrx +12 -12
- package/tests/client/basic/basic.components.test.tsrx +99 -25
- package/tests/client/basic/basic.errors.test.tsrx +18 -18
- package/tests/client/basic/basic.events.test.tsrx +42 -42
- package/tests/client/basic/basic.get-set.test.tsrx +8 -8
- package/tests/client/basic/basic.reactivity.test.tsrx +73 -38
- package/tests/client/basic/basic.rendering.test.tsrx +25 -25
- package/tests/client/basic/basic.utilities.test.tsrx +3 -3
- package/tests/client/boundaries.test.tsrx +8 -8
- package/tests/client/boxed-locals.test.tsrx +452 -0
- package/tests/client/compiler/__snapshots__/compiler.assignments.test.tsrx.snap +6 -6
- package/tests/client/compiler/compiler.assignments.test.tsrx +9 -73
- package/tests/client/compiler/compiler.attributes.test.tsrx +23 -23
- package/tests/client/compiler/compiler.basic.test.tsrx +15 -60
- package/tests/client/compiler/compiler.tracked-access.test.tsrx +18 -43
- package/tests/client/compiler/compiler.try-in-function.test.tsrx +2 -2
- package/tests/client/composite/__snapshots__/composite.render.test.tsrx.snap +0 -1
- package/tests/client/composite/composite.dynamic-components.test.tsrx +77 -6
- package/tests/client/composite/composite.props.test.tsrx +149 -12
- package/tests/client/composite/composite.reactivity.test.tsrx +51 -52
- package/tests/client/composite/composite.render.test.tsrx +26 -9
- package/tests/client/css/scoped-styles.test.tsrx +8 -8
- package/tests/client/date.test.tsrx +42 -42
- package/tests/client/derived-release.test.tsrx +370 -0
- package/tests/client/dynamic-elements.test.tsrx +45 -45
- package/tests/client/events.test.tsrx +97 -71
- package/tests/client/for-selector.test.tsrx +14 -14
- package/tests/client/for-single-root-items.test.tsrx +118 -3
- package/tests/client/for.test.tsrx +332 -31
- package/tests/client/head.test.tsrx +19 -19
- package/tests/client/html.test.tsrx +11 -9
- package/tests/client/if-block.test.tsrx +80 -0
- package/tests/client/map.test.tsrx +16 -16
- package/tests/client/media-query.test.tsrx +7 -7
- package/tests/client/portal.test.tsrx +224 -26
- package/tests/client/primitive-text.test.tsrx +50 -0
- package/tests/client/prop-kind-switch.test.tsrx +141 -0
- package/tests/client/ref.test.tsrx +17 -17
- package/tests/client/return.test.tsrx +26 -3
- package/tests/client/root-boundary.test.tsrx +42 -0
- package/tests/client/scoped-flush.test.tsrx +8 -8
- package/tests/client/set.test.tsrx +6 -6
- package/tests/client/svg.test.tsrx +11 -11
- package/tests/client/switch.test.tsrx +44 -44
- package/tests/client/track-async-hydration.test.tsrx +4 -4
- package/tests/client/try.test.tsrx +151 -83
- package/tests/client/tsx.test.tsrx +43 -40
- package/tests/client/url/url.derived.test.tsrx +6 -6
- package/tests/client/url-search-params/url-search-params.derived.test.tsrx +8 -8
- package/tests/client/url-search-params/url-search-params.iteration.test.tsrx +10 -10
- package/tests/client/url-search-params/url-search-params.mutation.test.tsrx +10 -10
- package/tests/client/url-search-params/url-search-params.retrieval.test.tsrx +18 -18
- package/tests/client/url-search-params/url-search-params.serialization.test.tsrx +2 -2
- package/tests/hydration/basic.test.js +74 -1
- package/tests/hydration/build-components.js +22 -1
- package/tests/hydration/compiled/client/basic.js +1142 -713
- package/tests/hydration/compiled/client/composite.js +151 -100
- package/tests/hydration/compiled/client/events.js +184 -171
- package/tests/hydration/compiled/client/for.js +1472 -1132
- package/tests/hydration/compiled/client/fragment-cursor.js +2341 -0
- package/tests/hydration/compiled/client/head.js +254 -201
- package/tests/hydration/compiled/client/hmr.js +54 -41
- package/tests/hydration/compiled/client/html-in-template.js +54 -39
- package/tests/hydration/compiled/client/html.js +1633 -1263
- package/tests/hydration/compiled/client/if-children.js +420 -270
- package/tests/hydration/compiled/client/if-fragment-controlflow.js +363 -317
- package/tests/hydration/compiled/client/if.js +229 -219
- package/tests/hydration/compiled/client/mixed-control-flow.js +420 -404
- package/tests/hydration/compiled/client/nested-control-flow.js +1326 -1277
- package/tests/hydration/compiled/client/portal.js +87 -95
- package/tests/hydration/compiled/client/reactivity.js +135 -101
- package/tests/hydration/compiled/client/return.js +28 -19
- package/tests/hydration/compiled/client/streaming.js +390 -306
- package/tests/hydration/compiled/client/switch.js +258 -266
- package/tests/hydration/compiled/client/track-async-serialization.js +448 -280
- package/tests/hydration/compiled/client/try.js +173 -129
- package/tests/hydration/compiled/client/typed-text.js +71 -0
- package/tests/hydration/compiled/fixtures/money.js +10 -0
- package/tests/hydration/compiled/server/basic.js +123 -6
- package/tests/hydration/compiled/server/composite.js +16 -30
- package/tests/hydration/compiled/server/events.js +66 -18
- package/tests/hydration/compiled/server/for.js +117 -41
- package/tests/hydration/compiled/server/fragment-cursor.js +1687 -0
- package/tests/hydration/compiled/server/head.js +20 -20
- package/tests/hydration/compiled/server/hmr.js +2 -2
- package/tests/hydration/compiled/server/html.js +70 -238
- package/tests/hydration/compiled/server/if-children.js +107 -15
- package/tests/hydration/compiled/server/if.js +11 -15
- package/tests/hydration/compiled/server/mixed-control-flow.js +8 -8
- package/tests/hydration/compiled/server/portal.js +14 -22
- package/tests/hydration/compiled/server/reactivity.js +14 -14
- package/tests/hydration/compiled/server/streaming.js +19 -19
- package/tests/hydration/compiled/server/switch.js +8 -8
- package/tests/hydration/compiled/server/track-async-serialization.js +150 -23
- package/tests/hydration/compiled/server/try.js +8 -8
- package/tests/hydration/compiled/server/typed-text.js +17 -0
- package/tests/hydration/components/basic.tsrx +44 -8
- package/tests/hydration/components/composite.tsrx +2 -2
- package/tests/hydration/components/events.tsrx +25 -25
- package/tests/hydration/components/for.tsrx +115 -67
- package/tests/hydration/components/fragment-cursor.tsrx +650 -0
- package/tests/hydration/components/head.tsrx +16 -16
- package/tests/hydration/components/hmr.tsrx +2 -2
- package/tests/hydration/components/html.tsrx +7 -7
- package/tests/hydration/components/if-children.tsrx +72 -25
- package/tests/hydration/components/if.tsrx +18 -18
- package/tests/hydration/components/mixed-control-flow.tsrx +11 -11
- package/tests/hydration/components/portal.tsrx +3 -3
- package/tests/hydration/components/reactivity.tsrx +16 -16
- package/tests/hydration/components/streaming.tsrx +20 -20
- package/tests/hydration/components/switch.tsrx +20 -20
- package/tests/hydration/components/text-types.ts +4 -0
- package/tests/hydration/components/track-async-serialization.tsrx +80 -26
- package/tests/hydration/components/try.tsrx +8 -8
- package/tests/hydration/components/typed-text.tsrx +22 -0
- package/tests/hydration/fixtures/money.js +10 -0
- package/tests/hydration/for.test.js +36 -0
- package/tests/hydration/fragment-cursor.test.js +111 -0
- package/tests/hydration/if-children.test.js +24 -0
- package/tests/hydration/streaming.test.js +19 -0
- package/tests/hydration/track-async-serialization.test.js +87 -2
- package/tests/hydration/tsconfig.text-types.json +10 -0
- package/tests/hydration/typed-text.test.js +34 -0
- package/tests/server/await.test.tsrx +3 -3
- package/tests/server/basic.attributes.test.tsrx +42 -42
- package/tests/server/basic.components.test.tsrx +64 -8
- package/tests/server/basic.test.tsrx +34 -32
- package/tests/server/compiler.test.tsrx +1 -70
- package/tests/server/composite.props.test.tsrx +6 -6
- package/tests/server/dynamic-elements.test.tsrx +31 -8
- package/tests/server/for.test.tsrx +94 -0
- package/tests/server/head.test.tsrx +11 -11
- package/tests/server/scoped-styles.test.tsrx +2 -2
- package/tests/server/streaming-ssr.test.tsrx +48 -43
- package/tests/server/track-async-serialization.test.tsrx +204 -21
- package/tests/server/try.test.tsrx +48 -48
- package/tests/types/transport.ts +40 -0
- package/tests/utils/vite-plugin-config.test.js +23 -0
- package/types/index.d.ts +48 -7
- package/types/server.d.ts +3 -0
- package/types/transport.d.ts +15 -0
- package/src/runtime/internal/client/switch.js +0 -113
- package/src/utils/errors.js +0 -13
- package/tests/client/lazy-array.test.tsrx +0 -31
- package/tests/client/lazy-destructuring.test.tsrx +0 -438
- package/tests/client/tracked-index-access.test.tsrx +0 -113
- package/tests/server/lazy-destructuring.test.tsrx +0 -595
- package/tests/server/tracked-index-access.test.tsrx +0 -76
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { render } from './blocks.js';
|
|
2
|
-
import { HEAD_BLOCK } from './constants.js';
|
|
2
|
+
import { DETACHED_BLOCK, HEAD_BLOCK } from './constants.js';
|
|
3
3
|
import { COMMENT_NODE } from '../../../constants.js';
|
|
4
4
|
import { create_text, get_first_child, get_next_sibling } from './operations.js';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
hydrate_node,
|
|
7
|
+
hydrating,
|
|
8
|
+
set_hydrate_node,
|
|
9
|
+
set_hydrating,
|
|
10
|
+
set_hydration,
|
|
11
|
+
} from './hydration.js';
|
|
6
12
|
|
|
7
13
|
/**
|
|
8
14
|
* @param {string} hash
|
|
@@ -49,11 +55,10 @@ export function head(hash, render_fn) {
|
|
|
49
55
|
}
|
|
50
56
|
|
|
51
57
|
try {
|
|
52
|
-
render(() => render_fn(anchor), null, HEAD_BLOCK);
|
|
58
|
+
render(() => render_fn(anchor), null, HEAD_BLOCK | DETACHED_BLOCK);
|
|
53
59
|
} finally {
|
|
54
60
|
if (was_hydrating) {
|
|
55
|
-
|
|
56
|
-
set_hydrate_node(previous_hydrate_node);
|
|
61
|
+
set_hydration(true, previous_hydrate_node);
|
|
57
62
|
}
|
|
58
63
|
}
|
|
59
64
|
}
|
|
@@ -28,6 +28,7 @@ export function html(node, get_html, svg = false, mathml = false) {
|
|
|
28
28
|
if (hydrating) {
|
|
29
29
|
// The anchor is the hash comment - we need to skip past it and its content
|
|
30
30
|
set_hydrate_node(anchor);
|
|
31
|
+
/** @type {Node | null} */
|
|
31
32
|
var next = hydrate_next();
|
|
32
33
|
|
|
33
34
|
// Walk until we find the empty comment end marker
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
/** @import { Derived, Tracked } from '#client' */
|
|
1
|
+
/** @import { AppendIntoAnchor, Block, Derived, Tracked } from '#client' */
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
COMMENT_NODE,
|
|
5
5
|
HYDRATION_END,
|
|
6
6
|
HYDRATION_ERROR,
|
|
7
7
|
HYDRATION_START,
|
|
8
|
+
TEXT_NODE,
|
|
8
9
|
} from '../../../constants.js';
|
|
9
|
-
import {
|
|
10
|
+
import { create_text, first_child_getter, next_sibling_getter } from './operations.js';
|
|
11
|
+
import { active_block } from './runtime.js';
|
|
10
12
|
|
|
11
13
|
export let hydrating = false;
|
|
12
14
|
|
|
@@ -21,15 +23,22 @@ export let hydrate_node = null;
|
|
|
21
23
|
*/
|
|
22
24
|
export const track_hash_reference = new Map();
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
/**
|
|
27
|
+
* @param {boolean} value
|
|
28
|
+
*/
|
|
29
|
+
export function set_hydrating(value) {
|
|
30
|
+
hydrating = value;
|
|
26
31
|
}
|
|
27
32
|
|
|
28
33
|
/**
|
|
34
|
+
* Enters or leaves a hydration walk: both the flag and the cursor, which is
|
|
35
|
+
* allowed to be null when restoring the state of a client-only mount.
|
|
29
36
|
* @param {boolean} value
|
|
37
|
+
* @param {Node | null} node
|
|
30
38
|
*/
|
|
31
|
-
export function
|
|
39
|
+
export function set_hydration(value, node) {
|
|
32
40
|
hydrating = value;
|
|
41
|
+
hydrate_node = node;
|
|
33
42
|
}
|
|
34
43
|
|
|
35
44
|
/**
|
|
@@ -44,11 +53,144 @@ export function set_hydrate_node(node, mounting = false) {
|
|
|
44
53
|
}
|
|
45
54
|
|
|
46
55
|
export function hydrate_next() {
|
|
47
|
-
|
|
56
|
+
var node = next_sibling_getter.call(/** @type {Node} */ (hydrate_node));
|
|
57
|
+
if (node === null) {
|
|
58
|
+
throw HYDRATION_ERROR;
|
|
59
|
+
}
|
|
60
|
+
return (hydrate_node = node);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Descends the cursor into the current node's first child, the way a
|
|
65
|
+
* compiled `element.firstChild` read does while mounting.
|
|
66
|
+
* @param {boolean} [is_text]
|
|
67
|
+
* @returns {Node}
|
|
68
|
+
*/
|
|
69
|
+
export function hydrate_first_child(is_text) {
|
|
70
|
+
var child = first_child_getter.call(/** @type {Node} */ (hydrate_node));
|
|
71
|
+
|
|
72
|
+
if (child === null || (is_text === true && child.nodeType !== TEXT_NODE)) {
|
|
73
|
+
child = repair_first_child(child);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return (hydrate_node = child);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Adopts the text node that is an element's only child, leaving the cursor on
|
|
81
|
+
* the element: nothing else inside it navigates, so the parent's sibling
|
|
82
|
+
* traversal continues from the element with no pop().
|
|
83
|
+
* @returns {Node}
|
|
84
|
+
*/
|
|
85
|
+
export function hydrate_text_child() {
|
|
86
|
+
var child = first_child_getter.call(/** @type {Node} */ (hydrate_node));
|
|
87
|
+
|
|
88
|
+
if (child === null || child.nodeType !== TEXT_NODE) {
|
|
89
|
+
child = repair_first_child(child);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return child;
|
|
48
93
|
}
|
|
49
94
|
|
|
50
|
-
|
|
51
|
-
|
|
95
|
+
/**
|
|
96
|
+
* Handles `<p>{text}</p>` where `text` rendered empty on the server: there is
|
|
97
|
+
* no text node to adopt (or, with siblings, the next node is not one), so one
|
|
98
|
+
* is created in its place.
|
|
99
|
+
* @param {Node | null} child
|
|
100
|
+
* @returns {Text}
|
|
101
|
+
*/
|
|
102
|
+
function repair_first_child(child) {
|
|
103
|
+
var text = create_text();
|
|
104
|
+
if (child === null) {
|
|
105
|
+
/** @type {Node} */ (hydrate_node).appendChild(text);
|
|
106
|
+
} else {
|
|
107
|
+
/** @type {ChildNode} */ (child).before(text);
|
|
108
|
+
}
|
|
109
|
+
return text;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Moves the cursor to the current node's next sibling, the way a compiled
|
|
114
|
+
* `node.nextSibling` read does while mounting.
|
|
115
|
+
* @param {boolean} [is_text]
|
|
116
|
+
* @returns {Node}
|
|
117
|
+
*/
|
|
118
|
+
export function hydrate_next_sibling(is_text) {
|
|
119
|
+
var next_sibling = /** @type {ChildNode | null} */ (
|
|
120
|
+
next_sibling_getter.call(/** @type {Node} */ (hydrate_node))
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
if (next_sibling === null || (is_text === true && next_sibling.nodeType !== TEXT_NODE)) {
|
|
124
|
+
if (is_text !== true) {
|
|
125
|
+
throw HYDRATION_ERROR;
|
|
126
|
+
}
|
|
127
|
+
next_sibling = repair_next_sibling(next_sibling);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
return (hydrate_node = next_sibling);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* A sibling `{expression}` that rendered empty on the server has no text node
|
|
135
|
+
* to hydrate: create one after the current node (or before whatever follows).
|
|
136
|
+
* @param {ChildNode | null} next_sibling
|
|
137
|
+
* @returns {Text}
|
|
138
|
+
*/
|
|
139
|
+
function repair_next_sibling(next_sibling) {
|
|
140
|
+
var text = create_text();
|
|
141
|
+
if (next_sibling === null) {
|
|
142
|
+
/** @type {ChildNode} */ (hydrate_node).after(text);
|
|
143
|
+
} else {
|
|
144
|
+
next_sibling.before(text);
|
|
145
|
+
}
|
|
146
|
+
return text;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* The hydration path of `append`: repositions the hydration cursor instead
|
|
151
|
+
* of inserting. Kept out of the insert path so a client-only mount never
|
|
152
|
+
* compiles it.
|
|
153
|
+
*
|
|
154
|
+
* Every hydrated node, block, and component leaves the cursor on its last
|
|
155
|
+
* DOM node, and whoever owns the next node steps past it: a parent element
|
|
156
|
+
* with its sibling traversal, a control-flow block by reaching its end
|
|
157
|
+
* marker, an append-into sentinel by adopting the cursor as the next
|
|
158
|
+
* component's first node.
|
|
159
|
+
* @param {ChildNode | AppendIntoAnchor} anchor
|
|
160
|
+
* @param {Node} dom
|
|
161
|
+
*/
|
|
162
|
+
export function hydrate_append(anchor, dom) {
|
|
163
|
+
var node = /** @type {Node} */ (hydrate_node);
|
|
164
|
+
|
|
165
|
+
// The cursor descended into dom's children (child()/sibling() traversal
|
|
166
|
+
// inside a single-node template) without a compiler-emitted pop(): bring it
|
|
167
|
+
// back up to dom before deciding where to leave it.
|
|
168
|
+
if (node !== dom && dom.contains(node)) {
|
|
169
|
+
node = dom;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// A child component renders into the anchor it was handed, which is its
|
|
173
|
+
// own first node. Its content is hydrated, so leave the cursor on the
|
|
174
|
+
// content's last node for the parent's sibling traversal.
|
|
175
|
+
if (anchor === dom) {
|
|
176
|
+
hydrate_node = node;
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
if (node !== dom) {
|
|
181
|
+
// A fragment's cursor sits on its last top-level node, past the
|
|
182
|
+
// template's first node: widen the block's end to cover the whole
|
|
183
|
+
// fragment rather than only the node assign_nodes saw.
|
|
184
|
+
var s = /** @type {Block} */ (active_block).s;
|
|
185
|
+
if (s !== null) {
|
|
186
|
+
s.end = node;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Step past the content: a branch lands on its block's end marker, the
|
|
191
|
+
// root on the boundary's end marker, an append-into sentinel on the next
|
|
192
|
+
// component's first node.
|
|
193
|
+
hydrate_node = next_sibling_getter.call(node);
|
|
52
194
|
}
|
|
53
195
|
|
|
54
196
|
export function next(n = 1) {
|
|
@@ -56,7 +198,7 @@ export function next(n = 1) {
|
|
|
56
198
|
var node = hydrate_node;
|
|
57
199
|
|
|
58
200
|
for (var i = 0; i < n; i++) {
|
|
59
|
-
node =
|
|
201
|
+
node = next_sibling_getter.call(/** @type {Node} */ (node));
|
|
60
202
|
}
|
|
61
203
|
|
|
62
204
|
hydrate_node = node;
|
|
@@ -91,6 +233,6 @@ export function skip_to_hydration_end() {
|
|
|
91
233
|
depth += 1;
|
|
92
234
|
}
|
|
93
235
|
}
|
|
94
|
-
node = /** @type {Node} */ (
|
|
236
|
+
node = /** @type {Node} */ (next_sibling_getter.call(node));
|
|
95
237
|
}
|
|
96
238
|
}
|
|
@@ -1,71 +1,260 @@
|
|
|
1
|
-
/** @import { Block } from '#client' */
|
|
1
|
+
/** @import { AppendIntoAnchor, Block } from '#client' */
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
|
|
3
|
+
import {
|
|
4
|
+
block,
|
|
5
|
+
branch,
|
|
6
|
+
destroy_block,
|
|
7
|
+
get_first_node,
|
|
8
|
+
get_last_node,
|
|
9
|
+
move_block_last,
|
|
10
|
+
remove_block_dom,
|
|
11
|
+
} from './blocks.js';
|
|
12
|
+
import { DETACHED_BLOCK, IF_BLOCK, RENDER_BLOCK, UNINITIALIZED } from './constants.js';
|
|
5
13
|
import { hydrate_next, hydrate_node, hydrating } from './hydration.js';
|
|
14
|
+
import { create_text, resolve_anchor } from './operations.js';
|
|
15
|
+
import { active_block, probe_if, run_untracked } from './runtime.js';
|
|
6
16
|
import { append } from './template.js';
|
|
7
17
|
|
|
8
18
|
/**
|
|
9
|
-
*
|
|
10
|
-
*
|
|
19
|
+
* The if block renders its branch directly: the block owns the branch's DOM
|
|
20
|
+
* range and its children are the branch's blocks, so no branch block sits in
|
|
21
|
+
* between. Its condition runs tracked and returns the branch function to
|
|
22
|
+
* render (or nothing); the branch renders untracked, like a branch block
|
|
23
|
+
* would.
|
|
24
|
+
* @typedef {{
|
|
25
|
+
* start: Node | null;
|
|
26
|
+
* end: Node | null;
|
|
27
|
+
* a: Node | AppendIntoAnchor;
|
|
28
|
+
* fn: (x: any) => Branch | undefined;
|
|
29
|
+
* x: any;
|
|
30
|
+
* b: Branch | undefined | typeof UNINITIALIZED;
|
|
31
|
+
* o: Block | null;
|
|
32
|
+
* }} IfState
|
|
33
|
+
* @typedef {(anchor: Node, x: any) => void} Branch
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
function noop() {}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* The last DOM node rendered by the current branch through a child block,
|
|
40
|
+
* for a branch that has no range of its own (its root is control flow).
|
|
41
|
+
* @param {Block} block
|
|
42
|
+
* @param {Block | null} skip
|
|
43
|
+
* @returns {Node | null}
|
|
44
|
+
*/
|
|
45
|
+
function last_child_node(block, skip) {
|
|
46
|
+
var child = block.last;
|
|
47
|
+
while (child !== null) {
|
|
48
|
+
if (child !== skip) {
|
|
49
|
+
var node = get_last_node(child);
|
|
50
|
+
if (node !== null) {
|
|
51
|
+
return node;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
child = child.prev;
|
|
55
|
+
}
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* @param {Block} block
|
|
61
|
+
* @param {Block | null} skip
|
|
62
|
+
* @returns {Node | null}
|
|
63
|
+
*/
|
|
64
|
+
function first_child_node(block, skip) {
|
|
65
|
+
var child = block.first;
|
|
66
|
+
while (child !== null) {
|
|
67
|
+
if (child !== skip) {
|
|
68
|
+
var node = get_first_node(child);
|
|
69
|
+
if (node !== null) {
|
|
70
|
+
return node;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
child = child.next;
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Destroys the current branch: its DOM range, then its blocks (all children
|
|
80
|
+
* of the if block except the anchor's owner). `remove_dom` stays on for the
|
|
81
|
+
* children when the branch renders through them and has no range itself.
|
|
82
|
+
* @param {IfState} state
|
|
83
|
+
* @param {Block} block
|
|
84
|
+
*/
|
|
85
|
+
function destroy_branch(state, block) {
|
|
86
|
+
var start = state.start;
|
|
87
|
+
var remove_dom = start === null;
|
|
88
|
+
|
|
89
|
+
if (!remove_dom) {
|
|
90
|
+
remove_block_dom(start, /** @type {Node} */ (state.end));
|
|
91
|
+
state.start = state.end = null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
var keep = state.o;
|
|
95
|
+
var child = block.first;
|
|
96
|
+
while (child !== null) {
|
|
97
|
+
var next = child.next;
|
|
98
|
+
if (child !== keep) {
|
|
99
|
+
destroy_block(child, remove_dom);
|
|
100
|
+
}
|
|
101
|
+
child = next;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Turns the append-into sentinel of a root-controlled if into a text anchor
|
|
107
|
+
* the if owns. The sentinel is only right for the first append, so the anchor
|
|
108
|
+
* is materialized as late as possible: when a branch swap needs the position
|
|
109
|
+
* of the branch being replaced (still rendered), or when the if renders
|
|
110
|
+
* nothing and would otherwise have no position at all. Until then a list of
|
|
111
|
+
* `@if` items keeps no anchor nodes in the DOM.
|
|
112
|
+
* @param {IfState} state
|
|
113
|
+
* @param {Block} block
|
|
114
|
+
*/
|
|
115
|
+
function materialize_anchor(state, block) {
|
|
116
|
+
var sentinel = /** @type {AppendIntoAnchor} */ (state.a);
|
|
117
|
+
var parent = sentinel.parent;
|
|
118
|
+
var text = create_text();
|
|
119
|
+
var last = state.start !== null ? state.end : last_child_node(block, null);
|
|
120
|
+
|
|
121
|
+
if (last === null || last.parentNode !== parent) {
|
|
122
|
+
parent.appendChild(text);
|
|
123
|
+
} else {
|
|
124
|
+
/** @type {ChildNode} */ (last).after(text);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
state.a = text;
|
|
128
|
+
// Created after the current branch, so block order follows DOM order;
|
|
129
|
+
// `update_branch` relinks it behind every later branch. The anchor sits
|
|
130
|
+
// outside the if's own range (it is the if's last node, see
|
|
131
|
+
// `get_last_node`), so the owner is detached: it removes the anchor even
|
|
132
|
+
// when the if has already removed its range.
|
|
133
|
+
state.o = branch(noop, DETACHED_BLOCK, { start: text, end: text });
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Renders `fn` as the if's branch when it is not the current one. The
|
|
138
|
+
* condition returns the branch function itself, so a branch is identified by
|
|
139
|
+
* that function and no flag is needed.
|
|
140
|
+
* @param {IfState} state
|
|
141
|
+
* @param {Branch | undefined} fn
|
|
142
|
+
*/
|
|
143
|
+
function update_branch(state, fn) {
|
|
144
|
+
var previous = state.b;
|
|
145
|
+
if (previous === fn) return;
|
|
146
|
+
state.b = fn;
|
|
147
|
+
|
|
148
|
+
var block = /** @type {Block} */ (active_block);
|
|
149
|
+
|
|
150
|
+
if (previous !== UNINITIALIZED) {
|
|
151
|
+
if (/** @type {AppendIntoAnchor} */ (state.a).into === true) {
|
|
152
|
+
materialize_anchor(state, block);
|
|
153
|
+
}
|
|
154
|
+
destroy_branch(state, block);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
var o = state.o;
|
|
158
|
+
|
|
159
|
+
if (fn !== undefined) {
|
|
160
|
+
run_untracked(fn, /** @type {Node} */ (state.a), state.x);
|
|
161
|
+
|
|
162
|
+
if (o !== null) {
|
|
163
|
+
move_block_last(o);
|
|
164
|
+
} else if (
|
|
165
|
+
/** @type {AppendIntoAnchor} */ (state.a).into === true &&
|
|
166
|
+
state.start === null &&
|
|
167
|
+
first_child_node(block, null) === null
|
|
168
|
+
) {
|
|
169
|
+
materialize_anchor(state, block);
|
|
170
|
+
}
|
|
171
|
+
} else if (/** @type {AppendIntoAnchor} */ (state.a).into === true) {
|
|
172
|
+
materialize_anchor(state, block);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* @param {IfState} state
|
|
178
|
+
*/
|
|
179
|
+
function run_if(state) {
|
|
180
|
+
update_branch(state, state.fn(state.x));
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* State lives on the block instead of per-if closures.
|
|
185
|
+
* @param {Node | AppendIntoAnchor} anchor
|
|
186
|
+
* @param {IfState['fn']} fn
|
|
187
|
+
* @param {any} x
|
|
188
|
+
* @returns {IfState}
|
|
189
|
+
*/
|
|
190
|
+
function if_block_state(anchor, fn, x) {
|
|
191
|
+
return {
|
|
192
|
+
// DOM range of the current branch
|
|
193
|
+
start: null,
|
|
194
|
+
end: null,
|
|
195
|
+
a: anchor,
|
|
196
|
+
fn,
|
|
197
|
+
// the captured local a hoisted condition and its branches receive
|
|
198
|
+
x,
|
|
199
|
+
// the current branch
|
|
200
|
+
b: UNINITIALIZED,
|
|
201
|
+
// block owning the anchor materialized from a sentinel
|
|
202
|
+
o: null,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* @param {Node | AppendIntoAnchor} node
|
|
208
|
+
* @param {IfState['fn']} fn
|
|
11
209
|
* @param {boolean} [root_controlled] When true the block renders directly before
|
|
12
|
-
* the component's `__anchor` (no synthesized `<!>` wrapper)
|
|
210
|
+
* the component's `__anchor` (no synthesized `<!>` wrapper), which may be an
|
|
211
|
+
* append-into sentinel: branches then append into the parent until the if
|
|
212
|
+
* needs a position of its own (see `materialize_anchor`). During hydration
|
|
13
213
|
* the SSR boundary start marker sits at the cursor; we hand it to `append()`
|
|
14
214
|
* afterwards so it performs the same context-aware boundary advance the
|
|
15
215
|
* eliminated wrapper's `append()` used to do.
|
|
216
|
+
* @param {any} [x] The one local a hoisted condition and its branches capture,
|
|
217
|
+
* passed to them as their second argument (see the compiler's if lowering).
|
|
16
218
|
* @returns {void}
|
|
17
219
|
*/
|
|
18
|
-
export function if_block(node, fn, root_controlled) {
|
|
220
|
+
export function if_block(node, fn, root_controlled, x) {
|
|
19
221
|
/** @type {Node | undefined} */
|
|
20
222
|
var boundary;
|
|
21
|
-
|
|
22
|
-
if (hydrating) {
|
|
23
|
-
if (root_controlled) {
|
|
24
|
-
boundary = /** @type {Node} */ (hydrate_node);
|
|
25
|
-
}
|
|
26
|
-
hydrate_next();
|
|
27
|
-
}
|
|
28
|
-
|
|
29
223
|
var anchor = node;
|
|
30
|
-
var has_branch = false;
|
|
31
|
-
/** @type {any} */
|
|
32
|
-
var condition = UNINITIALIZED;
|
|
33
|
-
/** @type {Block | null} */
|
|
34
|
-
var b = null;
|
|
35
|
-
|
|
36
|
-
/** @type {(fn: (anchor: Node) => void, flag?: boolean) => void} */
|
|
37
|
-
var set_branch = (fn, flag = true) => {
|
|
38
|
-
has_branch = true;
|
|
39
|
-
update_branch(flag, fn);
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
/** @type {(new_condition: any, fn: ((anchor: Node) => void) | null) => void} */
|
|
43
|
-
var update_branch = (new_condition, fn) => {
|
|
44
|
-
if (condition === (condition = new_condition)) return;
|
|
45
224
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
225
|
+
if (!hydrating) {
|
|
226
|
+
// Evaluate the condition before deciding whether the if needs a block:
|
|
227
|
+
// a condition that read no tracked state has its branch rendered by the
|
|
228
|
+
// probe itself, directly under the current block, with no if block, no
|
|
229
|
+
// state, and the branch's DOM and blocks belonging to the enclosing
|
|
230
|
+
// block like any other content. A dynamic condition gets its block,
|
|
231
|
+
// whose first run evaluates it again and subscribes it.
|
|
232
|
+
var rendered;
|
|
233
|
+
try {
|
|
234
|
+
rendered = probe_if(fn, x, node);
|
|
235
|
+
} catch {
|
|
236
|
+
// A condition that throws (a pending async read) is the block's to
|
|
237
|
+
// handle: create it and let its first run evaluate the condition.
|
|
238
|
+
rendered = false;
|
|
49
239
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
b = branch(() => fn(anchor));
|
|
240
|
+
if (!rendered) {
|
|
241
|
+
block(RENDER_BLOCK | IF_BLOCK, run_if, if_block_state(anchor, fn, x));
|
|
53
242
|
}
|
|
54
|
-
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
55
245
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
null,
|
|
65
|
-
IF_BLOCK,
|
|
66
|
-
);
|
|
246
|
+
if (root_controlled) {
|
|
247
|
+
// A sentinel resolves to the cursor, the block's SSR boundary marker.
|
|
248
|
+
anchor = resolve_anchor(node);
|
|
249
|
+
boundary = /** @type {Node} */ (hydrate_node);
|
|
250
|
+
}
|
|
251
|
+
hydrate_next();
|
|
252
|
+
|
|
253
|
+
block(RENDER_BLOCK | IF_BLOCK, run_if, if_block_state(anchor, fn, x));
|
|
67
254
|
|
|
68
|
-
if (
|
|
69
|
-
|
|
255
|
+
if (root_controlled) {
|
|
256
|
+
// The original `node`: for a sentinel, `hydrate_append` performs the
|
|
257
|
+
// cursor advance that stands in for the eliminated sibling navigation.
|
|
258
|
+
append(/** @type {ChildNode} */ (node), /** @type {Node} */ (boundary));
|
|
70
259
|
}
|
|
71
260
|
}
|
|
@@ -4,6 +4,7 @@ export {
|
|
|
4
4
|
next_sibling as sibling,
|
|
5
5
|
hydrate_first_child as hydrate_child,
|
|
6
6
|
hydrate_next_sibling as hydrate_sibling,
|
|
7
|
+
hydrate_text_child as hydrate_text,
|
|
7
8
|
append_into,
|
|
8
9
|
document,
|
|
9
10
|
create_text,
|
|
@@ -38,8 +39,10 @@ export {
|
|
|
38
39
|
TRACKED_UPDATED,
|
|
39
40
|
SUSPENSE_PENDING,
|
|
40
41
|
SUSPENSE_REJECTED,
|
|
42
|
+
RENDER_ENTRY as $r,
|
|
41
43
|
} from './constants.js';
|
|
42
44
|
export { event, render_event, delegate } from './events.js';
|
|
45
|
+
export { portal } from './portal.js';
|
|
43
46
|
|
|
44
47
|
export {
|
|
45
48
|
active_block,
|
|
@@ -49,14 +52,8 @@ export {
|
|
|
49
52
|
get,
|
|
50
53
|
get_tracked,
|
|
51
54
|
get_derived,
|
|
52
|
-
lazy_array_get,
|
|
53
|
-
lazy_array_rest,
|
|
54
|
-
lazy_array_set,
|
|
55
|
-
lazy_array_update,
|
|
56
|
-
lazy_array_update_pre,
|
|
57
55
|
set,
|
|
58
56
|
tracked,
|
|
59
|
-
spread_props,
|
|
60
57
|
computed_property,
|
|
61
58
|
call_property,
|
|
62
59
|
get_property,
|
|
@@ -74,11 +71,8 @@ export {
|
|
|
74
71
|
untrack,
|
|
75
72
|
ref_prop,
|
|
76
73
|
create_ref_prop,
|
|
77
|
-
fallback,
|
|
78
|
-
exclude_from_object,
|
|
79
74
|
derived,
|
|
80
75
|
tick,
|
|
81
|
-
proxy_props,
|
|
82
76
|
with_block,
|
|
83
77
|
with_ns,
|
|
84
78
|
handle_error,
|
|
@@ -98,12 +92,10 @@ export { if_block as if } from './if.js';
|
|
|
98
92
|
|
|
99
93
|
export { try_block as try, get_pending_boundary } from './try.js';
|
|
100
94
|
|
|
101
|
-
export {
|
|
95
|
+
export { if_block as switch } from './if.js';
|
|
102
96
|
|
|
103
97
|
export { template, append, text } from './template.js';
|
|
104
98
|
|
|
105
|
-
export { array_slice } from '@tsrx/core/runtime/language-helpers';
|
|
106
|
-
|
|
107
99
|
export { ripple_array } from '../../array.js';
|
|
108
100
|
|
|
109
101
|
export { ripple_object } from '../../object.js';
|