sprae 5.2.0 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,39 +14,38 @@
14
14
  <section class="todoapp">
15
15
  <header class="header">
16
16
  <h1>todos</h1>
17
- <input class="new-todo" placeholder="What needs to be done?" autofocus :onkeypress="e => {
18
- if (e.key !== 'Enter') return
19
- save(todos = [...todos, { text: e.target.value, done: false}])
20
- e.target.value = ''
21
- }">
17
+ <input class="new-todo" placeholder="What needs to be done?" autofocus @keypress.enter="
18
+ save(todos = [...todos, { text: this.value, done: false}])
19
+ this.value = ''
20
+ ">
22
21
  </header>
23
22
  <section class="main">
24
- <input id="toggle-all" class="toggle-all" type="checkbox" :onclick="e => {
23
+ <input id="toggle-all" class="toggle-all" type="checkbox" @click="
25
24
  const all = todos.every(item => item.done)
26
25
  save(todos = todos.map(item => (item.done = !all, item)))
27
- }">
26
+ ">
28
27
  <label for="toggle-all">Mark all as complete</label>
29
28
  <ul class="todo-list">
30
29
  <li :ref="li" :each="item in todos"
31
30
  :class="{completed: item.done}"
32
31
  :hidden="hash === '#/active' ? item.done : hash === '#/completed' ? !item.done : false"
33
- :ondblclick="e => {
32
+ @dblclick="
34
33
  li.querySelector('.edit').focus()
35
34
  li.classList.add('editing')
36
- }">
35
+ ">
37
36
  <div class="view">
38
37
  <input class="toggle" type="checkbox"
39
38
  :checked="item.done"
40
- :onchange="e => (item.done = !item.done, save(todos))"
39
+ @change="item.done = !item.done, save(todos)"
41
40
  />
42
41
  <label :text="item.text"></label>
43
- <button class="destroy" :onclick="e => (save(todos = todos.filter(i => i.text !== item.text)))"></button>
42
+ <button class="destroy" @click="save(todos = todos.filter(i => i.text !== item.text))"></button>
44
43
  </div>
45
44
  <input class=edit
46
45
  :value="item.text"
47
- :oninput="e => {item.text = e.target.value; save(todos)}"
48
- :onblur="e => li.classList.remove('editing');"
49
- :onkeypress="(e) => { e.key === 'Enter' ? e.target.blur() : null }"
46
+ @input="item.text = this.value; save(todos)"
47
+ @blur="li.classList.remove('editing');"
48
+ @keypress.enter="this.blur()"
50
49
  />
51
50
  </li>
52
51
  </ul>
@@ -62,7 +61,7 @@
62
61
  </ul>
63
62
  <button class="clear-completed"
64
63
  :hidden="todos.every(item => !item.done)"
65
- :onclick="e => save(todos = todos.filter(item => !item.done ? true : false))">
64
+ @click="save(todos = todos.filter(item => !item.done ? true : false))">
66
65
  Clear completed
67
66
  </button>
68
67
  </footer>
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sprae",
3
3
  "description": "DOM microhydration.",
4
- "version": "5.2.0",
4
+ "version": "6.0.0",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",
7
7
  "type": "module",
@@ -12,7 +12,7 @@
12
12
  "@preact/signals": "^1.1.3",
13
13
  "es-module-shims": "^1.6.2",
14
14
  "esbuild": "^0.15.14",
15
- "hyperf": "^1.5.0",
15
+ "hyperf": "^1.6.2",
16
16
  "jsdom": "^21.1.0",
17
17
  "signal-struct": "^1.10.0",
18
18
  "terser": "^5.15.1",
package/r&d.md CHANGED
@@ -225,13 +225,14 @@
225
225
  - slows down domdiff
226
226
  - can be solved as `<x :if="xxx" :="xxx && (...)'">` automatically
227
227
 
228
- ## [x] :onmount/onunmount? -> for now no reasons
228
+ ## [ ] :onmount/onunmount? ->
229
229
 
230
230
  + useful for :if, :each
231
231
  + useful to dispose listeners via :onunmount (opposed to hidden symbols)
232
232
  - doesn't really solve disposal: if element is attached again, it would need to reattach removed listeners
233
233
  -> can be dolved via teardowns returned from updators
234
234
  -> nah, event listeners don't need collection, just make sure no refs to element remain
235
+ + can be useful for lazy-loadings
235
236
 
236
237
  ## [x] :focus="direct code", :evt="direct code" -> nah, too messy.
237
238
 
@@ -374,7 +375,63 @@
374
375
  - still need that syntax for filters, maps etc
375
376
  + can be made async by default
376
377
  - illicit `event` object
378
+ + we don't seem to ever need that event argument, many cases are covered by `.prevent` or `.stop`
379
+ ~+ generally `e=>` seem to conflict logically with modifiers sense
380
+ + `e=>` brings syntax burden - we may not ever need functions
381
+ + less problem detecting `const/let` in code
377
382
  - conflicts with regular attrs logic: the code is immediately invoked and can assign a function.
383
+ - `:oninput="e => (handleCaret(e), updateTimecodes())"`
384
+ ~ `:oninput="handleCaret(event), updateTimecodes()"`
385
+ - `:onbeforeinput="handleBeforeInput"`
386
+ ~ `:onbeforeinput="handleBeforeInput(event)"`
387
+ - `:ondragenter..ondragleave:ondragenter..ondrop="e=>(this.classList.add('w-dragover'),e=>this.classList.remove('w-dragover'))"`
388
+ ~ `:ondragenter..ondragleave:ondragenter..ondrop="this.classList.add('w-dragover'), e=>this.classList.remove('w-dragover')"`
389
+ - `:ondrop="e=>console.log(e.dataTransfer.types)||e.preventDefault()"`
390
+ ~ `:ondrop.prevent="console.log(event.dataTransfer.types)"`
391
+ - `:onfocus="e => (e.relatedTarget ? e.relatedTarget.focus() : e.target.blur())"`
392
+ ~ `:onfocus="event.relatedTarget ? event.relatedTarget.focus() : event.target.blur()"`
393
+ - `:onpopstate.window="e => goto(e.state)"`
394
+ ~ `:onpopstate.window="goto(event.state)"`
395
+ - `:onclick.toggle="play"`
396
+ ~ `:onclick.toggle="play()"`
397
+
398
+ ## [ ] Should we introduce `@click` for short-notation events?
399
+ + gives shorter code for majority of cases
400
+ + can be non-conflicting
401
+ + compatible with all frameworks (vue, alpine, lucia, lit)
402
+ + gives better meaning to modifiers - moves them outside of `:` attribute
403
+ - multiple events `@input@change="code"` is not nice
404
+ ~ that's fine and even meaningful
405
+ - chain of events `@focus..@blur="return (e)=>{}"` creates confusing `return` outside of body, as well as inconsistent chain pattern
406
+ ? remove that pattern
407
+ + it's still unsatisfactory: `@mousedown.document..@mouseup.document="e=> (isMouseDown = true, e=> isMouseDown = false)"` works, but what if we want to add `@touchstart..@touchend`, or
408
+ . `@click..@click="play" @keydown.alt-space..@keydown.alt-space="play"`, so in other words we need cross-reaction `@click_or_altspace..@click_or_altspace`, not just one single chain.
409
+ + actually here `@click@keydown.space..@click@keydown.space` is possible, unlike `:ona..onb` case, the question is how to provide sequence in attribute
410
+ + the thing is that local state, introduced by initiator events, is not useful by itself, detached from scope.
411
+ . the state is better reflected in data scope, rather than by initiator event.
412
+ ? what about temporaries like `@a..@b="id=setTimeout(),()=>clearTimeout(id)"` or `@a.toggle="stop=play(),stop"`
413
+ . use `:with={id:null} @a="id=setTimeout()" @b="clearTimeout(id)"`
414
+ - introduces illicit `event` variable ~ although compatible with standard, still obscure
415
+ - `@` prefix is unchangeable ~ can be removed, not set, but still on the verge.
416
+ - `@click.toggle="code"` has same problem as `@a..@b` - how can we make code separation in attribute?
417
+ + remove toggle
418
+ + overall less code
419
+
420
+ ## [x] Multiple chain events resolution -> redirect to main event for now
421
+ * Consider
422
+ ```
423
+ :onclick..onclick="play"
424
+ :onkeydown.document.alt-space..onkeydown.document.alt-space="play"
425
+ ```
426
+ * When started by click and ended by alt-space, it doesn't clear the onclick
427
+ * We actually want here `:onclick:onkeydown.document.alt-space..onclick:onkeydown.document.alt-space`.
428
+ - this makes inconsistency of `..onclick` - colon is missing
429
+ - also it makes precedence of `:` and `..` unclear - what comes before what after.
430
+
431
+ ? Can we use `:onclick.toggle="play"`?
432
+ - it doesn't help with switch-over
433
+ ? Some 'or' character `:onclick--onkeydown`
434
+ ? We can redirect to main event, that's it for now
378
435
 
379
436
  ## [x] Should getters convert to computed? -> yes, that's relatively cheap and useful
380
437
 
@@ -501,22 +558,6 @@
501
558
  5. `:x="this.x=value"`
502
559
  + yepyepyep
503
560
 
504
- ## [x] Multiple chain events resolution -> redirect to main event for now
505
- * Consider
506
- ```
507
- :onclick..onclick="play"
508
- :onkeydown.document.alt-space..onkeydown.document.alt-space="play"
509
- ```
510
- * When started by click and ended by alt-space, it doesn't clear the onclick
511
- * We actually want here `:onclick:onkeydown.document.alt-space..onclick:onkeydown.document.alt-space`.
512
- - this makes inconsistency of `..onclick` - colon is missing
513
- - also it makes precedence of `:` and `..` unclear - what comes before what after.
514
-
515
- ? Can we use `:onclick.toggle="play"`?
516
- - it doesn't help with switch-over
517
- ? Some 'or' character `:onclick--onkeydown`
518
- ? We can redirect to main event, that's it for now
519
-
520
561
  ## [x] Insert content by reusing the node/template -> use `:render="ref" :with="data"`
521
562
 
522
563
  * Makes easy use of repeatable fragments, instead of web-components
package/readme.md CHANGED
@@ -2,32 +2,24 @@
2
2
 
3
3
  > DOM microhydration with `:` attributes.
4
4
 
5
- _Sprae_ is tiny progressive enhancement lib, a minimal essential alternative to [alpine](https://github.com/alpinejs/alpine), [petite-vue](https://github.com/vuejs/petite-vue) or [template-parts](https://github.com/github/template-parts) with improved ergonomics. It enables simple markup logic without external scripts. Perfect for small websites or prototypes.
5
+ _Sprae_ is tiny progressive enhancement framework, a minimal essential alternative to [alpine](https://github.com/alpinejs/alpine)/[lucia](https://github.com/aidenybai/lucia), [petite-vue](https://github.com/vuejs/petite-vue) or [template-parts](https://github.com/github/template-parts) with improved ergonomics[*](#justification--alternatives). It enables simple markup logic without external scripts. Perfect for small websites, prototypes or UI logic.
6
6
 
7
- ## Install
7
+ ## Use
8
+
9
+ ### Autoinit
8
10
 
9
- To autoinit on document, include [`sprae.auto.js`](./sprae.auto.js):
11
+ To autoinit document, include [`sprae.auto.js`](./sprae.auto.js):
10
12
 
11
13
  ```html
12
14
  <!-- <script src="https://cdn.jsdelivr.net/npm/sprae/sprae.auto.js" defer></script> -->
13
15
  <script src="./path/to/sprae.auto.js" defer></script>
14
16
 
15
- <a :each="id in ['a','b','c']" :href="`#${id}`"></a>
17
+ <a :each="id in ['a','b','c']" :href="`#${id}`" :text="id"></a>
16
18
  ```
17
19
 
18
- To use as module, import [`sprae.js`](./sprae.js):
20
+ ### Manual init
19
21
 
20
- ```html
21
- <script type="module">
22
- // import sprae from 'https://cdn.jsdelivr.net/npm/sprae/sprae.js';
23
- import sprae from './path/to/sprae.js';
24
- sprae(el, {foo: 'bar'});
25
- </script>
26
- ```
27
-
28
- ## Use
29
-
30
- Sprae evaluates attributes starting with `:`:
22
+ To use as module, import [`sprae.js`](./sprae.js):
31
23
 
32
24
  ```html
33
25
  <div id="container" :if="user">
@@ -35,15 +27,15 @@ Sprae evaluates attributes starting with `:`:
35
27
  </div>
36
28
 
37
29
  <script type="module">
38
- import sprae from 'sprae';
30
+ // import sprae from 'https://cdn.jsdelivr.net/npm/sprae/sprae.js';
31
+ import sprae from './path/to/sprae.js';
39
32
 
40
33
  const state = sprae(container, { user: { displayName: 'Dmitry Ivanov' } });
41
- state.user.displayName = 'dy'; // automatically updates DOM
34
+ state.user.displayName = 'dy'; // updates DOM
42
35
  </script>
43
36
  ```
44
37
 
45
- * `sprae` initializes container's subtree with data and immediately evaporates `:` attrs.
46
- * `state` object reflects current values, changing any props rerenders subtree next tick.
38
+ Sprae evaluates `:`-attributes and evaporates them. Reactive `state` reflects current values, can be updated directly.
47
39
 
48
40
 
49
41
  ## Attributes
@@ -68,7 +60,7 @@ Multiply element. `index` value starts from 1.
68
60
  <!-- Cases -->
69
61
  <li :each="item, idx in list" />
70
62
  <li :each="val, key in obj" />
71
- <li :each="idx1, idx0 in number" />
63
+ <li :each="idx0, idx in number" />
72
64
 
73
65
  <!-- Loop by condition -->
74
66
  <li :if="items" :each="item in items" :text="item" />
@@ -124,63 +116,6 @@ Set value of an input, textarea or select. Takes handle of `checked` and `select
124
116
  </select>
125
117
  ```
126
118
 
127
- #### `:<prop>="value?"`
128
-
129
- Set any attribute value or run an effect.
130
-
131
- ```html
132
- <!-- Single property -->
133
- <label :for="name" :text="name" />
134
-
135
- <!-- Multiple properties -->
136
- <input :id:name="name" />
137
-
138
- <!-- Effect (triggers any time bar changes) -->
139
- <div :fx="void bar()" ></div>
140
- ```
141
-
142
- #### `:="props?"`
143
-
144
- Spread multiple attibures.
145
-
146
- ```html
147
- <input :="{ id: name, name, type:'text', value }" />
148
- ```
149
-
150
- #### `:on<event>="handler"`, `:on<in>..on<out>="handler"`
151
-
152
- Add event listener or events chain.
153
-
154
- ```html
155
- <!-- Single event -->
156
- <input type="checkbox" :onchange="e => isChecked=e.target.value">
157
-
158
- <!-- Multiple events -->
159
- <input :value="text" :oninput:onchange="e => text=e.target.value">
160
-
161
- <!-- Sequence of events -->
162
- <button :onfocus..onblur="e => {
163
- // onfocus
164
- return e => {
165
- // onblur
166
- }
167
- }">
168
-
169
- <!-- Event modifiers -->
170
- <button :onclick.throttle-500="handler">Not too often</button>
171
- ```
172
-
173
- ##### Event modifiers
174
-
175
- * `.once`, `.passive`, `.capture` – listener [options](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#options).
176
- * `.prevent`, `.stop` – prevent default or stop propagation.
177
- * `.window`, `.document`, `.outside`, `.self` – specify event target.
178
- * `.throttle-<ms>`, `.debounce-<ms>` – defer function call with one of the methods.
179
- * `.toggle` – run function and its result in turn.
180
- * `.ctrl`, `.shift`, `.alt`, `.meta`, `.arrow`, `.enter`, `.escape`, `.tab`, `.space`, `.backspace`, `.delete`, `.digit`, `.letter`, `.character` – filter by [`event.key`](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values).
181
- * `.ctrl-<key>, .alt-<key>, .meta-<key>, .shift-<key>` – key combinations, eg. `.ctrl-alt-delete` or `.meta-x`.
182
- * `.*` – any other modifier has no effect, but allows binding multiple handlers to same event (like jQuery event classes).
183
-
184
119
  #### `:with="data"`
185
120
 
186
121
  Define or extend data scope for a subtree.
@@ -205,8 +140,8 @@ Include template as element content.
205
140
  ```html
206
141
  <template :ref="foo"><span :text="foo"></span></template>
207
142
 
208
- <div :render="foo" :with="{foo:'bar'}">unknown</div>
209
- <div :render="foo" :with="{foo:'baz'}">unknown</div>
143
+ <div :render="foo" :with="{foo:'bar'}">...inserted here...</div>
144
+ <div :render="foo" :with="{foo:'baz'}">...inserted here...</div>
210
145
  ```
211
146
 
212
147
  #### `:ref="id"`
@@ -221,18 +156,73 @@ Expose element to current data scope with the `id`:
221
156
  <!-- iterable items -->
222
157
  <ul>
223
158
  <li :each="item in items" :ref="item">
224
- <input :onfocus..onblur="e => (item.classList.add('editing'), e => item.classList.remove('editing'))"/>
159
+ <input @focus="item.classList.add('editing')" @blur="item.classList.remove('editing')"/>
225
160
  </li>
226
161
  </ul>
227
162
  ```
228
163
 
164
+ #### `:="props?"`
165
+
166
+ Spread multiple attibures.
167
+
168
+ ```html
169
+ <input :="{ id: name, name, type:'text', value }" />
170
+ ```
171
+
172
+ #### `:<prop>="value?"`
173
+
174
+ Set any attribute value or run an effect.
175
+
176
+ ```html
177
+ <!-- Single property -->
178
+ <label :for="name" :text="name" />
179
+
180
+ <!-- Multiple properties -->
181
+ <input :id:name="name" />
182
+
183
+ <!-- Effect - returns undefined, triggers any time bar changes -->
184
+ <div :fx="void bar()" ></div>
185
+
186
+ <!-- Raw event listener (see events) -->
187
+ <div :onclick="e=>e.preventDefault()"></div>
188
+ ```
189
+
190
+
191
+ ## Events
192
+
193
+ #### `@<event>="handler"`, `@<foo>@<bar>.<baz>="handler"`
194
+
195
+ Attach event listener or multiple listeners with possible modifiers, `event` variable holds current event.
196
+
197
+ ```html
198
+ <!-- Single event -->
199
+ <input type="checkbox" @change="isChecked = event.target.value">
200
+
201
+ <!-- Multiple events -->
202
+ <input :value="text" @input@change="text = event.target.value">
203
+
204
+ <!-- Event modifiers -->
205
+ <button @click.throttle-500="handler(event)">Not too often</button>
206
+ ```
207
+
208
+ ##### Event modifiers
209
+
210
+ * `.once`, `.passive`, `.capture` – listener [options](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/addEventListener#options).
211
+ * `.prevent`, `.stop` – prevent default or stop propagation.
212
+ * `.window`, `.document`, `.outside`, `.self` – specify event target.
213
+ * `.throttle-<ms>`, `.debounce-<ms>` – defer function call with one of the methods.
214
+ * `.ctrl`, `.shift`, `.alt`, `.meta`, `.arrow`, `.enter`, `.escape`, `.tab`, `.space`, `.backspace`, `.delete`, `.digit`, `.letter`, `.character` – filter by [`event.key`](https://developer.mozilla.org/en-US/docs/Web/API/UI_Events/Keyboard_event_key_values).
215
+ * `.ctrl-<key>, .alt-<key>, .meta-<key>, .shift-<key>` – key combinations, eg. `.ctrl-alt-delete` or `.meta-x`.
216
+ * `.*` – any other modifier has no effect, but allows binding multiple handlers to same event (like jQuery event classes).
217
+
218
+
229
219
  ## Sandbox
230
220
 
231
221
  Expressions are sandboxed, ie. have no access to global or window (since sprae can be run in server environment).
232
222
 
233
223
  ```html
234
- <div :x="window.x"></div>
235
- <!-- window is undefined -->
224
+ <div :x="global.x"></div>
225
+ <!-- global is undefined -->
236
226
  ```
237
227
 
238
228
  Default sandbox provides: _window_, _document_, _console_, _history_, _location_, _Array_, _Object_, _Number_, _String_, _Boolean_, _Date_, _Set_, _Map_.<br/>
@@ -253,13 +243,13 @@ To avoid _flash of unstyled content_, you can hide sprae attribute or add a cust
253
243
  * Wavearea: [demo](https://dy.github.io/wavearea?src=//cdn.freesound.org/previews/586/586281_2332564-lq.mp3), [code](https://github.com/dy/wavearea)
254
244
  * Prostogreen [demo](http://web-being.org/prostogreen/), [code](https://github.com/web-being/prostogreen/)
255
245
 
256
- ## Justification
246
+ ## Justification & alternatives
257
247
 
258
- * [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.
259
- * [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.
248
+ * [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. Also it's just nice to keep `{{}}` generic, regardless of markup, and attributes as part of markup.
249
+ * [Alpine](https://github.com/alpinejs/alpine) / [vue](https://github.com/vuejs/petite-vue) / [lit](https://github.com/lit/lit/tree/main/packages/lit-html) / [lucia](https://github.com/aidenybai/lucia) escape native HTML quirks, but the syntax (`:attr`, `v-*`,`x-*`, `l-*` `@evt`, `{{}}`) and 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, invent own tooling or complex reactivity.
260
250
  * 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).
261
251
 
262
- _Sprae_ takes convention of _templize directives_ (_alpine_/_vue_ attrs) and builds upon <del>[_@preact/signals_](https://ghub.io/@preact/signals)</del> simple reactive state.
252
+ _Sprae_ takes idea of _templize directives_/_alpine_/_vue_ attrs and builds upon <del>[_@preact/signals_](https://ghub.io/@preact/signals)</del> simple reactive state.
263
253
 
264
254
  * It doesn't break or modify static html markup.
265
255
  * It falls back to element content if uninitialized.
package/sprae.auto.js CHANGED
@@ -223,12 +223,6 @@
223
223
  }
224
224
  };
225
225
  };
226
- primary["with"] = (el, expr, rootState) => {
227
- let evaluate = parseExpr(el, expr, ":with");
228
- const localState = evaluate(rootState);
229
- let state2 = state(localState, rootState);
230
- sprae(el, state2);
231
- };
232
226
  var _each = Symbol(":each");
233
227
  primary["each"] = (tpl, expr) => {
234
228
  let each = parseForExpression(expr);
@@ -249,7 +243,7 @@
249
243
  if (!list)
250
244
  list = [];
251
245
  else if (typeof list === "number")
252
- list = Array.from({ length: list }, (_, i) => [i, i + 1]);
246
+ list = Array.from({ length: list }, (_, i) => [i + 1, i]);
253
247
  else if (Array.isArray(list))
254
248
  list = list.map((item, i) => [i + 1, item]);
255
249
  else if (typeof list === "object")
@@ -279,6 +273,12 @@
279
273
  }
280
274
  };
281
275
  };
276
+ primary["with"] = (el, expr, rootState) => {
277
+ let evaluate = parseExpr(el, expr, ":with");
278
+ const localState = evaluate(rootState);
279
+ let state2 = state(localState, rootState);
280
+ sprae(el, state2);
281
+ };
282
282
  primary["ref"] = (el, expr, state2) => {
283
283
  state2[expr] = el;
284
284
  };
@@ -376,19 +376,6 @@
376
376
  } : (value) => el.value = value;
377
377
  return (state2) => update(evaluate(state2));
378
378
  };
379
- secondary["on"] = (el, expr) => {
380
- let evaluate = parseExpr(el, expr, ":on");
381
- return (state2) => {
382
- let listeners = evaluate(state2);
383
- let offs = [];
384
- for (let evt in listeners)
385
- offs.push(on(el, evt, listeners[evt]));
386
- return () => {
387
- for (let off of offs)
388
- off();
389
- };
390
- };
391
- };
392
379
  var directives_default = (el, expr, state2, name) => {
393
380
  let evt = name.startsWith("on") && name.slice(2);
394
381
  let evaluate = parseExpr(el, expr, ":" + name);
@@ -402,43 +389,20 @@
402
389
  };
403
390
  return (state3) => attr(el, name, evaluate(state3));
404
391
  };
405
- var on = (target, evt, origFn) => {
406
- if (!origFn)
392
+ var on = (el, e, fn) => {
393
+ if (!fn)
407
394
  return;
408
- let ctxs = evt.split("..").map((e) => {
409
- let ctx = { evt: "", target, test: () => true };
410
- ctx.evt = (e.startsWith("on") ? e.slice(2) : e).replace(
411
- /\.(\w+)?-?([-\w]+)?/g,
412
- (match, mod, param = "") => (ctx.test = mods[mod]?.(ctx, ...param.split("-")) || ctx.test, "")
413
- );
414
- return ctx;
415
- });
416
- if (ctxs.length == 1)
417
- return addListenerWithMods(origFn, ctxs[0]);
418
- const onFn = (fn, cur = 0) => {
419
- let off;
420
- let curListener = (e) => {
421
- if (cur)
422
- off();
423
- let nextFn = fn.call(target, e);
424
- if (typeof nextFn !== "function")
425
- nextFn = () => {
426
- };
427
- if (cur + 1 < ctxs.length)
428
- onFn(nextFn, !cur ? 1 : cur + 1);
429
- };
430
- return off = addListenerWithMods(curListener, ctxs[cur]);
431
- };
432
- let rootOff = onFn(origFn);
433
- return () => rootOff();
434
- function addListenerWithMods(fn, { evt: evt2, target: target2, test, defer, stop, prevent, ...opts }) {
435
- if (defer)
436
- fn = defer(fn);
437
- let cb = (e) => test(e) && (stop && e.stopPropagation(), prevent && e.preventDefault(), fn.call(target2, e));
438
- target2.addEventListener(evt2, cb, opts);
439
- return () => target2.removeEventListener(evt2, cb, opts);
440
- }
441
- ;
395
+ const ctx = { evt: "", target: el, test: () => true };
396
+ ctx.evt = (e.startsWith("on") ? e.slice(2) : e).replace(
397
+ /\.(\w+)?-?([-\w]+)?/g,
398
+ (match, mod, param = "") => (ctx.test = mods[mod]?.(ctx, ...param.split("-")) || ctx.test, "")
399
+ );
400
+ const { evt, target, test, defer, stop, prevent, ...opts } = ctx;
401
+ if (defer)
402
+ fn = defer(fn);
403
+ const cb = (e2) => test(e2) && (stop && e2.stopPropagation(), prevent && e2.preventDefault(), fn.call(target, e2));
404
+ target.addEventListener(evt, cb, opts);
405
+ return () => target.removeEventListener(evt, cb, opts);
442
406
  };
443
407
  var mods = {
444
408
  prevent(ctx) {
@@ -462,9 +426,6 @@
462
426
  document(ctx) {
463
427
  ctx.target = document;
464
428
  },
465
- toggle(ctx) {
466
- ctx.defer = (fn, out) => (e) => out ? (out.call?.(ctx.target, e), out = null) : out = fn();
467
- },
468
429
  throttle(ctx, limit) {
469
430
  ctx.defer = (fn) => throttle(fn, limit ? Number(limit) || 0 : 108);
470
431
  },
@@ -606,18 +567,18 @@ ${directive}=${expression ? `"${expression}"
606
567
  }
607
568
  if (el.attributes) {
608
569
  for (let i = 0; i < el.attributes.length; ) {
609
- let attr2 = el.attributes[i];
610
- if (attr2.name[0] !== ":") {
570
+ let attr2 = el.attributes[i], prefix = attr2.name[0];
571
+ if (prefix === ":" || prefix === "@") {
572
+ el.removeAttribute(attr2.name);
573
+ let expr = prefix === "@" ? `event=>{${attr2.value}}` : attr2.value, names = attr2.name.slice(1).split(prefix);
574
+ for (let name of names) {
575
+ if (prefix === "@")
576
+ name = `on` + name;
577
+ let dir = secondary[name] || directives_default;
578
+ updates.push(dir(el, expr, state2, name));
579
+ }
580
+ } else
611
581
  i++;
612
- continue;
613
- }
614
- el.removeAttribute(attr2.name);
615
- let expr = attr2.value;
616
- let attrNames = attr2.name.slice(1).split(":");
617
- for (let attrName of attrNames) {
618
- let dir = secondary[attrName] || directives_default;
619
- updates.push(dir(el, expr, state2, attrName));
620
- }
621
582
  }
622
583
  }
623
584
  for (let i = 0, child; child = el.children[i]; i++) {
package/sprae.auto.min.js CHANGED
@@ -1 +1 @@
1
- (()=>{var e,t,r=Promise.prototype.then.bind(Promise.resolve()),n=new WeakMap,l=class extends Map{#e=new FinalizationRegistry((e=>super.delete(e)));get size(){return[...this].length}constructor(e=[]){super();for(const[t,r]of e)this.set(t,r)}get(e){return super.get(e)?.deref()}set(e,t){let r=super.get(e);return r&&this.#e.unregister(r),r=(e=>n.get(e)||(e=>{const t=new WeakRef(e);return n.set(e,t),t})(e))(t),this.#e.register(t,e,r),super.set(e,r)}},s=new Set,i=new WeakMap,o=new WeakMap,a=new WeakMap,u=Symbol("parent"),c={Array:Array,Object:Object,Number:Number,String:String,Boolean:Boolean,Date:Date,console:console,window:window,document:document,history:history,location:location},f={has:()=>!0,get(t,r){if("symbol"==typeof r)return t[r];if(!(r in t))return t[u]?.[r];if(r in Object.prototype||Array.isArray(t)&&r in Array.prototype&&"length"!==r)return t[r];let n=t[r];if(e){let n=i.get(t);n||i.set(t,n={}),n[r]?n[r].includes(e)||n[r].push(e):n[r]=[e]}if(n&&n.constructor===Object||Array.isArray(n)){let e=o.get(n);return e||o.set(n,e=new Proxy(n,f)),e}return n},set(e,t,r){if(!(t in e)&&e[u]&&t in e[u])return e[u][t]=r;if(!Array.isArray(e)&&Object.is(e[t],r))return!0;e[t]=r;let n=i.get(e)?.[t];if(n)for(let e of n)s.add(e);return h(),!0},deleteProperty:(e,t)=>(e[t]=void 0,delete e[t],!0)},p=(e,t)=>{if(o.has(e))return o.get(e);if(a.has(e))return e;let r=new Proxy(e,f);o.set(e,r),a.set(r,e);let n=Object.getOwnPropertyDescriptors(e);for(let t in n){let l=n[t];l.get&&l.get&&(l.get=l.get.bind(r),Object.defineProperty(e,t,l))}return e[u]=t?p(t):c,r},y=t=>{const r=()=>{let n=e;e=r,t(),e=n};return r(),r},h=()=>{t||(t=!0,r((()=>{for(let e of s)e.call();s.clear(),t=!1})))},g={},d={};g.if=(e,t)=>{let r=document.createTextNode(""),n=[j(e,t,":if")],l=[e],s=e;for(;(s=e.nextElementSibling)&&s.hasAttribute(":else");)s.removeAttribute(":else"),(t=s.getAttribute(":if"))?(s.removeAttribute(":if"),s.remove(),l.push(s),n.push(j(e,t,":else :if"))):(s.remove(),l.push(s),n.push((()=>1)));return e.replaceWith(s=r),e=>{let t=n.findIndex((t=>t(e)));l[t]!=s&&((s[m]||s).replaceWith(s=l[t]||r),O(s,e))}},g.with=(e,t,r)=>{const n=j(e,t,":with")(r);O(e,p(n,r))};var m=Symbol(":each");g.each=(e,t)=>{let r=function(e){let t=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,r=e.match(/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/);if(!r)return;let n=r[2].trim(),l=r[1].replace(/^\s*\(|\)\s*$/g,"").trim(),s=l.match(t);return s?[l.replace(t,"").trim(),s[1].trim(),n]:[l,"",n]}(t);if(!r)return E(new Error,e,t,":each");const n=e[m]=document.createTextNode("");e.replaceWith(n);const s=j(e,r[2],":each"),i=e.getAttribute(":key"),o=i?j(null,i,":each"):null;e.removeAttribute(":key");const a=e.getAttribute(":ref"),u=new l,c=new l;let f=[];return l=>{let i=s(l);i?"number"==typeof i?i=Array.from({length:i},((e,t)=>[t,t+1])):Array.isArray(i)?i=i.map(((e,t)=>[t+1,e])):"object"==typeof i?i=Object.entries(i):E(Error("Bad list value"),e,t,":each"):i=[];let y=[],h=[];for(let[t,n]of i){let s,i,f=o?.({[r[0]]:n,[r[1]]:t});null==f?s=e.cloneNode(!0):(s=c.get(f))||c.set(f,s=e.cloneNode(!0)),y.push(s),null!=f&&(i=u.get(f))?i[r[0]]=n:(i=p({[r[0]]:n,[a||""]:null,[r[1]]:t},l),null!=f&&u.set(f,i)),h.push(i)}!function(e,t,r,n){const l=new Map,s=new Map;let i,o;for(i=0;i<t.length;i++)l.set(t[i],i);for(i=0;i<r.length;i++)s.set(r[i],i);for(i=o=0;i!==t.length||o!==r.length;){var a=t[i],u=r[o];if(null===a)i++;else if(r.length<=o)e.removeChild(t[i]),i++;else if(t.length<=i)e.insertBefore(u,t[i]||n),o++;else if(a===u)i++,o++;else{var c=s.get(a),f=l.get(u);void 0===c?(e.removeChild(t[i]),i++):void 0===f?(e.insertBefore(u,t[i]||n),o++):(e.insertBefore(t[f],t[i]||n),t[f]=null,f>i+1&&i++,o++)}}}(n.parentNode,f,y,n),f=y;for(let e=0;e<y.length;e++)O(y[e],h[e])}},g.ref=(e,t,r)=>{r[t]=e},d.render=(e,t,r)=>{let n=j(e,t,":render")(r);n||E(new Error("Template not found"),e,t,":render");let l=n.content.cloneNode(!0);e.replaceChildren(l),O(e,r)},d.id=(e,t)=>{let r=j(e,t,":id");return t=>{return n=r(t),e.id=n||0===n?n:"";var n}},d.class=(e,t)=>{let r=j(e,t,":class"),n=e.getAttribute("class");return t=>{let l=r(t),s=[n];l&&("string"==typeof l?s.push(l):Array.isArray(l)?s.push(...l):s.push(...Object.entries(l).map((([e,t])=>t?e:"")))),(s=s.filter(Boolean).join(" "))?e.setAttribute("class",s):e.removeAttribute("class")}},d.style=(e,t)=>{let r=j(e,t,":style"),n=e.getAttribute("style")||"";return n.endsWith(";")||(n+="; "),t=>{let l=r(t);if("string"==typeof l)e.setAttribute("style",n+l);else{e.setAttribute("style",n);for(let t in l)e.style.setProperty(t,l[t])}}},d.text=(e,t)=>{let r=j(e,t,":text");return t=>{let n=r(t);e.textContent=null==n?"":n}},d[""]=(e,t)=>{let r=j(e,t,":");if(r)return t=>{let n=r(t);for(let t in n)x(e,t.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(e=>"-"+e.toLowerCase())),n[t])}},d.value=(e,t)=>{let r,n,l=j(e,t,":value"),s="text"===e.type||""===e.type?t=>e.setAttribute("value",e.value=null==t?"":t):"TEXTAREA"===e.tagName||"text"===e.type||""===e.type?t=>(r=e.selectionStart,n=e.selectionEnd,e.setAttribute("value",e.value=null==t?"":t),r&&e.setSelectionRange(r,n)):"checkbox"===e.type?t=>(e.value=t?"on":"",x(e,"checked",t)):"select-one"===e.type?t=>{for(let t in e.options)t.removeAttribute("selected");e.value=t,e.selectedOptions[0]?.setAttribute("selected","")}:t=>e.value=t;return e=>s(l(e))},d.on=(e,t)=>{let r=j(e,t,":on");return t=>{let n=r(t),l=[];for(let t in n)l.push(v(e,t,n[t]));return()=>{for(let e of l)e()}}};var b=(e,t,r,n)=>{let l=n.startsWith("on")&&n.slice(2),s=j(e,t,":"+n);if(s)return l?t=>{let r=s(t)||(()=>{});return v(e,l,r)}:t=>x(e,n,s(t))},v=(e,t,r)=>{if(!r)return;let n=t.split("..").map((t=>{let r={evt:"",target:e,test:()=>!0};return r.evt=(t.startsWith("on")?t.slice(2):t).replace(/\.(\w+)?-?([-\w]+)?/g,((e,t,n="")=>(r.test=A[t]?.(r,...n.split("-"))||r.test,""))),r}));if(1==n.length)return i(r,n[0]);const l=(t,r=0)=>{let s;return s=i((i=>{r&&s();let o=t.call(e,i);"function"!=typeof o&&(o=()=>{}),r+1<n.length&&l(o,r?r+1:1)}),n[r])};let s=l(r);return()=>s();function i(e,{evt:t,target:r,test:n,defer:l,stop:s,prevent:i,...o}){l&&(e=l(e));let a=t=>n(t)&&(s&&t.stopPropagation(),i&&t.preventDefault(),e.call(r,t));return r.addEventListener(t,a,o),()=>r.removeEventListener(t,a,o)}},A={prevent(e){e.prevent=!0},stop(e){e.stop=!0},once(e){e.once=!0},passive(e){e.passive=!0},capture(e){e.capture=!0},window(e){e.target=window},document(e){e.target=document},toggle(e){e.defer=(t,r)=>n=>r?(r.call?.(e.target,n),r=null):r=t()},throttle(e,t){e.defer=e=>k(e,t?Number(t)||0:108)},debounce(e,t){e.defer=e=>W(e,t?Number(t)||0:108)},outside:e=>t=>{let r=e.target;return!(r.contains(t.target)||!1===t.target.isConnected||r.offsetWidth<1&&r.offsetHeight<1)},self:e=>t=>t.target===e.target,ctrl:(e,...t)=>e=>w.ctrl(e)&&t.every((t=>w[t]?w[t](e):e.key===t)),shift:(e,...t)=>e=>w.shift(e)&&t.every((t=>w[t]?w[t](e):e.key===t)),alt:(e,...t)=>e=>w.alt(e)&&t.every((t=>w[t]?w[t](e):e.key===t)),meta:(e,...t)=>e=>w.meta(e)&&t.every((t=>w[t]?w[t](e):e.key===t)),arrow:e=>w.arrow,enter:e=>w.enter,escape:e=>w.escape,tab:e=>w.tab,space:e=>w.space,backspace:e=>w.backspace,delete:e=>w.delete,digit:e=>w.digit,letter:e=>w.letter,character:e=>w.character},w={ctrl:e=>e.ctrlKey||"Control"===e.key||"Ctrl"===e.key,shift:e=>e.shiftKey||"Shift"===e.key,alt:e=>e.altKey||"Alt"===e.key,meta:e=>e.metaKey||"Meta"===e.key||"Command"===e.key,arrow:e=>e.key.startsWith("Arrow"),enter:e=>"Enter"===e.key,escape:e=>e.key.startsWith("Esc"),tab:e=>"Tab"===e.key,space:e=>" "===e.key||"Space"===e.key||" "===e.key,backspace:e=>"Backspace"===e.key,delete:e=>"Delete"===e.key,digit:e=>/^\d$/.test(e.key),letter:e=>/^[a-zA-Z]$/.test(e.key),character:e=>/^\S$/.test(e.key)},k=(e,t)=>{let r,n,l=s=>{r=!0,setTimeout((()=>{if(r=!1,n)return n=!1,l(s),e(s)}),t)};return t=>r?n=!0:(l(t),e(t))},W=(e,t)=>{let r;return n=>{clearTimeout(r),r=setTimeout((()=>{r=null,e(n)}),t)}},x=(e,t,r)=>{null==r||!1===r?e.removeAttribute(t):e.setAttribute(t,!0===r?"":"number"==typeof r||"string"==typeof r?r:"")},S={};function j(e,t,r){let n=S[t];if(!n){let l=/^[\n\s]*if.*\(.*\)/.test(t)||/\b(let|const)\s/.test(t)&&!r.startsWith(":on")?`(() => {${t}})()`:t;try{n=S[t]=new Function("__scope",`with (__scope) { return ${l.trim()} };`)}catch(n){return E(n,e,t,r)}}return l=>{let s;try{s=n.call(e,l)}catch(n){return E(n,e,t,r)}return s}}function E(e,t,n,l){Object.assign(e,{element:t,expression:n}),console.warn(`∴ ${e.message}\n\n${l}=${n?`"${n}"\n\n`:""}`,t),r((()=>{throw e}),0)}O.globals=c;var N=new WeakMap;function O(e,t){if(!e.children)return;if(N.has(e))return Object.assign(N.get(e),t);const r=p(t||{}),n=[],l=(e,t=e.parentNode)=>{for(let l in g){let s=":"+l;if(e.hasAttribute?.(s)){let i=e.getAttribute(s);if(e.removeAttribute(s),n.push(g[l](e,i,r,l)),N.has(e))return;if(e.parentNode!==t)return!1}}if(e.attributes)for(let t=0;t<e.attributes.length;){let l=e.attributes[t];if(":"!==l.name[0]){t++;continue}e.removeAttribute(l.name);let s=l.value,i=l.name.slice(1).split(":");for(let t of i){let l=d[t]||b;n.push(l(e,s,r,t))}}for(let t,r=0;t=e.children[r];r++)!1===l(t,e)&&r--};l(e);for(let e of n)if(e){let t;y((()=>{"function"==typeof t&&t(),t=e(r)}))}return N.set(e,r),r}document.currentScript&&O(document.documentElement)})();
1
+ (()=>{var e,t,r=Promise.prototype.then.bind(Promise.resolve()),n=new WeakMap,s=class extends Map{#e=new FinalizationRegistry((e=>super.delete(e)));get size(){return[...this].length}constructor(e=[]){super();for(const[t,r]of e)this.set(t,r)}get(e){return super.get(e)?.deref()}set(e,t){let r=super.get(e);return r&&this.#e.unregister(r),r=(e=>n.get(e)||(e=>{const t=new WeakRef(e);return n.set(e,t),t})(e))(t),this.#e.register(t,e,r),super.set(e,r)}},l=new Set,i=new WeakMap,o=new WeakMap,a=new WeakMap,u=Symbol("parent"),c={Array:Array,Object:Object,Number:Number,String:String,Boolean:Boolean,Date:Date,console:console,window:window,document:document,history:history,location:location},f={has:()=>!0,get(t,r){if("symbol"==typeof r)return t[r];if(!(r in t))return t[u]?.[r];if(r in Object.prototype||Array.isArray(t)&&r in Array.prototype&&"length"!==r)return t[r];let n=t[r];if(e){let n=i.get(t);n||i.set(t,n={}),n[r]?n[r].includes(e)||n[r].push(e):n[r]=[e]}if(n&&n.constructor===Object||Array.isArray(n)){let e=o.get(n);return e||o.set(n,e=new Proxy(n,f)),e}return n},set(e,t,r){if(!(t in e)&&e[u]&&t in e[u])return e[u][t]=r;if(!Array.isArray(e)&&Object.is(e[t],r))return!0;e[t]=r;let n=i.get(e)?.[t];if(n)for(let e of n)l.add(e);return h(),!0},deleteProperty:(e,t)=>(e[t]=void 0,delete e[t],!0)},p=(e,t)=>{if(o.has(e))return o.get(e);if(a.has(e))return e;let r=new Proxy(e,f);o.set(e,r),a.set(r,e);let n=Object.getOwnPropertyDescriptors(e);for(let t in n){let s=n[t];s.get&&s.get&&(s.get=s.get.bind(r),Object.defineProperty(e,t,s))}return e[u]=t?p(t):c,r},y=t=>{const r=()=>{let n=e;e=r,t(),e=n};return r(),r},h=()=>{t||(t=!0,r((()=>{for(let e of l)e.call();l.clear(),t=!1})))},d={},g={};d.if=(e,t)=>{let r=document.createTextNode(""),n=[j(e,t,":if")],s=[e],l=e;for(;(l=e.nextElementSibling)&&l.hasAttribute(":else");)l.removeAttribute(":else"),(t=l.getAttribute(":if"))?(l.removeAttribute(":if"),l.remove(),s.push(l),n.push(j(e,t,":else :if"))):(l.remove(),s.push(l),n.push((()=>1)));return e.replaceWith(l=r),e=>{let t=n.findIndex((t=>t(e)));s[t]!=l&&((l[b]||l).replaceWith(l=s[t]||r),O(l,e))}};var b=Symbol(":each");d.each=(e,t)=>{let r=function(e){let t=/,([^,\}\]]*)(?:,([^,\}\]]*))?$/,r=e.match(/([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/);if(!r)return;let n=r[2].trim(),s=r[1].replace(/^\s*\(|\)\s*$/g,"").trim(),l=s.match(t);return l?[s.replace(t,"").trim(),l[1].trim(),n]:[s,"",n]}(t);if(!r)return E(new Error,e,t,":each");const n=e[b]=document.createTextNode("");e.replaceWith(n);const l=j(e,r[2],":each"),i=e.getAttribute(":key"),o=i?j(null,i,":each"):null;e.removeAttribute(":key");const a=e.getAttribute(":ref"),u=new s,c=new s;let f=[];return s=>{let i=l(s);i?"number"==typeof i?i=Array.from({length:i},((e,t)=>[t+1,t])):Array.isArray(i)?i=i.map(((e,t)=>[t+1,e])):"object"==typeof i?i=Object.entries(i):E(Error("Bad list value"),e,t,":each"):i=[];let y=[],h=[];for(let[t,n]of i){let l,i,f=o?.({[r[0]]:n,[r[1]]:t});null==f?l=e.cloneNode(!0):(l=c.get(f))||c.set(f,l=e.cloneNode(!0)),y.push(l),null!=f&&(i=u.get(f))?i[r[0]]=n:(i=p({[r[0]]:n,[a||""]:null,[r[1]]:t},s),null!=f&&u.set(f,i)),h.push(i)}!function(e,t,r,n){const s=new Map,l=new Map;let i,o;for(i=0;i<t.length;i++)s.set(t[i],i);for(i=0;i<r.length;i++)l.set(r[i],i);for(i=o=0;i!==t.length||o!==r.length;){var a=t[i],u=r[o];if(null===a)i++;else if(r.length<=o)e.removeChild(t[i]),i++;else if(t.length<=i)e.insertBefore(u,t[i]||n),o++;else if(a===u)i++,o++;else{var c=l.get(a),f=s.get(u);void 0===c?(e.removeChild(t[i]),i++):void 0===f?(e.insertBefore(u,t[i]||n),o++):(e.insertBefore(t[f],t[i]||n),t[f]=null,f>i+1&&i++,o++)}}}(n.parentNode,f,y,n),f=y;for(let e=0;e<y.length;e++)O(y[e],h[e])}},d.with=(e,t,r)=>{const n=j(e,t,":with")(r);O(e,p(n,r))},d.ref=(e,t,r)=>{r[t]=e},g.render=(e,t,r)=>{let n=j(e,t,":render")(r);n||E(new Error("Template not found"),e,t,":render");let s=n.content.cloneNode(!0);e.replaceChildren(s),O(e,r)},g.id=(e,t)=>{let r=j(e,t,":id");return t=>{return n=r(t),e.id=n||0===n?n:"";var n}},g.class=(e,t)=>{let r=j(e,t,":class"),n=e.getAttribute("class");return t=>{let s=r(t),l=[n];s&&("string"==typeof s?l.push(s):Array.isArray(s)?l.push(...s):l.push(...Object.entries(s).map((([e,t])=>t?e:"")))),(l=l.filter(Boolean).join(" "))?e.setAttribute("class",l):e.removeAttribute("class")}},g.style=(e,t)=>{let r=j(e,t,":style"),n=e.getAttribute("style")||"";return n.endsWith(";")||(n+="; "),t=>{let s=r(t);if("string"==typeof s)e.setAttribute("style",n+s);else{e.setAttribute("style",n);for(let t in s)e.style.setProperty(t,s[t])}}},g.text=(e,t)=>{let r=j(e,t,":text");return t=>{let n=r(t);e.textContent=null==n?"":n}},g[""]=(e,t)=>{let r=j(e,t,":");if(r)return t=>{let n=r(t);for(let t in n)x(e,t.replace(/[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,(e=>"-"+e.toLowerCase())),n[t])}},g.value=(e,t)=>{let r,n,s=j(e,t,":value"),l="text"===e.type||""===e.type?t=>e.setAttribute("value",e.value=null==t?"":t):"TEXTAREA"===e.tagName||"text"===e.type||""===e.type?t=>(r=e.selectionStart,n=e.selectionEnd,e.setAttribute("value",e.value=null==t?"":t),r&&e.setSelectionRange(r,n)):"checkbox"===e.type?t=>(e.value=t?"on":"",x(e,"checked",t)):"select-one"===e.type?t=>{for(let t in e.options)t.removeAttribute("selected");e.value=t,e.selectedOptions[0]?.setAttribute("selected","")}:t=>e.value=t;return e=>l(s(e))};var m=(e,t,r,n)=>{let s=n.startsWith("on")&&n.slice(2),l=j(e,t,":"+n);if(l)return s?t=>{let r=l(t)||(()=>{});return v(e,s,r)}:t=>x(e,n,l(t))},v=(e,t,r)=>{if(!r)return;const n={evt:"",target:e,test:()=>!0};n.evt=(t.startsWith("on")?t.slice(2):t).replace(/\.(\w+)?-?([-\w]+)?/g,((e,t,r="")=>(n.test=A[t]?.(n,...r.split("-"))||n.test,"")));const{evt:s,target:l,test:i,defer:o,stop:a,prevent:u,...c}=n;o&&(r=o(r));const f=e=>i(e)&&(a&&e.stopPropagation(),u&&e.preventDefault(),r.call(l,e));return l.addEventListener(s,f,c),()=>l.removeEventListener(s,f,c)},A={prevent(e){e.prevent=!0},stop(e){e.stop=!0},once(e){e.once=!0},passive(e){e.passive=!0},capture(e){e.capture=!0},window(e){e.target=window},document(e){e.target=document},throttle(e,t){e.defer=e=>k(e,t?Number(t)||0:108)},debounce(e,t){e.defer=e=>W(e,t?Number(t)||0:108)},outside:e=>t=>{let r=e.target;return!(r.contains(t.target)||!1===t.target.isConnected||r.offsetWidth<1&&r.offsetHeight<1)},self:e=>t=>t.target===e.target,ctrl:(e,...t)=>e=>w.ctrl(e)&&t.every((t=>w[t]?w[t](e):e.key===t)),shift:(e,...t)=>e=>w.shift(e)&&t.every((t=>w[t]?w[t](e):e.key===t)),alt:(e,...t)=>e=>w.alt(e)&&t.every((t=>w[t]?w[t](e):e.key===t)),meta:(e,...t)=>e=>w.meta(e)&&t.every((t=>w[t]?w[t](e):e.key===t)),arrow:e=>w.arrow,enter:e=>w.enter,escape:e=>w.escape,tab:e=>w.tab,space:e=>w.space,backspace:e=>w.backspace,delete:e=>w.delete,digit:e=>w.digit,letter:e=>w.letter,character:e=>w.character},w={ctrl:e=>e.ctrlKey||"Control"===e.key||"Ctrl"===e.key,shift:e=>e.shiftKey||"Shift"===e.key,alt:e=>e.altKey||"Alt"===e.key,meta:e=>e.metaKey||"Meta"===e.key||"Command"===e.key,arrow:e=>e.key.startsWith("Arrow"),enter:e=>"Enter"===e.key,escape:e=>e.key.startsWith("Esc"),tab:e=>"Tab"===e.key,space:e=>" "===e.key||"Space"===e.key||" "===e.key,backspace:e=>"Backspace"===e.key,delete:e=>"Delete"===e.key,digit:e=>/^\d$/.test(e.key),letter:e=>/^[a-zA-Z]$/.test(e.key),character:e=>/^\S$/.test(e.key)},k=(e,t)=>{let r,n,s=l=>{r=!0,setTimeout((()=>{if(r=!1,n)return n=!1,s(l),e(l)}),t)};return t=>r?n=!0:(s(t),e(t))},W=(e,t)=>{let r;return n=>{clearTimeout(r),r=setTimeout((()=>{r=null,e(n)}),t)}},x=(e,t,r)=>{null==r||!1===r?e.removeAttribute(t):e.setAttribute(t,!0===r?"":"number"==typeof r||"string"==typeof r?r:"")},S={};function j(e,t,r){let n=S[t];if(!n){let s=/^[\n\s]*if.*\(.*\)/.test(t)||/\b(let|const)\s/.test(t)&&!r.startsWith(":on")?`(() => {${t}})()`:t;try{n=S[t]=new Function("__scope",`with (__scope) { return ${s.trim()} };`)}catch(n){return E(n,e,t,r)}}return s=>{let l;try{l=n.call(e,s)}catch(n){return E(n,e,t,r)}return l}}function E(e,t,n,s){Object.assign(e,{element:t,expression:n}),console.warn(`∴ ${e.message}\n\n${s}=${n?`"${n}"\n\n`:""}`,t),r((()=>{throw e}),0)}O.globals=c;var N=new WeakMap;function O(e,t){if(!e.children)return;if(N.has(e))return Object.assign(N.get(e),t);const r=p(t||{}),n=[],s=(e,t=e.parentNode)=>{for(let s in d){let l=":"+s;if(e.hasAttribute?.(l)){let i=e.getAttribute(l);if(e.removeAttribute(l),n.push(d[s](e,i,r,s)),N.has(e))return;if(e.parentNode!==t)return!1}}if(e.attributes)for(let t=0;t<e.attributes.length;){let s=e.attributes[t],l=s.name[0];if(":"===l||"@"===l){e.removeAttribute(s.name);let t="@"===l?`event=>{${s.value}}`:s.value,i=s.name.slice(1).split(l);for(let s of i){"@"===l&&(s="on"+s);let i=g[s]||m;n.push(i(e,t,r,s))}}else t++}for(let t,r=0;t=e.children[r];r++)!1===s(t,e)&&r--};s(e);for(let e of n)if(e){let t;y((()=>{"function"==typeof t&&t(),t=e(r)}))}return N.set(e,r),r}document.currentScript&&O(document.documentElement)})();