aberdeen 1.17.0 → 2.0.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/dist/src/aberdeen.d.ts +928 -944
- package/dist/src/aberdeen.js +1693 -1704
- package/dist/src/aberdeen.js.map +3 -3
- package/dist/src/index.d.ts +12 -0
- package/dist/src/index.js +11 -0
- package/dist/src/index.js.map +10 -0
- package/dist/src/prediction.d.ts +7 -4
- package/dist/src/prediction.js +18 -23
- package/dist/src/prediction.js.map +3 -3
- package/dist/src/route.d.ts +112 -99
- package/dist/src/route.js +254 -254
- package/dist/src/route.js.map +3 -3
- package/dist/src/server-dom.d.ts +158 -0
- package/dist/src/server-dom.js +458 -0
- package/dist/src/server-dom.js.map +10 -0
- package/dist/src/server.d.ts +55 -0
- package/dist/src/server.js +25 -0
- package/dist/src/server.js.map +10 -0
- package/dist/src/transitions.js +7 -4
- package/dist/src/transitions.js.map +3 -3
- package/dist/tests/environment.d.ts +24 -0
- package/dist/tests/{fakedom.js → environment.js} +239 -288
- package/dist/tests/environment.js.map +11 -0
- package/dist/tests/helpers.d.ts +15 -3
- package/dist/tests/helpers.js +277 -306
- package/dist/tests/helpers.js.map +6 -5
- package/dist-docs/Tutorial/index.html +30 -30
- package/dist-docs/aberdeen/Aberdeen/index.html +350 -0
- package/dist-docs/aberdeen/InitOptions/index.html +4 -0
- package/dist-docs/aberdeen/KeyToString/index.html +2 -0
- package/dist-docs/aberdeen/PromiseProxy/index.html +6 -6
- package/dist-docs/aberdeen/SortKeyType/index.html +2 -0
- package/dist-docs/aberdeen/TargetType/index.html +2 -0
- package/dist-docs/aberdeen/ValueRef/index.html +2 -0
- package/dist-docs/aberdeen/WindowLike/index.html +5 -0
- package/dist-docs/aberdeen/{clone → createA}/index.html +10 -5
- package/dist-docs/aberdeen/index.html +13 -54
- package/dist-docs/assets/aberdeen/aberdeen.d.ts +928 -944
- package/dist-docs/assets/aberdeen/aberdeen.js +1693 -1704
- package/dist-docs/assets/aberdeen/aberdeen.js.map +3 -3
- package/dist-docs/assets/aberdeen/index.d.ts +12 -0
- package/dist-docs/assets/aberdeen/index.js +11 -0
- package/dist-docs/assets/aberdeen/index.js.map +10 -0
- package/dist-docs/assets/aberdeen/prediction.d.ts +7 -4
- package/dist-docs/assets/aberdeen/prediction.js +18 -23
- package/dist-docs/assets/aberdeen/prediction.js.map +3 -3
- package/dist-docs/assets/aberdeen/route.d.ts +112 -99
- package/dist-docs/assets/aberdeen/route.js +254 -254
- package/dist-docs/assets/aberdeen/route.js.map +3 -3
- package/dist-docs/assets/aberdeen/server-dom.d.ts +158 -0
- package/dist-docs/assets/aberdeen/server-dom.js +458 -0
- package/dist-docs/assets/aberdeen/server-dom.js.map +10 -0
- package/dist-docs/assets/aberdeen/server.d.ts +55 -0
- package/dist-docs/assets/aberdeen/server.js +25 -0
- package/dist-docs/assets/aberdeen/server.js.map +10 -0
- package/dist-docs/assets/aberdeen/transitions.js +7 -4
- package/dist-docs/assets/aberdeen/transitions.js.map +3 -3
- package/dist-docs/assets/navigation.js +1 -1
- package/dist-docs/assets/search.js +1 -1
- package/dist-docs/dispatcher/Dispatcher/index.html +5 -6
- package/dist-docs/dispatcher/MATCH_FAILED/index.html +2 -2
- package/dist-docs/dispatcher/MATCH_REST/index.html +2 -2
- package/dist-docs/dispatcher/index.html +2 -2
- package/dist-docs/hierarchy.html +1 -1
- package/dist-docs/index-1/index.html +2 -0
- package/dist-docs/index.html +2 -2
- package/dist-docs/media/CHANGELOG.md +14 -2
- package/dist-docs/modules.html +1 -1
- package/dist-docs/prediction/applyCanon/index.html +4 -3
- package/dist-docs/prediction/applyPrediction/index.html +4 -3
- package/dist-docs/prediction/index.html +2 -2
- package/dist-docs/route/Route/index.html +9 -9
- package/dist-docs/route/RouteApi/index.html +60 -0
- package/dist-docs/route/index.html +6 -15
- package/dist-docs/route/init/index.html +5 -0
- package/dist-docs/server/RenderToStringOptions/index.html +6 -0
- package/dist-docs/server/RenderToStringResult/index.html +6 -0
- package/dist-docs/server/index.html +4 -0
- package/dist-docs/server/renderToString/index.html +6 -0
- package/dist-docs/sitemap.xml +51 -155
- package/dist-docs/transitions/grow/index.html +2 -2
- package/dist-docs/transitions/index.html +2 -2
- package/dist-docs/transitions/shrink/index.html +2 -2
- package/package.json +17 -7
- package/skill/SKILL.md +28 -28
- package/skill/aberdeen.md +471 -3448
- package/skill/dispatcher.md +6 -16
- package/skill/prediction.md +17 -5
- package/skill/route.md +95 -77
- package/skill/transitions.md +3 -3
- package/src/aberdeen.ts +1226 -740
- package/src/index.ts +13 -0
- package/src/prediction.ts +25 -24
- package/src/route.ts +192 -142
- package/src/server-dom.ts +508 -0
- package/src/server.ts +74 -0
- package/src/transitions.ts +9 -3
- package/dist/tests/fakedom.d.ts +0 -9
- package/dist/tests/fakedom.js.map +0 -10
- package/dist-docs/aberdeen/A/index.html +0 -115
- package/dist-docs/aberdeen/CUSTOM_DUMP/index.html +0 -7
- package/dist-docs/aberdeen/NO_COPY/index.html +0 -2
- package/dist-docs/aberdeen/OPAQUE/index.html +0 -12
- package/dist-docs/aberdeen/clean/index.html +0 -11
- package/dist-docs/aberdeen/copy/index.html +0 -22
- package/dist-docs/aberdeen/count/index.html +0 -7
- package/dist-docs/aberdeen/cssVars/index.html +0 -11
- package/dist-docs/aberdeen/darkMode/index.html +0 -9
- package/dist-docs/aberdeen/default/index.html +0 -341
- package/dist-docs/aberdeen/derive/index.html +0 -18
- package/dist-docs/aberdeen/disableCreateDestroy/index.html +0 -6
- package/dist-docs/aberdeen/dump/index.html +0 -11
- package/dist-docs/aberdeen/insertCss/index.html +0 -30
- package/dist-docs/aberdeen/insertGlobalCss/index.html +0 -19
- package/dist-docs/aberdeen/invertString/index.html +0 -13
- package/dist-docs/aberdeen/isEmpty/index.html +0 -12
- package/dist-docs/aberdeen/map/index.html +0 -26
- package/dist-docs/aberdeen/merge/index.html +0 -11
- package/dist-docs/aberdeen/mount/index.html +0 -17
- package/dist-docs/aberdeen/multiMap/index.html +0 -28
- package/dist-docs/aberdeen/onEach/index.html +0 -19
- package/dist-docs/aberdeen/partition/index.html +0 -36
- package/dist-docs/aberdeen/peek/index.html +0 -40
- package/dist-docs/aberdeen/proxy/index.html +0 -35
- package/dist-docs/aberdeen/ref/index.html +0 -13
- package/dist-docs/aberdeen/runQueue/index.html +0 -13
- package/dist-docs/aberdeen/setErrorHandler/index.html +0 -16
- package/dist-docs/aberdeen/setSpacingCssVars/index.html +0 -8
- package/dist-docs/aberdeen/unmountAll/index.html +0 -5
- package/dist-docs/aberdeen/unproxy/index.html +0 -11
- package/dist-docs/route/back/index.html +0 -4
- package/dist-docs/route/current/index.html +0 -2
- package/dist-docs/route/go/index.html +0 -14
- package/dist-docs/route/interceptLinks/index.html +0 -8
- package/dist-docs/route/matchCurrent/index.html +0 -10
- package/dist-docs/route/persistScroll/index.html +0 -6
- package/dist-docs/route/push/index.html +0 -6
- package/dist-docs/route/setLog/index.html +0 -3
- package/dist-docs/route/up/index.html +0 -5
package/dist/src/aberdeen.d.ts
CHANGED
|
@@ -1,961 +1,945 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* Normally, changes to observed data sources (like proxied objects or arrays)
|
|
5
|
-
* are processed asynchronously in a batch after a brief timeout (0ms). This function
|
|
6
|
-
* allows you to bypass the timeout and process the update queue immediately.
|
|
7
|
-
*
|
|
8
|
-
* This can be useful in specific scenarios where you need the DOM to be updated
|
|
9
|
-
* synchronously.
|
|
10
|
-
*
|
|
11
|
-
* This function is re-entrant, meaning it is safe to call `runQueue` from within
|
|
12
|
-
* a function that is itself being executed as part of an update cycle triggered
|
|
13
|
-
* by a previous (or the same) `runQueue` call.
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```typescript
|
|
17
|
-
* const $data = A.proxy("before");
|
|
18
|
-
*
|
|
19
|
-
* A('#', $data);
|
|
20
|
-
* console.log(1, document.body.innerHTML); // before
|
|
21
|
-
*
|
|
22
|
-
* // Make an update that should cause the DOM to change.
|
|
23
|
-
* $data.value = "after";
|
|
24
|
-
*
|
|
25
|
-
* // Normally, the DOM update would happen after a timeout.
|
|
26
|
-
* // But this causes an immediate update:
|
|
27
|
-
* A.runQueue();
|
|
28
|
-
*
|
|
29
|
-
* console.log(2, document.body.innerHTML); // after
|
|
30
|
-
* ```
|
|
31
|
-
*/
|
|
32
|
-
export declare function runQueue(): void;
|
|
33
|
-
/**
|
|
34
|
-
* Creates a new string that has the opposite sort order compared to the input string.
|
|
35
|
-
*
|
|
36
|
-
* This is achieved by flipping the bits of each character code in the input string.
|
|
37
|
-
* The resulting string is intended for use as a sort key, particularly with the
|
|
38
|
-
* `makeKey` function in {@link onEach}, to achieve a descending sort order.
|
|
39
|
-
*
|
|
40
|
-
* **Warning:** The output string will likely contain non-printable characters or
|
|
41
|
-
* appear as gibberish and should not be displayed to the user.
|
|
42
|
-
*
|
|
43
|
-
* @example
|
|
44
|
-
* ```typescript
|
|
45
|
-
* const $users = A.proxy([
|
|
46
|
-
* { id: 1, name: 'Charlie', score: 95 },
|
|
47
|
-
* { id: 2, name: 'Alice', score: 100 },
|
|
48
|
-
* { id: 3, name: 'Bob', score: 90 },
|
|
49
|
-
* ]);
|
|
50
|
-
*
|
|
51
|
-
* A.onEach($users, ($user) => {
|
|
52
|
-
* A(`p#${$user.name}: ${$user.score}`);
|
|
53
|
-
* }, ($user) => A.invertString($user.name)); // Reverse alphabetic order
|
|
54
|
-
* ```
|
|
55
|
-
*
|
|
56
|
-
* @param input The string whose sort order needs to be inverted.
|
|
57
|
-
* @returns A new string that will sort in the reverse order of the input string.
|
|
58
|
-
* @see {@link onEach} for usage with sorting.
|
|
59
|
-
*/
|
|
60
|
-
export declare function invertString(input: string): string;
|
|
61
|
-
export declare function onEach<K, T>(target: Map<K, undefined | T>, render: (value: T, key: K) => void, makeKey?: (value: T, key: K) => SortKeyType): void;
|
|
62
|
-
export declare function onEach<T>(target: Set<T>, render: (value: T) => void, makeKey?: (value: T) => SortKeyType): void;
|
|
63
|
-
export declare function onEach<T>(target: ReadonlyArray<undefined | T>, render: (value: T, index: number) => void, makeKey?: (value: T, index: number) => SortKeyType): void;
|
|
64
|
-
export declare function onEach<K extends string | number | symbol, T>(target: Record<K, undefined | T>, render: (value: T, index: KeyToString<K>) => void, makeKey?: (value: T, index: KeyToString<K>) => SortKeyType): void;
|
|
65
|
-
/** @private */
|
|
66
|
-
export declare const EMPTY: unique symbol;
|
|
67
|
-
/**
|
|
68
|
-
* Reactively checks if an observable array, object, Map, or Set is empty.
|
|
69
|
-
*
|
|
70
|
-
* This function not only returns the current emptiness state but also establishes
|
|
71
|
-
* a reactive dependency. If the emptiness state of the `proxied` object or array
|
|
72
|
-
* changes later (e.g., an item is added to an empty array, or the last property
|
|
73
|
-
* is deleted from an object), the scope that called `isEmpty` will be automatically
|
|
74
|
-
* scheduled for re-evaluation.
|
|
75
|
-
*
|
|
76
|
-
* @param proxied The observable array, object, Map, or Set to check.
|
|
77
|
-
* @returns `true` if the array has length 0, the Map/Set has size 0, or the object has no own enumerable properties, `false` otherwise.
|
|
78
|
-
*
|
|
79
|
-
* @example
|
|
80
|
-
* ```typescript
|
|
81
|
-
* const $items = A.proxy([]);
|
|
82
|
-
*
|
|
83
|
-
* // Reactively display a message if the items array is empty
|
|
84
|
-
* A('div', () => {
|
|
85
|
-
* if (A.isEmpty($items)) {
|
|
86
|
-
* A('p i#No items yet!');
|
|
87
|
-
* } else {
|
|
88
|
-
* A.onEach($items, item => A('p#'+item));
|
|
89
|
-
* }
|
|
90
|
-
* });
|
|
91
|
-
*
|
|
92
|
-
* // Adding an item will automatically remove the "No items yet!" message
|
|
93
|
-
* setInterval(() => {
|
|
94
|
-
* if (!$items.length || Math.random()>0.5) $items.push('Item');
|
|
95
|
-
* else $items.length = 0;
|
|
96
|
-
* }, 1000)
|
|
97
|
-
* ```
|
|
2
|
+
* The minimal `window`-like object an Aberdeen instance renders against. A real browser
|
|
3
|
+
* `window`, a jsdom window, and the server window from `aberdeen/server` all satisfy this.
|
|
98
4
|
*/
|
|
99
|
-
export
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
5
|
+
export interface WindowLike {
|
|
6
|
+
document: any;
|
|
7
|
+
Node: any;
|
|
8
|
+
Element: any;
|
|
9
|
+
matchMedia?: (query: string) => any;
|
|
10
|
+
location?: any;
|
|
11
|
+
history?: any;
|
|
12
|
+
addEventListener?: (...args: any[]) => void;
|
|
13
|
+
removeEventListener?: (...args: any[]) => void;
|
|
14
|
+
/** Optional; falls back to the host's timers when absent (e.g. the lean server window). */
|
|
15
|
+
setTimeout?: (...args: any[]) => any;
|
|
16
|
+
queueMicrotask?: (callback: () => void) => void;
|
|
103
17
|
}
|
|
18
|
+
/** Options for {@link createA}. */
|
|
19
|
+
export interface InitOptions {
|
|
20
|
+
/** Set to `false` to disable `create`/`destroy` transitions for this instance (e.g. for SSR). */
|
|
21
|
+
transitions?: boolean;
|
|
22
|
+
}
|
|
23
|
+
/** Any value Aberdeen can proxy: array, plain object, Map or Set. */
|
|
24
|
+
export type TargetType = any[] | {
|
|
25
|
+
[key: string | symbol]: any;
|
|
26
|
+
} | Map<any, any> | Set<any>;
|
|
27
|
+
/** A sort key returned by `onEach`/`map` ordering callbacks. */
|
|
28
|
+
export type SortKeyType = number | string | Array<number | string> | undefined | void;
|
|
29
|
+
/** Maps object key types to the string form Aberdeen passes to callbacks. */
|
|
30
|
+
export type KeyToString<K> = K extends number ? string : K extends string | symbol ? K : K extends number | infer U ? string | U : K;
|
|
104
31
|
/**
|
|
105
|
-
*
|
|
106
|
-
*
|
|
107
|
-
* @param proxied The observable object to count. In case an `array`, `Map`, or `Set` is passed in, a {@link ref} to its `.length` or `.size` will be returned.
|
|
108
|
-
* @returns an observable object for which the `value` property reflects the number of properties in `proxied` with a value other than `undefined`, or the collection size for arrays, Maps, and Sets.
|
|
109
|
-
*
|
|
110
|
-
* @example
|
|
111
|
-
* ```typescript
|
|
112
|
-
* const $items = A.proxy({x: 3, y: 7} as any);
|
|
113
|
-
* const $count = A.count($items);
|
|
114
|
-
*
|
|
115
|
-
* // Create a DOM text node for the count:
|
|
116
|
-
* A('div text=', $count);
|
|
117
|
-
* // <div>2</div>
|
|
118
|
-
|
|
119
|
-
* // Or we can use it in an {@link derive} function:
|
|
120
|
-
* A(() => console.log("The count is now", $count.value));
|
|
121
|
-
* // The count is now 2
|
|
122
|
-
*
|
|
123
|
-
* // Adding/removing items will update the count
|
|
124
|
-
* $items.z = 12;
|
|
125
|
-
* // Asynchronously, after 0ms:
|
|
126
|
-
* // <div>3</div>
|
|
127
|
-
* // The count is now 3
|
|
128
|
-
* ```
|
|
129
|
-
*/
|
|
130
|
-
export declare function count(proxied: TargetType): ValueRef<number>;
|
|
131
|
-
/**
|
|
132
|
-
* When `proxy` is called with a Promise, the returned object has this shape.
|
|
32
|
+
* The Aberdeen instance returned by {@link createA}: a callable element-builder with every
|
|
33
|
+
* Aberdeen function attached as a method. `import A from 'aberdeen'` gives you one of these.
|
|
133
34
|
*/
|
|
134
|
-
export interface
|
|
35
|
+
export interface Aberdeen {
|
|
36
|
+
/** Build reactive DOM: create elements, set attributes/properties/event listeners, add content. See the tutorial for the full mini-language. */
|
|
37
|
+
(...args: any[]): undefined | Element;
|
|
135
38
|
/**
|
|
136
|
-
*
|
|
39
|
+
* Registers a cleanup function to be executed just before the current reactive scope
|
|
40
|
+
* is destroyed or redraws.
|
|
41
|
+
*
|
|
42
|
+
* This is useful for releasing resources, removing manual event listeners, or cleaning up
|
|
43
|
+
* side effects associated with the scope. Cleaners are run in reverse order of registration.
|
|
44
|
+
*
|
|
45
|
+
* Scopes are created by functions like {@link Aberdeen.derive}, {@link Aberdeen.mount}, {@link Aberdeen | A} (when given a render function),
|
|
46
|
+
* and internally by constructs like {@link Aberdeen.onEach}.
|
|
47
|
+
*
|
|
48
|
+
* @param cleaner - The function to execute during cleanup.
|
|
49
|
+
*
|
|
50
|
+
* @example Maintaing a sum for a changing array
|
|
51
|
+
* ```typescript
|
|
52
|
+
* const $numbers = A.proxy([3, 5, 10]);
|
|
53
|
+
* let $sum = A.proxy(0);
|
|
54
|
+
*
|
|
55
|
+
* // Show the array items and maintain the sum
|
|
56
|
+
* A.onEach($numbers, (item, index) => {
|
|
57
|
+
* A(`code#${index}→${item}`);
|
|
58
|
+
* // We'll update $sum.value using peek, as += first does a read, but
|
|
59
|
+
* // we don't want to subscribe.
|
|
60
|
+
* A.peek(() => $sum.value += item);
|
|
61
|
+
* // Clean gets called before each rerun for a certain item index
|
|
62
|
+
* // No need for peek here, as the clean code doesn't run in an
|
|
63
|
+
* // observer scope.
|
|
64
|
+
* A.clean(() => $sum.value -= item);
|
|
65
|
+
* })
|
|
66
|
+
*
|
|
67
|
+
* // Show the sum
|
|
68
|
+
* A('h1 text=', $sum);
|
|
69
|
+
*
|
|
70
|
+
* // Make random changes to the array
|
|
71
|
+
* const rnd = () => 0|(Math.random()*20);
|
|
72
|
+
* setInterval(() => $numbers[rnd()] = rnd(), 1000);
|
|
73
|
+
* ```
|
|
137
74
|
*/
|
|
138
|
-
|
|
75
|
+
clean(cleaner: () => void): void;
|
|
139
76
|
/**
|
|
140
|
-
*
|
|
77
|
+
* Clone an (optionally proxied) object or array.
|
|
78
|
+
*
|
|
79
|
+
* @param src The object or array to clone. If it is proxied, `clone` will subscribe to any changes to the (nested) data structure.
|
|
80
|
+
* @template T - The type of the objects being copied.
|
|
81
|
+
* @returns A new unproxied array or object (of the same type as `src`), containing a deep copy of `src`.
|
|
141
82
|
*/
|
|
142
|
-
|
|
83
|
+
clone<T extends object>(src: T): T;
|
|
84
|
+
/**
|
|
85
|
+
* Recursively copies properties or array items from `src` to `dst`.
|
|
86
|
+
* It's designed to work efficiently with reactive proxies created by {@link Aberdeen.proxy}.
|
|
87
|
+
*
|
|
88
|
+
* - **Minimizes Updates:** When copying between objects/arrays (proxied or not), if a nested object
|
|
89
|
+
* exists in `dst` with the same constructor as the corresponding object in `src`, `copy`
|
|
90
|
+
* will recursively copy properties into the existing `dst` object instead of replacing it.
|
|
91
|
+
* This minimizes change notifications for reactive (proxied) destinations.
|
|
92
|
+
* - **Fast with Proxies:** When copying to/from proxied objects, `copy` uses Aberdeen internals
|
|
93
|
+
* to speed things up (compared to a non-Aberdeen-aware deep copy).
|
|
94
|
+
*
|
|
95
|
+
* @param dst - The destination object/array/Map (proxied or unproxied).
|
|
96
|
+
* @param src - The source object/array/Map (proxied or unproxied). It won't be modified.
|
|
97
|
+
* @template T - The type of the objects being copied.
|
|
98
|
+
* @returns `true` if any changes were made to `dst`, or `false` if not.
|
|
99
|
+
* @throws Error if attempting to copy an array into a non-array or vice versa.
|
|
100
|
+
*
|
|
101
|
+
* @example Basic Copy
|
|
102
|
+
* ```typescript
|
|
103
|
+
* const $source = A.proxy({ a: 1, b: { c: 2 } });
|
|
104
|
+
* const $dest = A.proxy({ b: { d: 3 } });
|
|
105
|
+
* A.copy($dest, $source);
|
|
106
|
+
* console.log($dest); // proxy({ a: 1, b: { c: 2 } })
|
|
107
|
+
* A.copy($dest, 'b', { e: 4 });
|
|
108
|
+
* console.log($dest); // proxy({ a: 1, b: { e: 4 } })
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
copy<T extends object>(dst: T, src: T): boolean;
|
|
112
|
+
copy<T extends object>(dst: T, dstKey: keyof T, src: T[typeof dstKey]): boolean;
|
|
113
|
+
/**
|
|
114
|
+
* Reactively counts the number of properties in an object.
|
|
115
|
+
*
|
|
116
|
+
* @param proxied The observable object to count. In case an `array`, `Map`, or `Set` is passed in, a {@link Aberdeen.ref} to its `.length` or `.size` will be returned.
|
|
117
|
+
* @returns an observable object for which the `value` property reflects the number of properties in `proxied` with a value other than `undefined`, or the collection size for arrays, Maps, and Sets.
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* ```typescript
|
|
121
|
+
* const $items = A.proxy({x: 3, y: 7} as any);
|
|
122
|
+
* const $count = A.count($items);
|
|
123
|
+
*
|
|
124
|
+
* // Create a DOM text node for the count:
|
|
125
|
+
* A('div text=', $count);
|
|
126
|
+
* // <div>2</div>
|
|
127
|
+
|
|
128
|
+
* // Or we can use it in an {@link Aberdeen.derive} function:
|
|
129
|
+
* A(() => console.log("The count is now", $count.value));
|
|
130
|
+
* // The count is now 2
|
|
131
|
+
*
|
|
132
|
+
* // Adding/removing items will update the count
|
|
133
|
+
* $items.z = 12;
|
|
134
|
+
* // Asynchronously, after 0ms:
|
|
135
|
+
* // <div>3</div>
|
|
136
|
+
* // The count is now 3
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
count(proxied: TargetType): ValueRef<number>;
|
|
140
|
+
/**
|
|
141
|
+
* A reactive object containing CSS variable definitions.
|
|
142
|
+
*
|
|
143
|
+
* Any property you assign to `cssVars` becomes available as a CSS custom property throughout your application.
|
|
144
|
+
*
|
|
145
|
+
* Use {@link Aberdeen.setSpacingCssVars} to optionally initialize `cssVars[1]` through `cssVars[12]` with an exponential spacing scale.
|
|
146
|
+
*
|
|
147
|
+
* When you reference a CSS variable in Aberdeen using the `$` prefix (e.g., `$primary`), it automatically resolves to `var(--primary)`.
|
|
148
|
+
* For numeric keys (which can't be used directly as CSS custom property names), Aberdeen prefixes them with `m` (e.g., `$3` becomes `var(--m3)`).
|
|
149
|
+
*
|
|
150
|
+
* When you add the first property to cssVars, Aberdeen automatically creates a reactive `<style>` tag in `<head>`
|
|
151
|
+
* containing the `:root` CSS custom property declarations. The style tag is automatically removed if cssVars becomes empty.
|
|
152
|
+
*
|
|
153
|
+
* @example
|
|
154
|
+
* ```javascript
|
|
155
|
+
* import A from 'aberdeen';
|
|
156
|
+
*
|
|
157
|
+
* // Optionally initialize spacing scale
|
|
158
|
+
* A.setSpacingCssVars(); // Uses defaults: base=1, unit='rem'
|
|
159
|
+
*
|
|
160
|
+
* // Define custom colors - style tag is automatically created
|
|
161
|
+
* A.cssVars.primary = '#3b82f6';
|
|
162
|
+
* A.cssVars.danger = '#ef4444';
|
|
163
|
+
*
|
|
164
|
+
* // Use in elements with the $ prefix
|
|
165
|
+
* A('button bg:$primary fg:white #I'm a primary button');
|
|
166
|
+
*
|
|
167
|
+
* // Use spacing (if setSpacingCssVars() was called)
|
|
168
|
+
* A('hr mt:$3'); // Sets margin-top to var(--m3)
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
cssVars: Record<string, string>;
|
|
172
|
+
/**
|
|
173
|
+
* When set on an object or its prototype chain, {@link Aberdeen.dump} calls this as a render function
|
|
174
|
+
* (with the object as `this`) instead of its default recursive rendering. If the value is not
|
|
175
|
+
* a function, it's treated as a string to display.
|
|
176
|
+
*
|
|
177
|
+
* @example
|
|
178
|
+
* ```typescript
|
|
179
|
+
* class Color {
|
|
180
|
+
* constructor(public r: number, public g: number, public b: number) {}
|
|
181
|
+
* [CUSTOM_DUMP]() { A(`#rgb(${this.r}, ${this.g}, ${this.b})`); }
|
|
182
|
+
* }
|
|
183
|
+
* ```
|
|
184
|
+
*/
|
|
185
|
+
CUSTOM_DUMP: any;
|
|
186
|
+
/**
|
|
187
|
+
* Returns whether the user's browser prefers a dark color scheme.
|
|
188
|
+
*
|
|
189
|
+
* This function is reactive - scopes that call it will re-execute when the
|
|
190
|
+
* browser's color scheme preference changes (via the `prefers-color-scheme` media query).
|
|
191
|
+
*
|
|
192
|
+
* Use this in combination with {@link Aberdeen | A} and {@link Aberdeen.cssVars} to implement theme switching:
|
|
193
|
+
*
|
|
194
|
+
* @returns `true` if the browser prefers dark mode, `false` if it prefers light mode.
|
|
195
|
+
*
|
|
196
|
+
* @example
|
|
197
|
+
* ```javascript
|
|
198
|
+
* import A from 'aberdeen';
|
|
199
|
+
*
|
|
200
|
+
* // Reactively set colors based on browser preference
|
|
201
|
+
* A(() => {
|
|
202
|
+
* A.cssVars.bg = A.darkMode() ? '#1a1a1a' : '#ffffff';
|
|
203
|
+
* A.cssVars.fg = A.darkMode() ? '#e5e5e5' : '#000000';
|
|
204
|
+
* });
|
|
205
|
+
*
|
|
206
|
+
* A('div bg:$bg fg:$fg p:1rem #Colors change based on system dark mode preference');
|
|
207
|
+
* ```
|
|
208
|
+
*/
|
|
209
|
+
darkMode(): boolean;
|
|
210
|
+
/**
|
|
211
|
+
* Creates a reactive scope that automatically re-executes the provided function
|
|
212
|
+
* whenever any proxied data (created by {@link Aberdeen.proxy}) read during its last execution changes, storing
|
|
213
|
+
* its return value in an observable.
|
|
214
|
+
*
|
|
215
|
+
* Updates are batched and run asynchronously shortly after the changes occur.
|
|
216
|
+
* Use {@link Aberdeen.clean} to register cleanup logic for the scope.
|
|
217
|
+
* Use {@link Aberdeen.peek} or {@link Aberdeen.unproxy} within the function to read proxied data without subscribing to it.
|
|
218
|
+
*
|
|
219
|
+
* @param func - The function to execute reactively. Any DOM manipulations should typically
|
|
220
|
+
* be done using {@link Aberdeen | A} within this function. Its return value will be made available as an
|
|
221
|
+
* observable returned by the `derive()` function.
|
|
222
|
+
* @returns An observable object, with its `value` property containing whatever the last run of `func` returned.
|
|
223
|
+
*
|
|
224
|
+
* @example Observation creating UI components
|
|
225
|
+
* ```typescript
|
|
226
|
+
* const $data = A.proxy({ user: 'Frank', notifications: 42 });
|
|
227
|
+
*
|
|
228
|
+
* A('main', () => {
|
|
229
|
+
* console.log('Welcome');
|
|
230
|
+
* A('h3#Welcome, ' + $data.user); // Reactive text
|
|
231
|
+
*
|
|
232
|
+
* A.derive(() => {
|
|
233
|
+
* // When $data.notifications changes, only this inner scope reruns,
|
|
234
|
+
* // leaving the `<p>Welcome, ..</p>` untouched.
|
|
235
|
+
* console.log('Notifications');
|
|
236
|
+
* A('code.notification-badge text=', $data.notifications);
|
|
237
|
+
* A('a text=Notify! click=', () => $data.notifications++);
|
|
238
|
+
* });
|
|
239
|
+
* });
|
|
240
|
+
* ```
|
|
241
|
+
*
|
|
242
|
+
* ***Note*** that the above could just as easily be done using `A(func)` instead of `derive(func)`.
|
|
243
|
+
*
|
|
244
|
+
* @example Observation with return value
|
|
245
|
+
* ```typescript
|
|
246
|
+
* const $counter = A.proxy(0);
|
|
247
|
+
* setInterval(() => $counter.value++, 1000);
|
|
248
|
+
* const $double = A.derive(() => $counter.value * 2);
|
|
249
|
+
*
|
|
250
|
+
* A('h3', () => {
|
|
251
|
+
* A(`#counter=${$counter.value} double=${$double.value}`);
|
|
252
|
+
* })
|
|
253
|
+
* ```
|
|
254
|
+
*
|
|
255
|
+
* @overload
|
|
256
|
+
* @param func Func without a return value.
|
|
257
|
+
*/
|
|
258
|
+
derive<T>(func: () => T): ValueRef<T>;
|
|
259
|
+
/**
|
|
260
|
+
* Renders a live, recursive dump of a proxied data structure (or any value)
|
|
261
|
+
* into the DOM at the current {@link Aberdeen | A} insertion point.
|
|
262
|
+
*
|
|
263
|
+
* Uses `<ul>` and `<li>` elements to display object properties and array items.
|
|
264
|
+
* Updates reactively if the dumped data changes. Primarily intended for debugging purposes.
|
|
265
|
+
*
|
|
266
|
+
* @param data - The proxied data structure (or any value) to display.
|
|
267
|
+
* @returns The original `data` argument, allowing for chaining.
|
|
268
|
+
* @template T - The type of the data being dumped.
|
|
269
|
+
*
|
|
270
|
+
* @example Dumping reactive state
|
|
271
|
+
* ```typescript
|
|
272
|
+
* import A from 'aberdeen';
|
|
273
|
+
*
|
|
274
|
+
* const $state = A.proxy({
|
|
275
|
+
* user: { name: 'Frank', kids: 1 },
|
|
276
|
+
* items: ['a', 'b']
|
|
277
|
+
* });
|
|
278
|
+
*
|
|
279
|
+
* A('h2#Live State Dump');
|
|
280
|
+
* A.dump($state);
|
|
281
|
+
*
|
|
282
|
+
* // Change state later, the dump in the DOM will update
|
|
283
|
+
* setTimeout(() => { $state.user.kids++; $state.items.push('c'); }, 2000);
|
|
284
|
+
* ```
|
|
285
|
+
*/
|
|
286
|
+
dump<T>(data: T): T;
|
|
287
|
+
/**
|
|
288
|
+
* Inserts CSS rules into the document, scoping them with a unique class name.
|
|
289
|
+
*
|
|
290
|
+
* The `style` parameter can be either:
|
|
291
|
+
* - A **concise style string** (for rules applying to the root class).
|
|
292
|
+
* - An **object** where keys are selectors (with `&` representing the root class)
|
|
293
|
+
* and values are concise style strings or nested objects. When the key does not contain `&`,
|
|
294
|
+
* it is treated as a descendant selector. So `{p: "color:red"}` becomes `".AbdStlX p { color: red; }"` with `AbdStlX` being the generated class name.
|
|
295
|
+
*
|
|
296
|
+
* ### Concise Style Strings
|
|
297
|
+
*
|
|
298
|
+
* Concise style strings use two syntaxes (same as inline CSS in {@link Aberdeen | A}):
|
|
299
|
+
* - **Short form** `key:value` (no space after colon): The value ends at the next whitespace.
|
|
300
|
+
* Example: `'m:$3 bg:red r:8px'`
|
|
301
|
+
* - **Long form** `key: value;` (space after colon): The value continues until a semicolon.
|
|
302
|
+
* Example: `'box-shadow: 2px 0 6px black; transition: all 0.3s ease;'`
|
|
303
|
+
*
|
|
304
|
+
* Both forms can be mixed: `'m:$3 box-shadow: 0 2px 4px rgba(0,0,0,0.2); bg:$cardBg'`
|
|
305
|
+
*
|
|
306
|
+
* Supports the same CSS shortcuts as {@link Aberdeen | A} and CSS variable references with `$` (e.g., `$primary`, `$3`).
|
|
307
|
+
*
|
|
308
|
+
* @param style - A concise style string or a style object.
|
|
309
|
+
* @returns The unique class name prefix used for scoping (e.g., `.AbdStl1`).
|
|
310
|
+
* Use this prefix with {@link Aberdeen | A} to apply the styles.
|
|
311
|
+
*
|
|
312
|
+
* @example Basic Usage with Shortcuts and CSS Variables
|
|
313
|
+
* ```typescript
|
|
314
|
+
* const cardClass = A.insertCss({
|
|
315
|
+
* '&': 'bg:white p:$4 r:8px transition: background-color 0.3s;',
|
|
316
|
+
* '&:hover': 'bg:#f5f5f5',
|
|
317
|
+
* });
|
|
318
|
+
*
|
|
319
|
+
* A('section', cardClass, () => {
|
|
320
|
+
* A('p#Card content');
|
|
321
|
+
* });
|
|
322
|
+
* ```
|
|
323
|
+
*
|
|
324
|
+
* @example Nested Selectors and Media Queries
|
|
325
|
+
* ```typescript
|
|
326
|
+
* const formClass = A.insertCss({
|
|
327
|
+
* '&': 'bg:#0004 p:$3 r:$2',
|
|
328
|
+
* button: {
|
|
329
|
+
* '&': 'bg:$primary fg:white p:$2 r:4px cursor:pointer',
|
|
330
|
+
* '&:hover': 'bg:$primaryHover',
|
|
331
|
+
* '&:disabled': 'bg:#ccc cursor:not-allowed',
|
|
332
|
+
* '.icon': 'display:inline-block mr:$1',
|
|
333
|
+
* '@media (max-width: 600px)': 'p:$1 font-size:14px'
|
|
334
|
+
* }
|
|
335
|
+
* });
|
|
336
|
+
*
|
|
337
|
+
* A('form', formClass, () => {
|
|
338
|
+
* A('button', () => {
|
|
339
|
+
* A('span.icon text=🔥');
|
|
340
|
+
* A('#Click Me');
|
|
341
|
+
* });
|
|
342
|
+
* });
|
|
343
|
+
* ```
|
|
344
|
+
*
|
|
345
|
+
* @example Complex CSS Values
|
|
346
|
+
* ```typescript
|
|
347
|
+
* const badge = A.insertCss({
|
|
348
|
+
* '&::before': 'content: "★"; color:gold mr:$1',
|
|
349
|
+
* '&': 'position:relative box-shadow: 0 2px 8px rgba(0,0,0,0.15);'
|
|
350
|
+
* });
|
|
351
|
+
*
|
|
352
|
+
* A(badge + ' span#Product Name');
|
|
353
|
+
* ```
|
|
354
|
+
*/
|
|
355
|
+
insertCss(style: string | object): string;
|
|
356
|
+
/**
|
|
357
|
+
* Inserts CSS rules globally (unscoped).
|
|
358
|
+
*
|
|
359
|
+
* Works exactly like {@link Aberdeen.insertCss}, but without prefixing selectors with a unique class name.
|
|
360
|
+
* This is useful for global resets, base styles, or styles that need to apply to the entire document.
|
|
361
|
+
*
|
|
362
|
+
* Accepts the same concise style string syntax and CSS shortcuts as {@link Aberdeen.insertCss}.
|
|
363
|
+
* See {@link Aberdeen.insertCss} for detailed documentation on syntax and shortcuts.
|
|
364
|
+
*
|
|
365
|
+
* @param style - Object with selectors as keys and concise CSS strings as values.
|
|
366
|
+
*
|
|
367
|
+
* @example Global Reset and Base Styles
|
|
368
|
+
* ```typescript
|
|
369
|
+
* // Set up global styles using CSS shortcuts
|
|
370
|
+
* A.insertGlobalCss({
|
|
371
|
+
* "*": "m:0 p:0 box-sizing:border-box",
|
|
372
|
+
* "body": "font-family: system-ui, sans-serif; m:0 p:$3 bg:#434 fg:#d0dafa",
|
|
373
|
+
* "a": "text-decoration:none fg:#57f",
|
|
374
|
+
* "a:hover": "text-decoration:underline",
|
|
375
|
+
* "code": "font-family:monospace bg:#222 fg:#afc p:4px r:3px"
|
|
376
|
+
* });
|
|
377
|
+
*
|
|
378
|
+
* A('h2#Title without margins');
|
|
379
|
+
* A('a#This is a link');
|
|
380
|
+
* A('code#const x = 42;');
|
|
381
|
+
* ```
|
|
382
|
+
*
|
|
383
|
+
* @example Responsive Global Styles
|
|
384
|
+
* ```typescript
|
|
385
|
+
* A.insertGlobalCss({
|
|
386
|
+
* "html": "font-size:16px",
|
|
387
|
+
* "body": "line-height:1.6",
|
|
388
|
+
* "h1, h2, h3": "font-weight:600 mt:$4 mb:$2",
|
|
389
|
+
* "@media (max-width: 768px)": {
|
|
390
|
+
* "html": "font-size:14px",
|
|
391
|
+
* "body": "p:$2"
|
|
392
|
+
* },
|
|
393
|
+
* "@media (prefers-color-scheme: dark)": {
|
|
394
|
+
* "body": "bg:#1a1a1a fg:#e5e5e5",
|
|
395
|
+
* "code": "bg:#2a2a2a"
|
|
396
|
+
* }
|
|
397
|
+
* });
|
|
398
|
+
* ```
|
|
399
|
+
* At-rules such as `@media` and `@keyframes` should use nested objects. For keyframes,
|
|
400
|
+
* the step selectors (`0%`, `50%`, `100%`, etc.) become the nested keys and each value
|
|
401
|
+
* should be a concise CSS declaration string.
|
|
402
|
+
*
|
|
403
|
+
* @example Animation Keyframes
|
|
404
|
+
* ```typescript
|
|
405
|
+
* A.insertGlobalCss({
|
|
406
|
+
* "@keyframes connection-pulse": {
|
|
407
|
+
* "0%": "box-shadow: inset 0 0 0 0 rgba(255, 70, 70, 0.4);",
|
|
408
|
+
* "50%": "box-shadow: inset 0 0 0 6px rgba(255, 70, 70, 0.08);",
|
|
409
|
+
* "100%": "box-shadow: inset 0 0 0 0 rgba(255, 70, 70, 0.4);"
|
|
410
|
+
* }
|
|
411
|
+
* });
|
|
412
|
+
* ```
|
|
413
|
+
*/
|
|
414
|
+
insertGlobalCss(style: object): void;
|
|
415
|
+
/**
|
|
416
|
+
* Creates a new string that has the opposite sort order compared to the input string.
|
|
417
|
+
*
|
|
418
|
+
* This is achieved by flipping the bits of each character code in the input string.
|
|
419
|
+
* The resulting string is intended for use as a sort key, particularly with the
|
|
420
|
+
* `makeKey` function in {@link Aberdeen.onEach}, to achieve a descending sort order.
|
|
421
|
+
*
|
|
422
|
+
* **Warning:** The output string will likely contain non-printable characters or
|
|
423
|
+
* appear as gibberish and should not be displayed to the user.
|
|
424
|
+
*
|
|
425
|
+
* @example
|
|
426
|
+
* ```typescript
|
|
427
|
+
* const $users = A.proxy([
|
|
428
|
+
* { id: 1, name: 'Charlie', score: 95 },
|
|
429
|
+
* { id: 2, name: 'Alice', score: 100 },
|
|
430
|
+
* { id: 3, name: 'Bob', score: 90 },
|
|
431
|
+
* ]);
|
|
432
|
+
*
|
|
433
|
+
* A.onEach($users, ($user) => {
|
|
434
|
+
* A(`p#${$user.name}: ${$user.score}`);
|
|
435
|
+
* }, ($user) => A.invertString($user.name)); // Reverse alphabetic order
|
|
436
|
+
* ```
|
|
437
|
+
*
|
|
438
|
+
* @param input The string whose sort order needs to be inverted.
|
|
439
|
+
* @returns A new string that will sort in the reverse order of the input string.
|
|
440
|
+
* @see {@link Aberdeen.onEach} for usage with sorting.
|
|
441
|
+
*/
|
|
442
|
+
invertString(input: string): string;
|
|
443
|
+
/**
|
|
444
|
+
* Reactively checks if an observable array, object, Map, or Set is empty.
|
|
445
|
+
*
|
|
446
|
+
* This function not only returns the current emptiness state but also establishes
|
|
447
|
+
* a reactive dependency. If the emptiness state of the `proxied` object or array
|
|
448
|
+
* changes later (e.g., an item is added to an empty array, or the last property
|
|
449
|
+
* is deleted from an object), the scope that called `isEmpty` will be automatically
|
|
450
|
+
* scheduled for re-evaluation.
|
|
451
|
+
*
|
|
452
|
+
* @param proxied The observable array, object, Map, or Set to check.
|
|
453
|
+
* @returns `true` if the array has length 0, the Map/Set has size 0, or the object has no own enumerable properties, `false` otherwise.
|
|
454
|
+
*
|
|
455
|
+
* @example
|
|
456
|
+
* ```typescript
|
|
457
|
+
* const $items = A.proxy([]);
|
|
458
|
+
*
|
|
459
|
+
* // Reactively display a message if the items array is empty
|
|
460
|
+
* A('div', () => {
|
|
461
|
+
* if (A.isEmpty($items)) {
|
|
462
|
+
* A('p i#No items yet!');
|
|
463
|
+
* } else {
|
|
464
|
+
* A.onEach($items, item => A('p#'+item));
|
|
465
|
+
* }
|
|
466
|
+
* });
|
|
467
|
+
*
|
|
468
|
+
* // Adding an item will automatically remove the "No items yet!" message
|
|
469
|
+
* setInterval(() => {
|
|
470
|
+
* if (!$items.length || Math.random()>0.5) $items.push('Item');
|
|
471
|
+
* else $items.length = 0;
|
|
472
|
+
* }, 1000)
|
|
473
|
+
* ```
|
|
474
|
+
*/
|
|
475
|
+
isEmpty(proxied: TargetType): boolean;
|
|
476
|
+
/** When using a Map as `source`. */
|
|
477
|
+
map<K, IN, OUT>(source: Map<K, IN>, func: (value: IN, key: K) => undefined | OUT): Map<K, OUT>;
|
|
478
|
+
map<IN, OUT>(source: Array<IN>, func: (value: IN, index: number) => undefined | OUT): Array<OUT>;
|
|
479
|
+
map<IN, const IN_KEY extends string | number | symbol, OUT>(source: Record<IN_KEY, IN>, func: (value: IN, index: KeyToString<IN_KEY>) => undefined | OUT): Record<string | symbol, OUT>;
|
|
480
|
+
/**
|
|
481
|
+
* Like {@link Aberdeen.copy}, but uses merge semantics. Properties in `dst` not present in `src` are kept.
|
|
482
|
+
* `null`/`undefined` in `src` delete properties in `dst`.
|
|
483
|
+
*
|
|
484
|
+
* @example Basic merge
|
|
485
|
+
* ```typescript
|
|
486
|
+
* const source = { b: { c: 99 }, d: undefined }; // d: undefined will delete
|
|
487
|
+
* const $dest = A.proxy({ a: 1, b: { x: 5 }, d: 4 });
|
|
488
|
+
* A.merge($dest, source);
|
|
489
|
+
* A.merge($dest, 'b', { y: 6 }); // merge into $dest.b
|
|
490
|
+
* A.merge($dest, 'c', { z: 7 }); // $dest.c doesn't exist yet, so it will just be assigned
|
|
491
|
+
* console.log($dest); // proxy({ a: 1, b: { c: 99, x: 5, y: 6 }, c: { z: 7 } })
|
|
492
|
+
* ```
|
|
493
|
+
*
|
|
494
|
+
*/
|
|
495
|
+
merge<T extends object>(dst: T, value: Partial<T>): boolean;
|
|
496
|
+
merge<T extends object>(dst: T, dstKey: keyof T, value: Partial<T[typeof dstKey]>): boolean;
|
|
497
|
+
/**
|
|
498
|
+
* Attaches a reactive Aberdeen UI fragment to an existing DOM element. Without the use of
|
|
499
|
+
* this function, {@link Aberdeen | A} will assume `document.body` as its root.
|
|
500
|
+
*
|
|
501
|
+
* It creates a top-level reactive scope associated with the `parentElement`. The provided
|
|
502
|
+
* function `func` is executed immediately within this scope. Any proxied data read by `func`
|
|
503
|
+
* will cause it to re-execute when the data changes, updating the DOM elements created within it.
|
|
504
|
+
*
|
|
505
|
+
* Calls to {@link Aberdeen | A} inside `func` will append nodes to `parentElement`.
|
|
506
|
+
* You can nest {@link Aberdeen.derive} or other {@link Aberdeen | A} scopes within `func`.
|
|
507
|
+
* Use {@link Aberdeen.unmountAll} to clean up all mounted scopes and their DOM nodes.
|
|
508
|
+
*
|
|
509
|
+
* Mounting scopes happens reactively, meaning that if this function is called from within another
|
|
510
|
+
* ({@link Aberdeen.derive} or {@link Aberdeen | A} or {@link Aberdeen.mount}) scope that gets cleaned up, so will the mount.
|
|
511
|
+
*
|
|
512
|
+
* @param parentElement - The native DOM `Element` to which the UI fragment will be appended.
|
|
513
|
+
* @param func - The function that defines the UI fragment, typically containing calls to {@link Aberdeen | A}.
|
|
514
|
+
*
|
|
515
|
+
* @example Basic Mount
|
|
516
|
+
* ```javascript
|
|
517
|
+
* // Create a pre-existing DOM structure (without Aberdeen)
|
|
518
|
+
* document.body.innerHTML = `<h3>Static content <span id="title-extra"></span></h3><div class="box" id="app-root"></div>`;
|
|
519
|
+
*
|
|
520
|
+
* import A from 'aberdeen';
|
|
521
|
+
*
|
|
522
|
+
* const $runTime = A.proxy(0);
|
|
523
|
+
* setInterval(() => $runTime.value++, 1000);
|
|
524
|
+
*
|
|
525
|
+
* A.mount(document.getElementById('app-root'), () => {
|
|
526
|
+
* A('h4#Aberdeen App');
|
|
527
|
+
* A(`p#Run time: ${$runTime.value}s`);
|
|
528
|
+
* // Conditionally render some content somewhere else in the static page
|
|
529
|
+
* if ($runTime.value&1) {
|
|
530
|
+
* A.mount(document.getElementById('title-extra'), () =>
|
|
531
|
+
* A(`i#(${$runTime.value}s)`)
|
|
532
|
+
* );
|
|
533
|
+
* }
|
|
534
|
+
* });
|
|
535
|
+
* ```
|
|
536
|
+
*
|
|
537
|
+
* Note how the inner mount behaves reactively as well, automatically unmounting when it's parent observer scope re-runs.
|
|
538
|
+
*/
|
|
539
|
+
mount(parentElement: Element, func: () => void): void;
|
|
540
|
+
/** When using an array as `source`. */
|
|
541
|
+
multiMap<IN, OUT extends {
|
|
542
|
+
[key: string | symbol]: any;
|
|
543
|
+
}>(source: Array<IN>, func: (value: IN, index: number) => OUT | undefined): OUT;
|
|
544
|
+
multiMap<K extends string | number | symbol, IN, OUT extends {
|
|
545
|
+
[key: string | symbol]: any;
|
|
546
|
+
}>(source: Record<K, IN>, func: (value: IN, index: KeyToString<K>) => OUT | undefined): OUT;
|
|
547
|
+
multiMap<K, IN, OUT extends {
|
|
548
|
+
[key: string | symbol]: any;
|
|
549
|
+
}>(source: Map<K, IN>, func: (value: IN, key: K) => OUT | undefined): OUT;
|
|
550
|
+
/**
|
|
551
|
+
* A symbol that controls how Aberdeen handles an object in copy operations and proxy wrapping.
|
|
552
|
+
*
|
|
553
|
+
* The **presence** of this symbol (regardless of its value) prevents deep-copying: the object is
|
|
554
|
+
* stored and passed by reference in {@link Aberdeen.clone} and {@link Aberdeen.copy}.
|
|
555
|
+
*
|
|
556
|
+
* The **value** of the symbol controls proxy wrapping when the object is read from reactive state:
|
|
557
|
+
* - **Truthy** (e.g. `true`): the object is fully opaque — it is not wrapped in a proxy, so its
|
|
558
|
+
* properties are not observable. Use this for objects that break when proxied (e.g. class instances
|
|
559
|
+
* with internal slots, Promises) or that must be invisible to Aberdeen's reactive system.
|
|
560
|
+
* - **Falsy** (e.g. `false`): the object is still wrapped in a proxy, so reads on its properties
|
|
561
|
+
* create reactive dependencies as normal — only deep-copying is suppressed.
|
|
562
|
+
*/
|
|
563
|
+
OPAQUE: any;
|
|
564
|
+
/**
|
|
565
|
+
* Use {@link Aberdeen.OPAQUE} instead. This is an alias kept for backward compatibility.
|
|
566
|
+
*
|
|
567
|
+
* @deprecated
|
|
568
|
+
*/
|
|
569
|
+
NO_COPY: any;
|
|
570
|
+
/**
|
|
571
|
+
* Reactively iterates over the items of an observable array, object, Map, or Set, optionally rendering content for each item.
|
|
572
|
+
*
|
|
573
|
+
* Automatically updates when items are added, removed, or modified.
|
|
574
|
+
*
|
|
575
|
+
* @param target The observable array, object, Map, or Set to iterate over. Values that are `undefined` are skipped.
|
|
576
|
+
* @param render A function called for each item. It receives the item's (observable) value and its index/key. For Sets, only the value is provided. Any DOM elements created within this function will be associated with the item, placed at the right spot in the DOM, and cleaned up when redrawing/removing the item.
|
|
577
|
+
* @param makeKey An optional function to generate a sort key for each item. This controls the order in which items are rendered in the DOM. If omitted, arrays use index order, Sets use the item value itself, and objects/Maps use their natural key order. The returned key can be a number, string, or an array of numbers/strings for composite sorting. Use {@link Aberdeen.invertString} on string keys for descending order. Returning `null` or `undefined` from `makeKey` will prevent the item from being rendered.
|
|
578
|
+
*
|
|
579
|
+
* @example Iterating an array
|
|
580
|
+
* ```typescript
|
|
581
|
+
* const $items = A.proxy(['apple', 'banana', 'cherry']);
|
|
582
|
+
*
|
|
583
|
+
* // Basic iteration
|
|
584
|
+
* A.onEach($items, (item, index) => A(`li#${item} (#${index})`));
|
|
585
|
+
*
|
|
586
|
+
* // Add a new item - the list updates automatically
|
|
587
|
+
* setTimeout(() => $items.push('durian'), 2000);
|
|
588
|
+
* // Same for updates and deletes
|
|
589
|
+
* setTimeout(() => $items[1] = 'berry', 4000);
|
|
590
|
+
* setTimeout(() => delete $items[2], 6000);
|
|
591
|
+
* ```
|
|
592
|
+
*
|
|
593
|
+
* @example Iterating an array with custom ordering
|
|
594
|
+
* ```typescript
|
|
595
|
+
* const $users = A.proxy([
|
|
596
|
+
* { id: 3, group: 1, name: 'Charlie' },
|
|
597
|
+
* { id: 1, group: 1, name: 'Alice' },
|
|
598
|
+
* { id: 2, group: 2, name: 'Bob' },
|
|
599
|
+
* ]);
|
|
600
|
+
*
|
|
601
|
+
* // Sort by name alphabetically
|
|
602
|
+
* A.onEach($users, ($user) => {
|
|
603
|
+
* A(`p#${$user.name} (id=${$user.id})`);
|
|
604
|
+
* }, ($user) => [$user.group, $user.name]); // Sort by group, and within each group sort by name
|
|
605
|
+
* ```
|
|
606
|
+
*
|
|
607
|
+
* @example Iterating an object
|
|
608
|
+
* ```javascript
|
|
609
|
+
* const $config = A.proxy({ theme: 'dark', fontSize: 14, showTips: true });
|
|
610
|
+
*
|
|
611
|
+
* // Display configuration options
|
|
612
|
+
* A('dl', () => {
|
|
613
|
+
* A.onEach($config, (value, key) => {
|
|
614
|
+
* if (key === 'showTips') return; // Don't render this one
|
|
615
|
+
* A('dt#'+key);
|
|
616
|
+
* A('dd#'+value);
|
|
617
|
+
* });
|
|
618
|
+
* });
|
|
619
|
+
*
|
|
620
|
+
* // Change a value - the display updates automatically
|
|
621
|
+
* setTimeout(() => $config.fontSize = 16, 2000);
|
|
622
|
+
* ```
|
|
623
|
+
*
|
|
624
|
+
* @example Iterating a Set
|
|
625
|
+
* ```javascript
|
|
626
|
+
* const $tags = A.proxy(new Set(['ui', 'fast', 'tiny']));
|
|
627
|
+
*
|
|
628
|
+
* A('ul', () => {
|
|
629
|
+
* A.onEach($tags, (tag) => { // Defaults to alphabetically ordering by tag
|
|
630
|
+
* A(`li#${tag}`);
|
|
631
|
+
* });
|
|
632
|
+
* });
|
|
633
|
+
*
|
|
634
|
+
* setTimeout(() => $tags.add('reactive'), 2000);
|
|
635
|
+
* ```
|
|
636
|
+
* @see {@link Aberdeen.invertString} To easily create keys for reverse sorting.
|
|
637
|
+
*/
|
|
638
|
+
onEach<K, T>(target: Map<K, undefined | T>, render: (value: T, key: K) => void, makeKey?: (value: T, key: K) => SortKeyType): void;
|
|
639
|
+
onEach<T>(target: Set<T>, render: (value: T) => void, makeKey?: (value: T) => SortKeyType): void;
|
|
640
|
+
onEach<T>(target: ReadonlyArray<undefined | T>, render: (value: T, index: number) => void, makeKey?: (value: T, index: number) => SortKeyType): void;
|
|
641
|
+
onEach<K extends string | number | symbol, T>(target: Record<K, undefined | T>, render: (value: T, index: KeyToString<K>) => void, makeKey?: (value: T, index: KeyToString<K>) => SortKeyType): void;
|
|
642
|
+
/** When using an object as `array`. */
|
|
643
|
+
partition<OUT_K extends string | number | symbol, IN_V>(source: IN_V[], func: (value: IN_V, key: number) => undefined | OUT_K | OUT_K[]): Record<OUT_K, Record<number, IN_V>>;
|
|
644
|
+
partition<IN_K extends string | number | symbol, OUT_K extends string | number | symbol, IN_V>(source: Record<IN_K, IN_V>, func: (value: IN_V, key: IN_K) => undefined | OUT_K | OUT_K[]): Record<OUT_K, Record<IN_K, IN_V>>;
|
|
645
|
+
partition<IN_K extends string | number | symbol, OUT_K extends string | number | symbol, IN_V>(source: Map<IN_K, IN_V>, func: (value: IN_V, key: IN_K) => undefined | OUT_K | OUT_K[]): Record<OUT_K, Record<IN_K, IN_V>>;
|
|
143
646
|
/**
|
|
144
|
-
*
|
|
647
|
+
* Executes a function or retrieves a value *without* creating subscriptions in the current reactive scope, and returns its result.
|
|
648
|
+
*
|
|
649
|
+
* This is useful when you need to access reactive data inside a reactive scope (like {@link Aberdeen | A})
|
|
650
|
+
* but do not want changes to that specific data to trigger a re-execute of the scope.
|
|
651
|
+
*
|
|
652
|
+
* Note: You may also use {@link Aberdeen.unproxy} to get to the raw underlying data structure, which can be used to similar effect.
|
|
653
|
+
*
|
|
654
|
+
* @param target - Either a function to execute, or an object (which may also be an Array or a Map) to index.
|
|
655
|
+
* @param key - Optional key/index to use when `target` is an object.
|
|
656
|
+
* @returns The result of the function call, or the value at `target[key]` when `target` is an object or `target.get(key)` when it's a Map.
|
|
657
|
+
*
|
|
658
|
+
* @example Peeking within observer
|
|
659
|
+
* ```typescript
|
|
660
|
+
* const $data = A.proxy({ a: 1, b: 2 });
|
|
661
|
+
* A(() => {
|
|
662
|
+
* // re-executes only when $data.a changes, because $data.b is peeked.
|
|
663
|
+
* const b = A.peek(() => $data.b);
|
|
664
|
+
* console.log(`A is ${$data.a}, B was ${b} when A changed.`);
|
|
665
|
+
* });
|
|
666
|
+
* $data.b = 3; // Does not trigger console.log
|
|
667
|
+
* $data.a = 2; // Triggers console.log (logs "A is 2, B was 3 when A changed.")
|
|
668
|
+
* ```
|
|
669
|
+
*
|
|
145
670
|
*/
|
|
671
|
+
peek<T extends object, K extends keyof T>(target: T, key: K): T[K];
|
|
672
|
+
peek<K, V>(target: Map<K, V>, key: K): V | undefined;
|
|
673
|
+
peek<T>(target: T[], key: number): T | undefined;
|
|
674
|
+
peek<T>(target: () => T): T;
|
|
675
|
+
/**
|
|
676
|
+
* Creates a reactive proxy around the given data.
|
|
677
|
+
*
|
|
678
|
+
* Reading properties from the returned proxy within a reactive scope (like one created by
|
|
679
|
+
* {@link Aberdeen | A} or {@link Aberdeen.derive}) establishes a subscription. Modifying properties *through*
|
|
680
|
+
* the proxy will notify subscribed scopes, causing them to re-execute.
|
|
681
|
+
*
|
|
682
|
+
* - Plain objects, arrays, Maps, and Sets are wrapped in a standard JavaScript `Proxy` that intercepts
|
|
683
|
+
* property access and mutations, but otherwise works like the underlying data.
|
|
684
|
+
* - Primitives (string, number, boolean, null, undefined) are wrapped in an object
|
|
685
|
+
* `{ value: T }` which is then proxied. Access the primitive via the `.value` property.
|
|
686
|
+
* - Promises are represented by proxied objects `{ busy: boolean, value?: T, error?: any }`.
|
|
687
|
+
* Initially, `busy` is `true`. When the promise resolves, `value` is set and `busy`
|
|
688
|
+
* is set to `false`. If the promise is rejected, `error` is set and `busy` is also
|
|
689
|
+
* set to `false`.
|
|
690
|
+
*
|
|
691
|
+
* Use {@link Aberdeen.unproxy} to get the original underlying data back.
|
|
692
|
+
* By convention in the examples below, local variables that hold proxied values are prefixed with `$`.
|
|
693
|
+
*
|
|
694
|
+
* @param target - The object, array, Map, Set, or primitive value to make reactive.
|
|
695
|
+
* @returns A reactive proxy wrapping the target data.
|
|
696
|
+
* @template T - The type of the data being proxied.
|
|
697
|
+
*
|
|
698
|
+
* @example Object
|
|
699
|
+
* ```javascript
|
|
700
|
+
* const $state = A.proxy({ count: 0, message: 'Hello' });
|
|
701
|
+
* A(() => console.log($state.message)); // Subscribes to message
|
|
702
|
+
* setTimeout(() => $state.message = 'World', 1000); // Triggers the observing function
|
|
703
|
+
* setTimeout(() => $state.count++, 2000); // Triggers nothing
|
|
704
|
+
* ```
|
|
705
|
+
*
|
|
706
|
+
* @example Array
|
|
707
|
+
* ```javascript
|
|
708
|
+
* const $items = A.proxy(['a', 'b']);
|
|
709
|
+
* A(() => console.log($items.length)); // Subscribes to length
|
|
710
|
+
* setTimeout(() => $items.push('c'), 2000); // Triggers the observing function
|
|
711
|
+
* ```
|
|
712
|
+
*
|
|
713
|
+
* @example Primitive
|
|
714
|
+
* ```javascript
|
|
715
|
+
* const $name = A.proxy('Aberdeen');
|
|
716
|
+
* A(() => console.log($name.value)); // Subscribes to value
|
|
717
|
+
* setTimeout(() => $name.value = 'UI', 2000); // Triggers the observing function
|
|
718
|
+
* ```
|
|
719
|
+
*
|
|
720
|
+
* @example Set
|
|
721
|
+
* ```javascript
|
|
722
|
+
* const $tags = A.proxy(new Set(['ui', 'tiny']));
|
|
723
|
+
* A(() => console.log($tags.has('ui'), $tags.size));
|
|
724
|
+
* setTimeout(() => $tags.add('fast'), 1000);
|
|
725
|
+
* ```
|
|
726
|
+
*
|
|
727
|
+
* @example Class instance
|
|
728
|
+
* ```typescript
|
|
729
|
+
* class Widget {
|
|
730
|
+
* constructor(public name: string, public width: number, public height: number) {}
|
|
731
|
+
* grow() { this.width *= 2; }
|
|
732
|
+
* toString() { return `${this.name}Widget (${this.width}x${this.height})`; }
|
|
733
|
+
* }
|
|
734
|
+
* let $graph: Widget = A.proxy(new Widget('Graph', 200, 100));
|
|
735
|
+
* A(() => console.log(''+$graph));
|
|
736
|
+
* setTimeout(() => $graph.grow(), 2000);
|
|
737
|
+
* setTimeout(() => $graph.grow(), 4000);
|
|
738
|
+
* ```
|
|
739
|
+
*/
|
|
740
|
+
proxy<T extends any>(target: Promise<T>): PromiseProxy<T>;
|
|
741
|
+
proxy<T extends any>(target: Array<T>): Array<T extends number ? number : T extends string ? string : T extends boolean ? boolean : T>;
|
|
742
|
+
proxy<T extends object>(target: T): T;
|
|
743
|
+
proxy<T extends any>(target: T): ValueRef<T extends number ? number : T extends string ? string : T extends boolean ? boolean : T>;
|
|
744
|
+
/**
|
|
745
|
+
* Creates a reactive reference (`{ value: T }`-like object) to a specific value
|
|
746
|
+
* within a proxied object or array.
|
|
747
|
+
*
|
|
748
|
+
* This is primarily used for the `bind` property in {@link Aberdeen | A} to create two-way data bindings
|
|
749
|
+
* with form elements, and for passing a reactive property to any of the {@link Aberdeen | A} key-value pairs.
|
|
750
|
+
*
|
|
751
|
+
* Reading `ref.value` accesses the property from the underlying proxy (and subscribes the current scope).
|
|
752
|
+
* Assigning to `ref.value` updates the property in the underlying proxy (triggering reactive updates).
|
|
753
|
+
*
|
|
754
|
+
* @param target - The reactive proxy (created by {@link Aberdeen.proxy}) containing the target property.
|
|
755
|
+
* @param index - The key (for objects) or index (for arrays) of the property to reference.
|
|
756
|
+
* @returns A reference object with a `value` property linked to the specified proxy property.
|
|
757
|
+
*
|
|
758
|
+
* @example
|
|
759
|
+
* ```javascript
|
|
760
|
+
* const $formData = A.proxy({ color: 'orange', velocity: 42 });
|
|
761
|
+
*
|
|
762
|
+
* // Usage with `bind`
|
|
763
|
+
* A('input type=text bind=', A.ref($formData, 'color'));
|
|
764
|
+
*
|
|
765
|
+
* // Usage as a dynamic property, causes a TextNode with just the name to be created and live-updated
|
|
766
|
+
* A('p text="Selected color: " text=', A.ref($formData, 'color'), 'color:', A.ref($formData, 'color'));
|
|
767
|
+
*
|
|
768
|
+
* // Changes are actually stored in $formData - this causes logs like `{color: "Blue", velocity 42}`
|
|
769
|
+
* A(() => console.log($formData))
|
|
770
|
+
* ```
|
|
771
|
+
*/
|
|
772
|
+
ref<T extends TargetType, K extends keyof T>(target: T, index: K): ValueRef<T[K]>;
|
|
773
|
+
/**
|
|
774
|
+
* Forces the immediate and synchronous execution of all pending reactive updates.
|
|
775
|
+
*
|
|
776
|
+
* Normally, changes to observed data sources (like proxied objects or arrays)
|
|
777
|
+
* are processed asynchronously in a batch after a brief timeout (0ms). This function
|
|
778
|
+
* allows you to bypass the timeout and process the update queue immediately.
|
|
779
|
+
*
|
|
780
|
+
* This can be useful in specific scenarios where you need the DOM to be updated
|
|
781
|
+
* synchronously.
|
|
782
|
+
*
|
|
783
|
+
* This function is re-entrant, meaning it is safe to call `runQueue` from within
|
|
784
|
+
* a function that is itself being executed as part of an update cycle triggered
|
|
785
|
+
* by a previous (or the same) `runQueue` call.
|
|
786
|
+
*
|
|
787
|
+
* @example
|
|
788
|
+
* ```typescript
|
|
789
|
+
* const $data = A.proxy("before");
|
|
790
|
+
*
|
|
791
|
+
* A('#', $data);
|
|
792
|
+
* console.log(1, document.body.innerHTML); // before
|
|
793
|
+
*
|
|
794
|
+
* // Make an update that should cause the DOM to change.
|
|
795
|
+
* $data.value = "after";
|
|
796
|
+
*
|
|
797
|
+
* // Normally, the DOM update would happen after a timeout.
|
|
798
|
+
* // But this causes an immediate update:
|
|
799
|
+
* A.runQueue();
|
|
800
|
+
*
|
|
801
|
+
* console.log(2, document.body.innerHTML); // after
|
|
802
|
+
* ```
|
|
803
|
+
*/
|
|
804
|
+
runQueue(): void;
|
|
805
|
+
/**
|
|
806
|
+
* Sets a custom error handler function for errors that occur asynchronously
|
|
807
|
+
* within reactive scopes (e.g., during updates triggered by proxy changes in
|
|
808
|
+
* {@link Aberdeen.derive} or {@link Aberdeen | A} render functions).
|
|
809
|
+
*
|
|
810
|
+
* The default handler logs the error to `console.error` and adds a simple
|
|
811
|
+
* 'Error' message div to the DOM at the location where the error occurred (if possible).
|
|
812
|
+
*
|
|
813
|
+
* Your handler can provide custom logging, UI feedback, or suppress the default
|
|
814
|
+
* error message.
|
|
815
|
+
*
|
|
816
|
+
* @param handler - A function that accepts the `Error` object.
|
|
817
|
+
* - Return `false` to prevent adding an error message to the DOM.
|
|
818
|
+
* - Return `true` or `undefined` (or throw) to allow the error messages to be added to the DOM.
|
|
819
|
+
*
|
|
820
|
+
* @example Custom Logging and Suppressing Default Message
|
|
821
|
+
* ```typescript
|
|
822
|
+
* A.setErrorHandler(error => {
|
|
823
|
+
* console.warn('Aberdeen render error:', error.message);
|
|
824
|
+
* // Log to error reporting service
|
|
825
|
+
* // myErrorReporter.log(error);
|
|
826
|
+
*
|
|
827
|
+
* try {
|
|
828
|
+
* // Attempt to show a custom message in the UI
|
|
829
|
+
* A('div#Oops, something went wrong!', errorClass);
|
|
830
|
+
* } catch (e) {
|
|
831
|
+
* // Ignore errors during error handling itself
|
|
832
|
+
* }
|
|
833
|
+
*
|
|
834
|
+
* return false; // Suppress default console log and DOM error message
|
|
835
|
+
* });
|
|
836
|
+
*
|
|
837
|
+
* // Styling for our custom error message
|
|
838
|
+
* const errorClass = A.insertCss('background-color:#e31f00 display:inline-block color:white r:3px padding: 2px 4px;');
|
|
839
|
+
*
|
|
840
|
+
* // Cause an error within a render scope.
|
|
841
|
+
* A('div.box', () => {
|
|
842
|
+
* // Will cause our error handler to insert an error message within the box
|
|
843
|
+
* noSuchFunction();
|
|
844
|
+
* })
|
|
845
|
+
* ```
|
|
846
|
+
*/
|
|
847
|
+
setErrorHandler(handler?: (error: Error) => boolean | undefined): void;
|
|
848
|
+
/**
|
|
849
|
+
* Initializes `cssVars[0]` through `cssVars[12]` with an exponential spacing scale.
|
|
850
|
+
*
|
|
851
|
+
* The scale is calculated as `2^(n-3) * base`, providing values from `0.25 * base` to `512 * base`.
|
|
852
|
+
*
|
|
853
|
+
* @param base - The base size for the spacing scale that will apply to `cssVars[3]`. Every step up the scale will double this, while every step down will halve it. Defaults to 1.
|
|
854
|
+
* @param unit - The CSS unit to use, like 'rem', 'em', or 'px'. Defaults to 'rem'.
|
|
855
|
+
*
|
|
856
|
+
* @example
|
|
857
|
+
* ```javascript
|
|
858
|
+
* import A from 'aberdeen';
|
|
859
|
+
* // Use default scale (0.25rem to 512rem)
|
|
860
|
+
* A.setSpacingCssVars();
|
|
861
|
+
*
|
|
862
|
+
* // Use custom base size
|
|
863
|
+
* A.setSpacingCssVars(16, 'px'); // 4px to 8192px
|
|
864
|
+
*
|
|
865
|
+
* // Use em units
|
|
866
|
+
* A.setSpacingCssVars(1, 'em'); // 0.25em to 512em
|
|
867
|
+
*
|
|
868
|
+
* // Show the last generated spacing values
|
|
869
|
+
* A.onEach(A.cssVars, (value, key) => {
|
|
870
|
+
* A(`div #${key} → ${value}`)
|
|
871
|
+
* }, (value, key) => parseInt(key)); // Numeric sort
|
|
872
|
+
* ```
|
|
873
|
+
*/
|
|
874
|
+
setSpacingCssVars(base?: number, unit?: string): void;
|
|
875
|
+
/**
|
|
876
|
+
* Removes all Aberdeen-managed DOM nodes and stops all active reactive scopes
|
|
877
|
+
* (created by {@link Aberdeen.mount}, {@link Aberdeen.derive}, {@link Aberdeen | A} with functions, etc.).
|
|
878
|
+
*
|
|
879
|
+
* This effectively cleans up the entire Aberdeen application state. Aside from in
|
|
880
|
+
* automated tests, there should probably be little reason to call this function.
|
|
881
|
+
*/
|
|
882
|
+
unmountAll(): void;
|
|
883
|
+
/**
|
|
884
|
+
* Returns the original, underlying data target from a reactive proxy created by {@link Aberdeen.proxy}.
|
|
885
|
+
* If the input `target` is not a proxy, it is returned directly.
|
|
886
|
+
*
|
|
887
|
+
* This is useful when you want to avoid triggering subscriptions during read operations or
|
|
888
|
+
* re-executes during write operations. Using {@link Aberdeen.peek} is an alternative way to achieve this.
|
|
889
|
+
*
|
|
890
|
+
* @param target - A proxied object, array, or any other value.
|
|
891
|
+
* @returns The underlying (unproxied) data, or the input value if it wasn't a proxy.
|
|
892
|
+
* @template T - The type of the target.
|
|
893
|
+
*
|
|
894
|
+
* @example
|
|
895
|
+
* ```typescript
|
|
896
|
+
* const $user = A.proxy({ name: 'Frank' });
|
|
897
|
+
* const rawUser = A.unproxy($user);
|
|
898
|
+
*
|
|
899
|
+
* // Log reactively
|
|
900
|
+
* A(() => console.log('proxied', $user.name));
|
|
901
|
+
* // The following will only ever log once, as we're not subscribing to any observable
|
|
902
|
+
* A(() => console.log('unproxied', rawUser.name));
|
|
903
|
+
*
|
|
904
|
+
* // This cause the first log to run again:
|
|
905
|
+
* setTimeout(() => $user.name += '!', 1000);
|
|
906
|
+
*
|
|
907
|
+
* // This doesn't cause any new logs:
|
|
908
|
+
* setTimeout(() => rawUser.name += '?', 2000);
|
|
909
|
+
*
|
|
910
|
+
* // Both $user and rawUser end up as `{name: 'Frank!?'}`
|
|
911
|
+
* setTimeout(() => {
|
|
912
|
+
* console.log('final proxied', $user)
|
|
913
|
+
* console.log('final unproxied', rawUser)
|
|
914
|
+
* }, 3000);
|
|
915
|
+
* ```
|
|
916
|
+
*/
|
|
917
|
+
unproxy<T>(target: T): T;
|
|
918
|
+
}
|
|
919
|
+
/** The shape returned by {@link Aberdeen.ref}: an object whose single `value` property is reactive. */
|
|
920
|
+
export interface ValueRef<T> {
|
|
921
|
+
value: T;
|
|
922
|
+
}
|
|
923
|
+
/** When `proxy` is called with a Promise, the returned object has this shape. */
|
|
924
|
+
export interface PromiseProxy<T> {
|
|
925
|
+
/** True while the promise is pending, false once it has resolved or rejected. */
|
|
926
|
+
busy: boolean;
|
|
927
|
+
/** If the promise has resolved, the resolved value. */
|
|
928
|
+
value?: T;
|
|
929
|
+
/** If the promise has rejected, the rejection error. */
|
|
146
930
|
error?: any;
|
|
147
931
|
}
|
|
148
|
-
export declare function proxy<T extends any>(target: Promise<T>): PromiseProxy<T>;
|
|
149
|
-
export declare function proxy<T extends any>(target: Array<T>): Array<T extends number ? number : T extends string ? string : T extends boolean ? boolean : T>;
|
|
150
|
-
export declare function proxy<T extends object>(target: T): T;
|
|
151
|
-
export declare function proxy<T extends any>(target: T): ValueRef<T extends number ? number : T extends string ? string : T extends boolean ? boolean : T>;
|
|
152
|
-
/**
|
|
153
|
-
* Returns the original, underlying data target from a reactive proxy created by {@link proxy}.
|
|
154
|
-
* If the input `target` is not a proxy, it is returned directly.
|
|
155
|
-
*
|
|
156
|
-
* This is useful when you want to avoid triggering subscriptions during read operations or
|
|
157
|
-
* re-executes during write operations. Using {@link peek} is an alternative way to achieve this.
|
|
158
|
-
*
|
|
159
|
-
* @param target - A proxied object, array, or any other value.
|
|
160
|
-
* @returns The underlying (unproxied) data, or the input value if it wasn't a proxy.
|
|
161
|
-
* @template T - The type of the target.
|
|
162
|
-
*
|
|
163
|
-
* @example
|
|
164
|
-
* ```typescript
|
|
165
|
-
* const $user = A.proxy({ name: 'Frank' });
|
|
166
|
-
* const rawUser = A.unproxy($user);
|
|
167
|
-
*
|
|
168
|
-
* // Log reactively
|
|
169
|
-
* A(() => console.log('proxied', $user.name));
|
|
170
|
-
* // The following will only ever log once, as we're not subscribing to any observable
|
|
171
|
-
* A(() => console.log('unproxied', rawUser.name));
|
|
172
|
-
*
|
|
173
|
-
* // This cause the first log to run again:
|
|
174
|
-
* setTimeout(() => $user.name += '!', 1000);
|
|
175
|
-
*
|
|
176
|
-
* // This doesn't cause any new logs:
|
|
177
|
-
* setTimeout(() => rawUser.name += '?', 2000);
|
|
178
|
-
*
|
|
179
|
-
* // Both $user and rawUser end up as `{name: 'Frank!?'}`
|
|
180
|
-
* setTimeout(() => {
|
|
181
|
-
* console.log('final proxied', $user)
|
|
182
|
-
* console.log('final unproxied', rawUser)
|
|
183
|
-
* }, 3000);
|
|
184
|
-
* ```
|
|
185
|
-
*/
|
|
186
|
-
export declare function unproxy<T>(target: T): T;
|
|
187
|
-
/**
|
|
188
|
-
* Recursively copies properties or array items from `src` to `dst`.
|
|
189
|
-
* It's designed to work efficiently with reactive proxies created by {@link proxy}.
|
|
190
|
-
*
|
|
191
|
-
* - **Minimizes Updates:** When copying between objects/arrays (proxied or not), if a nested object
|
|
192
|
-
* exists in `dst` with the same constructor as the corresponding object in `src`, `copy`
|
|
193
|
-
* will recursively copy properties into the existing `dst` object instead of replacing it.
|
|
194
|
-
* This minimizes change notifications for reactive (proxied) destinations.
|
|
195
|
-
* - **Fast with Proxies:** When copying to/from proxied objects, `copy` uses Aberdeen internals
|
|
196
|
-
* to speed things up (compared to a non-Aberdeen-aware deep copy).
|
|
197
|
-
*
|
|
198
|
-
* @param dst - The destination object/array/Map (proxied or unproxied).
|
|
199
|
-
* @param src - The source object/array/Map (proxied or unproxied). It won't be modified.
|
|
200
|
-
* @template T - The type of the objects being copied.
|
|
201
|
-
* @returns `true` if any changes were made to `dst`, or `false` if not.
|
|
202
|
-
* @throws Error if attempting to copy an array into a non-array or vice versa.
|
|
203
|
-
*
|
|
204
|
-
* @example Basic Copy
|
|
205
|
-
* ```typescript
|
|
206
|
-
* const $source = A.proxy({ a: 1, b: { c: 2 } });
|
|
207
|
-
* const $dest = A.proxy({ b: { d: 3 } });
|
|
208
|
-
* A.copy($dest, $source);
|
|
209
|
-
* console.log($dest); // proxy({ a: 1, b: { c: 2 } })
|
|
210
|
-
* A.copy($dest, 'b', { e: 4 });
|
|
211
|
-
* console.log($dest); // proxy({ a: 1, b: { e: 4 } })
|
|
212
|
-
* ```
|
|
213
|
-
*/
|
|
214
|
-
export declare function copy<T extends object>(dst: T, src: T): boolean;
|
|
215
|
-
/**
|
|
216
|
-
* Like above, but copies `src` into `dst[dstKey]`. This is useful if you're unsure if dst[dstKey]
|
|
217
|
-
* already exists (as the right type of object) or if you don't want to subscribe to dst[dstKey].
|
|
218
|
-
*
|
|
219
|
-
* @param dstKey - Optional key in `dst` to copy into.
|
|
220
|
-
*/
|
|
221
|
-
export declare function copy<T extends object>(dst: T, dstKey: keyof T, src: T[typeof dstKey]): boolean;
|
|
222
|
-
/**
|
|
223
|
-
* Like {@link copy}, but uses merge semantics. Properties in `dst` not present in `src` are kept.
|
|
224
|
-
* `null`/`undefined` in `src` delete properties in `dst`.
|
|
225
|
-
*
|
|
226
|
-
* @example Basic merge
|
|
227
|
-
* ```typescript
|
|
228
|
-
* const source = { b: { c: 99 }, d: undefined }; // d: undefined will delete
|
|
229
|
-
* const $dest = A.proxy({ a: 1, b: { x: 5 }, d: 4 });
|
|
230
|
-
* A.merge($dest, source);
|
|
231
|
-
* A.merge($dest, 'b', { y: 6 }); // merge into $dest.b
|
|
232
|
-
* A.merge($dest, 'c', { z: 7 }); // $dest.c doesn't exist yet, so it will just be assigned
|
|
233
|
-
* console.log($dest); // proxy({ a: 1, b: { c: 99, x: 5, y: 6 }, c: { z: 7 } })
|
|
234
|
-
* ```
|
|
235
|
-
*
|
|
236
|
-
*/
|
|
237
|
-
export declare function merge<T extends object>(dst: T, value: Partial<T>): boolean;
|
|
238
|
-
export declare function merge<T extends object>(dst: T, dstKey: keyof T, value: Partial<T[typeof dstKey]>): boolean;
|
|
239
|
-
/**
|
|
240
|
-
* A symbol that controls how Aberdeen handles an object in copy operations and proxy wrapping.
|
|
241
|
-
*
|
|
242
|
-
* The **presence** of this symbol (regardless of its value) prevents deep-copying: the object is
|
|
243
|
-
* stored and passed by reference in {@link clone} and {@link copy}.
|
|
244
|
-
*
|
|
245
|
-
* The **value** of the symbol controls proxy wrapping when the object is read from reactive state:
|
|
246
|
-
* - **Truthy** (e.g. `true`): the object is fully opaque — it is not wrapped in a proxy, so its
|
|
247
|
-
* properties are not observable. Use this for objects that break when proxied (e.g. class instances
|
|
248
|
-
* with internal slots, Promises) or that must be invisible to Aberdeen's reactive system.
|
|
249
|
-
* - **Falsy** (e.g. `false`): the object is still wrapped in a proxy, so reads on its properties
|
|
250
|
-
* create reactive dependencies as normal — only deep-copying is suppressed.
|
|
251
|
-
*/
|
|
252
|
-
export declare const OPAQUE: unique symbol;
|
|
253
|
-
/**
|
|
254
|
-
* Use {@link OPAQUE} instead. This is an alias kept for backward compatibility.
|
|
255
|
-
*
|
|
256
|
-
* @deprecated
|
|
257
|
-
*/
|
|
258
|
-
export declare const NO_COPY: symbol;
|
|
259
|
-
/**
|
|
260
|
-
* A reactive object containing CSS variable definitions.
|
|
261
|
-
*
|
|
262
|
-
* Any property you assign to `cssVars` becomes available as a CSS custom property throughout your application.
|
|
263
|
-
*
|
|
264
|
-
* Use {@link setSpacingCssVars} to optionally initialize `cssVars[1]` through `cssVars[12]` with an exponential spacing scale.
|
|
265
|
-
*
|
|
266
|
-
* When you reference a CSS variable in Aberdeen using the `$` prefix (e.g., `$primary`), it automatically resolves to `var(--primary)`.
|
|
267
|
-
* For numeric keys (which can't be used directly as CSS custom property names), Aberdeen prefixes them with `m` (e.g., `$3` becomes `var(--m3)`).
|
|
268
|
-
*
|
|
269
|
-
* When you add the first property to cssVars, Aberdeen automatically creates a reactive `<style>` tag in `<head>`
|
|
270
|
-
* containing the `:root` CSS custom property declarations. The style tag is automatically removed if cssVars becomes empty.
|
|
271
|
-
*
|
|
272
|
-
* @example
|
|
273
|
-
* ```javascript
|
|
274
|
-
* import A from 'aberdeen';
|
|
275
|
-
*
|
|
276
|
-
* // Optionally initialize spacing scale
|
|
277
|
-
* A.setSpacingCssVars(); // Uses defaults: base=1, unit='rem'
|
|
278
|
-
*
|
|
279
|
-
* // Define custom colors - style tag is automatically created
|
|
280
|
-
* A.cssVars.primary = '#3b82f6';
|
|
281
|
-
* A.cssVars.danger = '#ef4444';
|
|
282
|
-
*
|
|
283
|
-
* // Use in elements with the $ prefix
|
|
284
|
-
* A('button bg:$primary fg:white #I'm a primary button');
|
|
285
|
-
*
|
|
286
|
-
* // Use spacing (if setSpacingCssVars() was called)
|
|
287
|
-
* A('hr mt:$3'); // Sets margin-top to var(--m3)
|
|
288
|
-
* ```
|
|
289
|
-
*/
|
|
290
|
-
export declare const cssVars: Record<string, string>;
|
|
291
|
-
/**
|
|
292
|
-
* Initializes `cssVars[0]` through `cssVars[12]` with an exponential spacing scale.
|
|
293
|
-
*
|
|
294
|
-
* The scale is calculated as `2^(n-3) * base`, providing values from `0.25 * base` to `512 * base`.
|
|
295
|
-
*
|
|
296
|
-
* @param base - The base size for the spacing scale that will apply to `cssVars[3]`. Every step up the scale will double this, while every step down will halve it. Defaults to 1.
|
|
297
|
-
* @param unit - The CSS unit to use, like 'rem', 'em', or 'px'. Defaults to 'rem'.
|
|
298
|
-
*
|
|
299
|
-
* @example
|
|
300
|
-
* ```javascript
|
|
301
|
-
* import A from 'aberdeen';
|
|
302
|
-
* // Use default scale (0.25rem to 512rem)
|
|
303
|
-
* A.setSpacingCssVars();
|
|
304
|
-
*
|
|
305
|
-
* // Use custom base size
|
|
306
|
-
* A.setSpacingCssVars(16, 'px'); // 4px to 8192px
|
|
307
|
-
*
|
|
308
|
-
* // Use em units
|
|
309
|
-
* A.setSpacingCssVars(1, 'em'); // 0.25em to 512em
|
|
310
|
-
*
|
|
311
|
-
* // Show the last generated spacing values
|
|
312
|
-
* A.onEach(A.cssVars, (value, key) => {
|
|
313
|
-
* A(`div #${key} → ${value}`)
|
|
314
|
-
* }, (value, key) => parseInt(key)); // Numeric sort
|
|
315
|
-
* ```
|
|
316
|
-
*/
|
|
317
|
-
export declare function setSpacingCssVars(base?: number, unit?: string): void;
|
|
318
|
-
/**
|
|
319
|
-
* Returns whether the user's browser prefers a dark color scheme.
|
|
320
|
-
*
|
|
321
|
-
* This function is reactive - scopes that call it will re-execute when the
|
|
322
|
-
* browser's color scheme preference changes (via the `prefers-color-scheme` media query).
|
|
323
|
-
*
|
|
324
|
-
* Use this in combination with {@link A | A} and {@link cssVars} to implement theme switching:
|
|
325
|
-
*
|
|
326
|
-
* @returns `true` if the browser prefers dark mode, `false` if it prefers light mode.
|
|
327
|
-
*
|
|
328
|
-
* @example
|
|
329
|
-
* ```javascript
|
|
330
|
-
* import A from 'aberdeen';
|
|
331
|
-
*
|
|
332
|
-
* // Reactively set colors based on browser preference
|
|
333
|
-
* A(() => {
|
|
334
|
-
* A.cssVars.bg = A.darkMode() ? '#1a1a1a' : '#ffffff';
|
|
335
|
-
* A.cssVars.fg = A.darkMode() ? '#e5e5e5' : '#000000';
|
|
336
|
-
* });
|
|
337
|
-
*
|
|
338
|
-
* A('div bg:$bg fg:$fg p:1rem #Colors change based on system dark mode preference');
|
|
339
|
-
* ```
|
|
340
|
-
*/
|
|
341
|
-
export declare function darkMode(): boolean;
|
|
342
|
-
/**
|
|
343
|
-
* Clone an (optionally proxied) object or array.
|
|
344
|
-
*
|
|
345
|
-
* @param src The object or array to clone. If it is proxied, `clone` will subscribe to any changes to the (nested) data structure.
|
|
346
|
-
* @template T - The type of the objects being copied.
|
|
347
|
-
* @returns A new unproxied array or object (of the same type as `src`), containing a deep copy of `src`.
|
|
348
|
-
*/
|
|
349
|
-
export declare function clone<T extends object>(src: T): T;
|
|
350
|
-
/**
|
|
351
|
-
* Creates a reactive reference (`{ value: T }`-like object) to a specific value
|
|
352
|
-
* within a proxied object or array.
|
|
353
|
-
*
|
|
354
|
-
* This is primarily used for the `bind` property in {@link A | A} to create two-way data bindings
|
|
355
|
-
* with form elements, and for passing a reactive property to any of the {@link A | A} key-value pairs.
|
|
356
|
-
*
|
|
357
|
-
* Reading `ref.value` accesses the property from the underlying proxy (and subscribes the current scope).
|
|
358
|
-
* Assigning to `ref.value` updates the property in the underlying proxy (triggering reactive updates).
|
|
359
|
-
*
|
|
360
|
-
* @param target - The reactive proxy (created by {@link proxy}) containing the target property.
|
|
361
|
-
* @param index - The key (for objects) or index (for arrays) of the property to reference.
|
|
362
|
-
* @returns A reference object with a `value` property linked to the specified proxy property.
|
|
363
|
-
*
|
|
364
|
-
* @example
|
|
365
|
-
* ```javascript
|
|
366
|
-
* const $formData = A.proxy({ color: 'orange', velocity: 42 });
|
|
367
|
-
*
|
|
368
|
-
* // Usage with `bind`
|
|
369
|
-
* A('input type=text bind=', A.ref($formData, 'color'));
|
|
370
|
-
*
|
|
371
|
-
* // Usage as a dynamic property, causes a TextNode with just the name to be created and live-updated
|
|
372
|
-
* A('p text="Selected color: " text=', A.ref($formData, 'color'), 'color:', A.ref($formData, 'color'));
|
|
373
|
-
*
|
|
374
|
-
* // Changes are actually stored in $formData - this causes logs like `{color: "Blue", velocity 42}`
|
|
375
|
-
* A(() => console.log($formData))
|
|
376
|
-
* ```
|
|
377
|
-
*/
|
|
378
|
-
export declare function ref<T extends TargetType, K extends keyof T>(target: T, index: K): ValueRef<T[K]>;
|
|
379
|
-
/**
|
|
380
|
-
* Make the `create` and `destroy` special properties no-ops.
|
|
381
|
-
*
|
|
382
|
-
* This is useful from within automated testing environments, where the transitioning
|
|
383
|
-
* new and lingering old elements may make writing reliable selectors difficult.
|
|
384
|
-
*
|
|
385
|
-
* As this is only intended for testing, there's no way to re-enable the special properties
|
|
386
|
-
* once disabled.
|
|
387
|
-
*/
|
|
388
|
-
export declare function disableCreateDestroy(): void;
|
|
389
|
-
/**
|
|
390
|
-
* The core function for building reactive user interfaces in Aberdeen. It creates and inserts new DOM elements
|
|
391
|
-
* and sets attributes/properties/event listeners on DOM elements. It does so in a reactive way, meaning that
|
|
392
|
-
* changes will be (mostly) undone when the current *scope* is destroyed or will be re-execute.
|
|
393
|
-
*
|
|
394
|
-
* @param {...(string | function | object | false | undefined | null)} args - Any number of arguments can be given. How they're interpreted depends on their types:
|
|
395
|
-
*
|
|
396
|
-
* ### String arguments
|
|
397
|
-
* Strings can be used to create and insert new elements, set classnames for the *current* element, and add text to the current element.
|
|
398
|
-
* The format of a string is: (**tag** | `.` **class** | **key**[=:]**val** | **key**[=:]"**val containing spaces**")* ('#' **text** | **key**[=:])?
|
|
399
|
-
*
|
|
400
|
-
* So a string may consist of any number of...
|
|
401
|
-
* - **tag** elements, like `h1` or `div`. These elements are created, added to the *current* element, and become the new *current* element for the rest of this `A` function execution.
|
|
402
|
-
* - CSS classes prefixed by `.` characters. These classes will be added to the *current* element. Optionally, CSS classes can be appended to a **tag** without a space. So both `div.myclass` and `div .myclass` are valid and do the same thing.
|
|
403
|
-
* - Property key/value pairs, like `type=password`, `placeholder="Your name"` or `data-id=123`. When the value contains spaces, it needs to be quoted with either "double quotes", 'single quotes' or \`backticks\`. Quotes within quoted values cannot be escaped (see the next rule for a solution). Key/value pairs will be handled according to *Property rules* below, but with the caveat that values can only be strings.
|
|
404
|
-
* - CSS key/value pairs using two syntaxes:
|
|
405
|
-
* - **Short form** `key:value` (no space after colon): The value ends at the next whitespace. Example: `m:$3 bg:red r:8px`
|
|
406
|
-
* - **Long form** `key: value;` (space after colon): The value continues until a semicolon. Example: `box-shadow: 2px 0 6px black; transition: all 0.3s ease;`
|
|
407
|
-
*
|
|
408
|
-
* Both forms support CSS shortcuts (see below). You can mix them: `m:$3 box-shadow: 0 2px 4px rgba(0,0,0,0.2); bg:$cardBg`
|
|
409
|
-
* The elements must be separated by spaces, except before a `.cssClass` if it is preceded by either **tag** or another CSS class.
|
|
410
|
-
*
|
|
411
|
-
* And a string may end in...
|
|
412
|
-
* - A '#' followed by text, which will be added as a `TextNode` to the *current* element. The text ranges til the end of the string, and may contain any characters, including spaces and quotes.
|
|
413
|
-
* - A key followed by an '=' character, in which case the value is expected as a separate argument. The key/value pair is set according to the *Property rules* below. This is useful when the value is not a string or contains spaces or user data. Example: `A('button text="Click me" click=', () => alert('Clicked!'))` or `A('input.value=', someUserData, "placeholder=", "Type your stuff")`. In case the value is a proxied object, its `.value` property will be applied reactively without needing to rerender the parent scope.
|
|
414
|
-
* - A key followed by a ':' character (with no value), in which case the value is expected as a separate argument. The value is treated as a CSS value to be set inline on the *current* element. Example: `A('div margin-top:', someValueInPx)`. In case the value is a proxied object, its `.value` property will be applied reactively without needing to rerender the parent scope.
|
|
415
|
-
*
|
|
416
|
-
* ### Function arguments
|
|
417
|
-
* When a function (without arguments nor a return value) is passed in, it will be reactively executed in its own observer scope, preserving the *current* element. So any `A()` invocations within this function will add child elements to or set properties on that element. If the function reads observable data, and that data is changed later on, the function we re-execute (after side effects, such as DOM modifications through `A`, have been cleaned - see also {@link clean}).
|
|
418
|
-
*
|
|
419
|
-
* ### Object arguments
|
|
420
|
-
* When an object is passed in, its key-value pairs are used to modify the *current* element according to the *Property rules* below, *unless* the key starts with a `$` character, in which case that character is stripped of and the key/value pair is treated as a CSS property, subject to the *CSS shortcuts* below. In case a value is a proxied object, its `.value` property will be applied reactively without needing to rerender the parent scope. In most cases, the string notation (`key=` and `key:`) is preferred over this object notation, for readability.
|
|
421
|
-
*
|
|
422
|
-
* ### DOM node arguments
|
|
423
|
-
* When a DOM Node (Element or TextNode) is passed in, it is added as a child to the *current* element. If the Node is an Element, it becomes the new *current* element for the rest of this `A` function execution.
|
|
424
|
-
*
|
|
425
|
-
* ### Property rules
|
|
426
|
-
* - **Attribute:** The common case is setting the value as an HTML attribute named key. For example `A('input placeholder=Name')` results in `<input placeholder="Name">`.
|
|
427
|
-
* - **Event listener:** If the value is a `function` it is set as an event listener for the event with the name given by the key. For example: A('button text=Press! click=', () => alert('Clicked!'))`. The event listener will be removed when the current scope is destroyed.
|
|
428
|
-
* - **DOM property:** When the value is a boolean, or the key is `"value"` or `"selectedIndex"`, it is set on the `current` element as a DOM property instead of an HTML attribute. For example `A('checked=', true)` would do `el.checked = true` for the *current* element.
|
|
429
|
-
* - **Conditional CSS class:** If the key starts with a `.` character, its either added to or removed from the *current* element as a CSS class, based on the truthiness of the value. So `A('.hidden=', isHidden)` would toggle the `hidden` CSS class. This only works if the `=` is the last character of the string, and the next argument is the value. Its common for the value to be a proxied object, in which case its `.value` is reactively applied without needing to rerender the parent scope.
|
|
430
|
-
* - **Create transition:** When the key is `"create"`, the value will be added as a CSS class to the *current* element immediately, and then removed right after the browser has finished doing a layout pass. This behavior only triggers when the scope setting the `create` is the top-level scope being (re-)run. This allows for creation transitions, without triggering the transitions for deeply nested elements being drawn as part of a larger component. The string may also contain multiple dot-separated CSS classes, such as `.fade.grow`. The initial dot is optional. Alternatively, to allow for more complex transitions, the value may be a function that receives the `HTMLElement` being created as its only argument. It is *only* called if this is the top-level element being created in this scope run. See `transitions.ts` in the Aberdeen source code for some examples.
|
|
431
|
-
* - **Destroy transition:** When the key is `"destroy"` the value will be used to apply a CSS transition if the *current* element is later on removed from the DOM and is the top-level element to be removed. This happens as follows: actual removal from the DOM is delayed by 2 seconds, and in the mean-time the value string is added as a CSS class to the element, allowing for a deletion transition. The string may also contain multiple dot-separated CSS classes, such as `.fade.shrink`. The initial dot is optional. Alternatively, to allow for more complex transitions, the value may be a function that receives the `HTMLElement` to be removed from the DOM as its only argument. This function may perform any transitions and is then itself responsible for eventually removing the element from the DOM. See `transitions.ts` in the Aberdeen source code for some examples.
|
|
432
|
-
* - **Two-way data binding:** When the key is `"bind"` a two-way binding between the `.value` property of the given proxied object, and the *current* input element (`<input>`, `<select>` or `<textarea>`) is created. This is often used together with {@link ref}, in order to use properties other than `.value`.
|
|
433
|
-
* - **Text:**: If the key is `"text"`, the value will be appended as a `TextNode` to the *current* element. The same can also be done with the `#` syntax in string arguments, though `text=` allows additional properties to come after in the same string: `A('button text=Hello click=', alert)`.
|
|
434
|
-
* - **Unsafe HTML:** When the key is `"html"`, the value will be added as HTML to the *current* element. This should only be used in exceptional situations. Beware of XSS! Never use this with untrusted user data.
|
|
435
|
-
* - **Rich text:** When the key is `"rich"`, the value is parsed as simple markdown-like syntax and rendered as inline elements. Supports `*italic*`, `**bold**`, `` `code` ``, and `[link text](/path)`. All text content is safely escaped, making it suitable for user data (though links should be validated if untrusted). Example: `A('p rich="Click *here* for **more** info")`.
|
|
436
|
-
*
|
|
437
|
-
* ### CSS shortcuts
|
|
438
|
-
* For conciseness, Aberdeen supports some CSS shortcuts when setting CSS properties.
|
|
439
|
-
* | Shortcut | Expands to |
|
|
440
|
-
* |----------|------------|
|
|
441
|
-
* | `m`, `mt`, `mb`, `ml`, `mr` | `margin`, `margin-top`, `margin-bottom`, `margin-left`, `margin-right` |
|
|
442
|
-
* | `mv`, `mh` | Vertical (top+bottom) or horizontal (left+right) margins |
|
|
443
|
-
* | `p`, `pt`, `pb`, `pl`, `pr` | `padding`, `padding-top`, `padding-bottom`, `padding-left`, `padding-right` |
|
|
444
|
-
* | `pv`, `ph` | Vertical or horizontal padding |
|
|
445
|
-
* | `w`, `h` | `width`, `height` |
|
|
446
|
-
* | `bg` | `background` |
|
|
447
|
-
* | `fg` | `color` |
|
|
448
|
-
* | `r` | `border-radius` |
|
|
449
|
-
*
|
|
450
|
-
* Also, when the value is a string starting with `$`, it is treated as a reference to a CSS variable, expanding to `var(--variableName)`. For numeric variable names (which can't be used directly as CSS custom property names), Aberdeen prefixes them with `m`, so `$3` expands to `var(--m3)`. This is primarily intended for use with {@link setSpacingCssVars}, which initializes spacing variables named `0` through `12` with an exponential spacing scale.
|
|
451
|
-
*
|
|
452
|
-
* @returns The most inner DOM element that was created (not counting text nodes nor elements created by content functions), or the current element if no new element was created. You should normally not need to use the return value - use this function's DOM manipulation abilities instead. One valid use case is when integrating with non-Aberdeen code that requires a reference to a DOM element.
|
|
453
|
-
*
|
|
454
|
-
* @example Create Element
|
|
455
|
-
* ```typescript
|
|
456
|
-
* A('button.secondary.outline text=Submit color:red disabled=', false, 'click=', () => console.log('Clicked!'));
|
|
457
|
-
* ```
|
|
458
|
-
*
|
|
459
|
-
* We want to set `disabled` as a property instead of an attribute, so we must use the `key=` syntax in order to provide
|
|
460
|
-
* `false` as a boolean instead of a string.
|
|
461
|
-
*
|
|
462
|
-
* @example Create Nested Elements
|
|
463
|
-
* ```typescript
|
|
464
|
-
* let inputElement: Element = A('label text="Click me" input type=checkbox');
|
|
465
|
-
* // You should usually not touch raw DOM elements, unless when integrating
|
|
466
|
-
* // with non-Aberdeen code.
|
|
467
|
-
* console.log('DOM element:', inputElement);
|
|
468
|
-
* ```
|
|
469
|
-
*
|
|
470
|
-
* @example Content Functions & Reactive Scope
|
|
471
|
-
* ```typescript
|
|
472
|
-
* const $state = A.proxy({ count: 0 });
|
|
473
|
-
* A('div', () => { // Outer element
|
|
474
|
-
* // This scope re-renders when $state.count changes
|
|
475
|
-
* A(`p#Count is ${$state.count}`);
|
|
476
|
-
* A('button text=Increment click=', () => $state.count++);
|
|
477
|
-
* });
|
|
478
|
-
* ```
|
|
479
|
-
*
|
|
480
|
-
* @example Two-way Binding
|
|
481
|
-
* ```typescript
|
|
482
|
-
* const $user = A.proxy({ name: '' });
|
|
483
|
-
* A('input placeholder=Name bind=', A.ref($user, 'name'));
|
|
484
|
-
* A('h3', () => { // Reactive scope
|
|
485
|
-
* A(`#Hello ${$user.name || 'stranger'}`);
|
|
486
|
-
* });
|
|
487
|
-
* ```
|
|
488
|
-
*
|
|
489
|
-
* @example Conditional Rendering
|
|
490
|
-
* ```typescript
|
|
491
|
-
* const $show = A.proxy(false);
|
|
492
|
-
* A('button click=', () => $show.value = !$show.value, () => A($show.value ? '#Hide' : '#Show'));
|
|
493
|
-
* A(() => { // Reactive scope
|
|
494
|
-
* if ($show.value) {
|
|
495
|
-
* A('p#Details are visible!');
|
|
496
|
-
* }
|
|
497
|
-
* });
|
|
498
|
-
* ```
|
|
499
|
-
*
|
|
500
|
-
* @example Proxied objects as values
|
|
501
|
-
* ```typescript
|
|
502
|
-
* const $myColor = A.proxy('red');
|
|
503
|
-
* A('p text="The color is " text=', $myColor, 'click=', () => $myColor.value = 'yellow')
|
|
504
|
-
* // Clicking the text will cause it to change color without recreating the <p> itself
|
|
505
|
-
* ```
|
|
506
|
-
* This is often used together with {@link ref}, in order to use properties other than `.value`.
|
|
507
|
-
*/
|
|
508
|
-
export declare function A(...args: any[]): undefined | Element;
|
|
509
|
-
/**
|
|
510
|
-
* Inserts CSS rules into the document, scoping them with a unique class name.
|
|
511
|
-
*
|
|
512
|
-
* The `style` parameter can be either:
|
|
513
|
-
* - A **concise style string** (for rules applying to the root class).
|
|
514
|
-
* - An **object** where keys are selectors (with `&` representing the root class)
|
|
515
|
-
* and values are concise style strings or nested objects. When the key does not contain `&`,
|
|
516
|
-
* it is treated as a descendant selector. So `{p: "color:red"}` becomes `".AbdStlX p { color: red; }"` with `AbdStlX` being the generated class name.
|
|
517
|
-
*
|
|
518
|
-
* ### Concise Style Strings
|
|
519
|
-
*
|
|
520
|
-
* Concise style strings use two syntaxes (same as inline CSS in {@link A | A}):
|
|
521
|
-
* - **Short form** `key:value` (no space after colon): The value ends at the next whitespace.
|
|
522
|
-
* Example: `'m:$3 bg:red r:8px'`
|
|
523
|
-
* - **Long form** `key: value;` (space after colon): The value continues until a semicolon.
|
|
524
|
-
* Example: `'box-shadow: 2px 0 6px black; transition: all 0.3s ease;'`
|
|
525
|
-
*
|
|
526
|
-
* Both forms can be mixed: `'m:$3 box-shadow: 0 2px 4px rgba(0,0,0,0.2); bg:$cardBg'`
|
|
527
|
-
*
|
|
528
|
-
* Supports the same CSS shortcuts as {@link A | A} and CSS variable references with `$` (e.g., `$primary`, `$3`).
|
|
529
|
-
*
|
|
530
|
-
* @param style - A concise style string or a style object.
|
|
531
|
-
* @returns The unique class name prefix used for scoping (e.g., `.AbdStl1`).
|
|
532
|
-
* Use this prefix with {@link A | A} to apply the styles.
|
|
533
|
-
*
|
|
534
|
-
* @example Basic Usage with Shortcuts and CSS Variables
|
|
535
|
-
* ```typescript
|
|
536
|
-
* const cardClass = A.insertCss({
|
|
537
|
-
* '&': 'bg:white p:$4 r:8px transition: background-color 0.3s;',
|
|
538
|
-
* '&:hover': 'bg:#f5f5f5',
|
|
539
|
-
* });
|
|
540
|
-
*
|
|
541
|
-
* A('section', cardClass, () => {
|
|
542
|
-
* A('p#Card content');
|
|
543
|
-
* });
|
|
544
|
-
* ```
|
|
545
|
-
*
|
|
546
|
-
* @example Nested Selectors and Media Queries
|
|
547
|
-
* ```typescript
|
|
548
|
-
* const formClass = A.insertCss({
|
|
549
|
-
* '&': 'bg:#0004 p:$3 r:$2',
|
|
550
|
-
* button: {
|
|
551
|
-
* '&': 'bg:$primary fg:white p:$2 r:4px cursor:pointer',
|
|
552
|
-
* '&:hover': 'bg:$primaryHover',
|
|
553
|
-
* '&:disabled': 'bg:#ccc cursor:not-allowed',
|
|
554
|
-
* '.icon': 'display:inline-block mr:$1',
|
|
555
|
-
* '@media (max-width: 600px)': 'p:$1 font-size:14px'
|
|
556
|
-
* }
|
|
557
|
-
* });
|
|
558
|
-
*
|
|
559
|
-
* A('form', formClass, () => {
|
|
560
|
-
* A('button', () => {
|
|
561
|
-
* A('span.icon text=🔥');
|
|
562
|
-
* A('#Click Me');
|
|
563
|
-
* });
|
|
564
|
-
* });
|
|
565
|
-
* ```
|
|
566
|
-
*
|
|
567
|
-
* @example Complex CSS Values
|
|
568
|
-
* ```typescript
|
|
569
|
-
* const badge = A.insertCss({
|
|
570
|
-
* '&::before': 'content: "★"; color:gold mr:$1',
|
|
571
|
-
* '&': 'position:relative box-shadow: 0 2px 8px rgba(0,0,0,0.15);'
|
|
572
|
-
* });
|
|
573
|
-
*
|
|
574
|
-
* A(badge + ' span#Product Name');
|
|
575
|
-
* ```
|
|
576
|
-
*/
|
|
577
|
-
export declare function insertCss(style: string | object): string;
|
|
578
|
-
/**
|
|
579
|
-
* Inserts CSS rules globally (unscoped).
|
|
580
|
-
*
|
|
581
|
-
* Works exactly like {@link insertCss}, but without prefixing selectors with a unique class name.
|
|
582
|
-
* This is useful for global resets, base styles, or styles that need to apply to the entire document.
|
|
583
|
-
*
|
|
584
|
-
* Accepts the same concise style string syntax and CSS shortcuts as {@link insertCss}.
|
|
585
|
-
* See {@link insertCss} for detailed documentation on syntax and shortcuts.
|
|
586
|
-
*
|
|
587
|
-
* @param style - Object with selectors as keys and concise CSS strings as values.
|
|
588
|
-
*
|
|
589
|
-
* @example Global Reset and Base Styles
|
|
590
|
-
* ```typescript
|
|
591
|
-
* // Set up global styles using CSS shortcuts
|
|
592
|
-
* A.insertGlobalCss({
|
|
593
|
-
* "*": "m:0 p:0 box-sizing:border-box",
|
|
594
|
-
* "body": "font-family: system-ui, sans-serif; m:0 p:$3 bg:#434 fg:#d0dafa",
|
|
595
|
-
* "a": "text-decoration:none fg:#57f",
|
|
596
|
-
* "a:hover": "text-decoration:underline",
|
|
597
|
-
* "code": "font-family:monospace bg:#222 fg:#afc p:4px r:3px"
|
|
598
|
-
* });
|
|
599
|
-
*
|
|
600
|
-
* A('h2#Title without margins');
|
|
601
|
-
* A('a#This is a link');
|
|
602
|
-
* A('code#const x = 42;');
|
|
603
|
-
* ```
|
|
604
|
-
*
|
|
605
|
-
* @example Responsive Global Styles
|
|
606
|
-
* ```typescript
|
|
607
|
-
* A.insertGlobalCss({
|
|
608
|
-
* "html": "font-size:16px",
|
|
609
|
-
* "body": "line-height:1.6",
|
|
610
|
-
* "h1, h2, h3": "font-weight:600 mt:$4 mb:$2",
|
|
611
|
-
* "@media (max-width: 768px)": {
|
|
612
|
-
* "html": "font-size:14px",
|
|
613
|
-
* "body": "p:$2"
|
|
614
|
-
* },
|
|
615
|
-
* "@media (prefers-color-scheme: dark)": {
|
|
616
|
-
* "body": "bg:#1a1a1a fg:#e5e5e5",
|
|
617
|
-
* "code": "bg:#2a2a2a"
|
|
618
|
-
* }
|
|
619
|
-
* });
|
|
620
|
-
* ```
|
|
621
|
-
* At-rules such as `@media` and `@keyframes` should use nested objects. For keyframes,
|
|
622
|
-
* the step selectors (`0%`, `50%`, `100%`, etc.) become the nested keys and each value
|
|
623
|
-
* should be a concise CSS declaration string.
|
|
624
|
-
*
|
|
625
|
-
* @example Animation Keyframes
|
|
626
|
-
* ```typescript
|
|
627
|
-
* A.insertGlobalCss({
|
|
628
|
-
* "@keyframes connection-pulse": {
|
|
629
|
-
* "0%": "box-shadow: inset 0 0 0 0 rgba(255, 70, 70, 0.4);",
|
|
630
|
-
* "50%": "box-shadow: inset 0 0 0 6px rgba(255, 70, 70, 0.08);",
|
|
631
|
-
* "100%": "box-shadow: inset 0 0 0 0 rgba(255, 70, 70, 0.4);"
|
|
632
|
-
* }
|
|
633
|
-
* });
|
|
634
|
-
* ```
|
|
635
|
-
*/
|
|
636
|
-
export declare function insertGlobalCss(style: object): void;
|
|
637
|
-
/**
|
|
638
|
-
* Sets a custom error handler function for errors that occur asynchronously
|
|
639
|
-
* within reactive scopes (e.g., during updates triggered by proxy changes in
|
|
640
|
-
* {@link derive} or {@link A | A} render functions).
|
|
641
|
-
*
|
|
642
|
-
* The default handler logs the error to `console.error` and adds a simple
|
|
643
|
-
* 'Error' message div to the DOM at the location where the error occurred (if possible).
|
|
644
|
-
*
|
|
645
|
-
* Your handler can provide custom logging, UI feedback, or suppress the default
|
|
646
|
-
* error message.
|
|
647
|
-
*
|
|
648
|
-
* @param handler - A function that accepts the `Error` object.
|
|
649
|
-
* - Return `false` to prevent adding an error message to the DOM.
|
|
650
|
-
* - Return `true` or `undefined` (or throw) to allow the error messages to be added to the DOM.
|
|
651
|
-
*
|
|
652
|
-
* @example Custom Logging and Suppressing Default Message
|
|
653
|
-
* ```typescript
|
|
654
|
-
* A.setErrorHandler(error => {
|
|
655
|
-
* console.warn('Aberdeen render error:', error.message);
|
|
656
|
-
* // Log to error reporting service
|
|
657
|
-
* // myErrorReporter.log(error);
|
|
658
|
-
*
|
|
659
|
-
* try {
|
|
660
|
-
* // Attempt to show a custom message in the UI
|
|
661
|
-
* A('div#Oops, something went wrong!', errorClass);
|
|
662
|
-
* } catch (e) {
|
|
663
|
-
* // Ignore errors during error handling itself
|
|
664
|
-
* }
|
|
665
|
-
*
|
|
666
|
-
* return false; // Suppress default console log and DOM error message
|
|
667
|
-
* });
|
|
668
|
-
*
|
|
669
|
-
* // Styling for our custom error message
|
|
670
|
-
* const errorClass = A.insertCss('background-color:#e31f00 display:inline-block color:white r:3px padding: 2px 4px;');
|
|
671
|
-
*
|
|
672
|
-
* // Cause an error within a render scope.
|
|
673
|
-
* A('div.box', () => {
|
|
674
|
-
* // Will cause our error handler to insert an error message within the box
|
|
675
|
-
* noSuchFunction();
|
|
676
|
-
* })
|
|
677
|
-
* ```
|
|
678
|
-
*/
|
|
679
|
-
export declare function setErrorHandler(handler?: (error: Error) => boolean | undefined): void;
|
|
680
|
-
/**
|
|
681
|
-
* Registers a cleanup function to be executed just before the current reactive scope
|
|
682
|
-
* is destroyed or redraws.
|
|
683
|
-
*
|
|
684
|
-
* This is useful for releasing resources, removing manual event listeners, or cleaning up
|
|
685
|
-
* side effects associated with the scope. Cleaners are run in reverse order of registration.
|
|
686
|
-
*
|
|
687
|
-
* Scopes are created by functions like {@link derive}, {@link mount}, {@link A | A} (when given a render function),
|
|
688
|
-
* and internally by constructs like {@link onEach}.
|
|
689
|
-
*
|
|
690
|
-
* @param cleaner - The function to execute during cleanup.
|
|
691
|
-
*
|
|
692
|
-
* @example Maintaing a sum for a changing array
|
|
693
|
-
* ```typescript
|
|
694
|
-
* const $numbers = A.proxy([3, 5, 10]);
|
|
695
|
-
* let $sum = A.proxy(0);
|
|
696
|
-
*
|
|
697
|
-
* // Show the array items and maintain the sum
|
|
698
|
-
* A.onEach($numbers, (item, index) => {
|
|
699
|
-
* A(`code#${index}→${item}`);
|
|
700
|
-
* // We'll update $sum.value using peek, as += first does a read, but
|
|
701
|
-
* // we don't want to subscribe.
|
|
702
|
-
* A.peek(() => $sum.value += item);
|
|
703
|
-
* // Clean gets called before each rerun for a certain item index
|
|
704
|
-
* // No need for peek here, as the clean code doesn't run in an
|
|
705
|
-
* // observer scope.
|
|
706
|
-
* A.clean(() => $sum.value -= item);
|
|
707
|
-
* })
|
|
708
|
-
*
|
|
709
|
-
* // Show the sum
|
|
710
|
-
* A('h1 text=', $sum);
|
|
711
|
-
*
|
|
712
|
-
* // Make random changes to the array
|
|
713
|
-
* const rnd = () => 0|(Math.random()*20);
|
|
714
|
-
* setInterval(() => $numbers[rnd()] = rnd(), 1000);
|
|
715
|
-
* ```
|
|
716
|
-
*/
|
|
717
|
-
export declare function clean(cleaner: () => void): void;
|
|
718
|
-
/**
|
|
719
|
-
* Creates a reactive scope that automatically re-executes the provided function
|
|
720
|
-
* whenever any proxied data (created by {@link proxy}) read during its last execution changes, storing
|
|
721
|
-
* its return value in an observable.
|
|
722
|
-
*
|
|
723
|
-
* Updates are batched and run asynchronously shortly after the changes occur.
|
|
724
|
-
* Use {@link clean} to register cleanup logic for the scope.
|
|
725
|
-
* Use {@link peek} or {@link unproxy} within the function to read proxied data without subscribing to it.
|
|
726
|
-
*
|
|
727
|
-
* @param func - The function to execute reactively. Any DOM manipulations should typically
|
|
728
|
-
* be done using {@link A | A} within this function. Its return value will be made available as an
|
|
729
|
-
* observable returned by the `derive()` function.
|
|
730
|
-
* @returns An observable object, with its `value` property containing whatever the last run of `func` returned.
|
|
731
|
-
*
|
|
732
|
-
* @example Observation creating UI components
|
|
733
|
-
* ```typescript
|
|
734
|
-
* const $data = A.proxy({ user: 'Frank', notifications: 42 });
|
|
735
|
-
*
|
|
736
|
-
* A('main', () => {
|
|
737
|
-
* console.log('Welcome');
|
|
738
|
-
* A('h3#Welcome, ' + $data.user); // Reactive text
|
|
739
|
-
*
|
|
740
|
-
* A.derive(() => {
|
|
741
|
-
* // When $data.notifications changes, only this inner scope reruns,
|
|
742
|
-
* // leaving the `<p>Welcome, ..</p>` untouched.
|
|
743
|
-
* console.log('Notifications');
|
|
744
|
-
* A('code.notification-badge text=', $data.notifications);
|
|
745
|
-
* A('a text=Notify! click=', () => $data.notifications++);
|
|
746
|
-
* });
|
|
747
|
-
* });
|
|
748
|
-
* ```
|
|
749
|
-
*
|
|
750
|
-
* ***Note*** that the above could just as easily be done using `A(func)` instead of `derive(func)`.
|
|
751
|
-
*
|
|
752
|
-
* @example Observation with return value
|
|
753
|
-
* ```typescript
|
|
754
|
-
* const $counter = A.proxy(0);
|
|
755
|
-
* setInterval(() => $counter.value++, 1000);
|
|
756
|
-
* const $double = A.derive(() => $counter.value * 2);
|
|
757
|
-
*
|
|
758
|
-
* A('h3', () => {
|
|
759
|
-
* A(`#counter=${$counter.value} double=${$double.value}`);
|
|
760
|
-
* })
|
|
761
|
-
* ```
|
|
762
|
-
*
|
|
763
|
-
* @overload
|
|
764
|
-
* @param func Func without a return value.
|
|
765
|
-
*/
|
|
766
|
-
export declare function derive<T>(func: () => T): ValueRef<T>;
|
|
767
|
-
/**
|
|
768
|
-
* Attaches a reactive Aberdeen UI fragment to an existing DOM element. Without the use of
|
|
769
|
-
* this function, {@link A | A} will assume `document.body` as its root.
|
|
770
|
-
*
|
|
771
|
-
* It creates a top-level reactive scope associated with the `parentElement`. The provided
|
|
772
|
-
* function `func` is executed immediately within this scope. Any proxied data read by `func`
|
|
773
|
-
* will cause it to re-execute when the data changes, updating the DOM elements created within it.
|
|
774
|
-
*
|
|
775
|
-
* Calls to {@link A | A} inside `func` will append nodes to `parentElement`.
|
|
776
|
-
* You can nest {@link derive} or other {@link A | A} scopes within `func`.
|
|
777
|
-
* Use {@link unmountAll} to clean up all mounted scopes and their DOM nodes.
|
|
778
|
-
*
|
|
779
|
-
* Mounting scopes happens reactively, meaning that if this function is called from within another
|
|
780
|
-
* ({@link derive} or {@link A | A} or {@link mount}) scope that gets cleaned up, so will the mount.
|
|
781
|
-
*
|
|
782
|
-
* @param parentElement - The native DOM `Element` to which the UI fragment will be appended.
|
|
783
|
-
* @param func - The function that defines the UI fragment, typically containing calls to {@link A | A}.
|
|
784
|
-
*
|
|
785
|
-
* @example Basic Mount
|
|
786
|
-
* ```javascript
|
|
787
|
-
* // Create a pre-existing DOM structure (without Aberdeen)
|
|
788
|
-
* document.body.innerHTML = `<h3>Static content <span id="title-extra"></span></h3><div class="box" id="app-root"></div>`;
|
|
789
|
-
*
|
|
790
|
-
* import A from 'aberdeen';
|
|
791
|
-
*
|
|
792
|
-
* const $runTime = A.proxy(0);
|
|
793
|
-
* setInterval(() => $runTime.value++, 1000);
|
|
794
|
-
*
|
|
795
|
-
* A.mount(document.getElementById('app-root'), () => {
|
|
796
|
-
* A('h4#Aberdeen App');
|
|
797
|
-
* A(`p#Run time: ${$runTime.value}s`);
|
|
798
|
-
* // Conditionally render some content somewhere else in the static page
|
|
799
|
-
* if ($runTime.value&1) {
|
|
800
|
-
* A.mount(document.getElementById('title-extra'), () =>
|
|
801
|
-
* A(`i#(${$runTime.value}s)`)
|
|
802
|
-
* );
|
|
803
|
-
* }
|
|
804
|
-
* });
|
|
805
|
-
* ```
|
|
806
|
-
*
|
|
807
|
-
* Note how the inner mount behaves reactively as well, automatically unmounting when it's parent observer scope re-runs.
|
|
808
|
-
*/
|
|
809
|
-
export declare function mount(parentElement: Element, func: () => void): void;
|
|
810
|
-
/**
|
|
811
|
-
* Removes all Aberdeen-managed DOM nodes and stops all active reactive scopes
|
|
812
|
-
* (created by {@link mount}, {@link derive}, {@link A | A} with functions, etc.).
|
|
813
|
-
*
|
|
814
|
-
* This effectively cleans up the entire Aberdeen application state. Aside from in
|
|
815
|
-
* automated tests, there should probably be little reason to call this function.
|
|
816
|
-
*/
|
|
817
|
-
export declare function unmountAll(): void;
|
|
818
|
-
/**
|
|
819
|
-
* Executes a function or retrieves a value *without* creating subscriptions in the current reactive scope, and returns its result.
|
|
820
|
-
*
|
|
821
|
-
* This is useful when you need to access reactive data inside a reactive scope (like {@link A | A})
|
|
822
|
-
* but do not want changes to that specific data to trigger a re-execute of the scope.
|
|
823
|
-
*
|
|
824
|
-
* Note: You may also use {@link unproxy} to get to the raw underlying data structure, which can be used to similar effect.
|
|
825
|
-
*
|
|
826
|
-
* @param target - Either a function to execute, or an object (which may also be an Array or a Map) to index.
|
|
827
|
-
* @param key - Optional key/index to use when `target` is an object.
|
|
828
|
-
* @returns The result of the function call, or the value at `target[key]` when `target` is an object or `target.get(key)` when it's a Map.
|
|
829
|
-
*
|
|
830
|
-
* @example Peeking within observer
|
|
831
|
-
* ```typescript
|
|
832
|
-
* const $data = A.proxy({ a: 1, b: 2 });
|
|
833
|
-
* A(() => {
|
|
834
|
-
* // re-executes only when $data.a changes, because $data.b is peeked.
|
|
835
|
-
* const b = A.peek(() => $data.b);
|
|
836
|
-
* console.log(`A is ${$data.a}, B was ${b} when A changed.`);
|
|
837
|
-
* });
|
|
838
|
-
* $data.b = 3; // Does not trigger console.log
|
|
839
|
-
* $data.a = 2; // Triggers console.log (logs "A is 2, B was 3 when A changed.")
|
|
840
|
-
* ```
|
|
841
|
-
*
|
|
842
|
-
*/
|
|
843
|
-
export declare function peek<T extends object, K extends keyof T>(target: T, key: K): T[K];
|
|
844
|
-
export declare function peek<K, V>(target: Map<K, V>, key: K): V | undefined;
|
|
845
|
-
export declare function peek<T>(target: T[], key: number): T | undefined;
|
|
846
|
-
export declare function peek<T>(target: () => T): T;
|
|
847
|
-
/** When using a Map as `source`. */
|
|
848
|
-
export declare function map<K, IN, OUT>(source: Map<K, IN>, func: (value: IN, key: K) => undefined | OUT): Map<K, OUT>;
|
|
849
|
-
/** When using an array as `source`. */
|
|
850
|
-
export declare function map<IN, OUT>(source: Array<IN>, func: (value: IN, index: number) => undefined | OUT): Array<OUT>;
|
|
851
|
-
/** When using an object as `source`. */
|
|
852
|
-
export declare function map<IN, const IN_KEY extends string | number | symbol, OUT>(source: Record<IN_KEY, IN>, func: (value: IN, index: KeyToString<IN_KEY>) => undefined | OUT): Record<string | symbol, OUT>;
|
|
853
|
-
/** When using an array as `source`. */
|
|
854
|
-
export declare function multiMap<IN, OUT extends {
|
|
855
|
-
[key: string | symbol]: any;
|
|
856
|
-
}>(source: Array<IN>, func: (value: IN, index: number) => OUT | undefined): OUT;
|
|
857
|
-
/** When using an object as `source`. */
|
|
858
|
-
export declare function multiMap<K extends string | number | symbol, IN, OUT extends {
|
|
859
|
-
[key: string | symbol]: any;
|
|
860
|
-
}>(source: Record<K, IN>, func: (value: IN, index: KeyToString<K>) => OUT | undefined): OUT;
|
|
861
|
-
/** When using a Map as `source`. */
|
|
862
|
-
export declare function multiMap<K, IN, OUT extends {
|
|
863
|
-
[key: string | symbol]: any;
|
|
864
|
-
}>(source: Map<K, IN>, func: (value: IN, key: K) => OUT | undefined): OUT;
|
|
865
|
-
/** When using an object as `array`. */
|
|
866
|
-
export declare function partition<OUT_K extends string | number | symbol, IN_V>(source: IN_V[], func: (value: IN_V, key: number) => undefined | OUT_K | OUT_K[]): Record<OUT_K, Record<number, IN_V>>;
|
|
867
|
-
/** When using an object as `source`. */
|
|
868
|
-
export declare function partition<IN_K extends string | number | symbol, OUT_K extends string | number | symbol, IN_V>(source: Record<IN_K, IN_V>, func: (value: IN_V, key: IN_K) => undefined | OUT_K | OUT_K[]): Record<OUT_K, Record<IN_K, IN_V>>;
|
|
869
|
-
/** When using a Map as `source`. */
|
|
870
|
-
export declare function partition<IN_K extends string | number | symbol, OUT_K extends string | number | symbol, IN_V>(source: Map<IN_K, IN_V>, func: (value: IN_V, key: IN_K) => undefined | OUT_K | OUT_K[]): Record<OUT_K, Record<IN_K, IN_V>>;
|
|
871
|
-
/**
|
|
872
|
-
* Renders a live, recursive dump of a proxied data structure (or any value)
|
|
873
|
-
* into the DOM at the current {@link A | A} insertion point.
|
|
874
|
-
*
|
|
875
|
-
* Uses `<ul>` and `<li>` elements to display object properties and array items.
|
|
876
|
-
* Updates reactively if the dumped data changes. Primarily intended for debugging purposes.
|
|
877
|
-
*
|
|
878
|
-
* @param data - The proxied data structure (or any value) to display.
|
|
879
|
-
* @returns The original `data` argument, allowing for chaining.
|
|
880
|
-
* @template T - The type of the data being dumped.
|
|
881
|
-
*
|
|
882
|
-
* @example Dumping reactive state
|
|
883
|
-
* ```typescript
|
|
884
|
-
* import A from 'aberdeen';
|
|
885
|
-
*
|
|
886
|
-
* const $state = A.proxy({
|
|
887
|
-
* user: { name: 'Frank', kids: 1 },
|
|
888
|
-
* items: ['a', 'b']
|
|
889
|
-
* });
|
|
890
|
-
*
|
|
891
|
-
* A('h2#Live State Dump');
|
|
892
|
-
* A.dump($state);
|
|
893
|
-
*
|
|
894
|
-
* // Change state later, the dump in the DOM will update
|
|
895
|
-
* setTimeout(() => { $state.user.kids++; $state.items.push('c'); }, 2000);
|
|
896
|
-
* ```
|
|
897
|
-
*/
|
|
898
|
-
export declare function dump<T>(data: T): T;
|
|
899
|
-
/**
|
|
900
|
-
* When set on an object or its prototype chain, {@link dump} calls this as a render function
|
|
901
|
-
* (with the object as `this`) instead of its default recursive rendering. If the value is not
|
|
902
|
-
* a function, it's treated as a string to display.
|
|
903
|
-
*
|
|
904
|
-
* @example
|
|
905
|
-
* ```typescript
|
|
906
|
-
* class Color {
|
|
907
|
-
* constructor(public r: number, public g: number, public b: number) {}
|
|
908
|
-
* [CUSTOM_DUMP]() { A(`#rgb(${this.r}, ${this.g}, ${this.b})`); }
|
|
909
|
-
* }
|
|
910
|
-
* ```
|
|
911
|
-
*/
|
|
912
|
-
export declare const CUSTOM_DUMP: unique symbol;
|
|
913
932
|
/**
|
|
914
|
-
*
|
|
915
|
-
* (
|
|
916
|
-
* values are available as properties on `A`.
|
|
933
|
+
* Create an isolated Aberdeen instance bound to the given window. Returns the callable `A`
|
|
934
|
+
* object (with all Aberdeen functions attached as properties).
|
|
917
935
|
*
|
|
918
|
-
*
|
|
919
|
-
*
|
|
920
|
-
*
|
|
936
|
+
* In the browser you normally import the pre-initialised default instance
|
|
937
|
+
* (`import A from 'aberdeen'`). Call `init` yourself to render against a non-browser DOM
|
|
938
|
+
* (see `aberdeen/server`) or to create multiple isolated instances. All reactive state lives
|
|
939
|
+
* in the returned instance, so separate instances never interfere.
|
|
921
940
|
*
|
|
922
|
-
*
|
|
923
|
-
*
|
|
924
|
-
*
|
|
925
|
-
* A('button text=+ click=', () => $state.count++);
|
|
926
|
-
* });
|
|
927
|
-
* ```
|
|
941
|
+
* @param window The window to render against. May be omitted for the browser default when
|
|
942
|
+
* no `window` global exists yet; rendering then throws until a real window is available.
|
|
943
|
+
* @param options See {@link InitOptions}.
|
|
928
944
|
*/
|
|
929
|
-
declare
|
|
930
|
-
/** {@inheritDoc clean} */ clean: typeof clean;
|
|
931
|
-
/** {@inheritDoc clone} */ clone: typeof clone;
|
|
932
|
-
/** {@inheritDoc copy} */ copy: typeof copy;
|
|
933
|
-
/** {@inheritDoc count} */ count: typeof count;
|
|
934
|
-
/** {@inheritDoc cssVars} */ cssVars: Record<string, string>;
|
|
935
|
-
/** {@inheritDoc CUSTOM_DUMP} */ CUSTOM_DUMP: symbol;
|
|
936
|
-
/** {@inheritDoc darkMode} */ darkMode: typeof darkMode;
|
|
937
|
-
/** {@inheritDoc derive} */ derive: typeof derive;
|
|
938
|
-
/** {@inheritDoc disableCreateDestroy} */ disableCreateDestroy: typeof disableCreateDestroy;
|
|
939
|
-
/** {@inheritDoc dump} */ dump: typeof dump;
|
|
940
|
-
/** {@inheritDoc insertCss} */ insertCss: typeof insertCss;
|
|
941
|
-
/** {@inheritDoc insertGlobalCss} */ insertGlobalCss: typeof insertGlobalCss;
|
|
942
|
-
/** {@inheritDoc invertString} */ invertString: typeof invertString;
|
|
943
|
-
/** {@inheritDoc isEmpty} */ isEmpty: typeof isEmpty;
|
|
944
|
-
/** {@inheritDoc map} */ map: typeof map;
|
|
945
|
-
/** {@inheritDoc merge} */ merge: typeof merge;
|
|
946
|
-
/** {@inheritDoc mount} */ mount: typeof mount;
|
|
947
|
-
/** {@inheritDoc multiMap} */ multiMap: typeof multiMap;
|
|
948
|
-
/** {@inheritDoc OPAQUE} */ OPAQUE: symbol;
|
|
949
|
-
/** {@inheritDoc NO_COPY} */ NO_COPY: symbol;
|
|
950
|
-
/** {@inheritDoc onEach} */ onEach: typeof onEach;
|
|
951
|
-
/** {@inheritDoc partition} */ partition: typeof partition;
|
|
952
|
-
/** {@inheritDoc peek} */ peek: typeof peek;
|
|
953
|
-
/** {@inheritDoc proxy} */ proxy: typeof proxy;
|
|
954
|
-
/** {@inheritDoc ref} */ ref: typeof ref;
|
|
955
|
-
/** {@inheritDoc runQueue} */ runQueue: typeof runQueue;
|
|
956
|
-
/** {@inheritDoc setErrorHandler} */ setErrorHandler: typeof setErrorHandler;
|
|
957
|
-
/** {@inheritDoc setSpacingCssVars} */ setSpacingCssVars: typeof setSpacingCssVars;
|
|
958
|
-
/** {@inheritDoc unmountAll} */ unmountAll: typeof unmountAll;
|
|
959
|
-
/** {@inheritDoc unproxy} */ unproxy: typeof unproxy;
|
|
960
|
-
};
|
|
961
|
-
export default _default;
|
|
945
|
+
export declare function createA(window?: WindowLike, options?: InitOptions): Aberdeen;
|