@pantoken/utils 0.5.0 → 1.0.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
@@ -47,12 +47,16 @@ const byName = resolveTokens(tokens, { mode: "dark" });
47
47
  - **`extractInstuiRefs(text)` / `tokenNames(ir)`** — the primitives the two checks build on,
48
48
  exposed for custom assertions.
49
49
  - **`colorUtilitiesCss(names, options?)`** — the semantic-colour utility emitter:
50
- `.<prefix>-bg-<name>` / `-fg-` / `-border-` from `--instui-color-<family>-<name>`, one per token.
50
+ `--bg-<name>` / `--text-<name>` / `--border-<name>` from `--instui-color-<family>-<name>`, one per
51
+ token. `--color-<name>` is emitted as an alias of `--text-<name>` (same declaration).
51
52
  - **`tokenUtilitiesCss(groups, options?)`** — the generic token→class emitter: one class per token,
52
53
  applied to its CSS property (the `--instui-` tail is the class name). Both emitters carry no
53
54
  InstUI-look opinion — the caller supplies the names. `@pantoken/components` feeds them a curated
54
- _semantic_ allowlist; `@pantoken/plugin-primitives` feeds the raw palette. `options.prefix` sets the
55
- class prefix; any falsy value drops it.
55
+ _semantic_ allowlist; `@pantoken/plugin-primitives` feeds the raw palette. Every class is a
56
+ double-dash global modifier built via `globalModifierSelector` — matches standalone or chained onto
57
+ any component, and wins the cascade deterministically over a same-named component modifier.
58
+ - **`globalModifierSelector(p, name)`** — the shared selector builder behind the two emitters above
59
+ (and every double-dash utility in `@pantoken/components`): `:where(*).--name.--name.--name`.
56
60
  - **`VAR_RE` / `LIGHT_DARK_RE`** — the two token regexes, built with `arkregex`'s `regex()` so
57
61
  their capture groups are typed on `.exec()` / `.matchAll()`. They're real `RegExp` instances.
58
62
  - **`Mode`, `ResolveOptions`, `Rgba`, `UtilityOptions`, `ColorUtilityNames`, `TokenUtilityGroup`** —
package/dist/index.d.mts CHANGED
@@ -325,14 +325,19 @@ interface UtilityOptions {
325
325
  * falsy value (`null`/`undefined`/`""`) drops the prefix entirely (`.bg-…`).
326
326
  */
327
327
  prefix?: string | null;
328
- /**
329
- * Component base-class names (e.g. `"button"`, `"view"`) to also emit a chained alias for, per
330
- * rule — `.<prefix>-bg-danger` (bare) plus `.<prefix>-button.-bg-danger` (chained), so the same
331
- * modifier works standalone or attached to any component. Omit for bare-only output (unchanged
332
- * behavior).
333
- */
334
- chainTargets?: readonly string[];
335
328
  }
329
+ /**
330
+ * Build a global-utility modifier selector: `:where(*).--name.--name.--name`. The modifier class
331
+ * repeated 3x gives the rule (0,3,0) specificity, which deterministically outranks any real 2-class
332
+ * component-modifier compound (`.instui-view.-mod`, 0,2,0) regardless of source order — the `:where(*)`
333
+ * wrapper contributes zero specificity of its own, so it's purely documentation that this is a global
334
+ * modifier, not a scoping condition. A plain class selector already matches standalone (`--mt-lg` with
335
+ * no other class) or chained onto any component, core or plugin-authored, with no per-component
336
+ * enumeration needed. Replaces the old bare-class-plus-enumerated-per-component-compound pattern
337
+ * (`globalSelectors`/`chainTargets`), which couldn't reach plugin-authored components and didn't scale
338
+ * to high-cardinality utilities like spacing.
339
+ */
340
+ declare function globalModifierSelector(p: string, name: string): string;
336
341
  /** One semantic colour family entry: a bare name (resolved against `--instui-color-<family>-<name>`)
337
342
  * or an explicit `[name, value]` pair — the second element is `var()`-wrapped if it's a `--custom-prop`
338
343
  * name, or used verbatim otherwise (a `light-dark(…)` expression, a raw keyword like `transparent`). */
@@ -346,9 +351,10 @@ interface ColorUtilityNames {
346
351
  /**
347
352
  * Build the semantic-colour utility stylesheet: `.<prefix>-bg-<name>` (background),
348
353
  * `.<prefix>-text-<name>` (text colour), `.<prefix>-border-<name>` (border colour), one per semantic
349
- * colour token. Overrides are therefore only ever token-valid — no primitives, no arbitrary hex. Pass
350
- * the token names per family (e.g. from `@pantoken/tokens`), or an explicit `[name, token]` pair to
351
- * source a name from a different token than the family's own scale.
354
+ * colour token. `.<prefix>-color-<name>` is emitted alongside `.<prefix>-text-<name>` as an alias — same
355
+ * declaration, either class name works. Overrides are therefore only ever token-valid — no primitives,
356
+ * no arbitrary hex. Pass the token names per family (e.g. from `@pantoken/tokens`), or an explicit
357
+ * `[name, token]` pair to source a name from a different token than the family's own scale.
352
358
  *
353
359
  * @param names - {@link ColorUtilityNames}.
354
360
  * @param options - {@link UtilityOptions}.
@@ -381,4 +387,4 @@ interface TokenUtilityGroup {
381
387
  */
382
388
  declare function tokenUtilitiesCss(groups: readonly TokenUtilityGroup[], options?: UtilityOptions): string;
383
389
  //#endregion
384
- export { type ColorUtilityEntry, type ColorUtilityNames, ELEVATION_NAMES, FOCUSABLE_SELECTOR, LIGHT_DARK_RE, type Mode, type ResolveOptions, type Rgba, SPACING_AUTO_STEP, SPACING_STEPS, type SpacingStep, type TokenUtilityGroup, type UtilityOptions, VAR_RE, camelCase, colorUtilitiesCss, danglingReferences, elevationDeclarations, extractInstuiRefs, focusOutlineDeclarations, focusOutlineRules, makeResolver, parseHexColor, resolveTokens, sanitizeSvg, tokenNames, tokenUtilitiesCss, unknownReferences };
390
+ export { type ColorUtilityEntry, type ColorUtilityNames, ELEVATION_NAMES, FOCUSABLE_SELECTOR, LIGHT_DARK_RE, type Mode, type ResolveOptions, type Rgba, SPACING_AUTO_STEP, SPACING_STEPS, type SpacingStep, type TokenUtilityGroup, type UtilityOptions, VAR_RE, camelCase, colorUtilitiesCss, danglingReferences, elevationDeclarations, extractInstuiRefs, focusOutlineDeclarations, focusOutlineRules, globalModifierSelector, makeResolver, parseHexColor, resolveTokens, sanitizeSvg, tokenNames, tokenUtilitiesCss, unknownReferences };
package/dist/index.mjs CHANGED
@@ -444,11 +444,27 @@ const SPACING_AUTO_STEP = {
444
444
  //#endregion
445
445
  //#region src/utility-css.ts
446
446
  /**
447
+ * Build a global-utility modifier selector: `:where(*).--name.--name.--name`. The modifier class
448
+ * repeated 3x gives the rule (0,3,0) specificity, which deterministically outranks any real 2-class
449
+ * component-modifier compound (`.instui-view.-mod`, 0,2,0) regardless of source order — the `:where(*)`
450
+ * wrapper contributes zero specificity of its own, so it's purely documentation that this is a global
451
+ * modifier, not a scoping condition. A plain class selector already matches standalone (`--mt-lg` with
452
+ * no other class) or chained onto any component, core or plugin-authored, with no per-component
453
+ * enumeration needed. Replaces the old bare-class-plus-enumerated-per-component-compound pattern
454
+ * (`globalSelectors`/`chainTargets`), which couldn't reach plugin-authored components and didn't scale
455
+ * to high-cardinality utilities like spacing.
456
+ */
457
+ function globalModifierSelector(p, name) {
458
+ const cls = `.--${name}`;
459
+ return `:where(*)${cls}${cls}${cls}`;
460
+ }
461
+ /**
447
462
  * Build the semantic-colour utility stylesheet: `.<prefix>-bg-<name>` (background),
448
463
  * `.<prefix>-text-<name>` (text colour), `.<prefix>-border-<name>` (border colour), one per semantic
449
- * colour token. Overrides are therefore only ever token-valid — no primitives, no arbitrary hex. Pass
450
- * the token names per family (e.g. from `@pantoken/tokens`), or an explicit `[name, token]` pair to
451
- * source a name from a different token than the family's own scale.
464
+ * colour token. `.<prefix>-color-<name>` is emitted alongside `.<prefix>-text-<name>` as an alias — same
465
+ * declaration, either class name works. Overrides are therefore only ever token-valid — no primitives,
466
+ * no arbitrary hex. Pass the token names per family (e.g. from `@pantoken/tokens`), or an explicit
467
+ * `[name, token]` pair to source a name from a different token than the family's own scale.
452
468
  *
453
469
  * @param names - {@link ColorUtilityNames}.
454
470
  * @param options - {@link UtilityOptions}.
@@ -459,17 +475,15 @@ const SPACING_AUTO_STEP = {
459
475
  function colorUtilitiesCss(names, options = {}) {
460
476
  const prefix = options.prefix || "";
461
477
  const p = prefix ? `${prefix}-` : "";
462
- const chainTargets = options.chainTargets ?? [];
463
478
  const emit = (family, util, prop, list) => list.map((entry) => {
464
479
  const isPair = (e) => typeof e !== "string";
465
480
  const [n, token] = isPair(entry) ? entry : [entry, `--instui-color-${family}-${entry}`];
466
481
  const value = token.startsWith("--") ? `var(${token})` : token;
467
- const modifier = `.-${util}-${n}`;
468
- return `${[`.${p}${util}-${n}`, ...chainTargets.map((target) => `.${p}${target}${modifier}`)].join(", ")} { ${prop}: ${value}; }`;
482
+ return `${(typeof util === "string" ? [util] : util).map((word) => globalModifierSelector(p, `${word}-${n}`)).join(", ")} { ${prop}: ${value}; }`;
469
483
  }).join("\n");
470
484
  return `/* InstUI semantic colour utilities (@pantoken/utils) — prefix: ${prefix} */\n${[
471
485
  emit("background", "bg", "background", names.background),
472
- emit("text", "text", "color", names.text),
486
+ emit("text", ["text", "color"], "color", names.text),
473
487
  emit("stroke", "border", "border-color", names.stroke)
474
488
  ].join("\n")}\n`;
475
489
  }
@@ -491,12 +505,10 @@ function colorUtilitiesCss(names, options = {}) {
491
505
  function tokenUtilitiesCss(groups, options = {}) {
492
506
  const prefix = options.prefix || "";
493
507
  const p = prefix ? `${prefix}-` : "";
494
- const chainTargets = options.chainTargets ?? [];
495
508
  return `/* InstUI token utilities (@pantoken/utils) — prefix: ${prefix} */\n${groups.flatMap(({ property, tokens }) => tokens.map((token) => {
496
509
  const name = token.replace(/^--instui-/, "");
497
- const modifier = `.-${name}`;
498
- return `${[`.${p}${name}`, ...chainTargets.map((target) => `.${p}${target}${modifier}`)].join(", ")} { ${property}: var(${token}); }`;
510
+ return `${globalModifierSelector(p, name)} { ${property}: var(${token}); }`;
499
511
  })).join("\n")}\n`;
500
512
  }
501
513
  //#endregion
502
- export { ELEVATION_NAMES, FOCUSABLE_SELECTOR, LIGHT_DARK_RE, SPACING_AUTO_STEP, SPACING_STEPS, VAR_RE, camelCase, colorUtilitiesCss, danglingReferences, elevationDeclarations, extractInstuiRefs, focusOutlineDeclarations, focusOutlineRules, makeResolver, parseHexColor, resolveTokens, sanitizeSvg, tokenNames, tokenUtilitiesCss, unknownReferences };
514
+ export { ELEVATION_NAMES, FOCUSABLE_SELECTOR, LIGHT_DARK_RE, SPACING_AUTO_STEP, SPACING_STEPS, VAR_RE, camelCase, colorUtilitiesCss, danglingReferences, elevationDeclarations, extractInstuiRefs, focusOutlineDeclarations, focusOutlineRules, globalModifierSelector, makeResolver, parseHexColor, resolveTokens, sanitizeSvg, tokenNames, tokenUtilitiesCss, unknownReferences };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pantoken/utils",
3
- "version": "0.5.0",
3
+ "version": "1.0.0",
4
4
  "description": "Shared pantoken helpers: token reference resolver, typed regexes (arkregex), name-case, and hex-colour parsing.",
5
5
  "homepage": "https://pantoken.iywahl.com",
6
6
  "bugs": "https://github.com/thedannywahl/pantoken/issues",