ripple 0.4.2 → 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 +164 -0
- package/package.json +10 -4
- package/src/constants.js +6 -0
- package/src/jsx-runtime.d.ts +2 -1
- package/src/runtime/array.js +15 -9
- package/src/runtime/index-client.js +25 -7
- package/src/runtime/index-server.js +1 -0
- package/src/runtime/internal/client/attributes.js +439 -0
- package/src/runtime/internal/client/blocks.js +20 -20
- package/src/runtime/internal/client/component.js +2 -5
- package/src/runtime/internal/client/composite.js +295 -95
- package/src/runtime/internal/client/constants.js +14 -6
- package/src/runtime/internal/client/context.js +3 -2
- package/src/runtime/internal/client/css.js +11 -26
- package/src/runtime/internal/client/errors.js +188 -0
- package/src/runtime/internal/client/events.js +79 -34
- package/src/runtime/internal/client/expression.js +25 -120
- package/src/runtime/internal/client/for.js +113 -262
- package/src/runtime/internal/client/head.js +4 -3
- package/src/runtime/internal/client/html.js +5 -3
- package/src/runtime/internal/client/hydrate.js +484 -0
- package/src/runtime/internal/client/hydration-enabled.js +7 -0
- package/src/runtime/internal/client/hydration.js +16 -81
- package/src/runtime/internal/client/if.js +69 -10
- package/src/runtime/internal/client/index.js +18 -10
- package/src/runtime/internal/client/operations.js +11 -7
- package/src/runtime/internal/client/portal.js +3 -2
- package/src/runtime/internal/client/render.js +42 -325
- package/src/runtime/internal/client/root-boundary-enabled.js +7 -0
- package/src/runtime/internal/client/runtime.js +157 -371
- package/src/runtime/internal/client/template-ns.js +88 -0
- package/src/runtime/internal/client/template.js +118 -139
- package/src/runtime/internal/client/track-async.js +356 -0
- package/src/runtime/internal/client/try.js +133 -319
- package/src/runtime/internal/client/types.d.ts +48 -24
- package/src/runtime/internal/server/index.js +31 -29
- package/src/runtime/internal/server/prerender.js +27 -0
- package/src/server/index.js +1 -0
- package/src/utils/class-name.js +28 -0
- package/tests/client/basic/basic.errors.test.tsrx +3 -3
- package/tests/client/compiler/__snapshots__/compiler.typescript.test.tsrx.snap +0 -2
- package/tests/client/compiler/compiler.basic.test.tsrx +2 -2
- package/tests/client/compiler/compiler.tracked-access.test.tsrx +3 -3
- package/tests/client/composite/composite.dynamic-components.test.tsrx +40 -0
- package/tests/client/composite/composite.props.test.tsrx +10 -10
- package/tests/client/css/scoped-styles.test.tsrx +3 -1
- package/tests/client/derived-release.test.tsrx +3 -3
- package/tests/client/for-item.test.tsrx +39 -0
- package/tests/client/for-selector.test.tsrx +95 -0
- package/tests/client/svg.test.tsrx +273 -1
- package/tests/hydration/compiled/client/basic.js +88 -87
- package/tests/hydration/compiled/client/composite.js +15 -6
- package/tests/hydration/compiled/client/events.js +40 -48
- package/tests/hydration/compiled/client/for.js +191 -199
- package/tests/hydration/compiled/client/fragment-cursor.js +633 -334
- package/tests/hydration/compiled/client/head.js +22 -22
- package/tests/hydration/compiled/client/hmr.js +14 -5
- package/tests/hydration/compiled/client/html-in-template.js +5 -5
- package/tests/hydration/compiled/client/html.js +195 -177
- package/tests/hydration/compiled/client/if-children.js +136 -63
- package/tests/hydration/compiled/client/if-fragment-controlflow.js +63 -43
- package/tests/hydration/compiled/client/if.js +78 -30
- package/tests/hydration/compiled/client/mixed-control-flow.js +90 -72
- package/tests/hydration/compiled/client/nested-control-flow.js +266 -307
- package/tests/hydration/compiled/client/portal.js +20 -11
- package/tests/hydration/compiled/client/reactivity.js +29 -29
- package/tests/hydration/compiled/client/return.js +2 -2
- package/tests/hydration/compiled/client/streaming.js +33 -35
- package/tests/hydration/compiled/client/switch.js +25 -25
- package/tests/hydration/compiled/client/track-async-serialization.js +41 -41
- package/tests/hydration/compiled/client/try.js +15 -15
- package/tests/hydration/compiled/client/typed-text.js +8 -7
- package/tests/hydration/compiled/server/basic.js +6 -6
- package/tests/hydration/compiled/server/events.js +8 -8
- package/tests/hydration/compiled/server/for.js +22 -22
- package/tests/hydration/compiled/server/fragment-cursor.js +188 -52
- package/tests/hydration/compiled/server/head.js +6 -6
- package/tests/hydration/compiled/server/hmr.js +1 -1
- package/tests/hydration/compiled/server/html.js +1 -1
- package/tests/hydration/compiled/server/if-children.js +9 -9
- package/tests/hydration/compiled/server/if.js +5 -5
- package/tests/hydration/compiled/server/mixed-control-flow.js +4 -4
- package/tests/hydration/compiled/server/portal.js +1 -1
- package/tests/hydration/compiled/server/reactivity.js +9 -9
- package/tests/hydration/compiled/server/streaming.js +9 -9
- package/tests/hydration/compiled/server/switch.js +4 -4
- package/tests/hydration/compiled/server/track-async-serialization.js +16 -16
- package/tests/hydration/compiled/server/try.js +4 -4
- package/tests/hydration/compiled/server/typed-text.js +1 -1
- package/tests/hydration/components/fragment-cursor.tsrx +60 -0
- package/tests/hydration/components/track-async-serialization.tsrx +2 -2
- package/tests/hydration/fragment-cursor.test.js +34 -1
- package/tests/hydration/track-async-serialization.test.js +1 -1
- package/tests/server/basic.components.test.tsrx +3 -3
- package/tests/server/track-async-serialization.test.tsrx +6 -6
- package/tests/utils/tracked-types.test.js +3 -3
- package/types/index.d.ts +8 -8
- package/types/server.d.ts +17 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
/** @import { Block } from '#client' */
|
|
2
|
+
|
|
3
|
+
import { block, branch, destroy_block, ref } from './blocks.js';
|
|
4
|
+
import { DESTROYED, REF_PROP, RENDER_BLOCK, TRACKED_OBJECT } from './constants.js';
|
|
5
|
+
import { isRefProp as is_ref_prop } from '@tsrx/core/runtime/ref';
|
|
6
|
+
import { is_ripple_object } from './utils.js';
|
|
7
|
+
import {
|
|
8
|
+
get_descriptors,
|
|
9
|
+
get_own_property_symbols,
|
|
10
|
+
get_prototype_of,
|
|
11
|
+
} from '@tsrx/core/runtime/language-helpers';
|
|
12
|
+
import { event_listener } from './events.js';
|
|
13
|
+
import { get_attribute_event_name, is_event_attribute } from '@tsrx/core/runtime/events';
|
|
14
|
+
import { get } from './runtime.js';
|
|
15
|
+
import { normalize_css_property_name } from '@tsrx/core/runtime/html';
|
|
16
|
+
import { set_class_value } from './render.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Dynamic attributes, styles and spreads. Apart from `render.js`, so that an
|
|
20
|
+
* app whose attributes are all static or class/text/value writes never loads
|
|
21
|
+
* the attribute tables these helpers consult.
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/** @type {Map<string, string[]>} */
|
|
25
|
+
var setters_cache = new Map();
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {Element} element
|
|
29
|
+
* @returns {string[]}
|
|
30
|
+
*/
|
|
31
|
+
function get_setters(element) {
|
|
32
|
+
var setters = setters_cache.get(element.nodeName);
|
|
33
|
+
if (setters) return setters;
|
|
34
|
+
setters_cache.set(element.nodeName, (setters = []));
|
|
35
|
+
|
|
36
|
+
var descriptors;
|
|
37
|
+
var proto = element; // In the case of custom elements there might be setters on the instance
|
|
38
|
+
var element_proto = Element.prototype;
|
|
39
|
+
|
|
40
|
+
// Stop at Element, from there on there's only unnecessary setters we're not interested in
|
|
41
|
+
// Do not use constructor.name here as that's unreliable in some browser environments
|
|
42
|
+
while (element_proto !== proto) {
|
|
43
|
+
descriptors = get_descriptors(proto);
|
|
44
|
+
|
|
45
|
+
for (var key in descriptors) {
|
|
46
|
+
if (descriptors[key].set) {
|
|
47
|
+
setters.push(key);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
proto = get_prototype_of(proto);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return setters;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @param {Element} element
|
|
59
|
+
* @param {any} value
|
|
60
|
+
* @param {Record<string, string | number | null | undefined> | undefined} prev
|
|
61
|
+
* @returns {void}
|
|
62
|
+
*/
|
|
63
|
+
export function set_style(element, value, prev = {}) {
|
|
64
|
+
if (value == null) {
|
|
65
|
+
element.removeAttribute('style');
|
|
66
|
+
} else if (typeof value !== 'string') {
|
|
67
|
+
apply_styles(/** @type {HTMLElement} */ (element), value, prev);
|
|
68
|
+
} else {
|
|
69
|
+
// @ts-ignore
|
|
70
|
+
element.style.cssText = value;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @param {Element} element
|
|
76
|
+
* @param {string} attribute
|
|
77
|
+
* @param {any} value
|
|
78
|
+
* @returns {void}
|
|
79
|
+
*/
|
|
80
|
+
export function set_attribute(element, attribute, value) {
|
|
81
|
+
if (value == null) {
|
|
82
|
+
element.removeAttribute(attribute);
|
|
83
|
+
} else if (typeof value !== 'string' && get_setters(element).includes(attribute)) {
|
|
84
|
+
/** @type {any} */ (element)[attribute] = value;
|
|
85
|
+
} else {
|
|
86
|
+
element.setAttribute(attribute, value);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* @param {HTMLElement} element
|
|
92
|
+
* @param {Record<string, string | number | null | undefined>} new_styles
|
|
93
|
+
* @param {Record<string, string | number | null | undefined>} prev
|
|
94
|
+
*/
|
|
95
|
+
function apply_styles(element, new_styles, prev) {
|
|
96
|
+
const style = element.style;
|
|
97
|
+
|
|
98
|
+
// Apply new styles
|
|
99
|
+
for (const key in new_styles) {
|
|
100
|
+
const css_prop = normalize_css_property_name(key);
|
|
101
|
+
const raw_value = new_styles[key];
|
|
102
|
+
const value = raw_value == null ? null : String(raw_value);
|
|
103
|
+
|
|
104
|
+
if (!(key in prev) || prev[key] !== value) {
|
|
105
|
+
style.setProperty(css_prop, value);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Remove properties that were in prev but not in new_styles
|
|
110
|
+
for (const key in prev) {
|
|
111
|
+
if (!(key in new_styles)) {
|
|
112
|
+
const css_prop = normalize_css_property_name(key);
|
|
113
|
+
style.removeProperty(css_prop);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Helper function to set a single attribute
|
|
120
|
+
* @param {Element} element
|
|
121
|
+
* @param {string} key
|
|
122
|
+
* @param {any} value
|
|
123
|
+
* @param {SpreadState} state
|
|
124
|
+
*/
|
|
125
|
+
function set_attribute_helper(element, key, value, state) {
|
|
126
|
+
if (key === 'class') {
|
|
127
|
+
const is_html = element.namespaceURI === 'http://www.w3.org/1999/xhtml';
|
|
128
|
+
set_class_value(/** @type {HTMLElement} */ (element), value, undefined, is_html);
|
|
129
|
+
} else if (key === 'innerHTML') {
|
|
130
|
+
element.removeAttribute('innerhtml');
|
|
131
|
+
/** @type {HTMLElement} */ (element).innerHTML = value == null ? '' : String(value);
|
|
132
|
+
} else if (key === 'style') {
|
|
133
|
+
set_style(element, value, state.p.style);
|
|
134
|
+
} else if (key === '#class') {
|
|
135
|
+
// Special case for the scope classes of an element that spreads props:
|
|
136
|
+
// one token per scope hash and applied theme.
|
|
137
|
+
element.classList.add(...String(value).split(' ').filter(Boolean));
|
|
138
|
+
} else if (is_event_attribute(key)) {
|
|
139
|
+
// Handle event handlers in spread props
|
|
140
|
+
var listeners = (state.l ??= {});
|
|
141
|
+
if (listeners[key]) {
|
|
142
|
+
listeners[key]();
|
|
143
|
+
listeners[key] = undefined;
|
|
144
|
+
}
|
|
145
|
+
if (value != null) {
|
|
146
|
+
const event_name = get_attribute_event_name(key, value);
|
|
147
|
+
listeners[key] = event_listener(event_name, element, value);
|
|
148
|
+
}
|
|
149
|
+
} else {
|
|
150
|
+
set_attribute(element, key, value);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
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.
|
|
160
|
+
*/
|
|
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
|
+
}
|
|
182
|
+
|
|
183
|
+
/** What a nullish or primitive spread value applies. */
|
|
184
|
+
var EMPTY = {};
|
|
185
|
+
|
|
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);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
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;
|
|
236
|
+
}
|
|
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
|
+
}
|
|
244
|
+
|
|
245
|
+
for (key in next) {
|
|
246
|
+
if (key === 'children') continue;
|
|
247
|
+
|
|
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;
|
|
256
|
+
}
|
|
257
|
+
current[key] = value;
|
|
258
|
+
|
|
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;
|
|
263
|
+
}
|
|
264
|
+
set_attribute_helper(element, key, value, state);
|
|
265
|
+
}
|
|
266
|
+
|
|
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
|
+
}
|
|
276
|
+
|
|
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);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
for (var key in next) {
|
|
301
|
+
if (key === 'children') continue;
|
|
302
|
+
|
|
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
|
+
}
|
|
315
|
+
|
|
316
|
+
state.r = refs;
|
|
317
|
+
state.p = current;
|
|
318
|
+
state.n = next;
|
|
319
|
+
state.t = tracked;
|
|
320
|
+
return state;
|
|
321
|
+
}
|
|
322
|
+
|
|
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
|
+
}
|
|
354
|
+
|
|
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;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
/**
|
|
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
|
|
383
|
+
*/
|
|
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
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
/**
|
|
403
|
+
* Keep spread refs in a branch block so ordinary spread updates do not destroy
|
|
404
|
+
* and recreate the ref block before `spread` can compare the previous and
|
|
405
|
+
* current ref values.
|
|
406
|
+
*
|
|
407
|
+
* @param {Element} element
|
|
408
|
+
* @param {any} ref_fn
|
|
409
|
+
* @returns {Block}
|
|
410
|
+
*/
|
|
411
|
+
function create_spread_ref_effect(element, ref_fn) {
|
|
412
|
+
return branch(() => {
|
|
413
|
+
ref(element, () => ref_fn);
|
|
414
|
+
});
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/**
|
|
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
|
|
434
|
+
* @param {number} [flags]
|
|
435
|
+
* @returns {Block}
|
|
436
|
+
*/
|
|
437
|
+
export function render_spread(element, fn, flags = 0) {
|
|
438
|
+
return block(RENDER_BLOCK | flags, run_spread, { e: element, f: fn, s: undefined });
|
|
439
|
+
}
|
|
@@ -15,10 +15,13 @@ 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';
|
|
21
|
-
import { apply_element_spread } from './render.js';
|
|
22
25
|
import { is_array } from '@tsrx/core/runtime/language-helpers';
|
|
23
26
|
import {
|
|
24
27
|
active_block,
|
|
@@ -32,17 +35,18 @@ import {
|
|
|
32
35
|
run_teardown,
|
|
33
36
|
schedule_update,
|
|
34
37
|
untrack,
|
|
38
|
+
active_namespace,
|
|
35
39
|
} from './runtime.js';
|
|
36
40
|
import { is_ripple_object } from './utils.js';
|
|
41
|
+
import { effect_orphan } from './errors.js';
|
|
42
|
+
import { HYDRATION } from 'ripple/internal/client/hydration-enabled';
|
|
37
43
|
|
|
38
44
|
/**
|
|
39
45
|
* @param {Function} fn
|
|
40
46
|
*/
|
|
41
47
|
export function user_effect(fn) {
|
|
42
48
|
if (active_block === null) {
|
|
43
|
-
|
|
44
|
-
'effect() must be called within an active context, such as a component or effect',
|
|
45
|
-
);
|
|
49
|
+
effect_orphan();
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
var component = active_component;
|
|
@@ -85,15 +89,6 @@ export function render(fn, state, flags = 0) {
|
|
|
85
89
|
return block;
|
|
86
90
|
}
|
|
87
91
|
|
|
88
|
-
/**
|
|
89
|
-
* @param {any} element
|
|
90
|
-
* @param {any} fn
|
|
91
|
-
* @param {number} [flags]
|
|
92
|
-
*/
|
|
93
|
-
export function render_spread(element, fn, flags = 0) {
|
|
94
|
-
return block(RENDER_BLOCK | flags, apply_element_spread(element, fn));
|
|
95
|
-
}
|
|
96
|
-
|
|
97
92
|
/**
|
|
98
93
|
* @param {Function} fn
|
|
99
94
|
* @param {number} [flags]
|
|
@@ -117,7 +112,7 @@ function noop() {}
|
|
|
117
112
|
* @param {Node} anchor
|
|
118
113
|
*/
|
|
119
114
|
export function own_anchor(node, anchor) {
|
|
120
|
-
if (anchor === node || hydrating) return;
|
|
115
|
+
if (anchor === node || (HYDRATION && hydrating)) return;
|
|
121
116
|
branch(noop, 0, { start: anchor, end: anchor });
|
|
122
117
|
}
|
|
123
118
|
|
|
@@ -273,7 +268,10 @@ export function create_block(flags, fn, state = null, co) {
|
|
|
273
268
|
co: co || active_component,
|
|
274
269
|
d: null,
|
|
275
270
|
first: null,
|
|
276
|
-
f:
|
|
271
|
+
f:
|
|
272
|
+
active_namespace === DEFAULT_NAMESPACE
|
|
273
|
+
? flags
|
|
274
|
+
: flags | (active_namespace === 'svg' ? SVG_BLOCK : MATHML_BLOCK),
|
|
277
275
|
fn,
|
|
278
276
|
i: ++block_id,
|
|
279
277
|
last: null,
|
|
@@ -459,8 +457,8 @@ export function remove_block_dom(node, end) {
|
|
|
459
457
|
export function move_block(block, target) {
|
|
460
458
|
var f = block.f;
|
|
461
459
|
|
|
462
|
-
// Only branch and
|
|
463
|
-
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) {
|
|
464
462
|
var s = block.s;
|
|
465
463
|
if (s !== null && s.start !== null) {
|
|
466
464
|
var node = s.start;
|
|
@@ -503,7 +501,7 @@ export function move_block(block, target) {
|
|
|
503
501
|
*/
|
|
504
502
|
export function get_first_node(block) {
|
|
505
503
|
var f = block.f;
|
|
506
|
-
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) {
|
|
507
505
|
var s = block.s;
|
|
508
506
|
if (s !== null && s.start !== null) {
|
|
509
507
|
return s.start;
|
|
@@ -527,7 +525,7 @@ export function get_first_node(block) {
|
|
|
527
525
|
*/
|
|
528
526
|
export function get_last_node(block) {
|
|
529
527
|
var f = block.f;
|
|
530
|
-
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) {
|
|
531
529
|
var s = block.s;
|
|
532
530
|
if (s !== null && s.start !== null) {
|
|
533
531
|
// An if's materialized anchor is its last node.
|
|
@@ -561,7 +559,9 @@ export function destroy_block(block, remove_dom = true) {
|
|
|
561
559
|
}
|
|
562
560
|
|
|
563
561
|
if (
|
|
564
|
-
(remove_dom &&
|
|
562
|
+
(remove_dom &&
|
|
563
|
+
(f & (BRANCH_BLOCK | ROOT_BLOCK | IF_BLOCK | COMPOSITE_BLOCK)) !== 0 &&
|
|
564
|
+
(f & TRY_BLOCK) === 0) ||
|
|
565
565
|
(f & HEAD_BLOCK) !== 0
|
|
566
566
|
) {
|
|
567
567
|
var s = block.s;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { is_tsrx_element } from '../../element.js';
|
|
4
4
|
import { render_value } from './expression.js';
|
|
5
5
|
import { active_block } from './runtime.js';
|
|
6
|
+
import { component_invalid } from './errors.js';
|
|
6
7
|
|
|
7
8
|
export { render_component } from './runtime.js';
|
|
8
9
|
|
|
@@ -21,9 +22,5 @@ export function render_tsrx_element(value, anchor, block = active_block) {
|
|
|
21
22
|
* @returns {never}
|
|
22
23
|
*/
|
|
23
24
|
export function throw_invalid_component_type(value) {
|
|
24
|
-
|
|
25
|
-
throw new TypeError('Invalid component type: received a TSRXElement value.');
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
throw new TypeError('Invalid component type: expected a component function.');
|
|
25
|
+
component_invalid(is_tsrx_element(value));
|
|
29
26
|
}
|