sprae 2.7.0 → 2.8.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 +2 -2
- package/r&d.md +62 -14
- package/readme.md +19 -4
- package/sprae.js +191 -65
- package/sprae.min.js +1 -1
- package/src/directives.js +126 -50
- package/test/test.js +77 -7
- package/todo.md +4 -1
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sprae",
|
|
3
3
|
"description": "DOM microhydration.",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.8.0",
|
|
5
5
|
"main": "src/index.js",
|
|
6
6
|
"module": "src/index.js",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"dependencies": {
|
|
9
9
|
"@preact/signals-core": "^1.2.2",
|
|
10
10
|
"primitive-pool": "^2.0.0",
|
|
11
|
-
"signal-struct": "^1.
|
|
11
|
+
"signal-struct": "^1.10.0",
|
|
12
12
|
"swapdom": "^1.1.1"
|
|
13
13
|
},
|
|
14
14
|
"devDependencies": {
|
package/r&d.md
CHANGED
|
@@ -289,9 +289,9 @@
|
|
|
289
289
|
* @sprae/item: `<x :item="{type:a, scope:b}"` – provide microdata
|
|
290
290
|
- can be solved naturally, unless there's special meaning
|
|
291
291
|
* @sprae/hcodes: `<x :hcode=""` – provide microformats
|
|
292
|
-
* @sprae/with
|
|
293
|
-
* @sprae/onconnected
|
|
294
292
|
* @sprae/onvisible?
|
|
293
|
+
- can be solved externally
|
|
294
|
+
* @sprae/onintersects
|
|
295
295
|
|
|
296
296
|
## [x] Write any-attributes via `:<prop>? -> yep`
|
|
297
297
|
|
|
@@ -330,7 +330,7 @@
|
|
|
330
330
|
+ Provides precisely controlled sandbox
|
|
331
331
|
- Some limited lang opportunities
|
|
332
332
|
- need to match many syntax quirks, can be tedious
|
|
333
|
-
~ can be fine to limit expressions to meaningful default:
|
|
333
|
+
~ can be fine to limit expressions to meaningful default: no Proxy, generators, awaits, global access etc.
|
|
334
334
|
- Somewhat heavy to bundle
|
|
335
335
|
~ 1-2kb is not super-heavy, besides kicks out signal-struct (with preact signals?)
|
|
336
336
|
+ Scope is easier to provide: no need for signal proxy
|
|
@@ -340,6 +340,7 @@
|
|
|
340
340
|
+ Deps can be analyzed / implemented without signals
|
|
341
341
|
- Screwed up debugging / stacktrace (unless errored properly)
|
|
342
342
|
~+ can actually provide better trace since no internal framework stuff is shown
|
|
343
|
+
+ can let means to enhance subscript's logs
|
|
343
344
|
+ that "unlimits" returned struct, so that any property can be added/deleted.
|
|
344
345
|
- doesn't really save from `new (()=>{}).constructor` hack: we gotta substitute objects too.
|
|
345
346
|
+ allows easier handle of `:with="a=1,b=2,c=3"` - we just naturally get local variables without messup with global
|
|
@@ -349,9 +350,10 @@
|
|
|
349
350
|
|
|
350
351
|
2. Use sandboxed proxy
|
|
351
352
|
- tough evaluation
|
|
352
|
-
-
|
|
353
|
+
- implementation hiccups
|
|
353
354
|
- screwed up data
|
|
354
355
|
- no full protection
|
|
356
|
+
- relatively slow
|
|
355
357
|
+ does minimal catch
|
|
356
358
|
|
|
357
359
|
## [x] :onclick="direct code" ? -> no: immediately invoked.
|
|
@@ -374,19 +376,23 @@
|
|
|
374
376
|
? maybe id should have same signature
|
|
375
377
|
? should it be very similar mechanism to `:with="a=1,b=2"`
|
|
376
378
|
|
|
377
|
-
## [
|
|
379
|
+
## [x] Event modifiers :ona.once, `:ona` -> let's try, there's a lot of use for both props and event
|
|
378
380
|
|
|
379
381
|
- .prevent,.stop - not needed since expects a function
|
|
380
382
|
? or should we just trigger it for user?
|
|
381
383
|
? :onclick.outside
|
|
382
384
|
? :onclick.window, :onclick.document
|
|
383
|
-
|
|
384
|
-
? :onclick.
|
|
385
|
-
|
|
385
|
+
+ can be needed, eg. mousedown..up can happen outside of current element (stop caret tracking in waveplay)
|
|
386
|
+
? :onclick.once, :onclick.passive, :onclick.capture
|
|
387
|
+
+ can pass props to event listener: there's no other way to do that
|
|
388
|
+
? :onclick.debounce-330
|
|
389
|
+
? :onclick.throttle-750
|
|
390
|
+
+ ...just handy everydayers and saves tons of noise
|
|
386
391
|
? :onclick.self
|
|
392
|
+
~ clicked on self, not the child
|
|
387
393
|
? :onspecial-event.camel, :onx-y.dot
|
|
388
|
-
|
|
389
|
-
? :onkeypress.shift.enter
|
|
394
|
+
~
|
|
395
|
+
? :onkeypress.shift.enter, :onmousemove.shift, :onmousemove.alt
|
|
390
396
|
.shift Shift
|
|
391
397
|
.enter Enter
|
|
392
398
|
.space Space
|
|
@@ -394,15 +400,57 @@
|
|
|
394
400
|
.cmd Cmd
|
|
395
401
|
.meta Cmd on Mac, Windows key on Windows
|
|
396
402
|
.alt Alt
|
|
397
|
-
.up .down .left .right
|
|
403
|
+
.up .down .left .right
|
|
398
404
|
.escape Escape
|
|
399
405
|
.tab Tab
|
|
400
406
|
.caps-lock Caps Lock
|
|
401
|
-
.equal Equal
|
|
402
|
-
.period Period
|
|
403
|
-
.slash Foward Slash
|
|
407
|
+
.equal Equal
|
|
408
|
+
.period Period
|
|
409
|
+
.slash Foward Slash
|
|
410
|
+
+ allows separating various key handlers: atm waveplay handles separate keys in the same method `handleKey`
|
|
411
|
+
+ allows tracking mouse interactions with shift hold
|
|
404
412
|
- conflict with dot-separated events
|
|
413
|
+
~not so popular nor encouraged
|
|
405
414
|
- lots of ad-hoc non-standard rules, can be handled in code
|
|
415
|
+
+ allow multiple setters for same props or multiple listeners for same events
|
|
416
|
+
+ oldschool jquery-compatible events
|
|
417
|
+
|
|
418
|
+
## [x] Mods design -> use event modifiers, not props modifiers
|
|
419
|
+
|
|
420
|
+
* [ ] ~~Prop modifiers~~
|
|
421
|
+
- overall seems code complication without much benefit
|
|
422
|
+
* [ ] value.bind? value.watch?
|
|
423
|
+
- let's wait for use-case: value can be too big to set it every time
|
|
424
|
+
* [ ] prop.reflect, prop.observe
|
|
425
|
+
- let's wait for use-case
|
|
426
|
+
* [ ] prop.boolean, .number, .string, .array, .object
|
|
427
|
+
- let's wait for use-case
|
|
428
|
+
* [ ] prop.once, prop.fx ? prop.init?
|
|
429
|
+
- doesn't seem required, let's wait for use case
|
|
430
|
+
* [ ] prop.change - run only if value changes
|
|
431
|
+
- seems like unnecessary manual optimization that must be done always automatically
|
|
432
|
+
? are there cases where force-update is necessary?
|
|
433
|
+
* [ ] prop.throttle-xxx, prop.debounce-xxx
|
|
434
|
+
- let's wait until that's really a problem
|
|
435
|
+
* [ ] prop.class
|
|
436
|
+
? what's the use-case
|
|
437
|
+
|
|
438
|
+
* [x] Event modifiers
|
|
439
|
+
* [x] onevt.x, onevt.y
|
|
440
|
+
+ jquery-like
|
|
441
|
+
+ multiple same events
|
|
442
|
+
* [x] onevt.once, onevt.passive, onevt.capture
|
|
443
|
+
+ standard props passing
|
|
444
|
+
* [x] onevt.prevent, onevt.stop
|
|
445
|
+
+ conventional mods
|
|
446
|
+
* [x] onevt.outside onevt.window, onevt.document, onevt.self
|
|
447
|
+
+ useful handlers, conventional mods
|
|
448
|
+
* [x] onevt.throttle-xxx, onevt.debounce-xxx
|
|
449
|
+
+ conventional
|
|
450
|
+
* [x] onevt.shift, onevt.cmd.shift, onevt.meta
|
|
451
|
+
+ conventional
|
|
452
|
+
* [x] onkey.enter, .space, .up|.down|.left|.right, .escape, .tab, .period, .slash, .caps-lock
|
|
453
|
+
+ conventional
|
|
406
454
|
|
|
407
455
|
## [x] Writing props on elements (like ones in :each) -> nah, just use `:x="this.x=abc"`
|
|
408
456
|
|
package/readme.md
CHANGED
|
@@ -2,9 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
> DOM microhydration with `:` attributes
|
|
4
4
|
|
|
5
|
-
A lightweight essential alternative to [alpine](https://github.com/alpinejs/alpine), [petite-vue](https://github.com/vuejs/petite-vue), [templize](https://github.com/dy/templize) or JSX with better ergonomics[*](#justification).<br>
|
|
6
|
-
It is reminiscent of [XSLT](https://www.w3schools.com/xml/xsl_intro.asp), considered a [buried treasure](https://github.com/bahrus/be-restated) by web-connoisseurs.
|
|
7
|
-
|
|
8
5
|
|
|
9
6
|
## Usage
|
|
10
7
|
|
|
@@ -163,10 +160,22 @@ Add event listeners.
|
|
|
163
160
|
}
|
|
164
161
|
}">
|
|
165
162
|
|
|
163
|
+
<!-- Event modifiers -->
|
|
164
|
+
<button :onclick.throttle-500="handler">Not too often</button>
|
|
165
|
+
|
|
166
166
|
<!-- Bulk/custom events -->
|
|
167
167
|
<button :on="{ click: handler, touch: handler, special: handler }">Submit</button>
|
|
168
168
|
```
|
|
169
169
|
|
|
170
|
+
##### Event modifiers
|
|
171
|
+
|
|
172
|
+
* `.once`, `.passive`, `.capture` – listener [options](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#options).
|
|
173
|
+
* `.prevent`, `.stop` – prevent default or stop propagation.
|
|
174
|
+
* `.window`, `.document`, `.outside`, `.self` – specify event target.
|
|
175
|
+
* `.throttle-108`, `.debounce-108` – define throttling or postponing callback with (optional) timeout in ms.
|
|
176
|
+
* `.ctrl`, `.shift`, `.alt`, `.meta`, `.cmd`, `.down`, `.up`, `.left`, `.right`, `.end`, `.home`, `.pagedown`, `.pageup`, `.enter`, `.plus`, `.minus`, `.star`, `.slash`, `.period`, `.equal`, `.underscore`, `.esc`, `.escape`, `.tab`, `.space`, `.backspace`, `.delete` – filter by [`event.key`](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values).
|
|
177
|
+
* `.*` – any other modifier has no effect, but allows binding multiple handlers to same event (like jQuery event classes).
|
|
178
|
+
|
|
170
179
|
#### `:data="values"`
|
|
171
180
|
|
|
172
181
|
Set [data-*](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/data-*) attributes. CamelCase is converted to dash-case.
|
|
@@ -334,11 +343,13 @@ This way, for example, _@preact/signals_ or _rxjs_ can be connected directly byp
|
|
|
334
343
|
|
|
335
344
|
## Justification
|
|
336
345
|
|
|
346
|
+
_Sprae_ is lightweight essential alternative to [alpine](https://github.com/alpinejs/alpine), [petite-vue](https://github.com/vuejs/petite-vue), [templize](https://github.com/dy/templize) or JSX with better ergonomics[*](#justification).
|
|
347
|
+
|
|
337
348
|
* [Template-parts](https://github.com/dy/template-parts) / [templize](https://github.com/dy/templize) is progressive, but is stuck with native HTML quirks ([parsing table](https://github.com/github/template-parts/issues/24), [svg attributes](https://github.com/github/template-parts/issues/25), [liquid syntax](https://shopify.github.io/liquid/tags/template/#raw) conflict etc). Also ergonomics of `attr="{{}}"` is inferior to `:attr=""` since it creates flash of uninitialized values.
|
|
338
349
|
* [Alpine](https://github.com/alpinejs/alpine) / [vue](https://github.com/vuejs/petite-vue) / [lit](https://github.com/lit/lit/tree/main/packages/lit-html) escapes native HTML quirks, but the syntax is a bit scattered: `:attr`, `v-*`,`x-*`, `@evt`, `{{}}` can be expressed with single convention. Besides, functionality is too broad and can be reduced to essence: perfection is when there's nothing to take away, not add. Also they tend to [self-encapsulate](https://github.com/alpinejs/alpine/discussions/3223), making interop hard.
|
|
339
350
|
* React/[preact](https://ghub.io/preact) does the job wiring up JS to HTML, but with an extreme of migrating HTML to JSX and enforcing SPA, which is not organic for HTML. Also it doesn't support reactive fields (needs render call).
|
|
340
351
|
|
|
341
|
-
|
|
352
|
+
_Sprae_ takes convention of _templize directives_ (_alpine_/_vue_ attrs) and builds upon [_@preact/signals_](https://ghub.io/@preact/signals).
|
|
342
353
|
|
|
343
354
|
* It doesn't break static html markup.
|
|
344
355
|
* It falls back to element content if uninitialized.
|
|
@@ -349,4 +360,8 @@ _sprae_ takes convention of _templize directives_ (_alpine_/_vue_ attrs) and bui
|
|
|
349
360
|
* Input data may contain [signals](https://ghub.io/@preact/signals) or [reactive values](https://ghub.io/sube).
|
|
350
361
|
* Elements / data API is open and enable easy interop.
|
|
351
362
|
|
|
363
|
+
|
|
364
|
+
It is reminiscent of [XSLT](https://www.w3schools.com/xml/xsl_intro.asp), considered a [buried treasure](https://github.com/bahrus/be-restated) by web-connoisseurs.
|
|
365
|
+
|
|
366
|
+
|
|
352
367
|
<p align="center"><a href="https://github.com/krsnzd/license/">🕉</a></p>
|
package/sprae.js
CHANGED
|
@@ -71,16 +71,16 @@ function v(i2) {
|
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
|
-
function
|
|
74
|
+
function e2(i2) {
|
|
75
75
|
this.v = i2;
|
|
76
76
|
this.i = 0;
|
|
77
77
|
this.n = void 0;
|
|
78
78
|
this.t = void 0;
|
|
79
79
|
}
|
|
80
|
-
|
|
80
|
+
e2.prototype.h = function() {
|
|
81
81
|
return true;
|
|
82
82
|
};
|
|
83
|
-
|
|
83
|
+
e2.prototype.S = function(i2) {
|
|
84
84
|
if (this.t !== i2 && void 0 === i2.e) {
|
|
85
85
|
i2.x = this.t;
|
|
86
86
|
if (void 0 !== this.t)
|
|
@@ -88,7 +88,7 @@ e.prototype.S = function(i2) {
|
|
|
88
88
|
this.t = i2;
|
|
89
89
|
}
|
|
90
90
|
};
|
|
91
|
-
|
|
91
|
+
e2.prototype.U = function(i2) {
|
|
92
92
|
var t2 = i2.e, h2 = i2.x;
|
|
93
93
|
if (void 0 !== t2) {
|
|
94
94
|
t2.x = h2;
|
|
@@ -101,7 +101,7 @@ e.prototype.U = function(i2) {
|
|
|
101
101
|
if (i2 === this.t)
|
|
102
102
|
this.t = h2;
|
|
103
103
|
};
|
|
104
|
-
|
|
104
|
+
e2.prototype.subscribe = function(i2) {
|
|
105
105
|
var t2 = this;
|
|
106
106
|
return b(function() {
|
|
107
107
|
var h2 = t2.value, o2 = 32 & this.f;
|
|
@@ -113,16 +113,16 @@ e.prototype.subscribe = function(i2) {
|
|
|
113
113
|
}
|
|
114
114
|
});
|
|
115
115
|
};
|
|
116
|
-
|
|
116
|
+
e2.prototype.valueOf = function() {
|
|
117
117
|
return this.value;
|
|
118
118
|
};
|
|
119
|
-
|
|
119
|
+
e2.prototype.toString = function() {
|
|
120
120
|
return this.value + "";
|
|
121
121
|
};
|
|
122
|
-
|
|
122
|
+
e2.prototype.peek = function() {
|
|
123
123
|
return this.v;
|
|
124
124
|
};
|
|
125
|
-
Object.defineProperty(
|
|
125
|
+
Object.defineProperty(e2.prototype, "value", { get: function() {
|
|
126
126
|
var i2 = v(this);
|
|
127
127
|
if (void 0 !== i2)
|
|
128
128
|
i2.i = this.i;
|
|
@@ -144,7 +144,7 @@ Object.defineProperty(e.prototype, "value", { get: function() {
|
|
|
144
144
|
}
|
|
145
145
|
} });
|
|
146
146
|
function u(i2) {
|
|
147
|
-
return new
|
|
147
|
+
return new e2(i2);
|
|
148
148
|
}
|
|
149
149
|
function d(i2) {
|
|
150
150
|
for (var t2 = i2.s; void 0 !== t2; t2 = t2.n)
|
|
@@ -183,13 +183,13 @@ function a(i2) {
|
|
|
183
183
|
i2.s = h2;
|
|
184
184
|
}
|
|
185
185
|
function l(i2) {
|
|
186
|
-
|
|
186
|
+
e2.call(this, void 0);
|
|
187
187
|
this.x = i2;
|
|
188
188
|
this.s = void 0;
|
|
189
189
|
this.g = f - 1;
|
|
190
190
|
this.f = 4;
|
|
191
191
|
}
|
|
192
|
-
(l.prototype = new
|
|
192
|
+
(l.prototype = new e2()).h = function() {
|
|
193
193
|
this.f &= -3;
|
|
194
194
|
if (1 & this.f)
|
|
195
195
|
return false;
|
|
@@ -230,10 +230,10 @@ l.prototype.S = function(i2) {
|
|
|
230
230
|
for (var t2 = this.s; void 0 !== t2; t2 = t2.n)
|
|
231
231
|
t2.S.S(t2);
|
|
232
232
|
}
|
|
233
|
-
|
|
233
|
+
e2.prototype.S.call(this, i2);
|
|
234
234
|
};
|
|
235
235
|
l.prototype.U = function(i2) {
|
|
236
|
-
|
|
236
|
+
e2.prototype.U.call(this, i2);
|
|
237
237
|
if (void 0 === this.t) {
|
|
238
238
|
this.f &= -33;
|
|
239
239
|
for (var t2 = this.s; void 0 !== t2; t2 = t2.n)
|
|
@@ -408,7 +408,7 @@ function signalStruct(values, proto) {
|
|
|
408
408
|
try {
|
|
409
409
|
Object.assign(s2.value, v2);
|
|
410
410
|
return;
|
|
411
|
-
} catch (
|
|
411
|
+
} catch (e3) {
|
|
412
412
|
}
|
|
413
413
|
s2.value = Object.seal(signalStruct(v2));
|
|
414
414
|
} else if (Array.isArray(v2))
|
|
@@ -425,7 +425,8 @@ function signalStruct(values, proto) {
|
|
|
425
425
|
return state;
|
|
426
426
|
}
|
|
427
427
|
if (Array.isArray(values) && !isStruct(values[0])) {
|
|
428
|
-
|
|
428
|
+
for (let i2 = 0; i2 < values.length; i2++)
|
|
429
|
+
values[i2] = signalStruct(values[i2]);
|
|
429
430
|
}
|
|
430
431
|
return values;
|
|
431
432
|
}
|
|
@@ -486,10 +487,6 @@ var primitive_pool_default = (key) => {
|
|
|
486
487
|
// src/directives.js
|
|
487
488
|
var primary = {};
|
|
488
489
|
var secondary = {};
|
|
489
|
-
primary["with"] = (el, expr, rootState) => {
|
|
490
|
-
let evaluate = parseExpr(el, expr, "with");
|
|
491
|
-
sprae(el, signalStruct(evaluate(rootState), rootState));
|
|
492
|
-
};
|
|
493
490
|
primary["if"] = (el, expr) => {
|
|
494
491
|
let holder = document.createTextNode(""), clauses = [parseExpr(el, expr, ":if")], els = [el], cur = el;
|
|
495
492
|
while (cur = el.nextElementSibling) {
|
|
@@ -511,11 +508,16 @@ primary["if"] = (el, expr) => {
|
|
|
511
508
|
return (state) => {
|
|
512
509
|
let i2 = clauses.findIndex((f2) => f2(state));
|
|
513
510
|
if (els[i2] != cur) {
|
|
511
|
+
;
|
|
514
512
|
(cur[_each] || cur).replaceWith(cur = els[i2] || holder);
|
|
515
513
|
sprae(cur, state);
|
|
516
514
|
}
|
|
517
515
|
};
|
|
518
516
|
};
|
|
517
|
+
primary["with"] = (el, expr, rootState) => {
|
|
518
|
+
let evaluate = parseExpr(el, expr, "with");
|
|
519
|
+
sprae(el, signalStruct(evaluate(rootState), rootState));
|
|
520
|
+
};
|
|
519
521
|
var _each = Symbol(":each");
|
|
520
522
|
primary["each"] = (tpl, expr) => {
|
|
521
523
|
let each = parseForExpression(expr);
|
|
@@ -622,6 +624,31 @@ secondary["text"] = (el, expr) => {
|
|
|
622
624
|
el.textContent = value == null ? "" : value;
|
|
623
625
|
};
|
|
624
626
|
};
|
|
627
|
+
secondary["data"] = (el, expr) => {
|
|
628
|
+
let evaluate = parseExpr(el, expr, ":data");
|
|
629
|
+
return (state) => {
|
|
630
|
+
let value = evaluate(state);
|
|
631
|
+
for (let key in value)
|
|
632
|
+
el.dataset[key] = value[key];
|
|
633
|
+
};
|
|
634
|
+
};
|
|
635
|
+
secondary["aria"] = (el, expr) => {
|
|
636
|
+
let evaluate = parseExpr(el, expr, ":aria");
|
|
637
|
+
const update = (value) => {
|
|
638
|
+
for (let key in value)
|
|
639
|
+
attr(el, "aria-" + dashcase(key), value[key] == null ? null : value[key] + "");
|
|
640
|
+
};
|
|
641
|
+
return (state) => update(evaluate(state));
|
|
642
|
+
};
|
|
643
|
+
secondary[""] = (el, expr) => {
|
|
644
|
+
let evaluate = parseExpr(el, expr, ":");
|
|
645
|
+
if (evaluate)
|
|
646
|
+
return (state) => {
|
|
647
|
+
let value = evaluate(state);
|
|
648
|
+
for (let key in value)
|
|
649
|
+
attr(el, dashcase(key), value[key]);
|
|
650
|
+
};
|
|
651
|
+
};
|
|
625
652
|
secondary["value"] = (el, expr) => {
|
|
626
653
|
let evaluate = parseExpr(el, expr, ":value");
|
|
627
654
|
let from, to;
|
|
@@ -645,16 +672,35 @@ secondary["on"] = (el, expr) => {
|
|
|
645
672
|
};
|
|
646
673
|
};
|
|
647
674
|
};
|
|
675
|
+
var directives_default = (el, expr, state, name) => {
|
|
676
|
+
let evt = name.startsWith("on") && name.slice(2);
|
|
677
|
+
let evaluate = parseExpr(el, expr, ":" + name);
|
|
678
|
+
if (!evaluate)
|
|
679
|
+
return;
|
|
680
|
+
if (evt)
|
|
681
|
+
return (state2) => {
|
|
682
|
+
let value = evaluate(state2);
|
|
683
|
+
if (value) {
|
|
684
|
+
addListener(el, evt, value);
|
|
685
|
+
return () => removeListener(el, evt, value);
|
|
686
|
+
}
|
|
687
|
+
};
|
|
688
|
+
return (state2) => attr(el, name, evaluate(state2));
|
|
689
|
+
};
|
|
648
690
|
var _stop = Symbol("stop");
|
|
649
691
|
var addListener = (el, evt, startFn) => {
|
|
650
|
-
|
|
651
|
-
|
|
692
|
+
let evts = evt.split("..").map((e3) => e3.startsWith("on") ? e3.slice(2) : e3), opts = {};
|
|
693
|
+
evts[0] = evts[0].replace(
|
|
694
|
+
/\.(\w+)?-?([\w]+)?/g,
|
|
695
|
+
(match, mod, param) => (mod = mods[mod]) ? ([el, startFn] = mod(el, startFn, opts, param), "") : ""
|
|
696
|
+
);
|
|
697
|
+
if (evts.length == 1)
|
|
698
|
+
el.addEventListener(evts[0], startFn, opts);
|
|
652
699
|
else {
|
|
653
|
-
const evts = evt.split("..").map((e2) => e2.startsWith("on") ? e2.slice(2) : e2);
|
|
654
700
|
const nextEvt = (fn, cur = 0) => {
|
|
655
|
-
let curListener = (
|
|
701
|
+
let curListener = (e3) => {
|
|
656
702
|
el.removeEventListener(evts[cur], curListener);
|
|
657
|
-
if (typeof (fn = fn.call(el,
|
|
703
|
+
if (typeof (fn = fn.call(el, e3)) !== "function")
|
|
658
704
|
fn = () => {
|
|
659
705
|
};
|
|
660
706
|
if (++cur < evts.length)
|
|
@@ -662,7 +708,7 @@ var addListener = (el, evt, startFn) => {
|
|
|
662
708
|
else if (!startFn[_stop])
|
|
663
709
|
nextEvt(startFn);
|
|
664
710
|
};
|
|
665
|
-
el.addEventListener(evts[cur], curListener);
|
|
711
|
+
el.addEventListener(evts[cur], curListener, opts);
|
|
666
712
|
};
|
|
667
713
|
nextEvt(startFn);
|
|
668
714
|
}
|
|
@@ -672,43 +718,123 @@ var removeListener = (el, evt, fn) => {
|
|
|
672
718
|
fn[_stop] = true;
|
|
673
719
|
el.removeEventListener(evt, fn);
|
|
674
720
|
};
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
let
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
const update = (value) => {
|
|
686
|
-
for (let key in value)
|
|
687
|
-
attr(el, "aria-" + dashcase(key), value[key] == null ? null : value[key] + "");
|
|
688
|
-
};
|
|
689
|
-
return (state) => update(evaluate(state));
|
|
690
|
-
};
|
|
691
|
-
secondary[""] = (el, expr) => {
|
|
692
|
-
let evaluate = parseExpr(el, expr, ":");
|
|
693
|
-
if (evaluate)
|
|
694
|
-
return (state) => {
|
|
695
|
-
let value = evaluate(state);
|
|
696
|
-
for (let key in value)
|
|
697
|
-
attr(el, dashcase(key), value[key]);
|
|
721
|
+
var mods = {
|
|
722
|
+
throttle(el, cb, opts, limit) {
|
|
723
|
+
limit = Number(limit) || 108;
|
|
724
|
+
let pause, planned, block = () => {
|
|
725
|
+
pause = true;
|
|
726
|
+
setTimeout(() => {
|
|
727
|
+
pause = false;
|
|
728
|
+
if (planned)
|
|
729
|
+
cb(e), planned = false, block();
|
|
730
|
+
});
|
|
698
731
|
};
|
|
732
|
+
return [el, (e3) => {
|
|
733
|
+
if (pause)
|
|
734
|
+
return planned = true;
|
|
735
|
+
cb(e3);
|
|
736
|
+
block();
|
|
737
|
+
}];
|
|
738
|
+
},
|
|
739
|
+
debounce(el, cb, opts, wait) {
|
|
740
|
+
wait = Number(wait) || 108;
|
|
741
|
+
let timeout, later = () => {
|
|
742
|
+
timeout = null;
|
|
743
|
+
cb(e);
|
|
744
|
+
};
|
|
745
|
+
return [el, (e3) => {
|
|
746
|
+
clearTimeout(timeout);
|
|
747
|
+
timeout = setTimeout(later, wait);
|
|
748
|
+
}];
|
|
749
|
+
},
|
|
750
|
+
window(el, cb) {
|
|
751
|
+
return [window, cb];
|
|
752
|
+
},
|
|
753
|
+
document(el, cb) {
|
|
754
|
+
return [document, cb];
|
|
755
|
+
},
|
|
756
|
+
outside(el, cb) {
|
|
757
|
+
return [el, (e3) => {
|
|
758
|
+
if (el.contains(e3.target))
|
|
759
|
+
return;
|
|
760
|
+
if (e3.target.isConnected === false)
|
|
761
|
+
return;
|
|
762
|
+
if (el.offsetWidth < 1 && el.offsetHeight < 1)
|
|
763
|
+
return;
|
|
764
|
+
cb(e3);
|
|
765
|
+
}];
|
|
766
|
+
},
|
|
767
|
+
prevent(el, cb) {
|
|
768
|
+
return [el, (e3) => {
|
|
769
|
+
e3.preventDefault();
|
|
770
|
+
cb(e3);
|
|
771
|
+
}];
|
|
772
|
+
},
|
|
773
|
+
stop(el, cb) {
|
|
774
|
+
return [el, (e3) => {
|
|
775
|
+
e3.stopPropagation();
|
|
776
|
+
cb(e3);
|
|
777
|
+
}];
|
|
778
|
+
},
|
|
779
|
+
self(el, cb) {
|
|
780
|
+
return [el, (e3) => {
|
|
781
|
+
e3.target === el && cb(e3);
|
|
782
|
+
}];
|
|
783
|
+
},
|
|
784
|
+
once(el, cb, opts) {
|
|
785
|
+
opts.once = true;
|
|
786
|
+
return [el, cb];
|
|
787
|
+
},
|
|
788
|
+
passive(el, cb, opts) {
|
|
789
|
+
opts.passive = true;
|
|
790
|
+
return [el, cb];
|
|
791
|
+
},
|
|
792
|
+
capture(el, cb, opts) {
|
|
793
|
+
opts.capture = true;
|
|
794
|
+
return [el, cb];
|
|
795
|
+
}
|
|
699
796
|
};
|
|
700
|
-
var
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
797
|
+
var keys = {
|
|
798
|
+
ctrl: "Control Ctrl",
|
|
799
|
+
shift: "Shift",
|
|
800
|
+
alt: "Alt",
|
|
801
|
+
meta: "Meta",
|
|
802
|
+
cmd: "Meta",
|
|
803
|
+
down: "ArrowDown",
|
|
804
|
+
up: "ArrowUp",
|
|
805
|
+
left: "ArrowLeft",
|
|
806
|
+
right: "ArrowRight",
|
|
807
|
+
arrowdown: "ArrowDown",
|
|
808
|
+
arrowup: "ArrowUp",
|
|
809
|
+
arrowleft: "ArrowLeft",
|
|
810
|
+
arrowright: "ArrowRight",
|
|
811
|
+
end: "End",
|
|
812
|
+
home: "Home",
|
|
813
|
+
pagedown: "PageDown",
|
|
814
|
+
pageup: "PageUp",
|
|
815
|
+
enter: "Enter",
|
|
816
|
+
plus: "+",
|
|
817
|
+
minus: "-",
|
|
818
|
+
star: "*",
|
|
819
|
+
slash: "/",
|
|
820
|
+
period: ".",
|
|
821
|
+
equal: "=",
|
|
822
|
+
underscore: "_",
|
|
823
|
+
esc: "Escape",
|
|
824
|
+
escape: "Escape",
|
|
825
|
+
tab: "Tab",
|
|
826
|
+
space: " ",
|
|
827
|
+
backspace: "Backspace",
|
|
828
|
+
delete: "Delete"
|
|
829
|
+
};
|
|
830
|
+
for (let keyAttr in keys) {
|
|
831
|
+
let keyName = keys[keyAttr];
|
|
832
|
+
mods[keyAttr] = (el, cb, opts, extraKey) => [el, (e3) => {
|
|
833
|
+
if (!e3.key || !keyName.includes(e3.key))
|
|
834
|
+
return;
|
|
835
|
+
cb(e3);
|
|
836
|
+
}];
|
|
837
|
+
}
|
|
712
838
|
var attr = (el, name, v2) => {
|
|
713
839
|
if (v2 == null || v2 === false)
|
|
714
840
|
el.removeAttribute(name);
|
|
@@ -722,16 +848,16 @@ function parseExpr(el, expression, dir) {
|
|
|
722
848
|
let rightSideSafeExpression = /^[\n\s]*if.*\(.*\)/.test(expression) || /^(let|const)\s/.test(expression) ? `(() => { ${expression} })()` : expression;
|
|
723
849
|
try {
|
|
724
850
|
evaluate = evaluatorMemo[expression] = new Function(`__scope`, `with (__scope) { return ${rightSideSafeExpression} };`);
|
|
725
|
-
} catch (
|
|
726
|
-
return exprError(
|
|
851
|
+
} catch (e3) {
|
|
852
|
+
return exprError(e3, el, expression, dir);
|
|
727
853
|
}
|
|
728
854
|
}
|
|
729
855
|
return (state) => {
|
|
730
856
|
let result;
|
|
731
857
|
try {
|
|
732
858
|
result = evaluate.call(el, state);
|
|
733
|
-
} catch (
|
|
734
|
-
return exprError(
|
|
859
|
+
} catch (e3) {
|
|
860
|
+
return exprError(e3, el, expression, dir);
|
|
735
861
|
}
|
|
736
862
|
return result;
|
|
737
863
|
};
|
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)&&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 l(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 f(t){this.v=t,this.i=0,this.n=void 0,this.t=void 0}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 a(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 h(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 c(t){f.call(this,void 0),this.x=t,this.s=void 0,this.g=s-1,this.f=4}function v(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,p(t),e}finally{i=o,e()}}}function p(t){for(var e=t.s;void 0!==e;e=e.n)e.S.U(e);t.x=void 0,t.s=void 0,v(t)}function d(t){if(i!==this)throw new Error("Out-of-order effect");h(this),i=t,this.f&=-2,8&this.f&&p(this),e()}function y(t){this.x=t,this.u=void 0,this.s=void 0,this.o=void 0,this.f=32}function b(t){var e=new y(t);return e.c(),e.d.bind(e)}f.prototype.h=function(){return!0},f.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)},f.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)},f.prototype.subscribe=function(t){var e=this;return b((function(){var i=e.value,r=32&this.f;this.f&=-33;try{t(i)}finally{this.f|=r}}))},f.prototype.valueOf=function(){return this.value},f.prototype.toString=function(){return this.value+""},f.prototype.peek=function(){return this.v},Object.defineProperty(f.prototype,"value",{get:function(){var t=l(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()}}}}),(c.prototype=new f).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{a(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,h(this),this.f&=-2,!0},c.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)}f.prototype.S.call(this,t)},c.prototype.U=function(t){if(f.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)}},c.prototype.N=function(){if(!(2&this.f)){this.f|=6;for(var t=this.t;void 0!==t;t=t.x)t.t.N()}},c.prototype.peek=function(){if(this.h()||t(),16&this.f)throw this.v;return this.v},Object.defineProperty(c.prototype,"value",{get:function(){1&this.f&&t();var e=l(this);if(this.h(),void 0!==e&&(e.i=this.i),16&this.f)throw this.v;return this.v}}),y.prototype.c=function(){var t=this.S();try{8&this.f||void 0===this.x||(this.u=this.x())}finally{t()}},y.prototype.S=function(){1&this.f&&t(),this.f|=1,this.f&=-9,v(this),a(this),n++;var e=i;return i=this,d.bind(this,e)},y.prototype.N=function(){2&this.f||(this.f|=2,this.o=r,r=this)},y.prototype.d=function(){this.f|=8,1&this.f||p(this)},Symbol.observable||=Symbol("observable");var m=new FinalizationRegistry((t=>t.call?.())),g=(t,e,i,r,n,o)=>{return t&&(s=(t[Symbol.observable]?.()||t).subscribe?.(e,i,r),o=s&&(()=>s.unsubscribe?.())||t.set&&t.call?.(n,e)||(t.then?.((t=>(!n&&e(t),r?.())),i)||(async o=>{try{for await(o of t){if(n)return;e(o)}r?.()}catch(t){i?.(t)}})())&&(t=>n=1),m.register(t,o),o);var s},S=t=>t&&t[A],A=Symbol("signal-struct");function w(t,e){if(S(t)&&!e)return t;if(x(t)){const n=Object.create(e||Object.getPrototypeOf(t)),o={},s=Object.getOwnPropertyDescriptors(t);for(let t in s){let e=s[t];if(e.get){let i=o[t]=new c(e.get.bind(n));Object.defineProperty(n,t,{get:()=>i.value,set:e.set?.bind(n),configurable:!1,enumerable:!0})}else{let s=e.value,l=(r=s)&&!!(r[Symbol.observable]||r[Symbol.asyncIterator]||r.call&&r.set||r.subscribe||r.then),u=o[t]=(i=s)&&i.peek?s:new f(l?void 0:x(s)?Object.seal(w(s)):Array.isArray(s)?w(s):s);l&&g(s,(t=>u.value=t)),Object.defineProperty(n,t,{get:()=>u.value,set(t){if(x(t)){if(x(u.value))try{return void Object.assign(u.value,t)}catch(t){}u.value=Object.seal(w(t))}else Array.isArray(t)?u.value=w(t):u.value=t},enumerable:!0,configurable:!1})}}return Object.defineProperty(n,A,{configurable:!1,enumerable:!1,value:!0}),n}var i,r;return Array.isArray(t)&&!S(t[0])?t.map((t=>w(t))):t}function x(t){return t&&t.constructor===Object}w.isStruct=S;var O=(t,e,i,r=null)=>{let n,o,s,l=0,f=i.length,u=e.length,{remove:a,same:h,insert:c,replace:v}=O;for(;l<f&&l<u&&h(e[l],i[l]);)l++;for(;l<f&&l<u&&h(i[f-1],e[u-1]);)r=i[(--u,--f)];if(l==u)for(;l<f;)c(r,i[l++],t);else{for(n=e[l];l<f;)s=i[l++],o=n?n.nextSibling:r,h(n,s)?n=o:l<f&&h(i[l],o)?(v(n,s,t),n=o):c(n,s,t);for(;!h(n,r);)o=n.nextSibling,a(n,t),n=o}return i};O.same=(t,e)=>t==e,O.replace=(t,e,i)=>i.replaceChild(e,t),O.insert=(t,e,i)=>i.insertBefore(e,t),O.remove=(t,e)=>e.removeChild(t);var j=O,N={},E={},k={},W=t=>null===t?E:void 0===t?k:"number"==typeof t||t instanceof Number?N[t]||(N[t]=new Number(t)):"string"==typeof t||t instanceof String?N[t]||(N[t]=new String(t)):"boolean"==typeof t||t instanceof Boolean?N[t]||(N[t]=new Boolean(t)):t,$={},P={};$.with=(t,e,i)=>{z(t,w(M(t,e,"with")(i),i))},$.if=(t,e)=>{let i=document.createTextNode(""),r=[M(t,e,":if")],n=[t],o=t;for(;(o=t.nextElementSibling)&&o.hasAttribute(":else");)o.removeAttribute(":else"),(e=o.getAttribute(":if"))?(o.removeAttribute(":if"),o.remove(),n.push(o),r.push(M(t,e,":else :if"))):(o.remove(),n.push(o),r.push((()=>1)));return t.replaceWith(o=i),t=>{let e=r.findIndex((e=>e(t)));n[e]!=o&&((o[C]||o).replaceWith(o=n[e]||i),z(o,t))}};var C=Symbol(":each");$.each=(t,e)=>{let i=function(t){let e=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,i=t.match(/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/);if(!i)return;let r=i[2].trim(),n=i[1].replace(/^\s*\(|\)\s*$/g,"").trim(),o=n.match(e);return o?[n.replace(e,"").trim(),o[1].trim(),r]:[n,"",r]}(e);if(!i)return R(new Error,t,e);const r=t[C]=document.createTextNode("");t.replaceWith(r);const n=M(t,i[2],":each"),o=t.getAttribute(":key"),s=o?M(null,o):null;t.removeAttribute(":key");const l=new WeakMap,f=new WeakMap;let u=[];return o=>{let a=n(o);a?"number"==typeof a?a=Array.from({length:a},((t,e)=>[e,e+1])):Array.isArray(a)?a=a.map(((t,e)=>[e+1,t])):"object"==typeof a?a=Object.entries(a):R(Error("Bad list value"),t,e,":each"):a=[];let h=[],c=[];for(let[e,r]of a){let n,u,a=s?.({[i[0]]:r,[i[1]]:e});("string"==typeof(v=a)||"boolean"==typeof v||"number"==typeof v)&&(a=W(a)),null==a?n=t.cloneNode(!0):(n=f.get(a))||f.set(a,n=t.cloneNode(!0)),h.push(n),null!=a&&(u=l.get(a))?u[i[0]]=r:(u=w({[i[0]]:r,[i[1]]:e},o),null!=a&&l.set(a,u)),c.push(u)}var v;j(r.parentNode,u,h,r),u=h;for(let t=0;t<h.length;t++)z(h[t],c[t])}},P.ref=(t,e,i)=>{i[e]=t},P.id=(t,e)=>{let i=M(t,e,":id");return e=>{return r=i(e),t.id=r||0===r?r:"";var r}},P.class=(t,e)=>{let i=M(t,e,":class"),r=t.className;return e=>{let n=i(e);t.className=r+typeof n=="string"?n:(Array.isArray(n)?n:Object.entries(n).map((([t,e])=>e?t:""))).filter(Boolean).join(" ")}},P.style=(t,e)=>{let i=M(t,e,":style"),r=t.getAttribute("style")||"";return r.endsWith(";")||(r+="; "),e=>{let n=i(e);if("string"==typeof n)t.setAttribute("style",r+n);else for(let e in n)t.style[e]=n[e]}},P.text=(t,e)=>{let i=M(t,e,":text");return e=>{let r=i(e);t.textContent=null==r?"":r}},P.value=(t,e)=>{let i,r,n=M(t,e,":value"),o="text"===t.type||""===t.type?e=>t.setAttribute("value",t.value=null==e?"":e):"TEXTAREA"===t.tagName||"text"===t.type||""===t.type?e=>(i=t.selectionStart,r=t.selectionEnd,t.setAttribute("value",t.value=null==e?"":e),i&&t.setSelectionRange(i,r)):"checkbox"===t.type?e=>(t.value=e?"on":"",D(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=>o(n(t))},P.on=(t,e)=>{let i=M(t,e,":on");return e=>{let r=i(e);for(let e in r)B(t,e,r[e]);return()=>{for(let e in r)L(t,e,r[e])}}};var U=Symbol("stop"),B=(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=l=>{t.removeEventListener(r[o],s),"function"!=typeof(e=e.call(t,l))&&(e=()=>{}),++o<r.length?n(e,o):i[U]||n(i)};t.addEventListener(r[o],s)};n(i)}},L=(t,e,i)=>{e.indexOf("..")>=0&&(i[U]=!0),t.removeEventListener(e,i)};P.data=(t,e)=>{let i=M(t,e,":data");return e=>{let r=i(e);for(let e in r)t.dataset[e]=r[e]}},P.aria=(t,e)=>{let i=M(t,e,":aria");return e=>(e=>{for(let i in e)D(t,"aria-"+F(i),null==e[i]?null:e[i]+"")})(i(e))},P[""]=(t,e)=>{let i=M(t,e,":");if(i)return e=>{let r=i(e);for(let e in r)D(t,F(e),r[e])}};var T=(t,e,i,r)=>{let n=r.startsWith("on")&&r.slice(2),o=M(t,e,":"+r);if(o)return n?e=>{let i=o(e);if(i)return B(t,n,i),()=>L(t,n,i)}:e=>D(t,r,o(e))},D=(t,e,i)=>{null==i||!1===i?t.removeAttribute(e):t.setAttribute(e,!0===i?"":"number"==typeof i||"string"==typeof i?i:"")},_={};function M(t,e,i){let r=_[e];if(!r){let n=/^[\n\s]*if.*\(.*\)/.test(e)||/^(let|const)\s/.test(e)?`(() => { ${e} })()`:e;try{r=_[e]=new Function("__scope",`with (__scope) { return ${n} };`)}catch(r){return R(r,t,e,i)}}return n=>{let o;try{o=r.call(t,n)}catch(r){return R(r,t,e,i)}return o}}function R(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 F(t){return t.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(t=>"-"+t.toLowerCase()))}var I=new WeakMap;function z(t,i){if(!t.children)return;if(I.has(t)){let r=I.get(t);return function(t){if(n>0)return t();n++;try{t()}finally{e()}}((()=>Object.assign(r,i))),r}const r=w(i||{}),o=[],s=(t,e=t.parentNode)=>{for(let i in $){let n=":"+i;if(t.hasAttribute?.(n)){let s=t.getAttribute(n);if(t.removeAttribute(n),!s)continue;if(o.push($[i](t,s,r,i)),I.has(t)||t.parentNode!==e)return!1}}if(t.attributes)for(let i=0;i<t.attributes.length;){let n=t.attributes[i];if(":"!==n.name[0]){i++;continue}t.removeAttribute(n.name);let s=n.value;if(!s)continue;let l=n.name.slice(1).split(":");for(let i of l){let n=P[i]||T;if(o.push(n(t,s,r,i)),I.has(t)||t.parentNode!==e)return!1}}for(let e,i=0;e=t.children[i];i++)!1===s(e,t)&&i--};s(t);for(let t of o)if(t){let e;b((()=>{"function"==typeof e&&e(),e=t(r)}))}return Object.seal(r),I.set(t,r),r}var X=z;export{X as default};
|
|
1
|
+
function t(){throw new Error("Cycle detected")}function r(){if(o>1)o--;else{for(var t,e=!1;void 0!==n;){var r=n;for(n=void 0,s++;void 0!==r;){var i=r.o;if(r.o=void 0,r.f&=-3,!(8&r.f)&&f(r))try{r.c()}catch(r){e||(t=r,e=!0)}r=i}}if(s=0,o--,e)throw t}}var i=void 0,n=void 0,o=0,s=0,l=0;function a(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 u(t){this.v=t,this.i=0,this.n=void 0,this.t=void 0}function f(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 c(t){for(var e=t.s;void 0!==e;e=e.n){var r=e.S.n;void 0!==r&&(e.r=r),e.S.n=e,e.i=-1}}function h(t){for(var e=t.s,r=void 0;void 0!==e;){var i=e.n;-1===e.i?(e.S.U(e),e.n=void 0):(void 0!==r&&(r.p=e),e.p=void 0,e.n=r,r=e),e.S.n=e.r,void 0!==e.r&&(e.r=void 0),e=i}t.s=r}function v(t){u.call(this,void 0),this.x=t,this.s=void 0,this.g=l-1,this.f=4}function p(t){var e=t.u;if(t.u=void 0,"function"==typeof e){o++;var n=i;i=void 0;try{e()}catch(e){throw t.f&=-2,t.f|=8,d(t),e}finally{i=n,r()}}}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");h(this),i=t,this.f&=-2,8&this.f&&d(this),r()}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)}u.prototype.h=function(){return!0},u.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)},u.prototype.U=function(t){var e=t.e,r=t.x;void 0!==e&&(e.x=r,t.e=void 0),void 0!==r&&(r.e=e,t.x=void 0),t===this.t&&(this.t=r)},u.prototype.subscribe=function(t){var e=this;return m((function(){var r=e.value,i=32&this.f;this.f&=-33;try{t(r)}finally{this.f|=i}}))},u.prototype.valueOf=function(){return this.value},u.prototype.toString=function(){return this.value+""},u.prototype.peek=function(){return this.v},Object.defineProperty(u.prototype,"value",{get:function(){var t=a(this);return void 0!==t&&(t.i=this.i),this.v},set:function(e){if(e!==this.v){s>100&&t(),this.v=e,this.i++,l++,o++;try{for(var i=this.t;void 0!==i;i=i.x)i.t.N()}finally{r()}}}}),(v.prototype=new u).h=function(){if(this.f&=-3,1&this.f)return!1;if(32==(36&this.f))return!0;if(this.f&=-5,this.g===l)return!0;if(this.g=l,this.f|=1,this.i>0&&!f(this))return this.f&=-2,!0;var t=i;try{c(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,h(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)}u.prototype.S.call(this,t)},v.prototype.U=function(t){if(u.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=a(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),c(this),o++;var e=i;return i=this,y.bind(this,e)},b.prototype.N=function(){2&this.f||(this.f|=2,this.o=n,n=this)},b.prototype.d=function(){this.f|=8,1&this.f||d(this)},Symbol.observable||=Symbol("observable");var g=new FinalizationRegistry((t=>t.call?.())),w=(t,e,r,i,n,o)=>{return t&&(s=(t[Symbol.observable]?.()||t).subscribe?.(e,r,i),o=s&&(()=>s.unsubscribe?.())||t.set&&t.call?.(n,e)||(t.then?.((t=>(!n&&e(t),i?.())),r)||(async o=>{try{for await(o of t){if(n)return;e(o)}i?.()}catch(t){r?.(t)}})())&&(t=>n=1),g.register(t,o),o);var s},A=t=>t&&t[S],S=Symbol("signal-struct");function x(t,e){if(A(t)&&!e)return t;if(O(t)){const n=Object.create(e||Object.getPrototypeOf(t)),o={},s=Object.getOwnPropertyDescriptors(t);for(let t in s){let e=s[t];if(e.get){let r=o[t]=new v(e.get.bind(n));Object.defineProperty(n,t,{get:()=>r.value,set:e.set?.bind(n),configurable:!1,enumerable:!0})}else{let s=e.value,l=(i=s)&&!!(i[Symbol.observable]||i[Symbol.asyncIterator]||i.call&&i.set||i.subscribe||i.then),a=o[t]=(r=s)&&r.peek?s:new u(l?void 0:O(s)?Object.seal(x(s)):Array.isArray(s)?x(s):s);l&&w(s,(t=>a.value=t)),Object.defineProperty(n,t,{get:()=>a.value,set(t){if(O(t)){if(O(a.value))try{return void Object.assign(a.value,t)}catch(t){}a.value=Object.seal(x(t))}else Array.isArray(t)?a.value=x(t):a.value=t},enumerable:!0,configurable:!1})}}return Object.defineProperty(n,S,{configurable:!1,enumerable:!1,value:!0}),n}var r,i;if(Array.isArray(t)&&!A(t[0]))for(let e=0;e<t.length;e++)t[e]=x(t[e]);return t}function O(t){return t&&t.constructor===Object}x.isStruct=A;var j=(t,e,r,i=null)=>{let n,o,s,l=0,a=r.length,u=e.length,{remove:f,same:c,insert:h,replace:v}=j;for(;l<a&&l<u&&c(e[l],r[l]);)l++;for(;l<a&&l<u&&c(r[a-1],e[u-1]);)i=r[(--u,--a)];if(l==u)for(;l<a;)h(i,r[l++],t);else{for(n=e[l];l<a;)s=r[l++],o=n?n.nextSibling:i,c(n,s)?n=o:l<a&&c(r[l],o)?(v(n,s,t),n=o):h(n,s,t);for(;!c(n,i);)o=n.nextSibling,f(n,t),n=o}return r};j.same=(t,e)=>t==e,j.replace=(t,e,r)=>r.replaceChild(e,t),j.insert=(t,e,r)=>r.insertBefore(e,t),j.remove=(t,e)=>e.removeChild(t);var N=j,E={},k={},P={},W=t=>null===t?k:void 0===t?P:"number"==typeof t||t instanceof Number?E[t]||(E[t]=new Number(t)):"string"==typeof t||t instanceof String?E[t]||(E[t]=new String(t)):"boolean"==typeof t||t instanceof Boolean?E[t]||(E[t]=new Boolean(t)):t,C={},D={};C.if=(t,e)=>{let r=document.createTextNode(""),i=[H(t,e,":if")],n=[t],o=t;for(;(o=t.nextElementSibling)&&o.hasAttribute(":else");)o.removeAttribute(":else"),(e=o.getAttribute(":if"))?(o.removeAttribute(":if"),o.remove(),n.push(o),i.push(H(t,e,":else :if"))):(o.remove(),n.push(o),i.push((()=>1)));return t.replaceWith(o=r),t=>{let e=i.findIndex((e=>e(t)));n[e]!=o&&((o[T]||o).replaceWith(o=n[e]||r),X(o,t))}},C.with=(t,e,r)=>{X(t,x(H(t,e,"with")(r),r))};var T=Symbol(":each");C.each=(t,e)=>{let r=function(t){let e=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,r=t.match(/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/);if(!r)return;let i=r[2].trim(),n=r[1].replace(/^\s*\(|\)\s*$/g,"").trim(),o=n.match(e);return o?[n.replace(e,"").trim(),o[1].trim(),i]:[n,"",i]}(e);if(!r)return I(new Error,t,e);const i=t[T]=document.createTextNode("");t.replaceWith(i);const n=H(t,r[2],":each"),o=t.getAttribute(":key"),s=o?H(null,o):null;t.removeAttribute(":key");const l=new WeakMap,a=new WeakMap;let u=[];return o=>{let f=n(o);f?"number"==typeof f?f=Array.from({length:f},((t,e)=>[e,e+1])):Array.isArray(f)?f=f.map(((t,e)=>[e+1,t])):"object"==typeof f?f=Object.entries(f):I(Error("Bad list value"),t,e,":each"):f=[];let c=[],h=[];for(let[e,i]of f){let n,u,f=s?.({[r[0]]:i,[r[1]]:e});("string"==typeof(v=f)||"boolean"==typeof v||"number"==typeof v)&&(f=W(f)),null==f?n=t.cloneNode(!0):(n=a.get(f))||a.set(f,n=t.cloneNode(!0)),c.push(n),null!=f&&(u=l.get(f))?u[r[0]]=i:(u=x({[r[0]]:i,[r[1]]:e},o),null!=f&&l.set(f,u)),h.push(u)}var v;N(i.parentNode,u,c,i),u=c;for(let t=0;t<c.length;t++)X(c[t],h[t])}},D.ref=(t,e,r)=>{r[e]=t},D.id=(t,e)=>{let r=H(t,e,":id");return e=>{return i=r(e),t.id=i||0===i?i:"";var i}},D.class=(t,e)=>{let r=H(t,e,":class"),i=t.className;return e=>{let n=r(e);t.className=i+typeof n=="string"?n:(Array.isArray(n)?n:Object.entries(n).map((([t,e])=>e?t:""))).filter(Boolean).join(" ")}},D.style=(t,e)=>{let r=H(t,e,":style"),i=t.getAttribute("style")||"";return i.endsWith(";")||(i+="; "),e=>{let n=r(e);if("string"==typeof n)t.setAttribute("style",i+n);else for(let e in n)t.style[e]=n[e]}},D.text=(t,e)=>{let r=H(t,e,":text");return e=>{let i=r(e);t.textContent=null==i?"":i}},D.data=(t,e)=>{let r=H(t,e,":data");return e=>{let i=r(e);for(let e in i)t.dataset[e]=i[e]}},D.aria=(t,e)=>{let r=H(t,e,":aria");return e=>(e=>{for(let r in e)_(t,"aria-"+q(r),null==e[r]?null:e[r]+"")})(r(e))},D[""]=(t,e)=>{let r=H(t,e,":");if(r)return e=>{let i=r(e);for(let e in i)_(t,q(e),i[e])}},D.value=(t,e)=>{let r,i,n=H(t,e,":value"),o="text"===t.type||""===t.type?e=>t.setAttribute("value",t.value=null==e?"":e):"TEXTAREA"===t.tagName||"text"===t.type||""===t.type?e=>(r=t.selectionStart,i=t.selectionEnd,t.setAttribute("value",t.value=null==e?"":e),r&&t.setSelectionRange(r,i)):"checkbox"===t.type?e=>(t.value=e?"on":"",_(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=>o(n(t))},D.on=(t,e)=>{let r=H(t,e,":on");return e=>{let i=r(e);for(let e in i)L(t,e,i[e]);return()=>{for(let e in i)B(t,e,i[e])}}};var U=(t,e,r,i)=>{let n=i.startsWith("on")&&i.slice(2),o=H(t,e,":"+i);if(o)return n?e=>{let r=o(e);if(r)return L(t,n,r),()=>B(t,n,r)}:e=>_(t,i,o(e))},$=Symbol("stop"),L=(t,e,r)=>{let i=e.split("..").map((t=>t.startsWith("on")?t.slice(2):t)),n={};if(i[0]=i[0].replace(/\.(\w+)?-?([\w]+)?/g,((e,i,o)=>(i=M[i])?([t,r]=i(t,r,n,o),""):"")),1==i.length)t.addEventListener(i[0],r,n);else{const e=(o,s=0)=>{let l=n=>{t.removeEventListener(i[s],l),"function"!=typeof(o=o.call(t,n))&&(o=()=>{}),++s<i.length?e(o,s):r[$]||e(r)};t.addEventListener(i[s],l,n)};e(r)}},B=(t,e,r)=>{e.indexOf("..")>=0&&(r[$]=!0),t.removeEventListener(e,r)},M={throttle(t,r,i,n){n=Number(n)||108;let o,s,l=()=>{o=!0,setTimeout((()=>{o=!1,s&&(r(e),s=!1,l())}))};return[t,t=>{if(o)return s=!0;r(t),l()}]},debounce(t,r,i,n){n=Number(n)||108;let o,s=()=>{o=null,r(e)};return[t,t=>{clearTimeout(o),o=setTimeout(s,n)}]},window:(t,e)=>[window,e],document:(t,e)=>[document,e],outside:(t,e)=>[t,r=>{t.contains(r.target)||!1!==r.target.isConnected&&(t.offsetWidth<1&&t.offsetHeight<1||e(r))}],prevent:(t,e)=>[t,t=>{t.preventDefault(),e(t)}],stop:(t,e)=>[t,t=>{t.stopPropagation(),e(t)}],self:(t,e)=>[t,r=>{r.target===t&&e(r)}],once:(t,e,r)=>(r.once=!0,[t,e]),passive:(t,e,r)=>(r.passive=!0,[t,e]),capture:(t,e,r)=>(r.capture=!0,[t,e])},R={ctrl:"Control Ctrl",shift:"Shift",alt:"Alt",meta:"Meta",cmd:"Meta",down:"ArrowDown",up:"ArrowUp",left:"ArrowLeft",right:"ArrowRight",arrowdown:"ArrowDown",arrowup:"ArrowUp",arrowleft:"ArrowLeft",arrowright:"ArrowRight",end:"End",home:"Home",pagedown:"PageDown",pageup:"PageUp",enter:"Enter",plus:"+",minus:"-",star:"*",slash:"/",period:".",equal:"=",underscore:"_",esc:"Escape",escape:"Escape",tab:"Tab",space:" ",backspace:"Backspace",delete:"Delete"};for(let t in R){let e=R[t];M[t]=(t,r,i,n)=>[t,t=>{t.key&&e.includes(t.key)&&r(t)}]}var _=(t,e,r)=>{null==r||!1===r?t.removeAttribute(e):t.setAttribute(e,!0===r?"":"number"==typeof r||"string"==typeof r?r:"")},F={};function H(t,e,r){let i=F[e];if(!i){let n=/^[\n\s]*if.*\(.*\)/.test(e)||/^(let|const)\s/.test(e)?`(() => { ${e} })()`:e;try{i=F[e]=new Function("__scope",`with (__scope) { return ${n} };`)}catch(i){return I(i,t,e,r)}}return n=>{let o;try{o=i.call(t,n)}catch(i){return I(i,t,e,r)}return o}}function I(t,e,r,i){Object.assign(t,{element:e,expression:r}),console.warn(`∴ ${t.message}\n\n${i}=${r?`"${r}"\n\n`:""}`,e),setTimeout((()=>{throw t}),0)}function q(t){return t.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(t=>"-"+t.toLowerCase()))}var z=new WeakMap;function X(t,e){if(!t.children)return;if(z.has(t)){let i=z.get(t);return function(t){if(o>0)return t();o++;try{t()}finally{r()}}((()=>Object.assign(i,e))),i}const i=x(e||{}),n=[],s=(t,e=t.parentNode)=>{for(let r in C){let o=":"+r;if(t.hasAttribute?.(o)){let s=t.getAttribute(o);if(t.removeAttribute(o),!s)continue;if(n.push(C[r](t,s,i,r)),z.has(t)||t.parentNode!==e)return!1}}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 l=o.name.slice(1).split(":");for(let r of l){let o=D[r]||U;if(n.push(o(t,s,i,r)),z.has(t)||t.parentNode!==e)return!1}}for(let e,r=0;e=t.children[r];r++)!1===s(e,t)&&r--};s(t);for(let t of n)if(t){let e;m((()=>{"function"==typeof e&&e(),e=t(i)}))}return Object.seal(i),z.set(t,i),i}var Z=X;export{Z as default};
|
package/src/directives.js
CHANGED
|
@@ -9,13 +9,9 @@ import p from 'primitive-pool'
|
|
|
9
9
|
export const primary = {}, secondary = {}
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
// :with must come before :if or :each or anyone else
|
|
13
|
-
primary['with'] = (el, expr, rootState) => {
|
|
14
|
-
let evaluate = parseExpr(el, expr, 'with')
|
|
15
|
-
sprae(el, signalStruct(evaluate(rootState), rootState));
|
|
16
|
-
}
|
|
17
|
-
|
|
18
12
|
// :if is interchangeable with :each depending on order, :if :each or :each :if have different meanings
|
|
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
|
|
19
15
|
primary['if'] = (el, expr) => {
|
|
20
16
|
let holder = document.createTextNode(''),
|
|
21
17
|
clauses = [parseExpr(el, expr, ':if')],
|
|
@@ -40,13 +36,20 @@ primary['if'] = (el, expr) => {
|
|
|
40
36
|
return (state) => {
|
|
41
37
|
let i = clauses.findIndex(f => f(state))
|
|
42
38
|
if (els[i] != cur) {
|
|
43
|
-
(cur[_each] || cur).replaceWith(cur = els[i] || holder);
|
|
39
|
+
;(cur[_each] || cur).replaceWith(cur = els[i] || holder);
|
|
44
40
|
// NOTE: it lazily initializes elements on insertion, it's safe to sprae multiple times
|
|
41
|
+
// but :if must come first to avoid preliminary caching
|
|
45
42
|
sprae(cur, state);
|
|
46
43
|
}
|
|
47
44
|
}
|
|
48
45
|
}
|
|
49
46
|
|
|
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
|
+
sprae(el, signalStruct(evaluate(rootState), rootState));
|
|
51
|
+
}
|
|
52
|
+
|
|
50
53
|
const _each = Symbol(':each')
|
|
51
54
|
|
|
52
55
|
// :each must init before :ref, :id or any others, since it defines scope
|
|
@@ -179,6 +182,32 @@ secondary['text'] = (el, expr) => {
|
|
|
179
182
|
}
|
|
180
183
|
}
|
|
181
184
|
|
|
185
|
+
secondary['data'] = (el, expr) => {
|
|
186
|
+
let evaluate = parseExpr(el, expr, ':data')
|
|
187
|
+
|
|
188
|
+
return ((state) => {
|
|
189
|
+
let value = evaluate(state)
|
|
190
|
+
for (let key in value) el.dataset[key] = value[key];
|
|
191
|
+
})
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
secondary['aria'] = (el, expr) => {
|
|
195
|
+
let evaluate = parseExpr(el, expr, ':aria')
|
|
196
|
+
const update = (value) => {
|
|
197
|
+
for (let key in value) attr(el, 'aria-' + dashcase(key), value[key] == null ? null : value[key] + '');
|
|
198
|
+
}
|
|
199
|
+
return ((state) => update(evaluate(state)))
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// set props in-bulk or run effect
|
|
203
|
+
secondary[''] = (el, expr) => {
|
|
204
|
+
let evaluate = parseExpr(el, expr, ':')
|
|
205
|
+
if (evaluate) return (state) => {
|
|
206
|
+
let value = evaluate(state)
|
|
207
|
+
for (let key in value) attr(el, dashcase(key), value[key]);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
182
211
|
// connect expr to element value
|
|
183
212
|
secondary['value'] = (el, expr) => {
|
|
184
213
|
let evaluate = parseExpr(el, expr, ':value')
|
|
@@ -216,13 +245,38 @@ secondary['on'] = (el, expr) => {
|
|
|
216
245
|
}
|
|
217
246
|
}
|
|
218
247
|
|
|
248
|
+
// any unknown directive
|
|
249
|
+
export default (el, expr, state, name) => {
|
|
250
|
+
let evt = name.startsWith('on') && name.slice(2)
|
|
251
|
+
let evaluate = parseExpr(el, expr, ':'+name)
|
|
252
|
+
|
|
253
|
+
if (!evaluate) return
|
|
254
|
+
|
|
255
|
+
if (evt) return state => {
|
|
256
|
+
let value = evaluate(state)
|
|
257
|
+
if (value) {
|
|
258
|
+
addListener(el, evt, value)
|
|
259
|
+
return () => removeListener(el, evt, value)
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
return state => attr(el, name, evaluate(state))
|
|
264
|
+
}
|
|
265
|
+
|
|
219
266
|
const _stop = Symbol('stop')
|
|
220
267
|
const addListener = (el, evt, startFn) => {
|
|
221
|
-
|
|
268
|
+
// ona..onb
|
|
269
|
+
let evts = evt.split('..').map(e => e.startsWith('on') ? e.slice(2) : e),
|
|
270
|
+
opts = {}
|
|
222
271
|
|
|
223
|
-
//
|
|
272
|
+
// onevt.debounce-108
|
|
273
|
+
evts[0] = evts[0].replace(
|
|
274
|
+
/\.(\w+)?-?([\w]+)?/g,
|
|
275
|
+
(match, mod, param) => (mod=mods[mod]) ? ([el, startFn] = mod(el, startFn, opts, param), '') : ''
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
if (evts.length == 1) el.addEventListener(evts[0], startFn, opts);
|
|
224
279
|
else {
|
|
225
|
-
const evts = evt.split('..').map(e => e.startsWith('on') ? e.slice(2) : e)
|
|
226
280
|
const nextEvt = (fn, cur=0) => {
|
|
227
281
|
let curListener = e => {
|
|
228
282
|
el.removeEventListener(evts[cur], curListener)
|
|
@@ -230,7 +284,7 @@ const addListener = (el, evt, startFn) => {
|
|
|
230
284
|
if (++cur < evts.length) nextEvt(fn, cur);
|
|
231
285
|
else if (!startFn[_stop]) nextEvt(startFn); // update only if chain isn't stopped
|
|
232
286
|
}
|
|
233
|
-
el.addEventListener(evts[cur],curListener)
|
|
287
|
+
el.addEventListener(evts[cur], curListener, opts)
|
|
234
288
|
}
|
|
235
289
|
nextEvt(startFn)
|
|
236
290
|
}
|
|
@@ -240,44 +294,67 @@ const removeListener = (el, evt, fn) => {
|
|
|
240
294
|
el.removeEventListener(evt, fn);
|
|
241
295
|
}
|
|
242
296
|
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
let
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
const update = (value) => {
|
|
255
|
-
for (let key in value) attr(el, 'aria-' + dashcase(key), value[key] == null ? null : value[key] + '');
|
|
256
|
-
}
|
|
257
|
-
return ((state) => update(evaluate(state)))
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
// set props in-bulk or run effect
|
|
261
|
-
secondary[''] = (el, expr) => {
|
|
262
|
-
let evaluate = parseExpr(el, expr, ':')
|
|
263
|
-
if (evaluate) return (state) => {
|
|
264
|
-
let value = evaluate(state)
|
|
265
|
-
for (let key in value) attr(el, dashcase(key), value[key]);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
// any other prop directive
|
|
270
|
-
export default (el, expr, values, name) => {
|
|
271
|
-
let evt = name.startsWith('on') && name.slice(2)
|
|
272
|
-
let evaluate = parseExpr(el, expr, ':'+name)
|
|
273
|
-
if (evaluate) return evt ? state => {
|
|
274
|
-
let value = evaluate(state)
|
|
275
|
-
if (value) {
|
|
276
|
-
addListener(el, evt, value)
|
|
277
|
-
return () => removeListener(el, evt, value)
|
|
297
|
+
// event modifiers
|
|
298
|
+
const mods = {
|
|
299
|
+
throttle(el, cb, opts, limit) {
|
|
300
|
+
limit = Number(limit) || 108
|
|
301
|
+
let pause, planned, block = () => {
|
|
302
|
+
pause = true
|
|
303
|
+
setTimeout(() => {
|
|
304
|
+
pause = false
|
|
305
|
+
// if event happened during blocked time, it schedules call by the end
|
|
306
|
+
if (planned) cb(e), planned = false, block();
|
|
307
|
+
})
|
|
278
308
|
}
|
|
279
|
-
|
|
280
|
-
|
|
309
|
+
return [el, e => {
|
|
310
|
+
if (pause) return planned = true
|
|
311
|
+
cb(e); block();
|
|
312
|
+
}]
|
|
313
|
+
},
|
|
314
|
+
|
|
315
|
+
debounce(el, cb, opts, wait) {
|
|
316
|
+
wait = Number(wait) || 108;
|
|
317
|
+
let timeout, later = () => { timeout = null; cb(e) }
|
|
318
|
+
return [el, (e) => {
|
|
319
|
+
clearTimeout(timeout)
|
|
320
|
+
timeout = setTimeout(later, wait)
|
|
321
|
+
}]
|
|
322
|
+
},
|
|
323
|
+
|
|
324
|
+
window(el, cb) { return [window, cb] },
|
|
325
|
+
document(el, cb) { return [document, cb] },
|
|
326
|
+
outside(el, cb) {
|
|
327
|
+
return [el, (e) => {
|
|
328
|
+
if (el.contains(e.target)) return
|
|
329
|
+
if (e.target.isConnected === false) return
|
|
330
|
+
if (el.offsetWidth < 1 && el.offsetHeight < 1) return
|
|
331
|
+
cb(e)
|
|
332
|
+
}]
|
|
333
|
+
},
|
|
334
|
+
prevent(el, cb) { return [el, e => { e.preventDefault(); cb(e) } ]},
|
|
335
|
+
stop(el, cb) { return [el, e => { e.stopPropagation(); cb(e) } ]},
|
|
336
|
+
self(el, cb) { return [el, e => { e.target === el && cb(e) } ]},
|
|
337
|
+
once(el, cb, opts) { opts.once = true; return [el, cb] },
|
|
338
|
+
passive(el, cb, opts) { opts.passive = true; return [el, cb] },
|
|
339
|
+
capture(el, cb, opts) { opts.capture = true; return [el, cb] },
|
|
340
|
+
};
|
|
341
|
+
let keys = {
|
|
342
|
+
ctrl:'Control Ctrl',
|
|
343
|
+
shift:'Shift',
|
|
344
|
+
alt:'Alt',
|
|
345
|
+
meta:'Meta',cmd:'Meta',
|
|
346
|
+
down:'ArrowDown',up:'ArrowUp',left:'ArrowLeft',right:'ArrowRight',
|
|
347
|
+
end:'End',home:'Home',pagedown:'PageDown',pageup:'PageUp',
|
|
348
|
+
enter:'Enter',plus:'+',minus:'-',star:'*',slash:'/',period:'.',equal:'=',underscore:'_',
|
|
349
|
+
esc:'Escape',escape:'Escape',tab:'Tab',space:' ',
|
|
350
|
+
backspace:'Backspace', delete:'Delete'
|
|
351
|
+
}
|
|
352
|
+
for (let keyAttr in keys) {
|
|
353
|
+
let keyName = keys[keyAttr]
|
|
354
|
+
mods[keyAttr] = (el, cb, opts, extraKey) => [el, e => {
|
|
355
|
+
if (!e.key || !keyName.includes(e.key)) return
|
|
356
|
+
cb(e)
|
|
357
|
+
}]
|
|
281
358
|
}
|
|
282
359
|
|
|
283
360
|
// set attr
|
|
@@ -286,7 +363,6 @@ const attr = (el, name, v) => {
|
|
|
286
363
|
else el.setAttribute(name, v === true ? '' : (typeof v === 'number' || typeof v === 'string') ? v : '')
|
|
287
364
|
}
|
|
288
365
|
|
|
289
|
-
|
|
290
366
|
let evaluatorMemo = {}
|
|
291
367
|
|
|
292
368
|
// borrowed from alpine: https://github.com/alpinejs/alpine/blob/main/packages/alpinejs/src/evaluator.js#L61
|
|
@@ -323,7 +399,7 @@ function parseExpr(el, expression, dir) {
|
|
|
323
399
|
}
|
|
324
400
|
}
|
|
325
401
|
|
|
326
|
-
|
|
402
|
+
function exprError(error, element, expression, dir) {
|
|
327
403
|
Object.assign( error, { element, expression } )
|
|
328
404
|
console.warn(`∴ ${error.message}\n\n${dir}=${ expression ? `"${expression}"\n\n` : '' }`, element)
|
|
329
405
|
setTimeout(() => { throw error }, 0)
|
package/test/test.js
CHANGED
|
@@ -148,7 +148,7 @@ test('text: core', async () => {
|
|
|
148
148
|
is(el.outerHTML, `<div></div>`)
|
|
149
149
|
})
|
|
150
150
|
|
|
151
|
-
test('
|
|
151
|
+
test('if: base', async () => {
|
|
152
152
|
let el = h`<p>
|
|
153
153
|
<span :if="a==1">a</span>
|
|
154
154
|
<span :else :if="a==2">b</span>
|
|
@@ -166,7 +166,7 @@ test('conditions: base', async () => {
|
|
|
166
166
|
is(el.innerHTML, '<span>c</span>')
|
|
167
167
|
})
|
|
168
168
|
|
|
169
|
-
test('
|
|
169
|
+
test('if: short with insertions', async () => {
|
|
170
170
|
let el = h`<p>
|
|
171
171
|
<span :if="a==1" :text="'1:'+a"></span>
|
|
172
172
|
<span :else :if="a==2" :text="'2:'+a"></span>
|
|
@@ -191,7 +191,7 @@ test('conditions: short with insertions', async () => {
|
|
|
191
191
|
params.a = null
|
|
192
192
|
})
|
|
193
193
|
|
|
194
|
-
test('
|
|
194
|
+
test('if: reactive values', async () => {
|
|
195
195
|
let el = h`<p>
|
|
196
196
|
<span :if="a==1" :text="'1:'+a"></span>
|
|
197
197
|
<span :else :if="a==2" :text="'2:'+a"></span>
|
|
@@ -215,12 +215,27 @@ test('conditions: reactive values', async () => {
|
|
|
215
215
|
is(el.innerHTML, '<span>4</span>')
|
|
216
216
|
})
|
|
217
217
|
|
|
218
|
-
test('
|
|
218
|
+
test('if: (#3) subsequent content is not abandoned', async () => {
|
|
219
219
|
let x = h`<x><y :if="!!y"></y><z :text="123"></z></x>`
|
|
220
220
|
sprae(x, {y: false})
|
|
221
221
|
is(x.outerHTML, `<x><z>123</z></x>`)
|
|
222
222
|
})
|
|
223
223
|
|
|
224
|
+
test('if: + :with doesnt prevent secondary effects from happening', () => {
|
|
225
|
+
let el = h`<div><x :if="x" :with="{}" :text="x"></x></div>`
|
|
226
|
+
let state = sprae(el, {x:''})
|
|
227
|
+
is(el.innerHTML, ``)
|
|
228
|
+
state.x = '123'
|
|
229
|
+
is(el.innerHTML, `<x>123</x>`)
|
|
230
|
+
|
|
231
|
+
// NOTE: we ignore this case
|
|
232
|
+
// let el2 = h`<div><x :if="x" :with="{x:cond}" :text="x"></x></div>`
|
|
233
|
+
// let state2 = sprae(el, {cond:''})
|
|
234
|
+
// is(el2.innerHTML, ``)
|
|
235
|
+
// state2.cond = '123'
|
|
236
|
+
// is(el2.innerHTML, `<x>123</x>`)
|
|
237
|
+
})
|
|
238
|
+
|
|
224
239
|
test('each: array', async () => {
|
|
225
240
|
// FIXME: in some conspicuous reason jsdom fails to update text nodes somehow
|
|
226
241
|
let el = h`<p>
|
|
@@ -409,12 +424,16 @@ test.todo('each: unmounted elements remove listeners', async () => {
|
|
|
409
424
|
|
|
410
425
|
test('each: internal children get updated by state update, also: update by running again', () => {
|
|
411
426
|
let el = h`<><x :each="item, idx in items" :text="item" :key="idx"></x></>`
|
|
412
|
-
sprae(el, { items: [1,2,3] })
|
|
427
|
+
let state = sprae(el, { items: [1,2,3] })
|
|
413
428
|
is(el.textContent, '123')
|
|
414
|
-
|
|
429
|
+
state.items = [2, 2, 3]
|
|
430
|
+
is(el.textContent, '223')
|
|
431
|
+
state = sprae(el, { items: [0,2,3] })
|
|
415
432
|
is(el.textContent, '023')
|
|
433
|
+
// NOTE: this doesn't update items, since they're new array
|
|
434
|
+
console.log('set items')
|
|
416
435
|
state.items[0] = 1
|
|
417
|
-
state.items = state.items
|
|
436
|
+
state.items = [...state.items]
|
|
418
437
|
is(el.textContent, '123')
|
|
419
438
|
})
|
|
420
439
|
|
|
@@ -554,6 +573,57 @@ test('on: state changes between chain of events', e => {
|
|
|
554
573
|
is(log, [1, 1.1, 2])
|
|
555
574
|
})
|
|
556
575
|
|
|
576
|
+
test('on: once', e => {
|
|
577
|
+
// NOTE: if callback updates it's still rebound
|
|
578
|
+
let el = h`<x :onx.once="(e=>x&&log.push(this))" ></x>`
|
|
579
|
+
let log = []
|
|
580
|
+
let state = sprae(el, {log, x:1})
|
|
581
|
+
el.dispatchEvent(new window.Event('x'));
|
|
582
|
+
is(log, [el])
|
|
583
|
+
el.dispatchEvent(new window.Event('x'));
|
|
584
|
+
is(log, [el])
|
|
585
|
+
state.x = 2
|
|
586
|
+
el.dispatchEvent(new window.Event('x'));
|
|
587
|
+
el.dispatchEvent(new window.Event('x'));
|
|
588
|
+
is(log, [el])
|
|
589
|
+
})
|
|
590
|
+
|
|
591
|
+
test('on: capture, stop, prevent', e => {
|
|
592
|
+
let el = h`<x :onx.capture="e=>log.push(1)"><y :onx="e=>log.push(2)"></y></x>`
|
|
593
|
+
let state = sprae(el, {log:[]})
|
|
594
|
+
el.firstChild.dispatchEvent(new window.Event('x', {bubbles:true}));
|
|
595
|
+
is(state.log, [1,2])
|
|
596
|
+
|
|
597
|
+
let el2 = h`<x :onx="e=>log.push(1)"><y :onx.stop="e=>log.push(2)"></y></x>`
|
|
598
|
+
let state2 = sprae(el2, {log:[]})
|
|
599
|
+
el2.firstChild.dispatchEvent(new window.Event('x', {bubbles:true}));
|
|
600
|
+
is(state2.log, [2])
|
|
601
|
+
})
|
|
602
|
+
|
|
603
|
+
test('on: window, self', e => {
|
|
604
|
+
let el = h`<x :onx.self="e=>log.push(1)"><y :onx.window="e=>log.push(2)"></y></x>`
|
|
605
|
+
let state = sprae(el, {log:[]})
|
|
606
|
+
el.firstChild.dispatchEvent(new window.Event('x', {bubbles:true}));
|
|
607
|
+
is(state.log, [])
|
|
608
|
+
el.dispatchEvent(new window.Event('x', {bubbles:true}));
|
|
609
|
+
is(state.log, [1])
|
|
610
|
+
window.dispatchEvent(new window.Event('x', {bubbles:true}));
|
|
611
|
+
is(state.log, [1,2])
|
|
612
|
+
})
|
|
613
|
+
|
|
614
|
+
test('on: keys', e => {
|
|
615
|
+
let el = h`<x :onkeydown.enter="e=>log.push(1)"></x>`
|
|
616
|
+
let state = {log:[]}
|
|
617
|
+
sprae(el, state)
|
|
618
|
+
el.dispatchEvent(new window.KeyboardEvent('keydown', { key: '' }));
|
|
619
|
+
is(state.log,[])
|
|
620
|
+
el.dispatchEvent(new window.KeyboardEvent('keydown', { key: 'Enter' }));
|
|
621
|
+
el.dispatchEvent(new window.KeyboardEvent('keydown', { key: '' }));
|
|
622
|
+
is(state.log,[1])
|
|
623
|
+
el.dispatchEvent(new window.KeyboardEvent('keydown', { key: 'Enter' }));
|
|
624
|
+
is(state.log,[1,1])
|
|
625
|
+
})
|
|
626
|
+
|
|
557
627
|
test('with: inline', () => {
|
|
558
628
|
let el = h`<x :with="{foo:'bar'}"><y :text="foo + baz"></y></x>`
|
|
559
629
|
let state = sprae(el, {baz: 'qux'})
|