sprae 3.0.1 → 4.0.0

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/test/dom.js CHANGED
@@ -25,6 +25,7 @@ test('hidden: core', async () => {
25
25
  let params = sprae(el, {hidden:true})
26
26
  is(el.outerHTML, `<div hidden=""></div>`)
27
27
  params.hidden = false
28
+ await tick()
28
29
  is(el.outerHTML, `<div></div>`)
29
30
  })
30
31
 
@@ -42,6 +43,7 @@ test('common: reactive', async () => {
42
43
  let params = sprae(el, {name:'text', url:'//google.com'})
43
44
  is(el.outerHTML, `<label for="text">text</label><input id="text" name="text" type="text"><a href="//google.com"></a><img src="//google.com">`)
44
45
  params.name = 'email'
46
+ await tick()
45
47
  is(el.outerHTML, `<label for="email">email</label><input id="email" name="email" type="email"><a href="//google.com"></a><img src="//google.com">`)
46
48
  })
47
49
 
@@ -76,17 +78,22 @@ test('style', async () => {
76
78
  let el = h`<x style="left: 1px" :style="style"></x>`
77
79
  let params = sprae(el, {style: "top: 1px"})
78
80
  is(el.outerHTML, `<x style="left: 1px; top: 1px"></x>`)
81
+
79
82
  params.style = {top: '2px'}
83
+ await tick()
80
84
  is(el.outerHTML, `<x style="left: 1px; top: 2px;"></x>`)
81
85
 
82
86
  params.style = {'--x': 123}
87
+ await tick()
83
88
  is(el.style.getPropertyValue('--x'), '123')
84
89
 
85
90
  params.style = {top:'1px', bottom:'2px'}
91
+ await tick()
86
92
  is(el.outerHTML, `<x style="left: 1px; top: 1px; bottom: 2px;"></x>`)
87
93
 
88
94
  params.style = {top:'2px', bottom: null}
89
95
  // FIXME
96
+ await tick()
90
97
  is(el.outerHTML, `<x style="left: 1px; top: 2px;"></x>`)
91
98
  })
92
99
 
@@ -96,6 +103,7 @@ test('class', async () => {
96
103
  let params = sprae(el, {a:'x', b:'y', c, d:false});
97
104
  is(el.outerHTML, `<x class="base x"></x><y class="y z"></y><z class="b"></z>`);
98
105
  params.d = true;
106
+ await tick()
99
107
  is(el.outerHTML, `<x class="base x"></x><y class="y z"></y><z class="b c"></z>`);
100
108
  // c.value = 'w'
101
109
  // is(el.outerHTML, `<x class="base x"></x><y class="y w"></y><z class="b c"></z>`);
@@ -126,6 +134,7 @@ test('props: calculation', async () => {
126
134
  let state = sprae(el, {x:3});
127
135
  is(el.outerHTML, `<x x="012"></x>`)
128
136
  state.x = 4
137
+ await tick()
129
138
  is(el.outerHTML, `<x x="0123"></x>`)
130
139
  })
131
140
 
@@ -138,13 +147,13 @@ test.todo('props: semicols in expression', async () => {
138
147
  })
139
148
 
140
149
 
141
- test('data: base', async () => {
150
+ test.skip('data: base', async () => {
142
151
  let el = h`<input :data="{a:1, fooBar:2}"/>`
143
152
  let params = sprae(el)
144
153
  is(el.outerHTML, `<input data-a="1" data-foo-bar="2">`)
145
154
  })
146
155
 
147
- test('aria: base', async () => {
156
+ test.skip('aria: base', async () => {
148
157
  let el = h`<input type="text" id="jokes" role="combobox" :aria="{controls:'joketypes', autocomplete:'list', expanded:false, activeOption:'item1', activedescendant:'', xxx:null}"/>`
149
158
  sprae(el)
150
159
  is(el.outerHTML, `<input type="text" id="jokes" role="combobox" aria-controls="joketypes" aria-autocomplete="list" aria-expanded="false" aria-active-option="item1" aria-activedescendant="">`)
@@ -156,6 +165,7 @@ test('value: direct', async () => {
156
165
  is(el.value, '1')
157
166
  is(el.outerHTML, `<input value="1">`)
158
167
  state.a = 2
168
+ await tick()
159
169
  is(el.value, '2')
160
170
  is(el.outerHTML, `<input value="2">`)
161
171
 
@@ -182,6 +192,7 @@ test('text: core', async () => {
182
192
  let params = sprae(el, {text:'abc'})
183
193
  is(el.outerHTML, `<div>abc</div>`)
184
194
  params.text = null
195
+ await tick()
185
196
  is(el.outerHTML, `<div></div>`)
186
197
  })
187
198
 
@@ -196,10 +207,13 @@ test('if: base', async () => {
196
207
 
197
208
  is(el.innerHTML, '<span>a</span>')
198
209
  params.a = 2
210
+ await tick()
199
211
  is(el.innerHTML, '<span>b</span>')
200
212
  params.a = 3
213
+ await tick()
201
214
  is(el.innerHTML, '<span>c</span>')
202
215
  params.a = null
216
+ await tick()
203
217
  is(el.innerHTML, '<span>c</span>')
204
218
  })
205
219
 
@@ -214,15 +228,20 @@ test('if: short with insertions', async () => {
214
228
 
215
229
  is(el.innerHTML, '<span>1:1</span>')
216
230
  params.a = 2
231
+ await tick()
217
232
  is(el.innerHTML, '<span>2:2</span>')
218
233
  params.a = 3
234
+ await tick()
219
235
  is(el.innerHTML, '<span>3</span>')
220
236
  params.a = 4
237
+ await tick()
221
238
  is(el.innerHTML, '<span>4</span>')
222
239
 
223
240
  params.a = 1
241
+ await tick()
224
242
  is(el.innerHTML, '<span>1:1</span>')
225
243
  params.a = 4
244
+ await tick()
226
245
  is(el.innerHTML, '<span>4</span>')
227
246
 
228
247
  params.a = null
@@ -258,15 +277,16 @@ test('if: (#3) subsequent content is not abandoned', async () => {
258
277
  is(x.outerHTML, `<x><z>123</z></x>`)
259
278
  })
260
279
 
261
- test('if: + :with doesnt prevent secondary effects from happening', () => {
262
- let el = h`<div><x :if="x" :with="{}" :text="x"></x></div>`
280
+ test('if: + :scope doesnt prevent secondary effects from happening', async () => {
281
+ let el = h`<div><x :if="x" :scope="{}" :text="x"></x></div>`
263
282
  let state = sprae(el, {x:''})
264
283
  is(el.innerHTML, ``)
265
284
  state.x = '123'
285
+ await tick()
266
286
  is(el.innerHTML, `<x>123</x>`)
267
287
 
268
288
  // NOTE: we ignore this case
269
- // let el2 = h`<div><x :if="x" :with="{x:cond}" :text="x"></x></div>`
289
+ // let el2 = h`<div><x :if="x" :scope="{x:cond}" :text="x"></x></div>`
270
290
  // let state2 = sprae(el, {cond:''})
271
291
  // is(el2.innerHTML, ``)
272
292
  // state2.cond = '123'
@@ -284,10 +304,13 @@ test('each: array', async () => {
284
304
  is(el.innerHTML, '')
285
305
  console.log('set 1,2')
286
306
  params.b = [1,2]
307
+ await tick()
287
308
  is(el.innerHTML, '<span>1</span><span>2</span>')
288
309
  params.b = []
310
+ await tick()
289
311
  is(el.innerHTML, '')
290
312
  params.b = null
313
+ await tick()
291
314
  is(el.innerHTML, '')
292
315
  })
293
316
 
@@ -302,10 +325,13 @@ test('each: object', async () => {
302
325
  is(el.innerHTML, '')
303
326
  console.log('set 1,2')
304
327
  params.b = { x:1, y:2 }
328
+ await tick()
305
329
  is(el.innerHTML, '<span>x,1</span><span>y,2</span>')
306
330
  params.b = []
331
+ await tick()
307
332
  is(el.innerHTML, '')
308
333
  params.b = null
334
+ await tick()
309
335
  is(el.innerHTML, '')
310
336
  })
311
337
 
@@ -318,12 +344,15 @@ test('each: loop within loop', async () => {
318
344
 
319
345
  is(el.innerHTML, '<x><y>1</y><y>2</y></x><x><y>3</y><y>4</y></x>')
320
346
  params.c = [[5,6], [3,4]]
347
+ await tick()
321
348
  is(el.innerHTML, '<x><y>5</y><y>6</y></x><x><y>3</y><y>4</y></x>')
322
349
  // params.c[1] = [7,8]
323
350
  params.c = [params.c[0], [7,8]]
351
+ await tick()
324
352
  is(el.innerHTML, '<x><y>5</y><y>6</y></x><x><y>7</y><y>8</y></x>')
325
353
  // is(el.innerHTML, '<span>1</span><span>2</span>')
326
354
  params.c = []
355
+ await tick()
327
356
  is(el.innerHTML, '')
328
357
  // params.b = null
329
358
  // is(el.innerHTML, '')
@@ -358,10 +387,13 @@ test('each: loop with condition', async () => {
358
387
 
359
388
  is(el.innerHTML, '')
360
389
  params.c = true
390
+ await tick()
361
391
  is(el.innerHTML, '<span>1</span><span>2</span>')
362
392
  params.b = [1]
393
+ await tick()
363
394
  is(el.innerHTML, '<span>1</span>')
364
395
  params.b = null
396
+ await tick()
365
397
  is(el.innerHTML, '')
366
398
  })
367
399
 
@@ -375,13 +407,17 @@ test('each: condition with loop', async () => {
375
407
 
376
408
  is(el.innerHTML, '<span>false</span>')
377
409
  params.c = true
410
+ await tick()
378
411
  is(el.innerHTML, '<span>1</span><span>2</span>')
379
412
  params.b = [1]
413
+ await tick()
380
414
  is(el.innerHTML, '<span>1</span>')
381
415
  params.b = null
416
+ await tick()
382
417
  is(el.innerHTML, '')
383
418
  console.log('c=false')
384
419
  params.c = false
420
+ await tick()
385
421
  is(el.innerHTML, '<span>false</span>')
386
422
  })
387
423
 
@@ -395,8 +431,10 @@ test('each: loop within condition', async () => {
395
431
 
396
432
  is(el.innerHTML, '<x><y>1</y></x>')
397
433
  params.a = 2
434
+ await tick()
398
435
  is(el.innerHTML, '<x><y>-1</y><y>-2</y></x>')
399
436
  params.a = 0
437
+ await tick()
400
438
  is(el.innerHTML, '')
401
439
  })
402
440
 
@@ -413,14 +451,16 @@ test('each: condition within loop', async () => {
413
451
 
414
452
  is(el.innerHTML, '<x><y>1:1</y></x><x><y>2:2</y></x><x><y>3</y></x>')
415
453
  params.b = [2]
454
+ await tick()
416
455
  is(el.innerHTML, '<x><y>2:2</y></x>')
417
456
  params.b = null
457
+ await tick()
418
458
  is(el.innerHTML, '')
419
459
  })
420
460
 
421
461
  test('each: next items have own "this", not single one', async () => {
422
462
  // FIXME: let el = h`<x :each="x in 3"></x>`
423
- let el = h`<div><x :each="x in 3" :data="{x}" :x="log.push(x, this.dataset.x)"></x></div>`
463
+ let el = h`<div><x :each="x in 3" :data-x="x" :x="log.push(x, this.dataset.x)"></x></div>`
424
464
  let log = []
425
465
  let state = sprae(el, {log})
426
466
  is(state.log, [1,'1',2,'2',3,'3'])
@@ -433,9 +473,11 @@ test('each: unkeyed', async () => {
433
473
  is(el.textContent, '123')
434
474
  // let first = el.firstChild
435
475
  state.xs = [1,3,2]
476
+ await tick()
436
477
  // is(el.firstChild, first)
437
478
  is(el.textContent, '132')
438
479
  state.xs = [3,3,3]
480
+ await tick()
439
481
  is(el.textContent, '333')
440
482
  // is(el.firstChild, first)
441
483
  })
@@ -448,9 +490,11 @@ test('each: keyed', async () => {
448
490
  is(el.textContent, '123')
449
491
  let first = el.firstChild
450
492
  state.xs = [1,3,2]
493
+ await tick()
451
494
  is(el.firstChild, first)
452
495
  is(el.textContent, '132')
453
496
  state.xs = [3,3,3]
497
+ await tick()
454
498
  is(el.textContent, '3')
455
499
  // is(el.firstChild, first)
456
500
  })
@@ -465,18 +509,21 @@ test('each: unmounted elements remove listeners', async () => {
465
509
  // let's hope they get removed without memory leaks :')
466
510
  })
467
511
 
468
- test('each: internal children get updated by state update, also: update by running again', () => {
512
+ test('each: internal children get updated by state update, also: update by running again', async () => {
469
513
  let el = h`<><x :each="item, idx in items" :text="item" :key="idx"></x></>`
470
514
  let state = sprae(el, { items: [1,2,3] })
471
515
  is(el.textContent, '123')
472
516
  state.items = [2, 2, 3]
517
+ await tick()
473
518
  is(el.textContent, '223')
474
519
  state = sprae(el, { items: [0,2,3] })
520
+ await tick()
475
521
  is(el.textContent, '023')
476
522
  // NOTE: this doesn't update items, since they're new array
477
523
  console.log('set items')
478
524
  state.items[0] = 1
479
- state.items = [...state.items]
525
+ // state.items = [...state.items]
526
+ await tick()
480
527
  is(el.textContent, '123')
481
528
  })
482
529
 
@@ -499,7 +546,7 @@ test('each: key-based caching is in-sync with direct elements', () => {
499
546
  is(el.outerHTML, el2.outerHTML)
500
547
  })
501
548
 
502
- test('on: base', () => {
549
+ test('on: base', async () => {
503
550
  let el = h`<div :on="{click(e){log.push('click')}, x}"></div>`
504
551
  let log = []
505
552
  let params = sprae(el, {x(){log.push('x')}, log})
@@ -511,11 +558,13 @@ test('on: base', () => {
511
558
  is(log, ['click','x'])
512
559
 
513
560
  params.x = function(){log.push('xx')}
561
+ await tick()
514
562
  el.dispatchEvent(new window.Event('x'));
515
563
  is(log, ['click','x','xx']);
516
564
 
517
565
  console.log('make null')
518
566
  params.x = null;
567
+ await tick()
519
568
  el.dispatchEvent(new window.Event('x'));
520
569
  is(log, ['click','x','xx']);
521
570
  })
@@ -632,7 +681,7 @@ test('on: parallel chains', e => {
632
681
  is(state.log, ['x','x','y','y','z','z','x']);
633
682
  })
634
683
 
635
- test('on: state changes between chain of events', e => {
684
+ test('on: state changes between chain of events', async e => {
636
685
  let el = h`<x :on="{'x..y':fn}"></x>`
637
686
  let log = []
638
687
  let state = sprae(el, {log, fn: () => (log.push('x1'), ()=>log.push('y1'))})
@@ -641,6 +690,7 @@ test('on: state changes between chain of events', e => {
641
690
  is(log, ['x1'])
642
691
  console.log('update fn')
643
692
  state.fn = () => (log.push('x2'), () => log.push('y2'))
693
+ await tick()
644
694
  is(log, ['x1'])
645
695
  // console.log('xx')
646
696
  // NOTE: state update registers new chain listener before finishing prev chain
@@ -808,16 +858,17 @@ test('on: modifiers chain', async e => {
808
858
  is(state.log,['x', 'x'])
809
859
  })
810
860
 
811
- test('with: inline', () => {
812
- let el = h`<x :with="{foo:'bar'}"><y :text="foo + baz"></y></x>`
861
+ test('with: inline', async () => {
862
+ let el = h`<x :scope="{foo:'bar'}"><y :text="foo + baz"></y></x>`
813
863
  let state = sprae(el, {baz: 'qux'})
814
864
  // FIXME: this doesn't inherit root scope baz property and instead uses hard-initialized one
815
865
  is(el.innerHTML, `<y>barqux</y>`)
816
866
  state.baz = 'quux'
867
+ await tick()
817
868
  is(el.innerHTML, `<y>barquux</y>`)
818
869
  })
819
870
  test.skip('with: inline reactive', () => {
820
- let el = h`<x :with="{foo:'bar'}"><y :text="foo + baz"></y></x>`
871
+ let el = h`<x :scope="{foo:'bar'}"><y :text="foo + baz"></y></x>`
821
872
  let baz = signal('qux')
822
873
  sprae(el, {baz})
823
874
  // FIXME: this doesn't inherit root scope baz property and instead uses hard-initialized one
@@ -825,48 +876,53 @@ test.skip('with: inline reactive', () => {
825
876
  baz.value = 'quux'
826
877
  is(el.innerHTML, `<y>barquux</y>`)
827
878
  })
828
- test('with: data', () => {
829
- let el = h`<x :with="x"><y :text="foo"></y></x>`
879
+ test('with: data', async () => {
880
+ let el = h`<x :scope="x"><y :text="foo"></y></x>`
830
881
  let state = sprae(el, {x: {foo:'bar'}})
831
882
  is(el.innerHTML, `<y>bar</y>`)
832
883
  console.log('update', state.x)
833
884
  state.x.foo = 'baz'
885
+ await tick()
834
886
  // Object.assign(state, {x:{foo:'baz'}})
835
887
  is(el.innerHTML, `<y>baz</y>`)
836
888
  })
837
- test('with: transparency', () => {
889
+ test('with: transparency', async () => {
838
890
  // NOTE: y:text initializes through directive, not through parent
839
891
  // therefore by default :text uses parent's state, not defined by element itself
840
- let el = h`<x :with="{foo:'foo'}"><y :with="b" :text="foo+bar"></y></x>`
892
+ let el = h`<x :scope="{foo:'foo'}"><y :scope="b" :text="foo+bar"></y></x>`
841
893
  let params = sprae(el, {b:{bar:'bar'}})
842
894
  is(el.innerHTML, `<y>foobar</y>`)
843
895
  params.b.bar = 'baz'
896
+ await tick()
844
897
  is(el.innerHTML, `<y>foobaz</y>`)
845
898
  })
846
899
  test.skip('with: reactive transparency', () => {
847
- let el = h`<x :with="{foo:1}"><y :with="b.c" :text="foo+bar"></y></x>`
900
+ let el = h`<x :scope="{foo:1}"><y :scope="b.c" :text="foo+bar"></y></x>`
848
901
  const bar = signal('2')
849
902
  sprae(el, {b:{c:{bar}}})
850
903
  is(el.innerHTML, `<y>12</y>`)
851
904
  bar.value = '3'
852
905
  is(el.innerHTML, `<y>13</y>`)
853
906
  })
854
- test('with: writes to state', () => {
855
- let a = h`<x :with="{a:1}"><y :on="{x(){a++}}" :text="a"></y></x>`
907
+ test('with: writes to state', async () => {
908
+ let a = h`<x :scope="{a:1}"><y :on="{x(){a++}}" :text="a"></y></x>`
856
909
  sprae(a)
857
910
  is(a.innerHTML, `<y>1</y>`)
858
911
  a.firstChild.dispatchEvent(new window.Event('x'))
912
+ await tick()
859
913
  is(a.innerHTML, `<y>2</y>`)
860
914
  a.firstChild.dispatchEvent(new window.Event('x'))
915
+ await tick()
861
916
  is(a.innerHTML, `<y>3</y>`)
862
917
  })
863
918
 
864
- test('ref: base', () => {
919
+ test('ref: base', async () => {
865
920
  let a = h`<a :ref="a" :init="log.push(a), null" :text="b"></a>`
866
921
  let state = sprae(a, {log:[], b:1})
867
922
  is(state.log[0], a)
868
923
  is(a.outerHTML, `<a>1</a>`)
869
924
  state.b = 2
925
+ await tick()
870
926
  is(a.outerHTML, `<a>2</a>`)
871
927
  is(state.a, a, 'Exposes to the state');
872
928
  })
@@ -903,7 +959,7 @@ test(':: scope refers to current element', async () => {
903
959
 
904
960
  test(':: scope directives must come first', async () => {
905
961
  // NOTE: we init attributes in order of definition
906
- let a = h`<x :text="y" :with="{y:1}" :ref="x"></x>`
962
+ let a = h`<x :text="y" :scope="{y:1}" :ref="x"></x>`
907
963
  sprae(a, {})
908
964
  is(a.outerHTML, `<x>1</x>`)
909
965
  })
package/test/index.html CHANGED
@@ -2,6 +2,11 @@
2
2
  <meta charset=utf-8>
3
3
  <title>Test</title>
4
4
 
5
+ <script defer src="../sprae.auto.js"></script>
6
+ <div :scope="{data:1}">
7
+ <span :text="data"></span>
8
+ </div>
9
+
5
10
  <script async src="../node_modules/es-module-shims/dist/es-module-shims.js"></script>
6
11
  <script type="importmap">
7
12
  {
@@ -27,4 +32,4 @@
27
32
  }
28
33
  </script>
29
34
 
30
- <script src="./test.js" type="module"></script>
35
+ <script src="./test.js" type="module"></script>
package/test/state.js CHANGED
@@ -1,9 +1,10 @@
1
- import {state, fx, batch} from '../src/state.js'
1
+ import {state, fx} from '../src/state.js'
2
2
  import t, {is, ok} from 'tst'
3
3
  import signalStruct from 'signal-struct'
4
4
  import { effect } from '@preact/signals-core'
5
+ import {tick} from 'wait-please'
5
6
 
6
- t('state: basic', t => {
7
+ t('state: basic', async t => {
7
8
  let s = state({x:0, y:1})
8
9
 
9
10
  let xy; fx(() => xy = s.x + s.y)
@@ -12,12 +13,14 @@ t('state: basic', t => {
12
13
  s.x = 2
13
14
  console.log('set 3')
14
15
  s.y = 3
16
+ await tick()
15
17
  is(xy, 5, 'Eq')
16
18
  s.y = 4
19
+ await tick()
17
20
  is(xy, 6, 'Eq')
18
21
  })
19
22
 
20
- t('state: signal-struct basics', t => {
23
+ t('state: signal-struct basics', async t => {
21
24
  let s = state({
22
25
  x: 0,
23
26
  y: 1,
@@ -39,8 +42,10 @@ t('state: signal-struct basics', t => {
39
42
  is(xy, 1)
40
43
  s.x = 2
41
44
  s.y = 3
45
+ await tick()
42
46
  is(xy, 5)
43
47
  s.y = 4
48
+ await tick()
44
49
  is(xy, 6)
45
50
 
46
51
  // getters are computed
@@ -51,7 +56,7 @@ t('state: signal-struct basics', t => {
51
56
  is(s.xy, 6)
52
57
  })
53
58
 
54
- t('state: deep props', () => {
59
+ t('state: deep props', async () => {
55
60
  let s = state({
56
61
  z: { r: 2, i: 3 }
57
62
  })
@@ -60,17 +65,20 @@ t('state: deep props', () => {
60
65
  let len; fx(() => (len = (s.z.r**2 + s.z.i**2)**0.5))
61
66
  s.z.r = 3
62
67
  s.z.i = 4
68
+ await tick()
63
69
  is(len, 5)
64
70
  s.z.r = 4
65
71
  s.z.i = 3
72
+ await tick()
66
73
  is(len, 5)
67
74
 
68
75
  // updating internal objects/arrays turns them into signals too
69
76
  s.z = { r: 5, i: 12}
77
+ await tick()
70
78
  is(len, 13)
71
79
  })
72
80
 
73
- t('state: array', () => {
81
+ t('state: array', async () => {
74
82
  let s = state({
75
83
  w: [1,2]
76
84
  })
@@ -79,23 +87,27 @@ t('state: array', () => {
79
87
  let mult; fx(() => mult = s.w?.[0] * s.w?.[1] || 0)
80
88
  is(mult, 2)
81
89
  s.w = [3,4]
90
+ await tick()
82
91
  is(mult,12)
83
92
 
84
93
  // nullifying is fine
85
94
  s.w = null
95
+ await tick()
86
96
  is(mult, 0)
87
97
 
88
98
  // delete is fine
89
99
  delete s.w
90
100
 
101
+ await tick()
91
102
  is(mult, 0)
92
103
 
93
104
  console.log('set w')
94
105
  s.w = [1,2]
106
+ await tick()
95
107
  is(mult, 2)
96
108
  })
97
109
 
98
- t('state: bulk-update', () => {
110
+ t('state: bulk-update', async () => {
99
111
  let s = state({
100
112
  x: 0,
101
113
  y: 1,
@@ -114,6 +126,7 @@ t('state: bulk-update', () => {
114
126
  // let [signals, update] = s
115
127
  // update({ x: 1, y: 1, z: { r: 3, i: 4 } })
116
128
  Object.assign(s, { x: 1, y: 1, z: { r: 3, i: 4 } })
129
+ await tick()
117
130
  is(xy, 2)
118
131
  is(len, 5, 'len after update')
119
132
  })
@@ -178,31 +191,37 @@ t('state: inheritance', () => {
178
191
  // })
179
192
  })
180
193
 
181
- t('state: inheritance: updating values in chain', () => {
194
+ t('state: inheritance: updating values in chain', async () => {
182
195
  let s1 = {x:1}
183
196
  let s = state(s1, {y:2})
184
- console.group('fx')
197
+ // console.group('fx')
185
198
  let xy = 0; fx(() => xy = s.x + s.y);
186
- console.groupEnd('fx')
199
+ // console.groupEnd('fx')
200
+ await tick()
187
201
  is(xy, 3)
188
202
  s.x++
203
+ await tick()
189
204
  is(xy, 4)
190
205
  console.log('y++')
191
206
  s.y++
207
+ await tick()
192
208
  is(xy, 5)
193
209
  })
194
210
 
195
- t('state: array items', () => {
211
+ t('state: array items', async () => {
196
212
  // arrays get each item converted to signal struct
197
213
  let s5 = state({list: [{x:1}, {x:2}]})
198
214
  let sum; fx(()=> sum = s5.list.reduce((sum, item)=>item.x + sum, 0))
199
215
  is(sum, 3)
200
216
  s5.list[0].x = 2
217
+ await tick()
201
218
  is(sum, 4)
202
219
  console.log('set array value')
203
220
  s5.list = [{x:3}, {x:3}]
221
+ await tick()
204
222
  is(sum, 6)
205
223
  s5.list = [{x:3}, {x:3}, {x:4}]
224
+ await tick()
206
225
  is(sum, 10)
207
226
  })
208
227
 
@@ -214,14 +233,17 @@ t('state: arrays retain reference', () => {
214
233
  is(list,[1,4,3])
215
234
  })
216
235
 
217
- t('state: direct list', () => {
236
+ t('state: direct list', async () => {
218
237
  // works with arrays as well
219
238
  let list = state([{x:1}, {x:2}])
220
239
  let sum; fx(()=> sum = list.reduce((sum, item)=>item.x + sum, 0))
221
240
  is(sum, 3)
222
241
  list[0].x = 2
242
+ is(list[0].x, 2)
243
+ await tick()
223
244
  is(sum, 4)
224
245
  list.splice(0, 2, {x:3}, {x:3})
246
+ await tick()
225
247
  console.log(list)
226
248
  is(sum, 6)
227
249
  })
@@ -240,7 +262,7 @@ t('state: circular?', () => {
240
262
  is (a, [1, 2])
241
263
  })
242
264
 
243
- t('state: batch', () => {
265
+ t.skip('state: batch', () => {
244
266
  let s = state({x:1, y:2})
245
267
  let log = []; fx(() => log.push(s.x + s.y))
246
268
  is(log, [3])
package/todo.md CHANGED
@@ -8,7 +8,7 @@
8
8
  * [x] combinations: :else :if
9
9
  * [x] :each :if, :if :each
10
10
  * [x] :each :each
11
- * [x] :with must be able to write state value as well
11
+ * [x] :scope must be able to write state value as well
12
12
  * [x] docs: give example to each directive
13
13
  * [x] initialize per-element: <x :each><y :if></y><x> - tree-dependent (:each comes first).
14
14
  * [x] generalize common attributes :prop="xyz"
@@ -22,7 +22,7 @@
22
22
  * [x] bulk events :ona:onb
23
23
  * [x] multiprop setter :a:b="c"
24
24
  * [x] make `this` in expression an element
25
- * ~~[x] replace :ref with :with="this as x"~~
25
+ * ~~[x] replace :ref with :scope="this as x"~~
26
26
  * [x] :ref creates instance in current state, not creates a new state
27
27
  * [x] to avoid extending signal-struct, we must collect state data before, and call updates after for extended state
28
28
  * [x] optimization: replace element-props with direct (better) setters
@@ -31,11 +31,11 @@
31
31
  * ~~[x] report usignal problem~~ author is not really interested
32
32
  * [x] `this` doesn't refer to element/scope in event handlers
33
33
  * [x] :text="" empty values shouldn't throw
34
- * [x] implement :with
34
+ * [x] implement :scope
35
35
  * [x] update :value without losing focus / position
36
36
  * ~~[x] run tiredown if element got removed from condition or loop (free memory)~~ no need just make sure no refs to elements stored
37
37
  * [x] `sprae(el, newState)` can update element's state directly (as batch!?) -> must be tested against repeats in directives
38
- * [x] :if :ref, :if :with -> context setters must come first always
38
+ * [x] :if :ref, :if :scope -> context setters must come first always
39
39
  * [x] :style="{'--x':value}"
40
40
  * [x] :onkeydown.ctrl-alt-D
41
41
  * [ ] frameworks benchmark
@@ -46,4 +46,6 @@
46
46
  * [x] once, capture, passive
47
47
  * [x] ...rest
48
48
  * [x] parallel chains
49
- * [x] Sandbox
49
+ * [x] Sandbox
50
+ * [x] Autorun
51
+ * [ ] There's some weird bug with attaching event listeners to document, hmmm. Need test case.