-
Notifications
You must be signed in to change notification settings - Fork 0
/
state.ts
95 lines (86 loc) · 2.5 KB
/
state.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import type { IConsumable } from './types';
import { createConsumable, getValue } from './consumables.js';
/**
* `state` creates a reactive value that can the be used with tags to create dinamic and reactive apps.
*
* @see https://github.com/nombrekeff/cardboard-js/wiki/State
*
* @example
* ```ts
* const count = state(0);
* count.changed(() => { ... });
* count.dispatch(2);
* count.value++;
*
* div().hideIf(count);
* div().disableIf(count);
* div(template('Count is: $count', { count: count }));
* ```
*/
export const state = <T>(initialValue: T): IConsumable<T> => {
return createConsumable(initialValue);
};
/**
* `listState` creates a reactive list of values that can be used with tags to manage dynamic and reactive apps.
* It wraps each item with an {@link IConsumable}
* @see https://github.com/nombrekeff/cardboard-js/wiki/ListState
*
* @example
* ```javascript
* const myList = listState([1, 2, 3]);
*
* myList.add(4);
* myList.addAt(0, 0);
* myList.remove(2);
* myList.removeWhere(item => item === 3);
* const listValues = myList.listValue;
* const listLength = myList.length;
*
* // Listen to changes in the list
* myList.list.changed(() => {
* // List has changed
* });
* ```
*/
export const listState = <T>(initialData: T[]) => {
const _list = state<Array<IConsumable<T>>>(
initialData.map((d) => createConsumable(d)),
);
const add = (item: T) => {
stateAdd(_list, createConsumable(item));
};
const addAt = (item: T, index: number) => {
stateAddAt(_list, createConsumable(item), index);
};
return {
get list() {
return _list;
},
get listValue() {
return _list.value;
},
add,
addAt,
remove: stateRemove.bind({}, _list),
removeWhere: stateRemoveWhere.bind({}, _list),
length: _list.intersect((_list) => _list.length),
};
};
export const stateAdd = <T>(cons: IConsumable<T[]>, item: T) => {
cons.value = [...cons.value, item];
};
export const stateAddAt = <T>(cons: IConsumable<T[]>, item: T, index: number) => {
let newData: any = [...cons.value];
newData.splice(index, 0, item);
cons.value = newData;
newData = [];
};
export const stateRemoveWhere = <T>(cons: IConsumable<T[]>, cb: (item: T, index: number) => boolean) => {
cons.value = cons.value.filter((el, i) => !cb(el, i));
};
export const stateRemove = <T>(cons: IConsumable<T[]>, item: T) => {
const index = cons.value.findIndex(cons => getValue(cons) === getValue(item));
stateRemoveWhere(cons, (_, i) => {
return index === i;
});
};