sprae 4.0.0 → 5.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/package.json +1 -1
- package/r&d.md +44 -2
- package/readme.md +48 -32
- package/src/directives.js +20 -10
- package/src/state.js +2 -0
- package/src/{weakish-map.js → util.js} +5 -0
- package/test/dom.js +25 -10
- package/test/index.html +1 -1
- package/todo.md +4 -4
package/package.json
CHANGED
package/r&d.md
CHANGED
|
@@ -518,15 +518,57 @@
|
|
|
518
518
|
? Some 'or' character `:onclick--onkeydown`
|
|
519
519
|
? We can redirect to main event, that's it for now
|
|
520
520
|
|
|
521
|
-
## [
|
|
521
|
+
## [x] Insert content by reusing the node/template -> use `:render="ref" :with="data"`
|
|
522
522
|
|
|
523
523
|
* Makes easy use of repeatable fragments, instead of web-components
|
|
524
524
|
+ sort-of "detached" for-each
|
|
525
525
|
+ reinforces :ref
|
|
526
526
|
? does it replace element or puts a content?
|
|
527
|
+
* Refs:
|
|
528
|
+
* https://github.com/justinfagnani/html-include-element - src=
|
|
529
|
+
* https://www.npmjs.com/package/imported-template - content=path-to-file
|
|
530
|
+
* https://github.com/SirPepe/html-import src="content.selector"
|
|
531
|
+
* https://github.com/Juicy/juicy-html - html="rawhtml"
|
|
532
|
+
* https://www.npmjs.com/package/html-import-wc - src=path
|
|
533
|
+
* https://github.com/sashafirsov/slotted-element - src=path-to-htmlor-json
|
|
534
|
+
* https://github.com/webcomponents/html-imports - href=filepath
|
|
535
|
+
* https://github.com/giuseppeg/xm - import src=filepath
|
|
536
|
+
* https://github.com/ProjectEvergreen/greenwood/tree/master/packages/plugin-include-html#link-tag-html-only
|
|
537
|
+
* https://github.com/maherbo/include-HTML-document-fragment - link href=path
|
|
538
|
+
* https://github.com/github/include-fragment-element - src=path-to-html
|
|
527
539
|
|
|
528
540
|
1. :use="ref-id"
|
|
529
|
-
|
|
541
|
+
```
|
|
542
|
+
<template :ref="abc" id="abc"><span :text="abc"></span></template>
|
|
543
|
+
|
|
544
|
+
<div :use="abc" :with="{abc:'def'}"></div>
|
|
545
|
+
<div :use="'#abc'" :with="{abc:'def'}"></div>
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
- `<use>` from SVG replaces element, but we need inserting content
|
|
549
|
+
|
|
550
|
+
2. :content="#template-id"
|
|
551
|
+
|
|
552
|
+
- conflicts with direct inline content
|
|
553
|
+
|
|
554
|
+
3. :include="#template-id"
|
|
555
|
+
|
|
556
|
+
- conflicts with path to file
|
|
557
|
+
|
|
558
|
+
4. :tpl="#template-id"
|
|
559
|
+
|
|
560
|
+
- some confusion of meaning
|
|
561
|
+
|
|
562
|
+
5. :render="#template-id"
|
|
563
|
+
|
|
564
|
+
+ compatible with liquid 5.0
|
|
565
|
+
+ makes sense as :render=a :with=b
|
|
566
|
+
|
|
567
|
+
* Let's think consequently.
|
|
568
|
+
1. `<template>` element has direct purpose for that
|
|
569
|
+
2. We provide content fallback for unloaded elements in case of `:text` as `<x :text="abc">fallback</x>`
|
|
570
|
+
3. There's too many ways to implement fetching - ideally we leave that concern out and focus only on including content
|
|
571
|
+
4. The approach is almost ready declarative custom element. `<template>` is standard part of it - adds to 1.
|
|
530
572
|
|
|
531
573
|
## [x] Remove non-essential directives -> yep, less API friction
|
|
532
574
|
* :aria - can be defined via plain attributes
|
package/readme.md
CHANGED
|
@@ -12,9 +12,7 @@ To autoinit on document, include [`sprae.auto.js`](./sprae.auto.js):
|
|
|
12
12
|
<!-- <script src="https://cdn.jsdelivr.net/npm/sprae/sprae.auto.js" defer></script> -->
|
|
13
13
|
<script src="./path/to/sprae.auto.js" defer></script>
|
|
14
14
|
|
|
15
|
-
<
|
|
16
|
-
<span :text="foo"></span>
|
|
17
|
-
</div>
|
|
15
|
+
<a :each="id in ['a','b','c']" :href="`#${id}`"></a>
|
|
18
16
|
```
|
|
19
17
|
|
|
20
18
|
To use as module, import [`sprae.js`](./sprae.js):
|
|
@@ -50,23 +48,6 @@ Sprae evaluates attributes starting with `:`:
|
|
|
50
48
|
|
|
51
49
|
## Attributes
|
|
52
50
|
|
|
53
|
-
#### `:scope="data"`
|
|
54
|
-
|
|
55
|
-
Define or extend data scope for a subtree.
|
|
56
|
-
|
|
57
|
-
```html
|
|
58
|
-
<!-- Inline data -->
|
|
59
|
-
<x :scope="{ foo: 'bar' }" :text="foo"></x>
|
|
60
|
-
|
|
61
|
-
<!-- External data -->
|
|
62
|
-
<y :scope="data"></y>
|
|
63
|
-
|
|
64
|
-
<!-- Extend scope -->
|
|
65
|
-
<x :scope="{ foo: 'bar' }">
|
|
66
|
-
<y :scope="{ baz: 'qux' }" :text="foo + baz"></y>
|
|
67
|
-
</x>
|
|
68
|
-
```
|
|
69
|
-
|
|
70
51
|
#### `:if="condition"`, `:else`
|
|
71
52
|
|
|
72
53
|
Control flow of elements.
|
|
@@ -148,7 +129,7 @@ Set value of an input, textarea or select. Takes handle of `checked` and `select
|
|
|
148
129
|
</select>
|
|
149
130
|
```
|
|
150
131
|
|
|
151
|
-
#### `:<prop>="value?"
|
|
132
|
+
#### `:<prop>="value?"`
|
|
152
133
|
|
|
153
134
|
Set any attribute value or run effect.
|
|
154
135
|
|
|
@@ -159,16 +140,21 @@ Set any attribute value or run effect.
|
|
|
159
140
|
<!-- Multiple properties -->
|
|
160
141
|
<input :id:name="name" />
|
|
161
142
|
|
|
162
|
-
<!--
|
|
163
|
-
<
|
|
143
|
+
<!-- Effect (triggers any time bar changes) -->
|
|
144
|
+
<div :fx="void bar()" ></div>
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
#### `:="props?"`
|
|
164
148
|
|
|
165
|
-
|
|
166
|
-
|
|
149
|
+
Spread multiple attibures.
|
|
150
|
+
|
|
151
|
+
```html
|
|
152
|
+
<input :="{ id: name, name, type:'text', value }" />
|
|
167
153
|
```
|
|
168
154
|
|
|
169
|
-
#### `:on<event>="handler"`, `:on
|
|
155
|
+
#### `:on<event>="handler"`, `:on<in>..on<out>="handler"`
|
|
170
156
|
|
|
171
|
-
Add event
|
|
157
|
+
Add event listener or events chain.
|
|
172
158
|
|
|
173
159
|
```html
|
|
174
160
|
<!-- Single event -->
|
|
@@ -189,9 +175,6 @@ Add event listeners.
|
|
|
189
175
|
|
|
190
176
|
<!-- Event modifiers -->
|
|
191
177
|
<button :onclick.throttle-500="handler">Not too often</button>
|
|
192
|
-
|
|
193
|
-
<!-- Bulk/custom events -->
|
|
194
|
-
<button :on="{ click: handler, touch: handler, special: handler }">Submit</button>
|
|
195
178
|
```
|
|
196
179
|
|
|
197
180
|
##### Event modifiers
|
|
@@ -205,6 +188,33 @@ Add event listeners.
|
|
|
205
188
|
* `.ctrl-<key>, .alt-<key>, .meta-<key>, .shift-<key>` – key combinations, eg. `.ctrl-alt-delete` or `.meta-x`.
|
|
206
189
|
* `.*` – any other modifier has no effect, but allows binding multiple handlers to same event (like jQuery event classes).
|
|
207
190
|
|
|
191
|
+
#### `:with="data"`
|
|
192
|
+
|
|
193
|
+
Define or extend data scope for a subtree.
|
|
194
|
+
|
|
195
|
+
```html
|
|
196
|
+
<!-- Inline data -->
|
|
197
|
+
<x :with="{ foo: 'bar' }" :text="foo"></x>
|
|
198
|
+
|
|
199
|
+
<!-- External data -->
|
|
200
|
+
<y :with="data"></y>
|
|
201
|
+
|
|
202
|
+
<!-- Extend scope -->
|
|
203
|
+
<x :with="{ foo: 'bar' }">
|
|
204
|
+
<y :with="{ baz: 'qux' }" :text="foo + baz"></y>
|
|
205
|
+
</x>
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
#### `:render="ref"`
|
|
209
|
+
|
|
210
|
+
Include template as element content.
|
|
211
|
+
|
|
212
|
+
```html
|
|
213
|
+
<template :ref="foo"><span :text="foo"></span></template>
|
|
214
|
+
|
|
215
|
+
<div :render="foo" :with="{foo:'bar'}">unknown</div>
|
|
216
|
+
<div :render="foo" :with="{foo:'baz'}">unknown</div>
|
|
217
|
+
```
|
|
208
218
|
|
|
209
219
|
#### `:ref="id"`
|
|
210
220
|
|
|
@@ -233,8 +243,14 @@ Expose element to current data scope with the `id`:
|
|
|
233
243
|
## Sandbox
|
|
234
244
|
|
|
235
245
|
Expressions are sandboxed, ie. have no access to global or window (since sprae can be run in server environment).
|
|
236
|
-
|
|
237
|
-
|
|
246
|
+
|
|
247
|
+
```html
|
|
248
|
+
<div :x="window.x"></div>
|
|
249
|
+
<!-- window is undefined -->
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
Default sandbox provides: _Array_, _Object_, _Number_, _String_, _Boolean_, _Date_, _console_.<br/>
|
|
253
|
+
Sandbox can be extended as `Object.assign(sprae.globals, { BigInt, window, document })`.
|
|
238
254
|
|
|
239
255
|
## Examples
|
|
240
256
|
|
package/src/directives.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import sprae from './core.js'
|
|
3
3
|
import swap from './domdiff.js'
|
|
4
4
|
import { state as createState} from './state.js'
|
|
5
|
-
import { WeakishMap } from './
|
|
5
|
+
import { queueMicrotask, WeakishMap } from './util.js'
|
|
6
6
|
|
|
7
7
|
// reserved directives - order matters!
|
|
8
8
|
// primary initialized first by selector, secondary initialized by iterating attributes
|
|
@@ -10,8 +10,8 @@ export const primary = {}, secondary = {}
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
// :if is interchangeable with :each depending on order, :if :each or :each :if have different meanings
|
|
13
|
-
// as for :if :
|
|
14
|
-
// we consider :
|
|
13
|
+
// as for :if :with - :if must init first, since it is lazy, to avoid initializing component ahead of time by :with
|
|
14
|
+
// we consider :with={x} :if={x} case insignificant
|
|
15
15
|
primary['if'] = (el, expr) => {
|
|
16
16
|
let holder = document.createTextNode(''),
|
|
17
17
|
clauses = [parseExpr(el, expr, ':if')],
|
|
@@ -44,9 +44,9 @@ primary['if'] = (el, expr) => {
|
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
// :
|
|
48
|
-
primary['
|
|
49
|
-
let evaluate = parseExpr(el, expr, '
|
|
47
|
+
// :with must come before :each, but :if has primary importance
|
|
48
|
+
primary['with'] = (el, expr, rootState) => {
|
|
49
|
+
let evaluate = parseExpr(el, expr, ':with')
|
|
50
50
|
const localState = evaluate(rootState)
|
|
51
51
|
let state = createState(localState, rootState)
|
|
52
52
|
// console.log(123, state.foo, state.bar)
|
|
@@ -58,7 +58,7 @@ const _each = Symbol(':each')
|
|
|
58
58
|
// :each must init before :ref, :id or any others, since it defines scope
|
|
59
59
|
primary['each'] = (tpl, expr) => {
|
|
60
60
|
let each = parseForExpression(expr);
|
|
61
|
-
if (!each) return exprError(new Error, tpl, expr);
|
|
61
|
+
if (!each) return exprError(new Error, tpl, expr, ':each');
|
|
62
62
|
|
|
63
63
|
// FIXME: make sure no memory leak here
|
|
64
64
|
// we need :if to be able to replace holder instead of tpl for :if :each case
|
|
@@ -68,7 +68,7 @@ primary['each'] = (tpl, expr) => {
|
|
|
68
68
|
const evaluate = parseExpr(tpl, each[2], ':each');
|
|
69
69
|
|
|
70
70
|
const keyExpr = tpl.getAttribute(':key');
|
|
71
|
-
const itemKey = keyExpr ? parseExpr(null, keyExpr) : null;
|
|
71
|
+
const itemKey = keyExpr ? parseExpr(null, keyExpr, ':each') : null;
|
|
72
72
|
tpl.removeAttribute(':key')
|
|
73
73
|
|
|
74
74
|
const refExpr = tpl.getAttribute(':ref');
|
|
@@ -142,6 +142,16 @@ function parseForExpression(expression) {
|
|
|
142
142
|
return [item, '', items]
|
|
143
143
|
}
|
|
144
144
|
|
|
145
|
+
secondary['render'] = (el, expr, state) => {
|
|
146
|
+
let evaluate = parseExpr(el, expr, ':render'),
|
|
147
|
+
tpl = evaluate(state)
|
|
148
|
+
|
|
149
|
+
if (!tpl) exprError(new Error('Template not found'), el, expr, ':render');
|
|
150
|
+
|
|
151
|
+
let content = tpl.content.cloneNode(true);
|
|
152
|
+
el.replaceChildren(content)
|
|
153
|
+
sprae(el, state)
|
|
154
|
+
}
|
|
145
155
|
|
|
146
156
|
secondary['ref'] = (el, expr, state) => {
|
|
147
157
|
// FIXME: wait for complex ref use-case
|
|
@@ -426,9 +436,9 @@ function parseExpr(el, expression, dir) {
|
|
|
426
436
|
}
|
|
427
437
|
}
|
|
428
438
|
|
|
429
|
-
function exprError(error, element, expression,
|
|
439
|
+
function exprError(error, element, expression, directive) {
|
|
430
440
|
Object.assign( error, { element, expression } )
|
|
431
|
-
console.warn(`∴ ${error.message}\n\n${
|
|
441
|
+
console.warn(`∴ ${error.message}\n\n${directive}=${ expression ? `"${expression}"\n\n` : '' }`, element)
|
|
432
442
|
queueMicrotask(() => { throw error }, 0)
|
|
433
443
|
}
|
|
434
444
|
|
package/src/state.js
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
|
|
2
|
+
// reset stacktrace or plan for fastest next call
|
|
3
|
+
// https://twitter.com/_developit/status/1634033380940455936
|
|
4
|
+
export const queueMicrotask = Promise.prototype.then.bind(Promise.resolve());
|
|
5
|
+
|
|
1
6
|
// based on https://github.com/WebReflection/not-so-weak/
|
|
2
7
|
const refs = new WeakMap;
|
|
3
8
|
|
package/test/dom.js
CHANGED
|
@@ -277,8 +277,8 @@ test('if: (#3) subsequent content is not abandoned', async () => {
|
|
|
277
277
|
is(x.outerHTML, `<x><z>123</z></x>`)
|
|
278
278
|
})
|
|
279
279
|
|
|
280
|
-
test('if: + :
|
|
281
|
-
let el = h`<div><x :if="x" :
|
|
280
|
+
test('if: + :with doesnt prevent secondary effects from happening', async () => {
|
|
281
|
+
let el = h`<div><x :if="x" :with="{}" :text="x"></x></div>`
|
|
282
282
|
let state = sprae(el, {x:''})
|
|
283
283
|
is(el.innerHTML, ``)
|
|
284
284
|
state.x = '123'
|
|
@@ -286,7 +286,7 @@ test('if: + :scope doesnt prevent secondary effects from happening', async () =>
|
|
|
286
286
|
is(el.innerHTML, `<x>123</x>`)
|
|
287
287
|
|
|
288
288
|
// NOTE: we ignore this case
|
|
289
|
-
// let el2 = h`<div><x :if="x" :
|
|
289
|
+
// let el2 = h`<div><x :if="x" :with="{x:cond}" :text="x"></x></div>`
|
|
290
290
|
// let state2 = sprae(el, {cond:''})
|
|
291
291
|
// is(el2.innerHTML, ``)
|
|
292
292
|
// state2.cond = '123'
|
|
@@ -859,7 +859,7 @@ test('on: modifiers chain', async e => {
|
|
|
859
859
|
})
|
|
860
860
|
|
|
861
861
|
test('with: inline', async () => {
|
|
862
|
-
let el = h`<x :
|
|
862
|
+
let el = h`<x :with="{foo:'bar'}"><y :text="foo + baz"></y></x>`
|
|
863
863
|
let state = sprae(el, {baz: 'qux'})
|
|
864
864
|
// FIXME: this doesn't inherit root scope baz property and instead uses hard-initialized one
|
|
865
865
|
is(el.innerHTML, `<y>barqux</y>`)
|
|
@@ -868,7 +868,7 @@ test('with: inline', async () => {
|
|
|
868
868
|
is(el.innerHTML, `<y>barquux</y>`)
|
|
869
869
|
})
|
|
870
870
|
test.skip('with: inline reactive', () => {
|
|
871
|
-
let el = h`<x :
|
|
871
|
+
let el = h`<x :with="{foo:'bar'}"><y :text="foo + baz"></y></x>`
|
|
872
872
|
let baz = signal('qux')
|
|
873
873
|
sprae(el, {baz})
|
|
874
874
|
// FIXME: this doesn't inherit root scope baz property and instead uses hard-initialized one
|
|
@@ -877,7 +877,7 @@ test.skip('with: inline reactive', () => {
|
|
|
877
877
|
is(el.innerHTML, `<y>barquux</y>`)
|
|
878
878
|
})
|
|
879
879
|
test('with: data', async () => {
|
|
880
|
-
let el = h`<x :
|
|
880
|
+
let el = h`<x :with="x"><y :text="foo"></y></x>`
|
|
881
881
|
let state = sprae(el, {x: {foo:'bar'}})
|
|
882
882
|
is(el.innerHTML, `<y>bar</y>`)
|
|
883
883
|
console.log('update', state.x)
|
|
@@ -889,7 +889,7 @@ test('with: data', async () => {
|
|
|
889
889
|
test('with: transparency', async () => {
|
|
890
890
|
// NOTE: y:text initializes through directive, not through parent
|
|
891
891
|
// therefore by default :text uses parent's state, not defined by element itself
|
|
892
|
-
let el = h`<x :
|
|
892
|
+
let el = h`<x :with="{foo:'foo'}"><y :with="b" :text="foo+bar"></y></x>`
|
|
893
893
|
let params = sprae(el, {b:{bar:'bar'}})
|
|
894
894
|
is(el.innerHTML, `<y>foobar</y>`)
|
|
895
895
|
params.b.bar = 'baz'
|
|
@@ -897,7 +897,7 @@ test('with: transparency', async () => {
|
|
|
897
897
|
is(el.innerHTML, `<y>foobaz</y>`)
|
|
898
898
|
})
|
|
899
899
|
test.skip('with: reactive transparency', () => {
|
|
900
|
-
let el = h`<x :
|
|
900
|
+
let el = h`<x :with="{foo:1}"><y :with="b.c" :text="foo+bar"></y></x>`
|
|
901
901
|
const bar = signal('2')
|
|
902
902
|
sprae(el, {b:{c:{bar}}})
|
|
903
903
|
is(el.innerHTML, `<y>12</y>`)
|
|
@@ -905,7 +905,7 @@ test.skip('with: reactive transparency', () => {
|
|
|
905
905
|
is(el.innerHTML, `<y>13</y>`)
|
|
906
906
|
})
|
|
907
907
|
test('with: writes to state', async () => {
|
|
908
|
-
let a = h`<x :
|
|
908
|
+
let a = h`<x :with="{a:1}"><y :on="{x(){a++}}" :text="a"></y></x>`
|
|
909
909
|
sprae(a)
|
|
910
910
|
is(a.innerHTML, `<y>1</y>`)
|
|
911
911
|
a.firstChild.dispatchEvent(new window.Event('x'))
|
|
@@ -916,6 +916,21 @@ test('with: writes to state', async () => {
|
|
|
916
916
|
is(a.innerHTML, `<y>3</y>`)
|
|
917
917
|
})
|
|
918
918
|
|
|
919
|
+
test(':render by ref', async () => {
|
|
920
|
+
let a = h`<template :ref="abc"><div :text="123"></div></template><x :render="abc">456</x>`
|
|
921
|
+
sprae(a)
|
|
922
|
+
is(a.outerHTML, `<template><div :text="123"></div></template><x><div>123</div></x>`)
|
|
923
|
+
})
|
|
924
|
+
|
|
925
|
+
test(':render :with', async () => {
|
|
926
|
+
let a = h`<template :ref="abc"><div :text="text"></div></template><x :render="abc" />`
|
|
927
|
+
let state = sprae(a, {text:'abc'})
|
|
928
|
+
is(a.outerHTML, `<template><div :text="text"></div></template><x><div>abc</div></x>`)
|
|
929
|
+
state.text = 'def'
|
|
930
|
+
await tick()
|
|
931
|
+
is(a.outerHTML, `<template><div :text="text"></div></template><x><div>def</div></x>`)
|
|
932
|
+
})
|
|
933
|
+
|
|
919
934
|
test('ref: base', async () => {
|
|
920
935
|
let a = h`<a :ref="a" :init="log.push(a), null" :text="b"></a>`
|
|
921
936
|
let state = sprae(a, {log:[], b:1})
|
|
@@ -959,7 +974,7 @@ test(':: scope refers to current element', async () => {
|
|
|
959
974
|
|
|
960
975
|
test(':: scope directives must come first', async () => {
|
|
961
976
|
// NOTE: we init attributes in order of definition
|
|
962
|
-
let a = h`<x :text="y" :
|
|
977
|
+
let a = h`<x :text="y" :with="{y:1}" :ref="x"></x>`
|
|
963
978
|
sprae(a, {})
|
|
964
979
|
is(a.outerHTML, `<x>1</x>`)
|
|
965
980
|
})
|
package/test/index.html
CHANGED
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] :
|
|
11
|
+
* [x] :with 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 :
|
|
25
|
+
* ~~[x] replace :ref with :with="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 :
|
|
34
|
+
* [x] implement :with
|
|
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 :
|
|
38
|
+
* [x] :if :ref, :if :with -> context setters must come first always
|
|
39
39
|
* [x] :style="{'--x':value}"
|
|
40
40
|
* [x] :onkeydown.ctrl-alt-D
|
|
41
41
|
* [ ] frameworks benchmark
|