ripple 0.3.8 → 0.3.10
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 +19 -0
- package/package.json +2 -2
- package/src/compiler/phases/1-parse/index.js +38 -172
- package/src/compiler/phases/2-analyze/index.js +308 -115
- package/src/compiler/phases/2-analyze/prune.js +13 -5
- package/src/compiler/phases/3-transform/client/index.js +197 -213
- package/src/compiler/phases/3-transform/segments.js +0 -7
- package/src/compiler/phases/3-transform/server/index.js +77 -170
- package/src/compiler/types/acorn.d.ts +1 -1
- package/src/compiler/types/estree.d.ts +1 -1
- package/src/compiler/types/import.d.ts +0 -2
- package/src/compiler/types/index.d.ts +14 -18
- package/src/compiler/types/parse.d.ts +3 -9
- package/src/compiler/utils.js +154 -21
- package/src/runtime/element.js +39 -0
- package/src/runtime/index-client.js +2 -13
- package/src/runtime/index-server.js +2 -2
- package/src/runtime/internal/client/bindings.js +3 -1
- package/src/runtime/internal/client/composite.js +11 -6
- package/src/runtime/internal/client/events.js +1 -1
- package/src/runtime/internal/client/expression.js +218 -0
- package/src/runtime/internal/client/head.js +3 -4
- package/src/runtime/internal/client/index.js +4 -1
- package/src/runtime/internal/client/portal.js +12 -6
- package/src/runtime/internal/client/runtime.js +0 -52
- package/src/runtime/internal/server/index.js +57 -56
- package/tests/client/basic/basic.components.test.ripple +85 -87
- package/tests/client/basic/basic.errors.test.ripple +28 -4
- package/tests/client/basic/basic.reactivity.test.ripple +10 -155
- package/tests/client/basic/basic.rendering.test.ripple +23 -8
- package/tests/client/capture-error.js +12 -0
- package/tests/client/compiler/compiler.basic.test.ripple +107 -18
- package/tests/client/composite/composite.props.test.ripple +5 -9
- package/tests/client/composite/composite.reactivity.test.ripple +35 -36
- package/tests/client/composite/composite.render.test.ripple +45 -13
- package/tests/client/css/global-additional-cases.test.ripple +3 -3
- package/tests/client/dynamic-elements.test.ripple +3 -4
- package/tests/client/lazy-destructuring.test.ripple +69 -12
- package/tests/client/svg.test.ripple +4 -4
- package/tests/hydration/basic.test.js +23 -0
- package/tests/hydration/compiled/client/basic.js +118 -66
- package/tests/hydration/compiled/client/composite.js +90 -37
- package/tests/hydration/compiled/client/events.js +18 -18
- package/tests/hydration/compiled/client/for.js +62 -62
- package/tests/hydration/compiled/client/head.js +10 -10
- package/tests/hydration/compiled/client/hmr.js +13 -10
- package/tests/hydration/compiled/client/html.js +274 -236
- package/tests/hydration/compiled/client/if-children.js +41 -35
- package/tests/hydration/compiled/client/if.js +2 -2
- package/tests/hydration/compiled/client/mixed-control-flow.js +12 -12
- package/tests/hydration/compiled/client/nested-control-flow.js +46 -46
- package/tests/hydration/compiled/client/portal.js +8 -8
- package/tests/hydration/compiled/client/reactivity.js +14 -14
- package/tests/hydration/compiled/client/return.js +2 -2
- package/tests/hydration/compiled/client/try.js +4 -4
- package/tests/hydration/compiled/server/basic.js +64 -31
- package/tests/hydration/compiled/server/composite.js +62 -29
- package/tests/hydration/compiled/server/hmr.js +24 -37
- package/tests/hydration/compiled/server/html.js +472 -611
- package/tests/hydration/compiled/server/if-children.js +77 -103
- package/tests/hydration/compiled/server/portal.js +8 -8
- package/tests/hydration/components/basic.ripple +15 -5
- package/tests/hydration/components/composite.ripple +13 -1
- package/tests/hydration/components/hmr.ripple +1 -3
- package/tests/hydration/components/html.ripple +13 -35
- package/tests/hydration/components/if-children.ripple +4 -8
- package/tests/hydration/composite.test.js +11 -0
- package/tests/server/basic.attributes.test.ripple +50 -0
- package/tests/server/basic.components.test.ripple +22 -28
- package/tests/server/basic.test.ripple +12 -0
- package/tests/server/compiler.test.ripple +43 -4
- package/tests/server/composite.props.test.ripple +5 -9
- package/tests/server/dynamic-elements.test.ripple +3 -4
- package/tests/server/lazy-destructuring.test.ripple +68 -12
- package/tests/server/style-identifier.test.ripple +2 -4
- package/tsconfig.typecheck.json +4 -0
- package/types/index.d.ts +9 -21
- package/tests/client/__snapshots__/tracked-expression.test.ripple.snap +0 -34
- package/tests/client/tracked-expression.test.ripple +0 -26
package/src/compiler/utils.js
CHANGED
|
@@ -292,25 +292,25 @@ export function is_component_level_function(context) {
|
|
|
292
292
|
* Returns the matched Ripple tracking call name
|
|
293
293
|
* @param {AST.Expression | AST.Super} callee
|
|
294
294
|
* @param {CommonContext} context
|
|
295
|
-
* @returns {'track' |
|
|
295
|
+
* @returns {'track' | null}
|
|
296
296
|
*/
|
|
297
297
|
export function is_ripple_track_call(callee, context) {
|
|
298
298
|
// Super expressions cannot be Ripple track calls
|
|
299
299
|
if (callee.type === 'Super') return null;
|
|
300
300
|
|
|
301
|
-
if (callee.type === 'Identifier' &&
|
|
302
|
-
return is_ripple_import(callee, context) ?
|
|
301
|
+
if (callee.type === 'Identifier' && callee.name === 'track') {
|
|
302
|
+
return is_ripple_import(callee, context) ? 'track' : null;
|
|
303
303
|
}
|
|
304
304
|
|
|
305
305
|
if (
|
|
306
306
|
callee.type === 'MemberExpression' &&
|
|
307
307
|
callee.object.type === 'Identifier' &&
|
|
308
308
|
callee.property.type === 'Identifier' &&
|
|
309
|
-
|
|
309
|
+
callee.property.name === 'track' &&
|
|
310
310
|
!callee.computed &&
|
|
311
311
|
is_ripple_import(callee, context)
|
|
312
312
|
) {
|
|
313
|
-
return
|
|
313
|
+
return 'track';
|
|
314
314
|
}
|
|
315
315
|
|
|
316
316
|
return null;
|
|
@@ -606,21 +606,8 @@ export function is_element_dynamic(node) {
|
|
|
606
606
|
* @returns {boolean}
|
|
607
607
|
*/
|
|
608
608
|
function is_id_dynamic(node) {
|
|
609
|
-
if (node.type === 'Identifier'
|
|
610
|
-
|
|
611
|
-
return true;
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
return false;
|
|
615
|
-
} else if (node.type === 'MemberExpression') {
|
|
616
|
-
if (/** @type {AST.Identifier} */ (node.object).tracked === true) {
|
|
617
|
-
return true;
|
|
618
|
-
}
|
|
619
|
-
if (node.property.type === 'MemberExpression') {
|
|
620
|
-
return is_id_dynamic(node.property);
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
return !!(/** @type {AST.Identifier} */ (node.property).tracked);
|
|
609
|
+
if (node.type === 'Identifier') {
|
|
610
|
+
return !!node.tracked;
|
|
624
611
|
}
|
|
625
612
|
|
|
626
613
|
return false;
|
|
@@ -644,7 +631,22 @@ export function normalize_children(children, context) {
|
|
|
644
631
|
const child = normalized[i];
|
|
645
632
|
const prev_child = normalized[i - 1];
|
|
646
633
|
|
|
647
|
-
if (
|
|
634
|
+
if (
|
|
635
|
+
(child.type === 'RippleExpression' || child.type === 'Text') &&
|
|
636
|
+
(prev_child?.type === 'RippleExpression' || prev_child?.type === 'Text')
|
|
637
|
+
) {
|
|
638
|
+
if (
|
|
639
|
+
(child.type === 'RippleExpression' &&
|
|
640
|
+
is_children_template_expression(child.expression, context.state.scope)) ||
|
|
641
|
+
(prev_child.type === 'RippleExpression' &&
|
|
642
|
+
is_children_template_expression(prev_child.expression, context.state.scope))
|
|
643
|
+
) {
|
|
644
|
+
continue;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
if (prev_child.type === 'Text' || child.type === 'Text') {
|
|
648
|
+
prev_child.type = 'Text';
|
|
649
|
+
}
|
|
648
650
|
if (child.expression.type === 'Literal' && prev_child.expression.type === 'Literal') {
|
|
649
651
|
prev_child.expression = b.literal(
|
|
650
652
|
prev_child.expression.value + String(child.expression.value),
|
|
@@ -663,6 +665,91 @@ export function normalize_children(children, context) {
|
|
|
663
665
|
return normalized;
|
|
664
666
|
}
|
|
665
667
|
|
|
668
|
+
/**
|
|
669
|
+
* @param {AST.Expression} expression
|
|
670
|
+
* @returns {AST.Expression}
|
|
671
|
+
*/
|
|
672
|
+
export function unwrap_template_expression(expression) {
|
|
673
|
+
/** @type {AST.Expression} */
|
|
674
|
+
let node = expression;
|
|
675
|
+
|
|
676
|
+
while (true) {
|
|
677
|
+
if (
|
|
678
|
+
node.type === 'ParenthesizedExpression' ||
|
|
679
|
+
node.type === 'TSAsExpression' ||
|
|
680
|
+
node.type === 'TSSatisfiesExpression' ||
|
|
681
|
+
node.type === 'TSNonNullExpression' ||
|
|
682
|
+
node.type === 'TSInstantiationExpression'
|
|
683
|
+
) {
|
|
684
|
+
node = /** @type {AST.Expression} */ (node.expression);
|
|
685
|
+
continue;
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
if (node.type === 'ChainExpression') {
|
|
689
|
+
node = /** @type {AST.Expression} */ (node.expression);
|
|
690
|
+
continue;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
break;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
return node;
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* @param {AST.Expression} expression
|
|
701
|
+
* @param {ScopeInterface | null | undefined} scope
|
|
702
|
+
* @param {ScopeInterface | null} [component_scope]
|
|
703
|
+
* @returns {boolean}
|
|
704
|
+
*/
|
|
705
|
+
export function is_children_template_expression(expression, scope, component_scope = null) {
|
|
706
|
+
if (scope == null) {
|
|
707
|
+
return false;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
const unwrapped = unwrap_template_expression(expression);
|
|
711
|
+
|
|
712
|
+
if (unwrapped.type === 'MemberExpression') {
|
|
713
|
+
let property_name = null;
|
|
714
|
+
|
|
715
|
+
if (!unwrapped.computed && unwrapped.property.type === 'Identifier') {
|
|
716
|
+
property_name = unwrapped.property.name;
|
|
717
|
+
} else if (
|
|
718
|
+
unwrapped.computed &&
|
|
719
|
+
unwrapped.property.type === 'Literal' &&
|
|
720
|
+
typeof unwrapped.property.value === 'string'
|
|
721
|
+
) {
|
|
722
|
+
property_name = unwrapped.property.value;
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
if (property_name === 'children') {
|
|
726
|
+
const target = unwrap_template_expression(/** @type {AST.Expression} */ (unwrapped.object));
|
|
727
|
+
|
|
728
|
+
if (target.type === 'Identifier') {
|
|
729
|
+
const binding = scope.get(target.name);
|
|
730
|
+
return (
|
|
731
|
+
binding?.declaration_kind === 'param' &&
|
|
732
|
+
(component_scope === null || binding.scope === component_scope)
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
if (unwrapped.type !== 'Identifier' || unwrapped.name !== 'children') {
|
|
739
|
+
return false;
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
const binding = scope.get(unwrapped.name);
|
|
743
|
+
return (
|
|
744
|
+
(binding?.declaration_kind === 'param' ||
|
|
745
|
+
binding?.kind === 'prop' ||
|
|
746
|
+
binding?.kind === 'prop_fallback' ||
|
|
747
|
+
binding?.kind === 'lazy' ||
|
|
748
|
+
binding?.kind === 'lazy_fallback') &&
|
|
749
|
+
(component_scope === null || binding.scope === component_scope)
|
|
750
|
+
);
|
|
751
|
+
}
|
|
752
|
+
|
|
666
753
|
/**
|
|
667
754
|
* @param {AST.Node} node
|
|
668
755
|
* @param {AST.Node[]} normalized
|
|
@@ -686,6 +773,52 @@ function normalize_child(node, normalized, context) {
|
|
|
686
773
|
}
|
|
687
774
|
}
|
|
688
775
|
|
|
776
|
+
/**
|
|
777
|
+
* Replaces any lazy subpatterns in a parameter pattern with their generated identifiers.
|
|
778
|
+
* This is used by client and server transforms so nested lazy destructuring can coexist
|
|
779
|
+
* with otherwise normal object/array params.
|
|
780
|
+
* @param {AST.Pattern} pattern
|
|
781
|
+
* @returns {AST.Pattern}
|
|
782
|
+
*/
|
|
783
|
+
export function replace_lazy_param_pattern(pattern) {
|
|
784
|
+
switch (pattern.type) {
|
|
785
|
+
case 'AssignmentPattern':
|
|
786
|
+
return { ...pattern, left: replace_lazy_param_pattern(pattern.left) };
|
|
787
|
+
|
|
788
|
+
case 'ObjectPattern':
|
|
789
|
+
if (pattern.lazy && pattern.metadata?.lazy_id) {
|
|
790
|
+
return /** @type {AST.Pattern} */ (b.id(pattern.metadata.lazy_id));
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
return {
|
|
794
|
+
...pattern,
|
|
795
|
+
properties: pattern.properties.map((property) =>
|
|
796
|
+
property.type === 'RestElement'
|
|
797
|
+
? { ...property, argument: replace_lazy_param_pattern(property.argument) }
|
|
798
|
+
: { ...property, value: replace_lazy_param_pattern(property.value) },
|
|
799
|
+
),
|
|
800
|
+
};
|
|
801
|
+
|
|
802
|
+
case 'ArrayPattern':
|
|
803
|
+
if (pattern.lazy && pattern.metadata?.lazy_id) {
|
|
804
|
+
return /** @type {AST.Pattern} */ (b.id(pattern.metadata.lazy_id));
|
|
805
|
+
}
|
|
806
|
+
|
|
807
|
+
return {
|
|
808
|
+
...pattern,
|
|
809
|
+
elements: pattern.elements.map((element) =>
|
|
810
|
+
element === null ? null : replace_lazy_param_pattern(element),
|
|
811
|
+
),
|
|
812
|
+
};
|
|
813
|
+
|
|
814
|
+
case 'RestElement':
|
|
815
|
+
return { ...pattern, argument: replace_lazy_param_pattern(pattern.argument) };
|
|
816
|
+
|
|
817
|
+
default:
|
|
818
|
+
return pattern;
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
|
|
689
822
|
/**
|
|
690
823
|
* @param {CommonContext} context
|
|
691
824
|
*/
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
const RIPPLE_ELEMENT = Symbol.for('ripple.element');
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {{
|
|
5
|
+
* render: Function;
|
|
6
|
+
* [RIPPLE_ELEMENT]: true;
|
|
7
|
+
* }} RippleElement
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* @param {Function} render
|
|
12
|
+
* @returns {RippleElement}
|
|
13
|
+
*/
|
|
14
|
+
export function ripple_element(render) {
|
|
15
|
+
return {
|
|
16
|
+
render,
|
|
17
|
+
[RIPPLE_ELEMENT]: true,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* @param {any} value
|
|
23
|
+
* @returns {value is RippleElement}
|
|
24
|
+
*/
|
|
25
|
+
export function is_ripple_element(value) {
|
|
26
|
+
return value != null && value[RIPPLE_ELEMENT] === true;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {any} value
|
|
31
|
+
* @returns {any}
|
|
32
|
+
*/
|
|
33
|
+
export function normalize_children(value) {
|
|
34
|
+
if (value == null || is_ripple_element(value) || typeof value !== 'function') {
|
|
35
|
+
return value;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
return ripple_element(value);
|
|
39
|
+
}
|
|
@@ -102,13 +102,7 @@ export function hydrate(component, options) {
|
|
|
102
102
|
|
|
103
103
|
export { Context } from './internal/client/context.js';
|
|
104
104
|
|
|
105
|
-
export {
|
|
106
|
-
flush_sync as flushSync,
|
|
107
|
-
track,
|
|
108
|
-
track_split as trackSplit,
|
|
109
|
-
untrack,
|
|
110
|
-
tick,
|
|
111
|
-
} from './internal/client/runtime.js';
|
|
105
|
+
export { flush_sync as flushSync, track, untrack, tick } from './internal/client/runtime.js';
|
|
112
106
|
|
|
113
107
|
export { RippleArray } from './array.js';
|
|
114
108
|
|
|
@@ -165,10 +159,5 @@ import { RippleURL } from './url.js';
|
|
|
165
159
|
import { RippleURLSearchParams } from './url-search-params.js';
|
|
166
160
|
import { RippleDate } from './date.js';
|
|
167
161
|
import { MediaQuery } from './media-query.js';
|
|
168
|
-
import {
|
|
169
|
-
track,
|
|
170
|
-
track_split as trackSplit,
|
|
171
|
-
untrack,
|
|
172
|
-
ref_prop as createRefKey,
|
|
173
|
-
} from './internal/client/runtime.js';
|
|
162
|
+
import { track, untrack, ref_prop as createRefKey } from './internal/client/runtime.js';
|
|
174
163
|
import { user_effect as effect } from './internal/client/blocks.js';
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { get, set, untrack, track
|
|
1
|
+
import { get, set, untrack, track } from './internal/server/index.js';
|
|
2
2
|
|
|
3
3
|
export { Context } from './internal/server/context.js';
|
|
4
4
|
|
|
5
|
-
export { get, set, untrack, track
|
|
5
|
+
export { get, set, untrack, track };
|
|
6
6
|
|
|
7
7
|
function noop() {}
|
|
8
8
|
|
|
@@ -186,7 +186,9 @@ function select_option(select, value, mounting = false) {
|
|
|
186
186
|
|
|
187
187
|
// Otherwise, update the selection
|
|
188
188
|
for (var option of select.options) {
|
|
189
|
-
option.selected = /** @type {string[]} */ (value).includes(
|
|
189
|
+
option.selected = /** @type {string[]} */ (value).includes(
|
|
190
|
+
/** @type {string} */ (get_option_value(option)),
|
|
191
|
+
);
|
|
190
192
|
}
|
|
191
193
|
|
|
192
194
|
return;
|
|
@@ -5,6 +5,7 @@ import { COMPOSITE_BLOCK, DEFAULT_NAMESPACE, NAMESPACE_URI } from './constants.j
|
|
|
5
5
|
import { hydrate_next, hydrating } from './hydration.js';
|
|
6
6
|
import { active_block, active_namespace, get, with_ns } from './runtime.js';
|
|
7
7
|
import { top_element_to_ns } from './utils.js';
|
|
8
|
+
import { is_ripple_element } from '../../element.js';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* @typedef {((anchor: Node, props: Record<string, any>, block: Block | null) => void)} ComponentFunction
|
|
@@ -29,6 +30,7 @@ export function composite(get_component, node, props) {
|
|
|
29
30
|
|
|
30
31
|
render(
|
|
31
32
|
() => {
|
|
33
|
+
// @ts-ignore — get() handles non-tracked values via is_ripple_object() check
|
|
32
34
|
var component = get(get_component());
|
|
33
35
|
|
|
34
36
|
if (b !== null) {
|
|
@@ -44,13 +46,14 @@ export function composite(get_component, node, props) {
|
|
|
44
46
|
});
|
|
45
47
|
} else if (component != null) {
|
|
46
48
|
// Custom element - only create if component is not null/undefined
|
|
49
|
+
const ns = top_element_to_ns(component, active_namespace);
|
|
47
50
|
var run = () => {
|
|
48
51
|
var block = /** @type {Block} */ (active_block);
|
|
49
52
|
|
|
50
53
|
var element =
|
|
51
|
-
|
|
54
|
+
ns !== DEFAULT_NAMESPACE
|
|
52
55
|
? document.createElementNS(
|
|
53
|
-
NAMESPACE_URI[
|
|
56
|
+
NAMESPACE_URI[ns],
|
|
54
57
|
/** @type {keyof HTMLElementTagNameMap} */ (component),
|
|
55
58
|
)
|
|
56
59
|
: document.createElement(/** @type {keyof HTMLElementTagNameMap} */ (component));
|
|
@@ -66,16 +69,18 @@ export function composite(get_component, node, props) {
|
|
|
66
69
|
|
|
67
70
|
render_spread(element, () => props || {});
|
|
68
71
|
|
|
69
|
-
if (
|
|
72
|
+
if (is_ripple_element(props?.children)) {
|
|
70
73
|
var child_anchor = document.createComment('');
|
|
71
74
|
element.appendChild(child_anchor);
|
|
72
75
|
|
|
73
|
-
|
|
76
|
+
if (ns !== DEFAULT_NAMESPACE) {
|
|
77
|
+
with_ns(ns, () => props.children.render(child_anchor, {}, block));
|
|
78
|
+
} else {
|
|
79
|
+
props.children.render(child_anchor, {}, block);
|
|
80
|
+
}
|
|
74
81
|
}
|
|
75
82
|
};
|
|
76
83
|
|
|
77
|
-
const ns = top_element_to_ns(component, active_namespace);
|
|
78
|
-
|
|
79
84
|
if (ns !== active_namespace) {
|
|
80
85
|
// support top-level dynamic element svg/math <@tag />
|
|
81
86
|
b = branch(() => with_ns(ns, run));
|
|
@@ -168,7 +168,7 @@ export function handle_event_propagation(event) {
|
|
|
168
168
|
null;
|
|
169
169
|
|
|
170
170
|
try {
|
|
171
|
-
var delegated = current_target['__' + event_name];
|
|
171
|
+
var delegated = /** @type {Record<string, any>} */ (current_target)['__' + event_name];
|
|
172
172
|
|
|
173
173
|
if (delegated !== undefined && !(/** @type {any} */ (current_target).disabled)) {
|
|
174
174
|
if (is_array(delegated)) {
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
/** @import { Block } from '#client' */
|
|
2
|
+
|
|
3
|
+
import { branch, destroy_block, render } from './blocks.js';
|
|
4
|
+
import { UNINITIALIZED } from './constants.js';
|
|
5
|
+
import { create_text, get_next_sibling } from './operations.js';
|
|
6
|
+
import { active_block } from './runtime.js';
|
|
7
|
+
import { hydrating, set_hydrate_node } from './hydration.js';
|
|
8
|
+
import { COMMENT_NODE, HYDRATION_END, HYDRATION_START, TEXT_NODE } from '../../../constants.js';
|
|
9
|
+
import { is_ripple_element } from '../../element.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {Node} node
|
|
13
|
+
* @param {() => any} get_value
|
|
14
|
+
* @returns {void}
|
|
15
|
+
*/
|
|
16
|
+
export function expression(node, get_value) {
|
|
17
|
+
var anchor = /** @type {ChildNode} */ (node);
|
|
18
|
+
/** @type {Block | null} */
|
|
19
|
+
var child_block = null;
|
|
20
|
+
/** @type {Comment | null} */
|
|
21
|
+
var end = null;
|
|
22
|
+
/** @type {Text | null} */
|
|
23
|
+
var text = null;
|
|
24
|
+
/** @type {string | import('../../element.js').RippleElement | typeof UNINITIALIZED} */
|
|
25
|
+
var value = UNINITIALIZED;
|
|
26
|
+
var is_element = false;
|
|
27
|
+
var initialized = false;
|
|
28
|
+
|
|
29
|
+
render(() => {
|
|
30
|
+
var next_value = get_value();
|
|
31
|
+
var next_is_element = is_ripple_element(next_value);
|
|
32
|
+
var is_hydration_marker = hydrating && anchor.nodeType === COMMENT_NODE;
|
|
33
|
+
|
|
34
|
+
if (is_hydration_marker) {
|
|
35
|
+
end ??= ensure_expression_end(anchor);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (next_is_element) {
|
|
39
|
+
if (initialized && is_element && value === next_value) {
|
|
40
|
+
if (end !== null) {
|
|
41
|
+
advance_hydration(end);
|
|
42
|
+
}
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (anchor.nodeType === TEXT_NODE) {
|
|
47
|
+
/** @type {Text} */ (anchor).nodeValue = '';
|
|
48
|
+
} else if (text !== null) {
|
|
49
|
+
text.remove();
|
|
50
|
+
text = null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (child_block !== null) {
|
|
54
|
+
destroy_block(child_block);
|
|
55
|
+
child_block = null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (end !== null && (initialized || !hydrating)) {
|
|
59
|
+
clear_expression_range(anchor, end);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (is_hydration_marker) {
|
|
63
|
+
set_hydrate_node(get_next_sibling(anchor) ?? end);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
child_block = branch(() => {
|
|
67
|
+
var block = active_block;
|
|
68
|
+
next_value.render(end ?? anchor, {}, block);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
value = next_value;
|
|
72
|
+
is_element = true;
|
|
73
|
+
initialized = true;
|
|
74
|
+
if (end !== null) {
|
|
75
|
+
advance_hydration(end);
|
|
76
|
+
}
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
var next_text = (next_value ?? '') + '';
|
|
81
|
+
|
|
82
|
+
if (initialized && !is_element && value === next_text) {
|
|
83
|
+
if (end !== null) {
|
|
84
|
+
advance_hydration(end);
|
|
85
|
+
}
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (child_block !== null) {
|
|
90
|
+
destroy_block(child_block);
|
|
91
|
+
child_block = null;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (is_hydration_marker) {
|
|
95
|
+
text = get_hydrated_text(anchor, /** @type {Comment} */ (end));
|
|
96
|
+
|
|
97
|
+
if (next_text === '') {
|
|
98
|
+
if (text !== null) {
|
|
99
|
+
text.remove();
|
|
100
|
+
text = null;
|
|
101
|
+
}
|
|
102
|
+
} else if (text === null) {
|
|
103
|
+
text = create_text(next_text);
|
|
104
|
+
/** @type {Comment} */ (end).before(text);
|
|
105
|
+
} else if (text.nodeValue !== next_text) {
|
|
106
|
+
text.nodeValue = next_text;
|
|
107
|
+
}
|
|
108
|
+
} else if (anchor.nodeType === COMMENT_NODE) {
|
|
109
|
+
if (next_text === '') {
|
|
110
|
+
if (text !== null) {
|
|
111
|
+
text.remove();
|
|
112
|
+
text = null;
|
|
113
|
+
}
|
|
114
|
+
} else if (text === null) {
|
|
115
|
+
text = create_text(next_text);
|
|
116
|
+
(end ?? anchor).before(text);
|
|
117
|
+
} else if (text.nodeValue !== next_text) {
|
|
118
|
+
text.nodeValue = next_text;
|
|
119
|
+
}
|
|
120
|
+
} else if (anchor.nodeType === TEXT_NODE) {
|
|
121
|
+
/** @type {Text} */ (anchor).nodeValue = next_text;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
value = next_text;
|
|
125
|
+
is_element = false;
|
|
126
|
+
initialized = true;
|
|
127
|
+
if (end !== null) {
|
|
128
|
+
advance_hydration(end);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* @param {Node} anchor
|
|
135
|
+
* @returns {Comment}
|
|
136
|
+
*/
|
|
137
|
+
function ensure_expression_end(anchor) {
|
|
138
|
+
if (hydrating) {
|
|
139
|
+
/** @type {Node | null} */
|
|
140
|
+
var current = get_next_sibling(anchor);
|
|
141
|
+
var depth = 0;
|
|
142
|
+
|
|
143
|
+
while (current !== null) {
|
|
144
|
+
if (current.nodeType === COMMENT_NODE) {
|
|
145
|
+
var data = /** @type {Comment} */ (current).data;
|
|
146
|
+
|
|
147
|
+
if (data === HYDRATION_START) {
|
|
148
|
+
depth += 1;
|
|
149
|
+
} else if (data === HYDRATION_END) {
|
|
150
|
+
if (depth === 0) {
|
|
151
|
+
return /** @type {Comment} */ (current);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
depth -= 1;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
current = get_next_sibling(current);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
throw new Error('Hydration mismatch: expected end marker for expression block');
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
var end = document.createComment(HYDRATION_END);
|
|
165
|
+
/** @type {ChildNode} */ (anchor).after(end);
|
|
166
|
+
return end;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* @param {Node} anchor
|
|
171
|
+
* @param {Node} end
|
|
172
|
+
* @returns {Text | null}
|
|
173
|
+
*/
|
|
174
|
+
function get_hydrated_text(anchor, end) {
|
|
175
|
+
var first = get_next_sibling(anchor);
|
|
176
|
+
|
|
177
|
+
if (first === end) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
if (first?.nodeType === TEXT_NODE && get_next_sibling(first) === end) {
|
|
182
|
+
return /** @type {Text} */ (first);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
clear_expression_range(anchor, end);
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* @param {Node} anchor
|
|
191
|
+
* @param {Node} end
|
|
192
|
+
* @returns {void}
|
|
193
|
+
*/
|
|
194
|
+
function clear_expression_range(anchor, end) {
|
|
195
|
+
var current = get_next_sibling(anchor);
|
|
196
|
+
|
|
197
|
+
while (current !== null && current !== end) {
|
|
198
|
+
var next = get_next_sibling(current);
|
|
199
|
+
/** @type {ChildNode} */ (current).remove();
|
|
200
|
+
current = next;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* @param {Comment} end
|
|
206
|
+
* @returns {void}
|
|
207
|
+
*/
|
|
208
|
+
function advance_hydration(end) {
|
|
209
|
+
if (!hydrating) {
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
var next = get_next_sibling(end);
|
|
214
|
+
|
|
215
|
+
if (next !== null) {
|
|
216
|
+
set_hydrate_node(next);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
/** @import { TemplateNode } from '#client' */
|
|
2
1
|
import { render } from './blocks.js';
|
|
3
2
|
import { HEAD_BLOCK } from './constants.js';
|
|
4
3
|
import { COMMENT_NODE } from '../../../constants.js';
|
|
@@ -38,8 +37,8 @@ export function head(hash, render_fn) {
|
|
|
38
37
|
if (head_anchor === null) {
|
|
39
38
|
set_hydrating(false);
|
|
40
39
|
} else {
|
|
41
|
-
var start =
|
|
42
|
-
head_anchor.remove(); // in case this component is repeated
|
|
40
|
+
var start = get_next_sibling(head_anchor);
|
|
41
|
+
/** @type {ChildNode} */ (head_anchor).remove(); // in case this component is repeated
|
|
43
42
|
|
|
44
43
|
set_hydrate_node(start);
|
|
45
44
|
}
|
|
@@ -54,7 +53,7 @@ export function head(hash, render_fn) {
|
|
|
54
53
|
} finally {
|
|
55
54
|
if (was_hydrating) {
|
|
56
55
|
set_hydrating(true);
|
|
57
|
-
set_hydrate_node(
|
|
56
|
+
set_hydrate_node(previous_hydrate_node);
|
|
58
57
|
}
|
|
59
58
|
}
|
|
60
59
|
}
|
|
@@ -52,7 +52,6 @@ export {
|
|
|
52
52
|
update_property,
|
|
53
53
|
update_pre_property,
|
|
54
54
|
track,
|
|
55
|
-
track_split,
|
|
56
55
|
push_component,
|
|
57
56
|
pop_component,
|
|
58
57
|
untrack,
|
|
@@ -106,6 +105,8 @@ export { script } from './script.js';
|
|
|
106
105
|
|
|
107
106
|
export { html } from './html.js';
|
|
108
107
|
|
|
108
|
+
export { expression } from './expression.js';
|
|
109
|
+
|
|
109
110
|
export { rpc } from './rpc.js';
|
|
110
111
|
|
|
111
112
|
export { tsx_compat } from './compat.js';
|
|
@@ -115,3 +116,5 @@ export { TRY_BLOCK, HMR } from './constants.js';
|
|
|
115
116
|
export { hmr } from './hmr.js';
|
|
116
117
|
|
|
117
118
|
export { pop, next } from './hydration.js';
|
|
119
|
+
|
|
120
|
+
export { ripple_element, normalize_children } from '../../element.js';
|
|
@@ -12,10 +12,11 @@ import {
|
|
|
12
12
|
set_hydrating,
|
|
13
13
|
set_hydrate_node,
|
|
14
14
|
} from './hydration.js';
|
|
15
|
+
import { is_ripple_element } from '../../element.js';
|
|
15
16
|
|
|
16
17
|
/**
|
|
17
18
|
* @param {any} _
|
|
18
|
-
* @param {{ target: Element, children: (
|
|
19
|
+
* @param {{ target: Element, children: import('../../element.js').RippleElement }} props
|
|
19
20
|
* @returns {void}
|
|
20
21
|
*/
|
|
21
22
|
export function Portal(_, props) {
|
|
@@ -26,7 +27,7 @@ export function Portal(_, props) {
|
|
|
26
27
|
|
|
27
28
|
/** @type {Element | symbol} */
|
|
28
29
|
let target = UNINITIALIZED;
|
|
29
|
-
/** @type {(
|
|
30
|
+
/** @type {import('../../element.js').RippleElement | symbol} */
|
|
30
31
|
let children = UNINITIALIZED;
|
|
31
32
|
/** @type {Block | null} */
|
|
32
33
|
var b = null;
|
|
@@ -44,8 +45,13 @@ export function Portal(_, props) {
|
|
|
44
45
|
|
|
45
46
|
try {
|
|
46
47
|
render(() => {
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
const next_target = props.target;
|
|
49
|
+
const next_children = props.children;
|
|
50
|
+
|
|
51
|
+
if (target === next_target && children === next_children) return;
|
|
52
|
+
|
|
53
|
+
target = next_target;
|
|
54
|
+
children = next_children;
|
|
49
55
|
|
|
50
56
|
if (b !== null) {
|
|
51
57
|
destroy_block(b);
|
|
@@ -65,8 +71,8 @@ export function Portal(_, props) {
|
|
|
65
71
|
var block = /** @type {Block} */ (active_block);
|
|
66
72
|
|
|
67
73
|
b = branch(() => {
|
|
68
|
-
if (
|
|
69
|
-
children(/** @type {Text} */ (anchor), {}, block);
|
|
74
|
+
if (is_ripple_element(children)) {
|
|
75
|
+
children.render(/** @type {Text} */ (anchor), {}, block);
|
|
70
76
|
}
|
|
71
77
|
});
|
|
72
78
|
|