@kbach/react 1.0.0-beta.28 → 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.
@@ -1,14 +1,16 @@
1
1
  import {
2
2
  resolveKbachConfig
3
- } from "./chunk-43FOLRQA.mjs";
3
+ } from "./chunk-UK5S55DF.mjs";
4
4
  import {
5
5
  buildResetCSS,
6
- defaultTheme
7
- } from "./chunk-OVKVZA7B.mjs";
6
+ colorVariablesCss,
7
+ defaultTheme,
8
+ withColorVariables
9
+ } from "./chunk-FBYS4BI3.mjs";
8
10
 
9
11
  // src/vite-plugin/index.ts
10
12
  import { readFileSync as readFileSync3, writeFileSync, mkdirSync, existsSync, statSync as statSync2 } from "fs";
11
- import { join as join4, dirname } from "path";
13
+ import { join as join4, dirname, basename } from "path";
12
14
  import { pathToFileURL } from "url";
13
15
  import { createRequire } from "module";
14
16
 
@@ -184,6 +186,8 @@ function formatKbachCSS(tokenRules, theme, usedTags) {
184
186
  lines.push("", ":root {", ` --kb-dark-mode: ${theme.darkMode};`);
185
187
  for (const [varName, val] of declarations) lines.push(` ${varName}: ${val};`);
186
188
  lines.push("}");
189
+ const colorVars = colorVariablesCss(theme);
190
+ if (colorVars) lines.push("", prettifyCSS(colorVars));
187
191
  lines.push("", prettifyCSS(text));
188
192
  return lines.join("\n");
189
193
  }
@@ -211,10 +215,13 @@ import { readFileSync as readFileSync2 } from "fs";
211
215
  import { join as join3 } from "path";
212
216
 
213
217
  // src/vite-plugin/wasmNode.ts
214
- import { generate_css } from "@kbach/core-engine/node";
218
+ import { generate_css, suggest_class } from "@kbach/core-engine/node";
215
219
  function generateCssForToken(token, themeJson) {
216
220
  return JSON.parse(generate_css(token, themeJson));
217
221
  }
222
+ function suggestClassForToken(token, themeJson) {
223
+ return suggest_class(token, themeJson) || null;
224
+ }
218
225
 
219
226
  // src/vite-plugin/scan.ts
220
227
  import { readdirSync, readFileSync, statSync } from "fs";
@@ -474,17 +481,18 @@ function isMarkerClass(base) {
474
481
  if (slashIdx === -1) return false;
475
482
  return MARKER_CLASSES.has(base.slice(0, slashIdx)) && slashIdx < base.length - 1;
476
483
  }
477
- function warnIfUnknownClass(token, filePath, code, isResolvable, projectCssClasses, warnedTokens) {
484
+ var TAILWIND_SHADE = /-(?:50|[1-9]00|950)(?:\/|$)/;
485
+ function warnIfUnknownClass(token, filePath, code, isResolvable, projectCssClasses, warnedTokens, suggest) {
478
486
  if (isResolvable || warnedTokens.has(token)) return;
479
487
  const base = stripModifierPrefix(token);
480
488
  if (!base || projectCssClasses.has(base) || isMarkerClass(base)) return;
481
489
  warnedTokens.add(token);
482
490
  const pos = findLineCol(code, token);
483
491
  const location = pos ? `${blue(filePath)}${green(`:${pos.line}:${pos.column}`)}` : blue(filePath);
484
- console.warn(
485
- `${kbachTag()} ${gray("Unknown class")} ${highlight(token)} ${gray("\u2014 no Kbach utility or project CSS rule matches it. Typo?")}
486
- ${bold("at")} ${location}`
487
- );
492
+ const suggestion = suggest?.(token) ?? null;
493
+ 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?");
494
+ console.warn(`${kbachTag()} ${gray("Unknown class")} ${highlight(token)} ${hint}
495
+ ${bold("at")} ${location}`);
488
496
  }
489
497
 
490
498
  // src/staticCss/engine.ts
@@ -494,7 +502,8 @@ function normPath(p) {
494
502
  }
495
503
  var SAFELIST_KEY = "\0kbach-safelist";
496
504
  function createKbachStaticCssEngine(options) {
497
- const { root, theme, themeJson, includeDirs, safelist } = options;
505
+ const { root, theme, includeDirs, safelist } = options;
506
+ const themeJson = JSON.stringify(withColorVariables(theme));
498
507
  const fileTokens = /* @__PURE__ */ new Map();
499
508
  const tokenRules = /* @__PURE__ */ new Map();
500
509
  const fileTags = /* @__PURE__ */ new Map();
@@ -512,7 +521,7 @@ function createKbachStaticCssEngine(options) {
512
521
  tokens.add(tok);
513
522
  const rules = resolveToken(tok);
514
523
  if (process.env.NODE_ENV !== "production") {
515
- warnIfUnknownClass(tok, filePath, code, rules.length > 0, projectCssClasses, warnedTokens);
524
+ warnIfUnknownClass(tok, filePath, code, rules.length > 0, projectCssClasses, warnedTokens, (t) => suggestClassForToken(t, themeJson));
516
525
  }
517
526
  }
518
527
  fileTokens.set(normPath(filePath), tokens);
@@ -597,13 +606,27 @@ function isEsmRequireFailure(err) {
597
606
  return err.code === "ERR_REQUIRE_ESM" || /is not defined in ES module scope/.test(err.message);
598
607
  }
599
608
  async function importConfigModule(path) {
600
- const mod = await import(pathToFileURL(path).href);
609
+ const url = pathToFileURL(path).href;
610
+ let mod;
611
+ try {
612
+ mod = await nativeImport(url + "?t=" + Date.now());
613
+ } catch (err) {
614
+ if (err.code !== "ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING") throw err;
615
+ mod = await import(url);
616
+ }
601
617
  return mod.default ?? mod;
602
618
  }
619
+ var nativeImport = new Function("url", "return import(url)");
603
620
  function requireConfigModule(root, path) {
604
- const mod = createRequire(root)(path);
621
+ const req = createRequire(root);
622
+ delete req.cache[req.resolve(path)];
623
+ const mod = req(path);
605
624
  return mod.default ?? mod;
606
625
  }
626
+ function isConfigFile(root, file) {
627
+ const norm = (p) => p.replace(/\\/g, "/").toLowerCase();
628
+ return /^kbach\.config\.(c|m)?js$/.test(basename(file)) && norm(dirname(file)) === norm(root);
629
+ }
607
630
  async function loadConfigFile(root) {
608
631
  const cjsPath = join4(root, "kbach.config.cjs");
609
632
  if (existsSync(cjsPath)) return requireConfigModule(root, cjsPath);
@@ -611,6 +634,7 @@ async function loadConfigFile(root) {
611
634
  if (existsSync(mjsPath)) return importConfigModule(mjsPath);
612
635
  const jsPath = join4(root, "kbach.config.js");
613
636
  if (!existsSync(jsPath)) return void 0;
637
+ if (isEsmProject(root)) return importConfigModule(jsPath);
614
638
  try {
615
639
  return requireConfigModule(root, jsPath);
616
640
  } catch (err) {
@@ -618,6 +642,13 @@ async function loadConfigFile(root) {
618
642
  return importConfigModule(jsPath);
619
643
  }
620
644
  }
645
+ function isEsmProject(root) {
646
+ try {
647
+ return JSON.parse(readFileSync3(join4(root, "package.json"), "utf-8")).type === "module";
648
+ } catch {
649
+ return false;
650
+ }
651
+ }
621
652
  async function resolveEffectiveTheme(root, options) {
622
653
  if (options.theme) return options.theme;
623
654
  if (options.config) return resolveKbachConfig(options.config);
@@ -629,7 +660,7 @@ function kbach(options = {}) {
629
660
  const safelist = options.safelist ?? [];
630
661
  let root = process.cwd();
631
662
  let theme = defaultTheme;
632
- let engine = createKbachStaticCssEngine({ root, theme, themeJson: JSON.stringify(theme), includeDirs, safelist });
663
+ let engine = createKbachStaticCssEngine({ root, theme, includeDirs, safelist });
633
664
  let mainCSSFilePath = join4(root, "src", "kbach.css");
634
665
  function mainCSSFile() {
635
666
  return mainCSSFilePath;
@@ -646,13 +677,27 @@ function kbach(options = {}) {
646
677
  syncMainCSSFile(server);
647
678
  }, CSS_SYNC_DEBOUNCE_MS);
648
679
  }
680
+ async function reloadConfig(server) {
681
+ if (options.theme || options.config) return;
682
+ try {
683
+ theme = await resolveEffectiveTheme(root, options);
684
+ } catch (err) {
685
+ console.warn(`${kbachTag()} Couldn't reload kbach.config: ${err.message}`);
686
+ return;
687
+ }
688
+ engine = createKbachStaticCssEngine({ root, theme, includeDirs, safelist });
689
+ engine.scanProjectCssSelectorsOnce();
690
+ engine.initialScan();
691
+ engine.processSafelist();
692
+ syncMainCSSFile(server);
693
+ }
649
694
  return {
650
695
  name: "kbach",
651
696
  enforce: "pre",
652
697
  async configResolved(resolved) {
653
698
  root = resolved.root;
654
699
  theme = await resolveEffectiveTheme(root, options);
655
- engine = createKbachStaticCssEngine({ root, theme, themeJson: JSON.stringify(theme), includeDirs, safelist });
700
+ engine = createKbachStaticCssEngine({ root, theme, includeDirs, safelist });
656
701
  mainCSSFilePath = findMainCSSFile(root, includeDirs, options.cssFile);
657
702
  },
658
703
  buildStart() {
@@ -667,6 +712,10 @@ function kbach(options = {}) {
667
712
  configureServer(server) {
668
713
  const onAddOrUnlink = (file, isUnlink) => {
669
714
  if (file.includes("node_modules")) return;
715
+ if (isConfigFile(root, file)) {
716
+ void reloadConfig(server);
717
+ return;
718
+ }
670
719
  if (!/\.(tsx?|jsx?)$/.test(file)) return;
671
720
  if (isUnlink) {
672
721
  engine.removeFile(file);
@@ -682,8 +731,12 @@ function kbach(options = {}) {
682
731
  server.watcher.on("add", (file) => onAddOrUnlink(file, false));
683
732
  server.watcher.on("unlink", (file) => onAddOrUnlink(file, true));
684
733
  },
685
- handleHotUpdate({ file, server }) {
734
+ async handleHotUpdate({ file, server }) {
686
735
  if (file.includes("node_modules")) return;
736
+ if (isConfigFile(root, file)) {
737
+ await reloadConfig(server);
738
+ return;
739
+ }
687
740
  if (!/\.(tsx?|jsx?)$/.test(file)) return;
688
741
  try {
689
742
  engine.processFile(file, readSourceFile(file));
@@ -704,6 +757,7 @@ export {
704
757
  findMainCSSFile,
705
758
  DEFAULT_SCAN_DIRS,
706
759
  CSS_SYNC_DEBOUNCE_MS,
760
+ isConfigFile,
707
761
  loadConfigFile,
708
762
  resolveEffectiveTheme,
709
763
  kbach
@@ -2,8 +2,9 @@ import {
2
2
  defaultTheme,
3
3
  detectDarkModeStrategyFromDom,
4
4
  getTheme,
5
+ parseHexRgb,
5
6
  setTheme
6
- } from "./chunk-OVKVZA7B.mjs";
7
+ } from "./chunk-FBYS4BI3.mjs";
7
8
 
8
9
  // src/darkModeStore.ts
9
10
  var STORAGE_KEY = "kbach-theme";
@@ -97,56 +98,6 @@ function seedDefaultMode(fallback) {
97
98
  notify();
98
99
  }
99
100
 
100
- // src/colorVariables.ts
101
- function parseHexRgb(hex) {
102
- const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(hex.trim());
103
- if (!m) return null;
104
- let h = m[1];
105
- if (h.length === 3) h = h.split("").map((c) => c + c).join("");
106
- const n = parseInt(h, 16);
107
- return [n >> 16 & 255, n >> 8 & 255, n & 255];
108
- }
109
- function wrapDarkDecls(strategy, decls) {
110
- switch (strategy) {
111
- case "class":
112
- return `.dark { ${decls} }`;
113
- case "media":
114
- return `@media (prefers-color-scheme: dark) { :root { ${decls} } }`;
115
- case "attribute":
116
- default:
117
- return `[data-theme="dark"] { ${decls} }`;
118
- }
119
- }
120
- var STYLE_ID = "kbach-colors";
121
- var injectedForTheme = null;
122
- function ensureColorVariablesInjected(theme) {
123
- if (typeof document === "undefined") return;
124
- if (injectedForTheme === theme) return;
125
- injectedForTheme = theme;
126
- const lightDecls = [];
127
- const darkDecls = [];
128
- for (const [name, value] of Object.entries(theme.colors)) {
129
- if (typeof value === "string") continue;
130
- const light = parseHexRgb(value.light);
131
- const dark = parseHexRgb(value.dark);
132
- if (!light || !dark) continue;
133
- lightDecls.push(`--kb-color-${name}: ${light.join(",")};`);
134
- darkDecls.push(`--kb-color-${name}: ${dark.join(",")};`);
135
- }
136
- let el = document.getElementById(STYLE_ID);
137
- if (lightDecls.length === 0) {
138
- el?.remove();
139
- return;
140
- }
141
- if (!el) {
142
- el = document.createElement("style");
143
- el.id = STYLE_ID;
144
- document.head.insertBefore(el, document.head.firstChild);
145
- }
146
- el.textContent = `:root { ${lightDecls.join(" ")} }
147
- ${wrapDarkDecls(theme.darkMode, darkDecls.join(" "))}`;
148
- }
149
-
150
101
  // src/config.ts
151
102
  function applyOpacityToHex(hex, opacityText) {
152
103
  const rgb = parseHexRgb(hex);
@@ -156,7 +107,13 @@ function applyOpacityToHex(hex, opacityText) {
156
107
  return `rgba(${rgb.join(",")},${clamped})`;
157
108
  }
158
109
  function resolveColorEntry(value, lookup) {
159
- if (typeof value !== "string") return value;
110
+ if (typeof value !== "string") {
111
+ const side = (v, mode2) => {
112
+ const r = resolveColorEntry(v, lookup);
113
+ return typeof r === "string" ? r : r[mode2];
114
+ };
115
+ return { light: side(value.light, "light"), dark: side(value.dark, "dark") };
116
+ }
160
117
  const slash = value.indexOf("/");
161
118
  const name = slash === -1 ? value : value.slice(0, slash);
162
119
  const opacity = slash === -1 ? void 0 : value.slice(slash + 1);
@@ -221,8 +178,6 @@ function applyKbachConfig(config) {
221
178
  }
222
179
 
223
180
  export {
224
- parseHexRgb,
225
- ensureColorVariablesInjected,
226
181
  getGlobalDarkMode,
227
182
  getGlobalThemeMode,
228
183
  setGlobalThemeMode,
package/dist/index.d.mts CHANGED
@@ -16,7 +16,13 @@ declare function isRuntimeCSSDisabled(): boolean;
16
16
  /**
17
17
  * Resolves a Kbach class string via the Rust/WASM engine, cascade-order-safe
18
18
  * injects the resulting CSS rules into a single `<style data-kbach>` tag,
19
- * and returns the class string unchanged for use as `className`.
19
+ * and returns the class string to use as `className` (the input, except
20
+ * for a mode-aware color whose values aren't hex, which the engine still
21
+ * expands into per-mode classes).
22
+ *
23
+ * Classes the page's static kbach.css already defines are left to it (see
24
+ * `staticClasses`), and mode-aware colors use the same CSS variables as the
25
+ * static build (see `refreshEngineTheme`), so kb() and kbach.css agree.
20
26
  *
21
27
  * Must be called after `await initKbach()` resolves — see wasmLoader.ts.
22
28
  */
package/dist/index.d.ts CHANGED
@@ -16,7 +16,13 @@ declare function isRuntimeCSSDisabled(): boolean;
16
16
  /**
17
17
  * Resolves a Kbach class string via the Rust/WASM engine, cascade-order-safe
18
18
  * injects the resulting CSS rules into a single `<style data-kbach>` tag,
19
- * and returns the class string unchanged for use as `className`.
19
+ * and returns the class string to use as `className` (the input, except
20
+ * for a mode-aware color whose values aren't hex, which the engine still
21
+ * expands into per-mode classes).
22
+ *
23
+ * Classes the page's static kbach.css already defines are left to it (see
24
+ * `staticClasses`), and mode-aware colors use the same CSS variables as the
25
+ * static build (see `refreshEngineTheme`), so kb() and kbach.css agree.
20
26
  *
21
27
  * Must be called after `await initKbach()` resolves — see wasmLoader.ts.
22
28
  */
package/dist/index.js CHANGED
@@ -467,6 +467,78 @@ function detectDarkModeStrategyFromDom() {
467
467
  setTheme({ ...activeTheme, darkMode: raw });
468
468
  }
469
469
 
470
+ // src/colorVariables.ts
471
+ function parseHexRgb(hex) {
472
+ const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(hex.trim());
473
+ if (!m) return null;
474
+ let h = m[1];
475
+ if (h.length === 3) h = h.split("").map((c) => c + c).join("");
476
+ const n = parseInt(h, 16);
477
+ return [n >> 16 & 255, n >> 8 & 255, n & 255];
478
+ }
479
+ function wrapDarkDecls(strategy, decls) {
480
+ switch (strategy) {
481
+ case "class":
482
+ return `.dark { ${decls} }`;
483
+ case "media":
484
+ return `@media (prefers-color-scheme: dark) { :root { ${decls} } }`;
485
+ case "attribute":
486
+ default:
487
+ return `[data-theme="dark"] { ${decls} }`;
488
+ }
489
+ }
490
+ function modeAwareDecls(theme) {
491
+ const light = [];
492
+ const dark = [];
493
+ for (const [name, value] of Object.entries(theme.colors)) {
494
+ if (typeof value === "string") continue;
495
+ const l = parseHexRgb(value.light);
496
+ const d = parseHexRgb(value.dark);
497
+ if (!l || !d) continue;
498
+ light.push(`--kb-color-${name}: ${l.join(",")};`);
499
+ dark.push(`--kb-color-${name}: ${d.join(",")};`);
500
+ }
501
+ return { light, dark };
502
+ }
503
+ function colorVariablesCss(theme) {
504
+ const { light, dark } = modeAwareDecls(theme);
505
+ if (light.length === 0) return "";
506
+ return `:root { ${light.join(" ")} }
507
+ ${wrapDarkDecls(theme.darkMode, dark.join(" "))}`;
508
+ }
509
+ function withColorVariables(theme) {
510
+ let changed = false;
511
+ const colors = {};
512
+ for (const [name, value] of Object.entries(theme.colors)) {
513
+ if (typeof value !== "string" && parseHexRgb(value.light) && parseHexRgb(value.dark)) {
514
+ colors[name] = `rgb(var(--kb-color-${name}))`;
515
+ changed = true;
516
+ } else {
517
+ colors[name] = value;
518
+ }
519
+ }
520
+ return changed ? { ...theme, colors } : theme;
521
+ }
522
+ var STYLE_ID = "kbach-colors";
523
+ var injectedForTheme = null;
524
+ function ensureColorVariablesInjected(theme) {
525
+ if (typeof document === "undefined") return;
526
+ if (injectedForTheme === theme) return;
527
+ injectedForTheme = theme;
528
+ const css = colorVariablesCss(theme);
529
+ let el = document.getElementById(STYLE_ID);
530
+ if (!css) {
531
+ el?.remove();
532
+ return;
533
+ }
534
+ if (!el) {
535
+ el = document.createElement("style");
536
+ el.id = STYLE_ID;
537
+ document.head.insertBefore(el, document.head.firstChild);
538
+ }
539
+ el.textContent = css;
540
+ }
541
+
470
542
  // src/reset.ts
471
543
  var RESET_STYLE_ID = "kbach-reset";
472
544
  var RESET_RULES = [
@@ -601,27 +673,88 @@ function ensureResetInjected() {
601
673
  var KB_CACHE_MAX = 500;
602
674
  var kbCache = /* @__PURE__ */ new Map();
603
675
  var cachedForThemeJson = null;
676
+ var engineThemeJson = "";
677
+ var hasModeAware = false;
678
+ function refreshEngineTheme() {
679
+ const theme = getTheme();
680
+ const withVars = withColorVariables(theme);
681
+ hasModeAware = withVars !== theme;
682
+ engineThemeJson = hasModeAware ? JSON.stringify(withVars) : getThemeJson();
683
+ }
684
+ var staticOwner = null;
685
+ var staticSheet = null;
686
+ var staticRuleCount = -1;
687
+ var staticTokens = /* @__PURE__ */ new Set();
688
+ function unescapeCssIdent(s) {
689
+ return s.replace(/\\([0-9a-fA-F]{1,6})\s?/g, (_, hex) => String.fromCodePoint(parseInt(hex, 16))).replace(/\\(.)/g, "$1");
690
+ }
691
+ function isStaticKbachSheet(sheet) {
692
+ try {
693
+ return Array.from(sheet.cssRules).some((r) => r instanceof CSSStyleRule && r.selectorText === ":root" && r.cssText.includes("--kb-dark-mode"));
694
+ } catch {
695
+ return false;
696
+ }
697
+ }
698
+ function collectClasses(rules, into) {
699
+ for (const r of Array.from(rules)) {
700
+ if (r instanceof CSSStyleRule) {
701
+ for (const m of r.selectorText.matchAll(/\.((?:\\[0-9a-fA-F]{1,6}\s?|\\.|[\w-])+)/g)) into.add(unescapeCssIdent(m[1]));
702
+ } else if ("cssRules" in r) {
703
+ collectClasses(r.cssRules, into);
704
+ }
705
+ }
706
+ }
707
+ function staticClasses() {
708
+ if (typeof document === "undefined") return staticTokens;
709
+ let sheet = staticOwner && staticOwner.sheet;
710
+ if (!sheet || !isStaticKbachSheet(sheet)) {
711
+ sheet = Array.from(document.styleSheets).find((s) => s !== styleEl?.sheet && isStaticKbachSheet(s)) ?? null;
712
+ staticOwner = sheet?.ownerNode ?? null;
713
+ }
714
+ if (!sheet) {
715
+ staticSheet = null;
716
+ staticTokens = /* @__PURE__ */ new Set();
717
+ return staticTokens;
718
+ }
719
+ if (sheet !== staticSheet || sheet.cssRules.length !== staticRuleCount) {
720
+ staticSheet = sheet;
721
+ staticRuleCount = sheet.cssRules.length;
722
+ staticTokens = /* @__PURE__ */ new Set();
723
+ collectClasses(sheet.cssRules, staticTokens);
724
+ }
725
+ return staticTokens;
726
+ }
604
727
  function kb(classString) {
605
728
  const themeJson = getThemeJson();
606
729
  if (themeJson !== cachedForThemeJson) {
607
730
  kbCache.clear();
608
731
  cachedForThemeJson = themeJson;
732
+ refreshEngineTheme();
733
+ }
734
+ const statics = runtimeCSSDisabled ? null : staticClasses();
735
+ let toResolve = classString;
736
+ let alreadyStatic = "";
737
+ if (statics && statics.size > 0) {
738
+ const tokens = classString.split(/\s+/).filter(Boolean);
739
+ toResolve = tokens.filter((t) => !statics.has(t)).join(" ");
740
+ alreadyStatic = tokens.filter((t) => statics.has(t)).join(" ");
609
741
  }
610
- let result = kbCache.get(classString);
742
+ let result = kbCache.get(toResolve);
611
743
  if (result === void 0) {
612
- const json = generateCss(classString, themeJson);
744
+ const json = generateCss(toResolve, engineThemeJson);
613
745
  result = JSON.parse(json);
614
746
  if (kbCache.size >= KB_CACHE_MAX) kbCache.clear();
615
- kbCache.set(classString, result);
747
+ kbCache.set(toResolve, result);
616
748
  }
617
749
  const { className, rules } = result;
618
750
  if (!runtimeCSSDisabled) {
619
751
  ensureResetInjected();
752
+ if (hasModeAware) ensureColorVariablesInjected(getTheme());
620
753
  for (const { rule, order } of rules) {
621
754
  injectRule(rule, order);
622
755
  }
623
756
  }
624
- return className;
757
+ return alreadyStatic ? (alreadyStatic + " " + className).trim() : className;
625
758
  }
626
759
 
627
760
  // src/KbachReset.tsx
@@ -631,56 +764,6 @@ function KbachReset() {
631
764
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("style", { id: RESET_STYLE_ID, children: BASE_RESET });
632
765
  }
633
766
 
634
- // src/colorVariables.ts
635
- function parseHexRgb(hex) {
636
- const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(hex.trim());
637
- if (!m) return null;
638
- let h = m[1];
639
- if (h.length === 3) h = h.split("").map((c) => c + c).join("");
640
- const n = parseInt(h, 16);
641
- return [n >> 16 & 255, n >> 8 & 255, n & 255];
642
- }
643
- function wrapDarkDecls(strategy, decls) {
644
- switch (strategy) {
645
- case "class":
646
- return `.dark { ${decls} }`;
647
- case "media":
648
- return `@media (prefers-color-scheme: dark) { :root { ${decls} } }`;
649
- case "attribute":
650
- default:
651
- return `[data-theme="dark"] { ${decls} }`;
652
- }
653
- }
654
- var STYLE_ID = "kbach-colors";
655
- var injectedForTheme = null;
656
- function ensureColorVariablesInjected(theme) {
657
- if (typeof document === "undefined") return;
658
- if (injectedForTheme === theme) return;
659
- injectedForTheme = theme;
660
- const lightDecls = [];
661
- const darkDecls = [];
662
- for (const [name, value] of Object.entries(theme.colors)) {
663
- if (typeof value === "string") continue;
664
- const light = parseHexRgb(value.light);
665
- const dark = parseHexRgb(value.dark);
666
- if (!light || !dark) continue;
667
- lightDecls.push(`--kb-color-${name}: ${light.join(",")};`);
668
- darkDecls.push(`--kb-color-${name}: ${dark.join(",")};`);
669
- }
670
- let el = document.getElementById(STYLE_ID);
671
- if (lightDecls.length === 0) {
672
- el?.remove();
673
- return;
674
- }
675
- if (!el) {
676
- el = document.createElement("style");
677
- el.id = STYLE_ID;
678
- document.head.insertBefore(el, document.head.firstChild);
679
- }
680
- el.textContent = `:root { ${lightDecls.join(" ")} }
681
- ${wrapDarkDecls(theme.darkMode, darkDecls.join(" "))}`;
682
- }
683
-
684
767
  // src/darkModeStore.ts
685
768
  var STORAGE_KEY = "kbach-theme";
686
769
  var listeners = /* @__PURE__ */ new Set();
@@ -782,7 +865,13 @@ function applyOpacityToHex(hex, opacityText) {
782
865
  return `rgba(${rgb.join(",")},${clamped})`;
783
866
  }
784
867
  function resolveColorEntry(value, lookup) {
785
- if (typeof value !== "string") return value;
868
+ if (typeof value !== "string") {
869
+ const side = (v, mode2) => {
870
+ const r = resolveColorEntry(v, lookup);
871
+ return typeof r === "string" ? r : r[mode2];
872
+ };
873
+ return { light: side(value.light, "light"), dark: side(value.dark, "dark") };
874
+ }
786
875
  const slash = value.indexOf("/");
787
876
  const name = slash === -1 ? value : value.slice(0, slash);
788
877
  const opacity = slash === -1 ? void 0 : value.slice(slash + 1);
package/dist/index.mjs CHANGED
@@ -4,26 +4,26 @@ import {
4
4
  isKbachReady,
5
5
  isRuntimeCSSDisabled,
6
6
  kb
7
- } from "./chunk-DJKDEDPE.mjs";
7
+ } from "./chunk-K6AUD64N.mjs";
8
8
  import {
9
9
  applyKbachConfig,
10
- ensureColorVariablesInjected,
11
10
  getGlobalDarkMode,
12
11
  getGlobalThemeMode,
13
- parseHexRgb,
14
12
  resolveKbachConfig,
15
13
  seedDefaultMode,
16
14
  setGlobalThemeMode,
17
15
  subscribeGlobalDarkMode,
18
16
  toggleGlobalDarkMode
19
- } from "./chunk-43FOLRQA.mjs";
17
+ } from "./chunk-UK5S55DF.mjs";
20
18
  import {
21
19
  BASE_RESET,
22
20
  RESET_STYLE_ID,
23
21
  defaultTheme,
22
+ ensureColorVariablesInjected,
24
23
  getTheme,
24
+ parseHexRgb,
25
25
  setTheme
26
- } from "./chunk-OVKVZA7B.mjs";
26
+ } from "./chunk-FBYS4BI3.mjs";
27
27
 
28
28
  // src/KbachReset.tsx
29
29
  import { jsx } from "react/jsx-runtime";