@kbach/react 0.5.24 → 0.5.26

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.
@@ -3350,6 +3350,35 @@ var customVariants = new Proxy(
3350
3350
  // src/vite-plugin.ts
3351
3351
  var VIRTUAL_ID = "virtual:kbach/styles.css";
3352
3352
  var RESOLVED_ID = "\0virtual:kbach/styles.css";
3353
+ var KBACH_START = "/* kbach:start */";
3354
+ var KBACH_END = "/* kbach:end */";
3355
+ function findMainCSSFile(root) {
3356
+ const candidates = [
3357
+ (0, import_path.join)(root, "app", "app.css"),
3358
+ (0, import_path.join)(root, "src", "index.css"),
3359
+ (0, import_path.join)(root, "src", "app.css"),
3360
+ (0, import_path.join)(root, "app", "index.css")
3361
+ ];
3362
+ for (const c of candidates) {
3363
+ if ((0, import_fs.existsSync)(c)) return c;
3364
+ }
3365
+ return null;
3366
+ }
3367
+ function writeKbachToFile(filePath, css) {
3368
+ let existing = "";
3369
+ try {
3370
+ existing = (0, import_fs.readFileSync)(filePath, "utf-8");
3371
+ } catch {
3372
+ }
3373
+ const block = `${KBACH_START}
3374
+ ${css}
3375
+ ${KBACH_END}`;
3376
+ const re = new RegExp(`${KBACH_START}[\\s\\S]*?${KBACH_END}`);
3377
+ const next = existing.includes(KBACH_START) ? existing.replace(re, block) : existing ? `${existing}
3378
+
3379
+ ${block}` : block;
3380
+ if (next !== existing) (0, import_fs.writeFileSync)(filePath, next, "utf-8");
3381
+ }
3353
3382
  function toNumericScreens(screens) {
3354
3383
  const out = {};
3355
3384
  for (const [k, v] of Object.entries(screens)) {
@@ -3395,9 +3424,8 @@ function kbach(userConfig) {
3395
3424
  const cfg = buildConfig(userConfig ?? {});
3396
3425
  const screens = toNumericScreens(cfg.theme.screens ?? {});
3397
3426
  const tokenCSS = /* @__PURE__ */ new Map();
3398
- const processedCSSFiles = /* @__PURE__ */ new Set();
3399
3427
  let root = process.cwd();
3400
- let server = null;
3428
+ let mainCSSFile = null;
3401
3429
  function processToken(token) {
3402
3430
  if (tokenCSS.has(token)) return false;
3403
3431
  tokenCSS.set(token, generateClassCSS(token, cfg.theme, cfg.darkMode, screens));
@@ -3421,54 +3449,23 @@ function kbach(userConfig) {
3421
3449
  }
3422
3450
  return parts.join("\n");
3423
3451
  }
3424
- function invalidateCSSModules() {
3425
- if (!server) return;
3426
- for (const id of processedCSSFiles) {
3427
- const mod = server.moduleGraph?.getModuleById(id);
3428
- if (mod) server.moduleGraph.invalidateModule(mod);
3429
- }
3430
- server.hot?.send({ type: "update", updates: [...processedCSSFiles].map((id) => ({
3431
- type: "js-update",
3432
- path: id,
3433
- acceptedPath: id,
3434
- timestamp: Date.now()
3435
- })) });
3436
- }
3437
3452
  return {
3438
3453
  name: "kbach",
3439
3454
  enforce: "pre",
3440
3455
  configResolved(resolved) {
3441
3456
  root = resolved.root;
3442
3457
  },
3443
- configureServer(s) {
3444
- server = s;
3445
- },
3446
3458
  buildStart() {
3447
3459
  for (const dir of ["src", "app", "pages", "components", "views", "layouts"]) {
3448
3460
  scanDir((0, import_path.join)(root, dir), (code) => extractFromCode(code));
3449
3461
  }
3462
+ mainCSSFile = findMainCSSFile(root);
3463
+ if (mainCSSFile) writeKbachToFile(mainCSSFile, getAllCSS());
3450
3464
  },
3451
- // ── CSS transform: append generated rules to the user's CSS file ──────────
3452
- // Works exactly like Tailwind's PostCSS plugin:
3453
- // - Your app.css content stays untouched (empty or your own rules)
3454
- // - Kbach appends its generated rules to the transform output
3455
- // - Vite serves the result via its normal CSS pipeline (<link rel="stylesheet">)
3456
- // - In production, it lands in the extracted CSS bundle file
3457
3465
  transform(code, id) {
3458
3466
  const cleanId = id.split("?")[0];
3459
- if (cleanId.endsWith(".css") && !id.includes("node_modules") && !id.includes("\0")) {
3460
- processedCSSFiles.add(cleanId);
3461
- const kbachCSS = getAllCSS();
3462
- if (!kbachCSS) return null;
3463
- return { code: `${code}
3464
- /* kbach */
3465
- ${kbachCSS}`, map: null };
3466
- }
3467
3467
  if (/\.(tsx?|jsx?)$/.test(cleanId) && !id.includes("node_modules")) {
3468
- const added = extractFromCode(code);
3469
- if (added && server && processedCSSFiles.size > 0) {
3470
- setTimeout(() => invalidateCSSModules(), 0);
3471
- }
3468
+ extractFromCode(code);
3472
3469
  }
3473
3470
  },
3474
3471
  // ── Virtual module (opt-in explicit import) ───────────────────────────────
@@ -3478,15 +3475,14 @@ ${kbachCSS}`, map: null };
3478
3475
  load(id) {
3479
3476
  if (id === RESOLVED_ID) return getAllCSS();
3480
3477
  },
3481
- // ── HMR: invalidate CSS when new classes are found in changed files ───────
3482
- handleHotUpdate({ file, server: s }) {
3478
+ // ── HMR: write updated CSS to file when new classes are found ────────────
3479
+ // Vite's own file watcher detects the change and hot-reloads the CSS —
3480
+ // no manual invalidation needed.
3481
+ handleHotUpdate({ file }) {
3483
3482
  if (file.includes("node_modules") || !/\.(tsx?|jsx?)$/.test(file)) return;
3484
3483
  try {
3485
3484
  const added = extractFromCode((0, import_fs.readFileSync)(file, "utf-8"));
3486
- if (added) {
3487
- server = s;
3488
- invalidateCSSModules();
3489
- }
3485
+ if (added && mainCSSFile) writeKbachToFile(mainCSSFile, getAllCSS());
3490
3486
  } catch {
3491
3487
  }
3492
3488
  }
@@ -4,10 +4,39 @@ import {
4
4
  } from "./chunk-SOBLKZGE.mjs";
5
5
 
6
6
  // src/vite-plugin.ts
7
- import { readFileSync, readdirSync, statSync } from "fs";
7
+ import { readFileSync, writeFileSync, existsSync, readdirSync, statSync } from "fs";
8
8
  import { join } from "path";
9
9
  var VIRTUAL_ID = "virtual:kbach/styles.css";
10
10
  var RESOLVED_ID = "\0virtual:kbach/styles.css";
11
+ var KBACH_START = "/* kbach:start */";
12
+ var KBACH_END = "/* kbach:end */";
13
+ function findMainCSSFile(root) {
14
+ const candidates = [
15
+ join(root, "app", "app.css"),
16
+ join(root, "src", "index.css"),
17
+ join(root, "src", "app.css"),
18
+ join(root, "app", "index.css")
19
+ ];
20
+ for (const c of candidates) {
21
+ if (existsSync(c)) return c;
22
+ }
23
+ return null;
24
+ }
25
+ function writeKbachToFile(filePath, css) {
26
+ let existing = "";
27
+ try {
28
+ existing = readFileSync(filePath, "utf-8");
29
+ } catch {
30
+ }
31
+ const block = `${KBACH_START}
32
+ ${css}
33
+ ${KBACH_END}`;
34
+ const re = new RegExp(`${KBACH_START}[\\s\\S]*?${KBACH_END}`);
35
+ const next = existing.includes(KBACH_START) ? existing.replace(re, block) : existing ? `${existing}
36
+
37
+ ${block}` : block;
38
+ if (next !== existing) writeFileSync(filePath, next, "utf-8");
39
+ }
11
40
  function toNumericScreens(screens) {
12
41
  const out = {};
13
42
  for (const [k, v] of Object.entries(screens)) {
@@ -53,9 +82,8 @@ function kbach(userConfig) {
53
82
  const cfg = buildConfig(userConfig ?? {});
54
83
  const screens = toNumericScreens(cfg.theme.screens ?? {});
55
84
  const tokenCSS = /* @__PURE__ */ new Map();
56
- const processedCSSFiles = /* @__PURE__ */ new Set();
57
85
  let root = process.cwd();
58
- let server = null;
86
+ let mainCSSFile = null;
59
87
  function processToken(token) {
60
88
  if (tokenCSS.has(token)) return false;
61
89
  tokenCSS.set(token, generateClassCSS(token, cfg.theme, cfg.darkMode, screens));
@@ -79,54 +107,23 @@ function kbach(userConfig) {
79
107
  }
80
108
  return parts.join("\n");
81
109
  }
82
- function invalidateCSSModules() {
83
- if (!server) return;
84
- for (const id of processedCSSFiles) {
85
- const mod = server.moduleGraph?.getModuleById(id);
86
- if (mod) server.moduleGraph.invalidateModule(mod);
87
- }
88
- server.hot?.send({ type: "update", updates: [...processedCSSFiles].map((id) => ({
89
- type: "js-update",
90
- path: id,
91
- acceptedPath: id,
92
- timestamp: Date.now()
93
- })) });
94
- }
95
110
  return {
96
111
  name: "kbach",
97
112
  enforce: "pre",
98
113
  configResolved(resolved) {
99
114
  root = resolved.root;
100
115
  },
101
- configureServer(s) {
102
- server = s;
103
- },
104
116
  buildStart() {
105
117
  for (const dir of ["src", "app", "pages", "components", "views", "layouts"]) {
106
118
  scanDir(join(root, dir), (code) => extractFromCode(code));
107
119
  }
120
+ mainCSSFile = findMainCSSFile(root);
121
+ if (mainCSSFile) writeKbachToFile(mainCSSFile, getAllCSS());
108
122
  },
109
- // ── CSS transform: append generated rules to the user's CSS file ──────────
110
- // Works exactly like Tailwind's PostCSS plugin:
111
- // - Your app.css content stays untouched (empty or your own rules)
112
- // - Kbach appends its generated rules to the transform output
113
- // - Vite serves the result via its normal CSS pipeline (<link rel="stylesheet">)
114
- // - In production, it lands in the extracted CSS bundle file
115
123
  transform(code, id) {
116
124
  const cleanId = id.split("?")[0];
117
- if (cleanId.endsWith(".css") && !id.includes("node_modules") && !id.includes("\0")) {
118
- processedCSSFiles.add(cleanId);
119
- const kbachCSS = getAllCSS();
120
- if (!kbachCSS) return null;
121
- return { code: `${code}
122
- /* kbach */
123
- ${kbachCSS}`, map: null };
124
- }
125
125
  if (/\.(tsx?|jsx?)$/.test(cleanId) && !id.includes("node_modules")) {
126
- const added = extractFromCode(code);
127
- if (added && server && processedCSSFiles.size > 0) {
128
- setTimeout(() => invalidateCSSModules(), 0);
129
- }
126
+ extractFromCode(code);
130
127
  }
131
128
  },
132
129
  // ── Virtual module (opt-in explicit import) ───────────────────────────────
@@ -136,15 +133,14 @@ ${kbachCSS}`, map: null };
136
133
  load(id) {
137
134
  if (id === RESOLVED_ID) return getAllCSS();
138
135
  },
139
- // ── HMR: invalidate CSS when new classes are found in changed files ───────
140
- handleHotUpdate({ file, server: s }) {
136
+ // ── HMR: write updated CSS to file when new classes are found ────────────
137
+ // Vite's own file watcher detects the change and hot-reloads the CSS —
138
+ // no manual invalidation needed.
139
+ handleHotUpdate({ file }) {
141
140
  if (file.includes("node_modules") || !/\.(tsx?|jsx?)$/.test(file)) return;
142
141
  try {
143
142
  const added = extractFromCode(readFileSync(file, "utf-8"));
144
- if (added) {
145
- server = s;
146
- invalidateCSSModules();
147
- }
143
+ if (added && mainCSSFile) writeKbachToFile(mainCSSFile, getAllCSS());
148
144
  } catch {
149
145
  }
150
146
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kbach/react",
3
- "version": "0.5.24",
3
+ "version": "0.5.26",
4
4
  "description": "React / React Native components and hooks for the Kbach framework",
5
5
  "source": "./src/index.ts",
6
6
  "main": "./dist/index.js",