aberdeen 0.0.8 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.txt +16 -0
- package/README.md +2 -155
- package/dist/aberdeen.d.ts +428 -0
- package/dist/aberdeen.js +713 -351
- package/dist/aberdeen.min.js +1 -1
- package/package.json +28 -16
package/LICENSE.txt
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
ISC License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2021 Frank van Viegen
|
|
4
|
+
|
|
5
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
6
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
7
|
+
copyright notice and this permission notice appear in all copies.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
10
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
11
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
12
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
13
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
14
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
15
|
+
PERFORMANCE OF THIS SOFTWARE.
|
|
16
|
+
|
package/README.md
CHANGED
|
@@ -1,160 +1,7 @@
|
|
|
1
1
|
Aberdeen
|
|
2
2
|
--------
|
|
3
3
|
|
|
4
|
-
A JavaScript library for quickly building performant declarative user interfaces *without* the use of a virtual DOM.
|
|
4
|
+
A TypeScript/JavaScript library for quickly building performant declarative user interfaces *without* the use of a virtual DOM.
|
|
5
5
|
|
|
6
|
-
The key insight is the use of many small anonymous functions, that will automatically rerun when the underlying data changes.
|
|
6
|
+
The key insight is the use of many small anonymous functions, that will automatically rerun when the underlying data changes. In order to trigger updates, that data should be encapsulated in any number of `Store` objects. They can hold anything, from simple values to deeply nested data structures, in which case user-interface functions can (automatically) subscribe to just the parts they depend upon.
|
|
7
7
|
|
|
8
|
-
## An example
|
|
9
|
-
|
|
10
|
-
```ts
|
|
11
|
-
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
```jsx
|
|
15
|
-
function Square(props) {
|
|
16
|
-
return (
|
|
17
|
-
<button className="square" onClick={props.onClick}>
|
|
18
|
-
{props.value}
|
|
19
|
-
</button>
|
|
20
|
-
);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
class Board extends React.Component {
|
|
24
|
-
renderSquare(i) {
|
|
25
|
-
return (
|
|
26
|
-
<Square
|
|
27
|
-
value={this.props.squares[i]}
|
|
28
|
-
onClick={() => this.props.onClick(i)}
|
|
29
|
-
/>
|
|
30
|
-
);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
render() {
|
|
34
|
-
return (
|
|
35
|
-
<div>
|
|
36
|
-
<div className="board-row">
|
|
37
|
-
{this.renderSquare(0)}
|
|
38
|
-
{this.renderSquare(1)}
|
|
39
|
-
{this.renderSquare(2)}
|
|
40
|
-
</div>
|
|
41
|
-
<div className="board-row">
|
|
42
|
-
{this.renderSquare(3)}
|
|
43
|
-
{this.renderSquare(4)}
|
|
44
|
-
{this.renderSquare(5)}
|
|
45
|
-
</div>
|
|
46
|
-
<div className="board-row">
|
|
47
|
-
{this.renderSquare(6)}
|
|
48
|
-
{this.renderSquare(7)}
|
|
49
|
-
{this.renderSquare(8)}
|
|
50
|
-
</div>
|
|
51
|
-
</div>
|
|
52
|
-
);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
class Game extends React.Component {
|
|
57
|
-
constructor(props) {
|
|
58
|
-
super(props);
|
|
59
|
-
this.state = {
|
|
60
|
-
history: [
|
|
61
|
-
{
|
|
62
|
-
squares: Array(9).fill(null)
|
|
63
|
-
}
|
|
64
|
-
],
|
|
65
|
-
stepNumber: 0,
|
|
66
|
-
xIsNext: true
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
handleClick(i) {
|
|
71
|
-
const history = this.state.history.slice(0, this.state.stepNumber + 1);
|
|
72
|
-
const current = history[history.length - 1];
|
|
73
|
-
const squares = current.squares.slice();
|
|
74
|
-
if (calculateWinner(squares) || squares[i]) {
|
|
75
|
-
return;
|
|
76
|
-
}
|
|
77
|
-
squares[i] = this.state.xIsNext ? "X" : "O";
|
|
78
|
-
this.setState({
|
|
79
|
-
history: history.concat([
|
|
80
|
-
{
|
|
81
|
-
squares: squares
|
|
82
|
-
}
|
|
83
|
-
]),
|
|
84
|
-
stepNumber: history.length,
|
|
85
|
-
xIsNext: !this.state.xIsNext
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
jumpTo(step) {
|
|
90
|
-
this.setState({
|
|
91
|
-
stepNumber: step,
|
|
92
|
-
xIsNext: (step % 2) === 0
|
|
93
|
-
});
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
render() {
|
|
97
|
-
const history = this.state.history;
|
|
98
|
-
const current = history[this.state.stepNumber];
|
|
99
|
-
const winner = calculateWinner(current.squares);
|
|
100
|
-
|
|
101
|
-
const moves = history.map((step, move) => {
|
|
102
|
-
const desc = move ?
|
|
103
|
-
'Go to move #' + move :
|
|
104
|
-
'Go to game start';
|
|
105
|
-
return (
|
|
106
|
-
<li key={move}>
|
|
107
|
-
<button onClick={() => this.jumpTo(move)}>{desc}</button>
|
|
108
|
-
</li>
|
|
109
|
-
);
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
let status;
|
|
113
|
-
if (winner) {
|
|
114
|
-
status = "Winner: " + winner;
|
|
115
|
-
} else {
|
|
116
|
-
status = "Next player: " + (this.state.xIsNext ? "X" : "O");
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
return (
|
|
120
|
-
<div className="game">
|
|
121
|
-
<div className="game-board">
|
|
122
|
-
<Board
|
|
123
|
-
squares={current.squares}
|
|
124
|
-
onClick={i => this.handleClick(i)}
|
|
125
|
-
/>
|
|
126
|
-
</div>
|
|
127
|
-
<div className="game-info">
|
|
128
|
-
<div>{status}</div>
|
|
129
|
-
<ol>{moves}</ol>
|
|
130
|
-
</div>
|
|
131
|
-
</div>
|
|
132
|
-
);
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// ========================================
|
|
137
|
-
|
|
138
|
-
ReactDOM.render(<Game />, document.getElementById("root"));
|
|
139
|
-
|
|
140
|
-
function calculateWinner(squares) {
|
|
141
|
-
const lines = [
|
|
142
|
-
[0, 1, 2],
|
|
143
|
-
[3, 4, 5],
|
|
144
|
-
[6, 7, 8],
|
|
145
|
-
[0, 3, 6],
|
|
146
|
-
[1, 4, 7],
|
|
147
|
-
[2, 5, 8],
|
|
148
|
-
[0, 4, 8],
|
|
149
|
-
[2, 4, 6]
|
|
150
|
-
];
|
|
151
|
-
for (let i = 0; i < lines.length; i++) {
|
|
152
|
-
const [a, b, c] = lines[i];
|
|
153
|
-
if (squares[a] && squares[a] === squares[b] && squares[a] === squares[c]) {
|
|
154
|
-
return squares[a];
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
return null;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
```
|
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
interface QueueRunner {
|
|
2
|
+
queueOrder: number;
|
|
3
|
+
queueRun(): void;
|
|
4
|
+
}
|
|
5
|
+
declare type SortKeyType = number | string | Array<number | string>;
|
|
6
|
+
interface Observer {
|
|
7
|
+
onChange(index: any, newData: DatumType, oldData: DatumType): void;
|
|
8
|
+
}
|
|
9
|
+
declare abstract class Scope implements QueueRunner, Observer {
|
|
10
|
+
parentElement: Element | undefined;
|
|
11
|
+
queueOrder: number;
|
|
12
|
+
precedingSibling: Node | Scope | undefined;
|
|
13
|
+
lastChild: Node | Scope | undefined;
|
|
14
|
+
cleaners: Array<{
|
|
15
|
+
_clean: (scope: Scope) => void;
|
|
16
|
+
}>;
|
|
17
|
+
isDead: boolean;
|
|
18
|
+
constructor(parentElement: Element | undefined, precedingSibling: Node | Scope | undefined, queueOrder: number);
|
|
19
|
+
findPrecedingNode(): Node | undefined;
|
|
20
|
+
findLastNode(): Node | undefined;
|
|
21
|
+
addNode(node: Node): void;
|
|
22
|
+
remove(): void;
|
|
23
|
+
_clean(): void;
|
|
24
|
+
onChange(index: any, newData: DatumType, oldData: DatumType): void;
|
|
25
|
+
abstract queueRun(): void;
|
|
26
|
+
}
|
|
27
|
+
declare class OnEachScope extends Scope {
|
|
28
|
+
/** The Node we are iterating */
|
|
29
|
+
collection: ObsCollection;
|
|
30
|
+
/** A function returning a number/string/array that defines the position of an item */
|
|
31
|
+
makeSortKey: (value: Store) => SortKeyType;
|
|
32
|
+
/** A function that renders an item */
|
|
33
|
+
renderer: (itemStore: Store) => void;
|
|
34
|
+
/** The ordered list of currently item scopes */
|
|
35
|
+
byPosition: OnEachItemScope[];
|
|
36
|
+
/** The item scopes in a Map by index */
|
|
37
|
+
byIndex: Map<any, OnEachItemScope>;
|
|
38
|
+
/** Indexes that have been created/removed and need to be handled in the next `queueRun` */
|
|
39
|
+
newIndexes: Set<any>;
|
|
40
|
+
removedIndexes: Set<any>;
|
|
41
|
+
constructor(parentElement: Element | undefined, precedingSibling: Node | Scope | undefined, queueOrder: number, collection: ObsCollection, renderer: (itemStore: Store) => void, makeSortKey: (itemStore: Store) => SortKeyType);
|
|
42
|
+
onChange(index: any, newData: DatumType, oldData: DatumType): void;
|
|
43
|
+
queueRun(): void;
|
|
44
|
+
_clean(): void;
|
|
45
|
+
renderInitial(): void;
|
|
46
|
+
addChild(itemIndex: any): void;
|
|
47
|
+
removeChild(itemIndex: any): void;
|
|
48
|
+
findPosition(sortStr: string): number;
|
|
49
|
+
insertAtPosition(child: OnEachItemScope): void;
|
|
50
|
+
removeFromPosition(child: OnEachItemScope): void;
|
|
51
|
+
}
|
|
52
|
+
declare class OnEachItemScope extends Scope {
|
|
53
|
+
parent: OnEachScope;
|
|
54
|
+
itemIndex: any;
|
|
55
|
+
sortStr: string;
|
|
56
|
+
constructor(parentElement: Element | undefined, precedingSibling: Node | Scope | undefined, queueOrder: number, parent: OnEachScope, itemIndex: any);
|
|
57
|
+
queueRun(): void;
|
|
58
|
+
update(): void;
|
|
59
|
+
}
|
|
60
|
+
declare type DatumType = string | number | Function | boolean | null | undefined | ObsMap | ObsArray;
|
|
61
|
+
declare abstract class ObsCollection {
|
|
62
|
+
observers: Map<any, Set<Observer>>;
|
|
63
|
+
addObserver(index: any, observer: Observer): boolean;
|
|
64
|
+
removeObserver(index: any, observer: Observer): void;
|
|
65
|
+
emitChange(index: any, newData: DatumType, oldData: DatumType): void;
|
|
66
|
+
_clean(observer: Observer): void;
|
|
67
|
+
setIndex(index: any, newValue: any, deleteMissing: boolean): void;
|
|
68
|
+
abstract rawGet(index: any): DatumType;
|
|
69
|
+
abstract rawSet(index: any, data: DatumType): void;
|
|
70
|
+
abstract merge(newValue: any, deleteMissing: boolean): void;
|
|
71
|
+
abstract getType(): string;
|
|
72
|
+
abstract getRecursive(depth: number): object | Set<any> | Array<any>;
|
|
73
|
+
abstract iterateIndexes(scope: OnEachScope): void;
|
|
74
|
+
abstract normalizeIndex(index: any): any;
|
|
75
|
+
abstract getCount(): number;
|
|
76
|
+
}
|
|
77
|
+
declare class ObsArray extends ObsCollection {
|
|
78
|
+
data: Array<DatumType>;
|
|
79
|
+
getType(): string;
|
|
80
|
+
getRecursive(depth: number): any[];
|
|
81
|
+
rawGet(index: any): DatumType;
|
|
82
|
+
rawSet(index: any, newData: DatumType): void;
|
|
83
|
+
merge(newValue: any, deleteMissing: boolean): boolean;
|
|
84
|
+
iterateIndexes(scope: OnEachScope): void;
|
|
85
|
+
normalizeIndex(index: any): any;
|
|
86
|
+
getCount(): number;
|
|
87
|
+
}
|
|
88
|
+
declare class ObsMap extends ObsCollection {
|
|
89
|
+
data: Map<any, DatumType>;
|
|
90
|
+
getType(): string;
|
|
91
|
+
getRecursive(depth: number): Map<any, any>;
|
|
92
|
+
rawGet(index: any): DatumType;
|
|
93
|
+
rawSet(index: any, newData: DatumType): void;
|
|
94
|
+
merge(newValue: any, deleteMissing: boolean): boolean;
|
|
95
|
+
iterateIndexes(scope: OnEachScope): void;
|
|
96
|
+
normalizeIndex(index: any): any;
|
|
97
|
+
getCount(): number;
|
|
98
|
+
}
|
|
99
|
+
export declare class Store {
|
|
100
|
+
private collection;
|
|
101
|
+
private idx;
|
|
102
|
+
constructor();
|
|
103
|
+
constructor(value: any);
|
|
104
|
+
/** @internal */
|
|
105
|
+
constructor(collection: ObsCollection, index: any);
|
|
106
|
+
/**
|
|
107
|
+
*
|
|
108
|
+
* @returns The index for this Store within its parent collection. This will be a `number`
|
|
109
|
+
* when the parent collection is an array, a `string` when it's an object, or any data type
|
|
110
|
+
* when it's a `Map`.
|
|
111
|
+
*
|
|
112
|
+
* @example
|
|
113
|
+
* ```
|
|
114
|
+
* let store = new Store({x: 123})
|
|
115
|
+
* let subStore = store.ref('x')
|
|
116
|
+
* assert(subStore.get() === 123)
|
|
117
|
+
* assert(subStore.index() === 'x') // <----
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
index(): any;
|
|
121
|
+
/** @internal */
|
|
122
|
+
_clean(scope: Scope): void;
|
|
123
|
+
/**
|
|
124
|
+
* @returns Resolves `path` and then retrieves the value that is there, subscribing
|
|
125
|
+
* to all read `Store` values. If `path` does not exist, `undefined` is returned.
|
|
126
|
+
* @param path - Any path terms to resolve before retrieving the value.
|
|
127
|
+
* @example
|
|
128
|
+
* ```
|
|
129
|
+
* let store = new Store({a: {b: {c: {d: 42}}}})
|
|
130
|
+
* assert(store.get('a', 'b') === {c: {d: 42}})
|
|
131
|
+
* ```
|
|
132
|
+
*/
|
|
133
|
+
get(...path: any): any;
|
|
134
|
+
/**
|
|
135
|
+
* @returns The same as [[`get`]], but doesn't subscribe to changes.
|
|
136
|
+
*/
|
|
137
|
+
peek(...path: any): any;
|
|
138
|
+
/**
|
|
139
|
+
* @returns Like [[`get`]], but throws a `TypeError` if the resulting value is not of type `number`.
|
|
140
|
+
* Using this instead of just [[`get`]] is especially useful from within TypeScript.
|
|
141
|
+
*/
|
|
142
|
+
getNumber(...path: any): number;
|
|
143
|
+
/**
|
|
144
|
+
* @returns Like [[`get`]], but throws a `TypeError` if the resulting value is not of type `string`.
|
|
145
|
+
* Using this instead of just [[`get`]] is especially useful from within TypeScript.
|
|
146
|
+
*/
|
|
147
|
+
getString(...path: any): string;
|
|
148
|
+
/**
|
|
149
|
+
* @returns Like [[`get`]], but throws a `TypeError` if the resulting value is not of type `boolean`.
|
|
150
|
+
* Using this instead of just [[`get`]] is especially useful from within TypeScript.
|
|
151
|
+
*/
|
|
152
|
+
getBoolean(...path: any): boolean;
|
|
153
|
+
/**
|
|
154
|
+
* @returns Like [[`get`]], but throws a `TypeError` if the resulting value is not of type `function`.
|
|
155
|
+
* Using this instead of just [[`get`]] is especially useful from within TypeScript.
|
|
156
|
+
*/
|
|
157
|
+
getFunction(...path: any): (Function);
|
|
158
|
+
/**
|
|
159
|
+
* @returns Like [[`get`]], but throws a `TypeError` if the resulting value is not of type `array`.
|
|
160
|
+
* Using this instead of just [[`get`]] is especially useful from within TypeScript.
|
|
161
|
+
*/
|
|
162
|
+
getArray(...path: any): any[];
|
|
163
|
+
/**
|
|
164
|
+
* @returns Like [[`get`]], but throws a `TypeError` if the resulting value is not of type `object`.
|
|
165
|
+
* Using this instead of just [[`get`]] is especially useful from within TypeScript.
|
|
166
|
+
*/
|
|
167
|
+
getObject(...path: any): object;
|
|
168
|
+
/**
|
|
169
|
+
* @returns Like [[`get`]], but throws a `TypeError` if the resulting value is not of type `map`.
|
|
170
|
+
* Using this instead of just [[`get`]] is especially useful from within TypeScript.
|
|
171
|
+
*/
|
|
172
|
+
getMap(...path: any): Map<any, any>;
|
|
173
|
+
/**
|
|
174
|
+
* @returns Like [[`get`]], but the first parameter is the default value (returned when the Store
|
|
175
|
+
* contains `undefined`). This default value is also used to determine the expected type,
|
|
176
|
+
* and to throw otherwise.
|
|
177
|
+
*/
|
|
178
|
+
getOr<T>(defaultValue: T, ...path: any): T;
|
|
179
|
+
/** Retrieve a value. This is a more flexible form of the [[`get`]] and [[`peek`]] methods.
|
|
180
|
+
* @returns The resulting value, or `undefined` if the `path` does not exist.
|
|
181
|
+
*/
|
|
182
|
+
query(opts: {
|
|
183
|
+
/** The value for this path should be retrieved. Defaults to `[]`, meaning the entire `Store`. */
|
|
184
|
+
path?: any[];
|
|
185
|
+
/** A string specifying what type the query is expected to return. Options are:
|
|
186
|
+
* "undefined", "null", "boolean", "number", "string", "function", "array", "map"
|
|
187
|
+
* and "object". If the store holds a different type of value, a `TypeError`
|
|
188
|
+
* exception is thrown. By default (when `type` is `undefined`) no type checking
|
|
189
|
+
* is done.
|
|
190
|
+
*/
|
|
191
|
+
type?: string;
|
|
192
|
+
depth?: number;
|
|
193
|
+
/** Return this value when the `path` does not exist. Defaults to `undefined`. */
|
|
194
|
+
defaultValue?: any;
|
|
195
|
+
/** When peek is `undefined` or `false`, the current scope will automatically be
|
|
196
|
+
* subscribed to changes of any parts of the store being read. When `true`, no
|
|
197
|
+
* subscribers will be performed.
|
|
198
|
+
*/
|
|
199
|
+
peek?: boolean;
|
|
200
|
+
}): any;
|
|
201
|
+
isEmpty(...path: any): boolean;
|
|
202
|
+
count(...path: any): number;
|
|
203
|
+
/**
|
|
204
|
+
* Returns "undefined", "null", "boolean", "number", "string", "function", "array", "map" or "object"
|
|
205
|
+
*/
|
|
206
|
+
getType(...path: any): string;
|
|
207
|
+
/**
|
|
208
|
+
* Sets the Store value to the last given argument. Any earlier argument are a Store-path that is first
|
|
209
|
+
* resolved/created using `makeRef`.
|
|
210
|
+
*/
|
|
211
|
+
set(...pathAndValue: any): void;
|
|
212
|
+
/**
|
|
213
|
+
* Sets the `Store` to the given `mergeValue`, but without deleting any pre-existing
|
|
214
|
+
* items when a collection overwrites a similarly typed collection. This results in
|
|
215
|
+
* a deep merge.
|
|
216
|
+
*/
|
|
217
|
+
merge(mergeValue: any): void;
|
|
218
|
+
/**
|
|
219
|
+
* Sets the value for the store to `undefined`, which causes it to be omitted from the map (or array, if it's at the end)
|
|
220
|
+
*/
|
|
221
|
+
delete(...path: any): void;
|
|
222
|
+
/**
|
|
223
|
+
* Pushes a value to the end of the Array that is at the specified path in the store.
|
|
224
|
+
* If that Store path is `undefined`, and Array is created first.
|
|
225
|
+
* The last argument is the value to be added, any earlier arguments indicate the path.
|
|
226
|
+
*/
|
|
227
|
+
push(newValue: any): number;
|
|
228
|
+
/**
|
|
229
|
+
* [[`peek`]] the current value, pass it through `func`, and [[`set`]] the resulting
|
|
230
|
+
* value.
|
|
231
|
+
* @param func The function transforming the value.
|
|
232
|
+
*/
|
|
233
|
+
modify(func: (value: any) => any): void;
|
|
234
|
+
/**
|
|
235
|
+
* Return a `Store` deeper within the tree by resolving the given `path`,
|
|
236
|
+
* subscribing to every level.
|
|
237
|
+
* In case `undefined` is encountered while resolving the path, a newly
|
|
238
|
+
* created `Store` containing `undefined` is returned. In that case, the
|
|
239
|
+
* `Store`'s [[`isDetached`]] method will return `true`.
|
|
240
|
+
* In case something other than a collection is encountered, an error is thrown.
|
|
241
|
+
*/
|
|
242
|
+
ref(...path: any[]): Store;
|
|
243
|
+
/**
|
|
244
|
+
* Similar to `ref()`, but instead of returning `undefined`, new objects are created when
|
|
245
|
+
* a path does not exist yet. An error is still thrown when the path tries to index an invalid
|
|
246
|
+
* type.
|
|
247
|
+
* Unlike `ref`, `makeRef` does *not* subscribe to the path levels, as it is intended to be
|
|
248
|
+
* a write-only operation.
|
|
249
|
+
*/
|
|
250
|
+
makeRef(...path: any[]): Store;
|
|
251
|
+
/** @Internal */
|
|
252
|
+
_observe(): DatumType;
|
|
253
|
+
onEach(...pathAndFuncs: any): void;
|
|
254
|
+
/**
|
|
255
|
+
* Applies a filter/map function on each item within the `Store`'s collection,
|
|
256
|
+
* and reactively manages the returned `Map` `Store` to hold any results.
|
|
257
|
+
*
|
|
258
|
+
* @param func - Function that transform the given store into an output value or
|
|
259
|
+
* `undefined` in case this value should be skipped:
|
|
260
|
+
*
|
|
261
|
+
* @returns - A map `Store` with the values returned by `func` and the corresponding
|
|
262
|
+
* keys from the original map, array or object `Store`.
|
|
263
|
+
*
|
|
264
|
+
* When items disappear from the `Store` or are changed in a way that `func` depends
|
|
265
|
+
* upon, the resulting items are removed from the output `Store` as well. When multiple
|
|
266
|
+
* input items produce the same output keys, this may lead to unexpected results.
|
|
267
|
+
*/
|
|
268
|
+
map(func: (store: Store) => any): Store;
|
|
269
|
+
multiMap(func: (store: Store) => any): Store;
|
|
270
|
+
/**
|
|
271
|
+
* @returns Returns `true` when the `Store` was created by [[`ref`]]ing a path that
|
|
272
|
+
* does not exist.
|
|
273
|
+
*/
|
|
274
|
+
isDetached(): boolean;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Create a new DOM element.
|
|
278
|
+
* @param tag - The tag of the element to be created and optionally dot-separated class names. For example: `h1` or `p.intro.has_avatar`.
|
|
279
|
+
* @param rest - The other arguments are flexible and interpreted based on their types:
|
|
280
|
+
* - `string`: Used as textContent for the element.
|
|
281
|
+
* - `object`: Used as attributes/properties for the element. See `applyProp` on how the distinction is made.
|
|
282
|
+
* - `function`: The render function used to draw the scope of the element. This function gets its own `Scope`, so that if any `Store` it reads changes, it will redraw by itself.
|
|
283
|
+
* - `Store`: Presuming `tag` is `"input"`, `"textarea"` or `"select"`, create a two-way binding between this `Store` value and the input element. The initial value of the input will be set to the initial value of the `Store`. After that, the `Store` will be updated when the input changes.
|
|
284
|
+
* @example
|
|
285
|
+
* node('aside.editorial', 'Yada yada yada....', () => {
|
|
286
|
+
* node('a', {href: '/bio'}, () => {
|
|
287
|
+
* node('img.author', {src: '/me.jpg', alt: 'The author'})
|
|
288
|
+
* })
|
|
289
|
+
* })
|
|
290
|
+
*/
|
|
291
|
+
export declare function node(tag?: string | Element, ...rest: any[]): void;
|
|
292
|
+
/**
|
|
293
|
+
* Add a text node at the current Scope position.
|
|
294
|
+
*/
|
|
295
|
+
export declare function text(text: string): void;
|
|
296
|
+
/**
|
|
297
|
+
* Set properties and attributes for the containing DOM element. Doing it this way
|
|
298
|
+
* as opposed to setting them directly from node() allows changing them later on
|
|
299
|
+
* without recreating the element itself. Also, code can be more readable this way.
|
|
300
|
+
* Note that when a nested `observe()` is used, properties set this way do NOT
|
|
301
|
+
* automatically revert to their previous values.
|
|
302
|
+
*/
|
|
303
|
+
export declare function prop(prop: string, value: any): void;
|
|
304
|
+
export declare function prop(props: object): void;
|
|
305
|
+
/**
|
|
306
|
+
* Return the browser Element that `node()`s would be rendered to at this point.
|
|
307
|
+
* NOTE: Manually changing the DOM is not recommended in most cases. There is
|
|
308
|
+
* usually a better, declarative way. Although there are no hard guarantees on
|
|
309
|
+
* how your changes interact with Aberdeen, in most cases results will not be
|
|
310
|
+
* terribly surprising. Be careful within the parent element of onEach() though.
|
|
311
|
+
*/
|
|
312
|
+
export declare function getParentElement(): Element;
|
|
313
|
+
/**
|
|
314
|
+
* Register a function that is to be executed right before the current reactive scope
|
|
315
|
+
* disappears or redraws.
|
|
316
|
+
* @param clean - The function to be executed.
|
|
317
|
+
*/
|
|
318
|
+
export declare function clean(clean: (scope: Scope) => void): void;
|
|
319
|
+
/**
|
|
320
|
+
* Create a new reactive scope and execute the `func` within that scope. When
|
|
321
|
+
* `Store`s that the `func` reads are updated, only this scope will need to be refreshed,
|
|
322
|
+
* leaving the parent scope untouched.
|
|
323
|
+
*
|
|
324
|
+
* In case this function is called outside of a an existing scope, it will create a new
|
|
325
|
+
* top-level scope (a [[`Mount`]]) without a `parentElement`, meaning that aberdeen operations
|
|
326
|
+
* that create/modify DOM elements are not permitted.
|
|
327
|
+
* @param func - The function to be (repeatedly) executed within the newly created scope.
|
|
328
|
+
* @returns The newly created `Mount` object in case this is a top-level reactive scope.
|
|
329
|
+
* @example
|
|
330
|
+
* ```
|
|
331
|
+
* let store = new Store('John Doe')
|
|
332
|
+
* mount(document.body, () => {
|
|
333
|
+
* node('div.card', () => {
|
|
334
|
+
* node('input', {placeholder: 'Name'}, store)
|
|
335
|
+
* observe(() => {
|
|
336
|
+
* prop('class', {correct: store.get().length > 5})
|
|
337
|
+
* })
|
|
338
|
+
* })
|
|
339
|
+
* })
|
|
340
|
+
* ```
|
|
341
|
+
*/
|
|
342
|
+
/**
|
|
343
|
+
* Reactively run a function, meaning the function will rerun when any `Store` that was read
|
|
344
|
+
* during its execution is updated.
|
|
345
|
+
* Calls to `observe` can be nested, such that changes to `Store`s read by the inner function do
|
|
346
|
+
* no cause the outer function to rerun.
|
|
347
|
+
*
|
|
348
|
+
* @param func - The function to be (repeatedly) executed.
|
|
349
|
+
* @example
|
|
350
|
+
* ```
|
|
351
|
+
* let number = new Store(0)
|
|
352
|
+
* let doubled = new Store()
|
|
353
|
+
* setInterval(() => number.set(0|Math.random()*100)), 1000)
|
|
354
|
+
*
|
|
355
|
+
* observe(() => {
|
|
356
|
+
* doubled.set(number.get() * 2)
|
|
357
|
+
* })
|
|
358
|
+
*
|
|
359
|
+
* observe(() => {
|
|
360
|
+
* console.log(doubled.get())
|
|
361
|
+
* })
|
|
362
|
+
*/
|
|
363
|
+
export declare function observe(func: () => void): void;
|
|
364
|
+
/**
|
|
365
|
+
* Like [[`observe`]], but allow the function to create DOM elements using [[`node`]].
|
|
366
|
+
|
|
367
|
+
* @param func - The function to be (repeatedly) executed, possibly adding DOM elements to `parentElement`.
|
|
368
|
+
* @param parentElement - A DOM element that will be used as the parent element for calls to `node`.
|
|
369
|
+
*
|
|
370
|
+
* @example
|
|
371
|
+
* ```
|
|
372
|
+
* let store = new Store(0)
|
|
373
|
+
* setInterval(() => store.modify(v => v+1), 1000)
|
|
374
|
+
*
|
|
375
|
+
* mount(document.body, () => {
|
|
376
|
+
* node('h2', `${store.get()} seconds have passed`)
|
|
377
|
+
* })
|
|
378
|
+
* ```
|
|
379
|
+
*
|
|
380
|
+
* An example nesting [[`observe`]] within `mount`:
|
|
381
|
+
* ```
|
|
382
|
+
* let selected = new Store(0)
|
|
383
|
+
* let colors = new Store(new Map())
|
|
384
|
+
*
|
|
385
|
+
* mount(document.body, () => {
|
|
386
|
+
* // This function will never rerun (as it does not read any `Store`s)
|
|
387
|
+
* node('button', '<<', {click: () => selected.modify(n => n-1)})
|
|
388
|
+
* node('button', '>>', {click: () => selected.modify(n => n+1)})
|
|
389
|
+
*
|
|
390
|
+
* observe(() => {
|
|
391
|
+
* // This will rerun whenever `selected` changes, recreating the <h2> and <input>.
|
|
392
|
+
* node('h2', '#'+selected.get())
|
|
393
|
+
* node('input', {type: 'color', value: '#ffffff'}, colors.ref(selected.get()))
|
|
394
|
+
* })
|
|
395
|
+
*
|
|
396
|
+
* observe(() => {
|
|
397
|
+
* // This function will rerun when `selected` or the selected color changes.
|
|
398
|
+
* // It will change the <body> background-color.
|
|
399
|
+
* prop({style: {backgroundColor: colors.get(selected.get()) || 'white'}})
|
|
400
|
+
* })
|
|
401
|
+
* })
|
|
402
|
+
* ```
|
|
403
|
+
*/
|
|
404
|
+
export declare function mount(parentElement: Element | undefined, func: () => void): void;
|
|
405
|
+
/** Runs the given function, while not subscribing the current scope when reading [[`Store`]] values.
|
|
406
|
+
*
|
|
407
|
+
* @param func Function to be executed immediately.
|
|
408
|
+
* @returns Whatever `func()` returns.
|
|
409
|
+
* @example
|
|
410
|
+
* ```
|
|
411
|
+
* import {Store, peek, text} from aberdeen
|
|
412
|
+
*
|
|
413
|
+
* let store = new Store(['a', 'b', 'c'])
|
|
414
|
+
*
|
|
415
|
+
* mount(document.body, () => {
|
|
416
|
+
* // Prevent rerender when store changes
|
|
417
|
+
* peek(() => {
|
|
418
|
+
* text(`Store has ${store.count()} elements, and the first is ${store.get(0)}`)
|
|
419
|
+
* })
|
|
420
|
+
* })
|
|
421
|
+
* ```
|
|
422
|
+
*
|
|
423
|
+
* In the above example `store.get(0)` could be replaced with `store.peek(0)` to achieve the
|
|
424
|
+
* same result without `peek()` wrapping everything. There is no non-subscribing equivalent
|
|
425
|
+
* for `count()` however.
|
|
426
|
+
*/
|
|
427
|
+
export declare function peek<T>(func: () => T): T;
|
|
428
|
+
export {};
|