sprae 6.1.1 → 6.1.2
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 +8 -1
- package/readme.md +55 -41
- package/sprae.auto.js +1 -1
- package/sprae.auto.min.js +1 -1
- package/sprae.js +1 -1
- package/sprae.min.js +1 -1
- package/src/core.js +5 -5
- package/src/directives.js +36 -37
- package/.gitattributes +0 -2
- package/.github/workflows/node.js.yml +0 -30
- package/examples/todomvc.html +0 -98
- package/r&d.md +0 -620
- package/test/attrs.js +0 -754
- package/test/events.js +0 -138
- package/test/index.html +0 -36
- package/test/register.cjs +0 -20
- package/test/state.js +0 -296
- package/test/test.js +0 -13
- package/todo.md +0 -54
package/test/attrs.js
DELETED
|
@@ -1,754 +0,0 @@
|
|
|
1
|
-
// import { signal } from 'usignal/sync'
|
|
2
|
-
import { signal } from '@preact/signals-core'
|
|
3
|
-
import test, {is, any, throws} from 'tst'
|
|
4
|
-
import {tick, time} from 'wait-please'
|
|
5
|
-
import sprae from '../src/index.js'
|
|
6
|
-
import h from 'hyperf'
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
test.skip('autoinit', async () => {
|
|
10
|
-
is(window.x.innerHTML, '1')
|
|
11
|
-
})
|
|
12
|
-
|
|
13
|
-
test('hidden: core', async () => {
|
|
14
|
-
let el = h`<div :hidden="hidden"></div>`
|
|
15
|
-
let params = sprae(el, {hidden:true})
|
|
16
|
-
is(el.outerHTML, `<div hidden=""></div>`)
|
|
17
|
-
params.hidden = false
|
|
18
|
-
await tick()
|
|
19
|
-
is(el.outerHTML, `<div></div>`)
|
|
20
|
-
})
|
|
21
|
-
|
|
22
|
-
test.skip('hidden: reactive', async () => {
|
|
23
|
-
const hidden = signal(true)
|
|
24
|
-
let el = h`<div :hidden="hidden"></div>`
|
|
25
|
-
sprae(el, {hidden})
|
|
26
|
-
is(el.outerHTML, `<div hidden=""></div>`)
|
|
27
|
-
hidden.value = false
|
|
28
|
-
is(el.outerHTML, `<div></div>`)
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
test('common: reactive', async () => {
|
|
32
|
-
let el = h`<label :for="name" :text="name" ></label><input :id="name" :name="name" :type="name" :disabled="!name"/><a :href="url"></a><img :src="url"/>`
|
|
33
|
-
let params = sprae(el, {name:'text', url:'//google.com'})
|
|
34
|
-
is(el.outerHTML, `<label for="text">text</label><input id="text" name="text" type="text"><a href="//google.com"></a><img src="//google.com">`)
|
|
35
|
-
params.name = 'email'
|
|
36
|
-
await tick()
|
|
37
|
-
is(el.outerHTML, `<label for="email">email</label><input id="email" name="email" type="email"><a href="//google.com"></a><img src="//google.com">`)
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
test('common: empty strings', async () => {
|
|
41
|
-
let el = h`<x :="" :x=""></x>`
|
|
42
|
-
sprae(el)
|
|
43
|
-
is(el.outerHTML, `<x></x>`)
|
|
44
|
-
})
|
|
45
|
-
|
|
46
|
-
test('common: comments', async () => {
|
|
47
|
-
let el = h`<x :="/* */" :x="/* */"></x>`
|
|
48
|
-
sprae(el)
|
|
49
|
-
is(el.outerHTML, `<x></x>`)
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
test('common: newlines', async () => {
|
|
53
|
-
let el = h`<x :text="
|
|
54
|
-
x
|
|
55
|
-
"></x>`
|
|
56
|
-
sprae(el, {x:1})
|
|
57
|
-
is(el.outerHTML, `<x>1</x>`)
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
test('common: const in on', async () => {
|
|
61
|
-
let el = h`<div :onx="() => {const x=1; y=x+1}"></div>`
|
|
62
|
-
let state = sprae(el, {y:0})
|
|
63
|
-
el.dispatchEvent(new CustomEvent('x'))
|
|
64
|
-
is(state.y, 2)
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
test('common: const in with', async () => {
|
|
68
|
-
let el = h`<div :with="{x(){let x = 1; y=x;}}" @x="x()"></div>`
|
|
69
|
-
let state = sprae(el,{y:0})
|
|
70
|
-
el.dispatchEvent(new CustomEvent('x'))
|
|
71
|
-
is(state.y, 1)
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
test('style', async () => {
|
|
75
|
-
let el = h`<x style="left: 1px" :style="style"></x>`
|
|
76
|
-
let params = sprae(el, {style: "top: 1px"})
|
|
77
|
-
is(el.outerHTML, `<x style="left: 1px; top: 1px"></x>`)
|
|
78
|
-
|
|
79
|
-
params.style = {top: '2px'}
|
|
80
|
-
await tick()
|
|
81
|
-
is(el.outerHTML, `<x style="left: 1px; top: 2px;"></x>`)
|
|
82
|
-
|
|
83
|
-
params.style = {'--x': 123}
|
|
84
|
-
await tick()
|
|
85
|
-
is(el.style.getPropertyValue('--x'), '123')
|
|
86
|
-
|
|
87
|
-
params.style = {top:'1px', bottom:'2px'}
|
|
88
|
-
await tick()
|
|
89
|
-
is(el.outerHTML, `<x style="left: 1px; top: 1px; bottom: 2px;"></x>`)
|
|
90
|
-
|
|
91
|
-
params.style = {top:'2px', bottom: null}
|
|
92
|
-
// FIXME
|
|
93
|
-
await tick()
|
|
94
|
-
is(el.outerHTML, `<x style="left: 1px; top: 2px;"></x>`)
|
|
95
|
-
})
|
|
96
|
-
|
|
97
|
-
test('class', async () => {
|
|
98
|
-
let el = h`<x class="base" :class="a"></x><y :class="[b, c]"></y><z :class="{b:true, c:d}"></z>`
|
|
99
|
-
const c = signal('z')
|
|
100
|
-
let params = sprae(el, {a:'x', b:'y', c, d:false});
|
|
101
|
-
is(el.outerHTML, `<x class="base x"></x><y class="y z"></y><z class="b"></z>`);
|
|
102
|
-
params.d = true;
|
|
103
|
-
await tick()
|
|
104
|
-
is(el.outerHTML, `<x class="base x"></x><y class="y z"></y><z class="b c"></z>`);
|
|
105
|
-
// c.value = 'w'
|
|
106
|
-
// is(el.outerHTML, `<x class="base x"></x><y class="y w"></y><z class="b c"></z>`);
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
test('class: undefined value', async () => {
|
|
110
|
-
let el = h`<x :class="a"></x><y :class="[b]"></y><z :class="{c}"></z>`
|
|
111
|
-
sprae(el, {a:undefined, b:undefined, c:undefined})
|
|
112
|
-
is(el.outerHTML, `<x></x><y></y><z></z>`)
|
|
113
|
-
})
|
|
114
|
-
|
|
115
|
-
test('class: old svg fun', async () => {
|
|
116
|
-
// raw html creates svganimatedstring
|
|
117
|
-
let el = document.createElement('div')
|
|
118
|
-
el.innerHTML = `<svg class="foo" :class="a ? 'x' : 'y'"></svg>`
|
|
119
|
-
|
|
120
|
-
let s = sprae(el, {a:true})
|
|
121
|
-
is(el.innerHTML, `<svg class="foo x"></svg>`)
|
|
122
|
-
s.a = false
|
|
123
|
-
await tick()
|
|
124
|
-
is(el.innerHTML, `<svg class="foo y"></svg>`)
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
test('props: base', async () => {
|
|
128
|
-
let el = h`<input :id="0" :="{for:1, title:2, help:3, type:4, placeholder: 5, value: 6, aB: 8}" :value="7"/>`
|
|
129
|
-
let params = sprae(el)
|
|
130
|
-
is(el.outerHTML, `<input id="0" for="1" title="2" help="3" type="4" placeholder="5" value="7" a-b="8">`)
|
|
131
|
-
})
|
|
132
|
-
|
|
133
|
-
test('props: sets prop', async () => {
|
|
134
|
-
let el = h`<x :x="this.x=1" :y="this.y='abc'"></x>`
|
|
135
|
-
sprae(el)
|
|
136
|
-
is(el.x, 1)
|
|
137
|
-
is(el.y, 'abc')
|
|
138
|
-
})
|
|
139
|
-
|
|
140
|
-
test('props: multiprop', async () => {
|
|
141
|
-
let el = h`<input :id:name:for="0" />`
|
|
142
|
-
let params = sprae(el)
|
|
143
|
-
is(el.outerHTML, `<input id="0" name="0" for="0">`)
|
|
144
|
-
})
|
|
145
|
-
|
|
146
|
-
test('props: calculation', async () => {
|
|
147
|
-
let el = h`<x :x="(()=>{ let a = 5; return Array.from({length: x}, (_,i)=>i).join('') })()"></x>`
|
|
148
|
-
let state = sprae(el, {x:3});
|
|
149
|
-
is(el.outerHTML, `<x x="012"></x>`)
|
|
150
|
-
state.x = 4
|
|
151
|
-
await tick()
|
|
152
|
-
is(el.outerHTML, `<x x="0123"></x>`)
|
|
153
|
-
})
|
|
154
|
-
|
|
155
|
-
test.todo('props: semicols in expression', async () => {
|
|
156
|
-
let el = h`<x :x="0; return Array.from({length: x}, (_,i)=>i).join('')"></x>`
|
|
157
|
-
let state = sprae(el, {x:3});
|
|
158
|
-
is(el.outerHTML, `<x x="012"></x>`)
|
|
159
|
-
state.x = 4
|
|
160
|
-
is(el.outerHTML, `<x x="0123"></x>`)
|
|
161
|
-
})
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
test.skip('data: base', async () => {
|
|
165
|
-
let el = h`<input :data="{a:1, fooBar:2}"/>`
|
|
166
|
-
let params = sprae(el)
|
|
167
|
-
is(el.outerHTML, `<input data-a="1" data-foo-bar="2">`)
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
test.skip('aria: base', async () => {
|
|
171
|
-
let el = h`<input type="text" id="jokes" role="combobox" :aria="{controls:'joketypes', autocomplete:'list', expanded:false, activeOption:'item1', activedescendant:'', xxx:null}"/>`
|
|
172
|
-
sprae(el)
|
|
173
|
-
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="">`)
|
|
174
|
-
})
|
|
175
|
-
|
|
176
|
-
test('value: direct', async () => {
|
|
177
|
-
let el = h`<input :value="a" />`
|
|
178
|
-
let state = sprae(el, {a:1})
|
|
179
|
-
is(el.value, '1')
|
|
180
|
-
is(el.outerHTML, `<input value="1">`)
|
|
181
|
-
state.a = 2
|
|
182
|
-
await tick()
|
|
183
|
-
is(el.value, '2')
|
|
184
|
-
is(el.outerHTML, `<input value="2">`)
|
|
185
|
-
|
|
186
|
-
el.value = 3
|
|
187
|
-
// el.dispatchEvent(new window.Event('change'))
|
|
188
|
-
// is(state.a, '3')
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
test('value: textarea', async () => {
|
|
192
|
-
let el = h`<textarea :value="a"></textarea>`
|
|
193
|
-
let state = sprae(el, {a: 'abcdefgh'})
|
|
194
|
-
is(el.selectionStart, 8)
|
|
195
|
-
is(el.selectionEnd, 8)
|
|
196
|
-
el.setSelectionRange(1, 4)
|
|
197
|
-
is(el.selectionStart, 1)
|
|
198
|
-
is(el.selectionEnd, 4)
|
|
199
|
-
state.a = 'xyzyvw'
|
|
200
|
-
is(el.selectionStart, 1)
|
|
201
|
-
is(el.selectionEnd, 4)
|
|
202
|
-
})
|
|
203
|
-
|
|
204
|
-
test('text: core', async () => {
|
|
205
|
-
let el = h`<div :text="text"></div>`
|
|
206
|
-
let params = sprae(el, {text:'abc'})
|
|
207
|
-
is(el.outerHTML, `<div>abc</div>`)
|
|
208
|
-
params.text = null
|
|
209
|
-
await tick()
|
|
210
|
-
is(el.outerHTML, `<div></div>`)
|
|
211
|
-
})
|
|
212
|
-
|
|
213
|
-
test('if: base', async () => {
|
|
214
|
-
let el = h`<p>
|
|
215
|
-
<span :if="a==1">a</span>
|
|
216
|
-
<span :else :if="a==2">b</span>
|
|
217
|
-
<span :else >c</span>
|
|
218
|
-
</p>`
|
|
219
|
-
|
|
220
|
-
const params = sprae(el, { a: 1 })
|
|
221
|
-
|
|
222
|
-
is(el.innerHTML, '<span>a</span>')
|
|
223
|
-
params.a = 2
|
|
224
|
-
await tick()
|
|
225
|
-
is(el.innerHTML, '<span>b</span>')
|
|
226
|
-
params.a = 3
|
|
227
|
-
await tick()
|
|
228
|
-
is(el.innerHTML, '<span>c</span>')
|
|
229
|
-
params.a = null
|
|
230
|
-
await tick()
|
|
231
|
-
is(el.innerHTML, '<span>c</span>')
|
|
232
|
-
})
|
|
233
|
-
|
|
234
|
-
test('if: short with insertions', async () => {
|
|
235
|
-
let el = h`<p>
|
|
236
|
-
<span :if="a==1" :text="'1:'+a"></span>
|
|
237
|
-
<span :else :if="a==2" :text="'2:'+a"></span>
|
|
238
|
-
<span :else :text="a"></span>
|
|
239
|
-
</p>`
|
|
240
|
-
|
|
241
|
-
const params = sprae(el, { a: 1 })
|
|
242
|
-
|
|
243
|
-
is(el.innerHTML, '<span>1:1</span>')
|
|
244
|
-
params.a = 2
|
|
245
|
-
await tick()
|
|
246
|
-
is(el.innerHTML, '<span>2:2</span>')
|
|
247
|
-
params.a = 3
|
|
248
|
-
await tick()
|
|
249
|
-
is(el.innerHTML, '<span>3</span>')
|
|
250
|
-
params.a = 4
|
|
251
|
-
await tick()
|
|
252
|
-
is(el.innerHTML, '<span>4</span>')
|
|
253
|
-
|
|
254
|
-
params.a = 1
|
|
255
|
-
await tick()
|
|
256
|
-
is(el.innerHTML, '<span>1:1</span>')
|
|
257
|
-
params.a = 4
|
|
258
|
-
await tick()
|
|
259
|
-
is(el.innerHTML, '<span>4</span>')
|
|
260
|
-
|
|
261
|
-
params.a = null
|
|
262
|
-
})
|
|
263
|
-
|
|
264
|
-
test.skip('if: reactive values', async () => {
|
|
265
|
-
let el = h`<p>
|
|
266
|
-
<span :if="a==1" :text="'1:'+a"></span>
|
|
267
|
-
<span :else :if="a==2" :text="'2:'+a"></span>
|
|
268
|
-
<span :else :text="a"></span>
|
|
269
|
-
</p>`
|
|
270
|
-
|
|
271
|
-
const a = signal(1)
|
|
272
|
-
sprae(el, { a })
|
|
273
|
-
|
|
274
|
-
is(el.innerHTML, '<span>1:1</span>')
|
|
275
|
-
a.value = 2
|
|
276
|
-
is(el.innerHTML, '<span>2:2</span>')
|
|
277
|
-
a.value = 3
|
|
278
|
-
is(el.innerHTML, '<span>3</span>')
|
|
279
|
-
a.value = 4
|
|
280
|
-
is(el.innerHTML, '<span>4</span>')
|
|
281
|
-
|
|
282
|
-
a.value = 1
|
|
283
|
-
is(el.innerHTML, '<span>1:1</span>')
|
|
284
|
-
a.value = 4
|
|
285
|
-
is(el.innerHTML, '<span>4</span>')
|
|
286
|
-
})
|
|
287
|
-
|
|
288
|
-
test('if: (#3) subsequent content is not abandoned', async () => {
|
|
289
|
-
let x = h`<x><y :if="!!y"></y><z :text="123"></z></x>`
|
|
290
|
-
sprae(x, {y: false})
|
|
291
|
-
is(x.outerHTML, `<x><z>123</z></x>`)
|
|
292
|
-
})
|
|
293
|
-
|
|
294
|
-
test('if: + :with doesnt prevent secondary effects from happening', async () => {
|
|
295
|
-
let el = h`<div><x :if="x" :with="{}" :text="x"></x></div>`
|
|
296
|
-
let state = sprae(el, {x:''})
|
|
297
|
-
is(el.innerHTML, ``)
|
|
298
|
-
state.x = '123'
|
|
299
|
-
await tick()
|
|
300
|
-
is(el.innerHTML, `<x>123</x>`)
|
|
301
|
-
|
|
302
|
-
// NOTE: we ignore this case
|
|
303
|
-
// let el2 = h`<div><x :if="x" :with="{x:cond}" :text="x"></x></div>`
|
|
304
|
-
// let state2 = sprae(el, {cond:''})
|
|
305
|
-
// is(el2.innerHTML, ``)
|
|
306
|
-
// state2.cond = '123'
|
|
307
|
-
// is(el2.innerHTML, `<x>123</x>`)
|
|
308
|
-
})
|
|
309
|
-
|
|
310
|
-
test('each: array', async () => {
|
|
311
|
-
// FIXME: in some conspicuous reason jsdom fails to update text nodes somehow
|
|
312
|
-
let el = h`<p>
|
|
313
|
-
<span :each="a in b" :text="a"></span>
|
|
314
|
-
</p>`
|
|
315
|
-
|
|
316
|
-
const params = sprae(el, { b: [] })
|
|
317
|
-
|
|
318
|
-
is(el.innerHTML, '')
|
|
319
|
-
console.log('set 1,2')
|
|
320
|
-
params.b = [1,2]
|
|
321
|
-
await tick()
|
|
322
|
-
is(el.innerHTML, '<span>1</span><span>2</span>')
|
|
323
|
-
params.b = []
|
|
324
|
-
await tick()
|
|
325
|
-
is(el.innerHTML, '')
|
|
326
|
-
params.b = null
|
|
327
|
-
await tick()
|
|
328
|
-
is(el.innerHTML, '')
|
|
329
|
-
})
|
|
330
|
-
|
|
331
|
-
test('each: object', async () => {
|
|
332
|
-
// FIXME: in some conspicuous reason jsdom fails to update text nodes somehow
|
|
333
|
-
let el = h`<p>
|
|
334
|
-
<span :each="x,key in b" :text="[key,x]"></span>
|
|
335
|
-
</p>`
|
|
336
|
-
|
|
337
|
-
const params = sprae(el, { b: null })
|
|
338
|
-
|
|
339
|
-
is(el.innerHTML, '')
|
|
340
|
-
console.log('set 1,2')
|
|
341
|
-
params.b = { x:1, y:2 }
|
|
342
|
-
await tick()
|
|
343
|
-
is(el.innerHTML, '<span>x,1</span><span>y,2</span>')
|
|
344
|
-
params.b = []
|
|
345
|
-
await tick()
|
|
346
|
-
is(el.innerHTML, '')
|
|
347
|
-
params.b = null
|
|
348
|
-
await tick()
|
|
349
|
-
is(el.innerHTML, '')
|
|
350
|
-
})
|
|
351
|
-
|
|
352
|
-
test('each: loop within loop', async () => {
|
|
353
|
-
let el = h`<p>
|
|
354
|
-
<x :each="b in c"><y :each="a in b" :text="a"></y></x>
|
|
355
|
-
</p>`
|
|
356
|
-
|
|
357
|
-
const params = sprae(el, { c: [[1,2], [3,4]] })
|
|
358
|
-
|
|
359
|
-
is(el.innerHTML, '<x><y>1</y><y>2</y></x><x><y>3</y><y>4</y></x>')
|
|
360
|
-
params.c = [[5,6], [3,4]]
|
|
361
|
-
await tick()
|
|
362
|
-
is(el.innerHTML, '<x><y>5</y><y>6</y></x><x><y>3</y><y>4</y></x>')
|
|
363
|
-
// params.c[1] = [7,8]
|
|
364
|
-
params.c = [params.c[0], [7,8]]
|
|
365
|
-
await tick()
|
|
366
|
-
is(el.innerHTML, '<x><y>5</y><y>6</y></x><x><y>7</y><y>8</y></x>')
|
|
367
|
-
// is(el.innerHTML, '<span>1</span><span>2</span>')
|
|
368
|
-
params.c = []
|
|
369
|
-
await tick()
|
|
370
|
-
is(el.innerHTML, '')
|
|
371
|
-
// params.b = null
|
|
372
|
-
// is(el.innerHTML, '')
|
|
373
|
-
})
|
|
374
|
-
|
|
375
|
-
test.skip('each: reactive values', async () => {
|
|
376
|
-
let el = h`<p>
|
|
377
|
-
<span :each="a in b" :text="a"></span>
|
|
378
|
-
</p>`
|
|
379
|
-
|
|
380
|
-
const b = signal([])
|
|
381
|
-
const params = sprae(el, { b })
|
|
382
|
-
|
|
383
|
-
is(el.innerHTML, '')
|
|
384
|
-
b.value = [1,2]
|
|
385
|
-
is(el.innerHTML, '<span>1</span><span>2</span>')
|
|
386
|
-
b.value = []
|
|
387
|
-
is(el.innerHTML, '')
|
|
388
|
-
params.b = null
|
|
389
|
-
is(el.innerHTML, '')
|
|
390
|
-
})
|
|
391
|
-
|
|
392
|
-
test('each: loop with condition', async () => {
|
|
393
|
-
// NOTE: there doesn't seem to be much value in exactly that
|
|
394
|
-
// also it creates confusion with :else directive
|
|
395
|
-
// prohibitin that allows in-order directives init
|
|
396
|
-
let el = h`<p>
|
|
397
|
-
<span :each="a in b" :text="a" :if="c"></span>
|
|
398
|
-
</p>`
|
|
399
|
-
|
|
400
|
-
const params = sprae(el, { b: [1,2], c: false })
|
|
401
|
-
|
|
402
|
-
is(el.innerHTML, '')
|
|
403
|
-
params.c = true
|
|
404
|
-
await tick()
|
|
405
|
-
is(el.innerHTML, '<span>1</span><span>2</span>')
|
|
406
|
-
params.b = [1]
|
|
407
|
-
await tick()
|
|
408
|
-
is(el.innerHTML, '<span>1</span>')
|
|
409
|
-
params.b = null
|
|
410
|
-
await tick()
|
|
411
|
-
is(el.innerHTML, '')
|
|
412
|
-
})
|
|
413
|
-
|
|
414
|
-
test('each: condition with loop', async () => {
|
|
415
|
-
let el = h`<p>
|
|
416
|
-
<span :if="c" :each="a in b" :text="a"></span>
|
|
417
|
-
<span :else :text="c"></span>
|
|
418
|
-
</p>`
|
|
419
|
-
|
|
420
|
-
const params = sprae(el, { b: [1,2], c: false })
|
|
421
|
-
|
|
422
|
-
is(el.innerHTML, '<span>false</span>')
|
|
423
|
-
params.c = true
|
|
424
|
-
await tick()
|
|
425
|
-
is(el.innerHTML, '<span>1</span><span>2</span>')
|
|
426
|
-
params.b = [1]
|
|
427
|
-
await tick()
|
|
428
|
-
is(el.innerHTML, '<span>1</span>')
|
|
429
|
-
params.b = null
|
|
430
|
-
await tick()
|
|
431
|
-
is(el.innerHTML, '')
|
|
432
|
-
console.log('c=false')
|
|
433
|
-
params.c = false
|
|
434
|
-
await tick()
|
|
435
|
-
is(el.innerHTML, '<span>false</span>')
|
|
436
|
-
})
|
|
437
|
-
|
|
438
|
-
test('each: loop within condition', async () => {
|
|
439
|
-
let el = h`<p>
|
|
440
|
-
<x :if="a==1"><y :each="i in a" :text="i"></y></x>
|
|
441
|
-
<x :else :if="a==2"><y :each="i in a" :text="-i"></y></x>
|
|
442
|
-
</p>`
|
|
443
|
-
|
|
444
|
-
const params = sprae(el, { a: 1 })
|
|
445
|
-
|
|
446
|
-
is(el.innerHTML, '<x><y>0</y></x>')
|
|
447
|
-
params.a = 2
|
|
448
|
-
await tick()
|
|
449
|
-
is(el.innerHTML, '<x><y>0</y><y>-1</y></x>')
|
|
450
|
-
params.a = 0
|
|
451
|
-
await tick()
|
|
452
|
-
is(el.innerHTML, '')
|
|
453
|
-
})
|
|
454
|
-
|
|
455
|
-
test('each: condition within loop', async () => {
|
|
456
|
-
let el = h`<p>
|
|
457
|
-
<x :each="a in b">
|
|
458
|
-
<y :if="a==1" :text="'1:'+a"></y>
|
|
459
|
-
<y :else :if="a==2" :text="'2:'+a"></y>
|
|
460
|
-
<y :else :text="a"></y>
|
|
461
|
-
</x>
|
|
462
|
-
</p>`
|
|
463
|
-
|
|
464
|
-
const params = sprae(el, { b: [1,2,3] })
|
|
465
|
-
|
|
466
|
-
is(el.innerHTML, '<x><y>1:1</y></x><x><y>2:2</y></x><x><y>3</y></x>')
|
|
467
|
-
params.b = [2]
|
|
468
|
-
await tick()
|
|
469
|
-
is(el.innerHTML, '<x><y>2:2</y></x>')
|
|
470
|
-
params.b = null
|
|
471
|
-
await tick()
|
|
472
|
-
is(el.innerHTML, '')
|
|
473
|
-
})
|
|
474
|
-
|
|
475
|
-
test('each: next items have own "this", not single one', async () => {
|
|
476
|
-
// FIXME: let el = h`<x :each="x in 3"></x>`
|
|
477
|
-
let el = h`<div><x :each="x in 3" :data-x="x" :x="log.push(x, this.dataset.x)"></x></div>`
|
|
478
|
-
let log = []
|
|
479
|
-
let state = sprae(el, {log})
|
|
480
|
-
is(state.log, [0,'0',1,'1',2,'2'])
|
|
481
|
-
})
|
|
482
|
-
|
|
483
|
-
test('each: unkeyed', async () => {
|
|
484
|
-
let el = h`<div><x :each="x in xs" :text="x"></x></div>`
|
|
485
|
-
let state = sprae(el, {xs:[1,2,3]})
|
|
486
|
-
is(el.children.length, 3)
|
|
487
|
-
is(el.textContent, '123')
|
|
488
|
-
// let first = el.firstChild
|
|
489
|
-
state.xs = [1,3,2]
|
|
490
|
-
await tick()
|
|
491
|
-
// is(el.firstChild, first)
|
|
492
|
-
is(el.textContent, '132')
|
|
493
|
-
state.xs = [3,3,3]
|
|
494
|
-
await tick()
|
|
495
|
-
is(el.textContent, '333')
|
|
496
|
-
// is(el.firstChild, first)
|
|
497
|
-
})
|
|
498
|
-
|
|
499
|
-
test('each: keyed', async () => {
|
|
500
|
-
// keyed
|
|
501
|
-
let el = h`<div><x :each="x in xs" :text="x" :key="x"></x></div>`
|
|
502
|
-
let state = sprae(el, {xs:[1,2,3]})
|
|
503
|
-
is(el.children.length, 3)
|
|
504
|
-
is(el.textContent, '123')
|
|
505
|
-
let first = el.firstChild
|
|
506
|
-
state.xs = [1,3,2]
|
|
507
|
-
await tick()
|
|
508
|
-
is(el.firstChild, first)
|
|
509
|
-
is(el.textContent, '132')
|
|
510
|
-
state.xs = [3,3,3]
|
|
511
|
-
await tick()
|
|
512
|
-
is(el.textContent, '3')
|
|
513
|
-
// is(el.firstChild, first)
|
|
514
|
-
})
|
|
515
|
-
|
|
516
|
-
test('each: wrapped source', async () => {
|
|
517
|
-
let el = h`<div><x :each="i in (x || 2)" :text="i"></x></div>`
|
|
518
|
-
sprae(el, {x:0})
|
|
519
|
-
is(el.innerHTML, `<x>0</x><x>1</x>`)
|
|
520
|
-
})
|
|
521
|
-
|
|
522
|
-
test('each: unmounted elements remove listeners', async () => {
|
|
523
|
-
// let's hope they get removed without memory leaks :')
|
|
524
|
-
})
|
|
525
|
-
|
|
526
|
-
test('each: internal children get updated by state update, also: update by running again', async () => {
|
|
527
|
-
let el = h`<><x :each="item, idx in items" :text="item" :key="idx"></x></>`
|
|
528
|
-
let state = sprae(el, { items: [1,2,3] })
|
|
529
|
-
is(el.textContent, '123')
|
|
530
|
-
state.items = [2, 2, 3]
|
|
531
|
-
await tick()
|
|
532
|
-
is(el.textContent, '223')
|
|
533
|
-
state = sprae(el, { items: [0,2,3] })
|
|
534
|
-
await tick()
|
|
535
|
-
is(el.textContent, '023')
|
|
536
|
-
// NOTE: this doesn't update items, since they're new array
|
|
537
|
-
console.log('set items')
|
|
538
|
-
state.items[0] = 1
|
|
539
|
-
// state.items = [...state.items]
|
|
540
|
-
await tick()
|
|
541
|
-
is(el.textContent, '123')
|
|
542
|
-
})
|
|
543
|
-
|
|
544
|
-
test('each: :id and others must receive value from context', () => {
|
|
545
|
-
let el = h`<div><x :id="idx" :each="item, idx in items"></x></div>`
|
|
546
|
-
sprae(el, {items:[1,2,3]})
|
|
547
|
-
is(el.innerHTML,`<x id="1"></x><x id="2"></x><x id="3"></x>`)
|
|
548
|
-
})
|
|
549
|
-
|
|
550
|
-
test('each: key-based caching is in-sync with direct elements', () => {
|
|
551
|
-
let el = h`<ul><li :each="i in x" :key="i" :id="i"></li></ul>`
|
|
552
|
-
let el2 = h`<ul><li :each="i in x" :id="i"></li></ul>`
|
|
553
|
-
let state = sprae(el, {x:2})
|
|
554
|
-
let state2 = sprae(el2, {x:2})
|
|
555
|
-
is(el.outerHTML, el2.outerHTML)
|
|
556
|
-
el.firstChild.after(el.firstChild.cloneNode(true))
|
|
557
|
-
el2.firstChild.after(el2.firstChild.cloneNode(true))
|
|
558
|
-
state.x = 3
|
|
559
|
-
state2.x = 3
|
|
560
|
-
is(el.outerHTML, el2.outerHTML)
|
|
561
|
-
})
|
|
562
|
-
|
|
563
|
-
test('each: with :with', () => {
|
|
564
|
-
let el = h`<ul><li :each="i in 3" :with="{x:i}" :text="x"></li></ul>`
|
|
565
|
-
sprae(el)
|
|
566
|
-
is(el.outerHTML, `<ul><li>0</li><li>1</li><li>2</li></ul>`)
|
|
567
|
-
})
|
|
568
|
-
|
|
569
|
-
test('with: inline', async () => {
|
|
570
|
-
let el = h`<x :with="{foo:'bar'}"><y :text="foo + baz"></y></x>`
|
|
571
|
-
let state = sprae(el, {baz: 'qux'})
|
|
572
|
-
// FIXME: this doesn't inherit root scope baz property and instead uses hard-initialized one
|
|
573
|
-
is(el.innerHTML, `<y>barqux</y>`)
|
|
574
|
-
state.baz = 'quux'
|
|
575
|
-
await tick()
|
|
576
|
-
is(el.innerHTML, `<y>barquux</y>`)
|
|
577
|
-
})
|
|
578
|
-
test.skip('with: inline reactive', () => {
|
|
579
|
-
let el = h`<x :with="{foo:'bar'}"><y :text="foo + baz"></y></x>`
|
|
580
|
-
let baz = signal('qux')
|
|
581
|
-
sprae(el, {baz})
|
|
582
|
-
// FIXME: this doesn't inherit root scope baz property and instead uses hard-initialized one
|
|
583
|
-
is(el.innerHTML, `<y>barqux</y>`)
|
|
584
|
-
baz.value = 'quux'
|
|
585
|
-
is(el.innerHTML, `<y>barquux</y>`)
|
|
586
|
-
})
|
|
587
|
-
test('with: data', async () => {
|
|
588
|
-
let el = h`<x :with="x"><y :text="foo"></y></x>`
|
|
589
|
-
let state = sprae(el, {x: {foo:'bar'}})
|
|
590
|
-
is(el.innerHTML, `<y>bar</y>`)
|
|
591
|
-
console.log('update', state.x)
|
|
592
|
-
state.x.foo = 'baz'
|
|
593
|
-
await tick()
|
|
594
|
-
// Object.assign(state, {x:{foo:'baz'}})
|
|
595
|
-
is(el.innerHTML, `<y>baz</y>`)
|
|
596
|
-
})
|
|
597
|
-
test('with: transparency', async () => {
|
|
598
|
-
// NOTE: y:text initializes through directive, not through parent
|
|
599
|
-
// therefore by default :text uses parent's state, not defined by element itself
|
|
600
|
-
let el = h`<x :with="{foo:'foo'}"><y :with="b" :text="foo+bar"></y></x>`
|
|
601
|
-
let params = sprae(el, {b:{bar:'bar'}})
|
|
602
|
-
is(el.innerHTML, `<y>foobar</y>`)
|
|
603
|
-
params.b.bar = 'baz'
|
|
604
|
-
await tick()
|
|
605
|
-
is(el.innerHTML, `<y>foobaz</y>`)
|
|
606
|
-
})
|
|
607
|
-
test.skip('with: reactive transparency', () => {
|
|
608
|
-
let el = h`<x :with="{foo:1}"><y :with="b.c" :text="foo+bar"></y></x>`
|
|
609
|
-
const bar = signal('2')
|
|
610
|
-
sprae(el, {b:{c:{bar}}})
|
|
611
|
-
is(el.innerHTML, `<y>12</y>`)
|
|
612
|
-
bar.value = '3'
|
|
613
|
-
is(el.innerHTML, `<y>13</y>`)
|
|
614
|
-
})
|
|
615
|
-
test('with: writes to state', async () => {
|
|
616
|
-
let a = h`<x :with="{a:1}"><y :onx="e=>a++" :text="a"></y></x>`
|
|
617
|
-
sprae(a)
|
|
618
|
-
is(a.innerHTML, `<y>1</y>`)
|
|
619
|
-
a.firstChild.dispatchEvent(new window.Event('x'))
|
|
620
|
-
await tick()
|
|
621
|
-
is(a.innerHTML, `<y>2</y>`)
|
|
622
|
-
a.firstChild.dispatchEvent(new window.Event('x'))
|
|
623
|
-
await tick()
|
|
624
|
-
is(a.innerHTML, `<y>3</y>`)
|
|
625
|
-
})
|
|
626
|
-
test('with: one of children (internal number of iterations, cant see the result here)', async () => {
|
|
627
|
-
let a = h `<div><x :text="x"></x><x :with={x:2} :text="x"></x><x :text="y">3</x></div>`
|
|
628
|
-
sprae(a, {x:1,y:3})
|
|
629
|
-
is(a.innerHTML,`<x>1</x><x>2</x><x>3</x>`)
|
|
630
|
-
})
|
|
631
|
-
|
|
632
|
-
test(':render by ref', async () => {
|
|
633
|
-
let a = h`<template :ref="abc"><div :text="123"></div></template><x :render="abc">456</x>`
|
|
634
|
-
sprae(a)
|
|
635
|
-
is(a.outerHTML, `<template><div :text="123"></div></template><x><div>123</div></x>`)
|
|
636
|
-
})
|
|
637
|
-
|
|
638
|
-
test(':render state', async () => {
|
|
639
|
-
let a = h`<template :ref="abc"><div :text="text"></div></template><x :render="abc" />`
|
|
640
|
-
let state = sprae(a, {text:'abc'})
|
|
641
|
-
is(a.outerHTML, `<template><div :text="text"></div></template><x><div>abc</div></x>`)
|
|
642
|
-
state.text = 'def'
|
|
643
|
-
await tick()
|
|
644
|
-
is(a.outerHTML, `<template><div :text="text"></div></template><x><div>def</div></x>`)
|
|
645
|
-
})
|
|
646
|
-
|
|
647
|
-
test(':render :with', async () => {
|
|
648
|
-
let a = h`<template :ref="tpl"><div :text="text"></div></template><x :render="tpl" :with="{text:'abc'}" />`
|
|
649
|
-
let state = sprae(a)
|
|
650
|
-
is(a.outerHTML, `<template><div :text="text"></div></template><x><div>abc</div></x>`)
|
|
651
|
-
})
|
|
652
|
-
|
|
653
|
-
test(':render nested items', async () => {
|
|
654
|
-
let el = h`<template :ref="tpl"><div :each="item in items" :text="item.id"></div></template><x :render="tpl" :with="{items:[{id:'a'},{id:'b'}]}" />`
|
|
655
|
-
let state = sprae(el)
|
|
656
|
-
is(el.outerHTML, `<template><div :each="item in items" :text="item.id"></div></template><x><div>a</div><div>b</div></x>`)
|
|
657
|
-
})
|
|
658
|
-
|
|
659
|
-
test.todo(':render template after use', async () => {
|
|
660
|
-
let a = h`<x :render="tpl" :with="{text:'abc'}" /><template :ref="tpl"><div :text="text"></div></template>`
|
|
661
|
-
let state = sprae(a)
|
|
662
|
-
is(a.outerHTML, `<x><div>abc</div></x><template><div :text="text"></div></template>`)
|
|
663
|
-
})
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
test('ref: base', async () => {
|
|
667
|
-
let a = h`<a :ref="a" :init="log.push(a), null" :text="b"></a>`
|
|
668
|
-
let state = sprae(a, {log:[], b:1})
|
|
669
|
-
is(state.log[0], a)
|
|
670
|
-
is(a.outerHTML, `<a>1</a>`)
|
|
671
|
-
state.b = 2
|
|
672
|
-
await tick()
|
|
673
|
-
is(a.outerHTML, `<a>2</a>`)
|
|
674
|
-
is(state.a, a, 'Exposes to the state');
|
|
675
|
-
})
|
|
676
|
-
|
|
677
|
-
test('ref: with :each', () => {
|
|
678
|
-
let a = h`<y><x :ref="x" :each="item in items" :text="log.push(x), item"/></y>`
|
|
679
|
-
let state = sprae(a, {log: [], items: [1,2]})
|
|
680
|
-
is(a.innerHTML, `<x>1</x><x>2</x>`)
|
|
681
|
-
is(state.log, [...a.children])
|
|
682
|
-
})
|
|
683
|
-
|
|
684
|
-
test.skip(':: reactive values', async () => {
|
|
685
|
-
let a = new Promise((ok) => setTimeout(() => ok(2), 10))
|
|
686
|
-
|
|
687
|
-
let el = h`<x :text="a">1</x>`
|
|
688
|
-
sprae(el, {a})
|
|
689
|
-
is(el.outerHTML, `<x></x>`)
|
|
690
|
-
|
|
691
|
-
await time(20)
|
|
692
|
-
is(el.outerHTML, `<x>2</x>`)
|
|
693
|
-
})
|
|
694
|
-
|
|
695
|
-
test(':: null result does nothing', async () => {
|
|
696
|
-
let a = h`<x :="undefined"></x>`
|
|
697
|
-
sprae(a)
|
|
698
|
-
is(a.outerHTML, `<x></x>`)
|
|
699
|
-
})
|
|
700
|
-
|
|
701
|
-
test(':: scope refers to current element', async () => {
|
|
702
|
-
let el = h`<x :text="log.push(this)"></x>`
|
|
703
|
-
let state = sprae(el, {log:[]})
|
|
704
|
-
is(state.log, [el])
|
|
705
|
-
})
|
|
706
|
-
|
|
707
|
-
test(':: scope directives must come first', async () => {
|
|
708
|
-
// NOTE: we init attributes in order of definition
|
|
709
|
-
let a = h`<x :text="y" :with="{y:1}" :ref="x"></x>`
|
|
710
|
-
sprae(a, {})
|
|
711
|
-
is(a.outerHTML, `<x>1</x>`)
|
|
712
|
-
})
|
|
713
|
-
|
|
714
|
-
test.todo('immediate scope', async () => {
|
|
715
|
-
let el = h`<x :with="{arr:[], inc(){ arr.push(1) }}" :onx="e=>inc()" :text="arr[0]"></x>`
|
|
716
|
-
sprae(el)
|
|
717
|
-
is(el.outerHTML, `<x></x>`)
|
|
718
|
-
el.dispatchEvent(new CustomEvent('x'))
|
|
719
|
-
await tick()
|
|
720
|
-
is(el.outerHTML, `<x>1</x>`)
|
|
721
|
-
})
|
|
722
|
-
|
|
723
|
-
test('getters', async () => {
|
|
724
|
-
let x = h`<h2 :text="doubledCount >= 1 ? 1 : 0"></h2>`
|
|
725
|
-
let state = sprae(x, {
|
|
726
|
-
count:0,
|
|
727
|
-
get doubledCount(){ return this.count * 2 }
|
|
728
|
-
})
|
|
729
|
-
is(x.outerHTML, `<h2>0</h2>`)
|
|
730
|
-
state.count++
|
|
731
|
-
await tick()
|
|
732
|
-
is(x.outerHTML, `<h2>1</h2>`)
|
|
733
|
-
})
|
|
734
|
-
|
|
735
|
-
test('sandbox', async () => {
|
|
736
|
-
let el = h`<x :x="log.push(typeof self, typeof console, typeof arguments, typeof __scope)"></x>`
|
|
737
|
-
let log = []
|
|
738
|
-
sprae(el.cloneNode(), {log})
|
|
739
|
-
is(log, ['undefined', 'object', 'undefined', 'undefined'])
|
|
740
|
-
|
|
741
|
-
log.splice(0)
|
|
742
|
-
Object.assign(sprae.globals, { self: window })
|
|
743
|
-
sprae(el.cloneNode(), {log})
|
|
744
|
-
is(log, ['object', 'object', 'undefined', 'undefined'])
|
|
745
|
-
})
|
|
746
|
-
|
|
747
|
-
test('subscribe to array length', async () => {
|
|
748
|
-
let el = h`<div :with="{likes:[]}"><x :onx="e=>likes.push(1)"></x><y :text="likes.length"></y></div>`
|
|
749
|
-
sprae(el)
|
|
750
|
-
is(el.innerHTML, `<x></x><y>0</y>`)
|
|
751
|
-
el.firstChild.dispatchEvent(new CustomEvent('x'))
|
|
752
|
-
await tick()
|
|
753
|
-
is(el.innerHTML, `<x></x><y>1</y>`)
|
|
754
|
-
})
|