ripple 0.2.105 → 0.2.107
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/package.json +1 -1
- package/src/compiler/phases/1-parse/index.js +18 -4
- package/src/compiler/phases/2-analyze/index.js +45 -4
- package/src/compiler/phases/3-transform/client/index.js +87 -12
- package/src/runtime/create-subscriber.js +34 -0
- package/src/runtime/index-client.js +8 -0
- package/src/runtime/index-server.js +27 -2
- package/src/runtime/internal/client/constants.js +13 -12
- package/src/runtime/internal/client/index.js +2 -0
- package/src/runtime/internal/client/runtime.js +19 -19
- package/src/runtime/internal/client/switch.js +32 -0
- package/src/runtime/media-query.js +39 -0
- package/src/runtime/reactive-value.js +21 -0
- package/src/runtime/url-search-params.js +147 -0
- package/src/runtime/url.js +164 -0
- package/src/utils/builders.js +33 -0
- package/tests/client/__snapshots__/compiler.test.ripple.snap +12 -0
- package/tests/client/basic.test.ripple +46 -1
- package/tests/client/compiler.test.ripple +33 -0
- package/tests/client/media-query.test.ripple +130 -0
- package/tests/client/url-search-params.test.ripple +912 -0
- package/tests/client/url.test.ripple +954 -0
- package/types/index.d.ts +41 -11
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.2.
|
|
6
|
+
"version": "0.2.107",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"module": "src/runtime/index-client.js",
|
|
9
9
|
"main": "src/runtime/index-client.js",
|
|
@@ -170,13 +170,14 @@ function RipplePlugin(config) {
|
|
|
170
170
|
// Look ahead to see if this is followed by a valid identifier character or opening paren
|
|
171
171
|
if (this.pos + 1 < this.input.length) {
|
|
172
172
|
const nextChar = this.input.charCodeAt(this.pos + 1);
|
|
173
|
-
|
|
173
|
+
|
|
174
174
|
// Check if this is @( for unboxing expression syntax
|
|
175
|
-
if (nextChar === 40) {
|
|
175
|
+
if (nextChar === 40) {
|
|
176
|
+
// ( character
|
|
176
177
|
this.pos += 2; // skip '@('
|
|
177
178
|
return this.finishToken(tt.parenL, '@(');
|
|
178
179
|
}
|
|
179
|
-
|
|
180
|
+
|
|
180
181
|
// Check if the next character can start an identifier
|
|
181
182
|
if (
|
|
182
183
|
(nextChar >= 65 && nextChar <= 90) || // A-Z
|
|
@@ -359,7 +360,7 @@ function RipplePlugin(config) {
|
|
|
359
360
|
if (this.type === tt.parenL && this.value === '@(') {
|
|
360
361
|
return this.parseTrackedExpression();
|
|
361
362
|
}
|
|
362
|
-
|
|
363
|
+
|
|
363
364
|
// Check if this is a tuple literal starting with #[
|
|
364
365
|
if (this.type === tt.bracketL && this.value === '#[') {
|
|
365
366
|
return this.parseTrackedArrayExpression();
|
|
@@ -1319,6 +1320,19 @@ function RipplePlugin(config) {
|
|
|
1319
1320
|
}
|
|
1320
1321
|
}
|
|
1321
1322
|
|
|
1323
|
+
if (this.type.label === 'jsxTagStart') {
|
|
1324
|
+
this.next();
|
|
1325
|
+
if (this.value === '/') {
|
|
1326
|
+
this.unexpected();
|
|
1327
|
+
}
|
|
1328
|
+
const node = this.parseElement();
|
|
1329
|
+
|
|
1330
|
+
if (!node) {
|
|
1331
|
+
this.unexpected();
|
|
1332
|
+
}
|
|
1333
|
+
return node;
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1322
1336
|
return super.parseStatement(context, topLevel, exports);
|
|
1323
1337
|
}
|
|
1324
1338
|
|
|
@@ -34,7 +34,8 @@ function mark_control_flow_has_template(path) {
|
|
|
34
34
|
node.type === 'ForInStatement' ||
|
|
35
35
|
node.type === 'ForOfStatement' ||
|
|
36
36
|
node.type === 'TryStatement' ||
|
|
37
|
-
node.type === 'IfStatement'
|
|
37
|
+
node.type === 'IfStatement' ||
|
|
38
|
+
node.type === 'SwitchStatement'
|
|
38
39
|
) {
|
|
39
40
|
node.metadata.has_template = true;
|
|
40
41
|
}
|
|
@@ -106,7 +107,7 @@ const visitors = {
|
|
|
106
107
|
}
|
|
107
108
|
|
|
108
109
|
if (
|
|
109
|
-
is_reference(node, /** @type {Node} */(parent)) &&
|
|
110
|
+
is_reference(node, /** @type {Node} */ (parent)) &&
|
|
110
111
|
node.tracked &&
|
|
111
112
|
binding?.node !== node
|
|
112
113
|
) {
|
|
@@ -117,7 +118,7 @@ const visitors = {
|
|
|
117
118
|
}
|
|
118
119
|
|
|
119
120
|
if (
|
|
120
|
-
is_reference(node, /** @type {Node} */(parent)) &&
|
|
121
|
+
is_reference(node, /** @type {Node} */ (parent)) &&
|
|
121
122
|
node.tracked &&
|
|
122
123
|
binding?.node !== node
|
|
123
124
|
) {
|
|
@@ -253,7 +254,12 @@ const visitors = {
|
|
|
253
254
|
// Track metadata for this component
|
|
254
255
|
const metadata = { await: false };
|
|
255
256
|
|
|
256
|
-
context.next({
|
|
257
|
+
context.next({
|
|
258
|
+
...context.state,
|
|
259
|
+
elements,
|
|
260
|
+
function_depth: context.state.function_depth + 1,
|
|
261
|
+
metadata,
|
|
262
|
+
});
|
|
257
263
|
|
|
258
264
|
const css = node.css;
|
|
259
265
|
|
|
@@ -282,6 +288,41 @@ const visitors = {
|
|
|
282
288
|
context.next();
|
|
283
289
|
},
|
|
284
290
|
|
|
291
|
+
SwitchStatement(node, context) {
|
|
292
|
+
if (!is_inside_component(context)) {
|
|
293
|
+
return context.next();
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
context.visit(node.discriminant, context.state);
|
|
297
|
+
|
|
298
|
+
for (const switch_case of node.cases) {
|
|
299
|
+
// Validate that each cases ends in a break statement, except for the last case
|
|
300
|
+
const last = switch_case.consequent?.[switch_case.consequent.length - 1];
|
|
301
|
+
|
|
302
|
+
if (last.type !== 'BreakStatement' && node.cases.indexOf(switch_case) !== node.cases.length - 1) {
|
|
303
|
+
error(
|
|
304
|
+
'Template switch cases must end with a break statement (with the exception of the last case).',
|
|
305
|
+
context.state.analysis.module.filename,
|
|
306
|
+
switch_case,
|
|
307
|
+
);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
node.metadata = {
|
|
311
|
+
has_template: false,
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
context.visit(switch_case, context.state);
|
|
315
|
+
|
|
316
|
+
if (!node.metadata.has_template) {
|
|
317
|
+
error(
|
|
318
|
+
'Component switch statements must contain a template in each of their cases. Move the switch statement into an effect if it does not render anything.',
|
|
319
|
+
context.state.analysis.module.filename,
|
|
320
|
+
node,
|
|
321
|
+
);
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
|
|
285
326
|
ForOfStatement(node, context) {
|
|
286
327
|
if (!is_inside_component(context)) {
|
|
287
328
|
return context.next();
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** @import {Expression, FunctionExpression, Pattern} from 'estree' */
|
|
1
|
+
/** @import {Expression, FunctionExpression, Pattern, Node, Program} from 'estree' */
|
|
2
2
|
|
|
3
3
|
import { walk } from 'zimmerframe';
|
|
4
4
|
import path from 'node:path';
|
|
@@ -72,7 +72,7 @@ function visit_function(node, context) {
|
|
|
72
72
|
let body = context.visit(node.body, {
|
|
73
73
|
...state,
|
|
74
74
|
// we are new context so tracking no longer applies
|
|
75
|
-
metadata: { ...state.metadata,
|
|
75
|
+
metadata: { ...state.metadata, tracking: false },
|
|
76
76
|
});
|
|
77
77
|
|
|
78
78
|
if (metadata?.tracked === true) {
|
|
@@ -159,9 +159,12 @@ const visitors = {
|
|
|
159
159
|
}
|
|
160
160
|
} else {
|
|
161
161
|
const binding = context.state.scope.get(node.name);
|
|
162
|
+
const is_right_side_of_assignment =
|
|
163
|
+
parent.type === 'AssignmentExpression' && parent.right === node;
|
|
162
164
|
if (
|
|
163
165
|
(context.state.metadata?.tracking === false ||
|
|
164
|
-
(parent.type !== 'AssignmentExpression' && parent.type !== 'UpdateExpression')
|
|
166
|
+
(parent.type !== 'AssignmentExpression' && parent.type !== 'UpdateExpression') ||
|
|
167
|
+
is_right_side_of_assignment) &&
|
|
165
168
|
(node.tracked ||
|
|
166
169
|
binding?.kind === 'prop' ||
|
|
167
170
|
binding?.kind === 'index' ||
|
|
@@ -175,10 +178,10 @@ const visitors = {
|
|
|
175
178
|
add_ripple_internal_import(context);
|
|
176
179
|
return b.call('_$_.get', build_getter(node, context));
|
|
177
180
|
}
|
|
178
|
-
}
|
|
179
181
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
+
add_ripple_internal_import(context);
|
|
183
|
+
return build_getter(node, context);
|
|
184
|
+
}
|
|
182
185
|
}
|
|
183
186
|
}
|
|
184
187
|
},
|
|
@@ -943,7 +946,7 @@ const visitors = {
|
|
|
943
946
|
? context.visit(right)
|
|
944
947
|
: b.binary(
|
|
945
948
|
operator === '+=' ? '+' : operator === '-=' ? '-' : operator === '*=' ? '*' : '/',
|
|
946
|
-
/** @type {
|
|
949
|
+
/** @type {Expression} */ (context.visit(left)),
|
|
947
950
|
/** @type {Expression} */ (context.visit(right)),
|
|
948
951
|
),
|
|
949
952
|
b.id('__block'),
|
|
@@ -962,7 +965,7 @@ const visitors = {
|
|
|
962
965
|
? context.visit(right)
|
|
963
966
|
: b.binary(
|
|
964
967
|
operator === '+=' ? '+' : operator === '-=' ? '-' : operator === '*=' ? '*' : '/',
|
|
965
|
-
/** @type {
|
|
968
|
+
/** @type {Expression} */ (
|
|
966
969
|
context.visit(left, { ...context.state, metadata: { tracking: false } })
|
|
967
970
|
),
|
|
968
971
|
/** @type {Expression} */ (context.visit(right)),
|
|
@@ -1014,7 +1017,6 @@ const visitors = {
|
|
|
1014
1017
|
);
|
|
1015
1018
|
}
|
|
1016
1019
|
|
|
1017
|
-
|
|
1018
1020
|
const left = object(argument);
|
|
1019
1021
|
const binding = context.state.scope.get(left.name);
|
|
1020
1022
|
const transformers = left && binding?.transform;
|
|
@@ -1075,6 +1077,54 @@ const visitors = {
|
|
|
1075
1077
|
);
|
|
1076
1078
|
},
|
|
1077
1079
|
|
|
1080
|
+
SwitchStatement(node, context) {
|
|
1081
|
+
if (!is_inside_component(context)) {
|
|
1082
|
+
return context.next();
|
|
1083
|
+
}
|
|
1084
|
+
context.state.template.push('<!>');
|
|
1085
|
+
|
|
1086
|
+
const id = context.state.flush_node();
|
|
1087
|
+
const statements = [];
|
|
1088
|
+
const cases = [];
|
|
1089
|
+
|
|
1090
|
+
let i = 1;
|
|
1091
|
+
|
|
1092
|
+
for (const switch_case of node.cases) {
|
|
1093
|
+
const consequent_scope =
|
|
1094
|
+
context.state.scopes.get(switch_case.consequent) || context.state.scope;
|
|
1095
|
+
const consequent_id = context.state.scope.generate(
|
|
1096
|
+
'switch_case_' + (switch_case.test == null ? 'default' : i),
|
|
1097
|
+
);
|
|
1098
|
+
const consequent = b.block(
|
|
1099
|
+
transform_body(switch_case.consequent, {
|
|
1100
|
+
...context,
|
|
1101
|
+
state: { ...context.state, scope: consequent_scope },
|
|
1102
|
+
}),
|
|
1103
|
+
);
|
|
1104
|
+
|
|
1105
|
+
statements.push(b.var(b.id(consequent_id), b.arrow([b.id('__anchor')], consequent)));
|
|
1106
|
+
|
|
1107
|
+
cases.push(
|
|
1108
|
+
b.switch_case(switch_case.test ? context.visit(switch_case.test) : null, [
|
|
1109
|
+
b.return(b.id(consequent_id)),
|
|
1110
|
+
]),
|
|
1111
|
+
);
|
|
1112
|
+
i++;
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
statements.push(
|
|
1116
|
+
b.stmt(
|
|
1117
|
+
b.call(
|
|
1118
|
+
'_$_.switch',
|
|
1119
|
+
id,
|
|
1120
|
+
b.thunk(b.block([b.switch(context.visit(node.discriminant), cases)])),
|
|
1121
|
+
),
|
|
1122
|
+
),
|
|
1123
|
+
);
|
|
1124
|
+
|
|
1125
|
+
context.state.init.push(b.block(statements));
|
|
1126
|
+
},
|
|
1127
|
+
|
|
1078
1128
|
IfStatement(node, context) {
|
|
1079
1129
|
if (!is_inside_component(context)) {
|
|
1080
1130
|
return context.next();
|
|
@@ -1263,7 +1313,7 @@ function join_template(items) {
|
|
|
1263
1313
|
push(e);
|
|
1264
1314
|
}
|
|
1265
1315
|
|
|
1266
|
-
const last = /** @type {
|
|
1316
|
+
const last = /** @type {any} */ (expression.quasis.at(-1));
|
|
1267
1317
|
quasi.value.cooked += /** @type {string} */ (last.value.cooked);
|
|
1268
1318
|
} else if (expression.type === 'Literal') {
|
|
1269
1319
|
/** @type {string} */ (quasi.value.cooked) += expression.value;
|
|
@@ -1412,6 +1462,23 @@ function transform_ts_child(node, context) {
|
|
|
1412
1462
|
}
|
|
1413
1463
|
|
|
1414
1464
|
state.init.push(b.if(visit(node.test), consequent, alternate));
|
|
1465
|
+
} else if (node.type === 'SwitchStatement') {
|
|
1466
|
+
const cases = [];
|
|
1467
|
+
|
|
1468
|
+
for (const switch_case of node.cases) {
|
|
1469
|
+
const consequent_scope =
|
|
1470
|
+
context.state.scopes.get(switch_case.consequent) || context.state.scope;
|
|
1471
|
+
const consequent_body = transform_body(switch_case.consequent, {
|
|
1472
|
+
...context,
|
|
1473
|
+
state: { ...context.state, scope: consequent_scope },
|
|
1474
|
+
});
|
|
1475
|
+
|
|
1476
|
+
cases.push(
|
|
1477
|
+
b.switch_case(switch_case.test ? context.visit(switch_case.test) : null, consequent_body),
|
|
1478
|
+
);
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
context.state.init.push(b.switch(context.visit(node.discriminant), cases));
|
|
1415
1482
|
} else if (node.type === 'ForOfStatement') {
|
|
1416
1483
|
const body_scope = context.state.scopes.get(node.body);
|
|
1417
1484
|
const block_body = transform_body(node.body.body, {
|
|
@@ -1464,6 +1531,8 @@ function transform_ts_child(node, context) {
|
|
|
1464
1531
|
const component = visit(node, state);
|
|
1465
1532
|
|
|
1466
1533
|
state.init.push(component);
|
|
1534
|
+
} else if (node.type === 'BreakStatement') {
|
|
1535
|
+
state.init.push(b.break);
|
|
1467
1536
|
} else {
|
|
1468
1537
|
debugger;
|
|
1469
1538
|
throw new Error('TODO');
|
|
@@ -1483,6 +1552,7 @@ function transform_children(children, context) {
|
|
|
1483
1552
|
node.type === 'IfStatement' ||
|
|
1484
1553
|
node.type === 'TryStatement' ||
|
|
1485
1554
|
node.type === 'ForOfStatement' ||
|
|
1555
|
+
node.type === 'SwitchStatement' ||
|
|
1486
1556
|
node.type === 'Html' ||
|
|
1487
1557
|
(node.type === 'Element' &&
|
|
1488
1558
|
(node.id.type !== 'Identifier' || !is_element_dom_element(node))),
|
|
@@ -1634,6 +1704,11 @@ function transform_children(children, context) {
|
|
|
1634
1704
|
} else if (node.type === 'TryStatement') {
|
|
1635
1705
|
node.is_controlled = is_controlled;
|
|
1636
1706
|
visit(node, { ...state, flush_node, namespace: state.namespace });
|
|
1707
|
+
} else if (node.type === 'SwitchStatement') {
|
|
1708
|
+
node.is_controlled = is_controlled;
|
|
1709
|
+
visit(node, { ...state, flush_node, namespace: state.namespace });
|
|
1710
|
+
} else if (node.type === 'BreakStatement') {
|
|
1711
|
+
// do nothing
|
|
1637
1712
|
} else {
|
|
1638
1713
|
debugger;
|
|
1639
1714
|
}
|
|
@@ -1715,8 +1790,8 @@ export function transform_client(filename, source, analysis, to_ts) {
|
|
|
1715
1790
|
to_ts,
|
|
1716
1791
|
};
|
|
1717
1792
|
|
|
1718
|
-
const program = /** @type {
|
|
1719
|
-
walk(analysis.ast, { ...state, namespace: 'html' }, visitors)
|
|
1793
|
+
const program = /** @type {Program} */ (
|
|
1794
|
+
walk(/** @type {Node} */ (analysis.ast), { ...state, namespace: 'html' }, visitors)
|
|
1720
1795
|
);
|
|
1721
1796
|
|
|
1722
1797
|
for (const hoisted of state.hoisted) {
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** @import { createSubscriber } from '#public' */
|
|
2
|
+
import { untrack, queue_microtask } from './internal/client/runtime.js';
|
|
3
|
+
import { effect } from './internal/client/blocks.js'
|
|
4
|
+
|
|
5
|
+
/** @type {createSubscriber} */
|
|
6
|
+
export function createSubscriber(start) {
|
|
7
|
+
let subscribers = 0;
|
|
8
|
+
/** @type {(() => void) | void} */
|
|
9
|
+
let stop;
|
|
10
|
+
|
|
11
|
+
return () => {
|
|
12
|
+
effect(() => {
|
|
13
|
+
if (subscribers === 0) {
|
|
14
|
+
stop = untrack(start);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
subscribers += 1;
|
|
18
|
+
|
|
19
|
+
return () => {
|
|
20
|
+
queue_microtask(() => {
|
|
21
|
+
// Only count down after a microtask, else we would reach 0 before our own render effect reruns,
|
|
22
|
+
// but reach 1 again when the tick callback of the prior teardown runs. That would mean we
|
|
23
|
+
// re-subcribe unnecessarily and create a memory leak because the old subscription is never cleaned up.
|
|
24
|
+
subscribers -= 1;
|
|
25
|
+
|
|
26
|
+
if (subscribers === 0) {
|
|
27
|
+
stop?.();
|
|
28
|
+
stop = undefined;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
}
|
|
@@ -62,6 +62,14 @@ export { TrackedMap } from './map.js';
|
|
|
62
62
|
|
|
63
63
|
export { TrackedDate } from './date.js';
|
|
64
64
|
|
|
65
|
+
export { TrackedURL } from './url.js';
|
|
66
|
+
|
|
67
|
+
export { TrackedURLSearchParams } from './url-search-params.js';
|
|
68
|
+
|
|
69
|
+
export { createSubscriber } from './create-subscriber.js';
|
|
70
|
+
|
|
71
|
+
export { MediaQuery } from './media-query.js';
|
|
72
|
+
|
|
65
73
|
export { user_effect as effect } from './internal/client/blocks.js';
|
|
66
74
|
|
|
67
75
|
export { Portal } from './internal/client/portal.js';
|
|
@@ -10,8 +10,6 @@ export function effect() {
|
|
|
10
10
|
// NO-OP
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export const TrackedArray = Array;
|
|
14
|
-
|
|
15
13
|
var empty_get_set = { get: undefined, set: undefined };
|
|
16
14
|
|
|
17
15
|
/**
|
|
@@ -44,3 +42,30 @@ export function track(v, get, set) {
|
|
|
44
42
|
v,
|
|
45
43
|
};
|
|
46
44
|
}
|
|
45
|
+
|
|
46
|
+
export const TrackedObject = globalThis.Object;
|
|
47
|
+
export const TrackedArray = globalThis.Array;
|
|
48
|
+
export const TrackedDate = globalThis.Date;
|
|
49
|
+
export const TrackedSet = globalThis.Set;
|
|
50
|
+
export const TrackedMap = globalThis.Map;
|
|
51
|
+
export const TrackedURL = globalThis.URL;
|
|
52
|
+
export const TrackedURLSearchParams = globalThis.URLSearchParams;
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* @param {string} query A media query string
|
|
56
|
+
* @param {boolean} [matches] Fallback value for the server
|
|
57
|
+
*/
|
|
58
|
+
export function MediaQuery(query, matches = false) {
|
|
59
|
+
if (!new.target) {
|
|
60
|
+
throw new TypeError('MediaQuery must be called with new');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return matches;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* @param {any} _
|
|
68
|
+
*/
|
|
69
|
+
export function createSubscriber(_) {
|
|
70
|
+
return () => { /* NO-OP */ };
|
|
71
|
+
}
|
|
@@ -5,19 +5,20 @@ export var BRANCH_BLOCK = 1 << 4;
|
|
|
5
5
|
export var FOR_BLOCK = 1 << 5;
|
|
6
6
|
export var TRY_BLOCK = 1 << 6;
|
|
7
7
|
export var IF_BLOCK = 1 << 7;
|
|
8
|
-
export var
|
|
9
|
-
export var
|
|
10
|
-
export var
|
|
11
|
-
export var
|
|
12
|
-
export var
|
|
13
|
-
export var
|
|
14
|
-
export var
|
|
15
|
-
export var
|
|
16
|
-
export var
|
|
17
|
-
export var
|
|
18
|
-
export var
|
|
8
|
+
export var SWITCH_BLOCK = 1 << 8;
|
|
9
|
+
export var COMPOSITE_BLOCK = 1 << 9;
|
|
10
|
+
export var ASYNC_BLOCK = 1 << 10;
|
|
11
|
+
export var HEAD_BLOCK = 1 << 11;
|
|
12
|
+
export var CONTAINS_UPDATE = 1 << 12;
|
|
13
|
+
export var CONTAINS_TEARDOWN = 1 << 13;
|
|
14
|
+
export var BLOCK_HAS_RUN = 1 << 14;
|
|
15
|
+
export var TRACKED = 1 << 15;
|
|
16
|
+
export var DERIVED = 1 << 16;
|
|
17
|
+
export var DEFERRED = 1 << 17;
|
|
18
|
+
export var PAUSED = 1 << 18;
|
|
19
|
+
export var DESTROYED = 1 << 19;
|
|
19
20
|
|
|
20
|
-
export var CONTROL_FLOW_BLOCK = FOR_BLOCK | IF_BLOCK | TRY_BLOCK | COMPOSITE_BLOCK;
|
|
21
|
+
export var CONTROL_FLOW_BLOCK = FOR_BLOCK | IF_BLOCK | SWITCH_BLOCK | TRY_BLOCK | COMPOSITE_BLOCK;
|
|
21
22
|
|
|
22
23
|
export var UNINITIALIZED = Symbol();
|
|
23
24
|
/** @type {unique symbol} */
|
|
@@ -57,6 +57,8 @@ export { if_block as if } from './if.js';
|
|
|
57
57
|
|
|
58
58
|
export { try_block as try, aborted } from './try.js';
|
|
59
59
|
|
|
60
|
+
export { switch_block as switch } from './switch.js';
|
|
61
|
+
|
|
60
62
|
export { template, append } from './template.js';
|
|
61
63
|
|
|
62
64
|
export { tracked_array } from '../../array.js';
|
|
@@ -172,7 +172,7 @@ function run_derived(computed) {
|
|
|
172
172
|
var previous_tracking = tracking;
|
|
173
173
|
var previous_dependency = active_dependency;
|
|
174
174
|
var previous_component = active_component;
|
|
175
|
-
|
|
175
|
+
var previous_is_mutating_allowed = is_mutating_allowed;
|
|
176
176
|
|
|
177
177
|
try {
|
|
178
178
|
active_block = computed.b;
|
|
@@ -180,7 +180,7 @@ function run_derived(computed) {
|
|
|
180
180
|
tracking = true;
|
|
181
181
|
active_dependency = null;
|
|
182
182
|
active_component = computed.co;
|
|
183
|
-
|
|
183
|
+
is_mutating_allowed = false;
|
|
184
184
|
|
|
185
185
|
destroy_computed_children(computed);
|
|
186
186
|
|
|
@@ -195,7 +195,7 @@ function run_derived(computed) {
|
|
|
195
195
|
tracking = previous_tracking;
|
|
196
196
|
active_dependency = previous_dependency;
|
|
197
197
|
active_component = previous_component;
|
|
198
|
-
|
|
198
|
+
is_mutating_allowed = previous_is_mutating_allowed;
|
|
199
199
|
}
|
|
200
200
|
}
|
|
201
201
|
|
|
@@ -270,8 +270,8 @@ var empty_get_set = { get: undefined, set: undefined };
|
|
|
270
270
|
*
|
|
271
271
|
* @param {any} v
|
|
272
272
|
* @param {Block} b
|
|
273
|
-
* @param {
|
|
274
|
-
* @param {
|
|
273
|
+
* @param {(value: any) => any} [get]
|
|
274
|
+
* @param {(next: any, prev: any) => any} [set]
|
|
275
275
|
* @returns {Tracked}
|
|
276
276
|
*/
|
|
277
277
|
export function tracked(v, b, get, set) {
|
|
@@ -288,8 +288,8 @@ export function tracked(v, b, get, set) {
|
|
|
288
288
|
/**
|
|
289
289
|
* @param {any} fn
|
|
290
290
|
* @param {any} block
|
|
291
|
-
* @param {
|
|
292
|
-
* @param {
|
|
291
|
+
* @param {(value: any) => any} [get]
|
|
292
|
+
* @param {(next: any, prev: any) => any} [set]
|
|
293
293
|
* @returns {Derived}
|
|
294
294
|
*/
|
|
295
295
|
export function derived(fn, block, get, set) {
|
|
@@ -510,17 +510,17 @@ export function async_computed(fn, block) {
|
|
|
510
510
|
|
|
511
511
|
/**
|
|
512
512
|
* @template V
|
|
513
|
-
* @param {Function} fn
|
|
514
|
-
* @param {V} v
|
|
513
|
+
* @param {Function} fn
|
|
514
|
+
* @param {V} v
|
|
515
515
|
*/
|
|
516
516
|
function trigger_track_get(fn, v) {
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
517
|
+
var previous_is_mutating_allowed = is_mutating_allowed;
|
|
518
|
+
try {
|
|
519
|
+
is_mutating_allowed = false;
|
|
520
|
+
return untrack(() => fn(v));
|
|
521
|
+
} finally {
|
|
522
|
+
is_mutating_allowed = previous_is_mutating_allowed;
|
|
523
|
+
}
|
|
524
524
|
}
|
|
525
525
|
|
|
526
526
|
/**
|
|
@@ -774,9 +774,9 @@ export function get_tracked(tracked) {
|
|
|
774
774
|
* @param {Block} block
|
|
775
775
|
*/
|
|
776
776
|
export function set(tracked, value, block) {
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
777
|
+
if (!is_mutating_allowed) {
|
|
778
|
+
throw new Error('Assignments or updates to tracked values are not allowed during computed "track(() => ...)" evaluation');
|
|
779
|
+
}
|
|
780
780
|
|
|
781
781
|
var old_value = tracked.v;
|
|
782
782
|
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/** @import { Block } from '#client' */
|
|
2
|
+
|
|
3
|
+
import { branch, destroy_block, render } from './blocks.js';
|
|
4
|
+
import { SWITCH_BLOCK } from './constants.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @param {Node} node
|
|
8
|
+
* @param {() => ((anchor: Node) => void)} fn
|
|
9
|
+
* @returns {void}
|
|
10
|
+
*/
|
|
11
|
+
export function switch_block(node, fn) {
|
|
12
|
+
var anchor = node;
|
|
13
|
+
/** @type {any} */
|
|
14
|
+
var current_branch = null;
|
|
15
|
+
/** @type {Block | null} */
|
|
16
|
+
var b = null;
|
|
17
|
+
|
|
18
|
+
render(() => {
|
|
19
|
+
const branch_fn = fn() ?? null;
|
|
20
|
+
if (current_branch === branch_fn) return;
|
|
21
|
+
current_branch = branch_fn;
|
|
22
|
+
|
|
23
|
+
if (b !== null) {
|
|
24
|
+
destroy_block(b);
|
|
25
|
+
b = null;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (branch_fn !== null) {
|
|
29
|
+
b = branch(() => branch_fn(anchor));
|
|
30
|
+
}
|
|
31
|
+
}, SWITCH_BLOCK);
|
|
32
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { on } from './internal/client/events.js';
|
|
2
|
+
import { get, safe_scope, set, tracked } from './internal/client/index.js';
|
|
3
|
+
import { ReactiveValue } from './reactive-value.js';
|
|
4
|
+
|
|
5
|
+
const parenthesis_regex = /\(.+\)/;
|
|
6
|
+
const non_parenthesized_keywords = new Set(['all', 'print', 'screen', 'and', 'or', 'not', 'only']);
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @constructor
|
|
10
|
+
* @param {string} query
|
|
11
|
+
* @param {boolean | undefined} [fallback]
|
|
12
|
+
* @returns {ReactiveValue<boolean>}
|
|
13
|
+
*/
|
|
14
|
+
export function MediaQuery(query, fallback) {
|
|
15
|
+
if (!new.target) {
|
|
16
|
+
throw new TypeError('MediaQuery must be called with new');
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
var block = safe_scope();
|
|
20
|
+
|
|
21
|
+
let final_query =
|
|
22
|
+
parenthesis_regex.test(query) ||
|
|
23
|
+
// we need to use `some` here because technically this `window.matchMedia('random,screen')` still returns true
|
|
24
|
+
query.split(/[\s,]+/).some((keyword) => non_parenthesized_keywords.has(keyword.trim()))
|
|
25
|
+
? query
|
|
26
|
+
: `(${query})`;
|
|
27
|
+
const q = window.matchMedia(final_query);
|
|
28
|
+
const matches = tracked(q.matches, block);
|
|
29
|
+
|
|
30
|
+
return new ReactiveValue(
|
|
31
|
+
() => get(matches),
|
|
32
|
+
() => on(q, 'change', () => {
|
|
33
|
+
// skip wrapping in untrack as createSubscriber already does it
|
|
34
|
+
if (q.matches !== get(matches)) {
|
|
35
|
+
set(matches, q.matches, block)
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
);
|
|
39
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** @import { Derived } from '#client' */
|
|
2
|
+
import { createSubscriber } from './create-subscriber.js';
|
|
3
|
+
import { safe_scope, derived } from './internal/client/runtime.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @template V
|
|
7
|
+
* @constructor
|
|
8
|
+
* @param {() => V} fn
|
|
9
|
+
* @param {() => void | (() => void)} start
|
|
10
|
+
* @returns {Derived}
|
|
11
|
+
*/
|
|
12
|
+
export function ReactiveValue(fn, start) {
|
|
13
|
+
if (!new.target) {
|
|
14
|
+
throw new TypeError('`ReactiveValue` must be called with new');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const s = createSubscriber(start);
|
|
18
|
+
const block = safe_scope();
|
|
19
|
+
|
|
20
|
+
return (derived(fn, block, () => { s(); return fn(); }, (_, prev) => prev));
|
|
21
|
+
}
|