aberdeen 1.3.2 → 1.4.1

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/src/aberdeen.ts CHANGED
@@ -285,6 +285,8 @@ class ChainedScope extends ContentScope {
285
285
  // If `currentScope` is not actually a ChainedScope, prevSibling will be undefined, as intended
286
286
  this.prevSibling = currentScope.getChildPrevSibling();
287
287
  currentScope.lastChild = this;
288
+ } else {
289
+ this.prevSibling = el.lastChild || undefined;
288
290
  }
289
291
 
290
292
  // We're always adding ourselve as a cleaner, in order to run our own cleaners
@@ -1701,6 +1703,26 @@ export const NO_COPY = Symbol("NO_COPY");
1701
1703
  // Promises break when proxied, so we'll just mark them as NO_COPY
1702
1704
  (Promise.prototype as any)[NO_COPY] = true;
1703
1705
 
1706
+ /**
1707
+ * CSS variable lookup table for the `@` value prefix.
1708
+ *
1709
+ * When a CSS value starts with `@`, the rest is used as a key to look up the actual value.
1710
+ * Pre-initialized with keys '1'-'12' mapping to an exponential rem scale (e.g., @1=0.25rem, @3=1rem).
1711
+ *
1712
+ * @example
1713
+ * ```typescript
1714
+ * cssVars.primary = '#3b82f6';
1715
+ * cssVars[3] = '16px'; // Override @3 to be 16px instead of 1rem
1716
+ * $('p color:@primary'); // Sets color to #3b82f6
1717
+ * $('div mt:@3'); // Sets margin-top to 16px
1718
+ * ```
1719
+ */
1720
+ export const cssVars: Record<string, string> = optProxy({});
1721
+
1722
+ for (let i = 1; i <= 12; i++) {
1723
+ cssVars[i] = 2 ** (i - 3) + "rem";
1724
+ }
1725
+
1704
1726
  /**
1705
1727
  * Clone an (optionally proxied) object or array.
1706
1728
  *
@@ -2062,7 +2084,7 @@ function findFirst(str: string, chars: string, startPos: number): number {
2062
2084
  let cssCount = 0;
2063
2085
 
2064
2086
  /**
2065
- * Inserts CSS rules into the document, optionally scoping them with a unique class name.
2087
+ * Inserts CSS rules into the document, scoping them with a unique class name.
2066
2088
  *
2067
2089
  * Takes a JavaScript object representation of CSS rules. camelCased property keys are
2068
2090
  * converted to kebab-case (e.g., `fontSize` becomes `font-size`).
@@ -2073,11 +2095,9 @@ let cssCount = 0;
2073
2095
  * - In case a selector contains a `&`, that character will be replaced by the parent selector.
2074
2096
  * - Selectors will be split on `,` characters, each combining with the parent selector with *or* semantics.
2075
2097
  * - Selector starting with `'@'` define at-rules like media queries. They may be nested within regular selectors.
2076
- * @param global - If `true`, styles are inserted globally without prefixing.
2077
- * If `false` (default), all selectors are prefixed with a unique generated
2078
- * class name (e.g., `.AbdStl1`) to scope the styles.
2079
- * @returns The unique class name prefix used for scoping (e.g., `.AbdStl1`), or an empty string
2080
- * if `global` was `true`. Use this prefix with {@link $} to apply the styles.
2098
+ * @param global - @deprecated Use {@link insertGlobalCss} instead.
2099
+ * @returns The unique class name prefix used for scoping (e.g., `.AbdStl1`). Use this
2100
+ * prefix with {@link $} to apply the styles.
2081
2101
  *
2082
2102
  * @example Scoped Styles
2083
2103
  * ```typescript
@@ -2102,28 +2122,60 @@ let cssCount = 0;
2102
2122
  * $('div.child-element#Child'); // .AbdStl1 .child-element rule applies
2103
2123
  * });
2104
2124
  * ```
2105
- *
2125
+ */
2126
+ export function insertCss(style: object, global = false): string {
2127
+ const prefix = global ? "" : `.AbdStl${++cssCount}`;
2128
+ const css = styleToCss(style, prefix);
2129
+ if (css) $(`style#${css}`);
2130
+ return prefix;
2131
+ }
2132
+
2133
+ /**
2134
+ * Inserts CSS rules globally.
2135
+ *
2136
+ * Works exactly like {@link insertCss}, but without prefixing selectors with a unique class name.
2137
+ *
2106
2138
  * @example Global Styles
2107
2139
  * ```typescript
2108
- * insertCss({
2140
+ * insertGlobalCss({
2109
2141
  * '*': {
2110
2142
  * fontFamily: 'monospace',
2143
+ * m: 0, // Using shortcut for margin
2111
2144
  * },
2112
2145
  * 'a': {
2113
2146
  * textDecoration: 'none',
2114
- * color: "#107ab0",
2147
+ * fg: "@primary", // Using foreground shortcut and CSS variable
2115
2148
  * }
2116
- * }, true); // Pass true for global
2149
+ * });
2117
2150
  *
2118
2151
  * $('a#Styled link');
2119
2152
  * ```
2120
2153
  */
2121
- export function insertCss(style: object, global = false): string {
2122
- const prefix = global ? "" : `.AbdStl${++cssCount}`;
2123
- const css = styleToCss(style, prefix);
2124
- if (css) $(`style#${css}`);
2125
- return prefix;
2126
- }
2154
+ export function insertGlobalCss(style: object): string {
2155
+ return insertCss(style, true);
2156
+ }
2157
+
2158
+ const CSS_SHORT: Record<string, string | string[]> = {
2159
+ m: "margin",
2160
+ mt: "marginTop",
2161
+ mb: "marginBottom",
2162
+ ml: "marginLeft",
2163
+ mr: "marginRight",
2164
+ mh: ["marginLeft", "marginRight"],
2165
+ mv: ["marginTop", "marginBottom"],
2166
+ p: "padding",
2167
+ pt: "paddingTop",
2168
+ pb: "paddingBottom",
2169
+ pl: "paddingLeft",
2170
+ pr: "paddingRight",
2171
+ ph: ["paddingLeft", "paddingRight"],
2172
+ pv: ["paddingTop", "paddingBottom"],
2173
+ w: "width",
2174
+ h: "height",
2175
+ bg: "background",
2176
+ fg: "color",
2177
+ r: "borderRadius",
2178
+ };
2127
2179
 
2128
2180
  function styleToCss(style: object, prefix: string): string {
2129
2181
  let props = "";
@@ -2142,7 +2194,11 @@ function styleToCss(style: object, prefix: string): string {
2142
2194
  );
2143
2195
  }
2144
2196
  } else {
2145
- props += `${k.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}:${v};`;
2197
+ const val = v == null || v === false ? "" : typeof v === 'string' ? (v[0] === '@' ? (cssVars as any)[v.substring(1)] || "" : v) : String(v);
2198
+ const expanded = CSS_SHORT[k] || k;
2199
+ for (const prop of (Array.isArray(expanded) ? expanded : [expanded])) {
2200
+ props += `${prop.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`)}:${val};`;
2201
+ }
2146
2202
  }
2147
2203
  }
2148
2204
  }
@@ -2165,10 +2221,15 @@ function applyArg(el: Element, key: string, value: any) {
2165
2221
  if (value) el.classList.add(...classes);
2166
2222
  else el.classList.remove(...classes);
2167
2223
  } else if (key[0] === "$") {
2168
- // Style
2169
- const name = key.substring(1);
2170
- if (value == null || value === false) (el as any).style[name] = "";
2171
- else (el as any).style[name] = `${value}`;
2224
+ // Style (with shortcuts)
2225
+ key = key.substring(1);
2226
+ const val = value == null || value === false ? "" : typeof value === 'string' ? (value[0] === '@' ? (cssVars as any)[value.substring(1)] || "" : value) : String(value);
2227
+ const expanded = CSS_SHORT[key] || key;
2228
+ if (typeof expanded === "string") {
2229
+ (el as any).style[expanded] = val;
2230
+ } else {
2231
+ for (const prop of expanded) (el as any).style[prop] = val;
2232
+ }
2172
2233
  } else if (value == null) {
2173
2234
  // Value left empty
2174
2235
  // Do nothing