aberdeen 1.3.1 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -162,7 +162,7 @@ Some further examples:
162
162
  - [Input demo](https://aberdeenjs.org/examples/input/) - [Source](https://github.com/vanviegen/aberdeen/tree/master/examples/input)
163
163
  - [Tic Tac Toe demo](https://aberdeenjs.org/examples/tictactoe/) - [Source](https://github.com/vanviegen/aberdeen/tree/master/examples/tictactoe)
164
164
  - [List demo](https://aberdeenjs.org/examples/list/) - [Source](https://github.com/vanviegen/aberdeen/tree/master/examples/list)
165
- - [Routing demo](https://aberdeenjs.org/examples/router/) - [Source](https://github.com/vanviegen/aberdeen/tree/master/examples/router)
165
+ - [Routing demo](https://aberdeenjs.org/examples/route/) - [Source](https://github.com/vanviegen/aberdeen/tree/master/examples/route)
166
166
  - [JS Framework Benchmark demo](https://aberdeenjs.org/examples/js-framework-benchmark/) - [Source](https://github.com/vanviegen/aberdeen/tree/master/examples/js-framework-benchmark)
167
167
 
168
168
  ## Learning Aberdeen
@@ -174,6 +174,26 @@ And you may want to study the examples above, of course!
174
174
 
175
175
  ## Changelog
176
176
 
177
+ ### 1.4.0 (2025-01-07)
178
+
179
+ **Enhancements:**
180
+ - Shortcuts for common CSS properties. For instance: `$('div mv:10px')` for setting vertical (top and bottom) margins.
181
+ - Variables you can set and use in CSS styles, e.g. `$('div bg:@myColor')` after setting `cssVars.myColor = 'red'`.
182
+ - Default CSS variables are defined for spacing: `@2` is `0.5rem`, `@3` is `1rem`, etc. For example: `$('r:@3')` sets border radius to (a dynamically configurable) `1rem`.
183
+ - All CSS shortcuts and `@` variables are also supported in `insertCss` and `insertGlobalCss`.
184
+ - Added `insertGlobalCss` for adding global styles. The `global` argument to `insertCss` is now deprecated.
185
+
186
+ **Fixes:**
187
+ - When doing `$('div #first', () => $('#second'))`, *second* now comes after *first*. It used to be the other way around.
188
+
189
+ ### 1.3.2 (2025-01-07)
190
+
191
+ **Enhancements:**
192
+ - It's now okay to first define a SELECT binding and then add its OPTIONs right after, while still allowing the binding to set the initial value. This used to throw an async error.
193
+
194
+ **Fixes:**
195
+ - Turns out some examples were still using old text content syntax.
196
+
177
197
  ### 1.3.1 (2025-01-07)
178
198
  **Fixes:**
179
199
  - Argument types accepted by `$` were too restrictive, as something like `$('prop=', myVal)` should be able to accept any type for `myVal`.
@@ -251,6 +251,21 @@ export declare function merge<T extends object>(dst: T, dstKey: keyof T, value:
251
251
  * be observed for changes.
252
252
  */
253
253
  export declare const NO_COPY: unique symbol;
254
+ /**
255
+ * CSS variable lookup table for the `@` value prefix.
256
+ *
257
+ * When a CSS value starts with `@`, the rest is used as a key to look up the actual value.
258
+ * Pre-initialized with keys '1'-'12' mapping to an exponential rem scale (e.g., @1=0.25rem, @3=1rem).
259
+ *
260
+ * @example
261
+ * ```typescript
262
+ * cssVars.primary = '#3b82f6';
263
+ * cssVars[3] = '16px'; // Override @3 to be 16px instead of 1rem
264
+ * $('p color:@primary'); // Sets color to #3b82f6
265
+ * $('div mt:@3'); // Sets margin-top to 16px
266
+ * ```
267
+ */
268
+ export declare const cssVars: Record<string, string>;
254
269
  /**
255
270
  * Clone an (optionally proxied) object or array.
256
271
  *
@@ -392,7 +407,7 @@ export declare function ref<T extends TargetType, K extends keyof T>(target: T,
392
407
  */
393
408
  export declare function $(...args: any[]): undefined | Element;
394
409
  /**
395
- * Inserts CSS rules into the document, optionally scoping them with a unique class name.
410
+ * Inserts CSS rules into the document, scoping them with a unique class name.
396
411
  *
397
412
  * Takes a JavaScript object representation of CSS rules. camelCased property keys are
398
413
  * converted to kebab-case (e.g., `fontSize` becomes `font-size`).
@@ -403,11 +418,9 @@ export declare function $(...args: any[]): undefined | Element;
403
418
  * - In case a selector contains a `&`, that character will be replaced by the parent selector.
404
419
  * - Selectors will be split on `,` characters, each combining with the parent selector with *or* semantics.
405
420
  * - Selector starting with `'@'` define at-rules like media queries. They may be nested within regular selectors.
406
- * @param global - If `true`, styles are inserted globally without prefixing.
407
- * If `false` (default), all selectors are prefixed with a unique generated
408
- * class name (e.g., `.AbdStl1`) to scope the styles.
409
- * @returns The unique class name prefix used for scoping (e.g., `.AbdStl1`), or an empty string
410
- * if `global` was `true`. Use this prefix with {@link $} to apply the styles.
421
+ * @param global - @deprecated Use {@link insertGlobalCss} instead.
422
+ * @returns The unique class name prefix used for scoping (e.g., `.AbdStl1`). Use this
423
+ * prefix with {@link $} to apply the styles.
411
424
  *
412
425
  * @example Scoped Styles
413
426
  * ```typescript
@@ -432,23 +445,30 @@ export declare function $(...args: any[]): undefined | Element;
432
445
  * $('div.child-element#Child'); // .AbdStl1 .child-element rule applies
433
446
  * });
434
447
  * ```
448
+ */
449
+ export declare function insertCss(style: object, global?: boolean): string;
450
+ /**
451
+ * Inserts CSS rules globally.
452
+ *
453
+ * Works exactly like {@link insertCss}, but without prefixing selectors with a unique class name.
435
454
  *
436
455
  * @example Global Styles
437
456
  * ```typescript
438
- * insertCss({
457
+ * insertGlobalCss({
439
458
  * '*': {
440
459
  * fontFamily: 'monospace',
460
+ * m: 0, // Using shortcut for margin
441
461
  * },
442
462
  * 'a': {
443
463
  * textDecoration: 'none',
444
- * color: "#107ab0",
464
+ * fg: "@primary", // Using foreground shortcut and CSS variable
445
465
  * }
446
- * }, true); // Pass true for global
466
+ * });
447
467
  *
448
468
  * $('a#Styled link');
449
469
  * ```
450
470
  */
451
- export declare function insertCss(style: object, global?: boolean): string;
471
+ export declare function insertGlobalCss(style: object): string;
452
472
  /**
453
473
  * Sets a custom error handler function for errors that occur asynchronously
454
474
  * within reactive scopes (e.g., during updates triggered by proxy changes in
package/dist/aberdeen.js CHANGED
@@ -165,6 +165,15 @@ class Scope {
165
165
  }
166
166
  }
167
167
 
168
+ class DelayedOneTimeRunner {
169
+ queueRun;
170
+ prio = --lastPrio;
171
+ constructor(queueRun) {
172
+ this.queueRun = queueRun;
173
+ queue(this);
174
+ }
175
+ }
176
+
168
177
  class ContentScope extends Scope {
169
178
  cleaners;
170
179
  constructor(cleaners = []) {
@@ -215,6 +224,8 @@ class ChainedScope extends ContentScope {
215
224
  if (el === currentScope.el) {
216
225
  this.prevSibling = currentScope.getChildPrevSibling();
217
226
  currentScope.lastChild = this;
227
+ } else {
228
+ this.prevSibling = el.lastChild || undefined;
218
229
  }
219
230
  if (!useParentCleaners)
220
231
  currentScope.cleaners.push(this);
@@ -1052,6 +1063,10 @@ var COPY_SUBSCRIBE = 32;
1052
1063
  var COPY_EMIT = 64;
1053
1064
  var NO_COPY = Symbol("NO_COPY");
1054
1065
  Promise.prototype[NO_COPY] = true;
1066
+ var cssVars = optProxy({});
1067
+ for (let i = 1;i <= 12; i++) {
1068
+ cssVars[i] = 2 ** (i - 3) + "rem";
1069
+ }
1055
1070
  function clone(src) {
1056
1071
  if (NO_COPY in src)
1057
1072
  return src;
@@ -1111,8 +1126,9 @@ function applyBind(el, target) {
1111
1126
  onInputChange();
1112
1127
  onProxyChange = () => {
1113
1128
  el.value = target.value;
1114
- if (el.tagName === "SELECT" && el.value != target.value)
1115
- throw new Error(`SELECT has no '${target.value}' OPTION (yet)`);
1129
+ if (el.tagName === "SELECT" && el.value != target.value) {
1130
+ new DelayedOneTimeRunner(() => el.value = target.value);
1131
+ }
1116
1132
  };
1117
1133
  }
1118
1134
  derive(onProxyChange);
@@ -1250,6 +1266,30 @@ function insertCss(style, global = false) {
1250
1266
  $(`style#${css}`);
1251
1267
  return prefix;
1252
1268
  }
1269
+ function insertGlobalCss(style) {
1270
+ return insertCss(style, true);
1271
+ }
1272
+ var CSS_SHORT = {
1273
+ m: "margin",
1274
+ mt: "marginTop",
1275
+ mb: "marginBottom",
1276
+ ml: "marginLeft",
1277
+ mr: "marginRight",
1278
+ mh: ["marginLeft", "marginRight"],
1279
+ mv: ["marginTop", "marginBottom"],
1280
+ p: "padding",
1281
+ pt: "paddingTop",
1282
+ pb: "paddingBottom",
1283
+ pl: "paddingLeft",
1284
+ pr: "paddingRight",
1285
+ ph: ["paddingLeft", "paddingRight"],
1286
+ pv: ["paddingTop", "paddingBottom"],
1287
+ w: "width",
1288
+ h: "height",
1289
+ bg: "background",
1290
+ fg: "color",
1291
+ r: "borderRadius"
1292
+ };
1253
1293
  function styleToCss(style, prefix) {
1254
1294
  let props = "";
1255
1295
  let rules = "";
@@ -1265,7 +1305,11 @@ ${styleToCss(v, prefix)}}
1265
1305
  rules += styleToCss(v, k.includes("&") ? k.replace(/&/g, prefix) : `${prefix} ${k}`);
1266
1306
  }
1267
1307
  } else {
1268
- props += `${k.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}:${v};`;
1308
+ const val = v == null || v === false ? "" : typeof v === "string" ? v[0] === "@" ? cssVars[v.substring(1)] || "" : v : String(v);
1309
+ const expanded = CSS_SHORT[k] || k;
1310
+ for (const prop of Array.isArray(expanded) ? expanded : [expanded]) {
1311
+ props += `${prop.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}:${val};`;
1312
+ }
1269
1313
  }
1270
1314
  }
1271
1315
  }
@@ -1288,11 +1332,15 @@ function applyArg(el, key, value) {
1288
1332
  else
1289
1333
  el.classList.remove(...classes);
1290
1334
  } else if (key[0] === "$") {
1291
- const name = key.substring(1);
1292
- if (value == null || value === false)
1293
- el.style[name] = "";
1294
- else
1295
- el.style[name] = `${value}`;
1335
+ key = key.substring(1);
1336
+ const val = value == null || value === false ? "" : typeof value === "string" ? value[0] === "@" ? cssVars[value.substring(1)] || "" : value : String(value);
1337
+ const expanded = CSS_SHORT[key] || key;
1338
+ if (typeof expanded === "string") {
1339
+ el.style[expanded] = val;
1340
+ } else {
1341
+ for (const prop of expanded)
1342
+ el.style[prop] = val;
1343
+ }
1296
1344
  } else if (value == null) {} else if (key in SPECIAL_PROPS) {
1297
1345
  SPECIAL_PROPS[key](el, value);
1298
1346
  } else if (typeof value === "function") {
@@ -1472,11 +1520,13 @@ export {
1472
1520
  leakScope,
1473
1521
  isEmpty,
1474
1522
  invertString,
1523
+ insertGlobalCss,
1475
1524
  insertCss,
1476
1525
  getParentElement,
1477
1526
  dump,
1478
1527
  derive,
1479
1528
  defaultEmitHandler,
1529
+ cssVars,
1480
1530
  count,
1481
1531
  copy,
1482
1532
  clone,
@@ -1485,5 +1535,5 @@ export {
1485
1535
  $
1486
1536
  };
1487
1537
 
1488
- //# debugId=C3082837141CF76064756E2164756E21
1538
+ //# debugId=BD37C20F6280CE8164756E2164756E21
1489
1539
  //# sourceMappingURL=aberdeen.js.map