@kbach/react 0.5.5 → 0.5.7

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/README.md CHANGED
@@ -329,7 +329,7 @@ Available families: slate, gray, zinc, neutral, stone, red, orange, amber, yello
329
329
  | Category | Examples |
330
330
  |---|---|
331
331
  | Background | `bg-white`, `bg-gray-10`, `bg-blue-6`, `bg-[#fff]` |
332
- | Text | `text-sm`, `text-2xl`, `text-gray-10`, `font-bold` |
332
+ | Text | `text-sm`, `text-2xl`, `text-gray-10`, `font-bold`, `font-sans` |
333
333
  | Text wrap | `text-balance`, `text-pretty`, `text-nowrap`, `text-wrap` |
334
334
  | Line clamp | `line-clamp-3`, `line-clamp-none` |
335
335
  | Padding | `p-4`, `px-6`, `py-3` |
@@ -389,3 +389,44 @@ import { updateConfig } from '@kbach/react';
389
389
 
390
390
  updateConfig({ extend: { theme: { colors: { brand: { 6: '#6366f1' } } } } });
391
391
  ```
392
+
393
+ ### Font Family
394
+
395
+ Define custom font families and use them with `font-<name>`:
396
+
397
+ ```js
398
+ // kbach.config.js
399
+ module.exports = {
400
+ extend: {
401
+ fontFamily: {
402
+ // shorthand: extend.fontFamily is equivalent to extend.theme.fontFamily
403
+ sans: 'CormorantGaramond_400Regular',
404
+ 'sans-md': 'CormorantGaramond_500Medium',
405
+ 'sans-semi': 'CormorantGaramond_600SemiBold',
406
+ 'sans-bold': 'CormorantGaramond_700Bold',
407
+ },
408
+ },
409
+ };
410
+ ```
411
+
412
+ Use them as utilities:
413
+
414
+ ```jsx
415
+ <Text className="font-sans">Regular</Text>
416
+ <Text className="font-sans-md">Medium</Text>
417
+ <Text className="font-sans-bold">Bold</Text>
418
+ ```
419
+
420
+ **Global default font (web only):** When you set `fontFamily.sans` to anything other than `'System'`, Kbach automatically injects `body { font-family: <your-font> }` into the page — all text inherits it without needing `font-sans` on every element.
421
+
422
+ **React Native:** CSS inheritance does not exist in RN. Apply `font-sans` (or your base font utility) to each `Text` component, or use `styled()` to create a pre-styled text component:
423
+
424
+ ```jsx
425
+ // Define once
426
+ const Body = styled(Text, 'font-sans');
427
+ const Heading = styled(Text, 'font-sans-bold text-2xl');
428
+
429
+ // Use everywhere
430
+ <Body>Regular text</Body>
431
+ <Heading>Title</Heading>
432
+ ```
@@ -8,7 +8,7 @@ import {
8
8
  resolve,
9
9
  useConditionalWidth,
10
10
  useGlobalDarkMode
11
- } from "./chunk-D7Q7ZCOW.mjs";
11
+ } from "./chunk-YLT5TFLD.mjs";
12
12
 
13
13
  // src/jsx-runtime.tsx
14
14
  import { jsx as _jsx, jsxs as _jsxs, Fragment } from "react/jsx-runtime";
@@ -3005,6 +3005,24 @@ function injectRule(rule) {
3005
3005
  } catch {
3006
3006
  }
3007
3007
  }
3008
+ var _globalStyleEl = null;
3009
+ function getGlobalStyleEl() {
3010
+ if (_globalStyleEl) return _globalStyleEl;
3011
+ _globalStyleEl = document.createElement("style");
3012
+ _globalStyleEl.setAttribute("data-kbach-global", "");
3013
+ document.head.insertBefore(_globalStyleEl, getStyleEl());
3014
+ return _globalStyleEl;
3015
+ }
3016
+ function injectGlobalStyles(theme) {
3017
+ if (typeof document === "undefined") return;
3018
+ const rules = [];
3019
+ const ff = theme.fontFamily;
3020
+ if (ff.sans && ff.sans !== "System") {
3021
+ const family = Array.isArray(ff.sans) ? ff.sans.join(", ") : ff.sans;
3022
+ rules.push(`body { font-family: ${family}; }`);
3023
+ }
3024
+ getGlobalStyleEl().textContent = rules.join("\n");
3025
+ }
3008
3026
  var MODIFIER_TO_PSEUDO = {
3009
3027
  hover: ":hover",
3010
3028
  focus: ":focus",
@@ -3384,16 +3402,21 @@ function buildConfig(userConfig) {
3384
3402
  if (userConfig.theme) {
3385
3403
  theme = deepMerge(theme, userConfig.theme);
3386
3404
  }
3387
- if (userConfig.extend?.theme) {
3388
- const ext = userConfig.extend.theme;
3389
- for (const [key, value] of Object.entries(ext)) {
3390
- if (value !== null && typeof value === "object" && !Array.isArray(value)) {
3391
- theme[key] = deepMerge(
3392
- theme[key] ?? {},
3393
- value
3394
- );
3395
- } else {
3396
- theme[key] = value;
3405
+ if (userConfig.extend) {
3406
+ const { theme: nestedTheme, ...directKeys } = userConfig.extend;
3407
+ const extSources = [];
3408
+ if (nestedTheme) extSources.push(nestedTheme);
3409
+ if (Object.keys(directKeys).length) extSources.push(directKeys);
3410
+ for (const ext of extSources) {
3411
+ for (const [key, value] of Object.entries(ext)) {
3412
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
3413
+ theme[key] = deepMerge(
3414
+ theme[key] ?? {},
3415
+ value
3416
+ );
3417
+ } else if (value !== void 0) {
3418
+ theme[key] = value;
3419
+ }
3397
3420
  }
3398
3421
  }
3399
3422
  }
@@ -3409,6 +3432,7 @@ function buildConfig(userConfig) {
3409
3432
  for (const plugin of resolved.plugins) {
3410
3433
  plugin(pluginAPI);
3411
3434
  }
3435
+ injectGlobalStyles(resolved.theme);
3412
3436
  return resolved;
3413
3437
  }
3414
3438
  function makePluginAPI(theme) {
package/dist/index.d.mts CHANGED
@@ -57,9 +57,10 @@ interface PluginAPI {
57
57
  interface FrameworkConfig {
58
58
  darkMode?: DarkMode;
59
59
  theme?: Partial<ThemeConfig>;
60
+ /** Additive theme extension — accepts either `extend.theme.X` or `extend.X` directly. */
60
61
  extend?: {
61
62
  theme?: Partial<ThemeConfig>;
62
- };
63
+ } & Partial<ThemeConfig>;
63
64
  plugins?: Array<(api: PluginAPI) => void>;
64
65
  content?: string[];
65
66
  }
package/dist/index.d.ts CHANGED
@@ -57,9 +57,10 @@ interface PluginAPI {
57
57
  interface FrameworkConfig {
58
58
  darkMode?: DarkMode;
59
59
  theme?: Partial<ThemeConfig>;
60
+ /** Additive theme extension — accepts either `extend.theme.X` or `extend.X` directly. */
60
61
  extend?: {
61
62
  theme?: Partial<ThemeConfig>;
62
- };
63
+ } & Partial<ThemeConfig>;
63
64
  plugins?: Array<(api: PluginAPI) => void>;
64
65
  content?: string[];
65
66
  }
package/dist/index.js CHANGED
@@ -3135,6 +3135,24 @@ function injectRule(rule) {
3135
3135
  } catch {
3136
3136
  }
3137
3137
  }
3138
+ var _globalStyleEl = null;
3139
+ function getGlobalStyleEl() {
3140
+ if (_globalStyleEl) return _globalStyleEl;
3141
+ _globalStyleEl = document.createElement("style");
3142
+ _globalStyleEl.setAttribute("data-kbach-global", "");
3143
+ document.head.insertBefore(_globalStyleEl, getStyleEl());
3144
+ return _globalStyleEl;
3145
+ }
3146
+ function injectGlobalStyles(theme) {
3147
+ if (typeof document === "undefined") return;
3148
+ const rules = [];
3149
+ const ff = theme.fontFamily;
3150
+ if (ff.sans && ff.sans !== "System") {
3151
+ const family = Array.isArray(ff.sans) ? ff.sans.join(", ") : ff.sans;
3152
+ rules.push(`body { font-family: ${family}; }`);
3153
+ }
3154
+ getGlobalStyleEl().textContent = rules.join("\n");
3155
+ }
3138
3156
  var MODIFIER_TO_PSEUDO = {
3139
3157
  hover: ":hover",
3140
3158
  focus: ":focus",
@@ -3514,16 +3532,21 @@ function buildConfig(userConfig) {
3514
3532
  if (userConfig.theme) {
3515
3533
  theme = deepMerge(theme, userConfig.theme);
3516
3534
  }
3517
- if (userConfig.extend?.theme) {
3518
- const ext = userConfig.extend.theme;
3519
- for (const [key, value] of Object.entries(ext)) {
3520
- if (value !== null && typeof value === "object" && !Array.isArray(value)) {
3521
- theme[key] = deepMerge(
3522
- theme[key] ?? {},
3523
- value
3524
- );
3525
- } else {
3526
- theme[key] = value;
3535
+ if (userConfig.extend) {
3536
+ const { theme: nestedTheme, ...directKeys } = userConfig.extend;
3537
+ const extSources = [];
3538
+ if (nestedTheme) extSources.push(nestedTheme);
3539
+ if (Object.keys(directKeys).length) extSources.push(directKeys);
3540
+ for (const ext of extSources) {
3541
+ for (const [key, value] of Object.entries(ext)) {
3542
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
3543
+ theme[key] = deepMerge(
3544
+ theme[key] ?? {},
3545
+ value
3546
+ );
3547
+ } else if (value !== void 0) {
3548
+ theme[key] = value;
3549
+ }
3527
3550
  }
3528
3551
  }
3529
3552
  }
@@ -3539,6 +3562,7 @@ function buildConfig(userConfig) {
3539
3562
  for (const plugin of resolved.plugins) {
3540
3563
  plugin(pluginAPI);
3541
3564
  }
3565
+ injectGlobalStyles(resolved.theme);
3542
3566
  return resolved;
3543
3567
  }
3544
3568
  function makePluginAPI(theme) {
package/dist/index.mjs CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  useConditionalWidth,
24
24
  useGlobalDarkMode,
25
25
  useGlobalWidth
26
- } from "./chunk-D7Q7ZCOW.mjs";
26
+ } from "./chunk-YLT5TFLD.mjs";
27
27
 
28
28
  // src/context.tsx
29
29
  import { createContext, useContext } from "react";
@@ -3026,6 +3026,24 @@ function injectRule(rule) {
3026
3026
  } catch {
3027
3027
  }
3028
3028
  }
3029
+ var _globalStyleEl = null;
3030
+ function getGlobalStyleEl() {
3031
+ if (_globalStyleEl) return _globalStyleEl;
3032
+ _globalStyleEl = document.createElement("style");
3033
+ _globalStyleEl.setAttribute("data-kbach-global", "");
3034
+ document.head.insertBefore(_globalStyleEl, getStyleEl());
3035
+ return _globalStyleEl;
3036
+ }
3037
+ function injectGlobalStyles(theme) {
3038
+ if (typeof document === "undefined") return;
3039
+ const rules = [];
3040
+ const ff = theme.fontFamily;
3041
+ if (ff.sans && ff.sans !== "System") {
3042
+ const family = Array.isArray(ff.sans) ? ff.sans.join(", ") : ff.sans;
3043
+ rules.push(`body { font-family: ${family}; }`);
3044
+ }
3045
+ getGlobalStyleEl().textContent = rules.join("\n");
3046
+ }
3029
3047
  var MODIFIER_TO_PSEUDO = {
3030
3048
  hover: ":hover",
3031
3049
  focus: ":focus",
@@ -3397,16 +3415,21 @@ function buildConfig(userConfig) {
3397
3415
  if (userConfig.theme) {
3398
3416
  theme = deepMerge(theme, userConfig.theme);
3399
3417
  }
3400
- if (userConfig.extend?.theme) {
3401
- const ext = userConfig.extend.theme;
3402
- for (const [key, value] of Object.entries(ext)) {
3403
- if (value !== null && typeof value === "object" && !Array.isArray(value)) {
3404
- theme[key] = deepMerge(
3405
- theme[key] ?? {},
3406
- value
3407
- );
3408
- } else {
3409
- theme[key] = value;
3418
+ if (userConfig.extend) {
3419
+ const { theme: nestedTheme, ...directKeys } = userConfig.extend;
3420
+ const extSources = [];
3421
+ if (nestedTheme) extSources.push(nestedTheme);
3422
+ if (Object.keys(directKeys).length) extSources.push(directKeys);
3423
+ for (const ext of extSources) {
3424
+ for (const [key, value] of Object.entries(ext)) {
3425
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
3426
+ theme[key] = deepMerge(
3427
+ theme[key] ?? {},
3428
+ value
3429
+ );
3430
+ } else if (value !== void 0) {
3431
+ theme[key] = value;
3432
+ }
3410
3433
  }
3411
3434
  }
3412
3435
  }
@@ -3422,6 +3445,7 @@ function buildConfig(userConfig) {
3422
3445
  for (const plugin of resolved.plugins) {
3423
3446
  plugin(pluginAPI);
3424
3447
  }
3448
+ injectGlobalStyles(resolved.theme);
3425
3449
  return resolved;
3426
3450
  }
3427
3451
  function makePluginAPI(theme) {
@@ -2,8 +2,8 @@ import {
2
2
  Fragment,
3
3
  jsx,
4
4
  jsxs
5
- } from "./chunk-UR4DTYE3.mjs";
6
- import "./chunk-D7Q7ZCOW.mjs";
5
+ } from "./chunk-3SF5YHWG.mjs";
6
+ import "./chunk-YLT5TFLD.mjs";
7
7
 
8
8
  // src/jsx-dev-runtime.tsx
9
9
  function jsxDEV(type, props, key, isStaticChildren, _source, _self) {
@@ -3025,6 +3025,24 @@ function injectRule(rule) {
3025
3025
  } catch {
3026
3026
  }
3027
3027
  }
3028
+ var _globalStyleEl = null;
3029
+ function getGlobalStyleEl() {
3030
+ if (_globalStyleEl) return _globalStyleEl;
3031
+ _globalStyleEl = document.createElement("style");
3032
+ _globalStyleEl.setAttribute("data-kbach-global", "");
3033
+ document.head.insertBefore(_globalStyleEl, getStyleEl());
3034
+ return _globalStyleEl;
3035
+ }
3036
+ function injectGlobalStyles(theme) {
3037
+ if (typeof document === "undefined") return;
3038
+ const rules = [];
3039
+ const ff = theme.fontFamily;
3040
+ if (ff.sans && ff.sans !== "System") {
3041
+ const family = Array.isArray(ff.sans) ? ff.sans.join(", ") : ff.sans;
3042
+ rules.push(`body { font-family: ${family}; }`);
3043
+ }
3044
+ getGlobalStyleEl().textContent = rules.join("\n");
3045
+ }
3028
3046
  var MODIFIER_TO_PSEUDO = {
3029
3047
  hover: ":hover",
3030
3048
  focus: ":focus",
@@ -3396,16 +3414,21 @@ function buildConfig(userConfig) {
3396
3414
  if (userConfig.theme) {
3397
3415
  theme = deepMerge(theme, userConfig.theme);
3398
3416
  }
3399
- if (userConfig.extend?.theme) {
3400
- const ext = userConfig.extend.theme;
3401
- for (const [key, value] of Object.entries(ext)) {
3402
- if (value !== null && typeof value === "object" && !Array.isArray(value)) {
3403
- theme[key] = deepMerge(
3404
- theme[key] ?? {},
3405
- value
3406
- );
3407
- } else {
3408
- theme[key] = value;
3417
+ if (userConfig.extend) {
3418
+ const { theme: nestedTheme, ...directKeys } = userConfig.extend;
3419
+ const extSources = [];
3420
+ if (nestedTheme) extSources.push(nestedTheme);
3421
+ if (Object.keys(directKeys).length) extSources.push(directKeys);
3422
+ for (const ext of extSources) {
3423
+ for (const [key, value] of Object.entries(ext)) {
3424
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
3425
+ theme[key] = deepMerge(
3426
+ theme[key] ?? {},
3427
+ value
3428
+ );
3429
+ } else if (value !== void 0) {
3430
+ theme[key] = value;
3431
+ }
3409
3432
  }
3410
3433
  }
3411
3434
  }
@@ -3421,6 +3444,7 @@ function buildConfig(userConfig) {
3421
3444
  for (const plugin of resolved.plugins) {
3422
3445
  plugin(pluginAPI);
3423
3446
  }
3447
+ injectGlobalStyles(resolved.theme);
3424
3448
  return resolved;
3425
3449
  }
3426
3450
  function makePluginAPI(theme) {
@@ -2,8 +2,8 @@ import {
2
2
  Fragment,
3
3
  jsx,
4
4
  jsxs
5
- } from "./chunk-UR4DTYE3.mjs";
6
- import "./chunk-D7Q7ZCOW.mjs";
5
+ } from "./chunk-3SF5YHWG.mjs";
6
+ import "./chunk-YLT5TFLD.mjs";
7
7
  export {
8
8
  Fragment,
9
9
  jsx,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kbach/react",
3
- "version": "0.5.5",
3
+ "version": "0.5.7",
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",