@kbach/react 1.0.0-beta.27 → 1.0.0-beta.29

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.
@@ -418,11 +418,87 @@ var defaultTheme = {
418
418
  // centering/padding) — see `ContainerConfig`'s own doc comment.
419
419
  container: {}
420
420
  };
421
+ var activeTheme = defaultTheme;
421
422
  var activeThemeJson = JSON.stringify(defaultTheme);
423
+ function getTheme() {
424
+ return activeTheme;
425
+ }
422
426
  function getThemeJson() {
423
427
  return activeThemeJson;
424
428
  }
425
429
 
430
+ // src/colorVariables.ts
431
+ function parseHexRgb(hex) {
432
+ const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(hex.trim());
433
+ if (!m) return null;
434
+ let h = m[1];
435
+ if (h.length === 3) h = h.split("").map((c) => c + c).join("");
436
+ const n = parseInt(h, 16);
437
+ return [n >> 16 & 255, n >> 8 & 255, n & 255];
438
+ }
439
+ function wrapDarkDecls(strategy, decls) {
440
+ switch (strategy) {
441
+ case "class":
442
+ return `.dark { ${decls} }`;
443
+ case "media":
444
+ return `@media (prefers-color-scheme: dark) { :root { ${decls} } }`;
445
+ case "attribute":
446
+ default:
447
+ return `[data-theme="dark"] { ${decls} }`;
448
+ }
449
+ }
450
+ function modeAwareDecls(theme) {
451
+ const light = [];
452
+ const dark = [];
453
+ for (const [name, value] of Object.entries(theme.colors)) {
454
+ if (typeof value === "string") continue;
455
+ const l = parseHexRgb(value.light);
456
+ const d = parseHexRgb(value.dark);
457
+ if (!l || !d) continue;
458
+ light.push(`--kb-color-${name}: ${l.join(",")};`);
459
+ dark.push(`--kb-color-${name}: ${d.join(",")};`);
460
+ }
461
+ return { light, dark };
462
+ }
463
+ function colorVariablesCss(theme) {
464
+ const { light, dark } = modeAwareDecls(theme);
465
+ if (light.length === 0) return "";
466
+ return `:root { ${light.join(" ")} }
467
+ ${wrapDarkDecls(theme.darkMode, dark.join(" "))}`;
468
+ }
469
+ function withColorVariables(theme) {
470
+ let changed = false;
471
+ const colors = {};
472
+ for (const [name, value] of Object.entries(theme.colors)) {
473
+ if (typeof value !== "string" && parseHexRgb(value.light) && parseHexRgb(value.dark)) {
474
+ colors[name] = `rgb(var(--kb-color-${name}))`;
475
+ changed = true;
476
+ } else {
477
+ colors[name] = value;
478
+ }
479
+ }
480
+ return changed ? { ...theme, colors } : theme;
481
+ }
482
+ var STYLE_ID = "kbach-colors";
483
+ var injectedForTheme = null;
484
+ function ensureColorVariablesInjected(theme) {
485
+ if (typeof document === "undefined") return;
486
+ if (injectedForTheme === theme) return;
487
+ injectedForTheme = theme;
488
+ const css = colorVariablesCss(theme);
489
+ let el = document.getElementById(STYLE_ID);
490
+ if (!css) {
491
+ el?.remove();
492
+ return;
493
+ }
494
+ if (!el) {
495
+ el = document.createElement("style");
496
+ el.id = STYLE_ID;
497
+ document.head.insertBefore(el, document.head.firstChild);
498
+ }
499
+ el.textContent = css;
500
+ }
501
+
426
502
  // src/reset.ts
427
503
  var RESET_STYLE_ID = "kbach-reset";
428
504
  var RESET_RULES = [
@@ -551,27 +627,88 @@ function ensureResetInjected() {
551
627
  var KB_CACHE_MAX = 500;
552
628
  var kbCache = /* @__PURE__ */ new Map();
553
629
  var cachedForThemeJson = null;
630
+ var engineThemeJson = "";
631
+ var hasModeAware = false;
632
+ function refreshEngineTheme() {
633
+ const theme = getTheme();
634
+ const withVars = withColorVariables(theme);
635
+ hasModeAware = withVars !== theme;
636
+ engineThemeJson = hasModeAware ? JSON.stringify(withVars) : getThemeJson();
637
+ }
638
+ var staticOwner = null;
639
+ var staticSheet = null;
640
+ var staticRuleCount = -1;
641
+ var staticTokens = /* @__PURE__ */ new Set();
642
+ function unescapeCssIdent(s) {
643
+ return s.replace(/\\([0-9a-fA-F]{1,6})\s?/g, (_, hex) => String.fromCodePoint(parseInt(hex, 16))).replace(/\\(.)/g, "$1");
644
+ }
645
+ function isStaticKbachSheet(sheet) {
646
+ try {
647
+ return Array.from(sheet.cssRules).some((r) => r instanceof CSSStyleRule && r.selectorText === ":root" && r.cssText.includes("--kb-dark-mode"));
648
+ } catch {
649
+ return false;
650
+ }
651
+ }
652
+ function collectClasses(rules, into) {
653
+ for (const r of Array.from(rules)) {
654
+ if (r instanceof CSSStyleRule) {
655
+ for (const m of r.selectorText.matchAll(/\.((?:\\[0-9a-fA-F]{1,6}\s?|\\.|[\w-])+)/g)) into.add(unescapeCssIdent(m[1]));
656
+ } else if ("cssRules" in r) {
657
+ collectClasses(r.cssRules, into);
658
+ }
659
+ }
660
+ }
661
+ function staticClasses() {
662
+ if (typeof document === "undefined") return staticTokens;
663
+ let sheet = staticOwner && staticOwner.sheet;
664
+ if (!sheet || !isStaticKbachSheet(sheet)) {
665
+ sheet = Array.from(document.styleSheets).find((s) => s !== styleEl?.sheet && isStaticKbachSheet(s)) ?? null;
666
+ staticOwner = sheet?.ownerNode ?? null;
667
+ }
668
+ if (!sheet) {
669
+ staticSheet = null;
670
+ staticTokens = /* @__PURE__ */ new Set();
671
+ return staticTokens;
672
+ }
673
+ if (sheet !== staticSheet || sheet.cssRules.length !== staticRuleCount) {
674
+ staticSheet = sheet;
675
+ staticRuleCount = sheet.cssRules.length;
676
+ staticTokens = /* @__PURE__ */ new Set();
677
+ collectClasses(sheet.cssRules, staticTokens);
678
+ }
679
+ return staticTokens;
680
+ }
554
681
  function kb(classString) {
555
682
  const themeJson = getThemeJson();
556
683
  if (themeJson !== cachedForThemeJson) {
557
684
  kbCache.clear();
558
685
  cachedForThemeJson = themeJson;
686
+ refreshEngineTheme();
687
+ }
688
+ const statics = runtimeCSSDisabled ? null : staticClasses();
689
+ let toResolve = classString;
690
+ let alreadyStatic = "";
691
+ if (statics && statics.size > 0) {
692
+ const tokens = classString.split(/\s+/).filter(Boolean);
693
+ toResolve = tokens.filter((t) => !statics.has(t)).join(" ");
694
+ alreadyStatic = tokens.filter((t) => statics.has(t)).join(" ");
559
695
  }
560
- let result = kbCache.get(classString);
696
+ let result = kbCache.get(toResolve);
561
697
  if (result === void 0) {
562
- const json = generateCss(classString, themeJson);
698
+ const json = generateCss(toResolve, engineThemeJson);
563
699
  result = JSON.parse(json);
564
700
  if (kbCache.size >= KB_CACHE_MAX) kbCache.clear();
565
- kbCache.set(classString, result);
701
+ kbCache.set(toResolve, result);
566
702
  }
567
703
  const { className, rules } = result;
568
704
  if (!runtimeCSSDisabled) {
569
705
  ensureResetInjected();
706
+ if (hasModeAware) ensureColorVariablesInjected(getTheme());
570
707
  for (const { rule, order } of rules) {
571
708
  injectRule(rule, order);
572
709
  }
573
710
  }
574
- return className;
711
+ return alreadyStatic ? (alreadyStatic + " " + className).trim() : className;
575
712
  }
576
713
 
577
714
  // src/jsx-runtime.tsx
@@ -2,9 +2,9 @@ import {
2
2
  Fragment,
3
3
  jsx,
4
4
  jsxs
5
- } from "./chunk-UP7MWEU5.mjs";
6
- import "./chunk-DJKDEDPE.mjs";
7
- import "./chunk-OVKVZA7B.mjs";
5
+ } from "./chunk-6KXERZP3.mjs";
6
+ import "./chunk-K6AUD64N.mjs";
7
+ import "./chunk-FBYS4BI3.mjs";
8
8
 
9
9
  // src/jsx-dev-runtime.tsx
10
10
  function jsxDEV(type, props, key, isStaticChildren, source, self) {
@@ -417,11 +417,87 @@ var defaultTheme = {
417
417
  // centering/padding) — see `ContainerConfig`'s own doc comment.
418
418
  container: {}
419
419
  };
420
+ var activeTheme = defaultTheme;
420
421
  var activeThemeJson = JSON.stringify(defaultTheme);
422
+ function getTheme() {
423
+ return activeTheme;
424
+ }
421
425
  function getThemeJson() {
422
426
  return activeThemeJson;
423
427
  }
424
428
 
429
+ // src/colorVariables.ts
430
+ function parseHexRgb(hex) {
431
+ const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(hex.trim());
432
+ if (!m) return null;
433
+ let h = m[1];
434
+ if (h.length === 3) h = h.split("").map((c) => c + c).join("");
435
+ const n = parseInt(h, 16);
436
+ return [n >> 16 & 255, n >> 8 & 255, n & 255];
437
+ }
438
+ function wrapDarkDecls(strategy, decls) {
439
+ switch (strategy) {
440
+ case "class":
441
+ return `.dark { ${decls} }`;
442
+ case "media":
443
+ return `@media (prefers-color-scheme: dark) { :root { ${decls} } }`;
444
+ case "attribute":
445
+ default:
446
+ return `[data-theme="dark"] { ${decls} }`;
447
+ }
448
+ }
449
+ function modeAwareDecls(theme) {
450
+ const light = [];
451
+ const dark = [];
452
+ for (const [name, value] of Object.entries(theme.colors)) {
453
+ if (typeof value === "string") continue;
454
+ const l = parseHexRgb(value.light);
455
+ const d = parseHexRgb(value.dark);
456
+ if (!l || !d) continue;
457
+ light.push(`--kb-color-${name}: ${l.join(",")};`);
458
+ dark.push(`--kb-color-${name}: ${d.join(",")};`);
459
+ }
460
+ return { light, dark };
461
+ }
462
+ function colorVariablesCss(theme) {
463
+ const { light, dark } = modeAwareDecls(theme);
464
+ if (light.length === 0) return "";
465
+ return `:root { ${light.join(" ")} }
466
+ ${wrapDarkDecls(theme.darkMode, dark.join(" "))}`;
467
+ }
468
+ function withColorVariables(theme) {
469
+ let changed = false;
470
+ const colors = {};
471
+ for (const [name, value] of Object.entries(theme.colors)) {
472
+ if (typeof value !== "string" && parseHexRgb(value.light) && parseHexRgb(value.dark)) {
473
+ colors[name] = `rgb(var(--kb-color-${name}))`;
474
+ changed = true;
475
+ } else {
476
+ colors[name] = value;
477
+ }
478
+ }
479
+ return changed ? { ...theme, colors } : theme;
480
+ }
481
+ var STYLE_ID = "kbach-colors";
482
+ var injectedForTheme = null;
483
+ function ensureColorVariablesInjected(theme) {
484
+ if (typeof document === "undefined") return;
485
+ if (injectedForTheme === theme) return;
486
+ injectedForTheme = theme;
487
+ const css = colorVariablesCss(theme);
488
+ let el = document.getElementById(STYLE_ID);
489
+ if (!css) {
490
+ el?.remove();
491
+ return;
492
+ }
493
+ if (!el) {
494
+ el = document.createElement("style");
495
+ el.id = STYLE_ID;
496
+ document.head.insertBefore(el, document.head.firstChild);
497
+ }
498
+ el.textContent = css;
499
+ }
500
+
425
501
  // src/reset.ts
426
502
  var RESET_STYLE_ID = "kbach-reset";
427
503
  var RESET_RULES = [
@@ -550,27 +626,88 @@ function ensureResetInjected() {
550
626
  var KB_CACHE_MAX = 500;
551
627
  var kbCache = /* @__PURE__ */ new Map();
552
628
  var cachedForThemeJson = null;
629
+ var engineThemeJson = "";
630
+ var hasModeAware = false;
631
+ function refreshEngineTheme() {
632
+ const theme = getTheme();
633
+ const withVars = withColorVariables(theme);
634
+ hasModeAware = withVars !== theme;
635
+ engineThemeJson = hasModeAware ? JSON.stringify(withVars) : getThemeJson();
636
+ }
637
+ var staticOwner = null;
638
+ var staticSheet = null;
639
+ var staticRuleCount = -1;
640
+ var staticTokens = /* @__PURE__ */ new Set();
641
+ function unescapeCssIdent(s) {
642
+ return s.replace(/\\([0-9a-fA-F]{1,6})\s?/g, (_, hex) => String.fromCodePoint(parseInt(hex, 16))).replace(/\\(.)/g, "$1");
643
+ }
644
+ function isStaticKbachSheet(sheet) {
645
+ try {
646
+ return Array.from(sheet.cssRules).some((r) => r instanceof CSSStyleRule && r.selectorText === ":root" && r.cssText.includes("--kb-dark-mode"));
647
+ } catch {
648
+ return false;
649
+ }
650
+ }
651
+ function collectClasses(rules, into) {
652
+ for (const r of Array.from(rules)) {
653
+ if (r instanceof CSSStyleRule) {
654
+ for (const m of r.selectorText.matchAll(/\.((?:\\[0-9a-fA-F]{1,6}\s?|\\.|[\w-])+)/g)) into.add(unescapeCssIdent(m[1]));
655
+ } else if ("cssRules" in r) {
656
+ collectClasses(r.cssRules, into);
657
+ }
658
+ }
659
+ }
660
+ function staticClasses() {
661
+ if (typeof document === "undefined") return staticTokens;
662
+ let sheet = staticOwner && staticOwner.sheet;
663
+ if (!sheet || !isStaticKbachSheet(sheet)) {
664
+ sheet = Array.from(document.styleSheets).find((s) => s !== styleEl?.sheet && isStaticKbachSheet(s)) ?? null;
665
+ staticOwner = sheet?.ownerNode ?? null;
666
+ }
667
+ if (!sheet) {
668
+ staticSheet = null;
669
+ staticTokens = /* @__PURE__ */ new Set();
670
+ return staticTokens;
671
+ }
672
+ if (sheet !== staticSheet || sheet.cssRules.length !== staticRuleCount) {
673
+ staticSheet = sheet;
674
+ staticRuleCount = sheet.cssRules.length;
675
+ staticTokens = /* @__PURE__ */ new Set();
676
+ collectClasses(sheet.cssRules, staticTokens);
677
+ }
678
+ return staticTokens;
679
+ }
553
680
  function kb(classString) {
554
681
  const themeJson = getThemeJson();
555
682
  if (themeJson !== cachedForThemeJson) {
556
683
  kbCache.clear();
557
684
  cachedForThemeJson = themeJson;
685
+ refreshEngineTheme();
686
+ }
687
+ const statics = runtimeCSSDisabled ? null : staticClasses();
688
+ let toResolve = classString;
689
+ let alreadyStatic = "";
690
+ if (statics && statics.size > 0) {
691
+ const tokens = classString.split(/\s+/).filter(Boolean);
692
+ toResolve = tokens.filter((t) => !statics.has(t)).join(" ");
693
+ alreadyStatic = tokens.filter((t) => statics.has(t)).join(" ");
558
694
  }
559
- let result = kbCache.get(classString);
695
+ let result = kbCache.get(toResolve);
560
696
  if (result === void 0) {
561
- const json = generateCss(classString, themeJson);
697
+ const json = generateCss(toResolve, engineThemeJson);
562
698
  result = JSON.parse(json);
563
699
  if (kbCache.size >= KB_CACHE_MAX) kbCache.clear();
564
- kbCache.set(classString, result);
700
+ kbCache.set(toResolve, result);
565
701
  }
566
702
  const { className, rules } = result;
567
703
  if (!runtimeCSSDisabled) {
568
704
  ensureResetInjected();
705
+ if (hasModeAware) ensureColorVariablesInjected(getTheme());
569
706
  for (const { rule, order } of rules) {
570
707
  injectRule(rule, order);
571
708
  }
572
709
  }
573
- return className;
710
+ return alreadyStatic ? (alreadyStatic + " " + className).trim() : className;
574
711
  }
575
712
 
576
713
  // src/jsx-runtime.tsx
@@ -2,9 +2,9 @@ import {
2
2
  Fragment,
3
3
  jsx,
4
4
  jsxs
5
- } from "./chunk-UP7MWEU5.mjs";
6
- import "./chunk-DJKDEDPE.mjs";
7
- import "./chunk-OVKVZA7B.mjs";
5
+ } from "./chunk-6KXERZP3.mjs";
6
+ import "./chunk-K6AUD64N.mjs";
7
+ import "./chunk-FBYS4BI3.mjs";
8
8
  export {
9
9
  Fragment,
10
10
  jsx,
@@ -34,6 +34,7 @@ __export(postcss_plugin_exports, {
34
34
  });
35
35
  module.exports = __toCommonJS(postcss_plugin_exports);
36
36
  var import_postcss = __toESM(require("postcss"));
37
+ var import_fs3 = require("fs");
37
38
  var import_path5 = require("path");
38
39
 
39
40
  // src/staticCss/engine.ts
@@ -44,6 +45,9 @@ var import_node = require("@kbach/core-engine/node");
44
45
  function generateCssForToken(token, themeJson) {
45
46
  return JSON.parse((0, import_node.generate_css)(token, themeJson));
46
47
  }
48
+ function suggestClassForToken(token, themeJson) {
49
+ return (0, import_node.suggest_class)(token, themeJson) || null;
50
+ }
47
51
 
48
52
  // src/vite-plugin/scan.ts
49
53
  var import_fs = require("fs");
@@ -485,6 +489,59 @@ function buildResetCSS(usedTags) {
485
489
  return RESET_RULES.filter((r) => !r.tags || r.tags.some((t) => usedTags.has(t))).map((r) => r.css).join("\n");
486
490
  }
487
491
 
492
+ // src/colorVariables.ts
493
+ function parseHexRgb(hex) {
494
+ const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(hex.trim());
495
+ if (!m) return null;
496
+ let h = m[1];
497
+ if (h.length === 3) h = h.split("").map((c) => c + c).join("");
498
+ const n = parseInt(h, 16);
499
+ return [n >> 16 & 255, n >> 8 & 255, n & 255];
500
+ }
501
+ function wrapDarkDecls(strategy, decls) {
502
+ switch (strategy) {
503
+ case "class":
504
+ return `.dark { ${decls} }`;
505
+ case "media":
506
+ return `@media (prefers-color-scheme: dark) { :root { ${decls} } }`;
507
+ case "attribute":
508
+ default:
509
+ return `[data-theme="dark"] { ${decls} }`;
510
+ }
511
+ }
512
+ function modeAwareDecls(theme) {
513
+ const light = [];
514
+ const dark = [];
515
+ for (const [name, value] of Object.entries(theme.colors)) {
516
+ if (typeof value === "string") continue;
517
+ const l = parseHexRgb(value.light);
518
+ const d = parseHexRgb(value.dark);
519
+ if (!l || !d) continue;
520
+ light.push(`--kb-color-${name}: ${l.join(",")};`);
521
+ dark.push(`--kb-color-${name}: ${d.join(",")};`);
522
+ }
523
+ return { light, dark };
524
+ }
525
+ function colorVariablesCss(theme) {
526
+ const { light, dark } = modeAwareDecls(theme);
527
+ if (light.length === 0) return "";
528
+ return `:root { ${light.join(" ")} }
529
+ ${wrapDarkDecls(theme.darkMode, dark.join(" "))}`;
530
+ }
531
+ function withColorVariables(theme) {
532
+ let changed = false;
533
+ const colors = {};
534
+ for (const [name, value] of Object.entries(theme.colors)) {
535
+ if (typeof value !== "string" && parseHexRgb(value.light) && parseHexRgb(value.dark)) {
536
+ colors[name] = `rgb(var(--kb-color-${name}))`;
537
+ changed = true;
538
+ } else {
539
+ colors[name] = value;
540
+ }
541
+ }
542
+ return changed ? { ...theme, colors } : theme;
543
+ }
544
+
488
545
  // src/vite-plugin/format.ts
489
546
  function formatKbachCSS(tokenRules, theme, usedTags) {
490
547
  const allEntries = [];
@@ -502,6 +559,8 @@ function formatKbachCSS(tokenRules, theme, usedTags) {
502
559
  lines.push("", ":root {", ` --kb-dark-mode: ${theme.darkMode};`);
503
560
  for (const [varName, val] of declarations) lines.push(` ${varName}: ${val};`);
504
561
  lines.push("}");
562
+ const colorVars = colorVariablesCss(theme);
563
+ if (colorVars) lines.push("", prettifyCSS(colorVars));
505
564
  lines.push("", prettifyCSS(text));
506
565
  return lines.join("\n");
507
566
  }
@@ -560,17 +619,18 @@ function isMarkerClass(base) {
560
619
  if (slashIdx === -1) return false;
561
620
  return MARKER_CLASSES.has(base.slice(0, slashIdx)) && slashIdx < base.length - 1;
562
621
  }
563
- function warnIfUnknownClass(token, filePath, code, isResolvable, projectCssClasses, warnedTokens) {
622
+ var TAILWIND_SHADE = /-(?:50|[1-9]00|950)(?:\/|$)/;
623
+ function warnIfUnknownClass(token, filePath, code, isResolvable, projectCssClasses, warnedTokens, suggest) {
564
624
  if (isResolvable || warnedTokens.has(token)) return;
565
625
  const base = stripModifierPrefix(token);
566
626
  if (!base || projectCssClasses.has(base) || isMarkerClass(base)) return;
567
627
  warnedTokens.add(token);
568
628
  const pos = findLineCol(code, token);
569
629
  const location = pos ? `${blue(filePath)}${green(`:${pos.line}:${pos.column}`)}` : blue(filePath);
570
- console.warn(
571
- `${kbachTag()} ${gray("Unknown class")} ${highlight(token)} ${gray("\u2014 no Kbach utility or project CSS rule matches it. Typo?")}
572
- ${bold("at")} ${location}`
573
- );
630
+ const suggestion = suggest?.(token) ?? null;
631
+ const hint = suggestion ? `${gray("\u2014 did you mean")} ${highlight(suggestion)}${gray("?")}${TAILWIND_SHADE.test(token) ? gray(" Kbach color shades run 1\u201312, not 50\u2013950.") : ""}` : gray("\u2014 no Kbach utility or project CSS rule matches it. Typo?");
632
+ console.warn(`${kbachTag()} ${gray("Unknown class")} ${highlight(token)} ${hint}
633
+ ${bold("at")} ${location}`);
574
634
  }
575
635
 
576
636
  // src/staticCss/engine.ts
@@ -580,7 +640,8 @@ function normPath(p) {
580
640
  }
581
641
  var SAFELIST_KEY = "\0kbach-safelist";
582
642
  function createKbachStaticCssEngine(options) {
583
- const { root, theme, themeJson, includeDirs, safelist } = options;
643
+ const { root, theme, includeDirs, safelist } = options;
644
+ const themeJson = JSON.stringify(withColorVariables(theme));
584
645
  const fileTokens = /* @__PURE__ */ new Map();
585
646
  const tokenRules = /* @__PURE__ */ new Map();
586
647
  const fileTags = /* @__PURE__ */ new Map();
@@ -598,7 +659,7 @@ function createKbachStaticCssEngine(options) {
598
659
  tokens.add(tok);
599
660
  const rules = resolveToken(tok);
600
661
  if (process.env.NODE_ENV !== "production") {
601
- warnIfUnknownClass(tok, filePath, code, rules.length > 0, projectCssClasses, warnedTokens);
662
+ warnIfUnknownClass(tok, filePath, code, rules.length > 0, projectCssClasses, warnedTokens, (t) => suggestClassForToken(t, themeJson));
602
663
  }
603
664
  }
604
665
  fileTokens.set(normPath(filePath), tokens);
@@ -1037,16 +1098,6 @@ function detectDarkModeStrategyFromDom() {
1037
1098
  setTheme({ ...activeTheme, darkMode: raw });
1038
1099
  }
1039
1100
 
1040
- // src/colorVariables.ts
1041
- function parseHexRgb(hex) {
1042
- const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(hex.trim());
1043
- if (!m) return null;
1044
- let h = m[1];
1045
- if (h.length === 3) h = h.split("").map((c) => c + c).join("");
1046
- const n = parseInt(h, 16);
1047
- return [n >> 16 & 255, n >> 8 & 255, n & 255];
1048
- }
1049
-
1050
1101
  // src/darkModeStore.ts
1051
1102
  var STORAGE_KEY = "kbach-theme";
1052
1103
  var listeners = /* @__PURE__ */ new Set();
@@ -1111,7 +1162,13 @@ function applyOpacityToHex(hex, opacityText) {
1111
1162
  return `rgba(${rgb.join(",")},${clamped})`;
1112
1163
  }
1113
1164
  function resolveColorEntry(value, lookup) {
1114
- if (typeof value !== "string") return value;
1165
+ if (typeof value !== "string") {
1166
+ const side = (v, mode2) => {
1167
+ const r = resolveColorEntry(v, lookup);
1168
+ return typeof r === "string" ? r : r[mode2];
1169
+ };
1170
+ return { light: side(value.light, "light"), dark: side(value.dark, "dark") };
1171
+ }
1115
1172
  const slash = value.indexOf("/");
1116
1173
  const name = slash === -1 ? value : value.slice(0, slash);
1117
1174
  const opacity = slash === -1 ? void 0 : value.slice(slash + 1);
@@ -1176,11 +1233,21 @@ function isEsmRequireFailure(err) {
1176
1233
  return err.code === "ERR_REQUIRE_ESM" || /is not defined in ES module scope/.test(err.message);
1177
1234
  }
1178
1235
  async function importConfigModule(path) {
1179
- const mod = await import((0, import_url.pathToFileURL)(path).href);
1236
+ const url = (0, import_url.pathToFileURL)(path).href;
1237
+ let mod;
1238
+ try {
1239
+ mod = await nativeImport(url + "?t=" + Date.now());
1240
+ } catch (err) {
1241
+ if (err.code !== "ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING") throw err;
1242
+ mod = await import(url);
1243
+ }
1180
1244
  return mod.default ?? mod;
1181
1245
  }
1246
+ var nativeImport = new Function("url", "return import(url)");
1182
1247
  function requireConfigModule(root, path) {
1183
- const mod = (0, import_module.createRequire)(root)(path);
1248
+ const req = (0, import_module.createRequire)(root);
1249
+ delete req.cache[req.resolve(path)];
1250
+ const mod = req(path);
1184
1251
  return mod.default ?? mod;
1185
1252
  }
1186
1253
  async function loadConfigFile(root) {
@@ -1190,6 +1257,7 @@ async function loadConfigFile(root) {
1190
1257
  if ((0, import_fs2.existsSync)(mjsPath)) return importConfigModule(mjsPath);
1191
1258
  const jsPath = (0, import_path4.join)(root, "kbach.config.js");
1192
1259
  if (!(0, import_fs2.existsSync)(jsPath)) return void 0;
1260
+ if (isEsmProject(root)) return importConfigModule(jsPath);
1193
1261
  try {
1194
1262
  return requireConfigModule(root, jsPath);
1195
1263
  } catch (err) {
@@ -1197,6 +1265,13 @@ async function loadConfigFile(root) {
1197
1265
  return importConfigModule(jsPath);
1198
1266
  }
1199
1267
  }
1268
+ function isEsmProject(root) {
1269
+ try {
1270
+ return JSON.parse((0, import_fs2.readFileSync)((0, import_path4.join)(root, "package.json"), "utf-8")).type === "module";
1271
+ } catch {
1272
+ return false;
1273
+ }
1274
+ }
1200
1275
  async function resolveEffectiveTheme(root, options) {
1201
1276
  if (options.theme) return options.theme;
1202
1277
  if (options.config) return resolveKbachConfig(options.config);
@@ -1251,7 +1326,6 @@ function kbachPostcss(options = {}) {
1251
1326
  const engine = createKbachStaticCssEngine({
1252
1327
  root: projectRoot,
1253
1328
  theme,
1254
- themeJson: JSON.stringify(theme),
1255
1329
  includeDirs,
1256
1330
  safelist
1257
1331
  });
@@ -1266,6 +1340,10 @@ function kbachPostcss(options = {}) {
1266
1340
  glob: "**/*"
1267
1341
  });
1268
1342
  }
1343
+ for (const name of ["kbach.config.js", "kbach.config.mjs", "kbach.config.cjs"]) {
1344
+ const file = (0, import_path5.resolve)(projectRoot, name);
1345
+ if ((0, import_fs3.existsSync)(file)) result.messages.push({ type: "dependency", plugin: "kbach", file });
1346
+ }
1269
1347
  spliceGeneratedCss(root, engine.generateCSS());
1270
1348
  }
1271
1349
  };
@@ -6,12 +6,13 @@ import {
6
6
  highlight,
7
7
  kbachTag,
8
8
  resolveEffectiveTheme
9
- } from "./chunk-KTRJZDVE.mjs";
10
- import "./chunk-43FOLRQA.mjs";
11
- import "./chunk-OVKVZA7B.mjs";
9
+ } from "./chunk-NHWKWY2T.mjs";
10
+ import "./chunk-UK5S55DF.mjs";
11
+ import "./chunk-FBYS4BI3.mjs";
12
12
 
13
13
  // src/postcss-plugin/index.ts
14
14
  import postcss from "postcss";
15
+ import { existsSync } from "fs";
15
16
  import { resolve as resolvePath } from "path";
16
17
  var KBACH_START_TEXT = "kbach:start";
17
18
  var KBACH_END_TEXT = "kbach:end";
@@ -59,7 +60,6 @@ function kbachPostcss(options = {}) {
59
60
  const engine = createKbachStaticCssEngine({
60
61
  root: projectRoot,
61
62
  theme,
62
- themeJson: JSON.stringify(theme),
63
63
  includeDirs,
64
64
  safelist
65
65
  });
@@ -74,6 +74,10 @@ function kbachPostcss(options = {}) {
74
74
  glob: "**/*"
75
75
  });
76
76
  }
77
+ for (const name of ["kbach.config.js", "kbach.config.mjs", "kbach.config.cjs"]) {
78
+ const file = resolvePath(projectRoot, name);
79
+ if (existsSync(file)) result.messages.push({ type: "dependency", plugin: "kbach", file });
80
+ }
77
81
  spliceGeneratedCss(root, engine.generateCSS());
78
82
  }
79
83
  };
@@ -64,6 +64,8 @@ interface KbachPluginOptions {
64
64
  declare function findMainCSSFile(root: string, includeDirs: string[], explicitCssFile?: string): string;
65
65
  declare const DEFAULT_SCAN_DIRS: string[];
66
66
  declare const CSS_SYNC_DEBOUNCE_MS = 50;
67
+ /** `kbach.config.js` / `.mjs` / `.cjs` directly in `root`. */
68
+ declare function isConfigFile(root: string, file: string): boolean;
67
69
  /**
68
70
  * Auto-discovers a `kbach.config.*` file at the project root — `undefined`
69
71
  * if none exists (the common case: most projects have no customization at
@@ -127,4 +129,4 @@ declare function resolveEffectiveTheme(root: string, options: {
127
129
  */
128
130
  declare function kbach(options?: KbachPluginOptions): Plugin;
129
131
 
130
- export { CSS_SYNC_DEBOUNCE_MS, DEFAULT_SCAN_DIRS, type KbachPluginOptions, findMainCSSFile, kbach, loadConfigFile, resolveEffectiveTheme };
132
+ export { CSS_SYNC_DEBOUNCE_MS, DEFAULT_SCAN_DIRS, type KbachPluginOptions, findMainCSSFile, isConfigFile, kbach, loadConfigFile, resolveEffectiveTheme };
@@ -64,6 +64,8 @@ interface KbachPluginOptions {
64
64
  declare function findMainCSSFile(root: string, includeDirs: string[], explicitCssFile?: string): string;
65
65
  declare const DEFAULT_SCAN_DIRS: string[];
66
66
  declare const CSS_SYNC_DEBOUNCE_MS = 50;
67
+ /** `kbach.config.js` / `.mjs` / `.cjs` directly in `root`. */
68
+ declare function isConfigFile(root: string, file: string): boolean;
67
69
  /**
68
70
  * Auto-discovers a `kbach.config.*` file at the project root — `undefined`
69
71
  * if none exists (the common case: most projects have no customization at
@@ -127,4 +129,4 @@ declare function resolveEffectiveTheme(root: string, options: {
127
129
  */
128
130
  declare function kbach(options?: KbachPluginOptions): Plugin;
129
131
 
130
- export { CSS_SYNC_DEBOUNCE_MS, DEFAULT_SCAN_DIRS, type KbachPluginOptions, findMainCSSFile, kbach, loadConfigFile, resolveEffectiveTheme };
132
+ export { CSS_SYNC_DEBOUNCE_MS, DEFAULT_SCAN_DIRS, type KbachPluginOptions, findMainCSSFile, isConfigFile, kbach, loadConfigFile, resolveEffectiveTheme };