Skip to content

Commit 78b289f

Browse files
committed
Start describing the view models
1 parent d1ca4e1 commit 78b289f

File tree

3 files changed

+190
-0
lines changed

3 files changed

+190
-0
lines changed
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { butterfly, StateSetter } from 'butterfloat'
2+
import { filter, map, mergeMap, Observable, range } from 'rxjs'
3+
import { RowViewModel } from './row-vm'
4+
5+
export interface IdRange {
6+
min: number
7+
max: number
8+
added: [start: number, count: number]
9+
}
10+
11+
export class AppViewModel {
12+
readonly #idRange: Observable<IdRange>
13+
readonly #setIdRange: (idRange: StateSetter<IdRange>) => void
14+
get idRange() {
15+
return this.#idRange
16+
}
17+
18+
readonly #selectedId: Observable<number>
19+
readonly #setSelectedId: (id: StateSetter<number>) => void
20+
get selectedId() {
21+
return this.#selectedId
22+
}
23+
24+
readonly #rows: Observable<RowViewModel>
25+
get rows() {
26+
return this.#rows
27+
}
28+
29+
constructor() {
30+
;[this.#idRange, this.#setIdRange] = butterfly<IdRange>({
31+
min: 0,
32+
max: 0,
33+
added: [-1, -1],
34+
})
35+
;[this.#selectedId, this.#setSelectedId] = butterfly<number>(-1)
36+
37+
this.#rows = this.#idRange.pipe(
38+
filter((idRange) => idRange.added[0] > 0 && idRange.added[1] > 0),
39+
mergeMap((idRange) => range(idRange.added[0], idRange.added[1])),
40+
map((id) => new RowViewModel(this, id)),
41+
)
42+
}
43+
44+
clear() {
45+
this.#setIdRange((current) => ({
46+
min: current.max,
47+
max: current.max,
48+
added: [-1, -1],
49+
}))
50+
}
51+
52+
selectRow(id: number) {
53+
this.#setSelectedId(id)
54+
}
55+
56+
addRows(count: number) {
57+
this.#setIdRange((current) => {
58+
const min = current.min
59+
const max = current.max + count
60+
return { min, max, added: [current.max, count] }
61+
})
62+
}
63+
}

frameworks/keyed/butterfloat/data.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
const adjectives = [
2+
'pretty',
3+
'large',
4+
'big',
5+
'small',
6+
'tall',
7+
'short',
8+
'long',
9+
'handsome',
10+
'plain',
11+
'quaint',
12+
'clean',
13+
'elegant',
14+
'easy',
15+
'angry',
16+
'crazy',
17+
'helpful',
18+
'mushy',
19+
'odd',
20+
'unsightly',
21+
'adorable',
22+
'important',
23+
'inexpensive',
24+
'cheap',
25+
'expensive',
26+
'fancy',
27+
]
28+
const colors = [
29+
'red',
30+
'yellow',
31+
'blue',
32+
'green',
33+
'pink',
34+
'brown',
35+
'purple',
36+
'brown',
37+
'white',
38+
'black',
39+
'orange',
40+
]
41+
42+
const nouns = [
43+
'table',
44+
'chair',
45+
'house',
46+
'bbq',
47+
'desk',
48+
'car',
49+
'pony',
50+
'cookie',
51+
'sandwich',
52+
'burger',
53+
'pizza',
54+
'mouse',
55+
'keyboard',
56+
]
57+
58+
export function randomLabel() {
59+
const adjective = adjectives[Math.floor(Math.random() * adjectives.length)]
60+
const color = colors[Math.floor(Math.random() * colors.length)]
61+
const noun = nouns[Math.floor(Math.random() * nouns.length)]
62+
return `${adjective} ${color} ${noun}`
63+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { butterfly, StateSetter } from 'butterfloat'
2+
import { filter, map, merge, NEVER, Observable, Subject, takeUntil } from 'rxjs'
3+
import { randomLabel } from './data.js'
4+
import { AppViewModel } from './app-vm.js'
5+
6+
export class RowViewModel {
7+
readonly #app: AppViewModel
8+
9+
readonly #id: number
10+
get id() {
11+
return this.#id
12+
}
13+
14+
readonly #label: Observable<string>
15+
readonly #setLabel: (label: StateSetter<string>) => void
16+
get label() {
17+
return this.#label
18+
}
19+
20+
readonly #remove = new Subject<boolean>()
21+
22+
readonly #alive: Observable<boolean>
23+
get alive() {
24+
return this.#alive
25+
}
26+
27+
readonly #selected: Observable<boolean>
28+
get selected() {
29+
return this.#selected
30+
}
31+
32+
constructor(app: AppViewModel, id: number) {
33+
this.#app = app
34+
this.#id = id
35+
;[this.#label, this.#setLabel] = butterfly(randomLabel())
36+
37+
this.#alive = NEVER.pipe(
38+
takeUntil(
39+
merge(
40+
this.#remove.pipe(filter(() => true)),
41+
this.#app.idRange.pipe(
42+
filter((range) => range.min > this.#id),
43+
map(() => true),
44+
),
45+
),
46+
),
47+
)
48+
49+
this.#selected = this.#app.selectedId.pipe(map((id) => id === this.#id))
50+
}
51+
52+
updateLabel() {
53+
this.#setLabel((current) => current + '!!!')
54+
}
55+
56+
remove() {
57+
this.#remove.next(true)
58+
this.#remove.complete()
59+
}
60+
61+
select() {
62+
this.#app.selectRow(this.#id)
63+
}
64+
}

0 commit comments

Comments
 (0)