rainbowindex 0.4.0 → 0.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.
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  compileScannedProject
3
- } from "./chunk-4SVFFDS2.mjs";
3
+ } from "./chunk-53WD6U2X.mjs";
4
4
  import {
5
5
  APPLY_ALIASES,
6
6
  DIRECTIVE_NAMES_SET,
@@ -20,7 +20,7 @@ import {
20
20
  resolveUtilityDeclarations,
21
21
  resolveVariant,
22
22
  splitSelectorList
23
- } from "./chunk-6DAHUFNU.mjs";
23
+ } from "./chunk-6GTG5SZJ.mjs";
24
24
 
25
25
  // src/integrations/postcss/index.ts
26
26
  import postcss2 from "postcss";
@@ -102,6 +102,7 @@ function processApply(root, theme, warnings) {
102
102
  }
103
103
  const customVariantMap = new Map(theme.customVariants.map((cv) => [cv.name, cv]));
104
104
  const checkedApplyRoots = /* @__PURE__ */ new Set();
105
+ const resolveCache = /* @__PURE__ */ new Map();
105
106
  for (let depth = 0; depth < MAX_APPLY_DEPTH; depth++) {
106
107
  const applyNodes = [];
107
108
  const classListByNode = /* @__PURE__ */ new Map();
@@ -127,7 +128,8 @@ function processApply(root, theme, warnings) {
127
128
  warnings,
128
129
  customVariantMap,
129
130
  groupRoots,
130
- checkedApplyRoots
131
+ checkedApplyRoots,
132
+ resolveCache
131
133
  );
132
134
  }
133
135
  }
@@ -144,7 +146,7 @@ function processApply(root, theme, warnings) {
144
146
  }
145
147
  }
146
148
  }
147
- function expandApply(atRule, classNames, theme, warnings, customVariantMap, groupRoots, checkedApplyRoots) {
149
+ function expandApply(atRule, classNames, theme, warnings, customVariantMap, groupRoots, checkedApplyRoots, resolveCache) {
148
150
  const parentRule = atRule.parent;
149
151
  if (parentRule?.type !== "rule") {
150
152
  warnings.push("[RI-1006] @apply must be used inside a CSS rule, not at the top level.");
@@ -166,8 +168,23 @@ function expandApply(atRule, classNames, theme, warnings, customVariantMap, grou
166
168
  }
167
169
  const resolved = [];
168
170
  for (const className of classNames) {
169
- const r = resolveClassName(className, theme, warnings, customVariantMap, checkedApplyRoots);
170
- if (r) resolved.push(r);
171
+ let entry = resolveCache.get(className);
172
+ if (!entry) {
173
+ const entryWarnings = [];
174
+ entry = {
175
+ result: resolveClassName(
176
+ className,
177
+ theme,
178
+ entryWarnings,
179
+ customVariantMap,
180
+ checkedApplyRoots
181
+ ),
182
+ warnings: entryWarnings
183
+ };
184
+ resolveCache.set(className, entry);
185
+ }
186
+ warnings.push(...entry.warnings);
187
+ if (entry.result) resolved.push(entry.result);
171
188
  }
172
189
  const baseGroups = [];
173
190
  const baseNestedBlocks = [];
@@ -556,16 +573,16 @@ var rainbowindex = (options = {}) => {
556
573
  const compilationWarnings = compiled.warnings;
557
574
  const from = root.source?.input?.file ?? root.source?.input?.id ?? root.source?.input?.from ?? "<rainbowindex>";
558
575
  stripRIDirectiveNodes(root);
559
- if (compiled.sections.length > 0) {
560
- const generatedRoot = postcss2.parse(compiled.sections.join("\n\n"), { from });
561
- root.prepend(generatedRoot.nodes);
562
- }
563
576
  const slotWarnings = [];
564
577
  warnStandaloneSlots(root, slotWarnings);
565
578
  pushWarningsDeduped(compilationWarnings, slotWarnings, warningSeen);
566
579
  const applyWarnings = [];
567
580
  processApply(root, compiled.theme, applyWarnings);
568
581
  pushWarningsDeduped(compilationWarnings, applyWarnings, warningSeen);
582
+ if (compiled.sections.length > 0) {
583
+ const generatedRoot = postcss2.parse(compiled.sections.join("\n\n"), { from });
584
+ root.prepend(generatedRoot.nodes);
585
+ }
569
586
  const cssFnWarnings = [];
570
587
  processCSSFunctions(root, compiled.theme, cssFnWarnings);
571
588
  pushWarningsDeduped(compilationWarnings, cssFnWarnings, warningSeen);
@@ -2101,6 +2101,7 @@ var FONT_FAMILY_PROPS = Object.freeze([
2101
2101
  "font-variation-settings"
2102
2102
  ]);
2103
2103
  var MASK_RADIAL_SIZE_PROPS = Object.freeze(["--ri-mask-radial-size"]);
2104
+ var STROKE_WIDTH_PROPS = Object.freeze(["stroke-width"]);
2104
2105
  var BG_IMAGE_PROPS = Object.freeze(["background-image"]);
2105
2106
  var BORDER_COLOR_PROPS = Object.freeze(["border-color"]);
2106
2107
  var OUTLINE_COLOR_PROPS = Object.freeze(["outline-color"]);
@@ -2108,6 +2109,7 @@ var OUTLINE_STYLE_PROPS = Object.freeze(["outline-style"]);
2108
2109
  var DECORATION_COLOR_PROPS = Object.freeze(["text-decoration-color"]);
2109
2110
  var RE_SIGNED_INT = /^-?\d+$/;
2110
2111
  var RE_UNSIGNED_INT = /^\d+$/;
2112
+ var RE_DECIMAL = /^\d+(?:[._]\d+)?$/;
2111
2113
  function colorOrDefault(prefix, colorProps) {
2112
2114
  const defaultProps = PREFIX_PROPS[prefix];
2113
2115
  return (value, _textSizes2, _fontFamilies2, colorNames) => isColorValue(value, void 0, colorNames) ? colorProps : defaultProps;
@@ -2134,6 +2136,14 @@ var DUAL_MODE_PREFIXES = {
2134
2136
  return PREFIX_PROPS.outline;
2135
2137
  return OUTLINE_STYLE_PROPS;
2136
2138
  },
2139
+ // Width-vs-color, mirroring svg.ts's generate-side dispatch: decimals
2140
+ // (stroke-2, stroke-1.5) and non-color arbitraries (stroke-[3px]) emit
2141
+ // stroke-width; every color-shaped value emits the `stroke` paint property.
2142
+ stroke: (value, _textSizes2, _fontFamilies2, colorNames) => {
2143
+ if (RE_DECIMAL.test(value) || value.startsWith("[") && !isColorValue(value, void 0, colorNames))
2144
+ return STROKE_WIDTH_PROPS;
2145
+ return PREFIX_PROPS.stroke;
2146
+ },
2137
2147
  decoration: (value, _textSizes2, _fontFamilies2, colorNames) => {
2138
2148
  if (value.startsWith("(length:") || value.startsWith("[length:"))
2139
2149
  return PREFIX_PROPS.decoration;
@@ -2410,16 +2420,19 @@ function mergeClasses(classes, resolve, cache) {
2410
2420
  return output;
2411
2421
  }
2412
2422
  function mergeFrom(inputs, resolve, cache) {
2413
- let allStrings = inputs.length > 0;
2423
+ let fastPath = true;
2424
+ let rawKey = "";
2414
2425
  for (let i = 0; i < inputs.length; i++) {
2415
2426
  const input = inputs[i];
2416
- if (typeof input !== "string" || input === "") {
2417
- allStrings = false;
2427
+ if (typeof input === "string") {
2428
+ if (input !== "") rawKey = rawKey === "" ? input : `${rawKey}\0${input}`;
2429
+ } else if (input) {
2430
+ fastPath = false;
2418
2431
  break;
2419
2432
  }
2420
2433
  }
2421
- if (allStrings) {
2422
- const rawKey = inputs.join("\0");
2434
+ if (fastPath) {
2435
+ if (rawKey === "") return "";
2423
2436
  if (rawKey.length <= RI_CACHE_KEY_MAX_LEN) {
2424
2437
  const cached = lruGet(cache, rawKey);
2425
2438
  if (cached !== void 0) return cached;
@@ -15,10 +15,10 @@ import {
15
15
  codepointCompare,
16
16
  parseUtility,
17
17
  resolveUtilityDeclarations
18
- } from "./chunk-6DAHUFNU.mjs";
18
+ } from "./chunk-6GTG5SZJ.mjs";
19
19
  import {
20
20
  SPECIAL_COLORS
21
- } from "./chunk-5Y7EXXLS.mjs";
21
+ } from "./chunk-KRZL4IDK.mjs";
22
22
 
23
23
  // src/project/css-entry.ts
24
24
  var CSS_ENTRY_CANDIDATES = Object.freeze([
package/dist/cli.mjs CHANGED
@@ -2,13 +2,13 @@
2
2
  import {
3
3
  CSS_ENTRY_CANDIDATES,
4
4
  enumerateClassNames
5
- } from "./chunk-YLB6FGIG.mjs";
5
+ } from "./chunk-WYMCN5OC.mjs";
6
6
  import {
7
7
  DEFAULT_EXCLUDES,
8
8
  DEFAULT_PATTERNS,
9
9
  compileScannedProject,
10
10
  getFontPreloadLinks
11
- } from "./chunk-4SVFFDS2.mjs";
11
+ } from "./chunk-53WD6U2X.mjs";
12
12
  import {
13
13
  MAX_DIRECTIVE_INPUT_SIZE,
14
14
  extractDirectives,
@@ -16,10 +16,10 @@ import {
16
16
  hasRIActivation,
17
17
  listVariants,
18
18
  resolveDirectives
19
- } from "./chunk-6DAHUFNU.mjs";
19
+ } from "./chunk-6GTG5SZJ.mjs";
20
20
  import {
21
21
  devWarn
22
- } from "./chunk-5Y7EXXLS.mjs";
22
+ } from "./chunk-KRZL4IDK.mjs";
23
23
 
24
24
  // src/entries/cli.ts
25
25
  import { realpathSync } from "fs";
@@ -1236,7 +1236,7 @@ function readPackageJSONSync(cwd) {
1236
1236
 
1237
1237
  // src/entries/cli.ts
1238
1238
  function getVersion() {
1239
- return true ? "0.4.0" : "unknown";
1239
+ return true ? "0.4.1" : "unknown";
1240
1240
  }
1241
1241
  async function main() {
1242
1242
  const args = process.argv.slice(2);
package/dist/editor.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { P as ParsedDirective, R as ResolvedTheme } from './index-BB2HoeMj.js';
2
- export { b as createThemeSnapshot } from './index-BB2HoeMj.js';
1
+ import { P as ParsedDirective, R as ResolvedTheme } from './index-Dp6i5TSv.js';
2
+ export { b as createThemeSnapshot } from './index-Dp6i5TSv.js';
3
3
  import { b as CompilationSnapshot, C as ColorDefinition } from './context-ruu2x_jR.js';
4
4
  export { e as defaultTheme } from './context-ruu2x_jR.js';
5
5
 
package/dist/editor.mjs CHANGED
@@ -2,7 +2,7 @@ import {
2
2
  CSS_ENTRY_CANDIDATES,
3
3
  UTILITY_VALUE_SPACES,
4
4
  enumerateClassNames
5
- } from "./chunk-YLB6FGIG.mjs";
5
+ } from "./chunk-WYMCN5OC.mjs";
6
6
  import {
7
7
  isSourceFile
8
8
  } from "./chunk-3HRMFZGE.mjs";
@@ -27,7 +27,7 @@ import {
27
27
  parseUtility,
28
28
  severityForCode,
29
29
  warningCode
30
- } from "./chunk-6DAHUFNU.mjs";
30
+ } from "./chunk-6GTG5SZJ.mjs";
31
31
  import {
32
32
  computeDarkStop,
33
33
  defaultTheme,
@@ -38,7 +38,7 @@ import {
38
38
  oklabToLinearSrgb,
39
39
  oklchToOklab,
40
40
  resolverFor
41
- } from "./chunk-5Y7EXXLS.mjs";
41
+ } from "./chunk-KRZL4IDK.mjs";
42
42
 
43
43
  // src/engine/inspector.ts
44
44
  var RESOLUTION_CACHE_CAP = 1e4;
@@ -383,7 +383,7 @@ function createEditorSession(options = {}) {
383
383
  }
384
384
 
385
385
  // src/entries/editor.ts
386
- var version = true ? "0.4.0" : "0.0.0-dev";
386
+ var version = true ? "0.4.1" : "0.0.0-dev";
387
387
  var EDITOR_API_VERSION = 1;
388
388
  var editorCapabilities = Object.freeze([
389
389
  "class-candidates",
@@ -12,11 +12,9 @@ interface FontFace {
12
12
  style: string;
13
13
  /** font-display strategy. */
14
14
  display: string;
15
- /** Unicode subsets — used as a Google Fonts URL hint. */
16
- subset: string;
17
15
  /** Optional unicode-range descriptor emitted into the @font-face (local subsetting). */
18
16
  unicodeRange?: string;
19
- /** Per-face preload override; when undefined the slot-level default applies. */
17
+ /** Whether to emit a preload link for this face's font file. */
20
18
  preload?: boolean;
21
19
  /** Whether the weight was explicitly set by the user (not a default).
22
20
  * Used by refreshFontWeightDefaults() to avoid overriding user intent. */
@@ -38,19 +36,25 @@ interface FontSlot {
38
36
  features: string | null;
39
37
  /** Font variation settings — applied via the font-<slot> utility. */
40
38
  variation: string | null;
41
- /** Slot-level preload default for faces that don't set their own. */
42
- preload: boolean;
43
39
  /** One or more faces — each emits an @font-face for local providers. */
44
40
  faces: FontFace[];
45
- /** User-specified fallback font for metrics-adjusted @font-face. */
46
- metricsFallback?: string;
47
- /** User-specified size-adjust percentage. */
41
+ /**
42
+ * CLS-fallback metrics config from the `metrics:` key. Absent = automatic
43
+ * (from the built-in table when the family is known); `null` = disabled via
44
+ * `metrics: none`; an object overrides the fallback font and/or the numbers.
45
+ */
46
+ metrics?: FontMetricsConfig | null;
47
+ }
48
+ /**
49
+ * Parsed `metrics:` value. `fallback` picks the local font to metric-match.
50
+ * The four override percentages are all-present or all-absent (the parser
51
+ * enforces arity); when absent they are computed from the built-in table.
52
+ */
53
+ interface FontMetricsConfig {
54
+ fallback?: string;
48
55
  sizeAdjust?: number;
49
- /** User-specified ascent-override percentage. */
50
56
  ascent?: number;
51
- /** User-specified descent-override percentage. */
52
57
  descent?: number;
53
- /** User-specified line-gap-override percentage. */
54
58
  lineGap?: number;
55
59
  }
56
60
 
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import { PluginCreator } from 'postcss';
2
2
  export { C as ColorDefinition, a as CompilationContext, b as CompilationSnapshot, F as FluidConfig, T as TextSize, c as Theme, d as createCompilationContext, e as defaultTheme, f as finalizeCompilationContext, r as registerColorNames, g as registerCustomFontFamilies, h as registerCustomTextSizes, i as registerCustomUtility } from './context-ruu2x_jR.js';
3
3
  export { D as DEFAULT_TEXT_SIZES, c as createRi, r as ri, s as safelist } from './safelist-D9-Plqta.js';
4
- import { R as ResolvedTheme, P as ParsedDirective } from './index-BB2HoeMj.js';
5
- export { C as CompilationResult, a as CompiledRule, c as createCompiler } from './index-BB2HoeMj.js';
4
+ import { R as ResolvedTheme, P as ParsedDirective } from './index-Dp6i5TSv.js';
5
+ export { C as CompilationResult, a as CompiledRule, c as createCompiler } from './index-Dp6i5TSv.js';
6
6
 
7
7
  interface RainbowIndexOptions {
8
8
  sources?: string[];
package/dist/index.mjs CHANGED
@@ -3,17 +3,17 @@ import {
3
3
  } from "./chunk-PD4ZXGJ6.mjs";
4
4
  import {
5
5
  postcss_default
6
- } from "./chunk-TLR6RP5L.mjs";
6
+ } from "./chunk-IYIUS7AE.mjs";
7
7
  import {
8
8
  finalizeProjectCompilation,
9
9
  resolveGoogleFonts
10
- } from "./chunk-4SVFFDS2.mjs";
10
+ } from "./chunk-53WD6U2X.mjs";
11
11
  import {
12
12
  analyzeProjectCSS,
13
13
  createCompiler,
14
14
  extractClassesFromSource,
15
15
  pushWarningsDeduped
16
- } from "./chunk-6DAHUFNU.mjs";
16
+ } from "./chunk-6GTG5SZJ.mjs";
17
17
  import {
18
18
  DEFAULT_TEXT_SIZES,
19
19
  createCompilationContext,
@@ -25,7 +25,7 @@ import {
25
25
  registerCustomTextSizes,
26
26
  registerCustomUtility,
27
27
  ri
28
- } from "./chunk-5Y7EXXLS.mjs";
28
+ } from "./chunk-KRZL4IDK.mjs";
29
29
 
30
30
  // src/project/index.ts
31
31
  async function compileProject(options) {
package/dist/vite.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  postcss_default
3
- } from "./chunk-TLR6RP5L.mjs";
4
- import "./chunk-4SVFFDS2.mjs";
3
+ } from "./chunk-IYIUS7AE.mjs";
4
+ import "./chunk-53WD6U2X.mjs";
5
5
  import {
6
6
  isSourceFile
7
7
  } from "./chunk-3HRMFZGE.mjs";
@@ -12,10 +12,10 @@ import {
12
12
  hasRIActivation,
13
13
  isAtRuleBoundary,
14
14
  isAtRuleNameChar
15
- } from "./chunk-6DAHUFNU.mjs";
15
+ } from "./chunk-6GTG5SZJ.mjs";
16
16
  import {
17
17
  devWarn
18
- } from "./chunk-5Y7EXXLS.mjs";
18
+ } from "./chunk-KRZL4IDK.mjs";
19
19
 
20
20
  // src/integrations/vite.ts
21
21
  import { existsSync } from "fs";
@@ -57,61 +57,33 @@ var KEYWORD_BODY_DIRECTIVES = new Set(
57
57
  var REMOVAL_RE = /!([\w][\w-]*)\s*;/g;
58
58
  var FLUID_KEYWORD_RE = /\b(no-parabolic|parabolic|no-shift|shift)\s*;?/g;
59
59
  var COLOR_FLAG_RE = /(?<=[{;\s]|^)(inline|no-parabolic|parabolic)\s*(?:;|(?=}))/g;
60
- function rewriteTopLevel(body, rewrite) {
61
- if (!body.includes("{")) return rewrite(body);
60
+ function mapTopLevelSpans(body, mapOutside, mapBlock) {
61
+ let brace = body.indexOf("{");
62
+ if (brace === -1) return mapOutside(body);
62
63
  let out = "";
63
64
  let segStart = 0;
64
- let depth = 0;
65
- for (let i = 0; i < body.length; i++) {
66
- const ch = body[i];
67
- if (ch === "{") {
68
- if (depth === 0) {
69
- out += rewrite(body.slice(segStart, i));
70
- segStart = i;
71
- }
72
- depth++;
73
- } else if (ch === "}") {
74
- if (depth > 0) depth--;
75
- if (depth === 0) {
76
- out += body.slice(segStart, i + 1);
77
- segStart = i + 1;
78
- }
79
- }
65
+ while (brace !== -1) {
66
+ out += mapOutside(body.slice(segStart, brace));
67
+ const close = findClosingBrace(body, brace);
68
+ if (close === -1) return out + body.slice(brace);
69
+ out += `{${mapBlock(body.slice(brace + 1, close))}}`;
70
+ segStart = close + 1;
71
+ brace = body.indexOf("{", segStart);
80
72
  }
81
- out += depth === 0 ? rewrite(body.slice(segStart)) : body.slice(segStart);
82
- return out;
73
+ return out + mapOutside(body.slice(segStart));
83
74
  }
75
+ var keepSpan = (span) => span;
84
76
  function rewriteColorOptionFlag(_match, keyword) {
85
77
  if (keyword === "inline") return "--ri-inline: true;";
86
78
  const negated = keyword.startsWith("no-");
87
79
  return `--ri-${negated ? keyword.slice(3) : keyword}: ${negated ? "false" : "true"};`;
88
80
  }
89
81
  function rewriteColorOptionFlags(body) {
90
- if (!body.includes("{")) return body;
91
- let out = "";
92
- let segStart = 0;
93
- let depth = 0;
94
- let blockStart = -1;
95
- for (let i = 0; i < body.length; i++) {
96
- const ch = body[i];
97
- if (ch === "{") {
98
- if (depth === 0) {
99
- out += body.slice(segStart, i + 1);
100
- blockStart = i + 1;
101
- }
102
- depth++;
103
- } else if (ch === "}") {
104
- if (depth > 0) depth--;
105
- if (depth === 0 && blockStart !== -1) {
106
- out += body.slice(blockStart, i).replace(COLOR_FLAG_RE, rewriteColorOptionFlag);
107
- out += "}";
108
- segStart = i + 1;
109
- blockStart = -1;
110
- }
111
- }
112
- }
113
- out += body.slice(segStart);
114
- return out;
82
+ return mapTopLevelSpans(
83
+ body,
84
+ keepSpan,
85
+ (interior) => interior.replace(COLOR_FLAG_RE, rewriteColorOptionFlag)
86
+ );
115
87
  }
116
88
  function rewriteDirectiveBodies(code) {
117
89
  let out = "";
@@ -146,17 +118,21 @@ function rewriteDirectiveBodies(code) {
146
118
  const close = findClosingBrace(code, braceIdx);
147
119
  const bodyStart = braceIdx + 1;
148
120
  const bodyEnd = close === -1 ? code.length : close;
149
- let rewritten = rewriteTopLevel(code.slice(bodyStart, bodyEnd), (span) => {
150
- let s = span;
151
- if (removals) s = s.replace(REMOVAL_RE, "--ri-rm: $1;");
152
- if (keywords) {
153
- s = s.replace(FLUID_KEYWORD_RE, (_, kw) => {
154
- const negated = kw.startsWith("no-");
155
- return `--ri-${negated ? kw.slice(3) : kw}: ${negated ? "false" : "true"};`;
156
- });
157
- }
158
- return s;
159
- });
121
+ let rewritten = mapTopLevelSpans(
122
+ code.slice(bodyStart, bodyEnd),
123
+ (span) => {
124
+ let s = span;
125
+ if (removals) s = s.replace(REMOVAL_RE, "--ri-rm: $1;");
126
+ if (keywords) {
127
+ s = s.replace(FLUID_KEYWORD_RE, (_, kw) => {
128
+ const negated = kw.startsWith("no-");
129
+ return `--ri-${negated ? kw.slice(3) : kw}: ${negated ? "false" : "true"};`;
130
+ });
131
+ }
132
+ return s;
133
+ },
134
+ keepSpan
135
+ );
160
136
  if (name === "color") rewritten = rewriteColorOptionFlags(rewritten);
161
137
  out += code.slice(last, bodyStart) + rewritten;
162
138
  last = bodyEnd;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rainbowindex",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "CSS-first system for building and maintaining consistent user interfaces",
5
5
  "keywords": [
6
6
  "css",
@@ -97,6 +97,7 @@
97
97
  },
98
98
  "devDependencies": {
99
99
  "@biomejs/biome": "^2.4.16",
100
+ "@capsizecss/metrics": "^4.2.0",
100
101
  "@types/node": "^25.9.1",
101
102
  "@vitest/coverage-v8": "^4.1.0",
102
103
  "postcss": "^8.5.8",