aberdeen 0.4.0 → 0.5.0
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 +1 -1
- package/README.md +134 -96
- package/dist/aberdeen.d.ts +637 -528
- package/dist/aberdeen.js +1144 -1957
- package/dist/aberdeen.js.map +11 -1
- package/dist/helpers/reverseSortedSet.d.ts +91 -0
- package/dist/prediction.d.ts +7 -3
- package/dist/prediction.js +77 -93
- package/dist/prediction.js.map +10 -1
- package/dist/route.d.ts +36 -19
- package/dist/route.js +131 -158
- package/dist/route.js.map +10 -1
- package/dist/transitions.js +30 -70
- package/dist/transitions.js.map +10 -1
- package/dist-min/aberdeen.js +7 -2
- package/dist-min/aberdeen.js.map +11 -1
- package/dist-min/prediction.js +4 -2
- package/dist-min/prediction.js.map +10 -1
- package/dist-min/route.js +4 -2
- package/dist-min/route.js.map +10 -1
- package/dist-min/transitions.js +4 -2
- package/dist-min/transitions.js.map +10 -1
- package/package.json +20 -23
- package/src/aberdeen.ts +1918 -1814
- package/src/helpers/reverseSortedSet.ts +188 -0
- package/src/prediction.ts +14 -9
- package/src/route.ts +81 -64
- package/src/transitions.ts +1 -14
- package/dist-min/aberdeen.d.ts +0 -601
- package/dist-min/prediction.d.ts +0 -29
- package/dist-min/route.d.ts +0 -30
- package/dist-min/transitions.d.ts +0 -18
package/LICENSE.txt
CHANGED
package/README.md
CHANGED
|
@@ -1,130 +1,169 @@
|
|
|
1
1
|
A TypeScript/JavaScript library for quickly building performant declarative user interfaces *without* the use of a virtual DOM.
|
|
2
2
|
|
|
3
|
-
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
|
|
4
|
-
|
|
3
|
+
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 *proxied* JavaScript objects. They can hold anything, from simple values to complex and deeply nested data structures, in which case user-interface functions can (automatically) subscribe to just the parts they depend upon.
|
|
5
4
|
|
|
6
5
|
## Why use Aberdeen?
|
|
7
6
|
|
|
8
7
|
- It provides a flexible and simple to understand model for reactive user-interface building.
|
|
9
8
|
- It allows you to express user-interfaces in plain JavaScript (or TypeScript) in an easy to read form, without (JSX-like) compilation steps.
|
|
10
|
-
- It's fast, as it doesn't use a *virtual DOM* and only reruns small pieces of code in response to updated data.
|
|
11
|
-
- It
|
|
12
|
-
- It
|
|
9
|
+
- It's fast, as it doesn't use a *virtual DOM* and only reruns small pieces of code, redrawing minimal pieces of the UI, in response to updated data.
|
|
10
|
+
- It makes displaying and updating sorted lists very easy and very fast.
|
|
11
|
+
- It's tiny, at about 5kb (minimized and gzipped) and without any run-time dependencies.
|
|
12
|
+
- It comes with batteries included:
|
|
13
13
|
- Client-side routing.
|
|
14
|
-
-
|
|
15
|
-
-
|
|
14
|
+
- Revertible patches, for optimistic user-interface updates.
|
|
15
|
+
- Component-local CSS generator.
|
|
16
|
+
- Helper functions for reactively working with data, such as for deriving, (multi)mapping, filtering, partitioning and counting.
|
|
17
|
+
- A couple of add/remove transition effects, to get you started.
|
|
16
18
|
|
|
17
|
-
##
|
|
19
|
+
## Why *not* use Aberdeen?
|
|
18
20
|
|
|
19
|
-
-
|
|
20
|
-
-
|
|
21
|
-
- [List example demo](https://vanviegen.github.io/aberdeen/examples/list/) - [Source](https://github.com/vanviegen/aberdeen/tree/master/examples/list)
|
|
22
|
-
- [Routing example demo](https://vanviegen.github.io/aberdeen/examples/router/) - [Source](https://github.com/vanviegen/aberdeen/tree/master/examples/router)
|
|
21
|
+
- There are not many of us -Aberdeen developers- yet, so don't expect terribly helpful StackOver/AI answers.
|
|
22
|
+
- You'd have to code things yourself, instead of duct-taping together a gazillion React ecosystem libraries.
|
|
23
23
|
|
|
24
|
+
## Example code
|
|
24
25
|
|
|
25
|
-
To get a quick impression of what Aberdeen code looks like,
|
|
26
|
+
To get a quick impression of what Aberdeen code looks like, below is a Tic-tac-toe app with undo history. If you're reading this on [the official website](https://vanviegen.github.io/aberdeen/README/) you should see a working demo below the code, and an 'edit' button in the top-right corner of the code, to play around.
|
|
26
27
|
|
|
27
28
|
```javascript
|
|
28
|
-
import {$,
|
|
29
|
+
import {$, proxy, onEach, insertCss, observe} from "aberdeen";
|
|
29
30
|
|
|
30
|
-
//
|
|
31
|
-
const squares = new Store([]) // eg. ['X', undefined, 'O', 'X']
|
|
32
|
-
const history = new Store([[]]) // eg. [[], [undefined, undefined, undefined, X], ...]
|
|
33
|
-
const historyPos = new Store(null) // set while 'time traveling' our undo history
|
|
31
|
+
// Helper functions
|
|
34
32
|
|
|
35
|
-
|
|
36
|
-
const
|
|
37
|
-
|
|
33
|
+
function calculateWinner(board) {
|
|
34
|
+
const lines = [
|
|
35
|
+
[0, 1, 2], [3, 4, 5], [6, 7, 8], // horizontal
|
|
36
|
+
[0, 3, 6], [1, 4, 7], [2, 5, 8], // vertical
|
|
37
|
+
[0, 4, 8], [2, 4, 6] // diagonal
|
|
38
|
+
];
|
|
39
|
+
for (const [a, b, c] of lines) {
|
|
40
|
+
if (board[a] && board[a] === board[b] && board[a] === board[c]) {
|
|
41
|
+
return board[a];
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
38
45
|
|
|
39
|
-
|
|
46
|
+
function getCurrentMarker(board) {
|
|
47
|
+
return board.filter(v => v).length % 2 ? "O" : "X";
|
|
48
|
+
}
|
|
40
49
|
|
|
41
|
-
function
|
|
42
|
-
|
|
43
|
-
let value = squares(position).get()
|
|
44
|
-
if (value) $({text: value})
|
|
45
|
-
else $({click: () => fillSquare(position)})
|
|
46
|
-
})
|
|
50
|
+
function getBoard(history) {
|
|
51
|
+
return history.boards[history.current];
|
|
47
52
|
}
|
|
48
53
|
|
|
49
|
-
function
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
function markSquare(history, position) {
|
|
55
|
+
const board = getBoard(history);
|
|
56
|
+
|
|
57
|
+
// Don't allow markers when we already have a winner
|
|
58
|
+
if (calculateWinner(board)) return;
|
|
59
|
+
|
|
60
|
+
// Copy the current board, and insert the marker into it
|
|
61
|
+
const newBoard = board.slice();
|
|
62
|
+
newBoard[position] = getCurrentMarker(board);
|
|
63
|
+
|
|
64
|
+
// Truncate any future states, and write a new future
|
|
65
|
+
history.current++;
|
|
66
|
+
history.boards.length = history.current;
|
|
67
|
+
history.boards.push(newBoard);
|
|
57
68
|
}
|
|
58
69
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
70
|
+
// Define component-local CSS, which we'll utilize in the drawBoard function.
|
|
71
|
+
// Of course, you can use any other styling solution instead, if you prefer.
|
|
72
|
+
|
|
73
|
+
const boardStyle = insertCss({
|
|
74
|
+
display: 'grid',
|
|
75
|
+
gap: '0.5em',
|
|
76
|
+
gridTemplateColumns: '1fr 1fr 1fr',
|
|
77
|
+
'> *': {
|
|
78
|
+
width: '2em',
|
|
79
|
+
height: '2em',
|
|
80
|
+
padding: 0,
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// UI drawing functions.
|
|
85
|
+
|
|
86
|
+
function drawBoard(history) {
|
|
87
|
+
$('div', boardStyle, () => {
|
|
88
|
+
for(let pos=0; pos<9; pos++) {
|
|
89
|
+
$('button.square', () => {
|
|
90
|
+
let marker = getBoard(history)[pos];
|
|
91
|
+
if (marker) {
|
|
92
|
+
$({ text: marker });
|
|
93
|
+
} else {
|
|
94
|
+
$({ click: () => markSquare(history, pos) });
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
})
|
|
78
99
|
}
|
|
79
100
|
|
|
80
|
-
|
|
101
|
+
function drawStatusMessage(history) {
|
|
102
|
+
$('h4', () => {
|
|
103
|
+
// Reruns whenever observable data read by calculateWinner or getCurrentMarker changes
|
|
104
|
+
const board = getBoard(history);
|
|
105
|
+
const winner = calculateWinner(board);
|
|
106
|
+
if (winner) {
|
|
107
|
+
$(`:Winner: ${winner}!`);
|
|
108
|
+
} else if (board.filter(square=>square).length === 9) {
|
|
109
|
+
$(`:It's a draw...`);
|
|
110
|
+
} else {
|
|
111
|
+
$(`:Current player: ${getCurrentMarker(board)}`);
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
81
115
|
|
|
82
|
-
function
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
116
|
+
function drawTurns(history) {
|
|
117
|
+
$('div:Select a turn:')
|
|
118
|
+
// Reactively iterate all (historic) board versions
|
|
119
|
+
onEach(history.boards, (_, index) => {
|
|
120
|
+
$('button', {
|
|
121
|
+
// A text node:
|
|
122
|
+
text: index,
|
|
123
|
+
// Conditional css class:
|
|
124
|
+
".outline": observe(() => history.current != index),
|
|
125
|
+
// Inline styles:
|
|
126
|
+
$marginRight: "0.5em",
|
|
127
|
+
$marginTop: "0.5em",
|
|
128
|
+
// Event listener:
|
|
129
|
+
click: () => history.current = index,
|
|
130
|
+
});
|
|
131
|
+
});
|
|
98
132
|
}
|
|
99
133
|
|
|
100
|
-
function
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
134
|
+
function drawMain() {
|
|
135
|
+
// Define our state, wrapped by an observable proxy
|
|
136
|
+
const history = proxy({
|
|
137
|
+
boards: [[]], // eg. [[], [undefined, 'O', undefined, 'X'], ...]
|
|
138
|
+
current: 0, // indicates which of the boards is currently showing
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
$('main.row', () => {
|
|
142
|
+
$('div.box', () => drawBoard(history));
|
|
143
|
+
$('div.box', {$flex: 1}, () => {
|
|
144
|
+
drawStatusMessage(history);
|
|
145
|
+
drawTurns(history);
|
|
146
|
+
});
|
|
147
|
+
});
|
|
111
148
|
}
|
|
112
149
|
|
|
113
|
-
// Fire it up!
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
$('.game', () => {
|
|
117
|
-
$('.game-board', drawBoard)
|
|
118
|
-
$('.game-info', drawInfo)
|
|
119
|
-
})
|
|
120
|
-
})
|
|
150
|
+
// Fire it up! Mounts on document.body by default..
|
|
151
|
+
|
|
152
|
+
drawMain();
|
|
121
153
|
```
|
|
122
154
|
|
|
155
|
+
Some further examples:
|
|
156
|
+
|
|
157
|
+
- [Input example demo](https://vanviegen.github.io/aberdeen/examples/input/) - [Source](https://github.com/vanviegen/aberdeen/tree/master/examples/input)
|
|
158
|
+
- [List example demo](https://vanviegen.github.io/aberdeen/examples/list/) - [Source](https://github.com/vanviegen/aberdeen/tree/master/examples/list)
|
|
159
|
+
- [Routing example demo](https://vanviegen.github.io/aberdeen/examples/router/) - [Source](https://github.com/vanviegen/aberdeen/tree/master/examples/router)
|
|
160
|
+
- [JS Framework Benchmark demo](https://vanviegen.github.io/aberdeen/examples/js-framework-benchmark/) - [Source](https://github.com/vanviegen/aberdeen/tree/master/examples/js-framework-benchmark)
|
|
123
161
|
|
|
124
|
-
## Reference documentation
|
|
125
162
|
|
|
126
|
-
|
|
163
|
+
## Documentation
|
|
127
164
|
|
|
165
|
+
- [Tutorial](https://vanviegen.github.io/aberdeen/Tutorial/)
|
|
166
|
+
- [Reference documentation](https://vanviegen.github.io/aberdeen/modules.html)
|
|
128
167
|
|
|
129
168
|
## Roadmap
|
|
130
169
|
|
|
@@ -132,8 +171,7 @@ https://vanviegen.github.io/aberdeen/modules.html
|
|
|
132
171
|
- [x] A better alternative for scheduleTask.
|
|
133
172
|
- [x] A simple router.
|
|
134
173
|
- [x] Optimistic client-side predictions.
|
|
135
|
-
- [
|
|
136
|
-
- [
|
|
174
|
+
- [x] Performance profiling and tuning regarding lists.
|
|
175
|
+
- [x] Support for (component local) CSS
|
|
137
176
|
- [ ] Architecture document.
|
|
138
177
|
- [ ] SVG support.
|
|
139
|
-
- [ ] Performance profiling and tuning regarding lists.
|