ripple 0.2.3 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +51 -20
- package/package.json +1 -1
- package/src/compiler/phases/1-parse/index.js +68 -11
- package/src/compiler/phases/2-analyze/index.js +0 -14
- package/src/compiler/phases/3-transform/index.js +29 -14
- package/src/runtime/internal/client/constants.js +1 -0
- package/src/runtime/internal/client/index.js +1 -1
- package/src/runtime/internal/client/render.js +0 -10
- package/src/runtime/internal/client/runtime.js +21 -5
- package/src/runtime/internal/client/try.js +2 -2
- package/types/index.d.ts +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
<picture>
|
|
2
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/ripple-dark.png">
|
|
3
|
+
<img src="assets/ripple-light.png" alt="Ripple - the elegant UI framework for the web" />
|
|
4
|
+
</picture>
|
|
5
|
+
|
|
6
|
+
# What is Ripple?
|
|
2
7
|
|
|
3
8
|
> Currently, this project is still in early development, and should not be used in production.
|
|
4
9
|
|
|
@@ -14,6 +19,8 @@ TypeScript and JSX, but with a few interesting touches. In my experience, this h
|
|
|
14
19
|
|
|
15
20
|
Right now, there will be plenty of bugs, things just won't work either and you'll find TODOs everywhere. At this stage, Ripple is more of an early alpha version of something that _might_ be, rather than something you should try and adopt. If anything, maybe some of the ideas can be shared and incubated back into other frameworks. There's also a lot of similarities with Svelte 5, and that's not by accident, that's because of my recent time working on Svelte 5.
|
|
16
21
|
|
|
22
|
+
If you'd like to know more, join the [Ripple Discord](https://discord.gg/JBF2ySrh2W).
|
|
23
|
+
|
|
17
24
|
## Features
|
|
18
25
|
|
|
19
26
|
- **Reactive State Management**: Built-in reactivity with `$` prefixed variables
|
|
@@ -29,20 +36,19 @@ Right now, there will be plenty of bugs, things just won't work either and you'l
|
|
|
29
36
|
|
|
30
37
|
## Quick Start
|
|
31
38
|
|
|
32
|
-
###
|
|
39
|
+
### Try Ripple
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
pnpm i --save ripple
|
|
36
|
-
```
|
|
41
|
+
> We're working hard on getting an online playgroud available. Watch this space!
|
|
37
42
|
|
|
38
|
-
You
|
|
43
|
+
You can try Ripple now by using our basic Vite template by running these commands in your terminal:
|
|
39
44
|
|
|
40
45
|
```bash
|
|
41
|
-
|
|
46
|
+
npx degit trueadm/ripple/templates/basic my-app
|
|
47
|
+
cd my-app
|
|
48
|
+
npm i # or yarn or pnpm
|
|
49
|
+
npm run dev # or yarn or pnpm
|
|
42
50
|
```
|
|
43
51
|
|
|
44
|
-
You can see a working example in the [playground demo app](https://github.com/trueadm/ripple/tree/main/playground).
|
|
45
|
-
|
|
46
52
|
### Mounting your app
|
|
47
53
|
|
|
48
54
|
You can use the `mount` API from the `ripple` package to render your Ripple component, using the `target`
|
|
@@ -77,14 +83,31 @@ component Button(props: { text: string, onClick: () => void }) {
|
|
|
77
83
|
}
|
|
78
84
|
|
|
79
85
|
// Usage
|
|
80
|
-
|
|
86
|
+
component App() {
|
|
87
|
+
<Button text="Click me" onClick={() => console.log("Clicked!")} />
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+

|
|
92
|
+
|
|
93
|
+
Ripple's templating language also supports shorthands and object spreads too:
|
|
94
|
+
|
|
95
|
+
```svelte
|
|
96
|
+
// you can do a normal prop
|
|
97
|
+
<div onClick={onClick}>{text}</div>
|
|
98
|
+
|
|
99
|
+
// or using the shorthand prop
|
|
100
|
+
<div {onClick}>{text}</div>
|
|
101
|
+
|
|
102
|
+
// and you can spread props
|
|
103
|
+
<div {...properties}>{text}</div>
|
|
81
104
|
```
|
|
82
105
|
|
|
83
106
|
### Reactive Variables
|
|
84
107
|
|
|
85
108
|
Variables prefixed with `$` are automatically reactive:
|
|
86
109
|
|
|
87
|
-
```
|
|
110
|
+
```ts
|
|
88
111
|
let $name = "World";
|
|
89
112
|
let $count = 0;
|
|
90
113
|
|
|
@@ -94,7 +117,7 @@ $count++;
|
|
|
94
117
|
|
|
95
118
|
Object properties prefixed with `$` are also automatically reactive:
|
|
96
119
|
|
|
97
|
-
```
|
|
120
|
+
```ts
|
|
98
121
|
let counter = { $current: 0 };
|
|
99
122
|
|
|
100
123
|
// Updates automatically trigger re-renders
|
|
@@ -103,7 +126,7 @@ counter.$current++;
|
|
|
103
126
|
|
|
104
127
|
Derived values are simply `$` variables that combined different parts of state:
|
|
105
128
|
|
|
106
|
-
```
|
|
129
|
+
```ts
|
|
107
130
|
let $count = 0;
|
|
108
131
|
let $double = $count * 2;
|
|
109
132
|
let $quadruple = $double * 2;
|
|
@@ -172,6 +195,8 @@ can only occur _inside_ a `component` body – you can't create JSX inside funct
|
|
|
172
195
|
</div>
|
|
173
196
|
```
|
|
174
197
|
|
|
198
|
+

|
|
199
|
+
|
|
175
200
|
Note that strings inside the template need to be inside `{"string"}`, you can't do `<div>hello</div>` as Ripple
|
|
176
201
|
has no idea if `hello` is a string or maybe some JavaScript code that needs evaluating, so just ensure you wrap them
|
|
177
202
|
in curly braces. This shouldn't be an issue in the real-world anyway, as you'll likely use an i18n library that means
|
|
@@ -191,13 +216,15 @@ component Truthy({ x }) {
|
|
|
191
216
|
</span>
|
|
192
217
|
} else {
|
|
193
218
|
<span>
|
|
194
|
-
{"x is
|
|
219
|
+
{"x is falsy"}
|
|
195
220
|
</span>
|
|
196
221
|
}
|
|
197
222
|
</div>
|
|
198
223
|
}
|
|
199
224
|
```
|
|
200
225
|
|
|
226
|
+

|
|
227
|
+
|
|
201
228
|
### For statements
|
|
202
229
|
|
|
203
230
|
You can render collections using a `for...of` block, and you don't need to specify a `key` prop like
|
|
@@ -214,6 +241,8 @@ component ListView({ title, items }) {
|
|
|
214
241
|
}
|
|
215
242
|
```
|
|
216
243
|
|
|
244
|
+

|
|
245
|
+
|
|
217
246
|
### Try statements
|
|
218
247
|
|
|
219
248
|
Try blocks work to building the foundation for **error boundaries**, when the runtime encounters
|
|
@@ -235,6 +264,8 @@ component ErrorBoundary() {
|
|
|
235
264
|
}
|
|
236
265
|
```
|
|
237
266
|
|
|
267
|
+

|
|
268
|
+
|
|
238
269
|
### Props
|
|
239
270
|
|
|
240
271
|
If you want a prop to be reactive, you should also give it a `$` prefix.
|
|
@@ -252,7 +283,7 @@ component Button(props: { $text: string, onClick: () => void }) {
|
|
|
252
283
|
|
|
253
284
|
### Children
|
|
254
285
|
|
|
255
|
-
Use `$children` prop and the `<$
|
|
286
|
+
Use `$children` prop and then use it in the form of `<$children />` for component composition.
|
|
256
287
|
|
|
257
288
|
When you pass in children to a component, it gets implicitly passed as the `$children` prop, in the form of a component.
|
|
258
289
|
|
|
@@ -261,7 +292,7 @@ import type { Component } from 'ripple';
|
|
|
261
292
|
|
|
262
293
|
component Card(props: { $children: Component }) {
|
|
263
294
|
<div class="card">
|
|
264
|
-
<$
|
|
295
|
+
<$children />
|
|
265
296
|
</div>
|
|
266
297
|
}
|
|
267
298
|
|
|
@@ -278,7 +309,7 @@ import type { Component } from 'ripple';
|
|
|
278
309
|
|
|
279
310
|
component Card(props: { $children: Component }) {
|
|
280
311
|
<div class="card">
|
|
281
|
-
<$
|
|
312
|
+
<$children />
|
|
282
313
|
</div>
|
|
283
314
|
}
|
|
284
315
|
|
|
@@ -336,14 +367,14 @@ component MyComponent() {
|
|
|
336
367
|
|
|
337
368
|
## VSCode Extension
|
|
338
369
|
|
|
339
|
-
The Ripple VSCode extension provides:
|
|
370
|
+
The [Ripple VSCode extension](https://marketplace.visualstudio.com/items?itemName=ripplejs.ripple-vscode-plugin) provides:
|
|
340
371
|
|
|
341
372
|
- **Syntax Highlighting** for `.ripple` files
|
|
342
373
|
- **Real-time Diagnostics** for compilation errors
|
|
343
374
|
- **TypeScript Integration** for type checking
|
|
344
375
|
- **IntelliSense** for autocompletion
|
|
345
376
|
|
|
346
|
-
|
|
377
|
+
You can find the extension on the VS Code Marketplace as [`Ripple for VS Code`](https://marketplace.visualstudio.com/items?itemName=ripplejs.ripple-vscode-plugin).
|
|
347
378
|
|
|
348
379
|
## Playground
|
|
349
380
|
|
|
@@ -353,4 +384,4 @@ Feel free to play around with how Ripple works. If you clone the repo, you can t
|
|
|
353
384
|
pnpm i && cd playground && pnpm dev
|
|
354
385
|
```
|
|
355
386
|
|
|
356
|
-
The playground uses Ripple's Vite plugin, where you can play around with things inside the `playground/src` directory.
|
|
387
|
+
The playground uses Ripple's Vite plugin, where you can play around with things inside the `playground/src` directory.
|
package/package.json
CHANGED
|
@@ -9,8 +9,8 @@ function convert_from_jsx(node) {
|
|
|
9
9
|
node.type = 'Identifier';
|
|
10
10
|
} else if (node.type === 'JSXMemberExpression') {
|
|
11
11
|
node.type = 'MemberExpression';
|
|
12
|
-
node.object = convert_from_jsx(node.object)
|
|
13
|
-
node.property = convert_from_jsx(node.property)
|
|
12
|
+
node.object = convert_from_jsx(node.object);
|
|
13
|
+
node.property = convert_from_jsx(node.property);
|
|
14
14
|
}
|
|
15
15
|
return node;
|
|
16
16
|
}
|
|
@@ -24,6 +24,38 @@ function RipplePlugin(config) {
|
|
|
24
24
|
class RippleParser extends Parser {
|
|
25
25
|
#path = [];
|
|
26
26
|
|
|
27
|
+
parseExportDefaultDeclaration() {
|
|
28
|
+
// Check if this is "export default component"
|
|
29
|
+
if (this.value === 'component') {
|
|
30
|
+
const node = this.startNode();
|
|
31
|
+
node.type = 'Component';
|
|
32
|
+
node.css = null;
|
|
33
|
+
node.default = true;
|
|
34
|
+
this.next();
|
|
35
|
+
this.enterScope(0);
|
|
36
|
+
|
|
37
|
+
node.id = this.type.label === 'name' ? this.parseIdent() : null;
|
|
38
|
+
|
|
39
|
+
this.parseFunctionParams(node);
|
|
40
|
+
this.eat(tt.braceL);
|
|
41
|
+
node.body = [];
|
|
42
|
+
this.#path.push(node);
|
|
43
|
+
|
|
44
|
+
this.parseTemplateBody(node.body);
|
|
45
|
+
|
|
46
|
+
this.#path.pop();
|
|
47
|
+
this.exitScope();
|
|
48
|
+
|
|
49
|
+
this.next();
|
|
50
|
+
this.finishNode(node, 'Component');
|
|
51
|
+
this.awaitPos = 0;
|
|
52
|
+
|
|
53
|
+
return node;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return super.parseExportDefaultDeclaration();
|
|
57
|
+
}
|
|
58
|
+
|
|
27
59
|
shouldParseExportStatement() {
|
|
28
60
|
if (super.shouldParseExportStatement()) {
|
|
29
61
|
return true;
|
|
@@ -253,10 +285,7 @@ function RipplePlugin(config) {
|
|
|
253
285
|
case 62: // '>'
|
|
254
286
|
case 125: {
|
|
255
287
|
// '}'
|
|
256
|
-
if (
|
|
257
|
-
ch === 125 &&
|
|
258
|
-
(this.#path.at(-1).type === 'Component')
|
|
259
|
-
) {
|
|
288
|
+
if (ch === 125 && this.#path.at(-1).type === 'Component') {
|
|
260
289
|
return original.readToken.call(this, ch);
|
|
261
290
|
}
|
|
262
291
|
this.raise(
|
|
@@ -318,7 +347,7 @@ function RipplePlugin(config) {
|
|
|
318
347
|
if (open.name.type === 'JSXIdentifier') {
|
|
319
348
|
open.name.type = 'Identifier';
|
|
320
349
|
}
|
|
321
|
-
|
|
350
|
+
|
|
322
351
|
element.id = convert_from_jsx(open.name);
|
|
323
352
|
element.attributes = open.attributes;
|
|
324
353
|
element.selfClosing = open.selfClosing;
|
|
@@ -364,6 +393,37 @@ function RipplePlugin(config) {
|
|
|
364
393
|
return element;
|
|
365
394
|
}
|
|
366
395
|
|
|
396
|
+
parseSubscript(base, startPos, startLoc, noCalls, maybeAsyncArrow, optionalChained, forInit) {
|
|
397
|
+
if (this.value === '<' && this.#path.findLast((n) => n.type === 'Component')) {
|
|
398
|
+
// Check if this looks like JSX by looking ahead
|
|
399
|
+
const ahead = this.lookahead();
|
|
400
|
+
if (ahead.type.label === 'name' || ahead.value === '/' || ahead.value === '>') {
|
|
401
|
+
// This is JSX, rewind to the end of the object expression
|
|
402
|
+
// and let ASI handle the semicolon insertion naturally
|
|
403
|
+
this.pos = base.end;
|
|
404
|
+
this.type = tt.braceR;
|
|
405
|
+
this.value = '}';
|
|
406
|
+
this.start = base.end - 1;
|
|
407
|
+
this.end = base.end;
|
|
408
|
+
const position = this.curPosition();
|
|
409
|
+
this.startLoc = position;
|
|
410
|
+
this.endLoc = position;
|
|
411
|
+
this.next();
|
|
412
|
+
|
|
413
|
+
return base;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
return super.parseSubscript(
|
|
417
|
+
base,
|
|
418
|
+
startPos,
|
|
419
|
+
startLoc,
|
|
420
|
+
noCalls,
|
|
421
|
+
maybeAsyncArrow,
|
|
422
|
+
optionalChained,
|
|
423
|
+
forInit
|
|
424
|
+
);
|
|
425
|
+
}
|
|
426
|
+
|
|
367
427
|
parseTemplateBody(body) {
|
|
368
428
|
var inside_func =
|
|
369
429
|
this.context.some((n) => n.token === 'function') || this.scopeStack.length > 1;
|
|
@@ -456,10 +516,7 @@ function RipplePlugin(config) {
|
|
|
456
516
|
parseBlock(createNewLexicalScope, node, exitStrict) {
|
|
457
517
|
const parent = this.#path.at(-1);
|
|
458
518
|
|
|
459
|
-
if (
|
|
460
|
-
parent?.type === 'Component' ||
|
|
461
|
-
parent?.type === 'Element'
|
|
462
|
-
) {
|
|
519
|
+
if (parent?.type === 'Component' || parent?.type === 'Element') {
|
|
463
520
|
if (createNewLexicalScope === void 0) createNewLexicalScope = true;
|
|
464
521
|
if (node === void 0) node = this.startNode();
|
|
465
522
|
|
|
@@ -439,20 +439,6 @@ const visitors = {
|
|
|
439
439
|
attribute
|
|
440
440
|
);
|
|
441
441
|
}
|
|
442
|
-
} else if (name === 'ref') {
|
|
443
|
-
if (is_dom_element) {
|
|
444
|
-
error(
|
|
445
|
-
'Cannot have a `ref` prop on an element, did you mean `$ref`?',
|
|
446
|
-
state.analysis.module.filename,
|
|
447
|
-
attribute
|
|
448
|
-
);
|
|
449
|
-
} else {
|
|
450
|
-
error(
|
|
451
|
-
'Cannot have a `ref` prop on a component, did you mean `$ref`?',
|
|
452
|
-
state.analysis.module.filename,
|
|
453
|
-
attribute
|
|
454
|
-
);
|
|
455
|
-
}
|
|
456
442
|
}
|
|
457
443
|
|
|
458
444
|
if (is_tracked_name(name)) {
|
|
@@ -44,7 +44,7 @@ function visit_function(node, context) {
|
|
|
44
44
|
|
|
45
45
|
let body = context.visit(node.body, state);
|
|
46
46
|
|
|
47
|
-
if (metadata
|
|
47
|
+
if (metadata?.tracked === true) {
|
|
48
48
|
return /** @type {FunctionExpression} */ ({
|
|
49
49
|
...node,
|
|
50
50
|
params: node.params.map((param) => context.visit(param, state)),
|
|
@@ -66,7 +66,7 @@ function build_getter(node, context) {
|
|
|
66
66
|
|
|
67
67
|
// don't transform the declaration itself
|
|
68
68
|
if (node !== binding?.node && binding?.transform) {
|
|
69
|
-
return binding.transform.read(node);
|
|
69
|
+
return binding.transform.read(node, context.state?.metadata?.spread);
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
@@ -409,18 +409,12 @@ const visitors = {
|
|
|
409
409
|
continue;
|
|
410
410
|
}
|
|
411
411
|
|
|
412
|
-
if (name === '$ref') {
|
|
413
|
-
const id = state.flush_node();
|
|
414
|
-
const value = attr.value;
|
|
415
|
-
|
|
416
|
-
state.init.push(b.stmt(b.call('$.set_ref', id, visit(value, state))));
|
|
417
|
-
continue;
|
|
418
|
-
}
|
|
419
|
-
|
|
420
412
|
if (is_event_attribute(name)) {
|
|
421
|
-
|
|
413
|
+
let capture = name.endsWith('Capture');
|
|
414
|
+
let event_name = capture
|
|
415
|
+
? name.slice(2, -7).toLowerCase()
|
|
416
|
+
: name.slice(2).toLowerCase();
|
|
422
417
|
let handler = visit(attr.value, state);
|
|
423
|
-
let capture = false; // TODO
|
|
424
418
|
|
|
425
419
|
if (attr.metadata?.delegated) {
|
|
426
420
|
let delegated_assignment;
|
|
@@ -552,8 +546,9 @@ const visitors = {
|
|
|
552
546
|
|
|
553
547
|
state.template.push('<!>');
|
|
554
548
|
|
|
549
|
+
const is_spreading = node.attributes.some((attr) => attr.type === 'SpreadAttribute');
|
|
555
550
|
const tracked = [];
|
|
556
|
-
|
|
551
|
+
const props = [];
|
|
557
552
|
let children_prop = null;
|
|
558
553
|
|
|
559
554
|
for (const attr of node.attributes) {
|
|
@@ -577,6 +572,15 @@ const visitors = {
|
|
|
577
572
|
} else {
|
|
578
573
|
props.push(b.prop('init', attr.name, visit(attr.value, state)));
|
|
579
574
|
}
|
|
575
|
+
} else if (attr.type === 'SpreadAttribute') {
|
|
576
|
+
props.push(
|
|
577
|
+
b.spread(
|
|
578
|
+
b.call(
|
|
579
|
+
'$.spread_object',
|
|
580
|
+
visit(attr.argument, { ...state, metadata: { ...state.metadata, spread: true } })
|
|
581
|
+
)
|
|
582
|
+
)
|
|
583
|
+
);
|
|
580
584
|
} else {
|
|
581
585
|
throw new Error('TODO');
|
|
582
586
|
}
|
|
@@ -600,7 +604,18 @@ const visitors = {
|
|
|
600
604
|
}
|
|
601
605
|
}
|
|
602
606
|
|
|
603
|
-
if (
|
|
607
|
+
if (is_spreading) {
|
|
608
|
+
state.init.push(
|
|
609
|
+
b.stmt(
|
|
610
|
+
b.call(
|
|
611
|
+
node.id,
|
|
612
|
+
id,
|
|
613
|
+
b.call('$.tracked_spread_object', b.thunk(b.object(props))),
|
|
614
|
+
b.id('$.active_block')
|
|
615
|
+
)
|
|
616
|
+
)
|
|
617
|
+
);
|
|
618
|
+
} else if (tracked.length > 0) {
|
|
604
619
|
state.init.push(
|
|
605
620
|
b.stmt(
|
|
606
621
|
b.call(
|
|
@@ -7,7 +7,6 @@ export {
|
|
|
7
7
|
set_value,
|
|
8
8
|
set_checked,
|
|
9
9
|
set_selected,
|
|
10
|
-
set_ref
|
|
11
10
|
} from './render.js';
|
|
12
11
|
|
|
13
12
|
export { render, render_spread, async } from './blocks.js';
|
|
@@ -25,6 +24,7 @@ export {
|
|
|
25
24
|
async_computed,
|
|
26
25
|
tracked,
|
|
27
26
|
tracked_object,
|
|
27
|
+
tracked_spread_object,
|
|
28
28
|
computed_property,
|
|
29
29
|
get_property,
|
|
30
30
|
set_property,
|
|
@@ -157,16 +157,6 @@ export function set_selected(element, selected) {
|
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
|
|
160
|
-
export function set_ref(dom, fn) {
|
|
161
|
-
effect(() => {
|
|
162
|
-
fn(dom);
|
|
163
|
-
|
|
164
|
-
return () => {
|
|
165
|
-
fn(null);
|
|
166
|
-
};
|
|
167
|
-
});
|
|
168
|
-
}
|
|
169
|
-
|
|
170
160
|
export function apply_element_spread(element, fn) {
|
|
171
161
|
return () => {
|
|
172
162
|
set_attributes(element, fn());
|
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
EFFECT_BLOCK,
|
|
19
19
|
PAUSED,
|
|
20
20
|
ROOT_BLOCK,
|
|
21
|
+
SPREAD_OBJECT,
|
|
21
22
|
TRACKED,
|
|
22
23
|
TRACKED_OBJECT,
|
|
23
24
|
TRY_BLOCK,
|
|
@@ -217,9 +218,9 @@ export function tracked(v, b) {
|
|
|
217
218
|
};
|
|
218
219
|
}
|
|
219
220
|
|
|
220
|
-
export function computed(fn,
|
|
221
|
+
export function computed(fn, block) {
|
|
221
222
|
return {
|
|
222
|
-
b,
|
|
223
|
+
b: block,
|
|
223
224
|
blocks: null,
|
|
224
225
|
c: 0,
|
|
225
226
|
d: null,
|
|
@@ -644,7 +645,7 @@ export function flush_sync(fn) {
|
|
|
644
645
|
var previous_queued_root_blocks = queued_root_blocks;
|
|
645
646
|
|
|
646
647
|
try {
|
|
647
|
-
|
|
648
|
+
var root_blocks = [];
|
|
648
649
|
|
|
649
650
|
scheduler_mode = FLUSH_SYNC;
|
|
650
651
|
queued_root_blocks = root_blocks;
|
|
@@ -667,6 +668,17 @@ export function flush_sync(fn) {
|
|
|
667
668
|
}
|
|
668
669
|
}
|
|
669
670
|
|
|
671
|
+
export function tracked_spread_object(fn) {
|
|
672
|
+
var obj = fn();
|
|
673
|
+
|
|
674
|
+
define_property(obj, SPREAD_OBJECT, {
|
|
675
|
+
value: fn,
|
|
676
|
+
enumerable: false
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
return obj;
|
|
680
|
+
}
|
|
681
|
+
|
|
670
682
|
export function tracked_object(obj, properties, block) {
|
|
671
683
|
var tracked_properties = obj[TRACKED_OBJECT];
|
|
672
684
|
|
|
@@ -719,6 +731,10 @@ export function get_property(obj, property, chain = false) {
|
|
|
719
731
|
|
|
720
732
|
if (tracked_property !== undefined) {
|
|
721
733
|
value = obj[property] = get(tracked_property);
|
|
734
|
+
} else if (SPREAD_OBJECT in obj) {
|
|
735
|
+
var spread_fn = obj[SPREAD_OBJECT];
|
|
736
|
+
var properties = spread_fn();
|
|
737
|
+
return get_property(properties, property, chain);
|
|
722
738
|
}
|
|
723
739
|
|
|
724
740
|
return value;
|
|
@@ -851,11 +867,11 @@ export function spread_object(obj) {
|
|
|
851
867
|
return { ...obj };
|
|
852
868
|
}
|
|
853
869
|
var keys = original_object_keys(obj);
|
|
854
|
-
|
|
870
|
+
var values = {};
|
|
855
871
|
|
|
856
872
|
for (var i = 0; i < keys.length; i++) {
|
|
857
873
|
var key = keys[i];
|
|
858
|
-
values[key] =
|
|
874
|
+
values[key] = get_property(obj, key);
|
|
859
875
|
}
|
|
860
876
|
|
|
861
877
|
return values;
|
|
@@ -109,13 +109,13 @@ export function capture() {
|
|
|
109
109
|
var previous_tracking = tracking;
|
|
110
110
|
var previous_block = active_block;
|
|
111
111
|
var previous_reaction = active_reaction;
|
|
112
|
-
|
|
112
|
+
var previous_component = active_component;
|
|
113
113
|
|
|
114
114
|
return () => {
|
|
115
115
|
set_tracking(previous_tracking);
|
|
116
116
|
set_active_block(previous_block);
|
|
117
117
|
set_active_reaction(previous_reaction);
|
|
118
|
-
|
|
118
|
+
set_active_component(previous_component);
|
|
119
119
|
|
|
120
120
|
queue_microtask(exit);
|
|
121
121
|
};
|
package/types/index.d.ts
CHANGED