Skip to content

Commit 71064e4

Browse files
committed
Add custom push view example
1 parent 7b68be5 commit 71064e4

File tree

3 files changed

+92
-2
lines changed

3 files changed

+92
-2
lines changed

docs/reference/views/index.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -214,9 +214,15 @@ The example below appends an element every time an event is fired:
214214
messages.emit("Bar");
215215
```
216216

217-
You can find more complex view implementation examples [in rvx's core view module](https://github.com/mxjp/rvx/blob/main/src/core/view.ts) and [this example](../../examples/custom-view.md).
217+
You can find more complex view implementation examples here:
218+
219+
+ [rvx core views](https://github.com/mxjp/rvx/blob/main/src/core/view.ts)
220+
+ Examples
221+
+ [Rotate](../../examples/view-rotate.md)
222+
+ [Push](../../examples/view-push.md)
218223

219224
## Lifecycle Conventions
220225
When the [lifecycle](../lifecycle.md) in which a view was created is disposed, all of it's nodes should remain in place by convention.
226+
221227
+ This results in much better performance when disposing large amounts of nested views.
222228
+ Users of that view have the ability to keep displaying remaining content for animation purposes.

examples/src/view-push.tsx

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
/*
2+
3+
# Custom View / Push
4+
This example shows a custom view that pushes elements onto itself.
5+
6+
This can be useful when you only ever append or prepend elements and you require the absolute best performance possible.
7+
8+
*/
9+
10+
import { $, capture, Component, Nest, render, teardown, TeardownHook, View } from "rvx";
11+
import { Emitter, Event } from "rvx/event";
12+
13+
export function Example() {
14+
const reset = $();
15+
const actions = new Emitter<[Action, number]>();
16+
17+
return <div class="column">
18+
<div class="row">
19+
<button on:click={() => actions.emit("prepend", Math.random())}>Prepend</button>
20+
<button on:click={() => actions.emit("append", Math.random())}>Append</button>
21+
<button on:click={() => reset.notify()}>Reset</button>
22+
</div>
23+
<ul>
24+
{/*
25+
Combine with <Nest> to reset the
26+
inner state when "reset" is updated:
27+
*/}
28+
<Nest watch={reset}>
29+
{() => <PushView actions={actions.event}>
30+
{item => {
31+
return <li>{item}</li>;
32+
}}
33+
</PushView>}
34+
</Nest>
35+
</ul>
36+
</div>;
37+
}
38+
39+
type Action = "prepend" | "append";
40+
41+
function PushView<T>(props: {
42+
children: Component<T>;
43+
actions: Event<[Action, T]>;
44+
}) {
45+
return new View((setBoundary, self) => {
46+
// Keep an array of teardown hooks to dispose instances later:
47+
const dispose: TeardownHook[] = [];
48+
teardown(() => dispose.forEach(h => h()));
49+
50+
// Create an initial anchor element:
51+
const anchor = document.createComment("");
52+
setBoundary(anchor, anchor);
53+
54+
// Handle action events:
55+
props.actions((action, item) => {
56+
let parent: Node | null = anchor.parentElement;
57+
if (!parent) {
58+
// Create a parent if there is none:
59+
parent = document.createDocumentFragment();
60+
parent.appendChild(anchor);
61+
}
62+
63+
// Render the item into a view & capture it's lifecycle:
64+
let view!: View;
65+
dispose.push(capture(() => {
66+
view = render(props.children(item));
67+
}));
68+
69+
// Append or prepend the item view to this one:
70+
if (action === "append") {
71+
const next = self.last!.nextSibling;
72+
if (next) {
73+
view.insertBefore(parent, next);
74+
} else {
75+
view.appendTo(parent);
76+
}
77+
setBoundary(undefined, view.last);
78+
} else {
79+
view.insertBefore(parent, self.first!);
80+
setBoundary(view.first, undefined);
81+
}
82+
});
83+
});
84+
}

examples/src/custom-view.tsx renamed to examples/src/view-rotate.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*
22
3-
# Custom View
3+
# Custom View / Rotate
44
This example shows a custom view that rotates the order of it's logical children when a signal is updated.
55
66
You can toggle the visibility of the entire view or one of it's children to demonstrate boundary tracking.

0 commit comments

Comments
 (0)