sprae 1.0.0 → 2.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/.github/workflows/node.js.yml +30 -0
- package/package.json +7 -2
- package/plan.md +20 -6
- package/r&d.md +60 -9
- package/readme.md +121 -72
- package/sprae.js +644 -252
- package/sprae.min.js +1 -1
- package/src/core.js +30 -102
- package/src/directives.js +235 -0
- package/src/index.js +1 -1
- package/test/index.html +5 -2
- package/test/test.js +148 -71
- package/src/directives/aria.js +0 -10
- package/src/directives/common.js +0 -15
- package/src/directives/data.js +0 -10
- package/src/directives/if.js +0 -31
- package/src/directives/index.js +0 -11
- package/src/directives/on.js +0 -12
- package/src/directives/prop.js +0 -10
- package/src/directives/text.js +0 -10
- package/src/directives/value.js +0 -26
- package/src/directives/with.js +0 -21
package/test/test.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { signal } from '
|
|
1
|
+
// import { signal } from 'usignal'
|
|
2
|
+
import { signal } from '@preact/signals-core'
|
|
2
3
|
import test, {is, any, throws} from 'tst'
|
|
3
4
|
import {tick, time} from 'wait-please'
|
|
4
5
|
import sprae from '../src/index.js'
|
|
@@ -21,34 +22,34 @@ test.skip('autoinit', async () => {
|
|
|
21
22
|
test('hidden: core', async () => {
|
|
22
23
|
let el = h`<div :hidden="hidden"></div>`
|
|
23
24
|
let params = sprae(el, {hidden:true})
|
|
24
|
-
is(el.outerHTML, `<div
|
|
25
|
+
is(el.outerHTML, `<div hidden=""></div>`)
|
|
25
26
|
params.hidden = false
|
|
26
|
-
is(el.outerHTML, `<div
|
|
27
|
+
is(el.outerHTML, `<div></div>`)
|
|
27
28
|
})
|
|
28
29
|
|
|
29
30
|
test('hidden: reactive', async () => {
|
|
30
31
|
const hidden = signal(true)
|
|
31
32
|
let el = h`<div :hidden="hidden"></div>`
|
|
32
33
|
sprae(el, {hidden})
|
|
33
|
-
is(el.outerHTML, `<div
|
|
34
|
+
is(el.outerHTML, `<div hidden=""></div>`)
|
|
34
35
|
hidden.value = false
|
|
35
|
-
is(el.outerHTML, `<div
|
|
36
|
+
is(el.outerHTML, `<div></div>`)
|
|
36
37
|
})
|
|
37
38
|
|
|
38
39
|
test('common: reactive', async () => {
|
|
39
40
|
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"/>`
|
|
40
41
|
let params = sprae(el, {name:'text', url:'//google.com'})
|
|
41
|
-
is(el.outerHTML, `<label
|
|
42
|
+
is(el.outerHTML, `<label for="text">text</label><input id="text" name="text" type="text"><a href="//google.com"></a><img src="//google.com">`)
|
|
42
43
|
params.name = 'email'
|
|
43
|
-
is(el.outerHTML, `<label
|
|
44
|
+
is(el.outerHTML, `<label for="email">email</label><input id="email" name="email" type="email"><a href="//google.com"></a><img src="//google.com">`)
|
|
44
45
|
})
|
|
45
46
|
|
|
46
47
|
test('common: style', async () => {
|
|
47
48
|
let el = h`<x :style="style"></x>`
|
|
48
49
|
let params = sprae(el, {style: "top: 1px"})
|
|
49
|
-
is(el.outerHTML, `<x
|
|
50
|
+
is(el.outerHTML, `<x style="top: 1px"></x>`)
|
|
50
51
|
params.style = {top: '2px'}
|
|
51
|
-
is(el.outerHTML, `<x
|
|
52
|
+
is(el.outerHTML, `<x style="top: 2px"></x>`)
|
|
52
53
|
})
|
|
53
54
|
|
|
54
55
|
test('common: class', async () => {
|
|
@@ -62,111 +63,111 @@ test('common: class', async () => {
|
|
|
62
63
|
is(el.outerHTML, `<x class="x"></x><y class="y w"></y><z class="b c"></z>`);
|
|
63
64
|
})
|
|
64
65
|
|
|
65
|
-
test('props: base', async () => {
|
|
66
|
-
let el = h`<input :
|
|
66
|
+
test('spread props: base', async () => {
|
|
67
|
+
let el = h`<input :id="0" :="{for:1, title:2, help:3, type:4, placeholder: 5, value: 6}" :value="7"/>`
|
|
67
68
|
let params = sprae(el)
|
|
68
|
-
is(el.outerHTML, `<input
|
|
69
|
+
is(el.outerHTML, `<input id="0" for="1" title="2" help="3" type="4" placeholder="5" value="7">`)
|
|
69
70
|
})
|
|
70
71
|
|
|
71
72
|
test('data: base', async () => {
|
|
72
73
|
let el = h`<input :data="{a:1, fooBar:2}"/>`
|
|
73
74
|
let params = sprae(el)
|
|
74
|
-
is(el.outerHTML, `<input
|
|
75
|
+
is(el.outerHTML, `<input data-a="1" data-foo-bar="2">`)
|
|
75
76
|
})
|
|
76
77
|
|
|
77
78
|
test('aria: base', async () => {
|
|
78
|
-
let el = h`<input type="text" id="jokes" role="combobox" :aria="{controls:'joketypes', autocomplete:'list', expanded:false, activeOption:'item1', activedescendant:''}"/>`
|
|
79
|
+
let el = h`<input type="text" id="jokes" role="combobox" :aria="{controls:'joketypes', autocomplete:'list', expanded:false, activeOption:'item1', activedescendant:'', xxx:null}"/>`
|
|
79
80
|
sprae(el)
|
|
80
|
-
is(el.outerHTML, `<input type="text" id="jokes" role="combobox"
|
|
81
|
+
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="">`)
|
|
81
82
|
})
|
|
82
83
|
|
|
83
|
-
test('
|
|
84
|
+
test('value: direct', async () => {
|
|
84
85
|
let el = h`<input :value="a" />`
|
|
85
86
|
let state = sprae(el, {a:1})
|
|
86
87
|
is(el.value, '1')
|
|
87
|
-
is(el.outerHTML, `<input
|
|
88
|
+
is(el.outerHTML, `<input value="1">`)
|
|
88
89
|
state.a = 2
|
|
89
90
|
is(el.value, '2')
|
|
90
|
-
is(el.outerHTML, `<input
|
|
91
|
+
is(el.outerHTML, `<input value="2">`)
|
|
91
92
|
|
|
92
93
|
el.value = 3
|
|
93
|
-
el.dispatchEvent(new window.Event('change'))
|
|
94
|
-
is(state.a, '3')
|
|
94
|
+
// el.dispatchEvent(new window.Event('change'))
|
|
95
|
+
// is(state.a, '3')
|
|
95
96
|
})
|
|
96
97
|
|
|
97
98
|
test('text: core', async () => {
|
|
98
99
|
let el = h`<div :text="text"></div>`
|
|
99
100
|
let params = sprae(el, {text:'abc'})
|
|
100
|
-
is(el.outerHTML, `<div
|
|
101
|
+
is(el.outerHTML, `<div>abc</div>`)
|
|
101
102
|
params.text = null
|
|
102
|
-
is(el.outerHTML, `<div
|
|
103
|
+
is(el.outerHTML, `<div></div>`)
|
|
103
104
|
})
|
|
104
105
|
|
|
105
106
|
test('conditions: base', async () => {
|
|
106
107
|
let el = h`<p>
|
|
107
108
|
<span :if="a==1">a</span>
|
|
108
|
-
<span :else
|
|
109
|
+
<span :else :if="a==2">b</span>
|
|
109
110
|
<span :else >c</span>
|
|
110
111
|
</p>`
|
|
111
112
|
|
|
112
113
|
const params = sprae(el, { a: 1 })
|
|
113
114
|
|
|
114
|
-
is(el.innerHTML, '<span
|
|
115
|
+
is(el.innerHTML, '<span>a</span>')
|
|
115
116
|
params.a = 2
|
|
116
|
-
is(el.innerHTML, '<span
|
|
117
|
+
is(el.innerHTML, '<span>b</span>')
|
|
117
118
|
params.a = 3
|
|
118
|
-
is(el.innerHTML, '<span
|
|
119
|
-
|
|
120
|
-
|
|
119
|
+
is(el.innerHTML, '<span>c</span>')
|
|
120
|
+
params.a = null
|
|
121
|
+
is(el.innerHTML, '<span>c</span>')
|
|
121
122
|
})
|
|
122
123
|
|
|
123
124
|
test('conditions: short with insertions', async () => {
|
|
124
125
|
let el = h`<p>
|
|
125
126
|
<span :if="a==1" :text="'1:'+a"></span>
|
|
126
|
-
<span :else
|
|
127
|
+
<span :else :if="a==2" :text="'2:'+a"></span>
|
|
127
128
|
<span :else :text="a"></span>
|
|
128
129
|
</p>`
|
|
129
130
|
|
|
130
131
|
const params = sprae(el, { a: 1 })
|
|
131
132
|
|
|
132
|
-
is(el.innerHTML, '<span
|
|
133
|
+
is(el.innerHTML, '<span>1:1</span>')
|
|
133
134
|
params.a = 2
|
|
134
|
-
is(el.innerHTML, '<span
|
|
135
|
+
is(el.innerHTML, '<span>2:2</span>')
|
|
135
136
|
params.a = 3
|
|
136
|
-
is(el.innerHTML, '<span
|
|
137
|
+
is(el.innerHTML, '<span>3</span>')
|
|
137
138
|
params.a = 4
|
|
138
|
-
is(el.innerHTML, '<span
|
|
139
|
+
is(el.innerHTML, '<span>4</span>')
|
|
139
140
|
|
|
140
141
|
params.a = 1
|
|
141
|
-
is(el.innerHTML, '<span
|
|
142
|
+
is(el.innerHTML, '<span>1:1</span>')
|
|
142
143
|
params.a = 4
|
|
143
|
-
is(el.innerHTML, '<span
|
|
144
|
+
is(el.innerHTML, '<span>4</span>')
|
|
144
145
|
|
|
145
|
-
|
|
146
|
+
params.a = null
|
|
146
147
|
})
|
|
147
148
|
|
|
148
149
|
test('conditions: reactive values', async () => {
|
|
149
150
|
let el = h`<p>
|
|
150
151
|
<span :if="a==1" :text="'1:'+a"></span>
|
|
151
|
-
<span :else
|
|
152
|
+
<span :else :if="a==2" :text="'2:'+a"></span>
|
|
152
153
|
<span :else :text="a"></span>
|
|
153
154
|
</p>`
|
|
154
155
|
|
|
155
156
|
const a = signal(1)
|
|
156
157
|
sprae(el, { a })
|
|
157
158
|
|
|
158
|
-
is(el.innerHTML, '<span
|
|
159
|
+
is(el.innerHTML, '<span>1:1</span>')
|
|
159
160
|
a.value = 2
|
|
160
|
-
is(el.innerHTML, '<span
|
|
161
|
+
is(el.innerHTML, '<span>2:2</span>')
|
|
161
162
|
a.value = 3
|
|
162
|
-
is(el.innerHTML, '<span
|
|
163
|
+
is(el.innerHTML, '<span>3</span>')
|
|
163
164
|
a.value = 4
|
|
164
|
-
is(el.innerHTML, '<span
|
|
165
|
+
is(el.innerHTML, '<span>4</span>')
|
|
165
166
|
|
|
166
167
|
a.value = 1
|
|
167
|
-
is(el.innerHTML, '<span
|
|
168
|
+
is(el.innerHTML, '<span>1:1</span>')
|
|
168
169
|
a.value = 4
|
|
169
|
-
is(el.innerHTML, '<span
|
|
170
|
+
is(el.innerHTML, '<span>4</span>')
|
|
170
171
|
})
|
|
171
172
|
|
|
172
173
|
|
|
@@ -179,12 +180,34 @@ test('each: base', async () => {
|
|
|
179
180
|
const params = sprae(el, { b: [] })
|
|
180
181
|
|
|
181
182
|
is(el.innerHTML, '')
|
|
183
|
+
console.log('set 1,2')
|
|
182
184
|
params.b = [1,2]
|
|
183
|
-
is(el.innerHTML, '<span
|
|
185
|
+
is(el.innerHTML, '<span>1</span><span>2</span>')
|
|
184
186
|
params.b = []
|
|
185
187
|
is(el.innerHTML, '')
|
|
186
|
-
|
|
188
|
+
params.b = null
|
|
189
|
+
is(el.innerHTML, '')
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
test('each: loop within loop', async () => {
|
|
193
|
+
let el = h`<p>
|
|
194
|
+
<x :each="b in c"><y :each="a in b" :text="a"></y></x>
|
|
195
|
+
</p>`
|
|
196
|
+
|
|
197
|
+
const params = sprae(el, { c: [[1,2], [3,4]] })
|
|
198
|
+
|
|
199
|
+
is(el.innerHTML, '<x><y>1</y><y>2</y></x><x><y>3</y><y>4</y></x>')
|
|
200
|
+
// console.log('set 1,2')
|
|
201
|
+
params.c = [[5,6], [3,4]]
|
|
202
|
+
is(el.innerHTML, '<x><y>5</y><y>6</y></x><x><y>3</y><y>4</y></x>')
|
|
203
|
+
// params.c[1] = [7,8]
|
|
204
|
+
params.c = [params.c[0], [7,8]]
|
|
205
|
+
is(el.innerHTML, '<x><y>5</y><y>6</y></x><x><y>7</y><y>8</y></x>')
|
|
206
|
+
// is(el.innerHTML, '<span>1</span><span>2</span>')
|
|
207
|
+
params.c = []
|
|
187
208
|
is(el.innerHTML, '')
|
|
209
|
+
// params.b = null
|
|
210
|
+
// is(el.innerHTML, '')
|
|
188
211
|
})
|
|
189
212
|
|
|
190
213
|
test('each: reactive values', async () => {
|
|
@@ -197,10 +220,10 @@ test('each: reactive values', async () => {
|
|
|
197
220
|
|
|
198
221
|
is(el.innerHTML, '')
|
|
199
222
|
b.value = [1,2]
|
|
200
|
-
is(el.innerHTML, '<span
|
|
223
|
+
is(el.innerHTML, '<span>1</span><span>2</span>')
|
|
201
224
|
b.value = []
|
|
202
225
|
is(el.innerHTML, '')
|
|
203
|
-
|
|
226
|
+
params.b = null
|
|
204
227
|
is(el.innerHTML, '')
|
|
205
228
|
})
|
|
206
229
|
|
|
@@ -209,28 +232,48 @@ test('each: loop with condition', async () => {
|
|
|
209
232
|
<span :each="a in b" :text="a" :if="c"></span>
|
|
210
233
|
</p>`
|
|
211
234
|
|
|
212
|
-
const params = sprae(el, { b: [1,2], c:false })
|
|
235
|
+
const params = sprae(el, { b: [1,2], c: false })
|
|
213
236
|
|
|
214
237
|
is(el.innerHTML, '')
|
|
215
238
|
params.c = true
|
|
216
|
-
is(el.innerHTML, '<span
|
|
239
|
+
is(el.innerHTML, '<span>1</span><span>2</span>')
|
|
240
|
+
params.b = [1]
|
|
241
|
+
is(el.innerHTML, '<span>1</span>')
|
|
242
|
+
params.b = null
|
|
243
|
+
is(el.innerHTML, '')
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
test('each: condition with loop', async () => {
|
|
247
|
+
let el = h`<p>
|
|
248
|
+
<span :if="c" :each="a in b" :text="a"></span>
|
|
249
|
+
<span :else :text="c"></span>
|
|
250
|
+
</p>`
|
|
251
|
+
|
|
252
|
+
const params = sprae(el, { b: [1,2], c: false })
|
|
253
|
+
|
|
254
|
+
is(el.innerHTML, '<span>false</span>')
|
|
255
|
+
params.c = true
|
|
256
|
+
is(el.innerHTML, '<span>1</span><span>2</span>')
|
|
217
257
|
params.b = [1]
|
|
218
|
-
is(el.innerHTML, '<span
|
|
219
|
-
|
|
258
|
+
is(el.innerHTML, '<span>1</span>')
|
|
259
|
+
params.b = null
|
|
220
260
|
is(el.innerHTML, '')
|
|
261
|
+
console.log('c=false')
|
|
262
|
+
params.c = false
|
|
263
|
+
is(el.innerHTML, '<span>false</span>')
|
|
221
264
|
})
|
|
222
265
|
|
|
223
266
|
test('each: loop within condition', async () => {
|
|
224
267
|
let el = h`<p>
|
|
225
268
|
<x :if="a==1"><y :each="i in a" :text="i"></y></x>
|
|
226
|
-
<x :else
|
|
269
|
+
<x :else :if="a==2"><y :each="i in a" :text="-i"></y></x>
|
|
227
270
|
</p>`
|
|
228
271
|
|
|
229
272
|
const params = sprae(el, { a: 1 })
|
|
230
273
|
|
|
231
|
-
is(el.innerHTML, '<x
|
|
274
|
+
is(el.innerHTML, '<x><y>1</y></x>')
|
|
232
275
|
params.a = 2
|
|
233
|
-
is(el.innerHTML, '<x
|
|
276
|
+
is(el.innerHTML, '<x><y>-1</y><y>-2</y></x>')
|
|
234
277
|
params.a = 0
|
|
235
278
|
is(el.innerHTML, '')
|
|
236
279
|
})
|
|
@@ -239,17 +282,17 @@ test('each: condition within loop', async () => {
|
|
|
239
282
|
let el = h`<p>
|
|
240
283
|
<x :each="a in b">
|
|
241
284
|
<y :if="a==1" :text="'1:'+a"></y>
|
|
242
|
-
<y :else
|
|
285
|
+
<y :else :if="a==2" :text="'2:'+a"></y>
|
|
243
286
|
<y :else :text="a"></y>
|
|
244
287
|
</x>
|
|
245
288
|
</p>`
|
|
246
289
|
|
|
247
290
|
const params = sprae(el, { b: [1,2,3] })
|
|
248
291
|
|
|
249
|
-
is(el.innerHTML, '<x
|
|
292
|
+
is(el.innerHTML, '<x><y>1:1</y></x><x><y>2:2</y></x><x><y>3</y></x>')
|
|
250
293
|
params.b = [2]
|
|
251
|
-
is(el.innerHTML, '<x
|
|
252
|
-
|
|
294
|
+
is(el.innerHTML, '<x><y>2:2</y></x>')
|
|
295
|
+
params.b = null
|
|
253
296
|
is(el.innerHTML, '')
|
|
254
297
|
})
|
|
255
298
|
|
|
@@ -258,7 +301,7 @@ test('on: base', () => {
|
|
|
258
301
|
let log = signal([])
|
|
259
302
|
let params = sprae(el, {x(){log.value.push('x')}, log})
|
|
260
303
|
|
|
261
|
-
is(el.outerHTML, `<div
|
|
304
|
+
is(el.outerHTML, `<div></div>`);
|
|
262
305
|
el.dispatchEvent(new window.Event('click'));
|
|
263
306
|
is(log.value, ['click'])
|
|
264
307
|
el.dispatchEvent(new window.Event('x'));
|
|
@@ -268,7 +311,7 @@ test('on: base', () => {
|
|
|
268
311
|
el.dispatchEvent(new window.Event('x'));
|
|
269
312
|
is(log.value, ['click','x','xx']);
|
|
270
313
|
|
|
271
|
-
|
|
314
|
+
params.x = null;
|
|
272
315
|
el.dispatchEvent(new window.Event('x'));
|
|
273
316
|
is(log.value, ['click','x','xx']);
|
|
274
317
|
})
|
|
@@ -277,27 +320,61 @@ test('with: inline', () => {
|
|
|
277
320
|
let el = h`<x :with="{foo:'bar', baz}"><y :text="foo + baz"></y></x>`
|
|
278
321
|
let state = sprae(el, {baz: 'qux'})
|
|
279
322
|
// FIXME: this doesn't inherit root scope baz property and instead uses hard-initialized one
|
|
280
|
-
is(el.innerHTML, `<y
|
|
323
|
+
is(el.innerHTML, `<y>barqux</y>`)
|
|
281
324
|
state.baz = 'quux'
|
|
282
|
-
is(el.innerHTML, `<y
|
|
325
|
+
is(el.innerHTML, `<y>barquux</y>`)
|
|
326
|
+
})
|
|
327
|
+
test('with: inline reactive', () => {
|
|
328
|
+
let el = h`<x :with="{foo:'bar', baz}"><y :text="foo + baz"></y></x>`
|
|
329
|
+
let baz = signal('qux')
|
|
330
|
+
let state = sprae(el, {baz})
|
|
331
|
+
// FIXME: this doesn't inherit root scope baz property and instead uses hard-initialized one
|
|
332
|
+
is(el.innerHTML, `<y>barqux</y>`)
|
|
333
|
+
baz.value = 'quux'
|
|
334
|
+
is(el.innerHTML, `<y>barquux</y>`)
|
|
283
335
|
})
|
|
284
336
|
test('with: data', () => {
|
|
285
337
|
let el = h`<x :with="x"><y :text="foo"></y></x>`
|
|
286
|
-
let
|
|
287
|
-
is(el.innerHTML, `<y
|
|
288
|
-
|
|
289
|
-
|
|
338
|
+
let state = sprae(el, {x:{foo:'bar'}})
|
|
339
|
+
is(el.innerHTML, `<y>bar</y>`)
|
|
340
|
+
console.log('update')
|
|
341
|
+
Object.assign(state, {x:{foo:'baz'}})
|
|
342
|
+
is(el.innerHTML, `<y>baz</y>`)
|
|
290
343
|
})
|
|
291
|
-
test('with:
|
|
344
|
+
test('with: transparency', () => {
|
|
292
345
|
// NOTE: y:text initializes through directive, not through parent
|
|
293
346
|
// therefore by default :text uses parent's state, not defined by element itself
|
|
294
347
|
let el = h`<x :with="{foo:'foo'}"><y :with="b" :text="foo+bar"></y></x>`
|
|
295
|
-
sprae(el, {b:{bar:'bar'}})
|
|
296
|
-
is(el.innerHTML, `<y
|
|
348
|
+
let params = sprae(el, {b:{bar:'bar'}})
|
|
349
|
+
is(el.innerHTML, `<y>foobar</y>`)
|
|
350
|
+
params.b.bar = 'baz'
|
|
351
|
+
is(el.innerHTML, `<y>foobaz</y>`)
|
|
297
352
|
})
|
|
298
|
-
test('with: reactive
|
|
353
|
+
test('with: reactive transparency', () => {
|
|
299
354
|
let el = h`<x :with="{foo:1}"><y :with="b.c" :text="foo+bar"></y></x>`
|
|
300
355
|
const bar = signal('2')
|
|
301
356
|
sprae(el, {b:{c:{bar}}})
|
|
302
|
-
is(el.innerHTML, `<y
|
|
357
|
+
is(el.innerHTML, `<y>12</y>`)
|
|
358
|
+
bar.value = '3'
|
|
359
|
+
is(el.innerHTML, `<y>13</y>`)
|
|
360
|
+
})
|
|
361
|
+
test('with: writes to state', () => {
|
|
362
|
+
let a = h`<x :with="{a:1}"><y :on="{x(){a++}}" :text="a"></y></x>`
|
|
363
|
+
sprae(a)
|
|
364
|
+
is(a.innerHTML, `<y>1</y>`)
|
|
365
|
+
a.firstChild.dispatchEvent(new window.Event('x'))
|
|
366
|
+
is(a.innerHTML, `<y>2</y>`)
|
|
367
|
+
a.firstChild.dispatchEvent(new window.Event('x'))
|
|
368
|
+
is(a.innerHTML, `<y>3</y>`)
|
|
369
|
+
})
|
|
370
|
+
|
|
371
|
+
test('reactives', async () => {
|
|
372
|
+
let a = new Promise((ok) => setTimeout(() => ok(2), 10))
|
|
373
|
+
|
|
374
|
+
let el = h`<x :text="a">1</x>`
|
|
375
|
+
sprae(el, {a})
|
|
376
|
+
is(el.outerHTML, `<x></x>`)
|
|
377
|
+
|
|
378
|
+
await time(20)
|
|
379
|
+
is(el.outerHTML, `<x>2</x>`)
|
|
303
380
|
})
|
package/src/directives/aria.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { directive, parseExpr } from '../core.js'
|
|
2
|
-
import { prop } from 'element-props'
|
|
3
|
-
|
|
4
|
-
directive(':aria', (el, expr) => {
|
|
5
|
-
let evaluate = parseExpr(expr);
|
|
6
|
-
return (state) => {
|
|
7
|
-
let value = evaluate(state);
|
|
8
|
-
for (let key in value) prop(el, 'aria'+key[0].toUpperCase()+key.slice(1), value[key]);
|
|
9
|
-
}
|
|
10
|
-
})
|
package/src/directives/common.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
// common directives just set/map value as is
|
|
2
|
-
import { directive, parseExpr } from '../core.js'
|
|
3
|
-
import {prop} from 'element-props'
|
|
4
|
-
|
|
5
|
-
common(`id`), common(`name`), common(`for`), common(`type`), common(`hidden`), common(`disabled`), common(`href`), common(`src`), common(`style`), common(`class`)
|
|
6
|
-
|
|
7
|
-
function common(name) {
|
|
8
|
-
directive(':'+name, (el,expr) => {
|
|
9
|
-
let evaluate = parseExpr(expr)
|
|
10
|
-
return state => {
|
|
11
|
-
let value = evaluate(state);
|
|
12
|
-
prop(el, name, value)
|
|
13
|
-
}
|
|
14
|
-
})
|
|
15
|
-
}
|
package/src/directives/data.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { directive, parseExpr } from '../core.js'
|
|
2
|
-
import { prop } from 'element-props'
|
|
3
|
-
|
|
4
|
-
directive(':data', (el, expr) => {
|
|
5
|
-
let evaluate = parseExpr(expr);
|
|
6
|
-
return (state) => {
|
|
7
|
-
let value = evaluate(state);
|
|
8
|
-
for (let key in value) el.dataset[key] = value[key];
|
|
9
|
-
}
|
|
10
|
-
})
|
package/src/directives/if.js
DELETED
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { directive, parseExpr } from '../core.js'
|
|
2
|
-
|
|
3
|
-
directive(':if', (el, expr) => {
|
|
4
|
-
let cur = el, els = [el], clauses = [parseExpr(expr)], holder = new Text
|
|
5
|
-
|
|
6
|
-
// collect clauses
|
|
7
|
-
while (cur = el.nextElementSibling) {
|
|
8
|
-
if (expr = cur.getAttribute(':else-if')) {
|
|
9
|
-
cur.removeAttribute(':else-if');
|
|
10
|
-
cur.classList.add('∴else-if')
|
|
11
|
-
cur.remove();
|
|
12
|
-
els.push(cur); clauses.push(parseExpr(expr));
|
|
13
|
-
continue
|
|
14
|
-
}
|
|
15
|
-
if (cur.hasAttribute(':else')) {
|
|
16
|
-
cur.removeAttribute(':else');
|
|
17
|
-
cur.classList.add('∴else')
|
|
18
|
-
cur.remove();
|
|
19
|
-
els.push(cur); clauses.push(() => 1);
|
|
20
|
-
}
|
|
21
|
-
break;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
cur = els[0]
|
|
25
|
-
|
|
26
|
-
return state => {
|
|
27
|
-
let idx = clauses.findIndex(match => match(state));
|
|
28
|
-
if (idx >= 0) cur.replaceWith(cur = els[idx]);
|
|
29
|
-
else cur.replaceWith(cur = holder);
|
|
30
|
-
}
|
|
31
|
-
})
|
package/src/directives/index.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
// order defines precedence
|
|
2
|
-
import './with.js'
|
|
3
|
-
import './each.js'
|
|
4
|
-
import './text.js'
|
|
5
|
-
import './if.js' // if must go last, after other directives are initialized, since it removes :else, :else-if from tree
|
|
6
|
-
import './common.js'
|
|
7
|
-
import './prop.js'
|
|
8
|
-
import './data.js'
|
|
9
|
-
import './aria.js'
|
|
10
|
-
import './value.js'
|
|
11
|
-
import './on.js'
|
package/src/directives/on.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { directive, parseExpr } from '../core.js'
|
|
2
|
-
|
|
3
|
-
directive(':on', (el, expr) => {
|
|
4
|
-
let evaluate = parseExpr(expr);
|
|
5
|
-
let listeners = {}
|
|
6
|
-
return (state) => {
|
|
7
|
-
for (let evt in listeners) el.removeEventListener(evt, listeners[evt]);
|
|
8
|
-
listeners = evaluate(state);
|
|
9
|
-
for (let evt in listeners) el.addEventListener(evt, listeners[evt]);
|
|
10
|
-
}
|
|
11
|
-
})
|
|
12
|
-
|
package/src/directives/prop.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { directive, parseExpr } from '../core.js'
|
|
2
|
-
import { prop } from 'element-props'
|
|
3
|
-
|
|
4
|
-
directive(':prop', (el, expr) => {
|
|
5
|
-
let evaluate = parseExpr(expr);
|
|
6
|
-
return (state) => {
|
|
7
|
-
let value = evaluate(state);
|
|
8
|
-
for (let key in value) prop(el, key, value[key]);
|
|
9
|
-
}
|
|
10
|
-
})
|
package/src/directives/text.js
DELETED
package/src/directives/value.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { input, prop } from "element-props";
|
|
2
|
-
import { directive, parseExpr } from '../core.js';
|
|
3
|
-
|
|
4
|
-
// connect expr to element value
|
|
5
|
-
directive(':value', (el, expr) => {
|
|
6
|
-
let evaluateGet = parseExpr(expr);
|
|
7
|
-
let [get, set] = input(el);
|
|
8
|
-
let evaluateSet = parseSetter(expr);
|
|
9
|
-
let curState, onchange = e => evaluateSet(curState, get(el));
|
|
10
|
-
el.addEventListener('input', onchange);
|
|
11
|
-
el.addEventListener('change', onchange);
|
|
12
|
-
return (state) => {
|
|
13
|
-
let value = evaluateGet(curState = state);
|
|
14
|
-
prop(el, 'value', value)
|
|
15
|
-
set(value);
|
|
16
|
-
}
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
const memo = {}
|
|
20
|
-
function parseSetter(expr) {
|
|
21
|
-
if (memo[expr]) return memo[expr]
|
|
22
|
-
return memo[expr] = new Function(
|
|
23
|
-
['scope', 'value'],
|
|
24
|
-
`with (scope) { ${expr} = value };`
|
|
25
|
-
)
|
|
26
|
-
}
|
package/src/directives/with.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import sprae, { directive, parseExpr } from '../core.js'
|
|
2
|
-
|
|
3
|
-
directive(':with', (el, expr, rootValues) => {
|
|
4
|
-
let evaluate = parseExpr(expr);
|
|
5
|
-
|
|
6
|
-
// it subsprays with shadowed values
|
|
7
|
-
// rootValues get updated by parent directives
|
|
8
|
-
// subscope doesn't contain reactive values
|
|
9
|
-
let subscope = Object.create(rootValues)
|
|
10
|
-
|
|
11
|
-
// FIXME: wonder if we better pass initial state rather than values snapshot, to let subtree subscribe to more complete set
|
|
12
|
-
// FIXME: likely initial set can be reactive itself then
|
|
13
|
-
Object.assign(subscope, evaluate(rootValues))
|
|
14
|
-
let [subvalues, subupdate] = sprae(el, subscope)
|
|
15
|
-
|
|
16
|
-
return (values) => {
|
|
17
|
-
let withValues = evaluate(values);
|
|
18
|
-
subupdate(withValues)
|
|
19
|
-
}
|
|
20
|
-
})
|
|
21
|
-
|