Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/nanoviews/.size-limit.json
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand Down
66 changes: 66 additions & 0 deletions packages/nanoviews/src/flow/for.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -1032,6 +1033,71 @@ describe('nanoviews', () => {
expect(container.innerHTML).toBe('<div><ul><li>nobody</li></ul></div>')
})

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('<div><ul><li>Yatoro:0</li><li>Larl:1</li></ul></div>')

// 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('<div><ul><li>Collapse:0</li><li>Larl:1</li></ul></div>')
})

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
Expand Down
14 changes: 14 additions & 0 deletions packages/nanoviews/src/flow/for.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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_<Item, Index, Value>(
as: (item: Item) => Value,
each_: (value: Value, index: Index) => Child
) {
return (item: Item, index: Index) => each_(as(item), index)
}

type AnyEach = (
item: Accessor<unknown>,
index: ReadableSignal<number>
Expand Down
9 changes: 0 additions & 9 deletions todo.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down