@kbach/react 0.5.28 → 0.5.30

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.
@@ -3448,8 +3448,9 @@ function writeKbachToFile(filePath, css) {
3448
3448
  const block = `${KBACH_START}
3449
3449
  ${css}
3450
3450
  ${KBACH_END}`;
3451
- const re = new RegExp(`${KBACH_START}[\\s\\S]*?${KBACH_END}`);
3452
- const next = existing.includes(KBACH_START) ? existing.replace(re, block) : existing ? `${existing}
3451
+ const start = existing.indexOf(KBACH_START);
3452
+ const end = existing.indexOf(KBACH_END);
3453
+ const next = start !== -1 && end !== -1 ? existing.slice(0, start) + block + existing.slice(end + KBACH_END.length) : existing ? `${existing}
3453
3454
 
3454
3455
  ${block}` : block;
3455
3456
  if (next !== existing) (0, import_fs.writeFileSync)(filePath, next, "utf-8");
@@ -3469,7 +3470,7 @@ function scanDir(dir, onFile) {
3469
3470
  try {
3470
3471
  const st = (0, import_fs.statSync)(full);
3471
3472
  if (st.isDirectory()) scanDir(full, onFile);
3472
- else if (/\.(tsx?|jsx?)$/.test(entry)) onFile((0, import_fs.readFileSync)(full, "utf-8"));
3473
+ else if (/\.(tsx?|jsx?)$/.test(entry)) onFile((0, import_fs.readFileSync)(full, "utf-8"), full);
3473
3474
  } catch {
3474
3475
  }
3475
3476
  }
@@ -3489,20 +3490,35 @@ function extractClassStrings(code) {
3489
3490
  function kbach(userConfig) {
3490
3491
  const cfg = buildConfig(userConfig ?? {});
3491
3492
  const screens = toNumericScreens(cfg.theme.screens ?? {});
3493
+ const fileTokens = /* @__PURE__ */ new Map();
3492
3494
  const tokenCSS = /* @__PURE__ */ new Map();
3493
3495
  let root = process.cwd();
3494
3496
  let mainCSSFile = null;
3495
- function processToken(token) {
3496
- if (tokenCSS.has(token)) return false;
3497
- tokenCSS.set(token, generateClassCSS(token, cfg.theme, cfg.darkMode, screens));
3498
- return true;
3499
- }
3500
- function extractFromCode(code) {
3501
- let added = false;
3497
+ function extractTokensFromCode(code) {
3498
+ const tokens = /* @__PURE__ */ new Set();
3502
3499
  for (const cls of extractClassStrings(code))
3503
3500
  for (const token of cls.split(/\s+/).filter(Boolean))
3504
- if (processToken(token)) added = true;
3505
- return added;
3501
+ tokens.add(token);
3502
+ return tokens;
3503
+ }
3504
+ function rebuildTokenCSS() {
3505
+ const live = /* @__PURE__ */ new Set();
3506
+ for (const tokens of fileTokens.values())
3507
+ for (const t of tokens) live.add(t);
3508
+ let changed = false;
3509
+ for (const token of tokenCSS.keys()) {
3510
+ if (!live.has(token)) {
3511
+ tokenCSS.delete(token);
3512
+ changed = true;
3513
+ }
3514
+ }
3515
+ for (const token of live) {
3516
+ if (!tokenCSS.has(token)) {
3517
+ tokenCSS.set(token, generateClassCSS(token, cfg.theme, cfg.darkMode, screens));
3518
+ changed = true;
3519
+ }
3520
+ }
3521
+ return changed;
3506
3522
  }
3507
3523
  function getFormattedCSS() {
3508
3524
  return formatKbachCSS(tokenCSS, cfg.theme);
@@ -3515,14 +3531,15 @@ function kbach(userConfig) {
3515
3531
  },
3516
3532
  buildStart() {
3517
3533
  for (const dir of ["src", "app", "pages", "components", "views", "layouts"])
3518
- scanDir((0, import_path.join)(root, dir), (code) => extractFromCode(code));
3534
+ scanDir((0, import_path.join)(root, dir), (code, filePath) => fileTokens.set(filePath, extractTokensFromCode(code)));
3535
+ rebuildTokenCSS();
3519
3536
  mainCSSFile = findMainCSSFile(root);
3520
3537
  if (mainCSSFile) writeKbachToFile(mainCSSFile, getFormattedCSS());
3521
3538
  },
3522
3539
  transform(code, id) {
3523
- const cleanId = id.split("?")[0];
3524
- if (/\.(tsx?|jsx?)$/.test(cleanId) && !id.includes("node_modules"))
3525
- extractFromCode(code);
3540
+ const filePath = id.split("?")[0];
3541
+ if (/\.(tsx?|jsx?)$/.test(filePath) && !id.includes("node_modules"))
3542
+ fileTokens.set(filePath, extractTokensFromCode(code));
3526
3543
  },
3527
3544
  resolveId(id) {
3528
3545
  if (id === VIRTUAL_ID) return RESOLVED_ID;
@@ -3533,8 +3550,8 @@ function kbach(userConfig) {
3533
3550
  handleHotUpdate({ file }) {
3534
3551
  if (file.includes("node_modules") || !/\.(tsx?|jsx?)$/.test(file)) return;
3535
3552
  try {
3536
- const added = extractFromCode((0, import_fs.readFileSync)(file, "utf-8"));
3537
- if (added && mainCSSFile) writeKbachToFile(mainCSSFile, getFormattedCSS());
3553
+ fileTokens.set(file, extractTokensFromCode((0, import_fs.readFileSync)(file, "utf-8")));
3554
+ if (rebuildTokenCSS() && mainCSSFile) writeKbachToFile(mainCSSFile, getFormattedCSS());
3538
3555
  } catch {
3539
3556
  }
3540
3557
  }
@@ -106,8 +106,9 @@ function writeKbachToFile(filePath, css) {
106
106
  const block = `${KBACH_START}
107
107
  ${css}
108
108
  ${KBACH_END}`;
109
- const re = new RegExp(`${KBACH_START}[\\s\\S]*?${KBACH_END}`);
110
- const next = existing.includes(KBACH_START) ? existing.replace(re, block) : existing ? `${existing}
109
+ const start = existing.indexOf(KBACH_START);
110
+ const end = existing.indexOf(KBACH_END);
111
+ const next = start !== -1 && end !== -1 ? existing.slice(0, start) + block + existing.slice(end + KBACH_END.length) : existing ? `${existing}
111
112
 
112
113
  ${block}` : block;
113
114
  if (next !== existing) writeFileSync(filePath, next, "utf-8");
@@ -127,7 +128,7 @@ function scanDir(dir, onFile) {
127
128
  try {
128
129
  const st = statSync(full);
129
130
  if (st.isDirectory()) scanDir(full, onFile);
130
- else if (/\.(tsx?|jsx?)$/.test(entry)) onFile(readFileSync(full, "utf-8"));
131
+ else if (/\.(tsx?|jsx?)$/.test(entry)) onFile(readFileSync(full, "utf-8"), full);
131
132
  } catch {
132
133
  }
133
134
  }
@@ -147,20 +148,35 @@ function extractClassStrings(code) {
147
148
  function kbach(userConfig) {
148
149
  const cfg = buildConfig(userConfig ?? {});
149
150
  const screens = toNumericScreens(cfg.theme.screens ?? {});
151
+ const fileTokens = /* @__PURE__ */ new Map();
150
152
  const tokenCSS = /* @__PURE__ */ new Map();
151
153
  let root = process.cwd();
152
154
  let mainCSSFile = null;
153
- function processToken(token) {
154
- if (tokenCSS.has(token)) return false;
155
- tokenCSS.set(token, generateClassCSS(token, cfg.theme, cfg.darkMode, screens));
156
- return true;
157
- }
158
- function extractFromCode(code) {
159
- let added = false;
155
+ function extractTokensFromCode(code) {
156
+ const tokens = /* @__PURE__ */ new Set();
160
157
  for (const cls of extractClassStrings(code))
161
158
  for (const token of cls.split(/\s+/).filter(Boolean))
162
- if (processToken(token)) added = true;
163
- return added;
159
+ tokens.add(token);
160
+ return tokens;
161
+ }
162
+ function rebuildTokenCSS() {
163
+ const live = /* @__PURE__ */ new Set();
164
+ for (const tokens of fileTokens.values())
165
+ for (const t of tokens) live.add(t);
166
+ let changed = false;
167
+ for (const token of tokenCSS.keys()) {
168
+ if (!live.has(token)) {
169
+ tokenCSS.delete(token);
170
+ changed = true;
171
+ }
172
+ }
173
+ for (const token of live) {
174
+ if (!tokenCSS.has(token)) {
175
+ tokenCSS.set(token, generateClassCSS(token, cfg.theme, cfg.darkMode, screens));
176
+ changed = true;
177
+ }
178
+ }
179
+ return changed;
164
180
  }
165
181
  function getFormattedCSS() {
166
182
  return formatKbachCSS(tokenCSS, cfg.theme);
@@ -173,14 +189,15 @@ function kbach(userConfig) {
173
189
  },
174
190
  buildStart() {
175
191
  for (const dir of ["src", "app", "pages", "components", "views", "layouts"])
176
- scanDir(join(root, dir), (code) => extractFromCode(code));
192
+ scanDir(join(root, dir), (code, filePath) => fileTokens.set(filePath, extractTokensFromCode(code)));
193
+ rebuildTokenCSS();
177
194
  mainCSSFile = findMainCSSFile(root);
178
195
  if (mainCSSFile) writeKbachToFile(mainCSSFile, getFormattedCSS());
179
196
  },
180
197
  transform(code, id) {
181
- const cleanId = id.split("?")[0];
182
- if (/\.(tsx?|jsx?)$/.test(cleanId) && !id.includes("node_modules"))
183
- extractFromCode(code);
198
+ const filePath = id.split("?")[0];
199
+ if (/\.(tsx?|jsx?)$/.test(filePath) && !id.includes("node_modules"))
200
+ fileTokens.set(filePath, extractTokensFromCode(code));
184
201
  },
185
202
  resolveId(id) {
186
203
  if (id === VIRTUAL_ID) return RESOLVED_ID;
@@ -191,8 +208,8 @@ function kbach(userConfig) {
191
208
  handleHotUpdate({ file }) {
192
209
  if (file.includes("node_modules") || !/\.(tsx?|jsx?)$/.test(file)) return;
193
210
  try {
194
- const added = extractFromCode(readFileSync(file, "utf-8"));
195
- if (added && mainCSSFile) writeKbachToFile(mainCSSFile, getFormattedCSS());
211
+ fileTokens.set(file, extractTokensFromCode(readFileSync(file, "utf-8")));
212
+ if (rebuildTokenCSS() && mainCSSFile) writeKbachToFile(mainCSSFile, getFormattedCSS());
196
213
  } catch {
197
214
  }
198
215
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kbach/react",
3
- "version": "0.5.28",
3
+ "version": "0.5.30",
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",