sprae 2.3.2 → 2.4.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/plan.md +5 -2
- package/r&d.md +110 -18
- package/readme.md +8 -24
- package/sprae.js +46 -25
- package/sprae.min.js +1 -1
- package/src/core.js +2 -0
- package/src/directives.js +58 -24
- package/test/test.js +71 -14
package/package.json
CHANGED
package/plan.md
CHANGED
|
@@ -29,8 +29,11 @@
|
|
|
29
29
|
* [x] Make sure `false` gets serialized, not removes attr
|
|
30
30
|
* [ ] Sandbox expressions: no global, no "scope" object name, no "arguments"
|
|
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
|
+
* [x] :text="" empty values shouldn't throw
|
|
34
|
+
* [ ] implement :with
|
|
33
35
|
* [ ] frameworks benchmark
|
|
34
36
|
* [ ] examples
|
|
35
37
|
* [x] todomvc
|
|
36
|
-
* [ ] wave-edit
|
|
38
|
+
* [ ] wave-edit
|
|
39
|
+
* [ ] `sprae(el, newState)` can update element's state directly (as batch!?) -> must be tested against repeats in directives
|
package/r&d.md
CHANGED
|
@@ -97,17 +97,40 @@
|
|
|
97
97
|
|
|
98
98
|
-> possibly we have to just subscribe via mechanism of signals-like deps, and :with just initializes subtree with extended object
|
|
99
99
|
|
|
100
|
-
## [
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
+
|
|
106
|
-
+ it
|
|
107
|
-
|
|
108
|
-
+ it
|
|
109
|
-
|
|
110
|
-
|
|
100
|
+
## [ ] :with? ->
|
|
101
|
+
|
|
102
|
+
1. Get rid of :with
|
|
103
|
+
+ with is bad JS practice/association
|
|
104
|
+
+? is there a bona-fide use case?
|
|
105
|
+
+ the implementation is heavy/unoptimal: two assign-updates happen: for root, for children
|
|
106
|
+
+ it is exception blocking streamline implementation of refs
|
|
107
|
+
+ it shadows data which creates all sorts of nasty debugging effects / states. Isn't it better to keep data/state transparent?
|
|
108
|
+
+ it even enables transparency of :each scopes, since they inherit root scope
|
|
109
|
+
+ it's easier to look out for data in one single place (state init), rather than in a bunch of markup locations
|
|
110
|
+
+?! can be replaced with sort of `<x :xyz="xyz=...calc"></x>`, no?
|
|
111
|
+
-> would need wrapping noname scope access
|
|
112
|
+
+ `:with` defines too many concerns:
|
|
113
|
+
* binds root updates -> child updates;
|
|
114
|
+
* binds child updates to root updates (writes);
|
|
115
|
+
* defines local variables
|
|
116
|
+
* aliases root variables
|
|
117
|
+
? is there value in all of these concerns? It seems we need only local variables, isn't it? Is there a chance partial extension can be required?
|
|
118
|
+
- `:with` can provide situational variables that are useful for props precalculation (since these variables can be reactive.)
|
|
119
|
+
* eg. `<span class="preloader" :with="{str: ''}" :init="setTimeout(() => str+='.', 500)" :text="str" />`
|
|
120
|
+
* that plays role of watch that doesn't require to be outside of local component state.
|
|
121
|
+
- `:with` allows local component state not cluttering global state. There's really no way to define local state that doesn't affect global state.
|
|
122
|
+
1.1 Slim `:with="{a,b,c}"` - just initializes vars
|
|
123
|
+
- Doesn't enable easy init syntax
|
|
124
|
+
2. Use `:let="x, y=2"`?
|
|
125
|
+
+ Doesn't pollute scope but instead cleanly declares local variables
|
|
126
|
+
+ Indicates only local initializer, not subscription
|
|
127
|
+
+ Liquid has `assign` tag `{% assign myVar = false %}` - it only initializes variable
|
|
128
|
+
+ Django `with` performs only alias / complex calc access https://docs.djangoproject.com/en/4.1/ref/templates/builtins/#with - it doesn't sync up global state.
|
|
129
|
+
? call it `:define="x, y, z"`?
|
|
130
|
+
-> it seems `:with="x=1, y=2"` works well. `:let` has dissonance with js'y let.
|
|
131
|
+
? how to extend state
|
|
132
|
+
3. `:with.x="1", :with.y="2"`
|
|
133
|
+
+ easier to parse, since init code can be _messy_
|
|
111
134
|
|
|
112
135
|
## [x] Should we inherit values from `init` in `sprae(el, init)`, instead of creating a snapshot of reactive values in `init`? -> nah, nice idea but too little use. Better create signals struct.
|
|
113
136
|
|
|
@@ -191,11 +214,24 @@
|
|
|
191
214
|
+ methods provided in `init` may not have access to scope _yet_.
|
|
192
215
|
~- not reliable way to obtain scope via `this.x` - better be explicit as `state.x`
|
|
193
216
|
|
|
194
|
-
## [x] :onconnected/:ondisconnected? ->
|
|
217
|
+
## [x] :onconnected/:ondisconnected? -> nah, just use noname effect or external functionality eg fast-on-load
|
|
195
218
|
|
|
196
|
-
|
|
219
|
+
+ can be useful for :if, :each handlers, eg to start animation when element appears in DOM.
|
|
220
|
+
- it is not connected-disconnected: it has nothing to do with document: it attaches/detaches from parent.
|
|
221
|
+
- connected-disconnected is too long name
|
|
222
|
+
? attach-detach?
|
|
223
|
+
? onmount-onunmount?
|
|
224
|
+
- slows down domdiff
|
|
225
|
+
- can be solved as `<x :if="xxx" :="xxx ? (...) : '">` automatically
|
|
226
|
+
|
|
227
|
+
## [x] :focus="direct code", :evt="direct code" -> nah, too messy.
|
|
228
|
+
|
|
229
|
+
+ makes proper use-case for direct code events
|
|
230
|
+
- doesn't make sense for rective properties inside
|
|
231
|
+
+ better fit for special props like `:mount`
|
|
232
|
+
- tons of new special-meaning namespace props
|
|
197
233
|
|
|
198
|
-
## [x] Chain of events: often useful to have shared context. -> Try `:
|
|
234
|
+
## [x] Chain of events: often useful to have shared context. -> Try `:onstart..onend`
|
|
199
235
|
|
|
200
236
|
* focus/blur, connected/disconnected, mousedown/mouseup, keydown/keyup, touchstart/touchmove/touchend, dragstart/dragover/dragend, animationstart/animationover/animationend, transitionstart/transitionend
|
|
201
237
|
? is there a way to organize handlers for chains of events?
|
|
@@ -208,14 +244,35 @@
|
|
|
208
244
|
- ? why not :on-focus-blur
|
|
209
245
|
- ? why not :onfocus-onblur
|
|
210
246
|
+ can be converted from on="{ focusBlur: event }" via dash notation
|
|
247
|
+
- messy error messages
|
|
211
248
|
+ less :on prefixes
|
|
212
249
|
+ has better "flowy" meaning
|
|
213
250
|
* 2.1 :onfocus-onblur="e => e => {}"
|
|
214
251
|
+ distinctive visually as 1
|
|
215
252
|
+ flowy nature of 2
|
|
253
|
+
- blocks `:onfile-attached` and other dashed events
|
|
254
|
+
- `ona-onb` vs `ona-b-onc` is hard to parse mentally
|
|
216
255
|
3. :onfocus.onblur="e => e => {}"
|
|
217
256
|
- looks like a modifier
|
|
218
257
|
- . can be used as event class onclick.x
|
|
258
|
+
4. `:onfocus--blur="e => e => {}"`
|
|
259
|
+
+ reminds BEM
|
|
260
|
+
- reminds BEM
|
|
261
|
+
5. `:onfocus..blur="e => e => {}"`
|
|
262
|
+
+ reminds range
|
|
263
|
+
+ literally means start..end
|
|
264
|
+
+ all pros of 2.
|
|
265
|
+
+ reminds spray via dots
|
|
266
|
+
- can be confusing if `blur` is event or just property (can that be a property?)
|
|
267
|
+
6. `:onfocus..onblur="e => e => {}"`
|
|
268
|
+
+ all props of 5.
|
|
269
|
+
+ more obvious that blur is event.
|
|
270
|
+
|
|
271
|
+
4. `:onfocus="e => e => {}"` Keep registered pairs of events: just expect focus return blur, etc.
|
|
272
|
+
+ Shorter syntax
|
|
273
|
+
+ Avoids :onfile-attachment-accepted problem
|
|
274
|
+
- Less verbose and explicit
|
|
275
|
+
- No way to customize sequences, eg. custom events
|
|
219
276
|
|
|
220
277
|
## [ ] Plugins
|
|
221
278
|
|
|
@@ -224,9 +281,10 @@
|
|
|
224
281
|
- can be solved naturally, unless there's special meaning
|
|
225
282
|
* @sprae/hcodes: `<x :hcode=""` – provide microformats
|
|
226
283
|
* @sprae/with
|
|
227
|
-
* @sprae/
|
|
284
|
+
* @sprae/onconnected
|
|
285
|
+
* @sprae/onvisible?
|
|
228
286
|
|
|
229
|
-
## [x] Write any-attributes via
|
|
287
|
+
## [x] Write any-attributes via `:<prop>? -> yep`
|
|
230
288
|
|
|
231
289
|
+ Since we support attr walking, maybe instead of :on and :prop just allow any attributes?
|
|
232
290
|
+ that would allow event and attr modifiers...
|
|
@@ -263,8 +321,10 @@
|
|
|
263
321
|
+ Provides precisely controlled sandbox
|
|
264
322
|
- Some limited lang opportunities
|
|
265
323
|
- need to match many syntax quirks, can be tedious
|
|
324
|
+
~ can be fine to limit expressions to meaningful default: why Proxy, generators, awaits, global access etc.
|
|
266
325
|
- Somewhat heavy to bundle
|
|
267
|
-
|
|
326
|
+
~ 1-2kb is not super-heavy, besides signal-struct kicks out
|
|
327
|
+
+ Scope is easier to provide: no need for signal proxy
|
|
268
328
|
+ Can detect access errors in advance
|
|
269
329
|
+ Syntax-level access to signals can be inavoidable: external signals still "leak in" (via arrays or etc.).
|
|
270
330
|
+ Updating simple objects should also rerender the template parts, not just signals.
|
|
@@ -272,6 +332,9 @@
|
|
|
272
332
|
- Screwed up debugging / stacktrace (unless errored)
|
|
273
333
|
+ that "unlimits" returned struct, so that any property can be added/deleted.
|
|
274
334
|
- doesn't really save from `new (()=>{}).constructor` hack: we gotta substitute objects too.
|
|
335
|
+
+ allows easier handle of `:with="a=1,b=2,c=3"` - we just naturally get local variables without messup with global
|
|
336
|
+
+ we can even define locals without `let`...
|
|
337
|
+
- not having "comfy" compatible JS at hand: cognitive load of whole language "layer" in-between
|
|
275
338
|
|
|
276
339
|
2. Use sandboxed proxy
|
|
277
340
|
- tough evaluation
|
|
@@ -297,4 +360,33 @@
|
|
|
297
360
|
## [ ] Better :ref
|
|
298
361
|
+ :ref="`a-${1}`"
|
|
299
362
|
+ :id:ref="xyz"
|
|
300
|
-
? maybe id should have same signature
|
|
363
|
+
? maybe id should have same signature
|
|
364
|
+
? should it be very similar mechanism to `:with="a=1,b=2"`
|
|
365
|
+
|
|
366
|
+
## [ ] Event modifiers :ona.once, `:ona`
|
|
367
|
+
|
|
368
|
+
- .prevent,.stop - not needed since expects a function
|
|
369
|
+
? or should we just trigger it for user?
|
|
370
|
+
? :onclick.outside
|
|
371
|
+
? :onclick.window, :onclick.document
|
|
372
|
+
? :onclick.once
|
|
373
|
+
? :onclick.debounce
|
|
374
|
+
? :onclick.throttle.750ms
|
|
375
|
+
? :onclick.self
|
|
376
|
+
? :onspecial-event.camel, :onx-y.dot
|
|
377
|
+
? :onclick.passive
|
|
378
|
+
? :onkeypress.shift.enter
|
|
379
|
+
.shift Shift
|
|
380
|
+
.enter Enter
|
|
381
|
+
.space Space
|
|
382
|
+
.ctrl Ctrl
|
|
383
|
+
.cmd Cmd
|
|
384
|
+
.meta Cmd on Mac, Windows key on Windows
|
|
385
|
+
.alt Alt
|
|
386
|
+
.up .down .left .right Up/Down/Left/Right arrows
|
|
387
|
+
.escape Escape
|
|
388
|
+
.tab Tab
|
|
389
|
+
.caps-lock Caps Lock
|
|
390
|
+
.equal Equal, =
|
|
391
|
+
.period Period, .
|
|
392
|
+
.slash Foward Slash, /
|
package/readme.md
CHANGED
|
@@ -124,9 +124,9 @@ Set value of an input, textarea or select. Takes handle of `checked` and `select
|
|
|
124
124
|
</select>
|
|
125
125
|
```
|
|
126
126
|
|
|
127
|
-
#### `:<prop>="value"`, `:="props"`
|
|
127
|
+
#### `:<prop>="value?"`, `:="props?"`
|
|
128
128
|
|
|
129
|
-
Set any prop value.
|
|
129
|
+
Set any prop value or run effect.
|
|
130
130
|
|
|
131
131
|
```html
|
|
132
132
|
<!-- Single property -->
|
|
@@ -137,9 +137,12 @@ Set any prop value.
|
|
|
137
137
|
|
|
138
138
|
<!-- Bulk properties -->
|
|
139
139
|
<input :="{ id: name, name, type:'text', value }" />
|
|
140
|
+
|
|
141
|
+
<!-- Effect (triggers any time foo or bar changes) -->
|
|
142
|
+
<div :="if (foo) bar()" :fx="void bar()" ></div>
|
|
140
143
|
```
|
|
141
144
|
|
|
142
|
-
#### `:on<event>="handler"`, `:on="events"`
|
|
145
|
+
#### `:on<event>="handler"`, `:on="events"`, `:<in>..<out>="handler"`
|
|
143
146
|
|
|
144
147
|
Add event listeners.
|
|
145
148
|
|
|
@@ -151,7 +154,7 @@ Add event listeners.
|
|
|
151
154
|
<input :value="text" :oninput:onchange="e => text=e.target.value">
|
|
152
155
|
|
|
153
156
|
<!-- Sequence of events -->
|
|
154
|
-
<button :onfocus
|
|
157
|
+
<button :onfocus..onblur="e => {
|
|
155
158
|
// onfocus
|
|
156
159
|
let id = setInterval(track,200)
|
|
157
160
|
return e => {
|
|
@@ -164,23 +167,6 @@ Add event listeners.
|
|
|
164
167
|
<button :on="{ click: handler, touch: handler, special: handler }">Submit</button>
|
|
165
168
|
```
|
|
166
169
|
|
|
167
|
-
<!--
|
|
168
|
-
#### `:oninit="fn"`
|
|
169
|
-
|
|
170
|
-
Create initializer handler - called whenever element is initialized by sprae.
|
|
171
|
-
|
|
172
|
-
```html
|
|
173
|
-
<div id="foo" :oninit="function(){ this === foo }"></div>
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
#### `:onconnect="fn"`, `:ondisconnect="fn"`
|
|
177
|
-
|
|
178
|
-
Invoked when element is connected or disconnected from DOM.
|
|
179
|
-
|
|
180
|
-
```html
|
|
181
|
-
```
|
|
182
|
-
-->
|
|
183
|
-
|
|
184
170
|
#### `:data="values"`
|
|
185
171
|
|
|
186
172
|
Set [data-*](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/data-*) attributes. CamelCase is converted to dash-case.
|
|
@@ -220,9 +206,7 @@ Expose element to data scope with the `id`:
|
|
|
220
206
|
<!-- iterable items -->
|
|
221
207
|
<ul>
|
|
222
208
|
<li :each="item in items" :ref="item">
|
|
223
|
-
<input
|
|
224
|
-
:onfocus-onblur="e => (item.classList.add('editing'), e => item.classList.remove('editing'))"
|
|
225
|
-
/>
|
|
209
|
+
<input :onfocus..onblur="e => (item.classList.add('editing'), e => item.classList.remove('editing'))"/>
|
|
226
210
|
</li>
|
|
227
211
|
</ul>
|
|
228
212
|
|
package/sprae.js
CHANGED
|
@@ -452,11 +452,14 @@ var primitive_pool_default = (key) => {
|
|
|
452
452
|
// src/directives.js
|
|
453
453
|
var directives = {};
|
|
454
454
|
var directives_default = (el, expr, values, name) => {
|
|
455
|
-
|
|
456
|
-
return directives.on(el, `{"${name.split("-").map((n2) => n2.startsWith("on") ? n2.slice(2) : n2).join("-")}": ${expr}}`, values);
|
|
457
|
-
}
|
|
455
|
+
let evt = name.startsWith("on") && name.slice(2);
|
|
458
456
|
let evaluate = parseExpr(el, expr, ":" + name);
|
|
459
|
-
|
|
457
|
+
let value;
|
|
458
|
+
return evt ? (state) => {
|
|
459
|
+
value && removeListener(el, evt, value);
|
|
460
|
+
value = evaluate(state);
|
|
461
|
+
value && addListener(el, evt, value);
|
|
462
|
+
} : (state) => attr(el, name, evaluate(state));
|
|
460
463
|
};
|
|
461
464
|
var attr = (el, name, v2) => {
|
|
462
465
|
if (v2 == null || v2 === false)
|
|
@@ -482,6 +485,13 @@ directives["ref"] = (el, expr, values) => {
|
|
|
482
485
|
;
|
|
483
486
|
values[expr] = el;
|
|
484
487
|
};
|
|
488
|
+
directives["with"] = (el, expr, rootState) => {
|
|
489
|
+
let evaluate = parseExpr(el, expr, "with");
|
|
490
|
+
throw "Unimplemented";
|
|
491
|
+
let withValues = evaluate(rootState);
|
|
492
|
+
let newState = Object.assign(Object.create(rootState), withValues);
|
|
493
|
+
sprae(el, newState);
|
|
494
|
+
};
|
|
485
495
|
directives["if"] = (el, expr, values) => {
|
|
486
496
|
let holder = document.createTextNode(""), clauses = [parseExpr(el, expr, ":if")], els = [el], cur = el;
|
|
487
497
|
while (cur = el.nextElementSibling) {
|
|
@@ -620,35 +630,44 @@ directives["value"] = (el, expr, values) => {
|
|
|
620
630
|
} : (value) => el.value = value;
|
|
621
631
|
return (state) => update(evaluate(state));
|
|
622
632
|
};
|
|
633
|
+
var _stop = Symbol("stop");
|
|
623
634
|
directives["on"] = (el, expr, values) => {
|
|
624
635
|
let evaluate = parseExpr(el, expr, ":on");
|
|
625
636
|
let listeners = {};
|
|
626
637
|
return (state) => {
|
|
627
638
|
for (let evt in listeners)
|
|
628
|
-
el
|
|
639
|
+
removeListener(el, evt, listeners[evt]);
|
|
629
640
|
listeners = evaluate(state);
|
|
630
|
-
for (let evt in listeners)
|
|
631
|
-
|
|
632
|
-
if (evts.length === 1)
|
|
633
|
-
el.addEventListener(evt, listeners[evt]);
|
|
634
|
-
else {
|
|
635
|
-
const startFn = listeners[evt];
|
|
636
|
-
const nextEvt = (fn, cur = 0) => {
|
|
637
|
-
el.addEventListener(evts[cur], listeners[evt] = (e2) => {
|
|
638
|
-
fn = fn(e2);
|
|
639
|
-
el.removeEventListener(evts[cur], listeners[evt]);
|
|
640
|
-
if (++cur < evts.length && typeof fn === "function")
|
|
641
|
-
nextEvt(fn, cur);
|
|
642
|
-
else
|
|
643
|
-
nextEvt(startFn);
|
|
644
|
-
});
|
|
645
|
-
};
|
|
646
|
-
nextEvt(startFn);
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
;
|
|
641
|
+
for (let evt in listeners)
|
|
642
|
+
addListener(el, evt, listeners[evt]);
|
|
650
643
|
};
|
|
651
644
|
};
|
|
645
|
+
var addListener = (el, evt, startFn) => {
|
|
646
|
+
if (evt.indexOf("..") < 0)
|
|
647
|
+
el.addEventListener(evt, startFn);
|
|
648
|
+
else {
|
|
649
|
+
const evts = evt.split("..").map((e2) => e2.startsWith("on") ? e2.slice(2) : e2);
|
|
650
|
+
const nextEvt = (fn, cur = 0) => {
|
|
651
|
+
let curListener = (e2) => {
|
|
652
|
+
el.removeEventListener(evts[cur], curListener);
|
|
653
|
+
if (typeof (fn = fn.call(el, e2)) !== "function")
|
|
654
|
+
fn = () => {
|
|
655
|
+
};
|
|
656
|
+
if (++cur < evts.length)
|
|
657
|
+
nextEvt(fn, cur);
|
|
658
|
+
else if (!startFn[_stop])
|
|
659
|
+
console.log("reset"), nextEvt(startFn);
|
|
660
|
+
};
|
|
661
|
+
el.addEventListener(evts[cur], curListener);
|
|
662
|
+
};
|
|
663
|
+
nextEvt(startFn);
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
var removeListener = (el, evt, fn) => {
|
|
667
|
+
if (evt.indexOf("..") >= 0)
|
|
668
|
+
console.log("rewire"), fn[_stop] = true;
|
|
669
|
+
el.removeEventListener(evt, fn);
|
|
670
|
+
};
|
|
652
671
|
directives["data"] = (el, expr, values) => {
|
|
653
672
|
let evaluate = parseExpr(el, expr, ":data");
|
|
654
673
|
return (state) => {
|
|
@@ -720,6 +739,8 @@ function sprae(container, values) {
|
|
|
720
739
|
}
|
|
721
740
|
el.removeAttribute(attr2.name);
|
|
722
741
|
let expr = attr2.value;
|
|
742
|
+
if (!expr)
|
|
743
|
+
continue;
|
|
723
744
|
let attrNames = attr2.name.slice(1).split(":");
|
|
724
745
|
for (let attrName of attrNames) {
|
|
725
746
|
let dir = directives[attrName] || directives_default;
|
package/sprae.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function t(){throw new Error("Cycle detected")}function e(){if(n>1)n--;else{for(var t,e=!1;void 0!==r;){var i=r;for(r=void 0,o++;void 0!==i;){var s=i.o;if(i.o=void 0,i.f&=-3,!(8&i.f)&&l(i))try{i.c()}catch(i){e||(t=i,e=!0)}i=s}}if(o=0,n--,e)throw t}}var i=void 0,r=void 0,n=0,o=0,s=0;function f(t){if(void 0!==i){var e=t.n;if(void 0===e||e.t!==i)return i.s=e={i:0,S:t,p:void 0,n:i.s,t:i,e:void 0,x:void 0,r:e},t.n=e,32&i.f&&t.S(e),e;if(-1===e.i)return e.i=0,void 0!==e.p&&(e.p.n=e.n,void 0!==e.n&&(e.n.p=e.p),e.p=void 0,e.n=i.s,i.s.p=e,i.s=e),e}}function a(t){this.v=t,this.i=0,this.n=void 0,this.t=void 0}function u(t){return new a(t)}function l(t){for(var e=t.s;void 0!==e;e=e.n)if(e.S.i!==e.i||!e.S.h()||e.S.i!==e.i)return!0;return!1}function h(t){for(var e=t.s;void 0!==e;e=e.n){var i=e.S.n;void 0!==i&&(e.r=i),e.S.n=e,e.i=-1}}function c(t){for(var e=t.s,i=void 0;void 0!==e;){var r=e.n;-1===e.i?(e.S.U(e),e.n=void 0):(void 0!==i&&(i.p=e),e.p=void 0,e.n=i,i=e),e.S.n=e.r,void 0!==e.r&&(e.r=void 0),e=r}t.s=i}function v(t){a.call(this,void 0),this.x=t,this.s=void 0,this.g=s-1,this.f=4}function p(t){var r=t.u;if(t.u=void 0,"function"==typeof r){n++;var o=i;i=void 0;try{r()}catch(e){throw t.f&=-2,t.f|=8,d(t),e}finally{i=o,e()}}}function d(t){for(var e=t.s;void 0!==e;e=e.n)e.S.U(e);t.x=void 0,t.s=void 0,p(t)}function y(t){if(i!==this)throw new Error("Out-of-order effect");c(this),i=t,this.f&=-2,8&this.f&&d(this),e()}function b(t){this.x=t,this.u=void 0,this.s=void 0,this.o=void 0,this.f=32}function m(t){var e=new b(t);return e.c(),e.d.bind(e)}a.prototype.h=function(){return!0},a.prototype.S=function(t){this.t!==t&&void 0===t.e&&(t.x=this.t,void 0!==this.t&&(this.t.e=t),this.t=t)},a.prototype.U=function(t){var e=t.e,i=t.x;void 0!==e&&(e.x=i,t.e=void 0),void 0!==i&&(i.e=e,t.x=void 0),t===this.t&&(this.t=i)},a.prototype.subscribe=function(t){var e=this;return m((function(){var i=e.value,r=32&this.f;this.f&=-33;try{t(i)}finally{this.f|=r}}))},a.prototype.valueOf=function(){return this.value},a.prototype.toString=function(){return this.value+""},a.prototype.peek=function(){return this.v},Object.defineProperty(a.prototype,"value",{get:function(){var t=f(this);return void 0!==t&&(t.i=this.i),this.v},set:function(i){if(i!==this.v){o>100&&t(),this.v=i,this.i++,s++,n++;try{for(var r=this.t;void 0!==r;r=r.x)r.t.N()}finally{e()}}}}),(v.prototype=new a).h=function(){if(this.f&=-3,1&this.f)return!1;if(32==(36&this.f))return!0;if(this.f&=-5,this.g===s)return!0;if(this.g=s,this.f|=1,this.i>0&&!l(this))return this.f&=-2,!0;var t=i;try{h(this),i=this;var e=this.x();(16&this.f||this.v!==e||0===this.i)&&(this.v=e,this.f&=-17,this.i++)}catch(t){this.v=t,this.f|=16,this.i++}return i=t,c(this),this.f&=-2,!0},v.prototype.S=function(t){if(void 0===this.t){this.f|=36;for(var e=this.s;void 0!==e;e=e.n)e.S.S(e)}a.prototype.S.call(this,t)},v.prototype.U=function(t){if(a.prototype.U.call(this,t),void 0===this.t){this.f&=-33;for(var e=this.s;void 0!==e;e=e.n)e.S.U(e)}},v.prototype.N=function(){if(!(2&this.f)){this.f|=6;for(var t=this.t;void 0!==t;t=t.x)t.t.N()}},v.prototype.peek=function(){if(this.h()||t(),16&this.f)throw this.v;return this.v},Object.defineProperty(v.prototype,"value",{get:function(){1&this.f&&t();var e=f(this);if(this.h(),void 0!==e&&(e.i=this.i),16&this.f)throw this.v;return this.v}}),b.prototype.c=function(){var t=this.S();try{8&this.f||void 0===this.x||(this.u=this.x())}finally{t()}},b.prototype.S=function(){1&this.f&&t(),this.f|=1,this.f&=-9,p(this),h(this),n++;var e=i;return i=this,y.bind(this,e)},b.prototype.N=function(){2&this.f||(this.f|=2,this.o=r,r=this)},b.prototype.d=function(){this.f|=8,1&this.f||d(this)},Symbol.observable||=Symbol("observable");var g=new FinalizationRegistry((t=>t.call?.())),S=t=>t&&t.peek,x=Symbol("signal-struct");function w(t){if((e=t)&&e[x])return t;var e;let i,r;if(O(t)){i={},r={};let e=Object.getOwnPropertyDescriptors(t);for(let t in e)r[t]=A(i,t,e[t].get?new v(e[t].get.bind(i)):e[t].value);return Object.defineProperty(i,x,{configurable:!1,enumerable:!1,value:!0}),Object.seal(i),i}return Array.isArray(t)?t.map((t=>w(t))):t}function A(t,e,i){let r,n=S(i)?i:O(i)||Array.isArray(i)?u(w(i)):u((r=(o=i)&&!!(o[Symbol.observable]||o[Symbol.asyncIterator]||o.call&&o.set||o.subscribe||o.then))?void 0:i);var o,s,f,a,l,h,c;return r&&(f=t=>n.value=t,(s=i)&&(c=(s[Symbol.observable]?.()||s).subscribe?.(f,a,undefined),h=c&&(()=>c.unsubscribe?.())||s.set&&s.call?.(l,f)||(s.then?.((t=>{!l&&f(t)}),a)||(async t=>{try{for await(t of s){if(l)return;f(t)}}catch(t){}})())&&(t=>l=1),g.register(s,h))),Object.defineProperty(t,e,{get:()=>n.value,set:!S(i)&&O(i)?t=>t?Object.assign(n.value,t):n.value=w(t):t=>n.value=w(t),enumerable:!0,configurable:!1}),n}function O(t){return t&&t.constructor===Object}var j=(t,e,i,r=null)=>{let n,o,s,f=0,a=i.length,u=e.length,{remove:l,same:h,insert:c,replace:v}=j;for(;f<a&&f<u&&h(e[f],i[f]);)f++;for(;f<a&&f<u&&h(i[a-1],e[u-1]);)r=i[(--u,--a)];if(f==u)for(;f<a;)c(r,i[f++],t);else{for(n=e[f];f<a;)s=i[f++],o=n?n.nextSibling:r,h(n,s)?n=o:f<a&&h(i[f],o)?(v(n,s,t),n=o):c(n,s,t);for(;!h(n,r);)o=n.nextSibling,l(n,t),n=o}return i};j.same=(t,e)=>t==e,j.replace=(t,e,i)=>i.replaceChild(e,t),j.insert=(t,e,i)=>i.insertBefore(e,t),j.remove=(t,e)=>e.removeChild(t);var N=j,E={},$={},W={},k={},C=(t,e,i,r)=>{if(r.startsWith("on"))return k.on(t,`{"${r.split("-").map((t=>t.startsWith("on")?t.slice(2):t)).join("-")}": ${e}}`,i);let n=D(t,e,":"+r);return e=>U(t,r,n(e))},U=(t,e,i)=>{null==i||!1===i?t.removeAttribute(e):t.setAttribute(e,!0===i?"":"number"==typeof i||"string"==typeof i?i:"")};k[""]=(t,e,i)=>{let r=D(t,e,":");return e=>{let i=r(e);for(let e in i)U(t,M(e),i[e])}};var B=Symbol(":each"),L=Symbol(":ref");k.ref=(t,e,i)=>{t.hasAttribute(":each")?t[L]=e:i[e]=t},k.if=(t,e,i)=>{let r=document.createTextNode(""),n=[D(t,e,":if")],o=[t],s=t;for(;(s=t.nextElementSibling)&&s.hasAttribute(":else");)s.removeAttribute(":else"),(e=s.getAttribute(":if"))?(s.removeAttribute(":if"),s.remove(),o.push(s),n.push(D(t,e,":else :if"))):(s.remove(),o.push(s),n.push((()=>1)));return t.replaceWith(s=r),t=>{let e=n.findIndex((e=>e(t)));o[e]!=s&&((s[B]||s).replaceWith(s=o[e]||r),F(s,t))}},k.each=(t,e,i)=>{let r=function(t){let e=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,i=t.match(/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/);if(!i)return;let r={};r.items=i[2].trim();let n=i[1].replace(/^\s*\(|\)\s*$/g,"").trim(),o=n.match(e);return o?(r.item=n.replace(e,"").trim(),r.index=o[1].trim()):r.item=n,r}(e);if(!r)return _(new Error,t,e);const n=t[B]=document.createTextNode("");t.replaceWith(n);const o=D(t,r.items,":each"),s=new WeakMap,f=new WeakMap;let a=[];return e=>{let i=o(e);i?"number"==typeof i?i=Array.from({length:i},((t,e)=>[e,e+1])):i.constructor===Object?i=Object.entries(i):Array.isArray(i)?i=i.map(((t,e)=>[e+1,t])):_(Error("Bad list value"),t,r.items,":each"):i=[];let u=[],l=[];for(let[n,o]of i){let i=null===(h=o)?$:void 0===h?W:"number"==typeof h||h instanceof Number?E[h]||(E[h]=new Number(h)):"string"==typeof h||h instanceof String?E[h]||(E[h]=new String(h)):"boolean"==typeof h||h instanceof Boolean?E[h]||(E[h]=new Boolean(h)):h,a=f.get(i);if(a||(a=t.cloneNode(!0),f.set(i,a)),u.push(a),!s.has(i)){let f=Object.create(e);f[r.item]=o,r.index&&(f[r.index]=n),t[L]&&(f[t[L]]=a),s.set(i,f)}l.push(s.get(i))}var h;N(n.parentNode,a,u,n),a=u;for(let t=0;t<u.length;t++)F(u[t],l[t])}},k.id=(t,e,i)=>{let r=D(t,e,":id");return e=>{return i=r(e),t.id=i||0===i?i:"";var i}},k.class=(t,e,i)=>{let r=D(t,e,":class"),n=t.className;return e=>{let i=r(e);t.className=n+typeof i=="string"?i:(Array.isArray(i)?i:Object.entries(i).map((([t,e])=>e?t:""))).filter(Boolean).join(" ")}},k.style=(t,e,i)=>{let r=D(t,e,":style"),n=t.getAttribute("style")||"";return n.endsWith(";")||(n+="; "),e=>{let i=r(e);if("string"==typeof i)t.setAttribute("style",n+i);else for(let e in i)t.style[e]=i[e]}},k.text=(t,e,i)=>{let r=D(t,e,":text");return e=>{return i=r(e),void(t.textContent=null==i?"":i);var i}},k.value=(t,e,i)=>{let r=D(t,e,":value"),n="text"===t.type||""===t.type?e=>t.setAttribute("value",t.value=null==e?"":e):"checkbox"===t.type?e=>(t.value=e?"on":"",U(t,"checked",e)):"select-one"===t.type?e=>{for(let e in t.options)e.removeAttribute("selected");t.value=e,t.selectedOptions[0]?.setAttribute("selected","")}:e=>t.value=e;return t=>n(r(t))},k.on=(t,e,i)=>{let r=D(t,e,":on"),n={};return e=>{for(let e in n)t.removeEventListener(e,n[e]);n=r(e);for(let e in n){const i=e.split("-");if(1===i.length)t.addEventListener(e,n[e]);else{const r=n[e],o=(s,f=0)=>{t.addEventListener(i[f],n[e]=a=>{s=s(a),t.removeEventListener(i[f],n[e]),++f<i.length&&"function"==typeof s?o(s,f):o(r)})};o(r)}}}},k.data=(t,e,i)=>{let r=D(t,e,":data");return e=>{let i=r(e);for(let e in i)t.dataset[e]=i[e]}},k.aria=(t,e,i)=>{let r=D(t,e,":aria");return e=>(e=>{for(let i in e)U(t,"aria-"+M(i),null==e[i]?null:e[i]+"")})(r(e))};var P={};function D(t,e,i){if(P[e])return P[e];let r,n=/^[\n\s]*if.*\(.*\)/.test(e)||/^(let|const)\s/.test(e)?`(() => { ${e} })()`:e;try{r=new Function("__scope",`with (__scope) { return (${n}) };`).bind(t)}catch(r){return _(r,t,e,i)}return P[e]=n=>{let o;try{o=r(n)}catch(r){return _(r,t,e,i)}return o}}function _(t,e,i,r){Object.assign(t,{element:e,expression:i}),console.warn(`∴ ${t.message}\n\n${r}=${i?`"${i}"\n\n`:""}`,e),setTimeout((()=>{throw t}),0)}function M(t){return t.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(t=>"-"+t.toLowerCase()))}var T=new WeakMap;function F(t,e){if(!t.children)return;if(T.has(t))return T.get(t);e||={};const i=[],r=(t,n=t.parentNode)=>{if(t.attributes)for(let r=0;r<t.attributes.length;){let o=t.attributes[r];if(":"!==o.name[0]){r++;continue}t.removeAttribute(o.name);let s=o.value,f=o.name.slice(1).split(":");for(let r of f){let o=k[r]||C;if(i.push(o(t,s,e,r)||(()=>{})),T.has(t)||t.parentNode!==n)return!1}}for(let e,i=0;e=t.children[i];i++)!1===r(e,t)&&i--};r(t);const n=w(e);for(let t of i)m((()=>t(n)));return T.set(t,n),n}var I=F;export{I as default};
|
|
1
|
+
function t(){throw new Error("Cycle detected")}function e(){if(n>1)n--;else{for(var t,e=!1;void 0!==r;){var i=r;for(r=void 0,o++;void 0!==i;){var s=i.o;if(i.o=void 0,i.f&=-3,!(8&i.f)&&u(i))try{i.c()}catch(i){e||(t=i,e=!0)}i=s}}if(o=0,n--,e)throw t}}var i=void 0,r=void 0,n=0,o=0,s=0;function f(t){if(void 0!==i){var e=t.n;if(void 0===e||e.t!==i)return i.s=e={i:0,S:t,p:void 0,n:i.s,t:i,e:void 0,x:void 0,r:e},t.n=e,32&i.f&&t.S(e),e;if(-1===e.i)return e.i=0,void 0!==e.p&&(e.p.n=e.n,void 0!==e.n&&(e.n.p=e.p),e.p=void 0,e.n=i.s,i.s.p=e,i.s=e),e}}function l(t){this.v=t,this.i=0,this.n=void 0,this.t=void 0}function a(t){return new l(t)}function u(t){for(var e=t.s;void 0!==e;e=e.n)if(e.S.i!==e.i||!e.S.h()||e.S.i!==e.i)return!0;return!1}function h(t){for(var e=t.s;void 0!==e;e=e.n){var i=e.S.n;void 0!==i&&(e.r=i),e.S.n=e,e.i=-1}}function c(t){for(var e=t.s,i=void 0;void 0!==e;){var r=e.n;-1===e.i?(e.S.U(e),e.n=void 0):(void 0!==i&&(i.p=e),e.p=void 0,e.n=i,i=e),e.S.n=e.r,void 0!==e.r&&(e.r=void 0),e=r}t.s=i}function v(t){l.call(this,void 0),this.x=t,this.s=void 0,this.g=s-1,this.f=4}function p(t){var r=t.u;if(t.u=void 0,"function"==typeof r){n++;var o=i;i=void 0;try{r()}catch(e){throw t.f&=-2,t.f|=8,d(t),e}finally{i=o,e()}}}function d(t){for(var e=t.s;void 0!==e;e=e.n)e.S.U(e);t.x=void 0,t.s=void 0,p(t)}function y(t){if(i!==this)throw new Error("Out-of-order effect");c(this),i=t,this.f&=-2,8&this.f&&d(this),e()}function b(t){this.x=t,this.u=void 0,this.s=void 0,this.o=void 0,this.f=32}function m(t){var e=new b(t);return e.c(),e.d.bind(e)}l.prototype.h=function(){return!0},l.prototype.S=function(t){this.t!==t&&void 0===t.e&&(t.x=this.t,void 0!==this.t&&(this.t.e=t),this.t=t)},l.prototype.U=function(t){var e=t.e,i=t.x;void 0!==e&&(e.x=i,t.e=void 0),void 0!==i&&(i.e=e,t.x=void 0),t===this.t&&(this.t=i)},l.prototype.subscribe=function(t){var e=this;return m((function(){var i=e.value,r=32&this.f;this.f&=-33;try{t(i)}finally{this.f|=r}}))},l.prototype.valueOf=function(){return this.value},l.prototype.toString=function(){return this.value+""},l.prototype.peek=function(){return this.v},Object.defineProperty(l.prototype,"value",{get:function(){var t=f(this);return void 0!==t&&(t.i=this.i),this.v},set:function(i){if(i!==this.v){o>100&&t(),this.v=i,this.i++,s++,n++;try{for(var r=this.t;void 0!==r;r=r.x)r.t.N()}finally{e()}}}}),(v.prototype=new l).h=function(){if(this.f&=-3,1&this.f)return!1;if(32==(36&this.f))return!0;if(this.f&=-5,this.g===s)return!0;if(this.g=s,this.f|=1,this.i>0&&!u(this))return this.f&=-2,!0;var t=i;try{h(this),i=this;var e=this.x();(16&this.f||this.v!==e||0===this.i)&&(this.v=e,this.f&=-17,this.i++)}catch(t){this.v=t,this.f|=16,this.i++}return i=t,c(this),this.f&=-2,!0},v.prototype.S=function(t){if(void 0===this.t){this.f|=36;for(var e=this.s;void 0!==e;e=e.n)e.S.S(e)}l.prototype.S.call(this,t)},v.prototype.U=function(t){if(l.prototype.U.call(this,t),void 0===this.t){this.f&=-33;for(var e=this.s;void 0!==e;e=e.n)e.S.U(e)}},v.prototype.N=function(){if(!(2&this.f)){this.f|=6;for(var t=this.t;void 0!==t;t=t.x)t.t.N()}},v.prototype.peek=function(){if(this.h()||t(),16&this.f)throw this.v;return this.v},Object.defineProperty(v.prototype,"value",{get:function(){1&this.f&&t();var e=f(this);if(this.h(),void 0!==e&&(e.i=this.i),16&this.f)throw this.v;return this.v}}),b.prototype.c=function(){var t=this.S();try{8&this.f||void 0===this.x||(this.u=this.x())}finally{t()}},b.prototype.S=function(){1&this.f&&t(),this.f|=1,this.f&=-9,p(this),h(this),n++;var e=i;return i=this,y.bind(this,e)},b.prototype.N=function(){2&this.f||(this.f|=2,this.o=r,r=this)},b.prototype.d=function(){this.f|=8,1&this.f||d(this)},Symbol.observable||=Symbol("observable");var g=new FinalizationRegistry((t=>t.call?.())),S=t=>t&&t.peek,w=Symbol("signal-struct");function x(t){if((e=t)&&e[w])return t;var e;let i,r;if(O(t)){i={},r={};let e=Object.getOwnPropertyDescriptors(t);for(let t in e)r[t]=A(i,t,e[t].get?new v(e[t].get.bind(i)):e[t].value);return Object.defineProperty(i,w,{configurable:!1,enumerable:!1,value:!0}),Object.seal(i),i}return Array.isArray(t)?t.map((t=>x(t))):t}function A(t,e,i){let r,n=S(i)?i:O(i)||Array.isArray(i)?a(x(i)):a((r=(o=i)&&!!(o[Symbol.observable]||o[Symbol.asyncIterator]||o.call&&o.set||o.subscribe||o.then))?void 0:i);var o,s,f,l,u,h,c;return r&&(f=t=>n.value=t,(s=i)&&(c=(s[Symbol.observable]?.()||s).subscribe?.(f,l,undefined),h=c&&(()=>c.unsubscribe?.())||s.set&&s.call?.(u,f)||(s.then?.((t=>{!u&&f(t)}),l)||(async t=>{try{for await(t of s){if(u)return;f(t)}}catch(t){}})())&&(t=>u=1),g.register(s,h))),Object.defineProperty(t,e,{get:()=>n.value,set:!S(i)&&O(i)?t=>t?Object.assign(n.value,t):n.value=x(t):t=>n.value=x(t),enumerable:!0,configurable:!1}),n}function O(t){return t&&t.constructor===Object}var j=(t,e,i,r=null)=>{let n,o,s,f=0,l=i.length,a=e.length,{remove:u,same:h,insert:c,replace:v}=j;for(;f<l&&f<a&&h(e[f],i[f]);)f++;for(;f<l&&f<a&&h(i[l-1],e[a-1]);)r=i[(--a,--l)];if(f==a)for(;f<l;)c(r,i[f++],t);else{for(n=e[f];f<l;)s=i[f++],o=n?n.nextSibling:r,h(n,s)?n=o:f<l&&h(i[f],o)?(v(n,s,t),n=o):c(n,s,t);for(;!h(n,r);)o=n.nextSibling,u(n,t),n=o}return i};j.same=(t,e)=>t==e,j.replace=(t,e,i)=>i.replaceChild(e,t),j.insert=(t,e,i)=>i.insertBefore(e,t),j.remove=(t,e)=>e.removeChild(t);var N=j,E={},W={},k={},$={},U=(t,e,i,r)=>{let n,o=r.startsWith("on")&&r.slice(2),s=T(t,e,":"+r);return o?e=>{n&&_(t,o,n),n=s(e),n&&D(t,o,n)}:e=>C(t,r,s(e))},C=(t,e,i)=>{null==i||!1===i?t.removeAttribute(e):t.setAttribute(e,!0===i?"":"number"==typeof i||"string"==typeof i?i:"")};$[""]=(t,e,i)=>{let r=T(t,e,":");return e=>{let i=r(e);for(let e in i)C(t,I(e),i[e])}};var B=Symbol(":each"),L=Symbol(":ref");$.ref=(t,e,i)=>{t.hasAttribute(":each")?t[L]=e:i[e]=t},$.with=(t,e,i)=>{throw T(t,e,"with"),"Unimplemented"},$.if=(t,e,i)=>{let r=document.createTextNode(""),n=[T(t,e,":if")],o=[t],s=t;for(;(s=t.nextElementSibling)&&s.hasAttribute(":else");)s.removeAttribute(":else"),(e=s.getAttribute(":if"))?(s.removeAttribute(":if"),s.remove(),o.push(s),n.push(T(t,e,":else :if"))):(s.remove(),o.push(s),n.push((()=>1)));return t.replaceWith(s=r),t=>{let e=n.findIndex((e=>e(t)));o[e]!=s&&((s[B]||s).replaceWith(s=o[e]||r),R(s,t))}},$.each=(t,e,i)=>{let r=function(t){let e=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,i=t.match(/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/);if(!i)return;let r={};r.items=i[2].trim();let n=i[1].replace(/^\s*\(|\)\s*$/g,"").trim(),o=n.match(e);return o?(r.item=n.replace(e,"").trim(),r.index=o[1].trim()):r.item=n,r}(e);if(!r)return F(new Error,t,e);const n=t[B]=document.createTextNode("");t.replaceWith(n);const o=T(t,r.items,":each"),s=new WeakMap,f=new WeakMap;let l=[];return e=>{let i=o(e);i?"number"==typeof i?i=Array.from({length:i},((t,e)=>[e,e+1])):i.constructor===Object?i=Object.entries(i):Array.isArray(i)?i=i.map(((t,e)=>[e+1,t])):F(Error("Bad list value"),t,r.items,":each"):i=[];let a=[],u=[];for(let[n,o]of i){let i=null===(h=o)?W:void 0===h?k:"number"==typeof h||h instanceof Number?E[h]||(E[h]=new Number(h)):"string"==typeof h||h instanceof String?E[h]||(E[h]=new String(h)):"boolean"==typeof h||h instanceof Boolean?E[h]||(E[h]=new Boolean(h)):h,l=f.get(i);if(l||(l=t.cloneNode(!0),f.set(i,l)),a.push(l),!s.has(i)){let f=Object.create(e);f[r.item]=o,r.index&&(f[r.index]=n),t[L]&&(f[t[L]]=l),s.set(i,f)}u.push(s.get(i))}var h;N(n.parentNode,l,a,n),l=a;for(let t=0;t<a.length;t++)R(a[t],u[t])}},$.id=(t,e,i)=>{let r=T(t,e,":id");return e=>{return i=r(e),t.id=i||0===i?i:"";var i}},$.class=(t,e,i)=>{let r=T(t,e,":class"),n=t.className;return e=>{let i=r(e);t.className=n+typeof i=="string"?i:(Array.isArray(i)?i:Object.entries(i).map((([t,e])=>e?t:""))).filter(Boolean).join(" ")}},$.style=(t,e,i)=>{let r=T(t,e,":style"),n=t.getAttribute("style")||"";return n.endsWith(";")||(n+="; "),e=>{let i=r(e);if("string"==typeof i)t.setAttribute("style",n+i);else for(let e in i)t.style[e]=i[e]}},$.text=(t,e,i)=>{let r=T(t,e,":text");return e=>{return i=r(e),void(t.textContent=null==i?"":i);var i}},$.value=(t,e,i)=>{let r=T(t,e,":value"),n="text"===t.type||""===t.type?e=>t.setAttribute("value",t.value=null==e?"":e):"checkbox"===t.type?e=>(t.value=e?"on":"",C(t,"checked",e)):"select-one"===t.type?e=>{for(let e in t.options)e.removeAttribute("selected");t.value=e,t.selectedOptions[0]?.setAttribute("selected","")}:e=>t.value=e;return t=>n(r(t))};var P=Symbol("stop");$.on=(t,e,i)=>{let r=T(t,e,":on"),n={};return e=>{for(let e in n)_(t,e,n[e]);n=r(e);for(let e in n)D(t,e,n[e])}};var D=(t,e,i)=>{if(e.indexOf("..")<0)t.addEventListener(e,i);else{const r=e.split("..").map((t=>t.startsWith("on")?t.slice(2):t)),n=(e,o=0)=>{let s=f=>{t.removeEventListener(r[o],s),"function"!=typeof(e=e.call(t,f))&&(e=()=>{}),++o<r.length?n(e,o):i[P]||(console.log("reset"),n(i))};t.addEventListener(r[o],s)};n(i)}},_=(t,e,i)=>{e.indexOf("..")>=0&&(console.log("rewire"),i[P]=!0),t.removeEventListener(e,i)};$.data=(t,e,i)=>{let r=T(t,e,":data");return e=>{let i=r(e);for(let e in i)t.dataset[e]=i[e]}},$.aria=(t,e,i)=>{let r=T(t,e,":aria");return e=>(e=>{for(let i in e)C(t,"aria-"+I(i),null==e[i]?null:e[i]+"")})(r(e))};var M={};function T(t,e,i){if(M[e])return M[e];let r,n=/^[\n\s]*if.*\(.*\)/.test(e)||/^(let|const)\s/.test(e)?`(() => { ${e} })()`:e;try{r=new Function("__scope",`with (__scope) { return (${n}) };`).bind(t)}catch(r){return F(r,t,e,i)}return M[e]=n=>{let o;try{o=r(n)}catch(r){return F(r,t,e,i)}return o}}function F(t,e,i,r){Object.assign(t,{element:e,expression:i}),console.warn(`∴ ${t.message}\n\n${r}=${i?`"${i}"\n\n`:""}`,e),setTimeout((()=>{throw t}),0)}function I(t){return t.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(t=>"-"+t.toLowerCase()))}var z=new WeakMap;function R(t,e){if(!t.children)return;if(z.has(t))return z.get(t);e||={};const i=[],r=(t,n=t.parentNode)=>{if(t.attributes)for(let r=0;r<t.attributes.length;){let o=t.attributes[r];if(":"!==o.name[0]){r++;continue}t.removeAttribute(o.name);let s=o.value;if(!s)continue;let f=o.name.slice(1).split(":");for(let r of f){let o=$[r]||U;if(i.push(o(t,s,e,r)||(()=>{})),z.has(t)||t.parentNode!==n)return!1}}for(let e,i=0;e=t.children[i];i++)!1===r(e,t)&&i--};r(t);const n=x(e);for(let t of i)m((()=>t(n)));return z.set(t,n),n}var Z=R;export{Z as default};
|
package/src/core.js
CHANGED
|
@@ -9,6 +9,7 @@ export default function sprae(container, values) {
|
|
|
9
9
|
if (memo.has(container)) return memo.get(container)
|
|
10
10
|
|
|
11
11
|
values ||= {};
|
|
12
|
+
// FIXME: init values must read "snapshot" of signals to avoid leaking actual signals to directives
|
|
12
13
|
|
|
13
14
|
const updates = []
|
|
14
15
|
|
|
@@ -20,6 +21,7 @@ export default function sprae(container, values) {
|
|
|
20
21
|
if (attr.name[0] !== ':') {i++; continue}
|
|
21
22
|
el.removeAttribute(attr.name)
|
|
22
23
|
let expr = attr.value
|
|
24
|
+
if (!expr) continue
|
|
23
25
|
let attrNames = attr.name.slice(1).split(':')
|
|
24
26
|
for (let attrName of attrNames) {
|
|
25
27
|
let dir = directives[attrName] || defaultDirective;
|
package/src/directives.js
CHANGED
|
@@ -8,14 +8,16 @@ export const directives = {}
|
|
|
8
8
|
|
|
9
9
|
// any-prop directives
|
|
10
10
|
export default (el, expr, values, name) => {
|
|
11
|
-
|
|
12
|
-
// :ona:onb=x -> :on={a:x,b:x}
|
|
13
|
-
// :ona-onb=x -> :on={aB:x}
|
|
14
|
-
return directives.on(el, `{"${name.split('-').map(n=>n.startsWith('on')?n.slice(2):n).join('-')}": ${expr}}`, values)
|
|
15
|
-
}
|
|
11
|
+
let evt = name.startsWith('on') && name.slice(2)
|
|
16
12
|
let evaluate = parseExpr(el, expr, ':'+name)
|
|
17
13
|
|
|
18
|
-
|
|
14
|
+
let value
|
|
15
|
+
return evt ? state => {
|
|
16
|
+
value && removeListener(el, evt, value)
|
|
17
|
+
value = evaluate(state)
|
|
18
|
+
value && addListener(el, evt, value)
|
|
19
|
+
}
|
|
20
|
+
: state => attr(el, name, evaluate(state))
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
// set attr
|
|
@@ -43,6 +45,30 @@ directives['ref'] = (el, expr, values) => {
|
|
|
43
45
|
values[expr] = el;
|
|
44
46
|
}
|
|
45
47
|
|
|
48
|
+
directives['with'] = (el, expr, rootState) => {
|
|
49
|
+
let evaluate = parseExpr(el, expr, 'with')
|
|
50
|
+
|
|
51
|
+
throw 'Unimplemented';
|
|
52
|
+
|
|
53
|
+
// prev iteration
|
|
54
|
+
// // Instead of extending signals (which is a bit hard since signal-struct internals is not uniform)
|
|
55
|
+
// // we bind updating
|
|
56
|
+
// const params = computed(() => Object.assign({}, rootState, evaluate(rootState)))
|
|
57
|
+
|
|
58
|
+
// // NOTE: initialized element doesn't proceed with its children
|
|
59
|
+
// let state = sprae(el, params.value)
|
|
60
|
+
|
|
61
|
+
// // but update is still called with parent state
|
|
62
|
+
// return (rootState) => batch(() => Object.assign(state, params.value))
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
// must be as simple as
|
|
66
|
+
// don't care if root state updates - we're subscribed to it via inheritance _or_ shadowing it
|
|
67
|
+
let withValues = evaluate(rootState);
|
|
68
|
+
let newState = Object.assign(Object.create(rootState), withValues)
|
|
69
|
+
sprae(el, newState)
|
|
70
|
+
}
|
|
71
|
+
|
|
46
72
|
directives['if'] = (el, expr, values) => {
|
|
47
73
|
let holder = document.createTextNode(''),
|
|
48
74
|
clauses = [parseExpr(el, expr, ':if')],
|
|
@@ -212,34 +238,42 @@ directives['value'] = (el, expr, values) => {
|
|
|
212
238
|
return (state) => update(evaluate(state))
|
|
213
239
|
}
|
|
214
240
|
|
|
241
|
+
const _stop = Symbol('stop')
|
|
215
242
|
directives['on'] = (el, expr, values) => {
|
|
216
243
|
let evaluate = parseExpr(el, expr, ':on')
|
|
217
244
|
let listeners = {}
|
|
218
245
|
|
|
219
246
|
return (state) => {
|
|
220
|
-
for (let evt in listeners) el
|
|
221
|
-
|
|
247
|
+
for (let evt in listeners) removeListener(el, evt, listeners[evt])
|
|
222
248
|
listeners = evaluate(state);
|
|
249
|
+
for (let evt in listeners) addListener(el, evt, listeners[evt])
|
|
250
|
+
}
|
|
251
|
+
}
|
|
223
252
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
}
|
|
237
|
-
nextEvt(startFn)
|
|
253
|
+
const addListener = (el, evt, startFn) => {
|
|
254
|
+
if (evt.indexOf('..')<0) el.addEventListener(evt, startFn);
|
|
255
|
+
|
|
256
|
+
// sequences like `a..b`: fn
|
|
257
|
+
else {
|
|
258
|
+
const evts = evt.split('..').map(e => e.startsWith('on') ? e.slice(2) : e)
|
|
259
|
+
const nextEvt = (fn, cur=0) => {
|
|
260
|
+
let curListener = e => {
|
|
261
|
+
el.removeEventListener(evts[cur], curListener)
|
|
262
|
+
if (typeof (fn = fn.call(el,e)) !== 'function') fn = ()=>{}
|
|
263
|
+
if (++cur < evts.length) nextEvt(fn, cur);
|
|
264
|
+
else if (!startFn[_stop]) console.log('reset'), nextEvt(startFn); // update only if chain isn't stopped
|
|
238
265
|
}
|
|
239
|
-
|
|
266
|
+
el.addEventListener(evts[cur],curListener)
|
|
267
|
+
}
|
|
268
|
+
nextEvt(startFn)
|
|
240
269
|
}
|
|
241
270
|
}
|
|
242
271
|
|
|
272
|
+
const removeListener = (el, evt, fn) => {
|
|
273
|
+
if (evt.indexOf('..')>=0) console.log('rewire'), fn[_stop] = true
|
|
274
|
+
el.removeEventListener(evt, fn);
|
|
275
|
+
}
|
|
276
|
+
|
|
243
277
|
directives['data'] = (el, expr, values) => {
|
|
244
278
|
let evaluate = parseExpr(el, expr, ':data')
|
|
245
279
|
|
|
@@ -301,4 +335,4 @@ export function exprError(error, element, expression, dir) {
|
|
|
301
335
|
|
|
302
336
|
function dashcase(str) {
|
|
303
337
|
return str.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g, (match) => '-' + match.toLowerCase());
|
|
304
|
-
};
|
|
338
|
+
};
|
package/test/test.js
CHANGED
|
@@ -44,6 +44,12 @@ test('common: reactive', async () => {
|
|
|
44
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">`)
|
|
45
45
|
})
|
|
46
46
|
|
|
47
|
+
test('common: empty strings', async () => {
|
|
48
|
+
let el = h`<x :="" :x=""></x>`
|
|
49
|
+
sprae(el)
|
|
50
|
+
is(el.outerHTML, `<x></x>`)
|
|
51
|
+
})
|
|
52
|
+
|
|
47
53
|
test('style', async () => {
|
|
48
54
|
let el = h`<x style="left: 1px" :style="style"></x>`
|
|
49
55
|
let params = sprae(el, {style: "top: 1px"})
|
|
@@ -347,24 +353,40 @@ test('on: base', () => {
|
|
|
347
353
|
is(log.value, ['click','x','xx']);
|
|
348
354
|
})
|
|
349
355
|
|
|
356
|
+
test('onevt: this context', e => {
|
|
357
|
+
let el = h`<div :onx="function(){log.push(this)}"></div>`
|
|
358
|
+
let state = sprae(el, {log: []})
|
|
359
|
+
el.dispatchEvent(new window.Event('x'));
|
|
360
|
+
is(state.log, [el])
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
test('on: this in chains refers to el', () => {
|
|
364
|
+
let el = h`<div :ona..onb="function(e){x=this; log.push(1); return () => log.push(2)}"></div>`
|
|
365
|
+
let state = sprae(el, {log:[], x:null})
|
|
366
|
+
el.dispatchEvent(new window.Event('a'));
|
|
367
|
+
is(state.log, [1])
|
|
368
|
+
})
|
|
369
|
+
|
|
350
370
|
test('on: multiple events', e => {
|
|
351
|
-
let el = h`<div :onscroll:onclick="e=>log.push(e.type)"></div>`
|
|
371
|
+
let el = h`<div :onscroll:onclick:onx="e=>log.push(e.type)"></div>`
|
|
352
372
|
let state = sprae(el, {log:[]})
|
|
353
373
|
|
|
354
374
|
el.dispatchEvent(new window.Event('click'));
|
|
355
375
|
is(state.log, ['click'])
|
|
356
376
|
el.dispatchEvent(new window.Event('scroll'));
|
|
357
377
|
is(state.log, ['click','scroll'])
|
|
378
|
+
el.dispatchEvent(new window.Event('x'));
|
|
379
|
+
is(state.log, ['click','scroll','x'])
|
|
358
380
|
})
|
|
359
381
|
|
|
360
382
|
test('on: in-out events', e => {
|
|
361
383
|
// let el = document.createElement('x');
|
|
362
|
-
// el.setAttribute(':onmousedown
|
|
363
|
-
let el = h`<x :onmousedown
|
|
364
|
-
|
|
365
|
-
let state = sprae(el, {log:[]})
|
|
384
|
+
// el.setAttribute(':onmousedown..onmouseup', 'e=>(log.push(e.type),e=>log.push(e.type))')
|
|
385
|
+
let el = h`<x :onmousedown..onmouseup="(e) => { x=this; log.push(e.type); return e=>log.push(e.type); }"></x>`
|
|
366
386
|
|
|
387
|
+
let state = sprae(el, {log:[],x:null})
|
|
367
388
|
el.dispatchEvent(new window.Event('mousedown'));
|
|
389
|
+
is(state.x, el);
|
|
368
390
|
is(state.log, ['mousedown'])
|
|
369
391
|
el.dispatchEvent(new window.Event('mouseup'));
|
|
370
392
|
is(state.log, ['mousedown','mouseup'])
|
|
@@ -374,7 +396,7 @@ test('on: in-out side-effects', e => {
|
|
|
374
396
|
let log = []
|
|
375
397
|
|
|
376
398
|
// 1. skip in event and do directly out
|
|
377
|
-
let el = h`<x :onin
|
|
399
|
+
let el = h`<x :onin..onout="io"></x>`
|
|
378
400
|
sprae(el, { io(e) {
|
|
379
401
|
log.push(e.type)
|
|
380
402
|
return (e) => (log.push(e.type), [1,2,3])
|
|
@@ -401,7 +423,7 @@ test('on: in-out side-effects', e => {
|
|
|
401
423
|
})
|
|
402
424
|
|
|
403
425
|
test('on: chain of events', e => {
|
|
404
|
-
let el = h`<div :onmousedown
|
|
426
|
+
let el = h`<div :onmousedown..onmousemove..onmouseup="e=>(log.push(e.type),e=>(log.push(e.type),e=>log.push(e.type)))"></div>`
|
|
405
427
|
let state = sprae(el, {log:[]})
|
|
406
428
|
|
|
407
429
|
el.dispatchEvent(new window.Event('mousedown'));
|
|
@@ -412,7 +434,36 @@ test('on: chain of events', e => {
|
|
|
412
434
|
is(state.log, ['mousedown','mousemove','mouseup'])
|
|
413
435
|
})
|
|
414
436
|
|
|
415
|
-
test
|
|
437
|
+
test('on: state changes between chain of events', e => {
|
|
438
|
+
let el = h`<x :on="{'x..y':fn}"></x>`
|
|
439
|
+
let log = []
|
|
440
|
+
let state = sprae(el, {log, fn: () => console.log('log1')||log.push(1)})
|
|
441
|
+
console.log('xx')
|
|
442
|
+
el.dispatchEvent(new window.Event('x'));
|
|
443
|
+
el.dispatchEvent(new window.Event('x'));
|
|
444
|
+
is(log, [1])
|
|
445
|
+
state.fn = () => (console.log('log1.1')||log.push(1.1), () => log.push(2))
|
|
446
|
+
is(log, [1])
|
|
447
|
+
// console.log('xx')
|
|
448
|
+
// NOTE: state update registers new chain listener before finishing prev chain
|
|
449
|
+
// el.dispatchEvent(new window.Event('x'));
|
|
450
|
+
// el.dispatchEvent(new window.Event('x'));
|
|
451
|
+
// is(log, [1])
|
|
452
|
+
console.log('yy')
|
|
453
|
+
el.dispatchEvent(new window.Event('y'));
|
|
454
|
+
el.dispatchEvent(new window.Event('y'));
|
|
455
|
+
is(log, [1])
|
|
456
|
+
console.log('xx')
|
|
457
|
+
el.dispatchEvent(new window.Event('x'));
|
|
458
|
+
el.dispatchEvent(new window.Event('x'));
|
|
459
|
+
is(log, [1, 1.1])
|
|
460
|
+
console.log('yy')
|
|
461
|
+
el.dispatchEvent(new window.Event('y'));
|
|
462
|
+
el.dispatchEvent(new window.Event('y'));
|
|
463
|
+
is(log, [1, 1.1, 2])
|
|
464
|
+
})
|
|
465
|
+
|
|
466
|
+
test.todo('with: inline', () => {
|
|
416
467
|
let el = h`<x :with="{foo:'bar', baz}"><y :text="foo + baz"></y></x>`
|
|
417
468
|
let state = sprae(el, {baz: 'qux'})
|
|
418
469
|
// FIXME: this doesn't inherit root scope baz property and instead uses hard-initialized one
|
|
@@ -420,7 +471,7 @@ test.skip('with: inline', () => {
|
|
|
420
471
|
state.baz = 'quux'
|
|
421
472
|
is(el.innerHTML, `<y>barquux</y>`)
|
|
422
473
|
})
|
|
423
|
-
test.
|
|
474
|
+
test.todo('with: inline reactive', () => {
|
|
424
475
|
let el = h`<x :with="{foo:'bar', baz}"><y :text="foo + baz"></y></x>`
|
|
425
476
|
let baz = signal('qux')
|
|
426
477
|
let state = sprae(el, {baz})
|
|
@@ -429,7 +480,7 @@ test.skip('with: inline reactive', () => {
|
|
|
429
480
|
baz.value = 'quux'
|
|
430
481
|
is(el.innerHTML, `<y>barquux</y>`)
|
|
431
482
|
})
|
|
432
|
-
test.
|
|
483
|
+
test.todo('with: data', () => {
|
|
433
484
|
let el = h`<x :with="x"><y :text="foo"></y></x>`
|
|
434
485
|
let state = sprae(el, {x:{foo:'bar'}})
|
|
435
486
|
is(el.innerHTML, `<y>bar</y>`)
|
|
@@ -437,7 +488,7 @@ test.skip('with: data', () => {
|
|
|
437
488
|
Object.assign(state, {x:{foo:'baz'}})
|
|
438
489
|
is(el.innerHTML, `<y>baz</y>`)
|
|
439
490
|
})
|
|
440
|
-
test.
|
|
491
|
+
test.todo('with: transparency', () => {
|
|
441
492
|
// NOTE: y:text initializes through directive, not through parent
|
|
442
493
|
// therefore by default :text uses parent's state, not defined by element itself
|
|
443
494
|
let el = h`<x :with="{foo:'foo'}"><y :with="b" :text="foo+bar"></y></x>`
|
|
@@ -446,7 +497,7 @@ test.skip('with: transparency', () => {
|
|
|
446
497
|
params.b.bar = 'baz'
|
|
447
498
|
is(el.innerHTML, `<y>foobaz</y>`)
|
|
448
499
|
})
|
|
449
|
-
test.
|
|
500
|
+
test.todo('with: reactive transparency', () => {
|
|
450
501
|
let el = h`<x :with="{foo:1}"><y :with="b.c" :text="foo+bar"></y></x>`
|
|
451
502
|
const bar = signal('2')
|
|
452
503
|
sprae(el, {b:{c:{bar}}})
|
|
@@ -454,7 +505,7 @@ test.skip('with: reactive transparency', () => {
|
|
|
454
505
|
bar.value = '3'
|
|
455
506
|
is(el.innerHTML, `<y>13</y>`)
|
|
456
507
|
})
|
|
457
|
-
test.
|
|
508
|
+
test.todo('with: writes to state', () => {
|
|
458
509
|
let a = h`<x :with="{a:1}"><y :on="{x(){a++}}" :text="a"></y></x>`
|
|
459
510
|
sprae(a)
|
|
460
511
|
is(a.innerHTML, `<y>1</y>`)
|
|
@@ -492,13 +543,19 @@ test(':: reactive values', async () => {
|
|
|
492
543
|
is(el.outerHTML, `<x>2</x>`)
|
|
493
544
|
})
|
|
494
545
|
|
|
546
|
+
test(':: null result does nothing', async () => {
|
|
547
|
+
let a = h`<x :="undefined"></x>`
|
|
548
|
+
sprae(a)
|
|
549
|
+
is(a.outerHTML, `<x></x>`)
|
|
550
|
+
})
|
|
551
|
+
|
|
495
552
|
test(':: scope refers to current element', async () => {
|
|
496
553
|
let el = h`<x :text="log.push(this)"></x>`
|
|
497
554
|
let state = sprae(el, {log:[]})
|
|
498
555
|
is(state.log, [el])
|
|
499
556
|
})
|
|
500
557
|
|
|
501
|
-
test.
|
|
558
|
+
test.todo(':: scope directives must come first', async () => {
|
|
502
559
|
// NOTE: we init attributes in order of definition
|
|
503
560
|
let a = h`<x :text="y" :with="{y:1}" :ref="x"></x>`
|
|
504
561
|
sprae(a, {})
|