ripple 0.2.105 → 0.2.106
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 +81 -31
- package/src/compiler/utils.js +1 -1
- 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.106",
|
|
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,11 @@ const visitors = {
|
|
|
159
159
|
}
|
|
160
160
|
} else {
|
|
161
161
|
const binding = context.state.scope.get(node.name);
|
|
162
|
+
const isRightSideOfAssignment = parent.type === 'AssignmentExpression' && parent.right === node;
|
|
162
163
|
if (
|
|
163
164
|
(context.state.metadata?.tracking === false ||
|
|
164
|
-
(parent.type !== 'AssignmentExpression' && parent.type !== 'UpdateExpression')
|
|
165
|
+
(parent.type !== 'AssignmentExpression' && parent.type !== 'UpdateExpression') ||
|
|
166
|
+
isRightSideOfAssignment) &&
|
|
165
167
|
(node.tracked ||
|
|
166
168
|
binding?.kind === 'prop' ||
|
|
167
169
|
binding?.kind === 'index' ||
|
|
@@ -175,10 +177,10 @@ const visitors = {
|
|
|
175
177
|
add_ripple_internal_import(context);
|
|
176
178
|
return b.call('_$_.get', build_getter(node, context));
|
|
177
179
|
}
|
|
178
|
-
}
|
|
179
180
|
|
|
180
|
-
|
|
181
|
-
|
|
181
|
+
add_ripple_internal_import(context);
|
|
182
|
+
return build_getter(node, context);
|
|
183
|
+
}
|
|
182
184
|
}
|
|
183
185
|
}
|
|
184
186
|
},
|
|
@@ -467,10 +469,9 @@ const visitors = {
|
|
|
467
469
|
|
|
468
470
|
const handle_static_attr = (name, value) => {
|
|
469
471
|
const attr_value = b.literal(
|
|
470
|
-
` ${name}${
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
: `="${value === true ? '' : escape_html(value, true)}"`
|
|
472
|
+
` ${name}${is_boolean_attribute(name) && value === true
|
|
473
|
+
? ''
|
|
474
|
+
: `="${value === true ? '' : escape_html(value, true)}"`
|
|
474
475
|
}`,
|
|
475
476
|
);
|
|
476
477
|
|
|
@@ -942,10 +943,10 @@ const visitors = {
|
|
|
942
943
|
operator === '='
|
|
943
944
|
? context.visit(right)
|
|
944
945
|
: b.binary(
|
|
945
|
-
|
|
946
|
-
/** @type {Pattern} */
|
|
947
|
-
/** @type {Expression} */
|
|
948
|
-
|
|
946
|
+
operator === '+=' ? '+' : operator === '-=' ? '-' : operator === '*=' ? '*' : '/',
|
|
947
|
+
/** @type {Pattern} */(context.visit(left)),
|
|
948
|
+
/** @type {Expression} */(context.visit(right)),
|
|
949
|
+
),
|
|
949
950
|
b.id('__block'),
|
|
950
951
|
);
|
|
951
952
|
}
|
|
@@ -961,12 +962,12 @@ const visitors = {
|
|
|
961
962
|
operator === '='
|
|
962
963
|
? context.visit(right)
|
|
963
964
|
: b.binary(
|
|
964
|
-
|
|
965
|
-
/** @type {Pattern} */
|
|
966
|
-
|
|
967
|
-
),
|
|
968
|
-
/** @type {Expression} */ (context.visit(right)),
|
|
965
|
+
operator === '+=' ? '+' : operator === '-=' ? '-' : operator === '*=' ? '*' : '/',
|
|
966
|
+
/** @type {Pattern} */(
|
|
967
|
+
context.visit(left, { ...context.state, metadata: { tracking: false } })
|
|
969
968
|
),
|
|
969
|
+
/** @type {Expression} */(context.visit(right)),
|
|
970
|
+
),
|
|
970
971
|
b.id('__block'),
|
|
971
972
|
);
|
|
972
973
|
}
|
|
@@ -1014,7 +1015,6 @@ const visitors = {
|
|
|
1014
1015
|
);
|
|
1015
1016
|
}
|
|
1016
1017
|
|
|
1017
|
-
|
|
1018
1018
|
const left = object(argument);
|
|
1019
1019
|
const binding = context.state.scope.get(left.name);
|
|
1020
1020
|
const transformers = left && binding?.transform;
|
|
@@ -1075,6 +1075,52 @@ const visitors = {
|
|
|
1075
1075
|
);
|
|
1076
1076
|
},
|
|
1077
1077
|
|
|
1078
|
+
SwitchStatement(node, context) {
|
|
1079
|
+
if (!is_inside_component(context)) {
|
|
1080
|
+
return context.next();
|
|
1081
|
+
}
|
|
1082
|
+
context.state.template.push('<!>');
|
|
1083
|
+
|
|
1084
|
+
const id = context.state.flush_node();
|
|
1085
|
+
const statements = [];
|
|
1086
|
+
const cases = [];
|
|
1087
|
+
|
|
1088
|
+
let i = 1;
|
|
1089
|
+
|
|
1090
|
+
for (const switch_case of node.cases) {
|
|
1091
|
+
const consequent_scope =
|
|
1092
|
+
context.state.scopes.get(switch_case.consequent) || context.state.scope;
|
|
1093
|
+
const consequent_id = context.state.scope.generate('switch_case_' + (switch_case.test == null ? 'default' : i));
|
|
1094
|
+
const consequent = b.block(
|
|
1095
|
+
transform_body(switch_case.consequent, {
|
|
1096
|
+
...context,
|
|
1097
|
+
state: { ...context.state, scope: consequent_scope },
|
|
1098
|
+
}),
|
|
1099
|
+
);
|
|
1100
|
+
|
|
1101
|
+
statements.push(b.var(b.id(consequent_id), b.arrow([b.id('__anchor')], consequent)));
|
|
1102
|
+
|
|
1103
|
+
cases.push(
|
|
1104
|
+
b.switch_case(switch_case.test ? context.visit(switch_case.test) : null, [
|
|
1105
|
+
b.return(b.id(consequent_id)),
|
|
1106
|
+
]),
|
|
1107
|
+
);
|
|
1108
|
+
i++;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
statements.push(
|
|
1112
|
+
b.stmt(
|
|
1113
|
+
b.call(
|
|
1114
|
+
'_$_.switch',
|
|
1115
|
+
id,
|
|
1116
|
+
b.thunk(b.block([b.switch(context.visit(node.discriminant), cases)])),
|
|
1117
|
+
),
|
|
1118
|
+
),
|
|
1119
|
+
);
|
|
1120
|
+
|
|
1121
|
+
context.state.init.push(b.block(statements));
|
|
1122
|
+
},
|
|
1123
|
+
|
|
1078
1124
|
IfStatement(node, context) {
|
|
1079
1125
|
if (!is_inside_component(context)) {
|
|
1080
1126
|
return context.next();
|
|
@@ -1126,12 +1172,12 @@ const visitors = {
|
|
|
1126
1172
|
b.stmt(b.call(b.id('__render'), b.id(consequent_id))),
|
|
1127
1173
|
alternate_id
|
|
1128
1174
|
? b.stmt(
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1175
|
+
b.call(
|
|
1176
|
+
b.id('__render'),
|
|
1177
|
+
b.id(alternate_id),
|
|
1178
|
+
node.alternate ? b.literal(false) : undefined,
|
|
1179
|
+
),
|
|
1180
|
+
)
|
|
1135
1181
|
: undefined,
|
|
1136
1182
|
),
|
|
1137
1183
|
]),
|
|
@@ -1184,9 +1230,9 @@ const visitors = {
|
|
|
1184
1230
|
node.handler === null
|
|
1185
1231
|
? b.literal(null)
|
|
1186
1232
|
: b.arrow(
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1233
|
+
[b.id('__anchor'), ...(node.handler.param ? [node.handler.param] : [])],
|
|
1234
|
+
b.block(transform_body(node.handler.body.body, context)),
|
|
1235
|
+
),
|
|
1190
1236
|
node.pending === null
|
|
1191
1237
|
? undefined
|
|
1192
1238
|
: b.arrow([b.id('__anchor')], b.block(transform_body(node.pending.body, context))),
|
|
@@ -1282,7 +1328,7 @@ function join_template(items) {
|
|
|
1282
1328
|
}
|
|
1283
1329
|
|
|
1284
1330
|
for (const quasi of template.quasis) {
|
|
1285
|
-
quasi.value.raw = sanitize_template_string(/** @type {string} */
|
|
1331
|
+
quasi.value.raw = sanitize_template_string(/** @type {string} */(quasi.value.cooked));
|
|
1286
1332
|
}
|
|
1287
1333
|
|
|
1288
1334
|
quasi.tail = true;
|
|
@@ -1483,6 +1529,7 @@ function transform_children(children, context) {
|
|
|
1483
1529
|
node.type === 'IfStatement' ||
|
|
1484
1530
|
node.type === 'TryStatement' ||
|
|
1485
1531
|
node.type === 'ForOfStatement' ||
|
|
1532
|
+
node.type === 'SwitchStatement' ||
|
|
1486
1533
|
node.type === 'Html' ||
|
|
1487
1534
|
(node.type === 'Element' &&
|
|
1488
1535
|
(node.id.type !== 'Identifier' || !is_element_dom_element(node))),
|
|
@@ -1634,6 +1681,9 @@ function transform_children(children, context) {
|
|
|
1634
1681
|
} else if (node.type === 'TryStatement') {
|
|
1635
1682
|
node.is_controlled = is_controlled;
|
|
1636
1683
|
visit(node, { ...state, flush_node, namespace: state.namespace });
|
|
1684
|
+
} else if (node.type === 'SwitchStatement') {
|
|
1685
|
+
node.is_controlled = is_controlled;
|
|
1686
|
+
visit(node, { ...state, flush_node, namespace: state.namespace });
|
|
1637
1687
|
} else {
|
|
1638
1688
|
debugger;
|
|
1639
1689
|
}
|
|
@@ -1715,7 +1765,7 @@ export function transform_client(filename, source, analysis, to_ts) {
|
|
|
1715
1765
|
to_ts,
|
|
1716
1766
|
};
|
|
1717
1767
|
|
|
1718
|
-
const program = /** @type {
|
|
1768
|
+
const program = /** @type {Program} */ (
|
|
1719
1769
|
walk(analysis.ast, { ...state, namespace: 'html' }, visitors)
|
|
1720
1770
|
);
|
|
1721
1771
|
|
package/src/compiler/utils.js
CHANGED
|
@@ -808,7 +808,7 @@ export function normalize_children(children, context) {
|
|
|
808
808
|
* @param {TransformContext} context
|
|
809
809
|
*/
|
|
810
810
|
function normalize_child(node, normalized, context) {
|
|
811
|
-
if (node.type === 'EmptyStatement') {
|
|
811
|
+
if (node.type === 'EmptyStatement' || node.type === 'BreakStatement') {
|
|
812
812
|
return;
|
|
813
813
|
} else if (
|
|
814
814
|
node.type === 'Element' &&
|
|
@@ -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
|
+
}
|