tutuca 0.9.64 → 0.9.65

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "tutuca",
3
- "version": "0.9.64",
3
+ "version": "0.9.65",
4
4
  "type": "module",
5
5
  "description": "Zero-dependency SPA framework with immutable state and virtual DOM",
6
6
  "main": "./dist/tutuca.js",
@@ -560,7 +560,7 @@ custom elements for use with Tutuca. See *Attribute Binding* above.
560
560
  <x text="@count"></x>
561
561
  </li>
562
562
 
563
- <!-- shared per-loop data (computed once before iteration) -->
563
+ <!-- shared per-loop data + slicing (computed once before iteration) -->
564
564
  <li @each=".items" @loop-with="getIterData" @when="filterItem">...</li>
565
565
 
566
566
  <!-- render a list of components -->
@@ -582,10 +582,31 @@ share the handler-name resolution rules below.
582
582
  alter: {
583
583
  filterItem(_key, item, iterData) { return item.includes(iterData.q); },
584
584
  enrichItem(binds, _key, item, iterData) { binds.count = item.length; },
585
- getIterData(seq) { return { q: this.query.toLowerCase() }; },
585
+ // `@loop-with` returns { iterData?, start?, end? } — all optional.
586
+ getIterData(seq) {
587
+ const start = this.page * this.pageSize;
588
+ return { iterData: { q: this.query.toLowerCase() }, start, end: start + this.pageSize };
589
+ },
586
590
  }
587
591
  ```
588
592
 
593
+ #### `@loop-with` return shape — `iterData` + slicing
594
+
595
+ A `@loop-with` handler returns an object with up to three optional keys:
596
+
597
+ - **`iterData`** — the shared per-loop value handed to `@when` /
598
+ `@enrich-with`. Defaults to `{ seq }` when omitted.
599
+ - **`start`, `end`** — a positional slice of the iteration, with
600
+ `Array.prototype.slice` semantics: `end` is exclusive, negatives count
601
+ from the end (`end: -3` drops the last 3), `undefined` means the
602
+ natural bound. Use this to **paginate** — skip a prefix and/or suffix
603
+ without iterating or rendering it.
604
+
605
+ Slicing is positional but **preserves each item's original key**: a List
606
+ sliced to `start: 2` still binds `@key` to `2, 3, …`, so events, drag,
607
+ and two-way binding keep their identity. `@when` then filters *within*
608
+ the window, so a page may yield fewer than `end - start` items.
609
+
589
610
  ### Lifecycle of `@each`
590
611
 
591
612
  For each render of an element with `@each=".items"`:
@@ -593,9 +614,11 @@ For each render of an element with `@each=".items"`:
593
614
  1. **Resolve sequence** — evaluate `.items`. Lists, IMaps, OMaps, ISets,
594
615
  and any class declaring a `SEQ_INFO` walker are recognized.
595
616
  2. **`@loop-with`** (once per render) — `getIterData.call(this, seq)` is
596
- called and its return becomes `iterData`. Skipped if no `@loop-with`;
597
- in that case `iterData` is `{ seq }` from the default.
598
- 3. For each `(key, value)` pair in the sequence:
617
+ called with the full sequence; its `iterData` becomes the shared
618
+ per-loop value and its `start`/`end` slice the iteration. Skipped if
619
+ no `@loop-with`; then `iterData` is `{ seq }` and the whole sequence
620
+ is iterated.
621
+ 3. For each `(key, value)` pair in the sliced sequence:
599
622
  1. **`@when`** — `filterItem.call(this, key, value, iterData)`; if it
600
623
  returns `false`, the item is skipped.
601
624
  2. **`@enrich-with`** — `enrichItem.call(this, binds, key, value, iterData)`.
@@ -84,8 +84,11 @@ Comp.input.handlerName.call(comp, arg1, arg2, /* … */);
84
84
  `alter` handlers run inside `@each` / `@when` / `@loop-with` /
85
85
  `@enrich-with` and have three distinct shapes:
86
86
 
87
- - `loopWith(seq)` — called once with the collection, returns an
88
- `iterData` object. `this` is the parent component instance.
87
+ - `loopWith(seq)` — called once with the full collection, returns
88
+ `{ iterData?, start?, end? }`: `iterData` is the shared per-loop value
89
+ (defaults to `{ seq }`); `start`/`end` slice the iteration
90
+ (`Array.prototype.slice` semantics, original keys preserved). `this`
91
+ is the parent component instance.
89
92
  - `when(key, value, iterData)` — called per element, returns truthy to
90
93
  keep. `this` is the parent component instance.
91
94
  - `enrichWith(binds, key, value, iterData)` — called per kept element;
@@ -125,7 +128,7 @@ const Items = component({
125
128
  name: "Items",
126
129
  fields: { items: [], multiplier: 1 },
127
130
  alter: {
128
- loopMeta(seq) { return { len: seq.length, doubled: seq.length * 2 }; },
131
+ loopMeta(seq) { return { iterData: { len: seq.length, doubled: seq.length * 2 } }; },
129
132
  keepEven(k) { return k % 2 === 0; },
130
133
  addLabel(binds, k, v, { len }) { binds.label = `${k}/${len}: ${v}`; },
131
134
  },