aberdeen 1.4.3 → 1.6.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/src/route.ts CHANGED
@@ -170,9 +170,9 @@ export function go(target: RouteTarget, nav: NavType = "go"): void {
170
170
  * @param target Same as for {@link go}, but merged into the current route instead deleting all state.
171
171
  */
172
172
  export function push(target: RouteTarget): void {
173
- let copy = clone(unproxy(current));
174
- merge(copy, targetToPartial(target));
175
- go(copy);
173
+ const c = clone(unproxy(current));
174
+ merge(c, targetToPartial(target));
175
+ go(c);
176
176
  }
177
177
 
178
178
  /**
@@ -1,45 +0,0 @@
1
- # Prediction (Optimistic UI)
2
-
3
- Apply UI changes immediately, auto-revert when server responds.
4
-
5
- ## API
6
-
7
- ```typescript
8
- import { applyPrediction, applyCanon } from 'aberdeen/prediction';
9
- ```
10
-
11
- ### `applyPrediction(func)`
12
- Runs function and records all proxy changes as a "prediction".
13
- Returns a `Patch` to use as `dropPatches` later, when the server responds.
14
-
15
- ### `applyCanon(func?, dropPatches?)`
16
- 1. Reverts all predictions
17
- 2. Runs `func` (typically applies server data)
18
- 3. Drops specified patches
19
- 4. Re-applies remaining predictions that still apply cleanly
20
-
21
- ## Example
22
- ```typescript
23
- async function toggleTodo(todo: Todo) {
24
- // Optimistic update
25
- const patch = applyPrediction(() => {
26
- todo.done = !todo.done;
27
- });
28
-
29
- try {
30
- const data = await api.updateTodo(todo.id, { done: todo.done });
31
-
32
- // Server responded - apply canonical state
33
- applyCanon(() => {
34
- Object.assign(todo, data);
35
- }, [patch]);
36
- } catch {
37
- // On error, just drop the prediction to revert
38
- applyCanon(undefined, [patch]);
39
- }
40
- }
41
- ```
42
-
43
- ## When to Use
44
- - When you want immediate UI feedback for user actions for which a server is authoritative.
45
- - As doing this manually for each such case is tedious, this should usually be integrated into the data updating/fetching layer.
@@ -1,81 +0,0 @@
1
- # Routing and Dispatching
2
-
3
- ## Router (`aberdeen/route`)
4
-
5
- The `current` object is a reactive proxy of the current URL state.
6
-
7
- ### Properties
8
- | Property | Type | Description |
9
- |----------|------|-------------|
10
- | `path` | `string` | Normalized path (e.g., `/users/123`) |
11
- | `p` | `string[]` | Path segments (e.g., `['users', '123']`) |
12
- | `search` | `Record<string,string>` | Query parameters |
13
- | `hash` | `string` | URL hash including `#` |
14
- | `state` | `Record<string,any>` | JSON-compatible state data |
15
- | `nav` | `NavType` | How we got here: `load`, `back`, `forward`, `go`, `push` |
16
- | `depth` | `number` | Navigation stack depth (starts at 1) |
17
-
18
- ### Navigation Functions
19
- ```typescript
20
- import * as route from 'aberdeen/route';
21
-
22
- route.go('/users/42'); // Navigate to new URL
23
- route.go({ p: ['users', 42], hash: 'top' }); // Object form
24
- route.push({ search: { tab: 'feed' } }); // Merge into current route
25
- route.back(); // Go back in history
26
- route.back({ path: '/home' }); // Back to matching entry, or replace
27
- route.up(); // Go up one path level
28
- route.persistScroll(); // Save/restore scroll position
29
- ```
30
-
31
- ### Reactive Routing Example
32
- ```typescript
33
- import * as route from 'aberdeen/route';
34
-
35
- $(() => {
36
- const [section, id] = route.current.p;
37
- if (section === 'users') drawUser(id);
38
- else if (section === 'settings') drawSettings();
39
- else drawHome();
40
- });
41
- ```
42
-
43
- ## Dispatcher (`aberdeen/dispatcher`)
44
-
45
- Type-safe path segment matching for complex routing.
46
-
47
- ```typescript
48
- import { Dispatcher, matchRest } from 'aberdeen/dispatcher';
49
- import * as route from 'aberdeen/route';
50
-
51
- const d = new Dispatcher();
52
-
53
- // Literal string match
54
- d.addRoute('home', () => drawHome());
55
-
56
- // Number extraction (uses built-in Number function)
57
- d.addRoute('user', Number, (id) => drawUser(id));
58
-
59
- // String extraction
60
- d.addRoute('user', Number, 'post', String, (userId, postId) => {
61
- drawPost(userId, postId);
62
- });
63
-
64
- // Rest of path as array
65
- d.addRoute('search', matchRest, (terms: string[]) => {
66
- performSearch(terms);
67
- });
68
-
69
- // Dispatch in reactive scope
70
- $(() => {
71
- if (!d.dispatch(route.current.p)) {
72
- draw404();
73
- }
74
- });
75
- ```
76
-
77
- ### Custom Matchers
78
- ```typescript
79
- const uuid = (s: string) => /^[0-9a-f-]{36}$/.test(s) ? s : matchFailed;
80
- d.addRoute('item', uuid, (id) => drawItem(id));
81
- ```
@@ -1,52 +0,0 @@
1
- # Transitions
2
-
3
- Animate elements entering/leaving the DOM via the `create` and `destroy` properties.
4
-
5
- **Important:** Transitions only trigger for **top-level** elements of a scope being (re-)run. Deeply nested elements drawn as part of a larger redraw do not trigger transitions.
6
-
7
- ## Built-in Transitions
8
-
9
- ```typescript
10
- import { grow, shrink } from 'aberdeen/transitions';
11
-
12
- // Apply to individual elements
13
- $('div create=', grow, 'destroy=', shrink, '#Animated');
14
-
15
- // Common with onEach for list animations
16
- onEach(items, item => {
17
- $('li create=', grow, 'destroy=', shrink, `#${item.text}`);
18
- });
19
- ```
20
-
21
- - `grow`: Scales element from 0 to full size with margin animation
22
- - `shrink`: Scales element to 0 and removes from DOM after animation
23
-
24
- Both detect horizontal flex containers and animate width instead of height.
25
-
26
- ## CSS-Based Transitions
27
-
28
- For custom transitions, use CSS class strings (dot-separated):
29
- ```typescript
30
- const fadeStyle = insertCss({
31
- transition: 'all 0.3s ease-out',
32
- '&.hidden': { opacity: 0, transform: 'translateY(-10px)' }
33
- });
34
-
35
- // Class added briefly on create (removed after layout)
36
- // Class added on destroy (element removed after 2s delay)
37
- $('div', fadeStyle, 'create=.hidden destroy=.hidden#Fading element');
38
- ```
39
-
40
- ## Custom Transition Functions
41
-
42
- For full control, pass functions. For `destroy`, your function must remove the element:
43
- ```typescript
44
- $('div create=', (el: HTMLElement) => {
45
- // Animate on mount - element already in DOM
46
- el.animate([{ opacity: 0 }, { opacity: 1 }], 300);
47
- }, 'destroy=', (el: HTMLElement) => {
48
- // YOU must remove the element when done
49
- el.animate([{ opacity: 1 }, { opacity: 0 }], 300)
50
- .finished.then(() => el.remove());
51
- }, '#Custom animated');
52
- ```