ripple 0.4.1 → 0.4.3

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.
Files changed (96) hide show
  1. package/CHANGELOG.md +162 -0
  2. package/package.json +9 -3
  3. package/src/constants.js +4 -0
  4. package/src/jsx-runtime.d.ts +2 -1
  5. package/src/runtime/array.js +15 -9
  6. package/src/runtime/index-client.js +25 -7
  7. package/src/runtime/index-server.js +1 -0
  8. package/src/runtime/internal/client/attributes.js +313 -0
  9. package/src/runtime/internal/client/blocks.js +4 -14
  10. package/src/runtime/internal/client/component.js +2 -5
  11. package/src/runtime/internal/client/composite.js +14 -6
  12. package/src/runtime/internal/client/constants.js +12 -6
  13. package/src/runtime/internal/client/context.js +3 -2
  14. package/src/runtime/internal/client/css.js +11 -26
  15. package/src/runtime/internal/client/errors.js +188 -0
  16. package/src/runtime/internal/client/events.js +79 -34
  17. package/src/runtime/internal/client/expression.js +21 -116
  18. package/src/runtime/internal/client/for.js +272 -222
  19. package/src/runtime/internal/client/head.js +4 -3
  20. package/src/runtime/internal/client/html.js +5 -3
  21. package/src/runtime/internal/client/hydrate.js +484 -0
  22. package/src/runtime/internal/client/hydration-enabled.js +7 -0
  23. package/src/runtime/internal/client/hydration.js +16 -97
  24. package/src/runtime/internal/client/if.js +13 -9
  25. package/src/runtime/internal/client/index.js +16 -8
  26. package/src/runtime/internal/client/operations.js +12 -9
  27. package/src/runtime/internal/client/portal.js +3 -2
  28. package/src/runtime/internal/client/render.js +75 -321
  29. package/src/runtime/internal/client/root-boundary-enabled.js +7 -0
  30. package/src/runtime/internal/client/runtime.js +129 -362
  31. package/src/runtime/internal/client/template-ns.js +47 -0
  32. package/src/runtime/internal/client/template.js +63 -140
  33. package/src/runtime/internal/client/track-async.js +356 -0
  34. package/src/runtime/internal/client/try.js +133 -319
  35. package/src/runtime/internal/client/types.d.ts +48 -24
  36. package/src/runtime/internal/server/index.js +38 -33
  37. package/src/runtime/internal/server/prerender.js +27 -0
  38. package/src/server/index.js +1 -0
  39. package/src/utils/class-name.js +28 -0
  40. package/tests/client/basic/basic.errors.test.tsrx +3 -3
  41. package/tests/client/compiler/__snapshots__/compiler.typescript.test.tsrx.snap +0 -2
  42. package/tests/client/compiler/compiler.basic.test.tsrx +4 -4
  43. package/tests/client/compiler/compiler.tracked-access.test.tsrx +3 -3
  44. package/tests/client/composite/composite.props.test.tsrx +10 -10
  45. package/tests/client/derived-release.test.tsrx +3 -3
  46. package/tests/client/for-item.test.tsrx +443 -0
  47. package/tests/client/for-selector.test.tsrx +95 -0
  48. package/tests/hydration/compiled/client/basic.js +97 -123
  49. package/tests/hydration/compiled/client/composite.js +5 -5
  50. package/tests/hydration/compiled/client/events.js +84 -79
  51. package/tests/hydration/compiled/client/for.js +229 -233
  52. package/tests/hydration/compiled/client/fragment-cursor.js +781 -481
  53. package/tests/hydration/compiled/client/head.js +23 -26
  54. package/tests/hydration/compiled/client/hmr.js +4 -4
  55. package/tests/hydration/compiled/client/html-in-template.js +5 -5
  56. package/tests/hydration/compiled/client/html.js +174 -208
  57. package/tests/hydration/compiled/client/if-children.js +71 -70
  58. package/tests/hydration/compiled/client/if-fragment-controlflow.js +46 -46
  59. package/tests/hydration/compiled/client/if.js +26 -26
  60. package/tests/hydration/compiled/client/mixed-control-flow.js +63 -105
  61. package/tests/hydration/compiled/client/nested-control-flow.js +170 -390
  62. package/tests/hydration/compiled/client/portal.js +10 -10
  63. package/tests/hydration/compiled/client/reactivity.js +36 -50
  64. package/tests/hydration/compiled/client/return.js +2 -2
  65. package/tests/hydration/compiled/client/streaming.js +34 -40
  66. package/tests/hydration/compiled/client/switch.js +25 -25
  67. package/tests/hydration/compiled/client/track-async-serialization.js +41 -41
  68. package/tests/hydration/compiled/client/try.js +15 -15
  69. package/tests/hydration/compiled/client/typed-text.js +8 -19
  70. package/tests/hydration/compiled/server/basic.js +6 -6
  71. package/tests/hydration/compiled/server/events.js +13 -61
  72. package/tests/hydration/compiled/server/for.js +23 -31
  73. package/tests/hydration/compiled/server/fragment-cursor.js +214 -366
  74. package/tests/hydration/compiled/server/head.js +6 -6
  75. package/tests/hydration/compiled/server/hmr.js +1 -1
  76. package/tests/hydration/compiled/server/html.js +1 -1
  77. package/tests/hydration/compiled/server/if-children.js +9 -9
  78. package/tests/hydration/compiled/server/if.js +5 -5
  79. package/tests/hydration/compiled/server/mixed-control-flow.js +4 -4
  80. package/tests/hydration/compiled/server/portal.js +1 -1
  81. package/tests/hydration/compiled/server/reactivity.js +9 -9
  82. package/tests/hydration/compiled/server/streaming.js +9 -9
  83. package/tests/hydration/compiled/server/switch.js +4 -4
  84. package/tests/hydration/compiled/server/track-async-serialization.js +16 -16
  85. package/tests/hydration/compiled/server/try.js +4 -4
  86. package/tests/hydration/compiled/server/typed-text.js +1 -1
  87. package/tests/hydration/components/fragment-cursor.tsrx +60 -0
  88. package/tests/hydration/components/track-async-serialization.tsrx +2 -2
  89. package/tests/hydration/fragment-cursor.test.js +34 -1
  90. package/tests/hydration/track-async-serialization.test.js +1 -1
  91. package/tests/server/basic.components.test.tsrx +3 -3
  92. package/tests/server/basic.test.tsrx +23 -0
  93. package/tests/server/track-async-serialization.test.tsrx +6 -6
  94. package/tests/utils/tracked-types.test.js +3 -3
  95. package/types/index.d.ts +8 -8
  96. package/types/server.d.ts +17 -0
@@ -0,0 +1,313 @@
1
+ /** @import { Block } from '#client' */
2
+
3
+ import { block, branch, destroy_block, ref } from './blocks.js';
4
+ import { DESTROYED, REF_PROP, RENDER_BLOCK } 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 {Record<string, (() => void) | undefined>} remove_listeners
124
+ * @param {Record<string | symbol, any>} prev
125
+ */
126
+ function set_attribute_helper(element, key, value, remove_listeners, prev) {
127
+ if (key === 'class') {
128
+ const is_html = element.namespaceURI === 'http://www.w3.org/1999/xhtml';
129
+ set_class_value(/** @type {HTMLElement} */ (element), value, undefined, is_html);
130
+ } else if (key === 'innerHTML') {
131
+ element.removeAttribute('innerhtml');
132
+ /** @type {HTMLElement} */ (element).innerHTML = value == null ? '' : String(value);
133
+ } else if (key === 'style') {
134
+ set_style(element, value, prev.style);
135
+ } else if (key === '#class') {
136
+ // Special case for the scope classes of an element that spreads props:
137
+ // one token per scope hash and applied theme.
138
+ element.classList.add(...String(value).split(' ').filter(Boolean));
139
+ } else if (typeof key === 'string' && is_event_attribute(key)) {
140
+ // Handle event handlers in spread props
141
+ if (remove_listeners[key]) {
142
+ remove_listeners[key]();
143
+ remove_listeners[key] = undefined;
144
+ }
145
+ if (value != null) {
146
+ const event_name = get_attribute_event_name(key, value);
147
+ remove_listeners[key] = event_listener(event_name, element, value);
148
+ }
149
+ } else {
150
+ set_attribute(element, key, value);
151
+ }
152
+ }
153
+
154
+ /**
155
+ * @param {Element} element
156
+ * @param {() => Record<string | symbol, any>} fn
157
+ * @returns {() => void}
158
+ */
159
+ export function apply_element_spread(element, fn) {
160
+ /** @type {Record<string | symbol, any>} */
161
+ var prev = {};
162
+ /** @type {Record<string | symbol, Block | undefined>} */
163
+ var effects = {};
164
+ /** @type {Record<string | symbol, (() => void) | undefined>} */
165
+ var remove_listeners = {};
166
+
167
+ /** @type {Record<symbol, any>} */
168
+ var prev_symbols = {};
169
+ /** @type {Record<string, any>} */
170
+ var prev_ref_props = {};
171
+
172
+ return () => {
173
+ var next = fn();
174
+ var current_symbols = /** @type {Record<symbol, any>} */ ({});
175
+
176
+ for (const symbol of get_own_property_symbols(next)) {
177
+ if (symbol.description !== REF_PROP) {
178
+ continue;
179
+ }
180
+ const ref_fn = next[symbol];
181
+ current_symbols[symbol] = ref_fn;
182
+
183
+ if (
184
+ !(symbol in prev_symbols) ||
185
+ ref_fn !== prev_symbols[symbol] ||
186
+ (effects[symbol] && (effects[symbol].f & DESTROYED) !== 0)
187
+ ) {
188
+ if (effects[symbol] && (effects[symbol].f & DESTROYED) === 0) {
189
+ destroy_block(effects[symbol]);
190
+ }
191
+ effects[symbol] = create_spread_ref_effect(element, ref_fn);
192
+ }
193
+ }
194
+
195
+ for (const symbol of get_own_property_symbols(prev_symbols)) {
196
+ if (!(symbol in current_symbols) && effects[symbol]) {
197
+ destroy_block(/** @type {Block} */ (effects[symbol]));
198
+ effects[symbol] = undefined;
199
+ }
200
+ }
201
+
202
+ prev_symbols = current_symbols;
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
+ }
213
+
214
+ current_ref_props[key] = ref_fn;
215
+
216
+ if (
217
+ !(key in prev_ref_props) ||
218
+ ref_fn !== prev_ref_props[key] ||
219
+ (effects[key] && (effects[key].f & DESTROYED) !== 0)
220
+ ) {
221
+ if (effects[key] && (effects[key].f & DESTROYED) === 0) {
222
+ destroy_block(effects[key]);
223
+ }
224
+ effects[key] = create_spread_ref_effect(element, ref_fn);
225
+ }
226
+ }
227
+
228
+ for (const key in prev_ref_props) {
229
+ if (!(key in current_ref_props) && effects[key]) {
230
+ destroy_block(/** @type {Block} */ (effects[key]));
231
+ effects[key] = undefined;
232
+ }
233
+ }
234
+
235
+ prev_ref_props = current_ref_props;
236
+
237
+ for (let key in remove_listeners) {
238
+ // Remove event listeners that are no longer present
239
+ if ((!keys.includes(key) || is_ref_prop(next[key])) && remove_listeners[key]) {
240
+ remove_listeners[key]();
241
+ remove_listeners[key] = undefined;
242
+ }
243
+ }
244
+
245
+ for (const key in prev) {
246
+ if (!keys.includes(key) || is_ref_prop(next[key])) {
247
+ if (key === '#class') {
248
+ continue;
249
+ }
250
+ set_attribute_helper(element, key, null, remove_listeners, prev);
251
+ }
252
+ }
253
+
254
+ /** @type {typeof prev} */
255
+ const current = {};
256
+ for (const key of keys) {
257
+ if (key === 'children') continue;
258
+
259
+ let value = next[key];
260
+ if (is_ref_prop(value)) {
261
+ continue;
262
+ }
263
+ if (is_ripple_object(value)) {
264
+ value = get(value);
265
+ }
266
+ current[key] = value;
267
+
268
+ if (key in prev && prev[key] === value && key !== '#class') {
269
+ continue;
270
+ }
271
+
272
+ set_attribute_helper(element, key, value, remove_listeners, prev);
273
+ }
274
+ prev = current;
275
+ };
276
+ }
277
+
278
+ /**
279
+ * The keys an element spread applies: every prop of a props instance, or the
280
+ * enumerable keys of a plain object.
281
+ * @param {Record<string | symbol, any>} next
282
+ * @returns {string[]}
283
+ */
284
+ function spread_keys(next) {
285
+ /** @type {string[]} */
286
+ var keys = [];
287
+ for (var key in next) keys.push(key);
288
+ return keys;
289
+ }
290
+
291
+ /**
292
+ * Keep spread refs in a branch block so ordinary spread updates do not destroy
293
+ * and recreate the ref block before `apply_element_spread` can compare the
294
+ * previous and current ref values.
295
+ *
296
+ * @param {Element} element
297
+ * @param {any} ref_fn
298
+ * @returns {Block}
299
+ */
300
+ function create_spread_ref_effect(element, ref_fn) {
301
+ return branch(() => {
302
+ ref(element, () => ref_fn);
303
+ });
304
+ }
305
+ /**
306
+ * A render block that applies a spread of attributes to an element.
307
+ * @param {any} element
308
+ * @param {any} fn
309
+ * @param {number} [flags]
310
+ */
311
+ export function render_spread(element, fn, flags = 0) {
312
+ return block(RENDER_BLOCK | flags, apply_element_spread(element, fn));
313
+ }
@@ -18,7 +18,6 @@ import {
18
18
  } from './constants.js';
19
19
  import { hydrating } from './hydration.js';
20
20
  import { next_sibling } from './operations.js';
21
- import { apply_element_spread } from './render.js';
22
21
  import { is_array } from '@tsrx/core/runtime/language-helpers';
23
22
  import {
24
23
  active_block,
@@ -34,15 +33,15 @@ import {
34
33
  untrack,
35
34
  } from './runtime.js';
36
35
  import { is_ripple_object } from './utils.js';
36
+ import { effect_orphan } from './errors.js';
37
+ import { HYDRATION } from 'ripple/internal/client/hydration-enabled';
37
38
 
38
39
  /**
39
40
  * @param {Function} fn
40
41
  */
41
42
  export function user_effect(fn) {
42
43
  if (active_block === null) {
43
- throw new Error(
44
- 'effect() must be called within an active context, such as a component or effect',
45
- );
44
+ effect_orphan();
46
45
  }
47
46
 
48
47
  var component = active_component;
@@ -85,15 +84,6 @@ export function render(fn, state, flags = 0) {
85
84
  return block;
86
85
  }
87
86
 
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
87
  /**
98
88
  * @param {Function} fn
99
89
  * @param {number} [flags]
@@ -117,7 +107,7 @@ function noop() {}
117
107
  * @param {Node} anchor
118
108
  */
119
109
  export function own_anchor(node, anchor) {
120
- if (anchor === node || hydrating) return;
110
+ if (anchor === node || (HYDRATION && hydrating)) return;
121
111
  branch(noop, 0, { start: anchor, end: anchor });
122
112
  }
123
113
 
@@ -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
- if (is_tsrx_element(value)) {
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
  }
@@ -1,13 +1,17 @@
1
1
  /** @import { Block } from '#client' */
2
+ import { component_invalid } from './errors.js';
2
3
 
3
- import { branch, destroy_block, render, render_spread } from './blocks.js';
4
+ import { branch, destroy_block, render } from './blocks.js';
5
+ import { render_spread } from './attributes.js';
4
6
  import { COMPOSITE_BLOCK, DEFAULT_NAMESPACE, NAMESPACE_URI } from './constants.js';
5
7
  import { hydrate_node, hydrate_next, hydrating, set_hydrate_node } from './hydration.js';
6
8
  import { first_child } from './operations.js';
7
9
  import { active_block, active_namespace, get, untrack, with_ns } from './runtime.js';
8
10
  import { top_element_to_ns } from './utils.js';
11
+ import { install_ns_templates } from './template-ns.js';
9
12
  import { is_tsrx_element } from '../../element.js';
10
13
  import { render_component } from './component.js';
14
+ import { HYDRATION } from 'ripple/internal/client/hydration-enabled';
11
15
 
12
16
  /**
13
17
  * @typedef {Function | string | null | undefined | false} CompositeTarget
@@ -19,7 +23,7 @@ import { render_component } from './component.js';
19
23
  * @returns {void}
20
24
  */
21
25
  export function composite(get_component, node, get_props) {
22
- if (hydrating) {
26
+ if (HYDRATION && hydrating) {
23
27
  // During hydration, `node` may already point at the first real SSR node
24
28
  // (e.g. layout children). Only skip forward when we are on an empty
25
29
  // comment anchor from a client template placeholder.
@@ -49,16 +53,20 @@ export function composite(get_component, node, get_props) {
49
53
  render_component(component, anchor, props);
50
54
  });
51
55
  } else if (is_tsrx_element(component)) {
52
- throw new TypeError('Invalid component type: received a TSRXElement value.');
56
+ component_invalid(true);
53
57
  } else if (component != null) {
54
58
  // Custom element - only create if component is not null/undefined
55
59
  const ns = top_element_to_ns(component, active_namespace);
60
+ if (ns !== DEFAULT_NAMESPACE) {
61
+ // Templates cloned inside the element parse in its namespace.
62
+ install_ns_templates();
63
+ }
56
64
  var run = () => {
57
65
  var block = /** @type {Block} */ (active_block);
58
66
 
59
67
  /** @type {Element} */
60
68
  var element;
61
- if (hydrating) {
69
+ if (HYDRATION && hydrating) {
62
70
  // Claim the SSR-rendered element instead of creating a new one.
63
71
  element = /** @type {Element} */ (hydrate_node);
64
72
  } else {
@@ -86,7 +94,7 @@ export function composite(get_component, node, get_props) {
86
94
  if (is_tsrx_element(props.children)) {
87
95
  /** @type {Node} */
88
96
  var child_anchor;
89
- if (hydrating) {
97
+ if (HYDRATION && hydrating) {
90
98
  // The server renders children directly inside the element with no
91
99
  // extra markers; descend the cursor so they claim those nodes.
92
100
  child_anchor = /** @type {Node} */ (first_child(element));
@@ -101,7 +109,7 @@ export function composite(get_component, node, get_props) {
101
109
  props.children.render(child_anchor, block, props.children.p);
102
110
  }
103
111
 
104
- if (hydrating) {
112
+ if (HYDRATION && hydrating) {
105
113
  // Reset the cursor to the claimed element so sibling traversal
106
114
  // continues after it.
107
115
  set_hydrate_node(element);
@@ -29,11 +29,17 @@ export var SELECTOR = 1 << 23;
29
29
  export var RELEASED = 1 << 24;
30
30
  /** A block whose latest run created deriveds that are recorded for release (see `release_deriveds`). */
31
31
  export var CREATES_DERIVEDS = 1 << 25;
32
+ /**
33
+ * A list item block that carries its body's render block itself (see the
34
+ * runtime's `item`): a branch block for its DOM range, and a reaction that
35
+ * re-runs the body's update function.
36
+ */
37
+ export var ITEM_BLOCK = 1 << 26;
32
38
 
33
39
  export var CONTROL_FLOW_BLOCK = FOR_BLOCK | IF_BLOCK | SWITCH_BLOCK | TRY_BLOCK | COMPOSITE_BLOCK;
34
40
 
35
41
  /** @type {unique symbol} */
36
- export const UNINITIALIZED = Symbol('uninitialized');
42
+ export const UNINITIALIZED = Symbol();
37
43
  /** @type {unique symbol} */
38
44
  export const TRACKED_ARRAY = Symbol();
39
45
  /** @type {unique symbol} */
@@ -52,13 +58,13 @@ export const NAMESPACE_URI = {
52
58
  mathml: 'http://www.w3.org/1998/Math/MathML',
53
59
  };
54
60
  /** @type {unique symbol} */
55
- export const TRACKED_UPDATED = Symbol('TRACKED_UPDATED');
61
+ export const TRACKED_UPDATED = Symbol();
56
62
  /** @type {unique symbol} */
57
- export const SUSPENSE_PENDING = Symbol('suspense_pending');
63
+ export const SUSPENSE_PENDING = Symbol();
58
64
  /** @type {unique symbol} */
59
- export const SUSPENSE_REJECTED = Symbol('suspense_rejected');
65
+ export const SUSPENSE_REJECTED = Symbol();
60
66
  /** @type {unique symbol} */
61
- export const ASYNC_DERIVED_READ_THROWN = Symbol('async_derived_read_thrown');
67
+ export const ASYNC_DERIVED_READ_THROWN = Symbol();
62
68
 
63
69
  /** The hoisted render function a module-level component carries (see `render_component`). */
64
- export const RENDER_ENTRY = Symbol('render');
70
+ export const RENDER_ENTRY = Symbol();
@@ -1,4 +1,5 @@
1
1
  /** @import { Component, ContextEntry } from '#client' */
2
+ import { context_orphan } from './errors.js';
2
3
 
3
4
  import { active_component } from './runtime.js';
4
5
 
@@ -18,7 +19,7 @@ export class Context {
18
19
  const component = active_component;
19
20
 
20
21
  if (component === null) {
21
- throw new Error('No active component found, cannot get context');
22
+ context_orphan(false);
22
23
  }
23
24
 
24
25
  // A component inherits its parent's chain of set entries when it is
@@ -45,7 +46,7 @@ export class Context {
45
46
  const component = active_component;
46
47
 
47
48
  if (component === null) {
48
- throw new Error('No active component found, cannot set context');
49
+ context_orphan(true);
49
50
  }
50
51
 
51
52
  component.c = { k: this, v: value, n: component.c };
@@ -24,49 +24,34 @@ function remove() {
24
24
  }
25
25
 
26
26
  /**
27
- * @param {function} callback
27
+ * Calls back once every stylesheet link has loaded (or failed).
28
+ * @param {() => void} callback
28
29
  * @returns {void}
29
30
  */
30
31
  function remove_when_css_loaded(callback) {
31
- /** @type {HTMLLinkElement[]} */
32
- const links = Array.from(
33
- /** @type {NodeListOf<HTMLLinkElement>} */ (
34
- document.querySelectorAll('link[rel="stylesheet"]')
35
- ),
32
+ var links = /** @type {NodeListOf<HTMLLinkElement>} */ (
33
+ document.querySelectorAll('link[rel="stylesheet"]')
36
34
  );
37
- let remaining = links.length;
35
+ var remaining = links.length;
38
36
 
39
37
  if (remaining === 0) {
40
38
  callback();
41
39
  return;
42
40
  }
43
41
 
44
- const done = () => {
45
- remaining--;
46
- if (remaining === 0) {
47
- // clean up all listeners
48
- links.forEach((link) => {
49
- link.removeEventListener('load', onLoad);
50
- link.removeEventListener('error', onError);
51
- });
42
+ var done = () => {
43
+ if (--remaining === 0) {
52
44
  callback();
53
45
  }
54
46
  };
55
47
 
56
- function onLoad() {
57
- done();
58
- }
59
- function onError() {
60
- done();
61
- }
62
-
63
- links.forEach((link) => {
48
+ for (var link of links) {
64
49
  if (link.sheet) {
65
50
  // already loaded (possibly cached)
66
51
  done();
67
52
  } else {
68
- link.addEventListener('load', onLoad);
69
- link.addEventListener('error', onError);
53
+ link.addEventListener('load', done, { once: true });
54
+ link.addEventListener('error', done, { once: true });
70
55
  }
71
- });
56
+ }
72
57
  }