diff --git a/packages/nanoviews/.size-limit.json b/packages/nanoviews/.size-limit.json
index 2275901e..1f5e310c 100644
--- a/packages/nanoviews/.size-limit.json
+++ b/packages/nanoviews/.size-limit.json
@@ -10,7 +10,7 @@
"name": "All publics (Brotli)",
"path": "dist/index.js",
"import": "*",
- "limit": "6.6 kB"
+ "limit": "6.65 kB"
},
{
"name": "Average usage (Gzip)",
diff --git a/packages/nanoviews/src/flow/for.spec.ts b/packages/nanoviews/src/flow/for.spec.ts
index bb1a9d6e..ee63fb5d 100644
--- a/packages/nanoviews/src/flow/for.spec.ts
+++ b/packages/nanoviews/src/flow/for.spec.ts
@@ -25,6 +25,7 @@ import {
import { fragment } from '../elements/fragment.js'
import {
trackById,
+ as_,
for_
} from './for.js'
import * as Stories from './for.stories.js'
@@ -1032,6 +1033,71 @@ describe('nanoviews', () => {
expect(container.innerHTML).toBe('
')
})
+ it('should hand the row through a transform with `as_`', () => {
+ const items = signal([
+ {
+ id: 1,
+ name: 'Yatoro'
+ },
+ {
+ id: 2,
+ name: 'Larl'
+ }
+ ])
+ const { container } = render(() => ul()(
+ for_(items, trackById)(
+ as_(record, ($player, $index) => li()($player.$name, ':', $index))
+ )
+ ))
+
+ expect(container.innerHTML).toBe('')
+
+ // the transformed row is still the row: a write reaches the array
+ untracked(items)[0].name = 'x'
+ items([
+ {
+ id: 1,
+ name: 'Collapse'
+ },
+ {
+ id: 2,
+ name: 'Larl'
+ }
+ ])
+
+ expect(container.innerHTML).toBe('')
+ })
+
+ it('should keep a row written through `as_` writable', () => {
+ const items = signal([
+ {
+ id: 1,
+ name: ' Larl '
+ }
+ ])
+
+ render(() => ul()(
+ for_(items, trackById)(
+ as_(record, ($player) => {
+ const name = untracked($player.$name)
+
+ if (name !== name.trim()) {
+ $player.$name(name.trim())
+ }
+
+ return li()($player.$name)
+ })
+ )
+ ))
+
+ expect(untracked(items)).toEqual([
+ {
+ id: 1,
+ name: 'Larl'
+ }
+ ])
+ })
+
describe('fuzz', () => {
// A named test pins a shape someone thought of; these walk sequences
// nobody did. Both invariants are checked after every step: the rows
diff --git a/packages/nanoviews/src/flow/for.ts b/packages/nanoviews/src/flow/for.ts
index 168301fb..8474f2d6 100644
--- a/packages/nanoviews/src/flow/for.ts
+++ b/packages/nanoviews/src/flow/for.ts
@@ -30,6 +30,20 @@ export function trackById(item: { id: unknown }) {
return item.id
}
+/**
+ * Hand the row through a transform before rendering it
+ * @param as - Function that transforms the row, eg `record`
+ * @param each_ - Function that renders the transformed row
+ * @returns Function to pass to `for_`
+ */
+/* @__NO_SIDE_EFFECTS__ */
+export function as_- (
+ as: (item: Item) => Value,
+ each_: (value: Value, index: Index) => Child
+) {
+ return (item: Item, index: Index) => each_(as(item), index)
+}
+
type AnyEach = (
item: Accessor,
index: ReadableSignal
diff --git a/todo.txt b/todo.txt
index 31e9e3cc..b3b46b8f 100644
--- a/todo.txt
+++ b/todo.txt
@@ -47,17 +47,8 @@
- for_ duplicate track keys: unsupported by design, must keep failing loudly - the crash lands a step away from the cause, so it needs a clear throw at the point of detection
- rework return slot$ to look like element/component? fn.prop is faster than {f,p}
- util to transform static props to signal props?
-- additional arg for record in for$? as$
- static index for untracked loop?
-for_($items)(
- as_(record, ($item) => li()($item.$name))
-)
-
-for_($items)(
- asRecord(($item) => li()($item.$name))
-)
-
## Perf
- !== undefined is faster