ripple 0.4.3 → 0.4.4
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 +57 -0
- package/package.json +3 -3
- package/src/constants.js +6 -0
- package/src/runtime/internal/client/attributes.js +251 -125
- package/src/runtime/internal/client/blocks.js +16 -6
- package/src/runtime/internal/client/composite.js +292 -100
- package/src/runtime/internal/client/constants.js +8 -0
- package/src/runtime/internal/client/expression.js +4 -4
- package/src/runtime/internal/client/for.js +13 -38
- package/src/runtime/internal/client/if.js +56 -1
- package/src/runtime/internal/client/index.js +6 -6
- package/src/runtime/internal/client/runtime.js +73 -11
- package/src/runtime/internal/client/template-ns.js +45 -4
- package/src/runtime/internal/client/template.js +56 -0
- package/tests/client/composite/composite.dynamic-components.test.tsrx +40 -0
- package/tests/client/css/scoped-styles.test.tsrx +3 -1
- package/tests/client/svg.test.tsrx +273 -1
- package/tests/hydration/compiled/client/basic.js +36 -35
- package/tests/hydration/compiled/client/composite.js +11 -2
- package/tests/hydration/compiled/client/events.js +1 -1
- package/tests/hydration/compiled/client/for.js +73 -62
- package/tests/hydration/compiled/client/fragment-cursor.js +182 -115
- package/tests/hydration/compiled/client/head.js +10 -10
- package/tests/hydration/compiled/client/hmr.js +11 -2
- package/tests/hydration/compiled/client/html-in-template.js +1 -1
- package/tests/hydration/compiled/client/html.js +78 -50
- package/tests/hydration/compiled/client/if-children.js +94 -26
- package/tests/hydration/compiled/client/if-fragment-controlflow.js +34 -14
- package/tests/hydration/compiled/client/if.js +65 -17
- package/tests/hydration/compiled/client/mixed-control-flow.js +50 -20
- package/tests/hydration/compiled/client/nested-control-flow.js +188 -97
- package/tests/hydration/compiled/client/portal.js +14 -5
- package/tests/hydration/compiled/client/reactivity.js +3 -3
- package/tests/hydration/compiled/client/streaming.js +17 -17
- package/tests/hydration/compiled/client/switch.js +17 -17
- package/tests/hydration/compiled/client/track-async-serialization.js +19 -19
- package/tests/hydration/compiled/client/try.js +9 -9
- package/tests/hydration/compiled/client/typed-text.js +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,62 @@
|
|
|
1
1
|
# ripple
|
|
2
2
|
|
|
3
|
+
## 0.4.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#1496](https://github.com/Ripple-TS/ripple/pull/1496)
|
|
8
|
+
[`0473e93`](https://github.com/Ripple-TS/ripple/commit/0473e93006e53cd15fcf6d851443d427ccf13e8b)
|
|
9
|
+
Thanks [@leonidaz](https://github.com/leonidaz)! - Update `@tsrx/core` to ^0.2.3
|
|
10
|
+
and use its SVG and MathML tag-name predicates for dynamic class handling,
|
|
11
|
+
removing the compiler's duplicate tag-name list.
|
|
12
|
+
|
|
13
|
+
- [#1490](https://github.com/Ripple-TS/ripple/pull/1490)
|
|
14
|
+
[`ff3a26a`](https://github.com/Ripple-TS/ripple/commit/ff3a26acef0c9584cf41d32bc8cbcc39d863d74c)
|
|
15
|
+
Thanks [@leonidaz](https://github.com/leonidaz)! - Blocks keep the namespace
|
|
16
|
+
they were created in when they rerun. A dynamic element whose tag changes, an
|
|
17
|
+
`@if` that toggles, or an `@for` that grows inside an SVG that is only known at
|
|
18
|
+
runtime (children rendered into a component's `<svg>`, a leaf component rendered
|
|
19
|
+
there) now creates its elements in the SVG namespace instead of HTML, and a
|
|
20
|
+
nested template cloned in that context no longer throws before a namespaced
|
|
21
|
+
template has been parsed. A dynamic element whose tag becomes `foreignObject`
|
|
22
|
+
renders its children as HTML.
|
|
23
|
+
|
|
24
|
+
- [#1488](https://github.com/Ripple-TS/ripple/pull/1488)
|
|
25
|
+
[`b3bf787`](https://github.com/Ripple-TS/ripple/commit/b3bf78756d9235412a2af264e42897652e8f911e)
|
|
26
|
+
Thanks [@leonidaz](https://github.com/leonidaz)! - Build a template that is one
|
|
27
|
+
element with static attributes and at most a text child with DOM calls instead
|
|
28
|
+
of parsing it. Parsing a `<template>` has a fixed cost that dwarfs such an
|
|
29
|
+
element, and an app's first render pays it once per distinct template; a chain
|
|
30
|
+
of 100 single-element components mounts about 35% faster.
|
|
31
|
+
|
|
32
|
+
- [#1495](https://github.com/Ripple-TS/ripple/pull/1495)
|
|
33
|
+
[`1b8381f`](https://github.com/Ripple-TS/ripple/commit/1b8381f31f98f84049764ca56676fc320721e844)
|
|
34
|
+
Thanks [@leonidaz](https://github.com/leonidaz)! - Faster element spreads,
|
|
35
|
+
dynamic elements and list items. An element spread is applied from the element's
|
|
36
|
+
own render function instead of a render block of its own, and a spread object
|
|
37
|
+
identical to the one applied last is skipped without a diff (a spread of a
|
|
38
|
+
tracked object or of tracked values is always diffed). A dynamic element
|
|
39
|
+
(`<{tag}>`) is one block that owns its element and applies its attributes
|
|
40
|
+
itself; a tag that does not change keeps its element and diffs the attributes,
|
|
41
|
+
so a swap between variants with the same tag no longer recreates the element. An
|
|
42
|
+
`@if` whose condition reads tracked state is evaluated by the render function of
|
|
43
|
+
the enclosing content (a list item's, an element's), so the if keeps a block for
|
|
44
|
+
its branch but not one that runs the condition. A dynamic element or component
|
|
45
|
+
called inside an `<svg>` or `<math>` template receives the namespace as an
|
|
46
|
+
argument instead of a `with_ns` closure. A dynamic element without children is
|
|
47
|
+
driven by the render function of the content it sits in, with no block or
|
|
48
|
+
closures of its own (`_$_.dynamic`); a build that can hydrate lets a composite
|
|
49
|
+
block claim the server element while hydrating. With `textTypes`, an attribute
|
|
50
|
+
value TypeScript proves to be a string is set with a direct `setAttribute` call,
|
|
51
|
+
and a proven `class` takes the string-only path. On the SVG dashboard benchmark,
|
|
52
|
+
mounting is about 20% faster and swapping 150 dynamic icons 40% faster.
|
|
53
|
+
- Updated dependencies
|
|
54
|
+
[[`0473e93`](https://github.com/Ripple-TS/ripple/commit/0473e93006e53cd15fcf6d851443d427ccf13e8b),
|
|
55
|
+
[`b3bf787`](https://github.com/Ripple-TS/ripple/commit/b3bf78756d9235412a2af264e42897652e8f911e),
|
|
56
|
+
[`1b8381f`](https://github.com/Ripple-TS/ripple/commit/1b8381f31f98f84049764ca56676fc320721e844),
|
|
57
|
+
[`ff3a26a`](https://github.com/Ripple-TS/ripple/commit/ff3a26acef0c9584cf41d32bc8cbcc39d863d74c)]:
|
|
58
|
+
- @tsrx/ripple@0.2.3
|
|
59
|
+
|
|
3
60
|
## 0.4.3
|
|
4
61
|
|
|
5
62
|
### Patch Changes
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"description": "Ripple is an elegant TypeScript UI framework",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "Dominic Gannaway",
|
|
6
|
-
"version": "0.4.
|
|
6
|
+
"version": "0.4.4",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"sideEffects": false,
|
|
9
9
|
"module": "src/runtime/index-client.js",
|
|
@@ -86,8 +86,8 @@
|
|
|
86
86
|
"csstype": "^3.2.3",
|
|
87
87
|
"devalue": "^5.9.2",
|
|
88
88
|
"esm-env": "^1.2.2",
|
|
89
|
-
"@tsrx/core": "^0.2.
|
|
90
|
-
"@tsrx/ripple": "0.2.
|
|
89
|
+
"@tsrx/core": "^0.2.3",
|
|
90
|
+
"@tsrx/ripple": "0.2.3"
|
|
91
91
|
},
|
|
92
92
|
"devDependencies": {
|
|
93
93
|
"@types/estree": "^1.0.8",
|
package/src/constants.js
CHANGED
|
@@ -38,3 +38,9 @@ export const ELEMENT_NODE = 1;
|
|
|
38
38
|
export const TEXT_NODE = 3;
|
|
39
39
|
export const COMMENT_NODE = 8;
|
|
40
40
|
export const DOCUMENT_FRAGMENT_NODE = 11;
|
|
41
|
+
|
|
42
|
+
// `if_static` flags (see the runtime's if module): the if renders directly
|
|
43
|
+
// before the component's `__anchor`, and the compiler proved its condition
|
|
44
|
+
// reads tracked state.
|
|
45
|
+
export const IF_ROOT_CONTROLLED = 1;
|
|
46
|
+
export const IF_TRACKED = 1 << 1;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @import { Block } from '#client' */
|
|
2
2
|
|
|
3
3
|
import { block, branch, destroy_block, ref } from './blocks.js';
|
|
4
|
-
import { DESTROYED, REF_PROP, RENDER_BLOCK } from './constants.js';
|
|
4
|
+
import { DESTROYED, REF_PROP, RENDER_BLOCK, TRACKED_OBJECT } from './constants.js';
|
|
5
5
|
import { isRefProp as is_ref_prop } from '@tsrx/core/runtime/ref';
|
|
6
6
|
import { is_ripple_object } from './utils.js';
|
|
7
7
|
import {
|
|
@@ -120,10 +120,9 @@ function apply_styles(element, new_styles, prev) {
|
|
|
120
120
|
* @param {Element} element
|
|
121
121
|
* @param {string} key
|
|
122
122
|
* @param {any} value
|
|
123
|
-
* @param {
|
|
124
|
-
* @param {Record<string | symbol, any>} prev
|
|
123
|
+
* @param {SpreadState} state
|
|
125
124
|
*/
|
|
126
|
-
function set_attribute_helper(element, key, value,
|
|
125
|
+
function set_attribute_helper(element, key, value, state) {
|
|
127
126
|
if (key === 'class') {
|
|
128
127
|
const is_html = element.namespaceURI === 'http://www.w3.org/1999/xhtml';
|
|
129
128
|
set_class_value(/** @type {HTMLElement} */ (element), value, undefined, is_html);
|
|
@@ -131,20 +130,21 @@ function set_attribute_helper(element, key, value, remove_listeners, prev) {
|
|
|
131
130
|
element.removeAttribute('innerhtml');
|
|
132
131
|
/** @type {HTMLElement} */ (element).innerHTML = value == null ? '' : String(value);
|
|
133
132
|
} else if (key === 'style') {
|
|
134
|
-
set_style(element, value,
|
|
133
|
+
set_style(element, value, state.p.style);
|
|
135
134
|
} else if (key === '#class') {
|
|
136
135
|
// Special case for the scope classes of an element that spreads props:
|
|
137
136
|
// one token per scope hash and applied theme.
|
|
138
137
|
element.classList.add(...String(value).split(' ').filter(Boolean));
|
|
139
|
-
} else if (
|
|
138
|
+
} else if (is_event_attribute(key)) {
|
|
140
139
|
// Handle event handlers in spread props
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
140
|
+
var listeners = (state.l ??= {});
|
|
141
|
+
if (listeners[key]) {
|
|
142
|
+
listeners[key]();
|
|
143
|
+
listeners[key] = undefined;
|
|
144
144
|
}
|
|
145
145
|
if (value != null) {
|
|
146
146
|
const event_name = get_attribute_event_name(key, value);
|
|
147
|
-
|
|
147
|
+
listeners[key] = event_listener(event_name, element, value);
|
|
148
148
|
}
|
|
149
149
|
} else {
|
|
150
150
|
set_attribute(element, key, value);
|
|
@@ -152,146 +152,257 @@ function set_attribute_helper(element, key, value, remove_listeners, prev) {
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
/**
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
155
|
+
* The state of one element spread: the object and values it last applied,
|
|
156
|
+
* and the listeners and ref effects it owns. `spread()` creates it on its
|
|
157
|
+
* first call and is handed it back by every later one, so the compiled render
|
|
158
|
+
* function keeps it in its own state object, and a `render_spread` block in
|
|
159
|
+
* its block state.
|
|
158
160
|
*/
|
|
159
|
-
export
|
|
160
|
-
/** @
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
161
|
+
export class SpreadState {
|
|
162
|
+
/** @param {Element} element */
|
|
163
|
+
constructor(element) {
|
|
164
|
+
this.e = element;
|
|
165
|
+
/** @type {Record<string | symbol, any> | null} the object last applied, compared by identity */
|
|
166
|
+
this.n = null;
|
|
167
|
+
/** @type {Record<string, any>} the values last applied, by key */
|
|
168
|
+
this.p = {};
|
|
169
|
+
/**
|
|
170
|
+
* The object last applied was a tracked object, or held a tracked value:
|
|
171
|
+
* the same object can carry new values, so it is never skipped on identity.
|
|
172
|
+
*/
|
|
173
|
+
this.t = false;
|
|
174
|
+
/** @type {Record<string, (() => void) | undefined> | null} listeners by event key */
|
|
175
|
+
this.l = null;
|
|
176
|
+
/** @type {Record<string | symbol, any> | null} the ref props last applied */
|
|
177
|
+
this.r = null;
|
|
178
|
+
/** @type {Record<string | symbol, Block | undefined> | null} the effects of those ref props */
|
|
179
|
+
this.b = null;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
171
182
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
var current_symbols = /** @type {Record<symbol, any>} */ ({});
|
|
183
|
+
/** What a nullish or primitive spread value applies. */
|
|
184
|
+
var EMPTY = {};
|
|
175
185
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
186
|
+
/**
|
|
187
|
+
* Applies a spread of attributes to an element, diffing against what the
|
|
188
|
+
* previous call applied: attributes, `class`, `style` objects, event
|
|
189
|
+
* listeners and ref props. An object identical to the last one applied is
|
|
190
|
+
* skipped outright, unless that object was a tracked object or held a
|
|
191
|
+
* tracked value (its contents can change while its identity does not).
|
|
192
|
+
* Called from a compiled render function with the state it returned before
|
|
193
|
+
* (`undefined` the first time), which the render function stores.
|
|
194
|
+
* @param {Element} element
|
|
195
|
+
* @param {any} next
|
|
196
|
+
* @param {SpreadState | undefined} state
|
|
197
|
+
* @returns {SpreadState}
|
|
198
|
+
*/
|
|
199
|
+
export function spread(element, next, state) {
|
|
200
|
+
if (next == null || (typeof next !== 'object' && typeof next !== 'function')) {
|
|
201
|
+
next = EMPTY;
|
|
202
|
+
}
|
|
203
|
+
if (state === undefined) {
|
|
204
|
+
return apply_spread(new SpreadState(element), next);
|
|
205
|
+
}
|
|
206
|
+
if (state.n === next && !state.t) {
|
|
207
|
+
return state;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
var prev = state.p;
|
|
211
|
+
/** @type {Record<string, any>} */
|
|
212
|
+
var current = {};
|
|
213
|
+
/** @type {Record<string | symbol, any> | null} */
|
|
214
|
+
var refs = null;
|
|
215
|
+
var tracked = TRACKED_OBJECT in next;
|
|
216
|
+
var key;
|
|
217
|
+
|
|
218
|
+
// A parent's ref prop travels through a spread on a symbol key.
|
|
219
|
+
var symbols = get_own_property_symbols(next);
|
|
220
|
+
for (var i = 0; i < symbols.length; i++) {
|
|
221
|
+
var symbol = symbols[i];
|
|
222
|
+
if (symbol.description === REF_PROP) {
|
|
223
|
+
refs = apply_ref_prop(state, symbol, next[symbol], refs);
|
|
193
224
|
}
|
|
225
|
+
}
|
|
194
226
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
227
|
+
// Listeners and attributes that are gone, or now carry a ref prop, are
|
|
228
|
+
// removed before anything is applied: removing `class` drops the scope
|
|
229
|
+
// classes too, which `#class` then adds back.
|
|
230
|
+
var listeners = state.l;
|
|
231
|
+
if (listeners !== null) {
|
|
232
|
+
for (key in listeners) {
|
|
233
|
+
if (listeners[key] !== undefined && (!(key in next) || is_ref_prop(next[key]))) {
|
|
234
|
+
/** @type {() => void} */ (listeners[key])();
|
|
235
|
+
listeners[key] = undefined;
|
|
199
236
|
}
|
|
200
237
|
}
|
|
238
|
+
}
|
|
239
|
+
for (key in prev) {
|
|
240
|
+
if (key !== '#class' && (!(key in next) || is_ref_prop(next[key]))) {
|
|
241
|
+
set_attribute_helper(element, key, null, state);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
201
244
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
/** @type {Record<string, any>} */
|
|
205
|
-
var current_ref_props = {};
|
|
206
|
-
var keys = spread_keys(next);
|
|
207
|
-
|
|
208
|
-
for (const key of keys) {
|
|
209
|
-
const ref_fn = next[key];
|
|
210
|
-
if (!is_ref_prop(ref_fn)) {
|
|
211
|
-
continue;
|
|
212
|
-
}
|
|
245
|
+
for (key in next) {
|
|
246
|
+
if (key === 'children') continue;
|
|
213
247
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
)
|
|
221
|
-
|
|
222
|
-
destroy_block(effects[key]);
|
|
223
|
-
}
|
|
224
|
-
effects[key] = create_spread_ref_effect(element, ref_fn);
|
|
225
|
-
}
|
|
248
|
+
var value = next[key];
|
|
249
|
+
if (typeof value === 'function' && is_ref_prop(value)) {
|
|
250
|
+
refs = apply_ref_prop(state, key, value, refs);
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
if (is_ripple_object(value)) {
|
|
254
|
+
value = get(value);
|
|
255
|
+
tracked = true;
|
|
226
256
|
}
|
|
257
|
+
current[key] = value;
|
|
227
258
|
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
259
|
+
// The scope classes are added after every run: a `class` write may
|
|
260
|
+
// have replaced them.
|
|
261
|
+
if (key !== '#class' && key in prev && prev[key] === value) {
|
|
262
|
+
continue;
|
|
233
263
|
}
|
|
264
|
+
set_attribute_helper(element, key, value, state);
|
|
265
|
+
}
|
|
234
266
|
|
|
235
|
-
|
|
267
|
+
if (state.r !== null) {
|
|
268
|
+
release_ref_props(state, refs);
|
|
269
|
+
}
|
|
270
|
+
state.r = refs;
|
|
271
|
+
state.p = current;
|
|
272
|
+
state.n = next;
|
|
273
|
+
state.t = tracked;
|
|
274
|
+
return state;
|
|
275
|
+
}
|
|
236
276
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
277
|
+
/**
|
|
278
|
+
* The first run of a spread: nothing to remove or compare, every value is
|
|
279
|
+
* applied.
|
|
280
|
+
* @param {SpreadState} state
|
|
281
|
+
* @param {Record<string | symbol, any>} next
|
|
282
|
+
* @returns {SpreadState}
|
|
283
|
+
*/
|
|
284
|
+
function apply_spread(state, next) {
|
|
285
|
+
var element = state.e;
|
|
286
|
+
/** @type {Record<string, any>} */
|
|
287
|
+
var current = {};
|
|
288
|
+
/** @type {Record<string | symbol, any> | null} */
|
|
289
|
+
var refs = null;
|
|
290
|
+
var tracked = TRACKED_OBJECT in next;
|
|
291
|
+
|
|
292
|
+
var symbols = get_own_property_symbols(next);
|
|
293
|
+
for (var i = 0; i < symbols.length; i++) {
|
|
294
|
+
var symbol = symbols[i];
|
|
295
|
+
if (symbol.description === REF_PROP) {
|
|
296
|
+
refs = apply_ref_prop(state, symbol, next[symbol], refs);
|
|
243
297
|
}
|
|
298
|
+
}
|
|
244
299
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
if (key === '#class') {
|
|
248
|
-
continue;
|
|
249
|
-
}
|
|
250
|
-
set_attribute_helper(element, key, null, remove_listeners, prev);
|
|
251
|
-
}
|
|
252
|
-
}
|
|
300
|
+
for (var key in next) {
|
|
301
|
+
if (key === 'children') continue;
|
|
253
302
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
303
|
+
var value = next[key];
|
|
304
|
+
if (typeof value === 'function' && is_ref_prop(value)) {
|
|
305
|
+
refs = apply_ref_prop(state, key, value, refs);
|
|
306
|
+
continue;
|
|
307
|
+
}
|
|
308
|
+
if (is_ripple_object(value)) {
|
|
309
|
+
value = get(value);
|
|
310
|
+
tracked = true;
|
|
311
|
+
}
|
|
312
|
+
current[key] = value;
|
|
313
|
+
set_attribute_helper(element, key, value, state);
|
|
314
|
+
}
|
|
258
315
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
}
|
|
266
|
-
current[key] = value;
|
|
316
|
+
state.r = refs;
|
|
317
|
+
state.p = current;
|
|
318
|
+
state.n = next;
|
|
319
|
+
state.t = tracked;
|
|
320
|
+
return state;
|
|
321
|
+
}
|
|
267
322
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
323
|
+
/**
|
|
324
|
+
* Keeps the effect of a ref prop the spread carried before, or creates one
|
|
325
|
+
* for a ref prop that is new or changed.
|
|
326
|
+
* @param {SpreadState} state
|
|
327
|
+
* @param {string | symbol} key
|
|
328
|
+
* @param {any} ref_fn
|
|
329
|
+
* @param {Record<string | symbol, any> | null} refs the ref props of this run
|
|
330
|
+
* @returns {Record<string | symbol, any>}
|
|
331
|
+
*/
|
|
332
|
+
function apply_ref_prop(state, key, ref_fn, refs) {
|
|
333
|
+
if (refs === null) {
|
|
334
|
+
refs = {};
|
|
335
|
+
}
|
|
336
|
+
refs[key] = ref_fn;
|
|
337
|
+
|
|
338
|
+
var previous = state.r;
|
|
339
|
+
var blocks = (state.b ??= {});
|
|
340
|
+
var block = blocks[key];
|
|
341
|
+
if (
|
|
342
|
+
previous === null ||
|
|
343
|
+
!(key in previous) ||
|
|
344
|
+
previous[key] !== ref_fn ||
|
|
345
|
+
(block !== undefined && (block.f & DESTROYED) !== 0)
|
|
346
|
+
) {
|
|
347
|
+
if (block !== undefined && (block.f & DESTROYED) === 0) {
|
|
348
|
+
destroy_block(block);
|
|
349
|
+
}
|
|
350
|
+
blocks[key] = create_spread_ref_effect(state.e, ref_fn);
|
|
351
|
+
}
|
|
352
|
+
return refs;
|
|
353
|
+
}
|
|
271
354
|
|
|
272
|
-
|
|
355
|
+
/**
|
|
356
|
+
* Destroys the effects of the ref props a spread no longer carries.
|
|
357
|
+
* @param {SpreadState} state
|
|
358
|
+
* @param {Record<string | symbol, any> | null} refs the ref props of this run
|
|
359
|
+
*/
|
|
360
|
+
function release_ref_props(state, refs) {
|
|
361
|
+
var previous = /** @type {Record<string | symbol, any>} */ (state.r);
|
|
362
|
+
var blocks = /** @type {Record<string | symbol, Block | undefined>} */ (state.b);
|
|
363
|
+
/** @type {(string | symbol)[]} */
|
|
364
|
+
var keys = get_own_property_symbols(previous);
|
|
365
|
+
for (var key in previous) {
|
|
366
|
+
keys.push(key);
|
|
367
|
+
}
|
|
368
|
+
for (var i = 0; i < keys.length; i++) {
|
|
369
|
+
var k = keys[i];
|
|
370
|
+
var block = blocks[k];
|
|
371
|
+
if ((refs === null || !(k in refs)) && block !== undefined) {
|
|
372
|
+
destroy_block(block);
|
|
373
|
+
blocks[k] = undefined;
|
|
273
374
|
}
|
|
274
|
-
|
|
275
|
-
};
|
|
375
|
+
}
|
|
276
376
|
}
|
|
277
377
|
|
|
278
378
|
/**
|
|
279
|
-
*
|
|
280
|
-
*
|
|
281
|
-
*
|
|
282
|
-
* @
|
|
379
|
+
* Releases what a spread owns when its element is dropped by something other
|
|
380
|
+
* than its block (a dynamic element replaced by a tag change): its ref
|
|
381
|
+
* effects, so refs receive null, and its listeners.
|
|
382
|
+
* @param {SpreadState | undefined} state
|
|
283
383
|
*/
|
|
284
|
-
function
|
|
285
|
-
|
|
286
|
-
var
|
|
287
|
-
|
|
288
|
-
|
|
384
|
+
export function release_spread(state) {
|
|
385
|
+
if (state === undefined) return;
|
|
386
|
+
var blocks = state.b;
|
|
387
|
+
if (blocks !== null) {
|
|
388
|
+
release_ref_props(state, null);
|
|
389
|
+
}
|
|
390
|
+
var listeners = state.l;
|
|
391
|
+
if (listeners !== null) {
|
|
392
|
+
for (var key in listeners) {
|
|
393
|
+
var remove = listeners[key];
|
|
394
|
+
if (remove !== undefined) {
|
|
395
|
+
remove();
|
|
396
|
+
listeners[key] = undefined;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
}
|
|
289
400
|
}
|
|
290
401
|
|
|
291
402
|
/**
|
|
292
403
|
* Keep spread refs in a branch block so ordinary spread updates do not destroy
|
|
293
|
-
* and recreate the ref block before `
|
|
294
|
-
*
|
|
404
|
+
* and recreate the ref block before `spread` can compare the previous and
|
|
405
|
+
* current ref values.
|
|
295
406
|
*
|
|
296
407
|
* @param {Element} element
|
|
297
408
|
* @param {any} ref_fn
|
|
@@ -302,12 +413,27 @@ function create_spread_ref_effect(element, ref_fn) {
|
|
|
302
413
|
ref(element, () => ref_fn);
|
|
303
414
|
});
|
|
304
415
|
}
|
|
416
|
+
|
|
305
417
|
/**
|
|
306
|
-
*
|
|
307
|
-
|
|
308
|
-
|
|
418
|
+
* @typedef {{ e: Element; f: () => any; s: SpreadState | undefined }} RenderSpreadState
|
|
419
|
+
*/
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* @param {RenderSpreadState} s
|
|
423
|
+
*/
|
|
424
|
+
function run_spread(s) {
|
|
425
|
+
s.s = spread(s.e, s.f(), s.s);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* A render block that applies a spread of attributes to an element: for a
|
|
430
|
+
* dynamic element, whose attributes are its props literal. Compiled
|
|
431
|
+
* elements apply their spread from their own render function instead.
|
|
432
|
+
* @param {Element} element
|
|
433
|
+
* @param {() => any} fn
|
|
309
434
|
* @param {number} [flags]
|
|
435
|
+
* @returns {Block}
|
|
310
436
|
*/
|
|
311
437
|
export function render_spread(element, fn, flags = 0) {
|
|
312
|
-
return block(RENDER_BLOCK | flags,
|
|
438
|
+
return block(RENDER_BLOCK | flags, run_spread, { e: element, f: fn, s: undefined });
|
|
313
439
|
}
|
|
@@ -15,6 +15,10 @@ import {
|
|
|
15
15
|
HEAD_BLOCK,
|
|
16
16
|
IF_BLOCK,
|
|
17
17
|
CREATES_DERIVEDS,
|
|
18
|
+
COMPOSITE_BLOCK,
|
|
19
|
+
DEFAULT_NAMESPACE,
|
|
20
|
+
SVG_BLOCK,
|
|
21
|
+
MATHML_BLOCK,
|
|
18
22
|
} from './constants.js';
|
|
19
23
|
import { hydrating } from './hydration.js';
|
|
20
24
|
import { next_sibling } from './operations.js';
|
|
@@ -31,6 +35,7 @@ import {
|
|
|
31
35
|
run_teardown,
|
|
32
36
|
schedule_update,
|
|
33
37
|
untrack,
|
|
38
|
+
active_namespace,
|
|
34
39
|
} from './runtime.js';
|
|
35
40
|
import { is_ripple_object } from './utils.js';
|
|
36
41
|
import { effect_orphan } from './errors.js';
|
|
@@ -263,7 +268,10 @@ export function create_block(flags, fn, state = null, co) {
|
|
|
263
268
|
co: co || active_component,
|
|
264
269
|
d: null,
|
|
265
270
|
first: null,
|
|
266
|
-
f:
|
|
271
|
+
f:
|
|
272
|
+
active_namespace === DEFAULT_NAMESPACE
|
|
273
|
+
? flags
|
|
274
|
+
: flags | (active_namespace === 'svg' ? SVG_BLOCK : MATHML_BLOCK),
|
|
267
275
|
fn,
|
|
268
276
|
i: ++block_id,
|
|
269
277
|
last: null,
|
|
@@ -449,8 +457,8 @@ export function remove_block_dom(node, end) {
|
|
|
449
457
|
export function move_block(block, target) {
|
|
450
458
|
var f = block.f;
|
|
451
459
|
|
|
452
|
-
// Only branch and
|
|
453
|
-
if ((f & (BRANCH_BLOCK | IF_BLOCK)) !== 0 && (f & TRY_BLOCK) === 0) {
|
|
460
|
+
// Only branch, if and composite blocks (excluding TRY_BLOCK) can have DOM state to move
|
|
461
|
+
if ((f & (BRANCH_BLOCK | IF_BLOCK | COMPOSITE_BLOCK)) !== 0 && (f & TRY_BLOCK) === 0) {
|
|
454
462
|
var s = block.s;
|
|
455
463
|
if (s !== null && s.start !== null) {
|
|
456
464
|
var node = s.start;
|
|
@@ -493,7 +501,7 @@ export function move_block(block, target) {
|
|
|
493
501
|
*/
|
|
494
502
|
export function get_first_node(block) {
|
|
495
503
|
var f = block.f;
|
|
496
|
-
if ((f & (BRANCH_BLOCK | IF_BLOCK)) !== 0 && (f & TRY_BLOCK) === 0) {
|
|
504
|
+
if ((f & (BRANCH_BLOCK | IF_BLOCK | COMPOSITE_BLOCK)) !== 0 && (f & TRY_BLOCK) === 0) {
|
|
497
505
|
var s = block.s;
|
|
498
506
|
if (s !== null && s.start !== null) {
|
|
499
507
|
return s.start;
|
|
@@ -517,7 +525,7 @@ export function get_first_node(block) {
|
|
|
517
525
|
*/
|
|
518
526
|
export function get_last_node(block) {
|
|
519
527
|
var f = block.f;
|
|
520
|
-
if ((f & (BRANCH_BLOCK | IF_BLOCK)) !== 0 && (f & TRY_BLOCK) === 0) {
|
|
528
|
+
if ((f & (BRANCH_BLOCK | IF_BLOCK | COMPOSITE_BLOCK)) !== 0 && (f & TRY_BLOCK) === 0) {
|
|
521
529
|
var s = block.s;
|
|
522
530
|
if (s !== null && s.start !== null) {
|
|
523
531
|
// An if's materialized anchor is its last node.
|
|
@@ -551,7 +559,9 @@ export function destroy_block(block, remove_dom = true) {
|
|
|
551
559
|
}
|
|
552
560
|
|
|
553
561
|
if (
|
|
554
|
-
(remove_dom &&
|
|
562
|
+
(remove_dom &&
|
|
563
|
+
(f & (BRANCH_BLOCK | ROOT_BLOCK | IF_BLOCK | COMPOSITE_BLOCK)) !== 0 &&
|
|
564
|
+
(f & TRY_BLOCK) === 0) ||
|
|
555
565
|
(f & HEAD_BLOCK) !== 0
|
|
556
566
|
) {
|
|
557
567
|
var s = block.s;
|