aberdeen 1.1.0 → 1.3.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/README.md CHANGED
@@ -31,17 +31,17 @@ const state = proxy({question: "How many roads must a man walk down?", answer: 4
31
31
 
32
32
  $('h3', () => {
33
33
  // This function reruns whenever the question or the answer changes
34
- $(`:${state.question} ↪ ${state.answer || 'Blowing in the wind'}`)
34
+ $('text=', `${state.question} ↪ ${state.answer || 'Blowing in the wind'}`)
35
35
  });
36
36
 
37
37
  // Two-way bind state.question to an <input>
38
- $('input', {placeholder: 'Question', bind: ref(state, 'question')})
38
+ $('input placeholder=Question bind=', ref(state, 'question'))
39
39
 
40
40
  // Allow state.answer to be modified using both an <input> and buttons
41
- $('div.row', {$marginTop: '1em'}, () => {
42
- $('button:-', {click: () => state.answer--});
43
- $('input', {type: 'number', bind: ref(state, 'answer')})
44
- $('button:+', {click: () => state.answer++});
41
+ $('div.row marginTop:1em', () => {
42
+ $('button text=- click=', () => state.answer--);
43
+ $('input type=number bind=', ref(state, 'answer'))
44
+ $('button text=+ click=', () => state.answer++);
45
45
  });
46
46
  ```
47
47
 
@@ -79,10 +79,10 @@ function drawMain() {
79
79
 
80
80
  // Add item and delete checked buttons.
81
81
  $('div.row', () => {
82
- $('button:+', {
82
+ $('button#+', {
83
83
  click: () => items.push(new TodoItem("")),
84
84
  });
85
- $('button.outline:Delete checked', {
85
+ $('button.outline#Delete checked', {
86
86
  click: () => {
87
87
  for(let idx in items) {
88
88
  if (items[idx].done) delete items[idx];
@@ -104,7 +104,7 @@ function drawItem(item) {
104
104
  $({".done": ref(item,'done')});
105
105
 
106
106
  // The checkmark is hidden using CSS
107
- $('div.checkmark:✅');
107
+ $('div.checkmark#✅');
108
108
 
109
109
  if (editing.value) {
110
110
  // Label <input>. Save using enter or button.
@@ -117,15 +117,15 @@ function drawItem(item) {
117
117
  value: item.label,
118
118
  keydown: e => e.key==='Enter' && save(),
119
119
  });
120
- $('button.outline:Cancel', {click: () => editing.value = false});
121
- $('button:Save', {click: save});
120
+ $('button.outline#Cancel', {click: () => editing.value = false});
121
+ $('button#Save', {click: save});
122
122
  } else {
123
123
  // Label as text.
124
- $('p:' + item.label);
124
+ $('p#' + item.label);
125
125
 
126
126
  // Edit icon, if not done.
127
127
  if (!item.done) {
128
- $('a:Edit', {
128
+ $('a#Edit', {
129
129
  click: e => {
130
130
  editing.value = true;
131
131
  e.stopPropagation(); // We don't want to toggle as well.
@@ -134,7 +134,7 @@ function drawItem(item) {
134
134
  }
135
135
 
136
136
  // Clicking a row toggles done.
137
- $({click: () => item.done = !item.done, $cursor: 'pointer'});
137
+ $('cursor:pointer click=', () => item.done = !item.done);
138
138
  }
139
139
  });
140
140
  }
@@ -174,7 +174,24 @@ And you may want to study the examples above, of course!
174
174
 
175
175
  ## Changelog
176
176
 
177
- ### 1.1.0 (2024-09-12)
177
+ ### 1.3.0 (2025-12-03)
178
+ **Breaking changes:**
179
+ - The shortcut for setting inline CSS styles in now `$('div color:red')` instead of `$('div $color=red')`.
180
+ - The shortcut for adding text content is now `$('p#Hello')` instead of `$('p:Hello')`. It now also works with dynamic content: `$('p#', myObservable)`.
181
+
182
+ **Enhancements:**
183
+ - New A() string parser, reducing complexity and line count.
184
+
185
+ ### 1.2.0 (2025-09-27)
186
+
187
+ **Enhancements:**
188
+ - The `$` function now supports a more concise syntax for setting attributes and properties. Instead of writing `$('p', 'button', {$color: 'red', click: () => ...})`, you can now write `$('p button $color=red click=', () => ...)`.
189
+ - The `proxy()` function can now accept `Promise`s, which will return an observable object with properties for `busy` status, `error` (if any), and the resolved `value`. This makes it easier to call async functions from within UI code.
190
+
191
+ **Breaking changes:**
192
+ - When a UI render function returns a `Promise`, that will now be reported as an error. Async render functions are fundamentally incompatible with Aberdeen's reactive model, so it's helpful to point that out. Use the new `proxy()` async support instead.
193
+
194
+ ### 1.1.0 (2025-09-12)
178
195
 
179
196
  This major release aims to reduce surprises in our API, aligning more closely with regular JavaScript semantics (for better or worse).
180
197
 
package/README.md.bak ADDED
@@ -0,0 +1,212 @@
1
+ # [Aberdeen](https://aberdeenjs.org/) [![](https://img.shields.io/badge/license-ISC-blue.svg)](https://github.com/vanviegen/aberdeen/blob/master/LICENSE.txt) [![](https://badge.fury.io/js/aberdeen.svg)](https://badge.fury.io/js/aberdeen) ![](https://img.shields.io/bundlejs/size/aberdeen) [![](https://img.shields.io/github/last-commit/vanviegen/aberdeen)](https://github.com/vanviegen/aberdeen)
2
+
3
+ Build fast reactive UIs in pure TypeScript/JavaScript without a virtual DOM.
4
+
5
+ Aberdeen's approach is refreshingly simple:
6
+
7
+ > Use many small anonymous functions for emitting DOM elements, and automatically rerun them when their underlying data changes. JavaScript `Proxy` is used to track reads and updates to this data, which can consist of anything, from simple values to complex, typed, and deeply nested data structures.
8
+
9
+ ## Why use Aberdeen?
10
+
11
+ - 🎩 **Simple:** Express UIs naturally in JavaScript/TypeScript, without build steps or JSX, and with a minimal amount of concepts you need to learn.
12
+ - ⏩ **Fast:** No virtual DOM. Aberdeen intelligently updates only the minimal, necessary parts of your UI when proxied data changes.
13
+ - 👥 **Awesome lists**: It's very easy and performant to reactively display data sorted by whatever you like.
14
+ - 🔬 **Tiny:** Around 6KB (minimized and gzipped) for the core system. Zero runtime dependencies.
15
+ - 🔋 **Batteries included**: Comes with browser history management, routing, revertible patches for optimistic user-interface updates, component-local CSS, SVG support, helper functions for transforming reactive data (mapping, partitioning, filtering, etc) and hide/unhide transition effects. No bikeshedding required!
16
+
17
+ ## Why *not* use Aberdeen?
18
+
19
+ - 🤷 **Lack of community:** There are not many of us -Aberdeen developers- yet, so don't expect terribly helpful Stack Overflow/AI answers.
20
+ - 📚 **Lack of ecosystem:** You'd have to code things yourself, instead of duct-taping together a gazillion React ecosystem libraries.
21
+
22
+ ## Examples
23
+
24
+ First, let's start with the obligatory reactive counter example. If you're reading this on [the official website](https://aberdeenjs.org) you should see a working demo below the code, and an 'edit' button in the top-right corner of the code, to play around.
25
+
26
+ ```javascript
27
+ import A from 'aberdeen';
28
+
29
+ // Define some state as a proxied (observable) object
30
+ const state = A.proxy({question: "How many roads must a man walk down?", answer: 42});
31
+
32
+ A`h3`(() => {
33
+ // This function reruns whenever the question or the answer changes
34
+ A`"${state.question} ↪ ${state.answer || 'Blowing in the wind'}"`;
35
+ });
36
+
37
+ // Two-way bind state.question to an <input>
38
+ A`input placeholder=Question bind!${A.at(state, 'question')}`;
39
+
40
+ // Allow state.answer to be modified using both an <input> and buttons
41
+ A`div.row`(() => {
42
+ A`button click=${() => state.answer--} "-"`;
43
+ A`input type=number bind!${A.at(state, 'answer')}`;
44
+ A`button click=${() => state.answer++} "+"`;
45
+ });
46
+ ```
47
+
48
+ Okay, next up is a somewhat more complex app - a todo-list with the following behavior:
49
+
50
+ - New items open in an 'editing state'.
51
+ - Items that are in 'editing state' show a text input, a save button and a cancel button. Done status cannot be toggled while editing.
52
+ - Pressing one of the buttons, or pressing enter will transition from 'editing state' to 'viewing state', saving the new label text unless cancel was pressed.
53
+ - In 'viewing state', the label is shown as non-editable. There's an 'Edit' link, that will transition the item to 'editing state'. Clicking anywhere else will toggle the done status.
54
+ - The list of items is sorted alphabetically by label. Items move when 'save' changes their label.
55
+ - Items that are created, moved or deleted grow and shrink as appropriate.
56
+
57
+ Pfew.. now let's look at the code:
58
+
59
+ ```typescript
60
+ import A from "aberdeen";
61
+ import {grow, shrink} from "aberdeen/transitions";
62
+
63
+ // We'll use a simple class to store our data.
64
+ class TodoItem {
65
+ constructor(public label: string = '', public done: boolean = false) {}
66
+ toggle() { this.done = !this.done; }
67
+ }
68
+
69
+ // The top-level user interface.
70
+ function drawMain() {
71
+ // Add some initial items. We'll wrap a proxy() around it!
72
+ let items: TodoItem[] = A.proxy([
73
+ new TodoItem('Make todo-list demo', true),
74
+ new TodoItem('Learn Aberdeen', false),
75
+ ]);
76
+
77
+ // Draw the list, ordered by label.
78
+ A.onEach(items, drawItem, item => item.label);
79
+
80
+ // Add item and delete checked buttons.
81
+ A`div.row`(() => {
82
+ A`button click=${() => items.push(new TodoItem(""))} "+"`;
83
+ A`button.outline click=${() => {
84
+ for(let idx in items) {
85
+ if (items[idx].done) delete items[idx];
86
+ }
87
+ }} "Delete checked"`;
88
+ });
89
+ };
90
+
91
+ // Called for each todo list item.
92
+ function drawItem(item) {
93
+ // Items without a label open in editing state.
94
+ // Note that we're creating this proxy outside the `div.row` scope
95
+ // create below, so that it will persist when that state reruns.
96
+ let editing: {value: boolean} = A.proxy(item.label == '');
97
+
98
+ A`div.row.${todoItemStyle} create!${grow} destroy!${shrink}`(() => {
99
+ // Conditionally add a class to `div.row`, based on item.done
100
+ A`if!${A.at(item,'done')} .done`;
101
+
102
+ // The checkmark is hidden using CSS
103
+ A`div.checkmark "✅"`;
104
+
105
+ if (editing.value) {
106
+ // Label <input>. Save using enter or button.
107
+ function save() {
108
+ editing.value = false;
109
+ item.label = inputElement.value;
110
+ }
111
+ let inputElement = A`input placeholder=Label value~${item.label} keydown=${e => e.key==='Enter' && save()}`;
112
+ A`button.outline click=${() => editing.value = false} "Cancel"`;
113
+ A`button click=${save} "Save"`;
114
+ } else {
115
+ // Label as text.
116
+ A`p "${item.label}"`;
117
+
118
+ // Edit icon, if not done.
119
+ if (!item.done) {
120
+ A`a click=${e => {
121
+ editing.value = true;
122
+ e.stopPropagation(); // We don't want to toggle as well.
123
+ }} "Edit"`;
124
+ }
125
+
126
+ // Clicking a row toggles done.
127
+ A`click=${() => item.done = !item.done} cursor:pointer`;
128
+ }
129
+ });
130
+ }
131
+
132
+ // Insert some component-local CSS, specific for this demo.
133
+ const todoItemStyle = A.insertCss({
134
+ marginBottom: "0.5rem",
135
+ ".checkmark": {
136
+ opacity: 0.2,
137
+ },
138
+ "&.done": {
139
+ textDecoration: "line-through",
140
+ ".checkmark": {
141
+ opacity: 1,
142
+ },
143
+ },
144
+ });
145
+
146
+ // Go!
147
+ drawMain();
148
+ ```
149
+
150
+ Some further examples:
151
+
152
+ - [Input demo](https://aberdeenjs.org/examples/input/) - [Source](https://github.com/vanviegen/aberdeen/tree/master/examples/input)
153
+ - [Tic Tac Toe demo](https://aberdeenjs.org/examples/tictactoe/) - [Source](https://github.com/vanviegen/aberdeen/tree/master/examples/tictactoe)
154
+ - [List demo](https://aberdeenjs.org/examples/list/) - [Source](https://github.com/vanviegen/aberdeen/tree/master/examples/list)
155
+ - [Routing demo](https://aberdeenjs.org/examples/router/) - [Source](https://github.com/vanviegen/aberdeen/tree/master/examples/router)
156
+ - [JS Framework Benchmark demo](https://aberdeenjs.org/examples/js-framework-benchmark/) - [Source](https://github.com/vanviegen/aberdeen/tree/master/examples/js-framework-benchmark)
157
+
158
+ ## Learning Aberdeen
159
+
160
+ - [Tutorial](https://aberdeenjs.org/Tutorial/)
161
+ - [Reference documentation](https://aberdeenjs.org/modules.html)
162
+
163
+ And you may want to study the examples above, of course!
164
+
165
+ ## Changelog
166
+
167
+ ### 1.2.0 (2025-09-27)
168
+
169
+ **Enhancements:**
170
+ - The `A` function now supports a concise template literal syntax for creating elements, setting attributes and properties, adding classes, etc. See the documentation for details.
171
+ - The `A.proxy()` function can now accept `Promise`s, which will return an observable object with properties for `busy` status, `error` (if any), and the resolved `value`. This makes it easier to call async functions from within UI code.
172
+
173
+ **Breaking changes:**
174
+ - When a UI render function returns a `Promise`, that will now be reported as an error. Async render functions are fundamentally incompatible with Aberdeen's reactive model, so it's helpful to point that out. Use the new `A.proxy()` async support instead.
175
+ - Setting attributes versus properties is no longer automatically inferred. Use `name=value` for attributes and `name~value` for properties.
176
+ - Special attributes (like `bind`, `create`, `destroy`, `if`, `else`, `end`, and `html`) now use a different syntax: `name!value` or just `name!`.
177
+ - Conditional rendering has been completely redesigned, now using `if!`, `else!`, and `end!` special attributes with different semantics.
178
+
179
+ ### 1.1.0 (2025-09-12)
180
+
181
+ This major release aims to reduce surprises in our API, aligning more closely with regular JavaScript semantics (for better or worse).
182
+
183
+ **Breaking changes:**
184
+
185
+ - Functions that iterate objects (like `A.onEach` and `A.map`) will now only work on *own* properties of the object, ignoring those in the prototype chain. The new behavior should be more consistent and faster.
186
+ - These iteration function now properly distinguish between `undefined` and *empty*. Previously, object/array/map items with `undefined` values were considered non-existent. The new behavior (though arguably confusing) is more consistent with regular JavaScript semantics.
187
+ - The `A.copy` function no longer ..
188
+ - Supports `SHALLOW` and `MERGE` flags. The latter has been replaced by a dedicated `A.merge` function. The former turned out not to be particularly useful.
189
+ - Has weird special cases that would allow copying objects into maps and merging objects into arrays.
190
+ - Copies properties from the prototype chain of objects. Only *own* properties are copied now. As the prototype link itself *is* copied over, this should actually result in copies being *more* similar to the original.
191
+ - The `observe` function has been renamed to `A.derive` to better reflect its purpose and match terminology used in other reactive programming libraries.
192
+ - The `A.route` API brings some significant changes. Modifying the `A.route` observable (which should now be accessed as `A.route.current`) will now always result in changing the current browser history item (URL and state, using `replaceState`), instead of using a heuristic to figure out what you probably want. Dedicated functions have been added for navigating to a new URL (`A.go`), back to a previous URL (`A.back`), and for going up in the route hierarchy (`A.up`).
193
+ - The concept of immediate observers (through the `immediateObserve` function) no longer exists. It caused unexpected behavior (for instance due to the fact that an array `pop()` in JavaScript is implemented as a delete followed by a length change, so happens in two steps that would each call immediate observers). The reason it existed was mostly to enable a pre-1.0 version of the `A.route` API. It turned out to be a mistake.
194
+
195
+ **Enhancements:**
196
+
197
+ - The `A.peek` function can now also accept an object and a key as argument (e.g. `A.peek(obj, 'myKey')`). It does the same as `A.peek(() => obj.myKey)`, but more concise and faster.
198
+ - The `A.copy` and `A.merge` functions now ..
199
+ - Accept an optional `dstKey` argument, allowing you to assign to a specific key with `A.copy` semantics, and without subscribing to the key.
200
+ - Return a boolean indicating whether any changes were made.
201
+ - Are faster.
202
+ - A new `A.dispatcher` module has been added. It provides a simple and type-safe way to match URL paths to handler functions, and extract parameters from the path. You can still use your own routing solution if you prefer, of course.
203
+ - The `A.route` module now also has tests, making the whole project now fully covered by tests.
204
+
205
+ **Fixes:**
206
+
207
+ - Browser-back behavior in the `A.route` module had some reliability issues after page reloads.
208
+ - The `A.copy` and `A.clone` function created Maps and Arrays with the wrong internal type. So `instanceof Array` would say yes, while `Array.isArray` would say no. JavaScript is weird.
209
+
210
+ ### 1.0.0 (2025-05-07)
211
+
212
+ After five years of working on this library on and off, I'm finally happy with its API and the developer experience it offers. I'm calling it 1.0! To celebrate, I've created some pretty fancy (if I may say so myself) interactive documentation and a tutorial.
@@ -49,7 +49,7 @@ export declare function runQueue(): void;
49
49
  * ]);
50
50
  *
51
51
  * onEach(users, (user) => {
52
- * $(`p:${user.name}: ${user.score}`);
52
+ * $(`p#${user.name}: ${user.score}`);
53
53
  * }, (user) => invertString(user.name)); // Reverse alphabetic order
54
54
  * ```
55
55
  *
@@ -80,9 +80,9 @@ export declare function onEach<K extends string | number | symbol, T>(target: Re
80
80
  * // Reactively display a message if the items array is empty
81
81
  * $('div', () => {
82
82
  * if (isEmpty(items)) {
83
- * $('p', 'i:No items yet!');
83
+ * $('p', 'i#No items yet!');
84
84
  * } else {
85
- * onEach(items, item=>$('p:'+item));
85
+ * onEach(items, item=>$('p#'+item));
86
86
  * }
87
87
  * });
88
88
  *
@@ -125,6 +125,24 @@ export interface ValueRef<T> {
125
125
  * ```
126
126
  */
127
127
  export declare function count(proxied: TargetType): ValueRef<number>;
128
+ /**
129
+ * When `proxy` is called with a Promise, the returned object has this shape.
130
+ */
131
+ export interface PromiseProxy<T> {
132
+ /**
133
+ * True if the promise is still pending, false if it has resolved or rejected.
134
+ */
135
+ busy: boolean;
136
+ /**
137
+ * If the promise has resolved, this contains the resolved value.
138
+ */
139
+ value?: T;
140
+ /**
141
+ * If the promise has rejected, this contains the rejection error.
142
+ */
143
+ error?: any;
144
+ }
145
+ export declare function proxy<T extends any>(target: Promise<T>): PromiseProxy<T>;
128
146
  export declare function proxy<T extends any>(target: Array<T>): Array<T extends number ? number : T extends string ? string : T extends boolean ? boolean : T>;
129
147
  export declare function proxy<T extends object>(target: T): T;
130
148
  export declare function proxy<T extends any>(target: T): ValueRef<T extends number ? number : T extends string ? string : T extends boolean ? boolean : T>;
@@ -227,6 +245,12 @@ export declare function copy<T extends object>(dst: T, dstKey: keyof T, src: T[t
227
245
  */
228
246
  export declare function merge<T extends object>(dst: T, value: Partial<T>): boolean;
229
247
  export declare function merge<T extends object>(dst: T, dstKey: keyof T, value: Partial<T[typeof dstKey]>): boolean;
248
+ /**
249
+ * A symbol that can be added to an object to prevent it from being cloned by {@link clone} or {@link copy}.
250
+ * This is useful for objects that should be shared by reference. That also mean that their contents won't
251
+ * be observed for changes.
252
+ */
253
+ export declare const NO_COPY: unique symbol;
230
254
  /**
231
255
  * Clone an (optionally proxied) object or array.
232
256
  *
@@ -261,7 +285,7 @@ export declare function clone<T extends object>(src: T): T;
261
285
  * });
262
286
  *
263
287
  * // Usage as a dynamic property, causes a TextNode with just the name to be created and live-updated
264
- * $('p:Selected color: ', {
288
+ * $('p#Selected color: ', {
265
289
  * text: ref(formData, 'color'),
266
290
  * $color: ref(formData, 'color')
267
291
  * });
@@ -279,11 +303,13 @@ export declare function ref<T extends TargetType, K extends keyof T>(target: T,
279
303
  * @param {...(string | function | object | false | undefined | null)} args - Any number of arguments can be given. How they're interpreted depends on their types:
280
304
  *
281
305
  * - `string`: Strings can be used to create and insert new elements, set classnames for the *current* element, and add text to the current element.
282
- * The format of a string is: **tag**? (`.` **class**)* (':' **text**)?
283
- * meaning it consists of...
284
- * - An optional HTML **tag**, something like `h1`. If present, a DOM element of that tag is created, and that element will be the *current* element for the rest of this `$` function execution.
285
- * - Any number of CSS classes prefixed by `.` characters. These classes will be added to the *current* element.
286
- * - Optional content **text** prefixed by a `:` character, ranging til the end of the string. This will be added as a TextNode to the *current* element.
306
+ * The format of a string is: (**tag** | `.` **class** | **key**=**val** | **key**="**long val**")* ('#' **text** | **key**=)?
307
+ * So there can be:
308
+ * - Any number of **tag** element, 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.
309
+ * - Any number of 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.
310
+ * - Any number of key/value pairs with string values, like `placeholder="Your name"` or `data-id=123`. These will be handled according to the rules specified for `object`, below, but with the caveat that values can only be strings. The quotes around string values are optional, unless the value contains spaces. It's not possible to escape quotes within the value. If you want to do that, or if you have user-provided values, use the `object` syntax (see below) or end your string with `key=` followed by the data as a separate argument (see below).
311
+ * - The string may end in 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.
312
+ * - Alternatively, the string may end in 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 rules specified for `object` 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")`.
287
313
  * - `function`: When a function (without argument 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 create DOM elements with our *current* element as parent. 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 {@link clean}).
288
314
  * - `object`: When an object is passed in, its key-value pairs are used to modify the *current* element in the following ways...
289
315
  * - `{<attrName>: any}`: The common case is setting the value as an HTML attribute named key. So `{placeholder: "Your name"}` would add `placeholder="Your name"` to the current HTML element.
@@ -298,7 +324,7 @@ export declare function ref<T extends TargetType, K extends keyof T>(target: T,
298
324
  * - `{<any>: <obsvalue>}`: Create a new observer scope and read the `value` property of the given observable (proxy) variable from within it, and apply the contained value using any of the other rules in this list. Example:
299
325
  * ```typescript
300
326
  * const myColor = proxy('red');
301
- * $('p:Test', {$color: myColor, click: () => myColor.value = 'yellow'})
327
+ * $('p#Test', {$color: myColor, click: () => myColor.value = 'yellow'})
302
328
  * // Clicking the text will cause it to change color without recreating the <p> itself
303
329
  * ```
304
330
  * This is often used together with {@link ref}, in order to use properties other than `.value`.
@@ -311,16 +337,24 @@ export declare function ref<T extends TargetType, K extends keyof T>(target: T,
311
337
  *
312
338
  * @example Create Element
313
339
  * ```typescript
314
- * $('button.secondary.outline:Submit', {
340
+ * $('button.secondary.outline#Submit', {
315
341
  * disabled: false,
316
342
  * click: () => console.log('Clicked!'),
317
343
  * $color: 'red'
318
344
  * });
319
345
  * ```
320
346
  *
347
+ * Which can also be written as:
348
+ * ```typescript
349
+ * $('button.secondary.outline text=Submit $color=red disabled=', false, 'click=', () => console.log('Clicked!'));
350
+ * ```
351
+ *
352
+ * We want to set `disabled` as a property instead of an attribute, so we must use the `key=` syntax in order to provide
353
+ * `false` as a boolean instead of a string.
354
+ *
321
355
  * @example Create Nested Elements
322
356
  * ```typescript
323
- * let inputElement: Element = $('label:Click me', 'input', {type: 'checkbox'});
357
+ * let inputElement: Element = $('label#Click me', 'input', {type: 'checkbox'});
324
358
  * // You should usually not touch raw DOM elements, unless when integrating
325
359
  * // with non-Aberdeen code.
326
360
  * console.log('DOM element:', inputElement);
@@ -331,8 +365,8 @@ export declare function ref<T extends TargetType, K extends keyof T>(target: T,
331
365
  * const state = proxy({ count: 0 });
332
366
  * $('div', () => { // Outer element
333
367
  * // This scope re-renders when state.count changes
334
- * $(`p:Count is ${state.count}`);
335
- * $('button:Increment', { click: () => state.count++ });
368
+ * $(`p#Count is ${state.count}`);
369
+ * $('button#Increment', { click: () => state.count++ });
336
370
  * });
337
371
  * ```
338
372
  *
@@ -341,17 +375,17 @@ export declare function ref<T extends TargetType, K extends keyof T>(target: T,
341
375
  * const user = proxy({ name: '' });
342
376
  * $('input', { placeholder: 'Name', bind: ref(user, 'name') });
343
377
  * $('h3', () => { // Reactive scope
344
- * $(`:Hello ${user.name || 'stranger'}`);
378
+ * $(`#Hello ${user.name || 'stranger'}`);
345
379
  * });
346
380
  * ```
347
381
  *
348
382
  * @example Conditional Rendering
349
383
  * ```typescript
350
384
  * const show = proxy(false);
351
- * $('button', { click: () => show.value = !show.value }, () => $(show.value ? ':Hide' : ':Show'));
385
+ * $('button', { click: () => show.value = !show.value }, () => $(show.value ? '#Hide' : '#Show'));
352
386
  * $(() => { // Reactive scope
353
387
  * if (show.value) {
354
- * $('p:Details are visible!');
388
+ * $('p#Details are visible!');
355
389
  * }
356
390
  * });
357
391
  * ```
@@ -394,8 +428,8 @@ export declare function $(...args: (string | null | undefined | false | (() => v
394
428
  *
395
429
  * // Apply the styles
396
430
  * $(scopeClass, () => { // Add class to the div
397
- * $(`:Scoped content`);
398
- * $('div.child-element:Child'); // .AbdStl1 .child-element rule applies
431
+ * $(`#Scoped content`);
432
+ * $('div.child-element#Child'); // .AbdStl1 .child-element rule applies
399
433
  * });
400
434
  * ```
401
435
  *
@@ -411,7 +445,7 @@ export declare function $(...args: (string | null | undefined | false | (() => v
411
445
  * }
412
446
  * }, true); // Pass true for global
413
447
  *
414
- * $('a:Styled link');
448
+ * $('a#Styled link');
415
449
  * ```
416
450
  */
417
451
  export declare function insertCss(style: object, global?: boolean): string;
@@ -439,7 +473,7 @@ export declare function insertCss(style: object, global?: boolean): string;
439
473
  *
440
474
  * try {
441
475
  * // Attempt to show a custom message in the UI
442
- * $('div.error-message:Oops, something went wrong!');
476
+ * $('div.error-message#Oops, something went wrong!');
443
477
  * } catch (e) {
444
478
  * // Ignore errors during error handling itself
445
479
  * }
@@ -510,7 +544,7 @@ export declare function getParentElement(): Element;
510
544
  *
511
545
  * // Show the array items and maintain the sum
512
546
  * onEach(myArray, (item, index) => {
513
- * $(`code:${index}→${item}`);
547
+ * $(`code#${index}→${item}`);
514
548
  * // We'll update sum.value using peek, as += first does a read, but
515
549
  * // we don't want to subscribe.
516
550
  * peek(() => sum.value += item);
@@ -549,14 +583,14 @@ export declare function clean(cleaner: () => void): void;
549
583
  *
550
584
  * $('main', () => {
551
585
  * console.log('Welcome');
552
- * $('h3:Welcome, ' + data.user); // Reactive text
586
+ * $('h3#Welcome, ' + data.user); // Reactive text
553
587
  *
554
588
  * derive(() => {
555
589
  * // When data.notifications changes, only this inner scope reruns,
556
590
  * // leaving the `<p>Welcome, ..</p>` untouched.
557
591
  * console.log('Notifications');
558
- * $('code.notification-badge:' + data.notifications);
559
- * $('a:Notify!', {click: () => data.notifications++});
592
+ * $('code.notification-badge#' + data.notifications);
593
+ * $('a#Notify!', {click: () => data.notifications++});
560
594
  * });
561
595
  * });
562
596
  * ```
@@ -570,7 +604,7 @@ export declare function clean(cleaner: () => void): void;
570
604
  * const double = derive(() => counter.value * 2);
571
605
  *
572
606
  * $('h3', () => {
573
- * $(`:counter=${counter.value} double=${double.value}`);
607
+ * $(`#counter=${counter.value} double=${double.value}`);
574
608
  * })
575
609
  * ```
576
610
  *
@@ -607,12 +641,12 @@ export declare function derive<T>(func: () => T): ValueRef<T>;
607
641
  * setInterval(() => runTime.value++, 1000);
608
642
  *
609
643
  * mount(document.getElementById('app-root'), () => {
610
- * $('h4:Aberdeen App');
611
- * $(`p:Run time: ${runTime.value}s`);
644
+ * $('h4#Aberdeen App');
645
+ * $(`p#Run time: ${runTime.value}s`);
612
646
  * // Conditionally render some content somewhere else in the static page
613
647
  * if (runTime.value&1) {
614
648
  * mount(document.getElementById('title-extra'), () =>
615
- * $(`i:(${runTime.value}s)`)
649
+ * $(`i#(${runTime.value}s)`)
616
650
  * );
617
651
  * }
618
652
  * });
@@ -701,7 +735,7 @@ export declare function partition<IN_K extends string | number | symbol, OUT_K e
701
735
  * items: ['a', 'b']
702
736
  * });
703
737
  *
704
- * $('h2:Live State Dump');
738
+ * $('h2#Live State Dump');
705
739
  * dump(state);
706
740
  *
707
741
  * // Change state later, the dump in the DOM will update