aberdeen 1.5.0 → 1.7.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.
@@ -0,0 +1,2338 @@
1
+ [**Aberdeen v1.7.0**](README.md)
2
+
3
+ ***
4
+
5
+ [Aberdeen](README.md) / aberdeen
6
+
7
+ # aberdeen
8
+
9
+ ## Interfaces
10
+
11
+ ### PromiseProxy
12
+
13
+ Defined in: [aberdeen.ts:1360](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L1360)
14
+
15
+ When `proxy` is called with a Promise, the returned object has this shape.
16
+
17
+ #### Type Parameters
18
+
19
+ ##### T
20
+
21
+ `T`
22
+
23
+ #### Properties
24
+
25
+ ##### busy
26
+
27
+ > **busy**: `boolean`
28
+
29
+ Defined in: [aberdeen.ts:1364](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L1364)
30
+
31
+ True if the promise is still pending, false if it has resolved or rejected.
32
+
33
+ ##### error?
34
+
35
+ > `optional` **error**: `any`
36
+
37
+ Defined in: [aberdeen.ts:1372](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L1372)
38
+
39
+ If the promise has rejected, this contains the rejection error.
40
+
41
+ ##### value?
42
+
43
+ > `optional` **value**: `T`
44
+
45
+ Defined in: [aberdeen.ts:1368](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L1368)
46
+
47
+ If the promise has resolved, this contains the resolved value.
48
+
49
+ ## Variables
50
+
51
+ ### cssVars
52
+
53
+ > `const` **cssVars**: `Record`\<`string`, `string`\>
54
+
55
+ Defined in: [aberdeen.ts:1772](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L1772)
56
+
57
+ A reactive object containing CSS variable definitions.
58
+
59
+ Any property you assign to `cssVars` becomes available as a CSS custom property throughout your application.
60
+
61
+ Use [setSpacingCssVars](#setspacingcssvars) to optionally initialize `cssVars[1]` through `cssVars[12]` with an exponential spacing scale.
62
+
63
+ When you reference a CSS variable in Aberdeen using the `$` prefix (e.g., `$primary`), it automatically resolves to `var(--primary)`.
64
+ 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)`).
65
+
66
+ When you add the first property to cssVars, Aberdeen automatically creates a reactive `<style>` tag in `<head>`
67
+ containing the `:root` CSS custom property declarations. The style tag is automatically removed if cssVars becomes empty.
68
+
69
+ #### Example
70
+
71
+ ```javascript
72
+ import { cssVars, setSpacingCssVars, $ } from 'aberdeen';
73
+
74
+ // Optionally initialize spacing scale
75
+ setSpacingCssVars(); // Uses defaults: base=1, unit='rem'
76
+
77
+ // Define custom colors - style tag is automatically created
78
+ cssVars.primary = '#3b82f6';
79
+ cssVars.danger = '#ef4444';
80
+
81
+ // Use in elements with the $ prefix
82
+ $('button bg:$primary fg:white');
83
+
84
+ // Use spacing (if setSpacingCssVars() was called)
85
+ $('div mt:$3'); // Sets margin-top to var(--m3)
86
+ ```
87
+
88
+ ***
89
+
90
+ ### NO\_COPY
91
+
92
+ > `const` **NO\_COPY**: *typeof* [`NO_COPY`](#no_copy)
93
+
94
+ Defined in: [aberdeen.ts:1736](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L1736)
95
+
96
+ A symbol that can be added to an object to prevent it from being cloned by [clone](#clone) or [copy](#copy).
97
+ This is useful for objects that should be shared by reference. That also mean that their contents won't
98
+ be observed for changes.
99
+
100
+ ## Functions
101
+
102
+ ### $()
103
+
104
+ > **$**(...`args`): `undefined` \| `Element`
105
+
106
+ Defined in: [aberdeen.ts:2156](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2156)
107
+
108
+ The core function for building reactive user interfaces in Aberdeen. It creates and inserts new DOM elements
109
+ and sets attributes/properties/event listeners on DOM elements. It does so in a reactive way, meaning that
110
+ changes will be (mostly) undone when the current *scope* is destroyed or will be re-execute.
111
+
112
+ #### Parameters
113
+
114
+ ##### args
115
+
116
+ ...`any`[]
117
+
118
+ Any number of arguments can be given. How they're interpreted depends on their types:
119
+
120
+ ### String arguments
121
+ Strings can be used to create and insert new elements, set classnames for the *current* element, and add text to the current element.
122
+ The format of a string is: (**tag** | `.` **class** | **key**[=:]**val** | **key**[=:]"**val containing spaces**")* ('#' **text** | **key**[=:])?
123
+
124
+ So a string may consist of any number of...
125
+ - **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 `$` function execution.
126
+ - 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.
127
+ - 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.
128
+ - CSS key/value pairs using two syntaxes:
129
+ - **Short form** `key:value` (no space after colon): The value ends at the next whitespace. Example: `m:$3 bg:red r:8px`
130
+ - **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;`
131
+
132
+ 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`
133
+ The elements must be separated by spaces, except before a `.cssClass` if it is preceded by either **tag** or another CSS class.
134
+
135
+ And a string may end in...
136
+ - 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.
137
+ - 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: `$('button text="Click me" click=', () => alert('Clicked!'))` or `$('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.
138
+ - 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: `$('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.
139
+
140
+ ### Function arguments
141
+ 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 `$()` 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 `$`, have been cleaned - see also [clean](#clean)).
142
+
143
+ ### Object arguments
144
+ 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.
145
+
146
+ ### DOM node arguments
147
+ 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 `$` function execution.
148
+
149
+ ### Property rules
150
+ - **Attribute:** The common case is setting the value as an HTML attribute named key. For example `$('input placeholder=Name')` results in `<input placeholder="Name">`.
151
+ - **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: $('button text=Press! click=', () => alert('Clicked!'))`. The event listener will be removed when the current scope is destroyed.
152
+ - **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 `$('checked=', true)` would do `el.checked = true` for the *current* element.
153
+ - **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 `$('.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.
154
+ - **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.
155
+ - **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.
156
+ - **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`.
157
+ - **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: `$('button text=Hello click=', alert)`.
158
+ - **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.
159
+
160
+ ### CSS shortcuts
161
+ For conciseness, Aberdeen supports some CSS shortcuts when setting CSS properties.
162
+ | Shortcut | Expands to |
163
+ |----------|------------|
164
+ | `m`, `mt`, `mb`, `ml`, `mr` | `margin`, `margin-top`, `margin-bottom`, `margin-left`, `margin-right` |
165
+ | `mv`, `mh` | Vertical (top+bottom) or horizontal (left+right) margins |
166
+ | `p`, `pt`, `pb`, `pl`, `pr` | `padding`, `padding-top`, `padding-bottom`, `padding-left`, `padding-right` |
167
+ | `pv`, `ph` | Vertical or horizontal padding |
168
+ | `w`, `h` | `width`, `height` |
169
+ | `bg` | `background` |
170
+ | `fg` | `color` |
171
+ | `r` | `border-radius` |
172
+
173
+ 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 [setSpacingCssVars](#setspacingcssvars), which initializes spacing variables named `0` through `12` with an exponential spacing scale.
174
+
175
+ #### Returns
176
+
177
+ `undefined` \| `Element`
178
+
179
+ 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.
180
+
181
+ #### Examples
182
+
183
+ ```typescript
184
+ $('button.secondary.outline text=Submit color:red disabled=', false, 'click=', () => console.log('Clicked!'));
185
+ ```
186
+
187
+ We want to set `disabled` as a property instead of an attribute, so we must use the `key=` syntax in order to provide
188
+ `false` as a boolean instead of a string.
189
+
190
+ ```typescript
191
+ let inputElement: Element = $('label text="Click me" input type=checkbox');
192
+ // You should usually not touch raw DOM elements, unless when integrating
193
+ // with non-Aberdeen code.
194
+ console.log('DOM element:', inputElement);
195
+ ```
196
+
197
+ ```typescript
198
+ const state = proxy({ count: 0 });
199
+ $('div', () => { // Outer element
200
+ // This scope re-renders when state.count changes
201
+ $(`p#Count is ${state.count}`);
202
+ $('button text=Increment click=', () => state.count++);
203
+ });
204
+ ```
205
+
206
+ ```typescript
207
+ const user = proxy({ name: '' });
208
+ $('input placeholder=Name bind=', ref(user, 'name'));
209
+ $('h3', () => { // Reactive scope
210
+ $(`#Hello ${user.name || 'stranger'}`);
211
+ });
212
+ ```
213
+
214
+ ```typescript
215
+ const show = proxy(false);
216
+ $('button click=', () => show.value = !show.value, () => $(show.value ? '#Hide' : '#Show'));
217
+ $(() => { // Reactive scope
218
+ if (show.value) {
219
+ $('p#Details are visible!');
220
+ }
221
+ });
222
+ ```
223
+
224
+ ```typescript
225
+ const myColor = proxy('red');
226
+ $('p text="The color is " text=', myColor, 'click=', () => myColor.value = 'yellow')
227
+ // Clicking the text will cause it to change color without recreating the <p> itself
228
+ ```
229
+ This is often used together with [ref](#ref), in order to use properties other than `.value`.
230
+
231
+ ***
232
+
233
+ ### clean()
234
+
235
+ > **clean**(`cleaner`): `void`
236
+
237
+ Defined in: [aberdeen.ts:2640](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2640)
238
+
239
+ Registers a cleanup function to be executed just before the current reactive scope
240
+ is destroyed or redraws.
241
+
242
+ This is useful for releasing resources, removing manual event listeners, or cleaning up
243
+ side effects associated with the scope. Cleaners are run in reverse order of registration.
244
+
245
+ Scopes are created by functions like [derive](#derive), [mount](#mount), [$](#) (when given a render function),
246
+ and internally by constructs like [onEach](#oneach).
247
+
248
+ #### Parameters
249
+
250
+ ##### cleaner
251
+
252
+ () => `void`
253
+
254
+ The function to execute during cleanup.
255
+
256
+ #### Returns
257
+
258
+ `void`
259
+
260
+ #### Example
261
+
262
+ ```typescript
263
+ const myArray = proxy([3, 5, 10]);
264
+ let sum = proxy(0);
265
+
266
+ // Show the array items and maintain the sum
267
+ onEach(myArray, (item, index) => {
268
+ $(`code#${index}→${item}`);
269
+ // We'll update sum.value using peek, as += first does a read, but
270
+ // we don't want to subscribe.
271
+ peek(() => sum.value += item);
272
+ // Clean gets called before each rerun for a certain item index
273
+ // No need for peek here, as the clean code doesn't run in an
274
+ // observer scope.
275
+ clean(() => sum.value -= item);
276
+ })
277
+
278
+ // Show the sum
279
+ $('h1 text=', sum);
280
+
281
+ // Make random changes to the array
282
+ const rnd = () => 0|(Math.random()*20);
283
+ setInterval(() => myArray[rnd()] = rnd(), 1000);
284
+ ```
285
+
286
+ ***
287
+
288
+ ### clone()
289
+
290
+ > **clone**\<`T`\>(`src`): `T`
291
+
292
+ Defined in: [aberdeen.ts:1893](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L1893)
293
+
294
+ Clone an (optionally proxied) object or array.
295
+
296
+ #### Type Parameters
297
+
298
+ ##### T
299
+
300
+ `T` *extends* `object`
301
+
302
+ The type of the objects being copied.
303
+
304
+ #### Parameters
305
+
306
+ ##### src
307
+
308
+ `T`
309
+
310
+ The object or array to clone. If it is proxied, `clone` will subscribe to any changes to the (nested) data structure.
311
+
312
+ #### Returns
313
+
314
+ `T`
315
+
316
+ A new unproxied array or object (of the same type as `src`), containing a deep copy of `src`.
317
+
318
+ ***
319
+
320
+ ### copy()
321
+
322
+ #### Call Signature
323
+
324
+ > **copy**\<`T`\>(`dst`, `src`): `boolean`
325
+
326
+ Defined in: [aberdeen.ts:1535](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L1535)
327
+
328
+ Recursively copies properties or array items from `src` to `dst`.
329
+ It's designed to work efficiently with reactive proxies created by [proxy](#proxy).
330
+
331
+ - **Minimizes Updates:** When copying between objects/arrays (proxied or not), if a nested object
332
+ exists in `dst` with the same constructor as the corresponding object in `src`, `copy`
333
+ will recursively copy properties into the existing `dst` object instead of replacing it.
334
+ This minimizes change notifications for reactive updates.
335
+ - **Handles Proxies:** Can accept proxied or unproxied objects/arrays for both `dst` and `src`.
336
+ - **Cross-Type Copying:** Supports copying between Maps and objects. When copying from an object
337
+ to a Map, object properties become Map entries. When copying from a Map to an object, Map entries
338
+ become object properties (only for Maps with string/number/symbol keys).
339
+
340
+ ##### Type Parameters
341
+
342
+ ###### T
343
+
344
+ `T` *extends* `object`
345
+
346
+ The type of the objects being copied.
347
+
348
+ ##### Parameters
349
+
350
+ ###### dst
351
+
352
+ `T`
353
+
354
+ The destination object/array/Map (proxied or unproxied).
355
+
356
+ ###### src
357
+
358
+ `T`
359
+
360
+ The source object/array/Map (proxied or unproxied). It won't be modified.
361
+
362
+ ##### Returns
363
+
364
+ `boolean`
365
+
366
+ `true` if any changes were made to `dst`, or `false` if not.
367
+
368
+ ##### Throws
369
+
370
+ Error if attempting to copy an array into a non-array or vice versa.
371
+
372
+ ##### Example
373
+
374
+ ```typescript
375
+ const source = proxy({ a: 1, b: { c: 2 } });
376
+ const dest = proxy({ b: { d: 3 } });
377
+ copy(dest, source);
378
+ console.log(dest); // proxy({ a: 1, b: { c: 2 } })
379
+ copy(dest, 'b', { e: 4 });
380
+ console.log(dest); // proxy({ a: 1, b: { e: 4 } })
381
+ ```
382
+
383
+ #### Call Signature
384
+
385
+ > **copy**\<`T`\>(`dst`, `dstKey`, `src`): `boolean`
386
+
387
+ Defined in: [aberdeen.ts:1542](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L1542)
388
+
389
+ Like above, but copies `src` into `dst[dstKey]`. This is useful if you're unsure if dst[dstKey]
390
+ already exists (as the right type of object) or if you don't want to subscribe to dst[dstKey].
391
+
392
+ ##### Type Parameters
393
+
394
+ ###### T
395
+
396
+ `T` *extends* `object`
397
+
398
+ ##### Parameters
399
+
400
+ ###### dst
401
+
402
+ `T`
403
+
404
+ ###### dstKey
405
+
406
+ keyof `T`
407
+
408
+ Optional key in `dst` to copy into.
409
+
410
+ ###### src
411
+
412
+ `T`\[keyof `T`\]
413
+
414
+ ##### Returns
415
+
416
+ `boolean`
417
+
418
+ ***
419
+
420
+ ### count()
421
+
422
+ > **count**(`proxied`): `ValueRef`\<`number`\>
423
+
424
+ Defined in: [aberdeen.ts:1057](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L1057)
425
+
426
+ Reactively counts the number of properties in an objects.
427
+
428
+ #### Parameters
429
+
430
+ ##### proxied
431
+
432
+ `TargetType`
433
+
434
+ The observable object to count. In case an `array` is passed in, a [ref](#ref) to its `.length` will be returned.
435
+
436
+ #### Returns
437
+
438
+ `ValueRef`\<`number`\>
439
+
440
+ an observable object for which the `value` property reflects the number of properties in `proxied` with a value other than `undefined`.
441
+
442
+ #### Example
443
+
444
+ ```typescript
445
+ const items = proxy({x: 3, y: 7} as any);
446
+ const cnt = count(items);
447
+
448
+ // Create a DOM text node for the count:
449
+ $('div text=', cnt);
450
+ // <div>2</div>
451
+
452
+ // Or we can use it in an {@link derive} function:
453
+ $(() => console.log("The count is now", cnt.value));
454
+ // The count is now 2
455
+
456
+ // Adding/removing items will update the count
457
+ items.z = 12;
458
+ // Asynchronously, after 0ms:
459
+ // <div>3</div>
460
+ // The count is now 3
461
+ ```
462
+
463
+ ***
464
+
465
+ ### darkMode()
466
+
467
+ > **darkMode**(): `boolean`
468
+
469
+ Defined in: [aberdeen.ts:1872](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L1872)
470
+
471
+ Returns whether the user's browser prefers a dark color scheme.
472
+
473
+ This function is reactive - scopes that call it will re-execute when the
474
+ browser's color scheme preference changes (via the `prefers-color-scheme` media query).
475
+
476
+ Use this in combination with [$](#) and [cssVars](#cssvars) to implement theme switching:
477
+
478
+ #### Returns
479
+
480
+ `boolean`
481
+
482
+ `true` if the browser prefers dark mode, `false` if it prefers light mode.
483
+
484
+ #### Example
485
+
486
+ ```javascript
487
+ import { darkMode, cssVars, $, mount } from 'aberdeen';
488
+
489
+ // Reactively set colors based on browser preference
490
+ $(() => {
491
+ cssVars.bg = darkMode() ? '#1a1a1a' : '#ffffff';
492
+ cssVars.fg = darkMode() ? '#e5e5e5' : '#000000';
493
+ });
494
+
495
+ $('div bg:$bg fg:$fg p:1rem #Colors change based on system dark mode preference');
496
+ ```
497
+
498
+ ***
499
+
500
+ ### derive()
501
+
502
+ > **derive**\<`T`\>(`func`): `ValueRef`\<`T`\>
503
+
504
+ Defined in: [aberdeen.ts:2692](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2692)
505
+
506
+ Creates a reactive scope that automatically re-executes the provided function
507
+ whenever any proxied data (created by [proxy](#proxy)) read during its last execution changes, storing
508
+ its return value in an observable.
509
+
510
+ Updates are batched and run asynchronously shortly after the changes occur.
511
+ Use [clean](#clean) to register cleanup logic for the scope.
512
+ Use [peek](#peek) or [unproxy](#unproxy) within the function to read proxied data without subscribing to it.
513
+
514
+ #### Type Parameters
515
+
516
+ ##### T
517
+
518
+ `T`
519
+
520
+ #### Parameters
521
+
522
+ ##### func
523
+
524
+ () => `T`
525
+
526
+ The function to execute reactively. Any DOM manipulations should typically
527
+ be done using [$](#) within this function. Its return value will be made available as an
528
+ observable returned by the `derive()` function.
529
+
530
+ #### Returns
531
+
532
+ `ValueRef`\<`T`\>
533
+
534
+ An observable object, with its `value` property containing whatever the last run of `func` returned.
535
+
536
+ #### Examples
537
+
538
+ ```typescript
539
+ const data = proxy({ user: 'Frank', notifications: 42 });
540
+
541
+ $('main', () => {
542
+ console.log('Welcome');
543
+ $('h3#Welcome, ' + data.user); // Reactive text
544
+
545
+ derive(() => {
546
+ // When data.notifications changes, only this inner scope reruns,
547
+ // leaving the `<p>Welcome, ..</p>` untouched.
548
+ console.log('Notifications');
549
+ $('code.notification-badge text=', data.notifications);
550
+ $('a text=Notify! click=', () => data.notifications++);
551
+ });
552
+ });
553
+ ```
554
+
555
+ ***Note*** that the above could just as easily be done using `$(func)` instead of `derive(func)`.
556
+
557
+ ```typescript
558
+ const counter = proxy(0);
559
+ setInterval(() => counter.value++, 1000);
560
+ const double = derive(() => counter.value * 2);
561
+
562
+ $('h3', () => {
563
+ $(`#counter=${counter.value} double=${double.value}`);
564
+ })
565
+ ```
566
+
567
+ ***
568
+
569
+ ### dump()
570
+
571
+ > **dump**\<`T`\>(`data`): `T`
572
+
573
+ Defined in: [aberdeen.ts:3113](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L3113)
574
+
575
+ Renders a live, recursive dump of a proxied data structure (or any value)
576
+ into the DOM at the current [$](#) insertion point.
577
+
578
+ Uses `<ul>` and `<li>` elements to display object properties and array items.
579
+ Updates reactively if the dumped data changes. Primarily intended for debugging purposes.
580
+
581
+ #### Type Parameters
582
+
583
+ ##### T
584
+
585
+ `T`
586
+
587
+ The type of the data being dumped.
588
+
589
+ #### Parameters
590
+
591
+ ##### data
592
+
593
+ `T`
594
+
595
+ The proxied data structure (or any value) to display.
596
+
597
+ #### Returns
598
+
599
+ `T`
600
+
601
+ The original `data` argument, allowing for chaining.
602
+
603
+ #### Example
604
+
605
+ ```typescript
606
+ import { $, proxy, dump } from 'aberdeen';
607
+
608
+ const state = proxy({
609
+ user: { name: 'Frank', kids: 1 },
610
+ items: ['a', 'b']
611
+ });
612
+
613
+ $('h2#Live State Dump');
614
+ dump(state);
615
+
616
+ // Change state later, the dump in the DOM will update
617
+ setTimeout(() => { state.user.kids++; state.items.push('c'); }, 2000);
618
+ ```
619
+
620
+ ***
621
+
622
+ ### insertCss()
623
+
624
+ > **insertCss**(`style`): `string`
625
+
626
+ Defined in: [aberdeen.ts:2349](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2349)
627
+
628
+ Inserts CSS rules into the document, scoping them with a unique class name.
629
+
630
+ The `style` parameter can be either:
631
+ - A **concise style string** (for rules applying to the root class).
632
+ - An **object** where keys are selectors (with `&` representing the root class)
633
+ and values are concise style strings or nested objects. When the key does not contain `&`,
634
+ it is treated as a descendant selector. So `{p: "color:red"}` becomes `".AbdStlX p { color: red; }"` with `AbdStlX` being the generated class name.
635
+
636
+ ### Concise Style Strings
637
+
638
+ Concise style strings use two syntaxes (same as inline CSS in [$](#)):
639
+ - **Short form** `key:value` (no space after colon): The value ends at the next whitespace.
640
+ Example: `'m:$3 bg:red r:8px'`
641
+ - **Long form** `key: value;` (space after colon): The value continues until a semicolon.
642
+ Example: `'box-shadow: 2px 0 6px black; transition: all 0.3s ease;'`
643
+
644
+ Both forms can be mixed: `'m:$3 box-shadow: 0 2px 4px rgba(0,0,0,0.2); bg:$cardBg'`
645
+
646
+ Supports the same CSS shortcuts as [$](#) and CSS variable references with `$` (e.g., `$primary`, `$3`).
647
+
648
+ #### Parameters
649
+
650
+ ##### style
651
+
652
+ A concise style string or a style object.
653
+
654
+ `string` | `object`
655
+
656
+ #### Returns
657
+
658
+ `string`
659
+
660
+ The unique class name prefix used for scoping (e.g., `.AbdStl1`).
661
+ Use this prefix with [$](#) to apply the styles.
662
+
663
+ #### Examples
664
+
665
+ ```typescript
666
+ const cardClass = insertCss({
667
+ '&': 'bg:white p:$4 r:8px transition: background-color 0.3s;',
668
+ '&:hover': 'bg:#f5f5f5',
669
+ });
670
+
671
+ $('section', cardClass, () => {
672
+ $('p#Card content');
673
+ });
674
+ ```
675
+
676
+ ```typescript
677
+ const formClass = insertCss({
678
+ '&': 'bg:#0004 p:$3 r:$2',
679
+ button: {
680
+ '&': 'bg:$primary fg:white p:$2 r:4px cursor:pointer',
681
+ '&:hover': 'bg:$primaryHover',
682
+ '&:disabled': 'bg:#ccc cursor:not-allowed',
683
+ '.icon': 'display:inline-block mr:$1',
684
+ '@media (max-width: 600px)': 'p:$1 font-size:14px'
685
+ }
686
+ });
687
+
688
+ $('form', formClass, () => {
689
+ $('button', () => {
690
+ $('span.icon text=🔥');
691
+ $('#Click Me');
692
+ });
693
+ });
694
+ ```
695
+
696
+ ```typescript
697
+ const badge = insertCss({
698
+ '&::before': 'content: "★"; color:gold mr:$1',
699
+ '&': 'position:relative box-shadow: 0 2px 8px rgba(0,0,0,0.15);'
700
+ });
701
+
702
+ $(badge + ' span#Product Name');
703
+ ```
704
+
705
+ ***
706
+
707
+ ### insertGlobalCss()
708
+
709
+ > **insertGlobalCss**(`style`): `void`
710
+
711
+ Defined in: [aberdeen.ts:2473](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2473)
712
+
713
+ Inserts CSS rules globally (unscoped).
714
+
715
+ Works exactly like [insertCss](#insertcss), but without prefixing selectors with a unique class name.
716
+ This is useful for global resets, base styles, or styles that need to apply to the entire document.
717
+
718
+ Accepts the same concise style string syntax and CSS shortcuts as [insertCss](#insertcss).
719
+ See [insertCss](#insertcss) for detailed documentation on syntax and shortcuts.
720
+
721
+ #### Parameters
722
+
723
+ ##### style
724
+
725
+ `object`
726
+
727
+ Object with selectors as keys and concise CSS strings as values.
728
+
729
+ #### Returns
730
+
731
+ `void`
732
+
733
+ #### Examples
734
+
735
+ ```typescript
736
+ // Set up global styles using CSS shortcuts
737
+ insertGlobalCss({
738
+ "*": "m:0 p:0 box-sizing:border-box",
739
+ "body": "font-family: system-ui, sans-serif; m:0 p:$3 bg:#434 fg:#d0dafa",
740
+ "a": "text-decoration:none fg:#57f",
741
+ "a:hover": "text-decoration:underline",
742
+ "code": "font-family:monospace bg:#222 fg:#afc p:4px r:3px"
743
+ });
744
+
745
+ $('h2#Title without margins');
746
+ $('a#This is a link');
747
+ $('code#const x = 42;');
748
+ ```
749
+
750
+ ```typescript
751
+ insertGlobalCss({
752
+ "html": "font-size:16px",
753
+ "body": "line-height:1.6",
754
+ "h1, h2, h3": "font-weight:600 mt:$4 mb:$2",
755
+ "@media (max-width: 768px)": {
756
+ "html": "font-size:14px",
757
+ "body": "p:$2"
758
+ },
759
+ "@media (prefers-color-scheme: dark)": {
760
+ "body": "bg:#1a1a1a fg:#e5e5e5",
761
+ "code": "bg:#2a2a2a"
762
+ }
763
+ });
764
+ ```
765
+
766
+ ***
767
+
768
+ ### invertString()
769
+
770
+ > **invertString**(`input`): `string`
771
+
772
+ Defined in: [aberdeen.ts:149](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L149)
773
+
774
+ Creates a new string that has the opposite sort order compared to the input string.
775
+
776
+ This is achieved by flipping the bits of each character code in the input string.
777
+ The resulting string is intended for use as a sort key, particularly with the
778
+ `makeKey` function in [onEach](#oneach), to achieve a descending sort order.
779
+
780
+ **Warning:** The output string will likely contain non-printable characters or
781
+ appear as gibberish and should not be displayed to the user.
782
+
783
+ #### Parameters
784
+
785
+ ##### input
786
+
787
+ `string`
788
+
789
+ The string whose sort order needs to be inverted.
790
+
791
+ #### Returns
792
+
793
+ `string`
794
+
795
+ A new string that will sort in the reverse order of the input string.
796
+
797
+ #### Example
798
+
799
+ ```typescript
800
+ const users = proxy([
801
+ { id: 1, name: 'Charlie', score: 95 },
802
+ { id: 2, name: 'Alice', score: 100 },
803
+ { id: 3, name: 'Bob', score: 90 },
804
+ ]);
805
+
806
+ onEach(users, (user) => {
807
+ $(`p#${user.name}: ${user.score}`);
808
+ }, (user) => invertString(user.name)); // Reverse alphabetic order
809
+ ```
810
+
811
+ #### See
812
+
813
+ [onEach](#oneach) for usage with sorting.
814
+
815
+ ***
816
+
817
+ ### isEmpty()
818
+
819
+ > **isEmpty**(`proxied`): `boolean`
820
+
821
+ Defined in: [aberdeen.ts:997](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L997)
822
+
823
+ Reactively checks if an observable array or object is empty.
824
+
825
+ This function not only returns the current emptiness state but also establishes
826
+ a reactive dependency. If the emptiness state of the `proxied` object or array
827
+ changes later (e.g., an item is added to an empty array, or the last property
828
+ is deleted from an object), the scope that called `isEmpty` will be automatically
829
+ scheduled for re-evaluation.
830
+
831
+ #### Parameters
832
+
833
+ ##### proxied
834
+
835
+ `TargetType`
836
+
837
+ The observable array or object to check.
838
+
839
+ #### Returns
840
+
841
+ `boolean`
842
+
843
+ `true` if the array has length 0 or the object has no own enumerable properties, `false` otherwise.
844
+
845
+ #### Example
846
+
847
+ ```typescript
848
+ const items = proxy([]);
849
+
850
+ // Reactively display a message if the items array is empty
851
+ $('div', () => {
852
+ if (isEmpty(items)) {
853
+ $('p i#No items yet!');
854
+ } else {
855
+ onEach(items, item => $('p#'+item));
856
+ }
857
+ });
858
+
859
+ // Adding an item will automatically remove the "No items yet!" message
860
+ setInterval(() => {
861
+ if (!items.length || Math.random()>0.5) items.push('Item');
862
+ else items.length = 0;
863
+ }, 1000)
864
+ ```
865
+
866
+ ***
867
+
868
+ ### map()
869
+
870
+ Reactively maps/filters items from a proxied source array or object to a new proxied array or object.
871
+
872
+ It iterates over the `target` proxy. For each item, it calls `func`.
873
+ - If `func` returns a value, it's added to the result proxy under the same key/index.
874
+ - If `func` returns `undefined`, the item is skipped (filtered out).
875
+
876
+ The returned proxy automatically updates when:
877
+ - Items are added/removed/updated in the `target` proxy.
878
+ - Any proxied data read *within* the `func` call changes (for a specific item).
879
+
880
+ #### Param
881
+
882
+ A function `(value, key) => mappedValue | undefined` that transforms each item.
883
+ It receives the item's value and its key/index. Return `undefined` to filter the item out.
884
+
885
+ #### Template
886
+
887
+ The type of items in the source proxy.
888
+
889
+ #### Template
890
+
891
+ The type of items in the resulting proxy.
892
+
893
+ #### Examples
894
+
895
+ ```typescript
896
+ const numbers = proxy([1, 2, 3]);
897
+ const doubled = map(numbers, (n) => n * 2);
898
+ // doubled is proxy([2, 4, 6])
899
+
900
+ $(() => console.log(doubled)); // Logs updates
901
+ numbers.push(4); // doubled becomes proxy([2, 4, 6, 8])
902
+ ```
903
+
904
+ ```typescript
905
+ const users = proxy({
906
+ 'u1': { name: 'Alice', active: true },
907
+ 'u2': { name: 'Bob', active: false },
908
+ 'u3': { name: 'Charlie', active: true }
909
+ });
910
+
911
+ const activeUserNames = map(users, (user) => user.active ? user.name : undefined);
912
+ // activeUserNames is proxy({ u1: 'Alice', u3: 'Charlie' })
913
+ $(() => console.log(Object.values(activeUserNames)));
914
+
915
+ users.u2.active = true;
916
+ // activeUserNames becomes proxy({ u1: 'Alice', u2: 'Bob', u3: 'Charlie' })
917
+ ```
918
+
919
+ #### Call Signature
920
+
921
+ > **map**\<`K`, `IN`, `OUT`\>(`source`, `func`): `Map`\<`K`, `OUT`\>
922
+
923
+ Defined in: [aberdeen.ts:2800](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2800)
924
+
925
+ When using a Map as `source`.
926
+
927
+ ##### Type Parameters
928
+
929
+ ###### K
930
+
931
+ `K`
932
+
933
+ ###### IN
934
+
935
+ `IN`
936
+
937
+ ###### OUT
938
+
939
+ `OUT`
940
+
941
+ ##### Parameters
942
+
943
+ ###### source
944
+
945
+ `Map`\<`K`, `IN`\>
946
+
947
+ ###### func
948
+
949
+ (`value`, `key`) => `undefined` \| `OUT`
950
+
951
+ ##### Returns
952
+
953
+ `Map`\<`K`, `OUT`\>
954
+
955
+ #### Call Signature
956
+
957
+ > **map**\<`IN`, `OUT`\>(`source`, `func`): `OUT`[]
958
+
959
+ Defined in: [aberdeen.ts:2805](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2805)
960
+
961
+ When using an array as `source`.
962
+
963
+ ##### Type Parameters
964
+
965
+ ###### IN
966
+
967
+ `IN`
968
+
969
+ ###### OUT
970
+
971
+ `OUT`
972
+
973
+ ##### Parameters
974
+
975
+ ###### source
976
+
977
+ `IN`[]
978
+
979
+ ###### func
980
+
981
+ (`value`, `index`) => `undefined` \| `OUT`
982
+
983
+ ##### Returns
984
+
985
+ `OUT`[]
986
+
987
+ #### Call Signature
988
+
989
+ > **map**\<`IN`, `IN_KEY`, `OUT`\>(`source`, `func`): `Record`\<`string` \| `symbol`, `OUT`\>
990
+
991
+ Defined in: [aberdeen.ts:2810](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2810)
992
+
993
+ When using an object as `source`.
994
+
995
+ ##### Type Parameters
996
+
997
+ ###### IN
998
+
999
+ `IN`
1000
+
1001
+ ###### IN_KEY
1002
+
1003
+ `IN_KEY` *extends* `string` \| `number` \| `symbol`
1004
+
1005
+ ###### OUT
1006
+
1007
+ `OUT`
1008
+
1009
+ ##### Parameters
1010
+
1011
+ ###### source
1012
+
1013
+ `Record`\<`IN_KEY`, `IN`\>
1014
+
1015
+ ###### func
1016
+
1017
+ (`value`, `index`) => `undefined` \| `OUT`
1018
+
1019
+ ##### Returns
1020
+
1021
+ `Record`\<`string` \| `symbol`, `OUT`\>
1022
+
1023
+ ***
1024
+
1025
+ ### merge()
1026
+
1027
+ #### Call Signature
1028
+
1029
+ > **merge**\<`T`\>(`dst`, `value`): `boolean`
1030
+
1031
+ Defined in: [aberdeen.ts:1575](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L1575)
1032
+
1033
+ Like [copy](#copy), but uses merge semantics. Properties in `dst` not present in `src` are kept.
1034
+ `null`/`undefined` in `src` delete properties in `dst`.
1035
+
1036
+ ##### Type Parameters
1037
+
1038
+ ###### T
1039
+
1040
+ `T` *extends* `object`
1041
+
1042
+ ##### Parameters
1043
+
1044
+ ###### dst
1045
+
1046
+ `T`
1047
+
1048
+ ###### value
1049
+
1050
+ `Partial`\<`T`\>
1051
+
1052
+ ##### Returns
1053
+
1054
+ `boolean`
1055
+
1056
+ ##### Example
1057
+
1058
+ ```typescript
1059
+ const source = { b: { c: 99 }, d: undefined }; // d: undefined will delete
1060
+ const dest = proxy({ a: 1, b: { x: 5 }, d: 4 });
1061
+ merge(dest, source);
1062
+ merge(dest, 'b', { y: 6 }); // merge into dest.b
1063
+ merge(dest, 'c', { z: 7 }); // merge.c doesn't exist yet, so it will just be assigned
1064
+ console.log(dest); // proxy({ a: 1, b: { c: 99, x: 5, y: 6 }, c: { z: 7 } })
1065
+ ```
1066
+
1067
+ #### Call Signature
1068
+
1069
+ > **merge**\<`T`\>(`dst`, `dstKey`, `value`): `boolean`
1070
+
1071
+ Defined in: [aberdeen.ts:1576](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L1576)
1072
+
1073
+ Like [copy](#copy), but uses merge semantics. Properties in `dst` not present in `src` are kept.
1074
+ `null`/`undefined` in `src` delete properties in `dst`.
1075
+
1076
+ ##### Type Parameters
1077
+
1078
+ ###### T
1079
+
1080
+ `T` *extends* `object`
1081
+
1082
+ ##### Parameters
1083
+
1084
+ ###### dst
1085
+
1086
+ `T`
1087
+
1088
+ ###### dstKey
1089
+
1090
+ keyof `T`
1091
+
1092
+ ###### value
1093
+
1094
+ `Partial`\<`T`\[keyof `T`\]\>
1095
+
1096
+ ##### Returns
1097
+
1098
+ `boolean`
1099
+
1100
+ ##### Example
1101
+
1102
+ ```typescript
1103
+ const source = { b: { c: 99 }, d: undefined }; // d: undefined will delete
1104
+ const dest = proxy({ a: 1, b: { x: 5 }, d: 4 });
1105
+ merge(dest, source);
1106
+ merge(dest, 'b', { y: 6 }); // merge into dest.b
1107
+ merge(dest, 'c', { z: 7 }); // merge.c doesn't exist yet, so it will just be assigned
1108
+ console.log(dest); // proxy({ a: 1, b: { c: 99, x: 5, y: 6 }, c: { z: 7 } })
1109
+ ```
1110
+
1111
+ ***
1112
+
1113
+ ### mount()
1114
+
1115
+ > **mount**(`parentElement`, `func`): `void`
1116
+
1117
+ Defined in: [aberdeen.ts:2739](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2739)
1118
+
1119
+ Attaches a reactive Aberdeen UI fragment to an existing DOM element. Without the use of
1120
+ this function, [$](#) will assume `document.body` as its root.
1121
+
1122
+ It creates a top-level reactive scope associated with the `parentElement`. The provided
1123
+ function `func` is executed immediately within this scope. Any proxied data read by `func`
1124
+ will cause it to re-execute when the data changes, updating the DOM elements created within it.
1125
+
1126
+ Calls to [$](#) inside `func` will append nodes to `parentElement`.
1127
+ You can nest [derive](#derive) or other [$](#) scopes within `func`.
1128
+ Use [unmountAll](#unmountall) to clean up all mounted scopes and their DOM nodes.
1129
+
1130
+ Mounting scopes happens reactively, meaning that if this function is called from within another
1131
+ ([derive](#derive) or [$](#) or [mount](#mount)) scope that gets cleaned up, so will the mount.
1132
+
1133
+ #### Parameters
1134
+
1135
+ ##### parentElement
1136
+
1137
+ `Element`
1138
+
1139
+ The native DOM `Element` to which the UI fragment will be appended.
1140
+
1141
+ ##### func
1142
+
1143
+ () => `void`
1144
+
1145
+ The function that defines the UI fragment, typically containing calls to [$](#).
1146
+
1147
+ #### Returns
1148
+
1149
+ `void`
1150
+
1151
+ #### Example
1152
+
1153
+ ```javascript
1154
+ // Create a pre-existing DOM structure (without Aberdeen)
1155
+ document.body.innerHTML = `<h3>Static content <span id="title-extra"></span></h3><div class="box" id="app-root"></div>`;
1156
+
1157
+ import { mount, $, proxy } from 'aberdeen';
1158
+
1159
+ const runTime = proxy(0);
1160
+ setInterval(() => runTime.value++, 1000);
1161
+
1162
+ mount(document.getElementById('app-root'), () => {
1163
+ $('h4#Aberdeen App');
1164
+ $(`p#Run time: ${runTime.value}s`);
1165
+ // Conditionally render some content somewhere else in the static page
1166
+ if (runTime.value&1) {
1167
+ mount(document.getElementById('title-extra'), () =>
1168
+ $(`i#(${runTime.value}s)`)
1169
+ );
1170
+ }
1171
+ });
1172
+ ```
1173
+
1174
+ Note how the inner mount behaves reactively as well, automatically unmounting when it's parent observer scope re-runs.
1175
+
1176
+ ***
1177
+
1178
+ ### multiMap()
1179
+
1180
+ Reactively maps items from a source proxy (array or object) to a target proxied object,
1181
+ where each source item can contribute multiple key-value pairs to the target.
1182
+
1183
+ It iterates over the `target` proxy. For each item, it calls `func`.
1184
+ - If `func` returns an object, all key-value pairs from that object are added to the result proxy.
1185
+ - If `func` returns `undefined`, the item contributes nothing.
1186
+
1187
+ The returned proxy automatically updates when:
1188
+ - Items are added/removed/updated in the `target` proxy.
1189
+ - Any proxied data read *within* the `func` call changes (for a specific item).
1190
+ - If multiple input items produce the same output key, the last one processed usually "wins",
1191
+ but the exact behavior on collision depends on update timing.
1192
+
1193
+ This is useful for "flattening" or "indexing" data, or converting an observable array to an observable object.
1194
+
1195
+ #### Param
1196
+
1197
+ The source proxied array or object.
1198
+
1199
+ #### Param
1200
+
1201
+ A function `(value, key) => ({...pairs} | undefined)` that transforms an item
1202
+ into an object of key-value pairs to add, or `undefined` to add nothing.
1203
+
1204
+ #### Template
1205
+
1206
+ The type of items in the source proxy.
1207
+
1208
+ #### Template
1209
+
1210
+ The type of the aggregated output object (should encompass all possible key-value pairs).
1211
+
1212
+ #### Example
1213
+
1214
+ ```typescript
1215
+ const items = proxy([
1216
+ { id: 'a', value: 10 },
1217
+ { id: 'b', value: 20 },
1218
+ ]);
1219
+ const itemsById = multiMap(items, (item) => ({
1220
+ [item.id]: item.value,
1221
+ [item.id+item.id]: item.value*10,
1222
+ }));
1223
+ // itemsById is proxy({ a: 10, aa: 100, b: 20, bb: 200 })
1224
+
1225
+ $(() => console.log(itemsById));
1226
+
1227
+ items.push({ id: 'c', value: 30 });
1228
+ // itemsById becomes proxy({ a: 10, aa: 100, b: 20, bb: 200, c: 30, cc: 300 })
1229
+ ```
1230
+
1231
+ #### Call Signature
1232
+
1233
+ > **multiMap**\<`IN`, `OUT`\>(`source`, `func`): `OUT`
1234
+
1235
+ Defined in: [aberdeen.ts:2890](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2890)
1236
+
1237
+ When using an array as `source`.
1238
+
1239
+ ##### Type Parameters
1240
+
1241
+ ###### IN
1242
+
1243
+ `IN`
1244
+
1245
+ ###### OUT
1246
+
1247
+ `OUT` *extends* `object`
1248
+
1249
+ ##### Parameters
1250
+
1251
+ ###### source
1252
+
1253
+ `IN`[]
1254
+
1255
+ ###### func
1256
+
1257
+ (`value`, `index`) => `undefined` \| `OUT`
1258
+
1259
+ ##### Returns
1260
+
1261
+ `OUT`
1262
+
1263
+ #### Call Signature
1264
+
1265
+ > **multiMap**\<`K`, `IN`, `OUT`\>(`source`, `func`): `OUT`
1266
+
1267
+ Defined in: [aberdeen.ts:2895](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2895)
1268
+
1269
+ When using an object as `source`.
1270
+
1271
+ ##### Type Parameters
1272
+
1273
+ ###### K
1274
+
1275
+ `K` *extends* `string` \| `number` \| `symbol`
1276
+
1277
+ ###### IN
1278
+
1279
+ `IN`
1280
+
1281
+ ###### OUT
1282
+
1283
+ `OUT` *extends* `object`
1284
+
1285
+ ##### Parameters
1286
+
1287
+ ###### source
1288
+
1289
+ `Record`\<`K`, `IN`\>
1290
+
1291
+ ###### func
1292
+
1293
+ (`value`, `index`) => `undefined` \| `OUT`
1294
+
1295
+ ##### Returns
1296
+
1297
+ `OUT`
1298
+
1299
+ #### Call Signature
1300
+
1301
+ > **multiMap**\<`K`, `IN`, `OUT`\>(`source`, `func`): `OUT`
1302
+
1303
+ Defined in: [aberdeen.ts:2901](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2901)
1304
+
1305
+ When using a Map as `source`.
1306
+
1307
+ ##### Type Parameters
1308
+
1309
+ ###### K
1310
+
1311
+ `K`
1312
+
1313
+ ###### IN
1314
+
1315
+ `IN`
1316
+
1317
+ ###### OUT
1318
+
1319
+ `OUT` *extends* `object`
1320
+
1321
+ ##### Parameters
1322
+
1323
+ ###### source
1324
+
1325
+ `Map`\<`K`, `IN`\>
1326
+
1327
+ ###### func
1328
+
1329
+ (`value`, `key`) => `undefined` \| `OUT`
1330
+
1331
+ ##### Returns
1332
+
1333
+ `OUT`
1334
+
1335
+ ***
1336
+
1337
+ ### onEach()
1338
+
1339
+ Reactively iterates over the items of an observable array or object, optionally rendering content for each item.
1340
+
1341
+ Automatically updates when items are added, removed, or modified.
1342
+
1343
+ #### Param
1344
+
1345
+ The observable array or object to iterate over. Values that are `undefined` are skipped.
1346
+
1347
+ #### Param
1348
+
1349
+ A function called for each item in the array. It receives the item's (observable) value and its index/key. 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.
1350
+
1351
+ #### Param
1352
+
1353
+ 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, items are rendered in array index order. The returned key can be a number, string, or an array of numbers/strings for composite sorting. Use [invertString](#invertstring) on string keys for descending order. Returning `null` or `undefined` from `makeKey` will prevent the item from being rendered.
1354
+
1355
+ #### Examples
1356
+
1357
+ ```typescript
1358
+ const items = proxy(['apple', 'banana', 'cherry']);
1359
+
1360
+ // Basic iteration
1361
+ onEach(items, (item, index) => $(`li#${item} (#${index})`));
1362
+
1363
+ // Add a new item - the list updates automatically
1364
+ setTimeout(() => items.push('durian'), 2000);
1365
+ // Same for updates and deletes
1366
+ setTimeout(() => items[1] = 'berry', 4000);
1367
+ setTimeout(() => delete items[2], 6000);
1368
+ ```
1369
+
1370
+ ```typescript
1371
+ const users = proxy([
1372
+ { id: 3, group: 1, name: 'Charlie' },
1373
+ { id: 1, group: 1, name: 'Alice' },
1374
+ { id: 2, group: 2, name: 'Bob' },
1375
+ ]);
1376
+
1377
+ // Sort by name alphabetically
1378
+ onEach(users, (user) => {
1379
+ $(`p#${user.name} (id=${user.id})`);
1380
+ }, (user) => [user.group, user.name]); // Sort by group, and within each group sort by name
1381
+ ```
1382
+
1383
+ ```javascript
1384
+ const config = proxy({ theme: 'dark', fontSize: 14, showTips: true });
1385
+
1386
+ // Display configuration options
1387
+ $('dl', () => {
1388
+ onEach(config, (value, key) => {
1389
+ if (key === 'showTips') return; // Don't render this one
1390
+ $('dt#'+key);
1391
+ $('dd#'+value);
1392
+ });
1393
+ });
1394
+
1395
+ // Change a value - the display updates automatically
1396
+ setTimeout(() => config.fontSize = 16, 2000);
1397
+ ```
1398
+
1399
+ #### See
1400
+
1401
+ [invertString](#invertstring) To easily create keys for reverse sorting.
1402
+
1403
+ #### Call Signature
1404
+
1405
+ > **onEach**\<`K`, `T`\>(`target`, `render`, `makeKey?`): `void`
1406
+
1407
+ Defined in: [aberdeen.ts:875](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L875)
1408
+
1409
+ ##### Type Parameters
1410
+
1411
+ ###### K
1412
+
1413
+ `K`
1414
+
1415
+ ###### T
1416
+
1417
+ `T`
1418
+
1419
+ ##### Parameters
1420
+
1421
+ ###### target
1422
+
1423
+ `Map`\<`K`, `undefined` \| `T`\>
1424
+
1425
+ ###### render
1426
+
1427
+ (`value`, `key`) => `void`
1428
+
1429
+ ###### makeKey?
1430
+
1431
+ (`value`, `key`) => `SortKeyType`
1432
+
1433
+ ##### Returns
1434
+
1435
+ `void`
1436
+
1437
+ #### Call Signature
1438
+
1439
+ > **onEach**\<`T`\>(`target`, `render`, `makeKey?`): `void`
1440
+
1441
+ Defined in: [aberdeen.ts:880](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L880)
1442
+
1443
+ ##### Type Parameters
1444
+
1445
+ ###### T
1446
+
1447
+ `T`
1448
+
1449
+ ##### Parameters
1450
+
1451
+ ###### target
1452
+
1453
+ readonly (`undefined` \| `T`)[]
1454
+
1455
+ ###### render
1456
+
1457
+ (`value`, `index`) => `void`
1458
+
1459
+ ###### makeKey?
1460
+
1461
+ (`value`, `index`) => `SortKeyType`
1462
+
1463
+ ##### Returns
1464
+
1465
+ `void`
1466
+
1467
+ #### Call Signature
1468
+
1469
+ > **onEach**\<`K`, `T`\>(`target`, `render`, `makeKey?`): `void`
1470
+
1471
+ Defined in: [aberdeen.ts:885](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L885)
1472
+
1473
+ ##### Type Parameters
1474
+
1475
+ ###### K
1476
+
1477
+ `K` *extends* `string` \| `number` \| `symbol`
1478
+
1479
+ ###### T
1480
+
1481
+ `T`
1482
+
1483
+ ##### Parameters
1484
+
1485
+ ###### target
1486
+
1487
+ `Record`\<`K`, `undefined` \| `T`\>
1488
+
1489
+ ###### render
1490
+
1491
+ (`value`, `index`) => `void`
1492
+
1493
+ ###### makeKey?
1494
+
1495
+ (`value`, `index`) => `SortKeyType`
1496
+
1497
+ ##### Returns
1498
+
1499
+ `void`
1500
+
1501
+ ***
1502
+
1503
+ ### partition()
1504
+
1505
+ Reactively partitions items from a source proxy (array or object) into multiple "bucket" proxies
1506
+ based on keys determined by a classifier function.
1507
+
1508
+ This function iterates through the `source` proxy using [onEach](#oneach). For each item,
1509
+ it calls the classifier `func`, which should return:
1510
+ - A single key (`OUT_K`): The item belongs to the bucket with this key.
1511
+ - An array of keys (`OUT_K[]`): The item belongs to all buckets specified in the array.
1512
+ - `undefined`: The item is not placed in any bucket.
1513
+
1514
+ The function returns a main proxied object. The keys of this object are the bucket keys (`OUT_K`)
1515
+ returned by `func`. Each value associated with a bucket key is another proxied object (the "bucket").
1516
+ This inner bucket object maps the *original* keys/indices from the `source` to the items
1517
+ themselves that were classified into that bucket.
1518
+
1519
+ The entire structure is reactive. Changes in the `source` proxy (adding/removing/updating items)
1520
+ or changes in dependencies read by the `func` will cause the output partitioning to update automatically.
1521
+ Buckets are created dynamically as needed and removed when they become empty.
1522
+
1523
+ #### Param
1524
+
1525
+ The input proxied Array or Record (e.g., created by [proxy](#proxy)) containing the items to partition.
1526
+
1527
+ #### Param
1528
+
1529
+ A classifier function `(value: IN_V, key: IN_K | number) => undefined | OUT_K | OUT_K[]`.
1530
+ It receives the item's value and its original key/index from the `source`. It returns the bucket key(s)
1531
+ the item belongs to, or `undefined` to ignore the item.
1532
+
1533
+ #### Template
1534
+
1535
+ The type of the keys used for the output buckets (string, number, or symbol).
1536
+
1537
+ #### Template
1538
+
1539
+ The type of the values in the source proxy.
1540
+
1541
+ #### Template
1542
+
1543
+ The type of the keys in the source proxy (if it's a Record).
1544
+
1545
+ #### Examples
1546
+
1547
+ ```typescript
1548
+ interface Product { id: string; category: string; name: string; }
1549
+ const products = proxy<Product[]>([
1550
+ { id: 'p1', category: 'Fruit', name: 'Apple' },
1551
+ { id: 'p2', category: 'Veg', name: 'Carrot' },
1552
+ { id: 'p3', category: 'Fruit', name: 'Banana' },
1553
+ ]);
1554
+
1555
+ // Partition products by category. Output keys are categories (string).
1556
+ // Inner keys are original array indices (number).
1557
+ const productsByCategory = partition(products, (product) => product.category);
1558
+
1559
+ // Reactively show the data structure
1560
+ dump(productsByCategory);
1561
+
1562
+ // Make random changes to the categories, to show reactiveness
1563
+ setInterval(() => products[0|(Math.random()*3)].category = ['Snack','Fruit','Veg'][0|(Math.random()*3)], 2000);
1564
+ ```
1565
+
1566
+ ```typescript
1567
+ interface User { id: number; tags: string[]; name: string; }
1568
+ const users = proxy({
1569
+ 'u1': { name: 'Alice', tags: ['active', 'new'] },
1570
+ 'u2': { name: 'Bob', tags: ['active'] }
1571
+ });
1572
+
1573
+ // Partition users by tag. Output keys are tags (string).
1574
+ // Inner keys are original object keys (string: 'u1', 'u2').
1575
+ const usersByTag = partition(users, (user) => user.tags);
1576
+
1577
+ console.log(usersByTag);
1578
+ ```
1579
+
1580
+ #### Call Signature
1581
+
1582
+ > **partition**\<`OUT_K`, `IN_V`\>(`source`, `func`): `Record`\<`OUT_K`, `Record`\<`number`, `IN_V`\>\>
1583
+
1584
+ Defined in: [aberdeen.ts:2965](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2965)
1585
+
1586
+ When using an object as `array`.
1587
+
1588
+ ##### Type Parameters
1589
+
1590
+ ###### OUT_K
1591
+
1592
+ `OUT_K` *extends* `string` \| `number` \| `symbol`
1593
+
1594
+ ###### IN_V
1595
+
1596
+ `IN_V`
1597
+
1598
+ ##### Parameters
1599
+
1600
+ ###### source
1601
+
1602
+ `IN_V`[]
1603
+
1604
+ ###### func
1605
+
1606
+ (`value`, `key`) => `undefined` \| `OUT_K` \| `OUT_K`[]
1607
+
1608
+ ##### Returns
1609
+
1610
+ `Record`\<`OUT_K`, `Record`\<`number`, `IN_V`\>\>
1611
+
1612
+ #### Call Signature
1613
+
1614
+ > **partition**\<`IN_K`, `OUT_K`, `IN_V`\>(`source`, `func`): `Record`\<`OUT_K`, `Record`\<`IN_K`, `IN_V`\>\>
1615
+
1616
+ Defined in: [aberdeen.ts:2970](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2970)
1617
+
1618
+ When using an object as `source`.
1619
+
1620
+ ##### Type Parameters
1621
+
1622
+ ###### IN_K
1623
+
1624
+ `IN_K` *extends* `string` \| `number` \| `symbol`
1625
+
1626
+ ###### OUT_K
1627
+
1628
+ `OUT_K` *extends* `string` \| `number` \| `symbol`
1629
+
1630
+ ###### IN_V
1631
+
1632
+ `IN_V`
1633
+
1634
+ ##### Parameters
1635
+
1636
+ ###### source
1637
+
1638
+ `Record`\<`IN_K`, `IN_V`\>
1639
+
1640
+ ###### func
1641
+
1642
+ (`value`, `key`) => `undefined` \| `OUT_K` \| `OUT_K`[]
1643
+
1644
+ ##### Returns
1645
+
1646
+ `Record`\<`OUT_K`, `Record`\<`IN_K`, `IN_V`\>\>
1647
+
1648
+ #### Call Signature
1649
+
1650
+ > **partition**\<`IN_K`, `OUT_K`, `IN_V`\>(`source`, `func`): `Record`\<`OUT_K`, `Record`\<`IN_K`, `IN_V`\>\>
1651
+
1652
+ Defined in: [aberdeen.ts:2979](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2979)
1653
+
1654
+ When using a Map as `source`.
1655
+
1656
+ ##### Type Parameters
1657
+
1658
+ ###### IN_K
1659
+
1660
+ `IN_K` *extends* `string` \| `number` \| `symbol`
1661
+
1662
+ ###### OUT_K
1663
+
1664
+ `OUT_K` *extends* `string` \| `number` \| `symbol`
1665
+
1666
+ ###### IN_V
1667
+
1668
+ `IN_V`
1669
+
1670
+ ##### Parameters
1671
+
1672
+ ###### source
1673
+
1674
+ `Map`\<`IN_K`, `IN_V`\>
1675
+
1676
+ ###### func
1677
+
1678
+ (`value`, `key`) => `undefined` \| `OUT_K` \| `OUT_K`[]
1679
+
1680
+ ##### Returns
1681
+
1682
+ `Record`\<`OUT_K`, `Record`\<`IN_K`, `IN_V`\>\>
1683
+
1684
+ ***
1685
+
1686
+ ### peek()
1687
+
1688
+ #### Call Signature
1689
+
1690
+ > **peek**\<`T`, `K`\>(`target`, `key`): `T`\[`K`\]
1691
+
1692
+ Defined in: [aberdeen.ts:2781](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2781)
1693
+
1694
+ Executes a function or retrieves a value *without* creating subscriptions in the current reactive scope, and returns its result.
1695
+
1696
+ This is useful when you need to access reactive data inside a reactive scope (like [$](#))
1697
+ but do not want changes to that specific data to trigger a re-execute of the scope.
1698
+
1699
+ Note: You may also use [unproxy](#unproxy) to get to the raw underlying data structure, which can be used to similar effect.
1700
+
1701
+ ##### Type Parameters
1702
+
1703
+ ###### T
1704
+
1705
+ `T` *extends* `object`
1706
+
1707
+ ###### K
1708
+
1709
+ `K` *extends* `string` \| `number` \| `symbol`
1710
+
1711
+ ##### Parameters
1712
+
1713
+ ###### target
1714
+
1715
+ `T`
1716
+
1717
+ Either a function to execute, or an object (which may also be an Array or a Map) to index.
1718
+
1719
+ ###### key
1720
+
1721
+ `K`
1722
+
1723
+ Optional key/index to use when `target` is an object.
1724
+
1725
+ ##### Returns
1726
+
1727
+ `T`\[`K`\]
1728
+
1729
+ 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.
1730
+
1731
+ ##### Example
1732
+
1733
+ ```typescript
1734
+ const data = proxy({ a: 1, b: 2 });
1735
+ $(() => {
1736
+ // re-executes only when data.a changes, because data.b is peeked.
1737
+ const b = peek(() => data.b);
1738
+ console.log(`A is ${data.a}, B was ${b} when A changed.`);
1739
+ });
1740
+ data.b = 3; // Does not trigger console.log
1741
+ data.a = 2; // Triggers console.log (logs "A is 2, B was 3 when A changed.")
1742
+ ```
1743
+
1744
+ #### Call Signature
1745
+
1746
+ > **peek**\<`K`, `V`\>(`target`, `key`): `undefined` \| `V`
1747
+
1748
+ Defined in: [aberdeen.ts:2782](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2782)
1749
+
1750
+ Executes a function or retrieves a value *without* creating subscriptions in the current reactive scope, and returns its result.
1751
+
1752
+ This is useful when you need to access reactive data inside a reactive scope (like [$](#))
1753
+ but do not want changes to that specific data to trigger a re-execute of the scope.
1754
+
1755
+ Note: You may also use [unproxy](#unproxy) to get to the raw underlying data structure, which can be used to similar effect.
1756
+
1757
+ ##### Type Parameters
1758
+
1759
+ ###### K
1760
+
1761
+ `K`
1762
+
1763
+ ###### V
1764
+
1765
+ `V`
1766
+
1767
+ ##### Parameters
1768
+
1769
+ ###### target
1770
+
1771
+ `Map`\<`K`, `V`\>
1772
+
1773
+ Either a function to execute, or an object (which may also be an Array or a Map) to index.
1774
+
1775
+ ###### key
1776
+
1777
+ `K`
1778
+
1779
+ Optional key/index to use when `target` is an object.
1780
+
1781
+ ##### Returns
1782
+
1783
+ `undefined` \| `V`
1784
+
1785
+ 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.
1786
+
1787
+ ##### Example
1788
+
1789
+ ```typescript
1790
+ const data = proxy({ a: 1, b: 2 });
1791
+ $(() => {
1792
+ // re-executes only when data.a changes, because data.b is peeked.
1793
+ const b = peek(() => data.b);
1794
+ console.log(`A is ${data.a}, B was ${b} when A changed.`);
1795
+ });
1796
+ data.b = 3; // Does not trigger console.log
1797
+ data.a = 2; // Triggers console.log (logs "A is 2, B was 3 when A changed.")
1798
+ ```
1799
+
1800
+ #### Call Signature
1801
+
1802
+ > **peek**\<`T`\>(`target`, `key`): `undefined` \| `T`
1803
+
1804
+ Defined in: [aberdeen.ts:2783](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2783)
1805
+
1806
+ Executes a function or retrieves a value *without* creating subscriptions in the current reactive scope, and returns its result.
1807
+
1808
+ This is useful when you need to access reactive data inside a reactive scope (like [$](#))
1809
+ but do not want changes to that specific data to trigger a re-execute of the scope.
1810
+
1811
+ Note: You may also use [unproxy](#unproxy) to get to the raw underlying data structure, which can be used to similar effect.
1812
+
1813
+ ##### Type Parameters
1814
+
1815
+ ###### T
1816
+
1817
+ `T`
1818
+
1819
+ ##### Parameters
1820
+
1821
+ ###### target
1822
+
1823
+ `T`[]
1824
+
1825
+ Either a function to execute, or an object (which may also be an Array or a Map) to index.
1826
+
1827
+ ###### key
1828
+
1829
+ `number`
1830
+
1831
+ Optional key/index to use when `target` is an object.
1832
+
1833
+ ##### Returns
1834
+
1835
+ `undefined` \| `T`
1836
+
1837
+ 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.
1838
+
1839
+ ##### Example
1840
+
1841
+ ```typescript
1842
+ const data = proxy({ a: 1, b: 2 });
1843
+ $(() => {
1844
+ // re-executes only when data.a changes, because data.b is peeked.
1845
+ const b = peek(() => data.b);
1846
+ console.log(`A is ${data.a}, B was ${b} when A changed.`);
1847
+ });
1848
+ data.b = 3; // Does not trigger console.log
1849
+ data.a = 2; // Triggers console.log (logs "A is 2, B was 3 when A changed.")
1850
+ ```
1851
+
1852
+ #### Call Signature
1853
+
1854
+ > **peek**\<`T`\>(`target`): `T`
1855
+
1856
+ Defined in: [aberdeen.ts:2784](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2784)
1857
+
1858
+ Executes a function or retrieves a value *without* creating subscriptions in the current reactive scope, and returns its result.
1859
+
1860
+ This is useful when you need to access reactive data inside a reactive scope (like [$](#))
1861
+ but do not want changes to that specific data to trigger a re-execute of the scope.
1862
+
1863
+ Note: You may also use [unproxy](#unproxy) to get to the raw underlying data structure, which can be used to similar effect.
1864
+
1865
+ ##### Type Parameters
1866
+
1867
+ ###### T
1868
+
1869
+ `T`
1870
+
1871
+ ##### Parameters
1872
+
1873
+ ###### target
1874
+
1875
+ () => `T`
1876
+
1877
+ Either a function to execute, or an object (which may also be an Array or a Map) to index.
1878
+
1879
+ ##### Returns
1880
+
1881
+ `T`
1882
+
1883
+ 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.
1884
+
1885
+ ##### Example
1886
+
1887
+ ```typescript
1888
+ const data = proxy({ a: 1, b: 2 });
1889
+ $(() => {
1890
+ // re-executes only when data.a changes, because data.b is peeked.
1891
+ const b = peek(() => data.b);
1892
+ console.log(`A is ${data.a}, B was ${b} when A changed.`);
1893
+ });
1894
+ data.b = 3; // Does not trigger console.log
1895
+ data.a = 2; // Triggers console.log (logs "A is 2, B was 3 when A changed.")
1896
+ ```
1897
+
1898
+ ***
1899
+
1900
+ ### proxy()
1901
+
1902
+ Creates a reactive proxy around the given data.
1903
+
1904
+ Reading properties from the returned proxy within a reactive scope (like one created by
1905
+ [$](#) or [derive](#derive)) establishes a subscription. Modifying properties *through*
1906
+ the proxy will notify subscribed scopes, causing them to re-execute.
1907
+
1908
+ - Plain objects and arrays are wrapped in a standard JavaScript `Proxy` that intercepts
1909
+ property access and mutations, but otherwise works like the underlying data.
1910
+ - Primitives (string, number, boolean, null, undefined) are wrapped in an object
1911
+ `{ value: T }` which is then proxied. Access the primitive via the `.value` property.
1912
+ - Promises are represented by proxied objects `{ busy: boolean, value?: T, error?: any }`.
1913
+ Initially, `busy` is `true`. When the promise resolves, `value` is set and `busy`
1914
+ is set to `false`. If the promise is rejected, `error` is set and `busy` is also
1915
+ set to `false`.
1916
+
1917
+ Use [unproxy](#unproxy) to get the original underlying data back.
1918
+
1919
+ #### Param
1920
+
1921
+ The object, array, or primitive value to make reactive.
1922
+
1923
+ #### Template
1924
+
1925
+ The type of the data being proxied.
1926
+
1927
+ #### Examples
1928
+
1929
+ ```javascript
1930
+ const state = proxy({ count: 0, message: 'Hello' });
1931
+ $(() => console.log(state.message)); // Subscribes to message
1932
+ setTimeout(() => state.message = 'World', 1000); // Triggers the observing function
1933
+ setTimeout(() => state.count++, 2000); // Triggers nothing
1934
+ ```
1935
+
1936
+ ```javascript
1937
+ const items = proxy(['a', 'b']);
1938
+ $(() => console.log(items.length)); // Subscribes to length
1939
+ setTimeout(() => items.push('c'), 2000); // Triggers the observing function
1940
+ ```
1941
+
1942
+ ```javascript
1943
+ const name = proxy('Aberdeen');
1944
+ $(() => console.log(name.value)); // Subscribes to value
1945
+ setTimeout(() => name.value = 'UI', 2000); // Triggers the observing function
1946
+ ```
1947
+
1948
+ ```typescript
1949
+ class Widget {
1950
+ constructor(public name: string, public width: number, public height: number) {}
1951
+ grow() { this.width *= 2; }
1952
+ toString() { return `${this.name}Widget (${this.width}x${this.height})`; }
1953
+ }
1954
+ let graph: Widget = proxy(new Widget('Graph', 200, 100));
1955
+ $(() => console.log(''+graph));
1956
+ setTimeout(() => graph.grow(), 2000);
1957
+ setTimeout(() => graph.grow(), 4000);
1958
+ ```
1959
+
1960
+ #### Call Signature
1961
+
1962
+ > **proxy**\<`T`\>(`target`): [`PromiseProxy`](#promiseproxy)\<`T`\>
1963
+
1964
+ Defined in: [aberdeen.ts:1375](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L1375)
1965
+
1966
+ ##### Type Parameters
1967
+
1968
+ ###### T
1969
+
1970
+ `T` *extends* `unknown`
1971
+
1972
+ ##### Parameters
1973
+
1974
+ ###### target
1975
+
1976
+ `Promise`\<`T`\>
1977
+
1978
+ ##### Returns
1979
+
1980
+ [`PromiseProxy`](#promiseproxy)\<`T`\>
1981
+
1982
+ #### Call Signature
1983
+
1984
+ > **proxy**\<`T`\>(`target`): `T` *extends* `number` ? `number` : `T` *extends* `string` ? `string` : `T` *extends* `boolean` ? `boolean` : `T`[]
1985
+
1986
+ Defined in: [aberdeen.ts:1376](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L1376)
1987
+
1988
+ ##### Type Parameters
1989
+
1990
+ ###### T
1991
+
1992
+ `T` *extends* `unknown`
1993
+
1994
+ ##### Parameters
1995
+
1996
+ ###### target
1997
+
1998
+ `T`[]
1999
+
2000
+ ##### Returns
2001
+
2002
+ `T` *extends* `number` ? `number` : `T` *extends* `string` ? `string` : `T` *extends* `boolean` ? `boolean` : `T`[]
2003
+
2004
+ #### Call Signature
2005
+
2006
+ > **proxy**\<`T`\>(`target`): `T`
2007
+
2008
+ Defined in: [aberdeen.ts:1377](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L1377)
2009
+
2010
+ ##### Type Parameters
2011
+
2012
+ ###### T
2013
+
2014
+ `T` *extends* `object`
2015
+
2016
+ ##### Parameters
2017
+
2018
+ ###### target
2019
+
2020
+ `T`
2021
+
2022
+ ##### Returns
2023
+
2024
+ `T`
2025
+
2026
+ #### Call Signature
2027
+
2028
+ > **proxy**\<`T`\>(`target`): `ValueRef`\<`T` *extends* `number` ? `number` : `T` *extends* `string` ? `string` : `T` *extends* `boolean` ? `boolean` : `T`\>
2029
+
2030
+ Defined in: [aberdeen.ts:1378](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L1378)
2031
+
2032
+ ##### Type Parameters
2033
+
2034
+ ###### T
2035
+
2036
+ `T` *extends* `unknown`
2037
+
2038
+ ##### Parameters
2039
+
2040
+ ###### target
2041
+
2042
+ `T`
2043
+
2044
+ ##### Returns
2045
+
2046
+ `ValueRef`\<`T` *extends* `number` ? `number` : `T` *extends* `string` ? `string` : `T` *extends* `boolean` ? `boolean` : `T`\>
2047
+
2048
+ ***
2049
+
2050
+ ### ref()
2051
+
2052
+ > **ref**\<`T`, `K`\>(`target`, `index`): `ValueRef`\<`T`\[`K`\]\>
2053
+
2054
+ Defined in: [aberdeen.ts:1954](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L1954)
2055
+
2056
+ Creates a reactive reference (`{ value: T }`-like object) to a specific value
2057
+ within a proxied object or array.
2058
+
2059
+ This is primarily used for the `bind` property in [$](#) to create two-way data bindings
2060
+ with form elements, and for passing a reactive property to any of the [$](#) key-value pairs.
2061
+
2062
+ Reading `ref.value` accesses the property from the underlying proxy (and subscribes the current scope).
2063
+ Assigning to `ref.value` updates the property in the underlying proxy (triggering reactive updates).
2064
+
2065
+ #### Type Parameters
2066
+
2067
+ ##### T
2068
+
2069
+ `T` *extends* `TargetType`
2070
+
2071
+ ##### K
2072
+
2073
+ `K` *extends* `string` \| `number` \| `symbol`
2074
+
2075
+ #### Parameters
2076
+
2077
+ ##### target
2078
+
2079
+ `T`
2080
+
2081
+ The reactive proxy (created by [proxy](#proxy)) containing the target property.
2082
+
2083
+ ##### index
2084
+
2085
+ `K`
2086
+
2087
+ The key (for objects) or index (for arrays) of the property to reference.
2088
+
2089
+ #### Returns
2090
+
2091
+ `ValueRef`\<`T`\[`K`\]\>
2092
+
2093
+ A reference object with a `value` property linked to the specified proxy property.
2094
+
2095
+ #### Example
2096
+
2097
+ ```javascript
2098
+ const formData = proxy({ color: 'orange', velocity: 42 });
2099
+
2100
+ // Usage with `bind`
2101
+ $('input type=text bind=', ref(formData, 'color'));
2102
+
2103
+ // Usage as a dynamic property, causes a TextNode with just the name to be created and live-updated
2104
+ $('p text="Selected color: " text=', ref(formData, 'color'), 'color:', ref(formData, 'color'));
2105
+
2106
+ // Changes are actually stored in formData - this causes logs like `{color: "Blue", velocity 42}`
2107
+ $(() => console.log(formData))
2108
+ ```
2109
+
2110
+ ***
2111
+
2112
+ ### runQueue()
2113
+
2114
+ > **runQueue**(): `void`
2115
+
2116
+ Defined in: [aberdeen.ts:69](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L69)
2117
+
2118
+ Forces the immediate and synchronous execution of all pending reactive updates.
2119
+
2120
+ Normally, changes to observed data sources (like proxied objects or arrays)
2121
+ are processed asynchronously in a batch after a brief timeout (0ms). This function
2122
+ allows you to bypass the timeout and process the update queue immediately.
2123
+
2124
+ This can be useful in specific scenarios where you need the DOM to be updated
2125
+ synchronously.
2126
+
2127
+ This function is re-entrant, meaning it is safe to call `runQueue` from within
2128
+ a function that is itself being executed as part of an update cycle triggered
2129
+ by a previous (or the same) `runQueue` call.
2130
+
2131
+ #### Returns
2132
+
2133
+ `void`
2134
+
2135
+ #### Example
2136
+
2137
+ ```typescript
2138
+ const data = proxy("before");
2139
+
2140
+ $('#', data);
2141
+ console.log(1, document.body.innerHTML); // before
2142
+
2143
+ // Make an update that should cause the DOM to change.
2144
+ data.value = "after";
2145
+
2146
+ // Normally, the DOM update would happen after a timeout.
2147
+ // But this causes an immediate update:
2148
+ runQueue();
2149
+
2150
+ console.log(2, document.body.innerHTML); // after
2151
+ ```
2152
+
2153
+ ***
2154
+
2155
+ ### setErrorHandler()
2156
+
2157
+ > **setErrorHandler**(`handler?`): `void`
2158
+
2159
+ Defined in: [aberdeen.ts:2596](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2596)
2160
+
2161
+ Sets a custom error handler function for errors that occur asynchronously
2162
+ within reactive scopes (e.g., during updates triggered by proxy changes in
2163
+ [derive](#derive) or [$](#) render functions).
2164
+
2165
+ The default handler logs the error to `console.error` and adds a simple
2166
+ 'Error' message div to the DOM at the location where the error occurred (if possible).
2167
+
2168
+ Your handler can provide custom logging, UI feedback, or suppress the default
2169
+ error message.
2170
+
2171
+ #### Parameters
2172
+
2173
+ ##### handler?
2174
+
2175
+ (`error`) => `undefined` \| `boolean`
2176
+
2177
+ A function that accepts the `Error` object.
2178
+ - Return `false` to prevent adding an error message to the DOM.
2179
+ - Return `true` or `undefined` (or throw) to allow the error messages to be added to the DOM.
2180
+
2181
+ #### Returns
2182
+
2183
+ `void`
2184
+
2185
+ #### Example
2186
+
2187
+ ```typescript
2188
+ setErrorHandler(error => {
2189
+ console.warn('Aberdeen render error:', error.message);
2190
+ // Log to error reporting service
2191
+ // myErrorReporter.log(error);
2192
+
2193
+ try {
2194
+ // Attempt to show a custom message in the UI
2195
+ $('div#Oops, something went wrong!', errorClass);
2196
+ } catch (e) {
2197
+ // Ignore errors during error handling itself
2198
+ }
2199
+
2200
+ return false; // Suppress default console log and DOM error message
2201
+ });
2202
+
2203
+ // Styling for our custom error message
2204
+ const errorClass = insertCss('background-color:#e31f00 display:inline-block color:white r:3px padding: 2px 4px;');
2205
+
2206
+ // Cause an error within a render scope.
2207
+ $('div.box', () => {
2208
+ // Will cause our error handler to insert an error message within the box
2209
+ noSuchFunction();
2210
+ })
2211
+ ```
2212
+
2213
+ ***
2214
+
2215
+ ### setSpacingCssVars()
2216
+
2217
+ > **setSpacingCssVars**(`base`, `unit`): `void`
2218
+
2219
+ Defined in: [aberdeen.ts:1800](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L1800)
2220
+
2221
+ Initializes `cssVars[0]` through `cssVars[12]` with an exponential spacing scale.
2222
+
2223
+ The scale is calculated as `2^(n-3) * base`, providing values from `0.25 * base` to `512 * base`.
2224
+
2225
+ #### Parameters
2226
+
2227
+ ##### base
2228
+
2229
+ `number` = `1`
2230
+
2231
+ 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.
2232
+
2233
+ ##### unit
2234
+
2235
+ `string` = `'rem'`
2236
+
2237
+ The CSS unit to use, like 'rem', 'em', or 'px'. Defaults to 'rem'.
2238
+
2239
+ #### Returns
2240
+
2241
+ `void`
2242
+
2243
+ #### Example
2244
+
2245
+ ```javascript
2246
+ import { setSpacingCssVars, cssVars, onEach, $} from 'aberdeen';
2247
+ // Use default scale (0.25rem to 512rem)
2248
+ setSpacingCssVars();
2249
+
2250
+ // Use custom base size
2251
+ setSpacingCssVars(16, 'px'); // 4px to 8192px
2252
+
2253
+ // Use em units
2254
+ setSpacingCssVars(1, 'em'); // 0.25em to 512em
2255
+
2256
+ // Show the last generated spacing values
2257
+ onEach(cssVars, (value, key) => {
2258
+ $(`div #${key} → ${value}`)
2259
+ }, (value, key) => parseInt(key)); // Numeric sort
2260
+ ```
2261
+
2262
+ ***
2263
+
2264
+ ### unmountAll()
2265
+
2266
+ > **unmountAll**(): `void`
2267
+
2268
+ Defined in: [aberdeen.ts:2750](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L2750)
2269
+
2270
+ Removes all Aberdeen-managed DOM nodes and stops all active reactive scopes
2271
+ (created by [mount](#mount), [derive](#derive), [$](#) with functions, etc.).
2272
+
2273
+ This effectively cleans up the entire Aberdeen application state. Aside from in
2274
+ automated tests, there should probably be little reason to call this function.
2275
+
2276
+ #### Returns
2277
+
2278
+ `void`
2279
+
2280
+ ***
2281
+
2282
+ ### unproxy()
2283
+
2284
+ > **unproxy**\<`T`\>(`target`): `T`
2285
+
2286
+ Defined in: [aberdeen.ts:1492](https://github.com/vanviegen/aberdeen/blob/876d65e85fa77c9453fc72e223d2239e9c745656/src/aberdeen.ts#L1492)
2287
+
2288
+ Returns the original, underlying data target from a reactive proxy created by [proxy](#proxy).
2289
+ If the input `target` is not a proxy, it is returned directly.
2290
+
2291
+ This is useful when you want to avoid triggering subscriptions during read operations or
2292
+ re-executes during write operations. Using [peek](#peek) is an alternative way to achieve this.
2293
+
2294
+ #### Type Parameters
2295
+
2296
+ ##### T
2297
+
2298
+ `T`
2299
+
2300
+ The type of the target.
2301
+
2302
+ #### Parameters
2303
+
2304
+ ##### target
2305
+
2306
+ `T`
2307
+
2308
+ A proxied object, array, or any other value.
2309
+
2310
+ #### Returns
2311
+
2312
+ `T`
2313
+
2314
+ The underlying (unproxied) data, or the input value if it wasn't a proxy.
2315
+
2316
+ #### Example
2317
+
2318
+ ```typescript
2319
+ const userProxy = proxy({ name: 'Frank' });
2320
+ const rawUser = unproxy(userProxy);
2321
+
2322
+ // Log reactively
2323
+ $(() => console.log('proxied', userProxy.name));
2324
+ // The following will only ever log once, as we're not subscribing to any observable
2325
+ $(() => console.log('unproxied', rawUser.name));
2326
+
2327
+ // This cause the first log to run again:
2328
+ setTimeout(() => userProxy.name += '!', 1000);
2329
+
2330
+ // This doesn't cause any new logs:
2331
+ setTimeout(() => rawUser.name += '?', 2000);
2332
+
2333
+ // Both userProxy and rawUser end up as `{name: 'Frank!?'}`
2334
+ setTimeout(() => {
2335
+ console.log('final proxied', userProxy)
2336
+ console.log('final unproxied', rawUser)
2337
+ }, 3000);
2338
+ ```