@barocss/kit 0.6.0 → 0.7.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/dist/index.cjs CHANGED
@@ -557,14 +557,23 @@ function parseClassName(className, ctx) {
557
557
  if (cache.has(className)) {
558
558
  return cache.get(className);
559
559
  }
560
- let important = false;
561
560
  let realClassName = className;
562
- if (className.startsWith("!")) {
561
+ const classPrefix = ctx ? configuredClassPrefix(ctx) : "";
562
+ if (classPrefix) {
563
+ if (!className.startsWith(classPrefix + ":")) {
564
+ const none = { modifiers: [], utility: null };
565
+ cache.set(className, none);
566
+ return none;
567
+ }
568
+ realClassName = className.slice(classPrefix.length + 1);
569
+ }
570
+ let important = false;
571
+ if (realClassName.startsWith("!")) {
563
572
  important = true;
564
- realClassName = className.slice(1);
565
- } else if (className.length > 1 && className.endsWith("!")) {
573
+ realClassName = realClassName.slice(1);
574
+ } else if (realClassName.length > 1 && realClassName.endsWith("!")) {
566
575
  important = true;
567
- realClassName = className.slice(0, -1);
576
+ realClassName = realClassName.slice(0, -1);
568
577
  }
569
578
  const tokens = tokenize(realClassName);
570
579
  const result = parseTokens(tokens, ctx);
@@ -574,6 +583,10 @@ function parseClassName(className, ctx) {
574
583
  cache.set(className, result);
575
584
  return result;
576
585
  }
586
+ function configuredClassPrefix(ctx) {
587
+ const configured = ctx.config("prefix");
588
+ return typeof configured === "string" && /^[a-z]+$/.test(configured) ? configured : "";
589
+ }
577
590
  function parseTokens(tokens, ctx) {
578
591
  const modifiers = [];
579
592
  let utility = null;
@@ -1097,24 +1110,41 @@ function animationToCssVars(animations) {
1097
1110
  }
1098
1111
  return result;
1099
1112
  }
1100
- function keyframesToCss(keyframes) {
1101
- if (!keyframes) return "";
1102
- let css = "";
1103
- for (const name in keyframes) {
1104
- const frames = keyframes[name];
1105
- css += `@keyframes ${name} {
1113
+ const COMMENT_OR_BLOCK = /\/\*|\*\/|[{};]/;
1114
+ function keyframesBlock(name, frames) {
1115
+ if (!name || COMMENT_OR_BLOCK.test(name) || /\s/.test(name) || !frames || typeof frames !== "object") return "";
1116
+ let body = "";
1117
+ for (const [step, props] of Object.entries(frames)) {
1118
+ if (COMMENT_OR_BLOCK.test(step) || !props || typeof props !== "object") return "";
1119
+ let decls = "";
1120
+ for (const [prop, value] of Object.entries(props)) {
1121
+ const v2 = String(value);
1122
+ if (COMMENT_OR_BLOCK.test(prop) || COMMENT_OR_BLOCK.test(v2)) return "";
1123
+ decls += ` ${prop}: ${v2};
1106
1124
  `;
1107
- for (const step in frames) {
1108
- css += ` ${step} {`;
1109
- const props = frames[step];
1110
- for (const prop in props) {
1111
- css += ` ${prop}: ${props[prop]};`;
1112
- }
1113
- css += " }\n";
1114
1125
  }
1115
- css += "}\n";
1126
+ body += ` ${step} {
1127
+ ${decls} }
1128
+ `;
1129
+ }
1130
+ return `@keyframes ${name} {
1131
+ ${body}}`;
1132
+ }
1133
+ function referencedKeyframes(css, ctx) {
1134
+ if (!css.includes("animation")) return [];
1135
+ const all = ctx.theme("keyframes");
1136
+ if (!all || typeof all !== "object") return [];
1137
+ const names = /* @__PURE__ */ new Set();
1138
+ for (const m of css.matchAll(/(?:^|[\s;{])animation(?:-name)?\s*:\s*([^;}]+)/g)) {
1139
+ const value = m[1].replace(/var\(--animate-([\w-]+)\)/g, (whole, key) => {
1140
+ const v2 = ctx.theme("animations", key) ?? ctx.theme("animation", key);
1141
+ return typeof v2 === "string" ? v2 : whole;
1142
+ });
1143
+ for (const word of value.split(/[\s,()]+/)) {
1144
+ if (word && Object.prototype.hasOwnProperty.call(all, word)) names.add(word);
1145
+ }
1116
1146
  }
1117
- return css;
1147
+ return [...names].map((n) => keyframesBlock(n, all[n])).filter(Boolean);
1118
1148
  }
1119
1149
  function transitionTimingFunctionToCssVars(transition) {
1120
1150
  const result = {};
@@ -1182,7 +1212,7 @@ function themeToCssVarsAll(theme) {
1182
1212
  ...borderRadiusToCssVars(theme.borderRadius),
1183
1213
  ...zIndexToCssVars(theme.zIndex),
1184
1214
  ...opacityToCssVars(theme.opacity),
1185
- ...animationToCssVars(theme.animations),
1215
+ ...animationToCssVars({ ...theme.animations, ...theme.animation }),
1186
1216
  ...transitionTimingFunctionToCssVars(theme.transitionTimingFunction),
1187
1217
  ...transitionDurationToCssVars(theme.transitionDuration),
1188
1218
  ...transitionDelayToCssVars(theme.transitionDelay),
@@ -1552,7 +1582,11 @@ function generateCss(classList, ctx, opts) {
1552
1582
  }
1553
1583
  return result;
1554
1584
  }).join(opts?.minify ? "" : "\n");
1555
- const rootRules = [...new Set(allAtRootNodes.filter((node) => node.type === "at-rule").map((node) => rootToCss([node], { minify: opts?.minify })))];
1585
+ const rootRules = [.../* @__PURE__ */ new Set([
1586
+ ...allAtRootNodes.filter((node) => node.type === "at-rule").map((node) => rootToCss([node], { minify: opts?.minify })),
1587
+ // #274: the @keyframes the class rules reference, once per sheet.
1588
+ ...referencedKeyframes(results, ctx)
1589
+ ])];
1556
1590
  const rootDeclarations = [...new Set(allAtRootNodes.filter((node) => node.type === "decl").map((node) => rootToCss([node], { minify: opts?.minify })).filter((decl2) => decl2 !== ""))];
1557
1591
  const rootCss = [
1558
1592
  ...rootRules,
@@ -1610,6 +1644,7 @@ function generateCssRules(classList, ctx, opts) {
1610
1644
  const css = rootToCss([node]);
1611
1645
  rootCssList.push(css);
1612
1646
  }
1647
+ rootCssList.push(...referencedKeyframes(cssList.join("\n"), ctx));
1613
1648
  return {
1614
1649
  cls,
1615
1650
  ast: allCleanAst,
@@ -1900,6 +1935,48 @@ class IncrementalParser {
1900
1935
  return Array.from(this.processedClasses);
1901
1936
  }
1902
1937
  }
1938
+ const customUtilityName = /^[A-Za-z_][A-Za-z0-9_-]*$/;
1939
+ const customUtilityProp = /^(--[A-Za-z0-9_-]+|-?[A-Za-z][A-Za-z0-9-]*)$/;
1940
+ function validateCustomUtility(name, decls) {
1941
+ if (typeof name !== "string" || !customUtilityName.test(name)) return null;
1942
+ if (!decls || typeof decls !== "object" || Array.isArray(decls)) return null;
1943
+ const out = [];
1944
+ for (const [prop, raw2] of Object.entries(decls)) {
1945
+ if (typeof raw2 !== "string" && typeof raw2 !== "number") return null;
1946
+ const value = String(raw2).trim();
1947
+ if (!customUtilityProp.test(prop) || !value || !isStructureSafeValue(value) || hasCommentDelimiter(value)) return null;
1948
+ out.push([prop, value]);
1949
+ }
1950
+ return out.length ? out : null;
1951
+ }
1952
+ function registerCustomUtilities(ctx, utilities) {
1953
+ if (!utilities || typeof utilities !== "object" || Array.isArray(utilities)) return;
1954
+ const list = getUtility(ctx);
1955
+ const builtins = [...list];
1956
+ const before = list.length;
1957
+ for (const [name, decls] of Object.entries(utilities)) {
1958
+ const safe = validateCustomUtility(name, decls);
1959
+ if (!safe) {
1960
+ debugWarn(`[BAROCSS] Ignoring invalid custom utility "${name}"`);
1961
+ continue;
1962
+ }
1963
+ const shadowed = builtins.filter((u) => u.match(name));
1964
+ registerUtility({
1965
+ name,
1966
+ category: "custom",
1967
+ match: (className) => className === name,
1968
+ handler: (value, c, token) => {
1969
+ let base = [];
1970
+ for (const reg of shadowed) {
1971
+ base = reg.handler(value, c, token, reg) || [];
1972
+ if (base.length > 0) break;
1973
+ }
1974
+ return [...base, ...safe.map(([prop, v]) => decl(prop, v))];
1975
+ }
1976
+ }, ctx);
1977
+ }
1978
+ if (list.length > before) list.unshift(...list.splice(before));
1979
+ }
1903
1980
  const preflightMinimalCSS = `
1904
1981
  /* BaroCSS Preflight - Minimal Reset */
1905
1982
  /* ================================= */
@@ -2685,7 +2762,6 @@ function getPreflightCSS(level = true) {
2685
2762
  return "";
2686
2763
  }
2687
2764
  const defaultConfig = {
2688
- prefix: "barocss-",
2689
2765
  darkMode: "media"
2690
2766
  // same as default
2691
2767
  };
@@ -2787,9 +2863,7 @@ function resolveTheme(config) {
2787
2863
  }
2788
2864
  function themeToCssVars(theme) {
2789
2865
  const vars = themeToCssVarsAll(theme);
2790
- const result = toCssVarsBlock(vars, `
2791
- ${keyframesToCss(theme.keyframes || {})}
2792
- `);
2866
+ const result = toCssVarsBlock(vars);
2793
2867
  return result;
2794
2868
  }
2795
2869
  function createContext(configObj) {
@@ -2843,6 +2917,7 @@ function createContext(configObj) {
2843
2917
  }
2844
2918
  };
2845
2919
  initializeContextState(ctx, getUtility(), getModifier());
2920
+ registerCustomUtilities(ctx, configObj.utilities);
2846
2921
  return ctx;
2847
2922
  }
2848
2923
  function jsonToAst(input, ctx) {
@@ -3614,10 +3689,12 @@ staticUtility("animate-bounce", [["animation", "var(--animate-bounce)"]], { cate
3614
3689
  staticUtility("animate-none", [["animation", "none"]], { category: "transitions" });
3615
3690
  functionalUtility({
3616
3691
  name: "animate",
3617
- prop: "animation",
3692
+ // #274: theme.animations (and Tailwind's theme.animation) names, e.g. theme.extend.animation.wiggle.
3693
+ themeKeys: ["animations", "animation"],
3618
3694
  supportsArbitrary: true,
3619
3695
  supportsCustomProperty: true,
3620
- handle: (value, ctx, token) => {
3696
+ handle: (value, ctx, token, extra) => {
3697
+ if (extra?.realThemeValue) return [decl("animation", `var(--animate-${extra.realThemeValue})`)];
3621
3698
  if (token.customProperty) {
3622
3699
  return [decl("animation", `var(${value})`)];
3623
3700
  }