aberdeen 1.18.2 → 1.19.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 +9 -0
- package/dist/src/aberdeen.d.ts +27 -0
- package/{dist-docs/assets/aberdeen/aberdeen.js → dist/src/aberdeen.dev.js} +776 -15
- package/dist/src/aberdeen.dev.js.map +12 -0
- package/dist/src/aberdeen.js +59 -13
- package/dist/src/aberdeen.js.map +3 -3
- package/dist/src/devtools.d.ts +26 -0
- package/html-to-aberdeen +9 -5
- package/package.json +17 -10
- package/skill/A.md +127 -0
- package/skill/Dispatcher.md +51 -0
- package/skill/OPAQUE.md +15 -0
- package/skill/PromiseProxy.md +25 -0
- package/skill/Route.md +50 -0
- package/skill/SKILL.md +272 -156
- package/skill/applyCanon.md +20 -0
- package/skill/applyPrediction.md +15 -0
- package/skill/back.md +11 -0
- package/skill/clean.md +43 -0
- package/skill/clone.md +15 -0
- package/skill/copy.md +40 -0
- package/skill/count.md +32 -0
- package/skill/cssVars.md +15 -0
- package/skill/darkMode.md +26 -0
- package/skill/derive.md +56 -0
- package/skill/developer-tools.md +23 -0
- package/skill/disableCreateDestroy.md +11 -0
- package/skill/dump.md +37 -0
- package/skill/freeze.md +20 -0
- package/skill/full-example-multi-page-app.md +146 -0
- package/skill/go.md +25 -0
- package/skill/grow.md +13 -0
- package/skill/html-to-aberdeen.md +9 -0
- package/skill/insertCss.md +79 -0
- package/skill/insertGlobalCss.md +68 -0
- package/skill/interceptLinks.md +19 -0
- package/skill/invertString.md +32 -0
- package/skill/isEmpty.md +38 -0
- package/skill/map.md +16 -0
- package/skill/matchCurrent.md +27 -0
- package/skill/merge.md +27 -0
- package/skill/mount.md +48 -0
- package/skill/multiMap.md +15 -0
- package/skill/onEach.md +14 -0
- package/skill/partition.md +15 -0
- package/skill/peek.md +36 -0
- package/skill/persistScroll.md +13 -0
- package/skill/proxy.md +11 -0
- package/skill/push.md +13 -0
- package/skill/ref.md +39 -0
- package/skill/runQueue.md +34 -0
- package/skill/setErrorHandler.md +48 -0
- package/skill/setLog.md +9 -0
- package/skill/setSpacingCssVars.md +31 -0
- package/skill/shrink.md +13 -0
- package/skill/unmountAll.md +9 -0
- package/skill/unproxy.md +43 -0
- package/skill/up.md +13 -0
- package/src/aberdeen.ts +194 -73
- package/src/devtools.ts +685 -0
- package/dist-docs/.nojekyll +0 -1
- package/dist-docs/Tutorial/index.html +0 -305
- package/dist-docs/aberdeen/A/index.html +0 -116
- package/dist-docs/aberdeen/CUSTOM_DUMP/index.html +0 -7
- package/dist-docs/aberdeen/NO_COPY/index.html +0 -2
- package/dist-docs/aberdeen/OPAQUE/index.html +0 -12
- package/dist-docs/aberdeen/PromiseProxy/index.html +0 -8
- package/dist-docs/aberdeen/clean/index.html +0 -11
- package/dist-docs/aberdeen/clone/index.html +0 -5
- package/dist-docs/aberdeen/copy/index.html +0 -22
- package/dist-docs/aberdeen/count/index.html +0 -7
- package/dist-docs/aberdeen/cssVars/index.html +0 -11
- package/dist-docs/aberdeen/darkMode/index.html +0 -9
- package/dist-docs/aberdeen/default/index.html +0 -342
- package/dist-docs/aberdeen/derive/index.html +0 -18
- package/dist-docs/aberdeen/disableCreateDestroy/index.html +0 -6
- package/dist-docs/aberdeen/dump/index.html +0 -11
- package/dist-docs/aberdeen/index.html +0 -54
- package/dist-docs/aberdeen/insertCss/index.html +0 -30
- package/dist-docs/aberdeen/insertGlobalCss/index.html +0 -19
- package/dist-docs/aberdeen/invertString/index.html +0 -13
- package/dist-docs/aberdeen/isEmpty/index.html +0 -12
- package/dist-docs/aberdeen/map/index.html +0 -26
- package/dist-docs/aberdeen/merge/index.html +0 -11
- package/dist-docs/aberdeen/mount/index.html +0 -17
- package/dist-docs/aberdeen/multiMap/index.html +0 -28
- package/dist-docs/aberdeen/onEach/index.html +0 -19
- package/dist-docs/aberdeen/partition/index.html +0 -36
- package/dist-docs/aberdeen/peek/index.html +0 -40
- package/dist-docs/aberdeen/proxy/index.html +0 -35
- package/dist-docs/aberdeen/ref/index.html +0 -13
- package/dist-docs/aberdeen/runQueue/index.html +0 -13
- package/dist-docs/aberdeen/setErrorHandler/index.html +0 -16
- package/dist-docs/aberdeen/setSpacingCssVars/index.html +0 -8
- package/dist-docs/aberdeen/unmountAll/index.html +0 -5
- package/dist-docs/aberdeen/unproxy/index.html +0 -11
- package/dist-docs/assets/aberdeen/aberdeen.d.ts +0 -963
- package/dist-docs/assets/aberdeen/aberdeen.js.map +0 -11
- package/dist-docs/assets/aberdeen/dispatcher.d.ts +0 -57
- package/dist-docs/assets/aberdeen/dispatcher.js +0 -66
- package/dist-docs/assets/aberdeen/dispatcher.js.map +0 -10
- package/dist-docs/assets/aberdeen/helpers/reverseSortedSet.d.ts +0 -96
- package/dist-docs/assets/aberdeen/prediction.d.ts +0 -33
- package/dist-docs/assets/aberdeen/prediction.js +0 -112
- package/dist-docs/assets/aberdeen/prediction.js.map +0 -10
- package/dist-docs/assets/aberdeen/route.d.ts +0 -137
- package/dist-docs/assets/aberdeen/route.js +0 -287
- package/dist-docs/assets/aberdeen/route.js.map +0 -10
- package/dist-docs/assets/aberdeen/transitions.d.ts +0 -18
- package/dist-docs/assets/aberdeen/transitions.js +0 -47
- package/dist-docs/assets/aberdeen/transitions.js.map +0 -10
- package/dist-docs/assets/custom.js +0 -573
- package/dist-docs/assets/favicon.png +0 -0
- package/dist-docs/assets/hierarchy.js +0 -1
- package/dist-docs/assets/highlight.css +0 -134
- package/dist-docs/assets/icons.js +0 -18
- package/dist-docs/assets/icons.svg +0 -1
- package/dist-docs/assets/main.js +0 -60
- package/dist-docs/assets/navigation.js +0 -1
- package/dist-docs/assets/search.js +0 -1
- package/dist-docs/assets/style.css +0 -1640
- package/dist-docs/dispatcher/Dispatcher/index.html +0 -21
- package/dist-docs/dispatcher/MATCH_FAILED/index.html +0 -2
- package/dist-docs/dispatcher/MATCH_REST/index.html +0 -2
- package/dist-docs/dispatcher/index.html +0 -4
- package/dist-docs/hierarchy.html +0 -1
- package/dist-docs/index.html +0 -61
- package/dist-docs/media/CHANGELOG.md +0 -266
- package/dist-docs/modules.html +0 -1
- package/dist-docs/prediction/applyCanon/index.html +0 -13
- package/dist-docs/prediction/applyPrediction/index.html +0 -8
- package/dist-docs/prediction/index.html +0 -9
- package/dist-docs/route/Route/index.html +0 -23
- package/dist-docs/route/back/index.html +0 -4
- package/dist-docs/route/current/index.html +0 -2
- package/dist-docs/route/go/index.html +0 -14
- package/dist-docs/route/index.html +0 -15
- package/dist-docs/route/interceptLinks/index.html +0 -8
- package/dist-docs/route/matchCurrent/index.html +0 -10
- package/dist-docs/route/persistScroll/index.html +0 -6
- package/dist-docs/route/push/index.html +0 -6
- package/dist-docs/route/setLog/index.html +0 -3
- package/dist-docs/route/up/index.html +0 -5
- package/dist-docs/sitemap.xml +0 -239
- package/dist-docs/transitions/grow/index.html +0 -6
- package/dist-docs/transitions/index.html +0 -5
- package/dist-docs/transitions/shrink/index.html +0 -6
- package/skill/aberdeen.md +0 -4586
- package/skill/dispatcher.md +0 -129
- package/skill/prediction.md +0 -73
- package/skill/route.md +0 -322
- package/skill/transitions.md +0 -59
|
@@ -1,305 +0,0 @@
|
|
|
1
|
-
<!DOCTYPE html><html class="default" lang="en" data-base="../"><head><meta charset="utf-8"/><meta http-equiv="x-ua-compatible" content="IE=edge"/><title>Tutorial | Aberdeen - v1.18.2</title><link rel="icon" href="../assets/favicon.png" type="image/png"/><meta name="description" content="Documentation for Aberdeen"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="stylesheet" href="../assets/style.css"/><link rel="stylesheet" href="../assets/highlight.css"/><script defer src="../assets/main.js"></script><script defer src="../assets/custom.js"></script><script async src="../assets/icons.js" id="tsd-icons-script"></script><script async src="../assets/search.js" id="tsd-search-script"></script><script async src="../assets/navigation.js" id="tsd-nav-script"></script></head><body><script>document.documentElement.dataset.theme = localStorage.getItem("tsd-theme") || "os";document.body.style.display="none";setTimeout(() => window.app?app.showPage():document.body.style.removeProperty("display"),500)</script><header class="tsd-page-toolbar"><div class="tsd-toolbar-contents container"><a href="../index.html" class="title">Aberdeen - v1.18.2</a><div id="tsd-toolbar-links"><a href="https://aberdeenjs.org/">What's this?</a><a href="https://aberdeenjs.org/Tutorial/">Tutorial</a><a href="https://github.com/vanviegen/aberdeen">GitHub</a></div><button id="tsd-search-trigger" class="tsd-widget" aria-label="Search"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-search"></use></svg></button><dialog id="tsd-search" aria-label="Search"><input role="combobox" id="tsd-search-input" aria-controls="tsd-search-results" aria-autocomplete="list" aria-expanded="true" autocapitalize="off" autocomplete="off" placeholder="Search the docs" maxLength="100"/><ul role="listbox" id="tsd-search-results"></ul><div id="tsd-search-status" aria-live="polite" aria-atomic="true"><div>Preparing search index...</div></div></dialog><a href="#" class="tsd-widget menu" id="tsd-toolbar-menu-trigger" data-toggle="menu" aria-label="Menu"><svg width="16" height="16" viewBox="0 0 16 16" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-menu"></use></svg></a></div></header><div class="container container-main"><div class="col-content"><div class="tsd-page-title"><ul class="tsd-breadcrumb" aria-label="Breadcrumb"><li><a href="" aria-current="page">Tutorial</a></li></ul></div><div class="tsd-panel tsd-typography"><h1 id="tutorial" class="tsd-anchor-link">Tutorial<a href="#tutorial" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h1><h2 id="creating-elements" class="tsd-anchor-link">Creating elements<a href="#creating-elements" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>This is a complete Aberdeen application:</p>
|
|
2
|
-
<pre><code class="javascript"><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">A</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen'</span><span class="hl-1">;</span><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'h3#Hello world'</span><span class="hl-1">);</span>
|
|
3
|
-
</code><button type="button">Copy</button></pre>
|
|
4
|
-
|
|
5
|
-
<p>It adds a <code><h3>Hello world</h3></code> element to the <code><body></code> (which is the default mount point).</p>
|
|
6
|
-
<p>The <a href="../aberdeen/A/" class="tsd-kind-function"> aberdeen.A</a> function accepts various forms of arguments, which can be combined.</p>
|
|
7
|
-
<p>When a string is passed:</p>
|
|
8
|
-
<ul>
|
|
9
|
-
<li>The inital part (if any) is the name of the element to be created.</li>
|
|
10
|
-
<li>One or multiple CSS classes can be added to the 'current' element, by prefixing them with a <code>.</code>.</li>
|
|
11
|
-
<li>Content text can be added by prefixing it with a <code>#</code>.</li>
|
|
12
|
-
</ul>
|
|
13
|
-
<p>Instead of the <code>#</code> prefix for text content, you can also use the <code>text=</code> property, like this: <code>A('h3 text="Hello world"')</code>. The double quotes are needed here only because our text contains a space.</p>
|
|
14
|
-
<p>For simple formatting, use <code>rich=</code> which supports <code>*italic*</code>, <code>**bold**</code>, <code>`code`</code>, and <code>[links](url)</code>:</p>
|
|
15
|
-
<pre><code class="javascript"><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'p rich="This is *italic*, **bold**, and `code` with a [link](/path)."'</span><span class="hl-1">);</span>
|
|
16
|
-
</code><button type="button">Copy</button></pre>
|
|
17
|
-
|
|
18
|
-
<p><code>A()</code> can accept multiple strings, so the following lines are equivalent:</p>
|
|
19
|
-
<pre><code class="javascript"><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button.outline.secondary#Pressing me does nothing!'</span><span class="hl-1">);</span><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button'</span><span class="hl-1">, </span><span class="hl-3">'.outline'</span><span class="hl-1">, </span><span class="hl-3">'.secondary'</span><span class="hl-1">, </span><span class="hl-3">'#Pressing me does nothing!'</span><span class="hl-1">);</span>
|
|
20
|
-
</code><button type="button">Copy</button></pre>
|
|
21
|
-
|
|
22
|
-
<p>Also, we can create multiple nested DOM elements in a single <a href="../aberdeen/A/" class="tsd-kind-function"> aberdeen.A</a> invocation, <em>if</em> the parents need to have only a single child. For instance:</p>
|
|
23
|
-
<pre><code class="javascript"><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.box'</span><span class="hl-1">, </span><span class="hl-3">'#Text within the div element...'</span><span class="hl-1">, </span><span class="hl-3">'input'</span><span class="hl-1">);</span>
|
|
24
|
-
</code><button type="button">Copy</button></pre>
|
|
25
|
-
|
|
26
|
-
<p>Note that you can play around, modifying any example while seeing its live result by pressing the <em>Edit</em> button that appears when hovering over an example!</p>
|
|
27
|
-
<p>In order to pass in additional properties and attributes to the 'current' DOM element, we can use the <code>key=value</code> or <code>key=</code>, value syntax. So to extend the above example:</p>
|
|
28
|
-
<pre><code class="javascript"><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.box id=cityContainer input value=London placeholder=City'</span><span class="hl-1">);</span>
|
|
29
|
-
</code><button type="button">Copy</button></pre>
|
|
30
|
-
|
|
31
|
-
<p>Note that <code>value</code> doesn't become an HTML attribute. This (together with <code>selectedIndex</code>) is one of two special cases, where Aberdeen applies it as a DOM property instead, in order to preserve the variable type (as attributes can only be strings).</p>
|
|
32
|
-
<p>When a value ends with <code>=</code>, the next argument is used as its value. This is used for dynamic values and event listeners. So to always log the current input value to the console you can do:</p>
|
|
33
|
-
<pre><code class="javascript"><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.box input value=Marshmallow input='</span><span class="hl-1">, </span><span class="hl-2">el</span><span class="hl-1"> </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">console</span><span class="hl-1">.</span><span class="hl-7">log</span><span class="hl-1">(</span><span class="hl-2">el</span><span class="hl-1">.</span><span class="hl-2">target</span><span class="hl-1">.</span><span class="hl-2">value</span><span class="hl-1">));</span>
|
|
34
|
-
</code><button type="button">Copy</button></pre>
|
|
35
|
-
|
|
36
|
-
<p>Note that the example is interactive - try typing something!</p>
|
|
37
|
-
<blockquote>
|
|
38
|
-
<p><strong>Note:</strong> <a href="../aberdeen/A/" class="tsd-kind-function"> aberdeen.A</a> also accepts object syntax as an alternative to strings (see the API reference), but the string syntax shown here is more concise and is recommended for most use cases.</p>
|
|
39
|
-
</blockquote>
|
|
40
|
-
<h2 id="inline-styles" class="tsd-anchor-link">Inline styles<a href="#inline-styles" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>To set inline CSS styles on elements, use the <code>property:value</code> (short form) or <code>property: value containing spaces;</code> (long form) syntax:</p>
|
|
41
|
-
<pre><code class="javascript"><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'p color:red padding:8px background-color:#a882 border: 2px solid #a884; #Styled text'</span><span class="hl-1">);</span>
|
|
42
|
-
</code><button type="button">Copy</button></pre>
|
|
43
|
-
|
|
44
|
-
<h3 id="property-shortcuts" class="tsd-anchor-link">Property shortcuts<a href="#property-shortcuts" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Aberdeen provides shortcuts for commonly used CSS properties, making your code more concise.</p>
|
|
45
|
-
<table>
|
|
46
|
-
<thead>
|
|
47
|
-
<tr>
|
|
48
|
-
<th>Shortcut</th>
|
|
49
|
-
<th>Expands to</th>
|
|
50
|
-
</tr>
|
|
51
|
-
</thead>
|
|
52
|
-
<tbody>
|
|
53
|
-
<tr>
|
|
54
|
-
<td><code>m</code>, <code>mt</code>, <code>mb</code>, <code>ml</code>, <code>mr</code></td>
|
|
55
|
-
<td><code>margin</code>, <code>margin-top</code>, <code>margin-bottom</code>, <code>margin-left</code>, <code>margin-right</code></td>
|
|
56
|
-
</tr>
|
|
57
|
-
<tr>
|
|
58
|
-
<td><code>mv</code>, <code>mh</code></td>
|
|
59
|
-
<td>Vertical (top+bottom) or horizontal (left+right) margins</td>
|
|
60
|
-
</tr>
|
|
61
|
-
<tr>
|
|
62
|
-
<td><code>p</code>, <code>pt</code>, <code>pb</code>, <code>pl</code>, <code>pr</code></td>
|
|
63
|
-
<td><code>padding</code>, <code>padding-top</code>, <code>padding-bottom</code>, <code>padding-left</code>, <code>padding-right</code></td>
|
|
64
|
-
</tr>
|
|
65
|
-
<tr>
|
|
66
|
-
<td><code>pv</code>, <code>ph</code></td>
|
|
67
|
-
<td>Vertical or horizontal padding</td>
|
|
68
|
-
</tr>
|
|
69
|
-
<tr>
|
|
70
|
-
<td><code>w</code>, <code>h</code></td>
|
|
71
|
-
<td><code>width</code>, <code>height</code></td>
|
|
72
|
-
</tr>
|
|
73
|
-
<tr>
|
|
74
|
-
<td><code>bg</code></td>
|
|
75
|
-
<td><code>background</code></td>
|
|
76
|
-
</tr>
|
|
77
|
-
<tr>
|
|
78
|
-
<td><code>fg</code></td>
|
|
79
|
-
<td><code>color</code></td>
|
|
80
|
-
</tr>
|
|
81
|
-
<tr>
|
|
82
|
-
<td><code>r</code></td>
|
|
83
|
-
<td><code>border-radius</code></td>
|
|
84
|
-
</tr>
|
|
85
|
-
</tbody>
|
|
86
|
-
</table>
|
|
87
|
-
<pre><code class="javascript"><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div mv:10px ph:20px bg:lightblue r:10% #Styled box'</span><span class="hl-1">);</span>
|
|
88
|
-
</code><button type="button">Copy</button></pre>
|
|
89
|
-
|
|
90
|
-
<h3 id="css-variables" class="tsd-anchor-link">CSS variables<a href="#css-variables" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>Values starting with <code>$</code> expand to native CSS custom properties via <code>var(--name)</code>. The <a href="../aberdeen/cssVars/" class="tsd-kind-variable">A.cssVars</a> object offers a convenient way of setting and updating CSS custom properties at the <code>:root</code> level.</p>
|
|
91
|
-
<p>When you add the first property to <code>A.cssVars</code>, Aberdeen automatically creates a reactive <code><style></code> tag in <code><head></code> containing the CSS custom property declarations.</p>
|
|
92
|
-
<pre><code class="javascript"><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">A</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen'</span><span class="hl-1">;</span><br/><br/><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-2">cssVars</span><span class="hl-1">.</span><span class="hl-2">primary</span><span class="hl-1"> = </span><span class="hl-3">'#3b82f6'</span><span class="hl-1">;</span><br/><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-2">cssVars</span><span class="hl-1">.</span><span class="hl-2">danger</span><span class="hl-1"> = </span><span class="hl-3">'#ef4444'</span><span class="hl-1">;</span><br/><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-2">cssVars</span><span class="hl-1">.</span><span class="hl-2">textLight</span><span class="hl-1"> = </span><span class="hl-3">'#f8fafc'</span><span class="hl-1">;</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button bg:$primary fg:$textLight #Primary'</span><span class="hl-1">);</span><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button bg:$danger fg:$textLight #Danger'</span><span class="hl-1">);</span>
|
|
93
|
-
</code><button type="button">Copy</button></pre>
|
|
94
|
-
|
|
95
|
-
<p>The above generates CSS like <code>background: var(--primary)</code> and automatically injects a <code>:root</code> style defining the actual values. Since this uses native CSS custom properties, changes to <code>A.cssVars</code> automatically propagate to all elements using those values.</p>
|
|
96
|
-
<h3 id="spacing-variables" class="tsd-anchor-link">Spacing variables<a href="#spacing-variables" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h3><p>You can optionally initialize <code>A.cssVars</code> with keys <code>1</code> through <code>12</code> mapping to an exponential <code>rem</code> scale using <a href="../aberdeen/setSpacingCssVars/" class="tsd-kind-function">A.setSpacingCssVars</a>. Since CSS custom property names can't start with a digit, numeric keys are prefixed with <code>m</code> (e.g., <code>$3</code> becomes <code>var(--m3)</code>):</p>
|
|
97
|
-
<pre><code class="javascript"><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">A</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen'</span><span class="hl-1">;</span><br/><br/><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">setSpacingCssVars</span><span class="hl-1">(); </span><span class="hl-4">// Default: base=1, unit='rem'</span><br/><span class="hl-4">// Or customize: A.setSpacingCssVars(16, 'px') or A.setSpacingCssVars(1, 'em')</span>
|
|
98
|
-
</code><button type="button">Copy</button></pre>
|
|
99
|
-
|
|
100
|
-
<table>
|
|
101
|
-
<thead>
|
|
102
|
-
<tr>
|
|
103
|
-
<th>Value</th>
|
|
104
|
-
<th>CSS Output</th>
|
|
105
|
-
<th>Result (default)</th>
|
|
106
|
-
</tr>
|
|
107
|
-
</thead>
|
|
108
|
-
<tbody>
|
|
109
|
-
<tr>
|
|
110
|
-
<td><code>$1</code></td>
|
|
111
|
-
<td><code>var(--m1)</code></td>
|
|
112
|
-
<td>0.25rem</td>
|
|
113
|
-
</tr>
|
|
114
|
-
<tr>
|
|
115
|
-
<td><code>$2</code></td>
|
|
116
|
-
<td><code>var(--m2)</code></td>
|
|
117
|
-
<td>0.5rem</td>
|
|
118
|
-
</tr>
|
|
119
|
-
<tr>
|
|
120
|
-
<td><code>$3</code></td>
|
|
121
|
-
<td><code>var(--m3)</code></td>
|
|
122
|
-
<td>1rem</td>
|
|
123
|
-
</tr>
|
|
124
|
-
<tr>
|
|
125
|
-
<td><code>$4</code></td>
|
|
126
|
-
<td><code>var(--m4)</code></td>
|
|
127
|
-
<td>2rem</td>
|
|
128
|
-
</tr>
|
|
129
|
-
<tr>
|
|
130
|
-
<td><code>$5</code></td>
|
|
131
|
-
<td><code>var(--m5)</code></td>
|
|
132
|
-
<td>4rem</td>
|
|
133
|
-
</tr>
|
|
134
|
-
<tr>
|
|
135
|
-
<td>...</td>
|
|
136
|
-
<td>...</td>
|
|
137
|
-
<td>2^(n-3) rem</td>
|
|
138
|
-
</tr>
|
|
139
|
-
</tbody>
|
|
140
|
-
</table>
|
|
141
|
-
<pre><code class="javascript"><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div mt:$3 ph:$4 #This text has 1rem top margin, 2rem left+right padding'</span><span class="hl-1">);</span>
|
|
142
|
-
</code><button type="button">Copy</button></pre>
|
|
143
|
-
|
|
144
|
-
<p>If you want different spacing, you can customize the base and unit when calling <code>A.setSpacingCssVars()</code>, or dynamically modify the values.</p>
|
|
145
|
-
<p>These shortcuts and variables are also available when using <a href="../aberdeen/insertCss/" class="tsd-kind-function">A.insertCss</a>.</p>
|
|
146
|
-
<h2 id="nesting-content" class="tsd-anchor-link">Nesting content<a href="#nesting-content" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Of course, putting everything in a single <a href="../aberdeen/A/" class="tsd-kind-function"> aberdeen.A</a> call will get messy soon, and you'll often want to nest more than one child within a parent. To do that, you can pass in a <em>content</em> function to <a href="../aberdeen/A/" class="tsd-kind-function"> aberdeen.A</a>, like this:</p>
|
|
147
|
-
<pre><code class="javascript"><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.box.row id=cityContainer'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'input value=London placeholder=City'</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button text=Confirm click='</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-7">alert</span><span class="hl-1">(</span><span class="hl-3">"You got it!"</span><span class="hl-1">));</span><br/><span class="hl-1">});</span>
|
|
148
|
-
</code><button type="button">Copy</button></pre>
|
|
149
|
-
|
|
150
|
-
<p>Why are we passing in a function instead of just, say, an array of children? I'm glad you asked! :-) For each such function Aberdeen will create an <em>observer</em>, which will play a major part in what comes next...</p>
|
|
151
|
-
<h2 id="observable-objects" class="tsd-anchor-link">Observable objects<a href="#observable-objects" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Aberdeen's reactivity system is built around observable objects. These are created using the <a href="../aberdeen/proxy/" class="tsd-kind-function">A.proxy</a> function:</p>
|
|
152
|
-
<p>By convention variables that hold proxied values are prefixed with <code>$</code> so reactive reads stand out.</p>
|
|
153
|
-
<p>When you access properties of a proxied object within an observer function (the function passed to <a href="../aberdeen/A/" class="tsd-kind-function"> aberdeen.A</a>), Aberdeen automatically tracks these dependencies. If the values change later, the observer function will re-run, updating only the affected parts of the DOM.</p>
|
|
154
|
-
<pre><code class="javascript"><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">A</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen'</span><span class="hl-1">;</span><br/><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$user</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">name:</span><span class="hl-1"> </span><span class="hl-3">'Alice'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">age:</span><span class="hl-1"> </span><span class="hl-8">28</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">city:</span><span class="hl-1"> </span><span class="hl-3">'Aberdeen'</span><span class="hl-1">,</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`h3#Hello, </span><span class="hl-5">${</span><span class="hl-2">$user</span><span class="hl-9">.</span><span class="hl-2">name</span><span class="hl-5">}</span><span class="hl-3">!`</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`p#You are </span><span class="hl-5">${</span><span class="hl-2">$user</span><span class="hl-9">.</span><span class="hl-2">age</span><span class="hl-5">}</span><span class="hl-3"> years old.`</span><span class="hl-1">);</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-7">setInterval</span><span class="hl-1">(() </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">$user</span><span class="hl-1">.</span><span class="hl-2">name</span><span class="hl-1"> = </span><span class="hl-3">'Bob'</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-2">$user</span><span class="hl-1">.</span><span class="hl-2">age</span><span class="hl-1">++;</span><br/><span class="hl-1">}, </span><span class="hl-8">2000</span><span class="hl-1">);</span>
|
|
155
|
-
</code><button type="button">Copy</button></pre>
|
|
156
|
-
|
|
157
|
-
<p>As the content function of our <code>div</code> is subscribed to both <code>$user.name</code> and <code>$user.age</code>, modifying either of these would trigger a re-run of that function, first undoing any side-effects (most notably: inserting DOM elements) of the earlier run. If, however <code>$user.city</code> is changed, no re-run would be triggered as the function is not subscribed to that property.</p>
|
|
158
|
-
<p>So if either property changes, both the <code><h3></code> and <code><p></code> are recreated as the inner most observer function tracking the changes is re-run. If you want to redraw on an even granular level, you can of course:</p>
|
|
159
|
-
<pre><code class="javascript"><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$user</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">name:</span><span class="hl-1"> </span><span class="hl-3">'Alice'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">age:</span><span class="hl-1"> </span><span class="hl-8">28</span><span class="hl-1">,</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`h3`</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">console</span><span class="hl-1">.</span><span class="hl-7">log</span><span class="hl-1">(</span><span class="hl-3">'Name draws:'</span><span class="hl-1">, </span><span class="hl-2">$user</span><span class="hl-1">.</span><span class="hl-2">name</span><span class="hl-1">)</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`#Hello, </span><span class="hl-5">${</span><span class="hl-2">$user</span><span class="hl-9">.</span><span class="hl-2">name</span><span class="hl-5">}</span><span class="hl-3">!`</span><span class="hl-1">);</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`p`</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">console</span><span class="hl-1">.</span><span class="hl-7">log</span><span class="hl-1">(</span><span class="hl-3">'Age draws:'</span><span class="hl-1">, </span><span class="hl-2">$user</span><span class="hl-1">.</span><span class="hl-2">age</span><span class="hl-1">)</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`#You are </span><span class="hl-5">${</span><span class="hl-2">$user</span><span class="hl-9">.</span><span class="hl-2">age</span><span class="hl-5">}</span><span class="hl-3"> years old.`</span><span class="hl-1">);</span><br/><span class="hl-1"> });</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-7">setInterval</span><span class="hl-1">(() </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">$user</span><span class="hl-1">.</span><span class="hl-2">age</span><span class="hl-1">++;</span><br/><span class="hl-1">}, </span><span class="hl-8">2000</span><span class="hl-1">);</span>
|
|
160
|
-
</code><button type="button">Copy</button></pre>
|
|
161
|
-
|
|
162
|
-
<p>Now, updating <code>$user.name</code> would only cause the <em>Hello</em> text node to be replaced, leaving the <code><div></code>, <code><h3></code> and <code><p></code> elements as they were.</p>
|
|
163
|
-
<h2 id="conditional-rendering" class="tsd-anchor-link">Conditional rendering<a href="#conditional-rendering" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Within an observer function (such as created by passing a function to <a href="../aberdeen/A/" class="tsd-kind-function"> aberdeen.A</a>), you can use regular JavaScript logic. Like <code>if</code> and <code>else</code>, for instance:</p>
|
|
164
|
-
<pre><code class="javascript"><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$user</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">loggedIn:</span><span class="hl-1"> </span><span class="hl-5">false</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-0">if</span><span class="hl-1"> (</span><span class="hl-2">$user</span><span class="hl-1">.</span><span class="hl-2">loggedIn</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button.outline text=Logout click='</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$user</span><span class="hl-1">.</span><span class="hl-2">loggedIn</span><span class="hl-1"> = </span><span class="hl-5">false</span><span class="hl-1">);</span><br/><span class="hl-1"> } </span><span class="hl-0">else</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button text=Login click='</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$user</span><span class="hl-1">.</span><span class="hl-2">loggedIn</span><span class="hl-1"> = </span><span class="hl-5">true</span><span class="hl-1">);</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">});</span>
|
|
165
|
-
</code><button type="button">Copy</button></pre>
|
|
166
|
-
|
|
167
|
-
<h2 id="observable-primitive-values" class="tsd-anchor-link">Observable primitive values<a href="#observable-primitive-values" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>The <a href="../aberdeen/proxy/" class="tsd-kind-function">A.proxy</a> method wraps an object in a JavaScript <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy" target="_blank" class="external">Proxy</a>. As this doesn't work for primitive values (like numbers, strings and booleans), the method will <em>create</em> an object in order to make it observable. The observable value is made available as its <code>.value</code> property.</p>
|
|
168
|
-
<pre><code class="javascript"><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$count</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">(</span><span class="hl-8">42</span><span class="hl-1">);</span><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.row'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-4">// This scope will not have to redraw</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button text=- click='</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$count</span><span class="hl-1">.</span><span class="hl-2">value</span><span class="hl-1">--);</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div text='</span><span class="hl-1">, </span><span class="hl-2">$count</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button text=+ click='</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$count</span><span class="hl-1">.</span><span class="hl-2">value</span><span class="hl-1">++);</span><br/><span class="hl-1">});</span>
|
|
169
|
-
</code><button type="button">Copy</button></pre>
|
|
170
|
-
|
|
171
|
-
<p>The reason the <code>div.row</code> scope doesn't redraw when <code>$count.value</code> changes is that we're passing the entire <code>$count</code> observable object to the <code>text:</code> property. Aberdeen then internally subscribes to <code>$count.value</code> for just that text node, ensuring minimal updates.</p>
|
|
172
|
-
<p>If we would have done <code>A('div', {text: $count.value});</code> instead, we <em>would</em> have subscribed to <code>$count.value</code> within the <code>div.row</code> scope, meaning we'd be redrawing the two buttons and the div every time the count changes.</p>
|
|
173
|
-
<p>This also works for other properties, such as inline styles:</p>
|
|
174
|
-
<pre><code class="javascript"><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">A</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen'</span><span class="hl-1">;</span><br/><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$textColor</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">(</span><span class="hl-3">'blue'</span><span class="hl-1">);</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.box color:'</span><span class="hl-1">, </span><span class="hl-2">$textColor</span><span class="hl-1">, </span><span class="hl-3">'#Click me to change color'</span><span class="hl-1">, </span><span class="hl-3">'click='</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">$textColor</span><span class="hl-1">.</span><span class="hl-2">value</span><span class="hl-1"> = </span><span class="hl-2">$textColor</span><span class="hl-1">.</span><span class="hl-2">value</span><span class="hl-1"> === </span><span class="hl-3">'blue'</span><span class="hl-1"> ? </span><span class="hl-3">'red'</span><span class="hl-1"> : </span><span class="hl-3">'blue'</span><span class="hl-1">;</span><br/><span class="hl-1">});</span>
|
|
175
|
-
</code><button type="button">Copy</button></pre>
|
|
176
|
-
|
|
177
|
-
<p>This way, when <code>$textColor.value</code> changes, only the style is updated without recreating the element.</p>
|
|
178
|
-
<h2 id="observable-arrays-and-sets" class="tsd-anchor-link">Observable arrays and sets<a href="#observable-arrays-and-sets" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>You can create observable arrays too. They work just like regular arrays, apart from being observable.</p>
|
|
179
|
-
<pre><code class="javascript"><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$items</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">([</span><span class="hl-8">1</span><span class="hl-1">, </span><span class="hl-8">2</span><span class="hl-1">, </span><span class="hl-8">3</span><span class="hl-1">]);</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'h3'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-4">// This subscribes to the length of the array and to the value at `$items.length-1` in the array.</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'#Last item: '</span><span class="hl-1">+</span><span class="hl-2">$items</span><span class="hl-1">[</span><span class="hl-2">$items</span><span class="hl-1">.</span><span class="hl-2">length</span><span class="hl-1">-</span><span class="hl-8">1</span><span class="hl-1">]);</span><br/><span class="hl-1">})</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'ul'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-4">// This subscribes to the entire array, and thus redraws all <li>s when any item changes.</span><br/><span class="hl-1"> </span><span class="hl-4">// In the next section, we'll learn about a better way.</span><br/><span class="hl-1"> </span><span class="hl-0">for</span><span class="hl-1"> (</span><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">item</span><span class="hl-1"> </span><span class="hl-5">of</span><span class="hl-1"> </span><span class="hl-2">$items</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`li#Item </span><span class="hl-5">${</span><span class="hl-2">item</span><span class="hl-5">}</span><span class="hl-3">`</span><span class="hl-1">);</span><br/><span class="hl-1"> }</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button text=Add click='</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$items</span><span class="hl-1">.</span><span class="hl-7">push</span><span class="hl-1">(</span><span class="hl-2">$items</span><span class="hl-1">.</span><span class="hl-2">length</span><span class="hl-1">+</span><span class="hl-8">1</span><span class="hl-1">));</span>
|
|
180
|
-
</code><button type="button">Copy</button></pre>
|
|
181
|
-
|
|
182
|
-
<p>Observable <code>Set</code>s work too. They preserve normal Set semantics, including <code>.size</code>. When you iterate them with <code>A.onEach()</code>, by default they are sorted by value (or an error is thrown if the value is not a number, string or an array of those).</p>
|
|
183
|
-
<pre><code class="javascript"><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$tags</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">(</span><span class="hl-5">new</span><span class="hl-1"> </span><span class="hl-7">Set</span><span class="hl-1">([</span><span class="hl-3">'ui'</span><span class="hl-1">, </span><span class="hl-3">'tiny'</span><span class="hl-1">]));</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`#Tag count: </span><span class="hl-5">${</span><span class="hl-2">$tags</span><span class="hl-9">.</span><span class="hl-2">size</span><span class="hl-5">}</span><span class="hl-3">`</span><span class="hl-1">);</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'ul'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">onEach</span><span class="hl-1">(</span><span class="hl-2">$tags</span><span class="hl-1">, </span><span class="hl-2">tag</span><span class="hl-1"> </span><span class="hl-5">=></span><span class="hl-1"> { </span><span class="hl-4">// Ordered by tag</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`li#</span><span class="hl-5">${</span><span class="hl-2">tag</span><span class="hl-5">}</span><span class="hl-3">`</span><span class="hl-1">);</span><br/><span class="hl-1"> });</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button text=Add fast click='</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$tags</span><span class="hl-1">.</span><span class="hl-7">add</span><span class="hl-1">(</span><span class="hl-3">'fast'</span><span class="hl-1">));</span>
|
|
184
|
-
</code><button type="button">Copy</button></pre>
|
|
185
|
-
|
|
186
|
-
<h2 id="typescript-and-classes" class="tsd-anchor-link">TypeScript and classes<a href="#typescript-and-classes" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Though this tutorial mostly uses plain JavaScript to explain the concepts, Aberdeen is written in and aimed towards TypeScript.</p>
|
|
187
|
-
<p>Class instances, like any other object, can be proxied to make them reactive.</p>
|
|
188
|
-
<pre><code class="typescript"><span class="hl-5">class</span><span class="hl-1"> </span><span class="hl-10">Widget</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-5">constructor</span><span class="hl-1">(</span><span class="hl-5">public</span><span class="hl-1"> </span><span class="hl-2">name</span><span class="hl-1">: </span><span class="hl-10">string</span><span class="hl-1">, </span><span class="hl-5">public</span><span class="hl-1"> </span><span class="hl-2">width</span><span class="hl-1">: </span><span class="hl-10">number</span><span class="hl-1">, </span><span class="hl-5">public</span><span class="hl-1"> </span><span class="hl-2">height</span><span class="hl-1">: </span><span class="hl-10">number</span><span class="hl-1">) {}</span><br/><span class="hl-1"> </span><span class="hl-7">grow</span><span class="hl-1">() { </span><span class="hl-5">this</span><span class="hl-1">.</span><span class="hl-2">width</span><span class="hl-1"> *= </span><span class="hl-8">2</span><span class="hl-1">; }</span><br/><span class="hl-1"> </span><span class="hl-7">toString</span><span class="hl-1">() { </span><span class="hl-0">return</span><span class="hl-1"> </span><span class="hl-3">`</span><span class="hl-5">${</span><span class="hl-5">this</span><span class="hl-9">.</span><span class="hl-2">name</span><span class="hl-5">}</span><span class="hl-3">Widget (</span><span class="hl-5">${</span><span class="hl-5">this</span><span class="hl-9">.</span><span class="hl-2">width</span><span class="hl-5">}</span><span class="hl-3">x</span><span class="hl-5">${</span><span class="hl-5">this</span><span class="hl-9">.</span><span class="hl-2">height</span><span class="hl-5">}</span><span class="hl-3">)`</span><span class="hl-1">; }</span><br/><span class="hl-1">}</span><br/><br/><span class="hl-5">let</span><span class="hl-1"> </span><span class="hl-2">$graph</span><span class="hl-1">: </span><span class="hl-10">Widget</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">(</span><span class="hl-5">new</span><span class="hl-1"> </span><span class="hl-7">Widget</span><span class="hl-1">(</span><span class="hl-3">'Graph'</span><span class="hl-1">, </span><span class="hl-8">200</span><span class="hl-1">, </span><span class="hl-8">100</span><span class="hl-1">));</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'h3'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'#'</span><span class="hl-1">+</span><span class="hl-2">$graph</span><span class="hl-1">));</span><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button text=Grow click='</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$graph</span><span class="hl-1">.</span><span class="hl-7">grow</span><span class="hl-1">());</span>
|
|
189
|
-
</code><button type="button">Copy</button></pre>
|
|
190
|
-
|
|
191
|
-
<p>The type returned by <a href="../aberdeen/proxy/" class="tsd-kind-function">A.proxy</a> matches the input type, meaning the type system does not distinguish proxied and unproxied objects. That makes sense, as they have the exact same methods and properties (though proxied objects may have additional side effects).</p>
|
|
192
|
-
<h2 id="efficient-list-rendering-with-aoneach" class="tsd-anchor-link">Efficient list rendering with A.onEach<a href="#efficient-list-rendering-with-aoneach" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>For rendering lists efficiently, Aberdeen provides the <a href="../aberdeen/onEach/" class="tsd-kind-function">A.onEach</a> function. It takes three arguments:</p>
|
|
193
|
-
<ol>
|
|
194
|
-
<li>The array to iterate over.</li>
|
|
195
|
-
<li>A render function that receives the item and its index.</li>
|
|
196
|
-
<li>An optional order function, that returns the value by which the item is to be sorted. By default, the output is sorted by array index.</li>
|
|
197
|
-
</ol>
|
|
198
|
-
<pre><code class="javascript"><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">A</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen'</span><span class="hl-1">;</span><br/><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$items</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">([]);</span><br/><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-7">randomInt</span><span class="hl-1"> = (</span><span class="hl-2">max</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-7">parseInt</span><span class="hl-1">(</span><span class="hl-2">Math</span><span class="hl-1">.</span><span class="hl-7">random</span><span class="hl-1">() * </span><span class="hl-2">max</span><span class="hl-1">);</span><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-7">randomWord</span><span class="hl-1"> = () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">Math</span><span class="hl-1">.</span><span class="hl-7">random</span><span class="hl-1">().</span><span class="hl-7">toString</span><span class="hl-1">(</span><span class="hl-8">36</span><span class="hl-1">).</span><span class="hl-7">substring</span><span class="hl-1">(</span><span class="hl-8">2</span><span class="hl-1">, </span><span class="hl-8">12</span><span class="hl-1">).</span><span class="hl-7">replace</span><span class="hl-1">(</span><span class="hl-11">/</span><span class="hl-12">[</span><span class="hl-11">0-9</span><span class="hl-12">]</span><span class="hl-13">+</span><span class="hl-11">/</span><span class="hl-5">g</span><span class="hl-1">, </span><span class="hl-3">''</span><span class="hl-1">).</span><span class="hl-7">replace</span><span class="hl-1">(</span><span class="hl-11">/</span><span class="hl-14">^</span><span class="hl-11">\w/</span><span class="hl-1">, </span><span class="hl-2">c</span><span class="hl-1"> </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">c</span><span class="hl-1">.</span><span class="hl-7">toUpperCase</span><span class="hl-1">());</span><br/><br/><span class="hl-4">// Make random mutations</span><br/><span class="hl-7">setInterval</span><span class="hl-1">(() </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-0">if</span><span class="hl-1"> (</span><span class="hl-7">randomInt</span><span class="hl-1">(</span><span class="hl-8">3</span><span class="hl-1">)) </span><span class="hl-2">$items</span><span class="hl-1">[</span><span class="hl-7">randomInt</span><span class="hl-1">(</span><span class="hl-8">7</span><span class="hl-1">)] = {</span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-7">randomWord</span><span class="hl-1">(), </span><span class="hl-2">prio:</span><span class="hl-1"> </span><span class="hl-7">randomInt</span><span class="hl-1">(</span><span class="hl-8">4</span><span class="hl-1">)};</span><br/><span class="hl-1"> </span><span class="hl-0">else</span><span class="hl-1"> </span><span class="hl-5">delete</span><span class="hl-1"> </span><span class="hl-2">$items</span><span class="hl-1">[</span><span class="hl-7">randomInt</span><span class="hl-1">(</span><span class="hl-8">7</span><span class="hl-1">)];</span><br/><span class="hl-1">}, </span><span class="hl-8">500</span><span class="hl-1">);</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.row.wide height:250px'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.box#By index'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">onEach</span><span class="hl-1">(</span><span class="hl-2">$items</span><span class="hl-1">, (</span><span class="hl-2">$item</span><span class="hl-1">, </span><span class="hl-2">index</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-4">// Called only for items that are created/updated</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`li#</span><span class="hl-5">${</span><span class="hl-2">$item</span><span class="hl-9">.</span><span class="hl-2">label</span><span class="hl-5">}</span><span class="hl-3"> (prio </span><span class="hl-5">${</span><span class="hl-2">$item</span><span class="hl-9">.</span><span class="hl-2">prio</span><span class="hl-5">}</span><span class="hl-3">)`</span><span class="hl-1">)</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> })</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.box#By label'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">onEach</span><span class="hl-1">(</span><span class="hl-2">$items</span><span class="hl-1">, (</span><span class="hl-2">$item</span><span class="hl-1">, </span><span class="hl-2">index</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`li#</span><span class="hl-5">${</span><span class="hl-2">$item</span><span class="hl-9">.</span><span class="hl-2">label</span><span class="hl-5">}</span><span class="hl-3"> (prio </span><span class="hl-5">${</span><span class="hl-2">$item</span><span class="hl-9">.</span><span class="hl-2">prio</span><span class="hl-5">}</span><span class="hl-3">)`</span><span class="hl-1">)</span><br/><span class="hl-1"> }, </span><span class="hl-2">$item</span><span class="hl-1"> </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$item</span><span class="hl-1">.</span><span class="hl-2">label</span><span class="hl-1">);</span><br/><span class="hl-1"> })</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.box#By desc prio, then label'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">onEach</span><span class="hl-1">(</span><span class="hl-2">$items</span><span class="hl-1">, (</span><span class="hl-2">$item</span><span class="hl-1">, </span><span class="hl-2">index</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`li#</span><span class="hl-5">${</span><span class="hl-2">$item</span><span class="hl-9">.</span><span class="hl-2">label</span><span class="hl-5">}</span><span class="hl-3"> (prio </span><span class="hl-5">${</span><span class="hl-2">$item</span><span class="hl-9">.</span><span class="hl-2">prio</span><span class="hl-5">}</span><span class="hl-3">)`</span><span class="hl-1">)</span><br/><span class="hl-1"> }, </span><span class="hl-2">$item</span><span class="hl-1"> </span><span class="hl-5">=></span><span class="hl-1"> [-</span><span class="hl-2">$item</span><span class="hl-1">.</span><span class="hl-2">prio</span><span class="hl-1">, </span><span class="hl-2">$item</span><span class="hl-1">.</span><span class="hl-2">label</span><span class="hl-1">]);</span><br/><span class="hl-1"> })</span><br/><span class="hl-1">})</span>
|
|
199
|
-
</code><button type="button">Copy</button></pre>
|
|
200
|
-
|
|
201
|
-
<p>We can also use <a href="../aberdeen/onEach/" class="tsd-kind-function">A.onEach</a> to reactively iterate over <em>objects</em>, arrays, <code>Map</code>s and <code>Set</code>s. For objects and <code>Map</code>s, the render and order functions receive <code>(value, key)</code> instead of <code>(value, index)</code>. For <code>Set</code>s, they receive only the value. By default, Sets are ordered by that value, which only works for numbers, strings and arrays of those, so Sets of objects need an explicit order function.</p>
|
|
202
|
-
<pre><code class="javascript"><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$pairs</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">({</span><span class="hl-2">A:</span><span class="hl-1"> </span><span class="hl-3">'Y'</span><span class="hl-1">, </span><span class="hl-2">B:</span><span class="hl-1"> </span><span class="hl-3">'X'</span><span class="hl-1">,});</span><br/><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-7">randomWord</span><span class="hl-1"> = () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">Math</span><span class="hl-1">.</span><span class="hl-7">random</span><span class="hl-1">().</span><span class="hl-7">toString</span><span class="hl-1">(</span><span class="hl-8">36</span><span class="hl-1">).</span><span class="hl-7">substring</span><span class="hl-1">(</span><span class="hl-8">2</span><span class="hl-1">, </span><span class="hl-8">12</span><span class="hl-1">).</span><span class="hl-7">replace</span><span class="hl-1">(</span><span class="hl-11">/</span><span class="hl-12">[</span><span class="hl-11">0-9</span><span class="hl-12">]</span><span class="hl-13">+</span><span class="hl-11">/</span><span class="hl-5">g</span><span class="hl-1">, </span><span class="hl-3">''</span><span class="hl-1">).</span><span class="hl-7">replace</span><span class="hl-1">(</span><span class="hl-11">/</span><span class="hl-14">^</span><span class="hl-11">\w/</span><span class="hl-1">, </span><span class="hl-2">c</span><span class="hl-1"> </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">c</span><span class="hl-1">.</span><span class="hl-7">toUpperCase</span><span class="hl-1">());</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button text="Add item" click='</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$pairs</span><span class="hl-1">[</span><span class="hl-7">randomWord</span><span class="hl-1">()] = </span><span class="hl-7">randomWord</span><span class="hl-1">());</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.row.wide margin-top:1em'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.box#By key'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">onEach</span><span class="hl-1">(</span><span class="hl-2">$pairs</span><span class="hl-1">, (</span><span class="hl-2">value</span><span class="hl-1">, </span><span class="hl-2">key</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`li#</span><span class="hl-5">${</span><span class="hl-2">key</span><span class="hl-5">}</span><span class="hl-3">: </span><span class="hl-5">${</span><span class="hl-2">value</span><span class="hl-5">}</span><span class="hl-3">`</span><span class="hl-1">)</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> })</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.box#By desc value'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">onEach</span><span class="hl-1">(</span><span class="hl-2">$pairs</span><span class="hl-1">, (</span><span class="hl-2">value</span><span class="hl-1">, </span><span class="hl-2">key</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`li#</span><span class="hl-5">${</span><span class="hl-2">key</span><span class="hl-5">}</span><span class="hl-3">: </span><span class="hl-5">${</span><span class="hl-2">value</span><span class="hl-5">}</span><span class="hl-3">`</span><span class="hl-1">)</span><br/><span class="hl-1"> }, </span><span class="hl-2">value</span><span class="hl-1"> </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">invertString</span><span class="hl-1">(</span><span class="hl-2">value</span><span class="hl-1">));</span><br/><span class="hl-1"> })</span><br/><span class="hl-1">})</span>
|
|
203
|
-
</code><button type="button">Copy</button></pre>
|
|
204
|
-
|
|
205
|
-
<p>Note the use of the provided <a href="../aberdeen/invertString/" class="tsd-kind-function">A.invertString</a> function to reverse-sort by a string value.</p>
|
|
206
|
-
<h2 id="two-way-binding" class="tsd-anchor-link">Two-way binding<a href="#two-way-binding" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Aberdeen makes it easy to create two-way bindings between form elements (the various <code><input></code> types, <code><textarea></code> and <code><select></code>) and your data, by passing an observable object with a <code>.value</code> as <code>bind:</code> property to <a href="../aberdeen/A/" class="tsd-kind-function"> aberdeen.A</a>.</p>
|
|
207
|
-
<p>To bind to object properties not named <code>.value</code> (e.g., <code>$user.name</code>), use <a href="../aberdeen/ref/" class="tsd-kind-function">A.ref</a>. This creates a new observable A.proxy whose <code>.value</code> property directly maps to the specified property (e.g., <code>name</code>) on your original observable object (e.g., <code>$user</code>).</p>
|
|
208
|
-
<pre><code class="javascript"><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">A</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen'</span><span class="hl-1">;</span><br/><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$user</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">name:</span><span class="hl-1"> </span><span class="hl-3">'Alice'</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">active:</span><span class="hl-1"> </span><span class="hl-5">false</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-4">// Text input binding</span><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'input placeholder=Name bind='</span><span class="hl-1">, </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">ref</span><span class="hl-1">(</span><span class="hl-2">$user</span><span class="hl-1">, </span><span class="hl-3">'name'</span><span class="hl-1">));</span><br/><br/><span class="hl-4">// Checkbox binding</span><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'label'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'input type=checkbox bind='</span><span class="hl-1">, </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">ref</span><span class="hl-1">(</span><span class="hl-2">$user</span><span class="hl-1">, </span><span class="hl-3">'active'</span><span class="hl-1">));</span><br/><span class="hl-1">}, </span><span class="hl-3">'#Active'</span><span class="hl-1">);</span><br/><br/><span class="hl-4">// Display the current state</span><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.box'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`p#Name: </span><span class="hl-5">${</span><span class="hl-2">$user</span><span class="hl-9">.</span><span class="hl-2">name</span><span class="hl-5">}</span><span class="hl-3"> `</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-4">// Binding works both ways</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button.outline.secondary#!'</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-7">click</span><span class="hl-2">:</span><span class="hl-1"> () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$user</span><span class="hl-1">.</span><span class="hl-2">name</span><span class="hl-1"> += </span><span class="hl-3">'!'</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`p#Status: </span><span class="hl-5">${</span><span class="hl-2">$user</span><span class="hl-9">.</span><span class="hl-2">active</span><span class="hl-9"> </span><span class="hl-1">?</span><span class="hl-9"> </span><span class="hl-3">'Active'</span><span class="hl-9"> </span><span class="hl-1">:</span><span class="hl-9"> </span><span class="hl-3">'Inactive'</span><span class="hl-5">}</span><span class="hl-3">`</span><span class="hl-1">);</span><br/><span class="hl-1">});</span>
|
|
209
|
-
</code><button type="button">Copy</button></pre>
|
|
210
|
-
|
|
211
|
-
<h2 id="css" class="tsd-anchor-link">CSS<a href="#css" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Through the <a href="../aberdeen/insertCss/" class="tsd-kind-function">A.insertCss</a> function, Aberdeen provides a way to create component-local CSS.</p>
|
|
212
|
-
<p>For simple single-element styles, you can pass a string directly:</p>
|
|
213
|
-
<pre><code class="javascript"><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">A</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen'</span><span class="hl-1">;</span><br/><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">simpleCard</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">insertCss</span><span class="hl-1">(</span><span class="hl-3">"bg:#f0f0f0 p:$3 r:8px"</span><span class="hl-1">);</span><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div'</span><span class="hl-1">, </span><span class="hl-2">simpleCard</span><span class="hl-1">, </span><span class="hl-3">'#Card content'</span><span class="hl-1">);</span>
|
|
214
|
-
</code><button type="button">Copy</button></pre>
|
|
215
|
-
|
|
216
|
-
<p>For more complex styles with nested selectors, pass an object where each key is a selector and each value is a style string using the same <code>property:value</code> syntax as inline styles:</p>
|
|
217
|
-
<pre><code class="javascript"><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">A</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen'</span><span class="hl-1">;</span><br/><br/><span class="hl-4">// Create a CSS class that can be applied to elements</span><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">myBoxStyle</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">insertCss</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-3">"&"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"border-color:#6936cd background-color:#1b0447"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-3">"button"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"background-color:#6936cd border:0 transition: box-shadow 0.3s; box-shadow: 0 0 4px #ff6a0044;"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-3">"button:hover"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"box-shadow: 0 0 16px #ff6a0088;"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-3">"@media (max-width: 600px)"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"p:$1"</span><span class="hl-1">, </span><span class="hl-4">// Media query is scoped to myBoxStyle as well</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-4">// myBoxStyle is now something like ".AbdStl1", the name for a generated CSS class.</span><br/><span class="hl-4">// Here's how to use it:</span><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.box'</span><span class="hl-1">, </span><span class="hl-2">myBoxStyle</span><span class="hl-1">, </span><span class="hl-3">'button#Click me'</span><span class="hl-1">);</span>
|
|
218
|
-
</code><button type="button">Copy</button></pre>
|
|
219
|
-
|
|
220
|
-
<p>The <code>"&"</code> selector refers to the element with the generated class itself. Child selectors like <code>"button"</code> are scoped to descendants of that element, while pseudo-selectors like <code>"&:hover"</code> apply to the element itself.</p>
|
|
221
|
-
<p>This allows you to create single-file components with advanced CSS rules. The <a href="../aberdeen/insertGlobalCss/" class="tsd-kind-function">A.insertGlobalCss</a> function can be used to add CSS without a class prefix - it accepts the same string or object syntax.</p>
|
|
222
|
-
<p>Both functions support the same CSS shortcuts and variables as inline styles (see above). For example:</p>
|
|
223
|
-
<pre><code class="javascript"><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">A</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen'</span><span class="hl-1">;</span><br/><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-2">cssVars</span><span class="hl-1">.</span><span class="hl-2">boxBg</span><span class="hl-1"> = </span><span class="hl-3">'#f0f0e0'</span><span class="hl-1">;</span><br/><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">insertGlobalCss</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-3">"body"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"m:0"</span><span class="hl-1">, </span><span class="hl-4">// Using shortcut for margin</span><br/><span class="hl-1"> </span><span class="hl-3">"form"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"bg:$boxBg mv:$3"</span><span class="hl-1"> </span><span class="hl-4">// Using background shortcut, CSS variable, and spacing value</span><br/><span class="hl-1">});</span>
|
|
224
|
-
</code><button type="button">Copy</button></pre>
|
|
225
|
-
|
|
226
|
-
<p>Of course, if you dislike JavaScript-based CSS and/or prefer to use some other way to style your components, you can just ignore this Aberdeen function.</p>
|
|
227
|
-
<h2 id="transitions" class="tsd-anchor-link">Transitions<a href="#transitions" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Aberdeen allows you to easily apply transitions on element creation and element destruction:</p>
|
|
228
|
-
<pre><code class="javascript"><span class="hl-5">let</span><span class="hl-1"> </span><span class="hl-2">titleStyle</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">insertCss</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-3">"&"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"transition: all 1s ease-out; transform-origin: left center;"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-3">"&.faded"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"opacity:0"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-3">"&.imploded"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"transform:scale(0.1)"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-3">"&.exploded"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"transform:scale(5)"</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$show</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">(</span><span class="hl-5">true</span><span class="hl-1">);</span><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'label'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'input type=checkbox bind='</span><span class="hl-1">, </span><span class="hl-2">$show</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'#Show title'</span><span class="hl-1">);</span><br/><span class="hl-1">});</span><br/><span class="hl-7">A</span><span class="hl-1">(() </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-0">if</span><span class="hl-1"> (!</span><span class="hl-2">$show</span><span class="hl-1">.</span><span class="hl-2">value</span><span class="hl-1">) </span><span class="hl-0">return</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'h2#(Dis)appearing text'</span><span class="hl-1">, </span><span class="hl-2">titleStyle</span><span class="hl-1">, </span><span class="hl-3">'create=faded.imploded destroy=faded.exploded'</span><span class="hl-1">);</span><br/><span class="hl-1">});</span>
|
|
229
|
-
</code><button type="button">Copy</button></pre>
|
|
230
|
-
|
|
231
|
-
<ul>
|
|
232
|
-
<li>The creation transition works by briefly adding the given CSS classes on element creation, and immediately removing them after the initial browser layout has taken place.</li>
|
|
233
|
-
<li>The destruction transition works by delaying the removal of the element from the DOM by two seconds (currently hardcoded - should be enough for any reasonable transition), while adding the given CSS classes.</li>
|
|
234
|
-
</ul>
|
|
235
|
-
<p>Though this approach is easy (you just need to provide some CSS), you may require more control over the specifics, for instance in order to animate the layout height (or width) taken by the element as well. (Note how the document height changes in the example above are rather ugly.) For this, <code>create</code> and <code>destroy</code> may be functions instead of CSS class names. For more control, create and destroy can also accept functions. While custom function details are beyond this tutorial, Aberdeen offers ready-made <a href="../transitions/grow/" class="tsd-kind-function"> transitions.grow</a> and <a href="../transitions/shrink/" class="tsd-kind-function"> transitions.shrink</a> transition functions (which also serve as excellent examples for creating your own):</p>
|
|
236
|
-
<pre><code class="javascript"><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">A</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen'</span><span class="hl-1">;</span><br/><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">grow</span><span class="hl-1">, </span><span class="hl-2">shrink</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen/transitions'</span><span class="hl-1">;</span><br/><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$items</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">([]);</span><br/><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-7">randomInt</span><span class="hl-1"> = (</span><span class="hl-2">max</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-7">parseInt</span><span class="hl-1">(</span><span class="hl-2">Math</span><span class="hl-1">.</span><span class="hl-7">random</span><span class="hl-1">() * </span><span class="hl-2">max</span><span class="hl-1">);</span><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-7">randomWord</span><span class="hl-1"> = () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">Math</span><span class="hl-1">.</span><span class="hl-7">random</span><span class="hl-1">().</span><span class="hl-7">toString</span><span class="hl-1">(</span><span class="hl-8">36</span><span class="hl-1">).</span><span class="hl-7">substring</span><span class="hl-1">(</span><span class="hl-8">2</span><span class="hl-1">, </span><span class="hl-8">12</span><span class="hl-1">).</span><span class="hl-7">replace</span><span class="hl-1">(</span><span class="hl-11">/</span><span class="hl-12">[</span><span class="hl-11">0-9</span><span class="hl-12">]</span><span class="hl-13">+</span><span class="hl-11">/</span><span class="hl-5">g</span><span class="hl-1">, </span><span class="hl-3">''</span><span class="hl-1">).</span><span class="hl-7">replace</span><span class="hl-1">(</span><span class="hl-11">/</span><span class="hl-14">^</span><span class="hl-11">\w/</span><span class="hl-1">, </span><span class="hl-2">c</span><span class="hl-1"> </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">c</span><span class="hl-1">.</span><span class="hl-7">toUpperCase</span><span class="hl-1">());</span><br/><br/><span class="hl-4">// Make random mutations</span><br/><span class="hl-7">setInterval</span><span class="hl-1">(() </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-0">if</span><span class="hl-1"> (</span><span class="hl-7">randomInt</span><span class="hl-1">(</span><span class="hl-8">3</span><span class="hl-1">)) </span><span class="hl-2">$items</span><span class="hl-1">[</span><span class="hl-7">randomInt</span><span class="hl-1">(</span><span class="hl-8">7</span><span class="hl-1">)] = {</span><span class="hl-2">label:</span><span class="hl-1"> </span><span class="hl-7">randomWord</span><span class="hl-1">(), </span><span class="hl-2">prio:</span><span class="hl-1"> </span><span class="hl-7">randomInt</span><span class="hl-1">(</span><span class="hl-8">4</span><span class="hl-1">)};</span><br/><span class="hl-1"> </span><span class="hl-0">else</span><span class="hl-1"> </span><span class="hl-5">delete</span><span class="hl-1"> </span><span class="hl-2">$items</span><span class="hl-1">[</span><span class="hl-7">randomInt</span><span class="hl-1">(</span><span class="hl-8">7</span><span class="hl-1">)];</span><br/><span class="hl-1">}, </span><span class="hl-8">500</span><span class="hl-1">);</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.row.wide height:250px'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.box#By index'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">onEach</span><span class="hl-1">(</span><span class="hl-2">$items</span><span class="hl-1">, (</span><span class="hl-2">$item</span><span class="hl-1">, </span><span class="hl-2">index</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`li#</span><span class="hl-5">${</span><span class="hl-2">$item</span><span class="hl-9">.</span><span class="hl-2">label</span><span class="hl-5">}</span><span class="hl-3"> (prio </span><span class="hl-5">${</span><span class="hl-2">$item</span><span class="hl-9">.</span><span class="hl-2">prio</span><span class="hl-5">}</span><span class="hl-3">)`</span><span class="hl-1">, {</span><span class="hl-2">create:</span><span class="hl-1"> </span><span class="hl-2">grow</span><span class="hl-1">, </span><span class="hl-2">destroy:</span><span class="hl-1"> </span><span class="hl-2">shrink</span><span class="hl-1">})</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> })</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.box#By label'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">onEach</span><span class="hl-1">(</span><span class="hl-2">$items</span><span class="hl-1">, (</span><span class="hl-2">$item</span><span class="hl-1">, </span><span class="hl-2">index</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`li#</span><span class="hl-5">${</span><span class="hl-2">$item</span><span class="hl-9">.</span><span class="hl-2">label</span><span class="hl-5">}</span><span class="hl-3"> (prio </span><span class="hl-5">${</span><span class="hl-2">$item</span><span class="hl-9">.</span><span class="hl-2">prio</span><span class="hl-5">}</span><span class="hl-3">)`</span><span class="hl-1">, {</span><span class="hl-2">create:</span><span class="hl-1"> </span><span class="hl-2">grow</span><span class="hl-1">, </span><span class="hl-2">destroy:</span><span class="hl-1"> </span><span class="hl-2">shrink</span><span class="hl-1">})</span><br/><span class="hl-1"> }, </span><span class="hl-2">$item</span><span class="hl-1"> </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$item</span><span class="hl-1">.</span><span class="hl-2">label</span><span class="hl-1">);</span><br/><span class="hl-1"> })</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.box#By desc prio, then label'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">onEach</span><span class="hl-1">(</span><span class="hl-2">$items</span><span class="hl-1">, (</span><span class="hl-2">$item</span><span class="hl-1">, </span><span class="hl-2">index</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`li#</span><span class="hl-5">${</span><span class="hl-2">$item</span><span class="hl-9">.</span><span class="hl-2">label</span><span class="hl-5">}</span><span class="hl-3"> (prio </span><span class="hl-5">${</span><span class="hl-2">$item</span><span class="hl-9">.</span><span class="hl-2">prio</span><span class="hl-5">}</span><span class="hl-3">)`</span><span class="hl-1">, {</span><span class="hl-2">create:</span><span class="hl-1"> </span><span class="hl-2">grow</span><span class="hl-1">, </span><span class="hl-2">destroy:</span><span class="hl-1"> </span><span class="hl-2">shrink</span><span class="hl-1">})</span><br/><span class="hl-1"> }, </span><span class="hl-2">$item</span><span class="hl-1"> </span><span class="hl-5">=></span><span class="hl-1"> [-</span><span class="hl-2">$item</span><span class="hl-1">.</span><span class="hl-2">prio</span><span class="hl-1">, </span><span class="hl-2">$item</span><span class="hl-1">.</span><span class="hl-2">label</span><span class="hl-1">]);</span><br/><span class="hl-1"> })</span><br/><span class="hl-1">});</span>
|
|
237
|
-
</code><button type="button">Copy</button></pre>
|
|
238
|
-
|
|
239
|
-
<h2 id="advanced-peeking-without-subscribing" class="tsd-anchor-link">Advanced: Peeking without subscribing<a href="#advanced-peeking-without-subscribing" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Sometimes you need to read reactive data inside an observer scope without creating a subscription to that data. The <a href="../aberdeen/peek/" class="tsd-kind-function">A.peek</a> function allows you to do this:</p>
|
|
240
|
-
<pre><code class="javascript"><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">A</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen'</span><span class="hl-1">;</span><br/><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$data</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">({ </span><span class="hl-2">a:</span><span class="hl-1"> </span><span class="hl-8">1</span><span class="hl-1">, </span><span class="hl-2">b:</span><span class="hl-1"> </span><span class="hl-8">2</span><span class="hl-1"> });</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(() </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-4">// This scope only re-runs when $data.a changes</span><br/><span class="hl-1"> </span><span class="hl-4">// Changes to $data.b won't trigger a re-render</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`h2#a == </span><span class="hl-5">${</span><span class="hl-2">$data</span><span class="hl-9">.</span><span class="hl-2">a</span><span class="hl-5">}</span><span class="hl-3"> && b == </span><span class="hl-5">${</span><span class="hl-6">A</span><span class="hl-9">.</span><span class="hl-7">peek</span><span class="hl-9">(</span><span class="hl-2">$data</span><span class="hl-9">, </span><span class="hl-3">'b'</span><span class="hl-9">)</span><span class="hl-5">}</span><span class="hl-3">`</span><span class="hl-1">);</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`button text="a++ (will update)" click=`</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$data</span><span class="hl-1">.</span><span class="hl-2">a</span><span class="hl-1">++);</span><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`button ml:1rem text="b++ (won't update)" click=`</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$data</span><span class="hl-1">.</span><span class="hl-2">b</span><span class="hl-1">++);</span>
|
|
241
|
-
</code><button type="button">Copy</button></pre>
|
|
242
|
-
|
|
243
|
-
<p>You can also pass a function to <code>A.peek()</code> to execute it without any subscriptions:</p>
|
|
244
|
-
<pre><code class="javascript"><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$a</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">(</span><span class="hl-8">42</span><span class="hl-1">);</span><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$b</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">(</span><span class="hl-8">7</span><span class="hl-1">);</span><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">sum</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">peek</span><span class="hl-1">(() </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$a</span><span class="hl-1">.</span><span class="hl-2">value</span><span class="hl-1"> + </span><span class="hl-2">$b</span><span class="hl-1">.</span><span class="hl-2">value</span><span class="hl-1">); </span><span class="hl-4">// Reads both without subscribing</span><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'#Sum is: '</span><span class="hl-1">+</span><span class="hl-2">sum</span><span class="hl-1">);</span><br/><span class="hl-7">setInterval</span><span class="hl-1">(() </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$a</span><span class="hl-1">.</span><span class="hl-2">value</span><span class="hl-1">++, </span><span class="hl-8">1000</span><span class="hl-1">); </span><span class="hl-4">// Won't update</span>
|
|
245
|
-
</code><button type="button">Copy</button></pre>
|
|
246
|
-
|
|
247
|
-
<p>This can be useful to avoid rerenders (of even rerender loops) when you only need a point-in-time snapshot of some reactive data.</p>
|
|
248
|
-
<h2 id="derived-values" class="tsd-anchor-link">Derived values<a href="#derived-values" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>An observer scope doesn't <em>need</em> to create DOM elements. It may also perform other side effects, such as modifying other observable objects. For instance:</p>
|
|
249
|
-
<pre><code class="javascript"><span class="hl-4">// NOTE: See below for a better way.</span><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$original</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">(</span><span class="hl-8">1</span><span class="hl-1">);</span><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$derived</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">();</span><br/><span class="hl-7">A</span><span class="hl-1">(() </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">$derived</span><span class="hl-1">.</span><span class="hl-2">value</span><span class="hl-1"> = </span><span class="hl-2">$original</span><span class="hl-1">.</span><span class="hl-2">value</span><span class="hl-1"> * </span><span class="hl-8">42</span><span class="hl-1">;</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'h3 text='</span><span class="hl-1">, </span><span class="hl-2">$derived</span><span class="hl-1">);</span><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button text=Increment click='</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$original</span><span class="hl-1">.</span><span class="hl-2">value</span><span class="hl-1">++);</span>
|
|
250
|
-
</code><button type="button">Copy</button></pre>
|
|
251
|
-
|
|
252
|
-
<p>The <a href="../aberdeen/derive/" class="tsd-kind-function">A.derive</a> function makes the above a little easier. It works just like passing a function to <a href="../aberdeen/A/" class="tsd-kind-function"> aberdeen.A</a>, creating an observer, the only difference being that the value returned by the function is reactively assigned to the <code>value</code> property of the observable object returned by <code>derive</code>. So the above could also be written as:</p>
|
|
253
|
-
<pre><code class="javascript"><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$original</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">(</span><span class="hl-8">1</span><span class="hl-1">);</span><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$derived</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">derive</span><span class="hl-1">(() </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$original</span><span class="hl-1">.</span><span class="hl-2">value</span><span class="hl-1"> * </span><span class="hl-8">42</span><span class="hl-1">);</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'h3 text='</span><span class="hl-1">, </span><span class="hl-2">$derived</span><span class="hl-1">);</span><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button text=Increment click='</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$original</span><span class="hl-1">.</span><span class="hl-2">value</span><span class="hl-1">++);</span>
|
|
254
|
-
</code><button type="button">Copy</button></pre>
|
|
255
|
-
|
|
256
|
-
<p>For deriving values from (possibly large) arrays, objects, Maps or Sets, Aberdeen provides specialized functions that enable fast, incremental updates to derived data: <a href="../aberdeen/map/" class="tsd-kind-function">A.map</a> (each item becomes zero or one derived item), <a href="../aberdeen/multiMap/" class="tsd-kind-function">A.multiMap</a> (each item becomes any number of derived items), <a href="../aberdeen/count/" class="tsd-kind-function">A.count</a> (reactively counts the number of object properties or collection items), <a href="../aberdeen/isEmpty/" class="tsd-kind-function">A.isEmpty</a> (true when the object/array/Map/Set has no items) and <a href="../aberdeen/partition/" class="tsd-kind-function">A.partition</a> (sorts each item into one or more buckets). An example:</p>
|
|
257
|
-
<pre><code class="javascript"><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">A</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen'</span><span class="hl-1">;</span><br/><br/><span class="hl-4">// Create some random data</span><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$people</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">({});</span><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-7">randomInt</span><span class="hl-1"> = (</span><span class="hl-2">max</span><span class="hl-1">) </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-7">parseInt</span><span class="hl-1">(</span><span class="hl-2">Math</span><span class="hl-1">.</span><span class="hl-7">random</span><span class="hl-1">() * </span><span class="hl-2">max</span><span class="hl-1">);</span><br/><span class="hl-7">setInterval</span><span class="hl-1">(() </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">$people</span><span class="hl-1">[</span><span class="hl-7">randomInt</span><span class="hl-1">(</span><span class="hl-8">250</span><span class="hl-1">)] = {</span><span class="hl-2">height:</span><span class="hl-1"> </span><span class="hl-8">150</span><span class="hl-1">+</span><span class="hl-7">randomInt</span><span class="hl-1">(</span><span class="hl-8">60</span><span class="hl-1">), </span><span class="hl-2">weight:</span><span class="hl-1"> </span><span class="hl-8">45</span><span class="hl-1">+</span><span class="hl-7">randomInt</span><span class="hl-1">(</span><span class="hl-8">90</span><span class="hl-1">)};</span><br/><span class="hl-1">}, </span><span class="hl-8">250</span><span class="hl-1">);</span><br/><br/><span class="hl-4">// Do some mapping, counting and observing</span><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$totalCount</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">count</span><span class="hl-1">(</span><span class="hl-2">$people</span><span class="hl-1">);</span><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$bmis</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">map</span><span class="hl-1">(</span><span class="hl-2">$people</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-2">$person</span><span class="hl-1"> </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">Math</span><span class="hl-1">.</span><span class="hl-7">round</span><span class="hl-1">(</span><span class="hl-2">$person</span><span class="hl-1">.</span><span class="hl-2">weight</span><span class="hl-1"> / ((</span><span class="hl-2">$person</span><span class="hl-1">.</span><span class="hl-2">height</span><span class="hl-1">/</span><span class="hl-8">100</span><span class="hl-1">) ** </span><span class="hl-8">2</span><span class="hl-1">))</span><br/><span class="hl-1">);</span><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$overweightBmis</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">map</span><span class="hl-1">(</span><span class="hl-2">$bmis</span><span class="hl-1">, </span><span class="hl-4">// Use A.map() as a filter</span><br/><span class="hl-1"> </span><span class="hl-2">bmi</span><span class="hl-1"> </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">bmi</span><span class="hl-1"> > </span><span class="hl-8">25</span><span class="hl-1"> ? </span><span class="hl-2">bmi</span><span class="hl-1"> : </span><span class="hl-5">undefined</span><br/><span class="hl-1">); </span><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$overweightCount</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">count</span><span class="hl-1">(</span><span class="hl-2">$overweightBmis</span><span class="hl-1">);</span><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$message</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">derive</span><span class="hl-1">(</span><br/><span class="hl-1"> () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-3">`There are </span><span class="hl-5">${</span><span class="hl-2">$totalCount</span><span class="hl-9">.</span><span class="hl-2">value</span><span class="hl-5">}</span><span class="hl-3"> people, of which </span><span class="hl-5">${</span><span class="hl-2">$overweightCount</span><span class="hl-9">.</span><span class="hl-2">value</span><span class="hl-5">}</span><span class="hl-3"> are overweight.`</span><br/><span class="hl-1">);</span><br/><br/><span class="hl-4">// Show the results</span><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'p text='</span><span class="hl-1">, </span><span class="hl-2">$message</span><span class="hl-1">);</span><br/><span class="hl-7">A</span><span class="hl-1">(() </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-4">// isEmpty only causes a re-run when the count changes between zero and non-zero</span><br/><span class="hl-1"> </span><span class="hl-0">if</span><span class="hl-1"> (</span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">isEmpty</span><span class="hl-1">(</span><span class="hl-2">$overweightBmis</span><span class="hl-1">)) </span><span class="hl-0">return</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'p#These are their BMIs:'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">onEach</span><span class="hl-1">(</span><span class="hl-2">$overweightBmis</span><span class="hl-1">, </span><span class="hl-2">bmi</span><span class="hl-1"> </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'# '</span><span class="hl-1">+</span><span class="hl-2">bmi</span><span class="hl-1">), </span><span class="hl-2">bmi</span><span class="hl-1"> </span><span class="hl-5">=></span><span class="hl-1"> -</span><span class="hl-2">bmi</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-4">// Sort by descending BMI</span><br/><span class="hl-1"> });</span><br/><span class="hl-1">})</span>
|
|
258
|
-
</code><button type="button">Copy</button></pre>
|
|
259
|
-
|
|
260
|
-
<h2 id="ui-components" class="tsd-anchor-link">UI Components<a href="#ui-components" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>UI Components in Aberdeen are just functions, named <code>draw<Something></code> by convention, that use <a href="../aberdeen/A/" class="tsd-kind-function"> aberdeen.A</a> to create some DOM structure. They can accept arguments, return (proxied) values and create local (proxied) state just like any other function.</p>
|
|
261
|
-
<pre><code class="javascript"><span class="hl-5">function</span><span class="hl-1"> </span><span class="hl-7">drawCounter</span><span class="hl-1">(</span><span class="hl-2">initialValue</span><span class="hl-1"> = </span><span class="hl-8">0</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$count</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">(</span><span class="hl-2">initialValue</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.row'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button text=- click='</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$count</span><span class="hl-1">.</span><span class="hl-2">value</span><span class="hl-1">--);</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div text='</span><span class="hl-1">, </span><span class="hl-2">$count</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button text=+ click='</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$count</span><span class="hl-1">.</span><span class="hl-2">value</span><span class="hl-1">++);</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> </span><span class="hl-0">return</span><span class="hl-1"> </span><span class="hl-2">$count</span><span class="hl-1">; </span><span class="hl-4">// Return the reactive count value for external use</span><br/><span class="hl-1">}</span><br/><span class="hl-4">// Create multiple independent instances:</span><br/><span class="hl-7">drawCounter</span><span class="hl-1">();</span><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$second</span><span class="hl-1"> = </span><span class="hl-7">drawCounter</span><span class="hl-1">(</span><span class="hl-8">42</span><span class="hl-1">);</span><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'input value='</span><span class="hl-1">, </span><span class="hl-2">$second</span><span class="hl-1">); </span><span class="hl-4">// Bind the second counter to an input field</span>
|
|
262
|
-
</code><button type="button">Copy</button></pre>
|
|
263
|
-
|
|
264
|
-
<h2 id="debugging-with-adump" class="tsd-anchor-link">Debugging with A.dump()<a href="#debugging-with-adump" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>The <a href="../aberdeen/dump/" class="tsd-kind-function">A.dump</a> function creates a live, interactive tree view of any data structure in the DOM. It's particularly useful for debugging reactive state:</p>
|
|
265
|
-
<pre><code class="javascript"><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">A</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen'</span><span class="hl-1">;</span><br/><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$state</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-2">user:</span><span class="hl-1"> { </span><span class="hl-2">name:</span><span class="hl-1"> </span><span class="hl-3">'Frank'</span><span class="hl-1">, </span><span class="hl-2">kids:</span><span class="hl-1"> </span><span class="hl-8">1</span><span class="hl-1"> },</span><br/><span class="hl-1"> </span><span class="hl-2">items:</span><span class="hl-1"> [</span><span class="hl-3">'a'</span><span class="hl-1">, </span><span class="hl-3">'b'</span><span class="hl-1">]</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'h2#Live State Dump'</span><span class="hl-1">);</span><br/><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">dump</span><span class="hl-1">(</span><span class="hl-2">$state</span><span class="hl-1">);</span><br/><br/><span class="hl-4">// The A.dump updates automatically as $state changes</span><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button text="Update state" click='</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-2">$state</span><span class="hl-1">.</span><span class="hl-2">user</span><span class="hl-1">.</span><span class="hl-2">kids</span><span class="hl-1">++;</span><br/><span class="hl-1"> </span><span class="hl-2">$state</span><span class="hl-1">.</span><span class="hl-2">items</span><span class="hl-1">.</span><span class="hl-7">push</span><span class="hl-1">(</span><span class="hl-3">'new'</span><span class="hl-1">);</span><br/><span class="hl-1">});</span>
|
|
266
|
-
</code><button type="button">Copy</button></pre>
|
|
267
|
-
|
|
268
|
-
<p>The A.dump renders recursively using <code><ul></code> and <code><li></code> elements, showing all properties and their values. It updates reactively when any proxied data changes. It is intended for debugging, though with some CSS styling you may find it useful in some simple real-world scenarios as well.</p>
|
|
269
|
-
<h2 id="html-to-aberdeen" class="tsd-anchor-link">html-to-aberdeen<a href="#html-to-aberdeen" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Sometimes, you want to just paste a largish block of HTML into your application (and then maybe modify it to bind some actual data). Having to translate HTML to <code>$</code> calls manually is little fun, so there's a tool for that:</p>
|
|
270
|
-
<pre><code class="sh"><span class="hl-7">npx</span><span class="hl-1"> </span><span class="hl-3">html-to-aberdeen</span>
|
|
271
|
-
</code><button type="button">Copy</button></pre>
|
|
272
|
-
|
|
273
|
-
<p>It takes HTML on stdin (paste it and press <code>ctrl-d</code> for end-of-file), and outputs JavaScript on stdout.</p>
|
|
274
|
-
<blockquote>
|
|
275
|
-
<p>Caveat: This tool has been vibe coded (thanks Claude!) with very little code review. As it doesn't use the filesystem nor the network, I'd say it's safe to use though! :-) Also, it happens to work pretty well.</p>
|
|
276
|
-
</blockquote>
|
|
277
|
-
<h2 id="routing" class="tsd-anchor-link">Routing<a href="#routing" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Aberdeen provides an optional built-in router via the <a href="../route/" class="tsd-kind-module"> route</a> module. The router is reactive and integrates seamlessly with browser history.</p>
|
|
278
|
-
<p>The <a href="../route/current/" class="tsd-kind-variable"> route.current</a> object is an observable that reflects the current URL:</p>
|
|
279
|
-
<pre><code class="javascript"><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">A</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen'</span><span class="hl-1">;</span><br/><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-5">*</span><span class="hl-1"> </span><span class="hl-0">as</span><span class="hl-1"> </span><span class="hl-2">route</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen/route'</span><span class="hl-1">;</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(() </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`p#Path string: </span><span class="hl-5">${</span><span class="hl-2">route</span><span class="hl-9">.</span><span class="hl-2">current</span><span class="hl-9">.</span><span class="hl-2">path</span><span class="hl-5">}</span><span class="hl-3">`</span><span class="hl-1">); </span><span class="hl-4">// eg "/example/123"</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`p#Path segments: </span><span class="hl-5">${</span><span class="hl-6">JSON</span><span class="hl-9">.</span><span class="hl-7">stringify</span><span class="hl-9">(</span><span class="hl-2">route</span><span class="hl-9">.</span><span class="hl-2">current</span><span class="hl-9">.</span><span class="hl-2">p</span><span class="hl-9">)</span><span class="hl-5">}</span><span class="hl-3">`</span><span class="hl-1">); </span><span class="hl-4">// eg ["example", "123"]</span><br/><span class="hl-1">});</span>
|
|
280
|
-
</code><button type="button">Copy</button></pre>
|
|
281
|
-
|
|
282
|
-
<p>To navigate programmatically, use <a href="../route/go/" class="tsd-kind-function"> route.go</a>:</p>
|
|
283
|
-
<pre><code class="javascript"><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">A</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen'</span><span class="hl-1">;</span><br/><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-5">*</span><span class="hl-1"> </span><span class="hl-0">as</span><span class="hl-1"> </span><span class="hl-2">route</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen/route'</span><span class="hl-1">;</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'h2'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'#'</span><span class="hl-1">, </span><span class="hl-2">route</span><span class="hl-1">.</span><span class="hl-2">current</span><span class="hl-1">.</span><span class="hl-2">path</span><span class="hl-1">));</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button#Go to settings'</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-7">click</span><span class="hl-2">:</span><span class="hl-1"> () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">route</span><span class="hl-1">.</span><span class="hl-7">go</span><span class="hl-1">(</span><span class="hl-3">'/settings'</span><span class="hl-1">)</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-4">// Or using path segments</span><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button ml:1rem #Go to user 123'</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-7">click</span><span class="hl-2">:</span><span class="hl-1"> () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">route</span><span class="hl-1">.</span><span class="hl-7">go</span><span class="hl-1">({</span><span class="hl-2">p:</span><span class="hl-1"> [</span><span class="hl-3">'users'</span><span class="hl-1">, </span><span class="hl-8">123</span><span class="hl-1">]})</span><br/><span class="hl-1">});</span>
|
|
284
|
-
</code><button type="button">Copy</button></pre>
|
|
285
|
-
|
|
286
|
-
<p>For convenience, you can call <a href="../route/interceptLinks/" class="tsd-kind-function"> route.interceptLinks</a> once to automatically convert clicks on local <code><a></code> tags into Aberdeen routing, so you can use regular anchor tags without manual click handlers. Example: <code>A('a href=/settings text=Settings')</code>.</p>
|
|
287
|
-
<pre><code class="javascript"><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">A</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen'</span><span class="hl-1">;</span><br/><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-5">*</span><span class="hl-1"> </span><span class="hl-0">as</span><span class="hl-1"> </span><span class="hl-2">route</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen/route'</span><span class="hl-1">;</span><br/><br/><span class="hl-2">route</span><span class="hl-1">.</span><span class="hl-7">interceptLinks</span><span class="hl-1">(); </span><span class="hl-4">// Just once on startup</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'h2'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'#'</span><span class="hl-1">, </span><span class="hl-2">route</span><span class="hl-1">.</span><span class="hl-2">current</span><span class="hl-1">.</span><span class="hl-2">path</span><span class="hl-1">));</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'a role=button href=/settings #Go to settings'</span><span class="hl-1">)</span>
|
|
288
|
-
</code><button type="button">Copy</button></pre>
|
|
289
|
-
|
|
290
|
-
<p>The <a href="../route/push/" class="tsd-kind-function"> route.push</a> function is useful for overlays that should be closeable with browser back:</p>
|
|
291
|
-
<pre><code class="javascript"><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">A</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen'</span><span class="hl-1">;</span><br/><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-5">*</span><span class="hl-1"> </span><span class="hl-0">as</span><span class="hl-1"> </span><span class="hl-2">route</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen/route'</span><span class="hl-1">;</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'button#Open modal'</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-7">click</span><span class="hl-2">:</span><span class="hl-1"> () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">route</span><span class="hl-1">.</span><span class="hl-7">push</span><span class="hl-1">({</span><span class="hl-2">state:</span><span class="hl-1"> {</span><span class="hl-2">modal:</span><span class="hl-1"> </span><span class="hl-3">'settings'</span><span class="hl-1">}})</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-7">A</span><span class="hl-1">(() </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-0">if</span><span class="hl-1"> (!</span><span class="hl-2">route</span><span class="hl-1">.</span><span class="hl-2">current</span><span class="hl-1">.</span><span class="hl-2">state</span><span class="hl-1">.</span><span class="hl-2">modal</span><span class="hl-1">) </span><span class="hl-0">return</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.modal-overlay'</span><span class="hl-1">, {</span><br/><span class="hl-1"> </span><span class="hl-7">click</span><span class="hl-2">:</span><span class="hl-1"> () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">route</span><span class="hl-1">.</span><span class="hl-7">back</span><span class="hl-1">({</span><span class="hl-2">state:</span><span class="hl-1"> {</span><span class="hl-2">modal:</span><span class="hl-1"> </span><span class="hl-5">undefined</span><span class="hl-1">}})</span><br/><span class="hl-1"> }, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.modal#Modal content here'</span><span class="hl-1">);</span><br/><span class="hl-1"> });</span><br/><span class="hl-1">});</span>
|
|
292
|
-
</code><button type="button">Copy</button></pre>
|
|
293
|
-
|
|
294
|
-
<p>Optionally, you can use the <a href="../dispatcher/Dispatcher/" class="tsd-kind-class"> dispatcher.Dispatcher</a> class for declarative routing. It allows you to register route patterns with associated handler functions, which are invoked when the current route matches the pattern. It can match typed parameters and rest parameters.</p>
|
|
295
|
-
<h2 id="prediction" class="tsd-anchor-link">Prediction<a href="#prediction" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>When building interactive applications with client-server communication, Aberdeen's prediction system allows for optimistic UI updates. The <a href="../prediction/applyPrediction/" class="tsd-kind-function"> prediction.applyPrediction</a> function records changes to any proxied objects made within its callback. These changes are treated as <em>predictions</em> that may later be confirmed or reverted based on server responses. When a server response arrives, the <a href="../prediction/applyCanon/" class="tsd-kind-function"> prediction.applyCanon</a> function applies authoritative changes from the server, reverting any conflicting predictions while attempting to reapply non-conflicting ones.</p>
|
|
296
|
-
<h2 id="full-example-multi-page-app" class="tsd-anchor-link">Full Example: Multi-page App<a href="#full-example-multi-page-app" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>Here's a complete example (a contact manager) demonstrating routing, state management, CSS, dark mode, and dynamic content:</p>
|
|
297
|
-
<pre><code class="typescript"><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-2">A</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen'</span><span class="hl-1">;</span><br/><span class="hl-0">import</span><span class="hl-1"> </span><span class="hl-5">*</span><span class="hl-1"> </span><span class="hl-0">as</span><span class="hl-1"> </span><span class="hl-2">route</span><span class="hl-1"> </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen/route'</span><span class="hl-1">;</span><br/><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">Dispatcher</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen/dispatcher'</span><span class="hl-1">;</span><br/><span class="hl-0">import</span><span class="hl-1"> { </span><span class="hl-2">grow</span><span class="hl-1">, </span><span class="hl-2">shrink</span><span class="hl-1"> } </span><span class="hl-0">from</span><span class="hl-1"> </span><span class="hl-3">'aberdeen/transitions'</span><span class="hl-1">;</span><br/><br/><span class="hl-5">class</span><span class="hl-1"> </span><span class="hl-10">Contact</span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-5">constructor</span><span class="hl-1">(</span><br/><span class="hl-1"> </span><span class="hl-5">public</span><span class="hl-1"> </span><span class="hl-2">id</span><span class="hl-1">: </span><span class="hl-10">number</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">public</span><span class="hl-1"> </span><span class="hl-2">firstName</span><span class="hl-1">: </span><span class="hl-10">string</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">public</span><span class="hl-1"> </span><span class="hl-2">lastName</span><span class="hl-1">: </span><span class="hl-10">string</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">public</span><span class="hl-1"> </span><span class="hl-2">email</span><span class="hl-1">: </span><span class="hl-10">string</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-5">public</span><span class="hl-1"> </span><span class="hl-2">phone</span><span class="hl-1">: </span><span class="hl-10">string</span><br/><span class="hl-1"> ) {}</span><br/><span class="hl-1">}</span><br/><br/><span class="hl-4">// Enable link interception for SPA navigation</span><br/><span class="hl-2">route</span><span class="hl-1">.</span><span class="hl-7">interceptLinks</span><span class="hl-1">();</span><br/><br/><span class="hl-4">// Initialize $1-$12 CSS variables for consistent spacing ($2=0.5rem, $3=1rem, $4=2rem, etc.)</span><br/><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">setSpacingCssVars</span><span class="hl-1">();</span><br/><br/><span class="hl-4">// Reactive theme based on system preference</span><br/><span class="hl-7">A</span><span class="hl-1">(() </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-2">cssVars</span><span class="hl-1">.</span><span class="hl-2">primary</span><span class="hl-1"> = </span><span class="hl-3">'#2563eb'</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-2">cssVars</span><span class="hl-1">.</span><span class="hl-2">bg</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">darkMode</span><span class="hl-1">() ? </span><span class="hl-3">'#0f172a'</span><span class="hl-1"> : </span><span class="hl-3">'#ffffff'</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-2">cssVars</span><span class="hl-1">.</span><span class="hl-2">fg</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">darkMode</span><span class="hl-1">() ? </span><span class="hl-3">'#e2e8f0'</span><span class="hl-1"> : </span><span class="hl-3">'#1e293b'</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-2">cssVars</span><span class="hl-1">.</span><span class="hl-2">cardBg</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">darkMode</span><span class="hl-1">() ? </span><span class="hl-3">'#1e293b'</span><span class="hl-1"> : </span><span class="hl-3">'#f8fafc'</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-2">cssVars</span><span class="hl-1">.</span><span class="hl-2">border</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">darkMode</span><span class="hl-1">() ? </span><span class="hl-3">'#334155'</span><span class="hl-1"> : </span><span class="hl-3">'#e2e8f0'</span><span class="hl-1">;</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-4">// Global styles for semantic HTML elements that apply everywhere</span><br/><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">insertGlobalCss</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-3">"*"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"m:0 p:0"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-3">"body"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"bg:$bg fg:$fg font-family: system-ui, sans-serif;"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-3">"a"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"color:$primary text-decoration:none"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-3">"a:hover"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"text-decoration:underline"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-3">"a[role=button]"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"bg:$primary fg:white r:8px p:$2"</span><span class="hl-1">,</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-4">// Application state</span><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$contacts</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">proxy</span><span class="hl-1">([</span><br/><span class="hl-1"> </span><span class="hl-5">new</span><span class="hl-1"> </span><span class="hl-7">Contact</span><span class="hl-1">(</span><span class="hl-8">1</span><span class="hl-1">, </span><span class="hl-3">'Emma'</span><span class="hl-1">, </span><span class="hl-3">'Wilson'</span><span class="hl-1">, </span><span class="hl-3">'emma.wilson@email.com'</span><span class="hl-1">, </span><span class="hl-3">'555-0101'</span><span class="hl-1">),</span><br/><span class="hl-1"> </span><span class="hl-5">new</span><span class="hl-1"> </span><span class="hl-7">Contact</span><span class="hl-1">(</span><span class="hl-8">2</span><span class="hl-1">, </span><span class="hl-3">'James'</span><span class="hl-1">, </span><span class="hl-3">'Anderson'</span><span class="hl-1">, </span><span class="hl-3">'j.anderson@email.com'</span><span class="hl-1">, </span><span class="hl-3">'555-0102'</span><span class="hl-1">),</span><br/><span class="hl-1"> </span><span class="hl-5">new</span><span class="hl-1"> </span><span class="hl-7">Contact</span><span class="hl-1">(</span><span class="hl-8">3</span><span class="hl-1">, </span><span class="hl-3">'Sofia'</span><span class="hl-1">, </span><span class="hl-3">'Martinez'</span><span class="hl-1">, </span><span class="hl-3">'sofia.m@email.com'</span><span class="hl-1">, </span><span class="hl-3">'555-0103'</span><span class="hl-1">),</span><br/><span class="hl-1"> </span><span class="hl-5">new</span><span class="hl-1"> </span><span class="hl-7">Contact</span><span class="hl-1">(</span><span class="hl-8">4</span><span class="hl-1">, </span><span class="hl-3">'Liam'</span><span class="hl-1">, </span><span class="hl-3">'Brown'</span><span class="hl-1">, </span><span class="hl-3">'liam.brown@email.com'</span><span class="hl-1">, </span><span class="hl-3">'555-0104'</span><span class="hl-1">)</span><br/><span class="hl-1">]);</span><br/><br/><span class="hl-4">// Router setup</span><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">dispatcher</span><span class="hl-1"> = </span><span class="hl-5">new</span><span class="hl-1"> </span><span class="hl-7">Dispatcher</span><span class="hl-1">();</span><br/><span class="hl-2">dispatcher</span><span class="hl-1">.</span><span class="hl-7">addRoute</span><span class="hl-1">(</span><span class="hl-2">drawHome</span><span class="hl-1">);</span><br/><span class="hl-2">dispatcher</span><span class="hl-1">.</span><span class="hl-7">addRoute</span><span class="hl-1">(</span><span class="hl-3">'contacts'</span><span class="hl-1">, </span><span class="hl-2">drawContactList</span><span class="hl-1">);</span><br/><span class="hl-2">dispatcher</span><span class="hl-1">.</span><span class="hl-7">addRoute</span><span class="hl-1">(</span><span class="hl-3">'contacts'</span><span class="hl-1">, </span><span class="hl-2">Number</span><span class="hl-1">, </span><span class="hl-2">drawContactDetail</span><span class="hl-1">);</span><br/><br/><span class="hl-4">// Main app</span><br/><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div.app'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'nav display:flex gap:$3 p:$3 border-bottom: 1px solid $border;'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'a href=/ text=Home font-weight:'</span><span class="hl-1">, </span><span class="hl-2">route</span><span class="hl-1">.</span><span class="hl-2">current</span><span class="hl-1">.</span><span class="hl-2">p</span><span class="hl-1">.</span><span class="hl-2">length</span><span class="hl-1"> === </span><span class="hl-8">0</span><span class="hl-1"> ? </span><span class="hl-3">'bold'</span><span class="hl-1"> : </span><span class="hl-3">'normal'</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'a href=/contacts text=Contacts font-weight:'</span><span class="hl-1">, </span><span class="hl-2">route</span><span class="hl-1">.</span><span class="hl-2">current</span><span class="hl-1">.</span><span class="hl-2">p</span><span class="hl-1">[</span><span class="hl-8">0</span><span class="hl-1">] === </span><span class="hl-3">'contacts'</span><span class="hl-1"> ? </span><span class="hl-3">'bold'</span><span class="hl-1"> : </span><span class="hl-3">'normal'</span><span class="hl-1">);</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'main p:$3'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">dispatcher</span><span class="hl-1">.</span><span class="hl-7">dispatch</span><span class="hl-1">(</span><span class="hl-2">route</span><span class="hl-1">.</span><span class="hl-2">current</span><span class="hl-1">.</span><span class="hl-2">p</span><span class="hl-1">));</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-5">function</span><span class="hl-1"> </span><span class="hl-7">drawHome</span><span class="hl-1">() {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'h1#Contact Manager'</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'p#A modern contact list with search, sort, and dark mode support.'</span><span class="hl-1">);</span><br/><span class="hl-1">}</span><br/><br/><span class="hl-4">// Contact card styles</span><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">cardStyle</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">insertCss</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-3">"&"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"bg:$cardBg border: 1px solid $border; r:8px p:$3 mv:$2 display:block transition: transform 0.2s;"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-3">"&:hover"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"transform:translateX(4px)"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-3">"a&"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"color:inherit;"</span><span class="hl-1">,</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">filterStyle</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">insertCss</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-3">"&"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"display:flex gap:$3 mv:$3"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-3">"> *"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"p:$2 r:4px bg:$bg fg:$fg border: 1px solid $border;"</span><span class="hl-1">,</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-5">function</span><span class="hl-1"> </span><span class="hl-7">drawContactList</span><span class="hl-1">() {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'h1#Contacts'</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><br/><span class="hl-1"> </span><span class="hl-4">// Search and sort controls</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div'</span><span class="hl-1">, </span><span class="hl-2">filterStyle</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'input flex:1 placeholder="Search contacts..." bind='</span><span class="hl-1">, </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">ref</span><span class="hl-1">(</span><span class="hl-2">route</span><span class="hl-1">.</span><span class="hl-2">current</span><span class="hl-1">.</span><span class="hl-2">search</span><span class="hl-1">, </span><span class="hl-3">'q'</span><span class="hl-1">));</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'select bind='</span><span class="hl-1">, </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">ref</span><span class="hl-1">(</span><span class="hl-2">route</span><span class="hl-1">.</span><span class="hl-2">current</span><span class="hl-1">.</span><span class="hl-2">search</span><span class="hl-1">, </span><span class="hl-3">'sort'</span><span class="hl-1">), () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'option value=firstName #First Name'</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'option value=lastName #Last Name'</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'option value=email #Email'</span><span class="hl-1">);</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> </span><br/><span class="hl-1"> </span><span class="hl-4">// Contact list</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">sortBy</span><span class="hl-1"> = </span><span class="hl-2">route</span><span class="hl-1">.</span><span class="hl-2">current</span><span class="hl-1">.</span><span class="hl-2">search</span><span class="hl-1">.</span><span class="hl-2">sort</span><span class="hl-1"> || </span><span class="hl-3">'firstName'</span><span class="hl-1">;</span><br/><br/><span class="hl-1"> </span><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$filtered</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">map</span><span class="hl-1">(</span><span class="hl-2">$contacts</span><span class="hl-1">, </span><span class="hl-2">$contact</span><span class="hl-1"> </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">query</span><span class="hl-1"> = </span><span class="hl-2">route</span><span class="hl-1">.</span><span class="hl-2">current</span><span class="hl-1">.</span><span class="hl-2">search</span><span class="hl-1">.</span><span class="hl-2">q</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-0">if</span><span class="hl-1"> (</span><span class="hl-2">query</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">info</span><span class="hl-1"> = </span><span class="hl-3">`</span><span class="hl-5">${</span><span class="hl-2">$contact</span><span class="hl-9">.</span><span class="hl-2">firstName</span><span class="hl-5">}</span><span class="hl-3"> </span><span class="hl-5">${</span><span class="hl-2">$contact</span><span class="hl-9">.</span><span class="hl-2">lastName</span><span class="hl-5">}</span><span class="hl-3"> </span><span class="hl-5">${</span><span class="hl-2">$contact</span><span class="hl-9">.</span><span class="hl-2">email</span><span class="hl-5">}</span><span class="hl-3">`</span><span class="hl-1">;</span><br/><span class="hl-1"> </span><span class="hl-0">if</span><span class="hl-1"> (!</span><span class="hl-2">info</span><span class="hl-1">.</span><span class="hl-7">toLowerCase</span><span class="hl-1">().</span><span class="hl-7">includes</span><span class="hl-1">(</span><span class="hl-2">query</span><span class="hl-1">.</span><span class="hl-7">toLowerCase</span><span class="hl-1">())) </span><span class="hl-0">return</span><span class="hl-1">; </span><span class="hl-4">// Skip!</span><br/><span class="hl-1"> }</span><br/><span class="hl-1"> </span><span class="hl-0">return</span><span class="hl-1"> </span><span class="hl-2">$contact</span><span class="hl-1">;</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> </span><br/><span class="hl-1"> </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">onEach</span><span class="hl-1">(</span><span class="hl-2">$filtered</span><span class="hl-1">, </span><span class="hl-2">$contact</span><span class="hl-1"> </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'a'</span><span class="hl-1">, </span><span class="hl-2">cardStyle</span><span class="hl-1">, </span><span class="hl-3">'create='</span><span class="hl-1">, </span><span class="hl-2">grow</span><span class="hl-1">, </span><span class="hl-3">'destroy='</span><span class="hl-1">, </span><span class="hl-2">shrink</span><span class="hl-1">, </span><span class="hl-3">`href=/contacts/</span><span class="hl-5">${</span><span class="hl-2">$contact</span><span class="hl-9">.</span><span class="hl-2">id</span><span class="hl-5">}</span><span class="hl-3">`</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'h2'</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'span font-weight:normal text='</span><span class="hl-1">, </span><span class="hl-2">$contact</span><span class="hl-1">.</span><span class="hl-2">firstName</span><span class="hl-1">+</span><span class="hl-3">" "</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'span text='</span><span class="hl-1">, </span><span class="hl-2">$contact</span><span class="hl-1">.</span><span class="hl-2">lastName</span><span class="hl-1">);</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div text='</span><span class="hl-1">, </span><span class="hl-2">$contact</span><span class="hl-1">.</span><span class="hl-2">email</span><span class="hl-1">);</span><br/><span class="hl-1"> });</span><br/><span class="hl-1"> }, </span><span class="hl-2">$contact</span><span class="hl-1"> </span><span class="hl-5">=></span><span class="hl-1"> </span><span class="hl-2">$contact</span><span class="hl-1">[</span><span class="hl-2">sortBy</span><span class="hl-1">].</span><span class="hl-7">toLowerCase</span><span class="hl-1">());</span><br/><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">`a role=button mt:$3 text="Add new contact" href=/contacts/</span><span class="hl-5">${</span><span class="hl-2">$contacts</span><span class="hl-9">.</span><span class="hl-2">length</span><span class="hl-5">}</span><span class="hl-3">`</span><span class="hl-1">);</span><br/><span class="hl-1"> });</span><br/><span class="hl-1">}</span><br/><br/><span class="hl-4">// Detail form styles</span><br/><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">detailStyle</span><span class="hl-1"> = </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">insertCss</span><span class="hl-1">({</span><br/><span class="hl-1"> </span><span class="hl-3">"&"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"bg:$cardBg border: 1px solid $border; r:8px p:$4 max-width:600px"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-3">"label"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"display:block font-weight:600 mt:$3 mb:$2"</span><span class="hl-1">,</span><br/><span class="hl-1"> </span><span class="hl-3">"input"</span><span class="hl-2">:</span><span class="hl-1"> </span><span class="hl-3">"w:100% p:$2 r:4px border: 1px solid $border; bg:$bg fg:$fg"</span><br/><span class="hl-1">});</span><br/><br/><span class="hl-5">function</span><span class="hl-1"> </span><span class="hl-7">drawContactDetail</span><span class="hl-1">(</span><span class="hl-2">id</span><span class="hl-1">: </span><span class="hl-10">number</span><span class="hl-1">) {</span><br/><span class="hl-1"> </span><span class="hl-2">$contacts</span><span class="hl-1">[</span><span class="hl-2">id</span><span class="hl-1">] ||= </span><span class="hl-5">new</span><span class="hl-1"> </span><span class="hl-7">Contact</span><span class="hl-1">(</span><span class="hl-2">id</span><span class="hl-1">, </span><span class="hl-3">''</span><span class="hl-1">, </span><span class="hl-3">''</span><span class="hl-1">, </span><span class="hl-3">''</span><span class="hl-1">, </span><span class="hl-3">''</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><span class="hl-5">const</span><span class="hl-1"> </span><span class="hl-6">$contact</span><span class="hl-1"> = </span><span class="hl-2">$contacts</span><span class="hl-1">[</span><span class="hl-2">id</span><span class="hl-1">];</span><br/><span class="hl-1"> </span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'a role=button href=/contacts #← Back'</span><span class="hl-1">);</span><br/><span class="hl-1"> </span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'div mt:$3'</span><span class="hl-1">, </span><span class="hl-2">detailStyle</span><span class="hl-1">, () </span><span class="hl-5">=></span><span class="hl-1"> {</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'h2 mb:$2 text='</span><span class="hl-1">, </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">ref</span><span class="hl-1">(</span><span class="hl-2">$contact</span><span class="hl-1">, </span><span class="hl-3">'firstName'</span><span class="hl-1">), </span><span class="hl-3">'text='</span><span class="hl-1">, </span><span class="hl-3">' '</span><span class="hl-1">, </span><span class="hl-3">'text='</span><span class="hl-1">, </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">ref</span><span class="hl-1">(</span><span class="hl-2">$contact</span><span class="hl-1">, </span><span class="hl-3">'lastName'</span><span class="hl-1">));</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'label text="First Name" input bind='</span><span class="hl-1">, </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">ref</span><span class="hl-1">(</span><span class="hl-2">$contact</span><span class="hl-1">, </span><span class="hl-3">'firstName'</span><span class="hl-1">));</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'label text="Last Name" input bind='</span><span class="hl-1">, </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">ref</span><span class="hl-1">(</span><span class="hl-2">$contact</span><span class="hl-1">, </span><span class="hl-3">'lastName'</span><span class="hl-1">));</span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'label text="Email" input type=email bind='</span><span class="hl-1">, </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">ref</span><span class="hl-1">(</span><span class="hl-2">$contact</span><span class="hl-1">, </span><span class="hl-3">'email'</span><span class="hl-1">)); </span><br/><span class="hl-1"> </span><span class="hl-7">A</span><span class="hl-1">(</span><span class="hl-3">'label text="Phone" input type=tel bind='</span><span class="hl-1">, </span><span class="hl-6">A</span><span class="hl-1">.</span><span class="hl-7">ref</span><span class="hl-1">(</span><span class="hl-2">$contact</span><span class="hl-1">, </span><span class="hl-3">'phone'</span><span class="hl-1">));</span><br/><span class="hl-1"> });</span><br/><span class="hl-1">}</span>
|
|
298
|
-
</code><button type="button">Copy</button></pre>
|
|
299
|
-
|
|
300
|
-
<h2 id="further-reading" class="tsd-anchor-link">Further reading<a href="#further-reading" aria-label="Permalink" class="tsd-anchor-icon"><svg viewBox="0 0 24 24" aria-hidden="true"><use href="../assets/icons.svg#icon-anchor"></use></svg></a></h2><p>If you've understood all/most of the above, you should be ready to get going with Aberdeen! You may also find these links helpful:</p>
|
|
301
|
-
<ul>
|
|
302
|
-
<li><a href="https://aberdeenjs.org/modules.html">Reference documentation</a></li>
|
|
303
|
-
<li><a href="https://aberdeenjs.org/#examples">Examples</a></li>
|
|
304
|
-
</ul>
|
|
305
|
-
</div></div><div class="col-sidebar"><div class="page-menu"><div class="tsd-navigation settings"><details class="tsd-accordion"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>Settings</h3></summary><div class="tsd-accordion-details"><div class="tsd-filter-visibility"><span class="settings-label">Member Visibility</span><ul id="tsd-filter-options"><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-protected" name="protected"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Protected</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-inherited" name="inherited" checked/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>Inherited</span></label></li><li class="tsd-filter-item"><label class="tsd-filter-input"><input type="checkbox" id="tsd-filter-external" name="external"/><svg width="32" height="32" viewBox="0 0 32 32" aria-hidden="true"><rect class="tsd-checkbox-background" width="30" height="30" x="1" y="1" rx="6" fill="none"></rect><path class="tsd-checkbox-checkmark" d="M8.35422 16.8214L13.2143 21.75L24.6458 10.25" stroke="none" stroke-width="3.5" stroke-linejoin="round" fill="none"></path></svg><span>External</span></label></li></ul></div><div class="tsd-theme-toggle"><label class="settings-label" for="tsd-theme">Theme</label><select id="tsd-theme"><option value="os">OS</option><option value="light">Light</option><option value="dark">Dark</option></select></div></div></details></div><details open class="tsd-accordion tsd-page-navigation"><summary class="tsd-accordion-summary"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" aria-hidden="true"><use href="../assets/icons.svg#icon-chevronDown"></use></svg><h3>On This Page</h3></summary><div class="tsd-accordion-details"><a href="#tutorial"><span>Tutorial</span></a><ul><li><a href="#creating-elements"><span>Creating elements</span></a></li><li><a href="#inline-styles"><span>Inline styles</span></a></li><li><ul><li><a href="#property-shortcuts"><span>Property shortcuts</span></a></li><li><a href="#css-variables"><span>CSS variables</span></a></li><li><a href="#spacing-variables"><span>Spacing variables</span></a></li></ul></li><li><a href="#nesting-content"><span>Nesting content</span></a></li><li><a href="#observable-objects"><span>Observable objects</span></a></li><li><a href="#conditional-rendering"><span>Conditional rendering</span></a></li><li><a href="#observable-primitive-values"><span>Observable primitive values</span></a></li><li><a href="#observable-arrays-and-sets"><span>Observable arrays and sets</span></a></li><li><a href="#typescript-and-classes"><span>Type<wbr/>Script and classes</span></a></li><li><a href="#efficient-list-rendering-with-aoneach"><span>Efficient list rendering with <wbr/>A.on<wbr/>Each</span></a></li><li><a href="#two-way-binding"><span>Two-<wbr/>way binding</span></a></li><li><a href="#css"><span>CSS</span></a></li><li><a href="#transitions"><span>Transitions</span></a></li><li><a href="#advanced-peeking-without-subscribing"><span>Advanced: <wbr/>Peeking without subscribing</span></a></li><li><a href="#derived-values"><span>Derived values</span></a></li><li><a href="#ui-components"><span>UI <wbr/>Components</span></a></li><li><a href="#debugging-with-adump"><span>Debugging with <wbr/>A.dump()</span></a></li><li><a href="#html-to-aberdeen"><span>html-<wbr/>to-<wbr/>aberdeen</span></a></li><li><a href="#routing"><span>Routing</span></a></li><li><a href="#prediction"><span>Prediction</span></a></li><li><a href="#full-example-multi-page-app"><span>Full <wbr/>Example: <wbr/>Multi-<wbr/>page <wbr/>App</span></a></li><li><a href="#further-reading"><span>Further reading</span></a></li></ul></div></details></div><div class="site-menu"><nav id="tsd-sidebar-links" class="tsd-navigation"><a href="https://aberdeenjs.org/" class="tsd-nav-link">What's this?</a><a href="https://aberdeenjs.org/Tutorial/" class="tsd-nav-link">Tutorial</a><a href="https://github.com/vanviegen/aberdeen" class="tsd-nav-link">GitHub</a></nav><nav class="tsd-navigation"><a href="../modules.html">Aberdeen - v1.18.2</a><ul class="tsd-small-nested-navigation" id="tsd-nav-container"><li>Loading...</li></ul></nav></div></div></div><footer></footer><div class="overlay"></div></body></html>
|