@kbach/react-native 1.0.0-beta.8 → 1.0.0-beta.9
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 +67 -235
- package/android/src/main/jniLibs/arm64-v8a/libkbach_core_engine.so +0 -0
- package/android/src/main/jniLibs/x86_64/libkbach_core_engine.so +0 -0
- package/dist/{chunk-KV3ZIXSH.mjs → chunk-DOWW44F7.mjs} +1 -1
- package/dist/chunk-H5Z24XX5.mjs +192 -0
- package/dist/{chunk-4BXM3QUV.mjs → chunk-HK6PDJJK.mjs} +21 -6
- package/dist/{chunk-JR3BLUAV.mjs → chunk-SY5OAY2C.mjs} +11 -4
- package/dist/chunk-X4UQCEOE.mjs +186 -0
- package/dist/{chunk-OIW7OQWO.mjs → chunk-YOC3SHF5.mjs} +1 -1
- package/dist/index.d.mts +4 -5
- package/dist/index.d.ts +4 -5
- package/dist/index.js +176 -39
- package/dist/index.mjs +9 -5
- package/dist/index.web.d.mts +1 -1
- package/dist/index.web.d.ts +1 -1
- package/dist/index.web.js +171 -39
- package/dist/index.web.mjs +9 -5
- package/dist/jsx-dev-runtime.js +31 -9
- package/dist/jsx-dev-runtime.mjs +3 -3
- package/dist/jsx-dev-runtime.web.js +22 -7
- package/dist/jsx-dev-runtime.web.mjs +3 -3
- package/dist/jsx-runtime.js +31 -9
- package/dist/jsx-runtime.mjs +3 -3
- package/dist/jsx-runtime.web.js +22 -7
- package/dist/jsx-runtime.web.mjs +3 -3
- package/dist/useColors-CeP5_HvM.d.mts +230 -0
- package/dist/useColors-CeP5_HvM.d.ts +230 -0
- package/package.json +1 -1
- package/src/babel-plugin.js +74 -2
- package/dist/ThemeContext-Dc5AC-m0.d.mts +0 -98
- package/dist/ThemeContext-Dc5AC-m0.d.ts +0 -98
- package/dist/chunk-CGU7UM2F.mjs +0 -66
- package/dist/chunk-JS5KIGAB.mjs +0 -192
|
@@ -280,11 +280,13 @@ var defaultTheme = {
|
|
|
280
280
|
colors: PALETTE,
|
|
281
281
|
// Real Tailwind's default spacing scale in full — every step is exactly
|
|
282
282
|
// `n * 4px`, including the fractional `.5` steps (`1.5` -> 6px, `2.5` ->
|
|
283
|
-
// 10px, `3.5` -> 14px) and the "px" literal (a bare 1px).
|
|
284
|
-
//
|
|
285
|
-
//
|
|
286
|
-
// `
|
|
287
|
-
//
|
|
283
|
+
// 10px, `3.5` -> 14px) and the "px" literal (a bare 1px). Only the
|
|
284
|
+
// "usual stops", though — `jsEngine/shared.ts`'s `spacingPx` (and the
|
|
285
|
+
// native Rust dispatcher's own `spacing_px`) falls back to Tailwind v4's
|
|
286
|
+
// live `n * 4px` formula for any bare numeric step not listed here
|
|
287
|
+
// (`p-0.25`, `w-13`, ...), so this table names the common values and
|
|
288
|
+
// gives a theme override something to target, not the full resolvable
|
|
289
|
+
// set. Mirrors @kbach/react's theme.ts exactly.
|
|
288
290
|
spacing: {
|
|
289
291
|
"0": 0,
|
|
290
292
|
"px": 1,
|
|
@@ -329,7 +331,20 @@ var defaultTheme = {
|
|
|
329
331
|
xl: 1280,
|
|
330
332
|
"2xl": 1536
|
|
331
333
|
},
|
|
332
|
-
|
|
334
|
+
// Byte-for-byte the same three stacks
|
|
335
|
+
// packages/core-engine/src/resolvers/typography.rs's `font_family_value`
|
|
336
|
+
// falls back to. On native these three still effectively no-op (see
|
|
337
|
+
// `first_font_name`'s own doc comment for why a generic CSS keyword
|
|
338
|
+
// isn't a real loadable font) — only a caller-configured custom name
|
|
339
|
+
// changes native rendering; Expo Web uses the full stack as-is.
|
|
340
|
+
fontFamily: {
|
|
341
|
+
sans: 'ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',
|
|
342
|
+
serif: 'ui-serif, Georgia, Cambria, "Times New Roman", Times, serif',
|
|
343
|
+
mono: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace'
|
|
344
|
+
},
|
|
345
|
+
darkMode: "attribute",
|
|
346
|
+
// Empty by default, matching real Tailwind's own defaults.
|
|
347
|
+
container: {}
|
|
333
348
|
};
|
|
334
349
|
var activeTheme = defaultTheme;
|
|
335
350
|
var activeThemeJson = JSON.stringify(defaultTheme);
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
getTheme,
|
|
6
6
|
getThemeJson
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-HK6PDJJK.mjs";
|
|
8
8
|
|
|
9
9
|
// src/nativeBridge.ts
|
|
10
10
|
import { Dimensions, TurboModuleRegistry } from "react-native";
|
|
@@ -259,6 +259,12 @@ function parseClass(token) {
|
|
|
259
259
|
function decl(property, value) {
|
|
260
260
|
return { property, value };
|
|
261
261
|
}
|
|
262
|
+
function spacingPx(theme, value) {
|
|
263
|
+
const fromTable = theme.spacing[value];
|
|
264
|
+
if (fromTable !== void 0) return fromTable;
|
|
265
|
+
const n = Number(value);
|
|
266
|
+
return Number.isFinite(n) && value.trim() !== "" ? n * 4 : void 0;
|
|
267
|
+
}
|
|
262
268
|
function resolveLength(theme, parsed) {
|
|
263
269
|
if (parsed.negative) return null;
|
|
264
270
|
const value = parsed.value;
|
|
@@ -266,7 +272,7 @@ function resolveLength(theme, parsed) {
|
|
|
266
272
|
if (parsed.isArbitrary) return value;
|
|
267
273
|
if (value === "full") return "100%";
|
|
268
274
|
if (value === "auto") return "auto";
|
|
269
|
-
const px = theme
|
|
275
|
+
const px = spacingPx(theme, value);
|
|
270
276
|
return px === void 0 ? null : `${px}px`;
|
|
271
277
|
}
|
|
272
278
|
function resolveNegatableLength(theme, parsed) {
|
|
@@ -274,7 +280,7 @@ function resolveNegatableLength(theme, parsed) {
|
|
|
274
280
|
if (parsed.isArbitrary) return null;
|
|
275
281
|
const value = parsed.value;
|
|
276
282
|
if (value === null) return null;
|
|
277
|
-
const px = theme
|
|
283
|
+
const px = spacingPx(theme, value);
|
|
278
284
|
if (px === void 0) return null;
|
|
279
285
|
if (px === 0) return "0px";
|
|
280
286
|
return `-${px}px`;
|
|
@@ -633,7 +639,8 @@ function resolve2(parsed, theme) {
|
|
|
633
639
|
|
|
634
640
|
// src/jsEngine/resolvers/color.ts
|
|
635
641
|
function lookupHex(theme, key) {
|
|
636
|
-
|
|
642
|
+
const entry = theme.colors[key];
|
|
643
|
+
return typeof entry === "string" ? entry : null;
|
|
637
644
|
}
|
|
638
645
|
|
|
639
646
|
// src/jsEngine/resolvers/border.ts
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getGlobalDarkMode,
|
|
3
|
+
getGlobalThemeMode,
|
|
4
|
+
seedDefaultMode,
|
|
5
|
+
setGlobalThemeMode,
|
|
6
|
+
subscribeGlobalDarkMode,
|
|
7
|
+
toggleGlobalDarkMode
|
|
8
|
+
} from "./chunk-Z664AKW7.mjs";
|
|
9
|
+
import {
|
|
10
|
+
defaultTheme,
|
|
11
|
+
getTheme,
|
|
12
|
+
setTheme
|
|
13
|
+
} from "./chunk-HK6PDJJK.mjs";
|
|
14
|
+
|
|
15
|
+
// src/config.ts
|
|
16
|
+
function parseHexRgb(hex) {
|
|
17
|
+
const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(hex.trim());
|
|
18
|
+
if (!m) return null;
|
|
19
|
+
let h = m[1];
|
|
20
|
+
if (h.length === 3) h = h.split("").map((c) => c + c).join("");
|
|
21
|
+
const n = parseInt(h, 16);
|
|
22
|
+
return [n >> 16 & 255, n >> 8 & 255, n & 255];
|
|
23
|
+
}
|
|
24
|
+
function applyOpacityToHex(hex, opacityText) {
|
|
25
|
+
const rgb = parseHexRgb(hex);
|
|
26
|
+
if (!rgb) return hex;
|
|
27
|
+
const a = Number(opacityText) / 100;
|
|
28
|
+
const clamped = Number.isFinite(a) ? Math.min(1, Math.max(0, a)) : 1;
|
|
29
|
+
return `rgba(${rgb.join(",")},${clamped})`;
|
|
30
|
+
}
|
|
31
|
+
function resolveColorEntry(value, lookup) {
|
|
32
|
+
const slash = value.indexOf("/");
|
|
33
|
+
const name = slash === -1 ? value : value.slice(0, slash);
|
|
34
|
+
const opacity = slash === -1 ? void 0 : value.slice(slash + 1);
|
|
35
|
+
const base = lookup(name);
|
|
36
|
+
if (base === void 0) return value;
|
|
37
|
+
return opacity === void 0 ? base : applyOpacityToHex(base, opacity);
|
|
38
|
+
}
|
|
39
|
+
function resolveColors(extend, existing) {
|
|
40
|
+
const resolved = {};
|
|
41
|
+
const lookup = (name) => {
|
|
42
|
+
const found = resolved[name] ?? existing[name];
|
|
43
|
+
return typeof found === "string" ? found : void 0;
|
|
44
|
+
};
|
|
45
|
+
for (const [name, value] of Object.entries(extend)) {
|
|
46
|
+
resolved[name] = resolveColorEntry(value, lookup);
|
|
47
|
+
}
|
|
48
|
+
return resolved;
|
|
49
|
+
}
|
|
50
|
+
function resolveKbachConfig(config) {
|
|
51
|
+
let theme = { ...defaultTheme, ...config.theme };
|
|
52
|
+
if (config.extend?.colors) {
|
|
53
|
+
theme = { ...theme, colors: { ...theme.colors, ...resolveColors(config.extend.colors, theme.colors) } };
|
|
54
|
+
}
|
|
55
|
+
if (config.extend?.spacing) {
|
|
56
|
+
theme = { ...theme, spacing: { ...theme.spacing, ...config.extend.spacing } };
|
|
57
|
+
}
|
|
58
|
+
if (config.extend?.screens) {
|
|
59
|
+
theme = { ...theme, screens: { ...theme.screens, ...config.extend.screens } };
|
|
60
|
+
}
|
|
61
|
+
if (config.extend?.fontFamily) {
|
|
62
|
+
theme = { ...theme, fontFamily: { ...theme.fontFamily, ...config.extend.fontFamily } };
|
|
63
|
+
}
|
|
64
|
+
if (config.extend?.container) {
|
|
65
|
+
theme = { ...theme, container: { ...theme.container, ...config.extend.container } };
|
|
66
|
+
}
|
|
67
|
+
if (config.darkMode) {
|
|
68
|
+
theme = { ...theme, darkMode: config.darkMode };
|
|
69
|
+
}
|
|
70
|
+
return theme;
|
|
71
|
+
}
|
|
72
|
+
function applyKbachConfig(config) {
|
|
73
|
+
const theme = resolveKbachConfig(config);
|
|
74
|
+
setTheme(theme);
|
|
75
|
+
return theme;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// src/useTheme.ts
|
|
79
|
+
import { useMemo, useSyncExternalStore } from "react";
|
|
80
|
+
function useTheme() {
|
|
81
|
+
const isDark = useSyncExternalStore(subscribeGlobalDarkMode, getGlobalDarkMode);
|
|
82
|
+
const mode = useSyncExternalStore(subscribeGlobalDarkMode, getGlobalThemeMode);
|
|
83
|
+
return useMemo(
|
|
84
|
+
() => ({ mode, isDark, setMode: setGlobalThemeMode, toggle: toggleGlobalDarkMode }),
|
|
85
|
+
[mode, isDark]
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// src/ThemeProvider.tsx
|
|
90
|
+
import { useEffect, useRef } from "react";
|
|
91
|
+
import { Fragment, jsx } from "react/jsx-runtime";
|
|
92
|
+
var mountedProviderCount = 0;
|
|
93
|
+
var warnedMultipleProviders = false;
|
|
94
|
+
function ThemeProvider({ children, defaultMode = "system" }) {
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
mountedProviderCount++;
|
|
97
|
+
if (mountedProviderCount > 1 && !warnedMultipleProviders) {
|
|
98
|
+
warnedMultipleProviders = true;
|
|
99
|
+
console.warn(
|
|
100
|
+
"[kbach] Multiple <ThemeProvider> instances are mounted at once. Dark-mode state is one global store useTheme() reads everywhere, not scoped per-provider, so their defaultMode seeds will fight over the same state."
|
|
101
|
+
);
|
|
102
|
+
}
|
|
103
|
+
return () => {
|
|
104
|
+
mountedProviderCount--;
|
|
105
|
+
};
|
|
106
|
+
}, []);
|
|
107
|
+
const seeded = useRef(false);
|
|
108
|
+
useEffect(() => {
|
|
109
|
+
if (seeded.current) return;
|
|
110
|
+
seeded.current = true;
|
|
111
|
+
seedDefaultMode(defaultMode);
|
|
112
|
+
}, []);
|
|
113
|
+
return /* @__PURE__ */ jsx(Fragment, { children });
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// src/useColors.ts
|
|
117
|
+
function parseHexRgb2(hex) {
|
|
118
|
+
const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(hex.trim());
|
|
119
|
+
if (!m) return null;
|
|
120
|
+
let h = m[1];
|
|
121
|
+
if (h.length === 3) h = h.split("").map((c) => c + c).join("");
|
|
122
|
+
const n = parseInt(h, 16);
|
|
123
|
+
return [n >> 16 & 255, n >> 8 & 255, n & 255];
|
|
124
|
+
}
|
|
125
|
+
function applyOpacity(color, opacity) {
|
|
126
|
+
const a = Math.max(0, Math.min(1, opacity / 100));
|
|
127
|
+
if (color.startsWith("#")) {
|
|
128
|
+
const rgb = parseHexRgb2(color);
|
|
129
|
+
return rgb ? `rgba(${rgb.join(",")},${a})` : color;
|
|
130
|
+
}
|
|
131
|
+
if (color.startsWith("rgb(")) return color.replace("rgb(", "rgba(").replace(")", `,${a})`);
|
|
132
|
+
if (color.startsWith("rgba(")) return color.replace(/,\s*[\d.]+\)$/, `,${a})`);
|
|
133
|
+
return color;
|
|
134
|
+
}
|
|
135
|
+
function resolveEntry(entry, isDark) {
|
|
136
|
+
return typeof entry === "string" ? entry : isDark ? entry.dark : entry.light;
|
|
137
|
+
}
|
|
138
|
+
function makeColorsProxy(theme, isDark) {
|
|
139
|
+
const alpha = (color, opacity) => opacity === void 0 ? color : applyOpacity(color, opacity);
|
|
140
|
+
const cache = /* @__PURE__ */ new Map();
|
|
141
|
+
function resolveNamed(key) {
|
|
142
|
+
let name = key;
|
|
143
|
+
let opacity;
|
|
144
|
+
if (key.includes("/")) {
|
|
145
|
+
const slash = key.indexOf("/");
|
|
146
|
+
name = key.slice(0, slash);
|
|
147
|
+
opacity = Number(key.slice(slash + 1));
|
|
148
|
+
}
|
|
149
|
+
const entry = theme.colors[name];
|
|
150
|
+
if (entry === void 0) return void 0;
|
|
151
|
+
const value = resolveEntry(entry, isDark);
|
|
152
|
+
return opacity === void 0 ? value : applyOpacity(value, opacity);
|
|
153
|
+
}
|
|
154
|
+
function makeFamilyProxy(family) {
|
|
155
|
+
return new Proxy({}, {
|
|
156
|
+
get(_, prop) {
|
|
157
|
+
const key = String(prop);
|
|
158
|
+
if (key === "then") return void 0;
|
|
159
|
+
return resolveNamed(`${family}-${key}`);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
return new Proxy({ alpha }, {
|
|
164
|
+
get(_, prop) {
|
|
165
|
+
const key = String(prop);
|
|
166
|
+
if (key === "then") return void 0;
|
|
167
|
+
if (key === "alpha") return alpha;
|
|
168
|
+
const direct = resolveNamed(key);
|
|
169
|
+
if (direct !== void 0) return direct;
|
|
170
|
+
if (!cache.has(key)) cache.set(key, makeFamilyProxy(key));
|
|
171
|
+
return cache.get(key);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
function useColors() {
|
|
176
|
+
const { isDark } = useTheme();
|
|
177
|
+
return makeColorsProxy(getTheme(), isDark);
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
export {
|
|
181
|
+
resolveKbachConfig,
|
|
182
|
+
applyKbachConfig,
|
|
183
|
+
useTheme,
|
|
184
|
+
ThemeProvider,
|
|
185
|
+
useColors
|
|
186
|
+
};
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { C as ColorEntry, a as ColorScale, b as ColorsAPI, c as ContainerConfig, K as KbachConfig, T as ThemeConfig, d as ThemeMode, e as ThemeProvider, f as ThemeProviderProps, g as ThemeState, h as applyKbachConfig, i as defaultTheme, j as getGlobalDarkMode, k as getGlobalThemeMode, l as getTheme, r as resolveKbachConfig, s as setGlobalThemeMode, m as setTheme, n as subscribeGlobalDarkMode, t as toggleGlobalDarkMode, u as useColors, o as useTheme } from './useColors-CeP5_HvM.mjs';
|
|
2
2
|
import 'react';
|
|
3
3
|
|
|
4
4
|
type StyleValue = string | number | {
|
|
@@ -25,10 +25,9 @@ interface StyleObject {
|
|
|
25
25
|
* whenever the mode is `'system'` (its own default), so nothing regresses
|
|
26
26
|
* for apps that never touch the override API at all. This function itself
|
|
27
27
|
* has no subscription of its own, so nothing re-renders just because the
|
|
28
|
-
* store's value changed — call `
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* and would miss an explicit override entirely.
|
|
28
|
+
* store's value changed — call `useTheme()` (its `isDark`) somewhere in
|
|
29
|
+
* the tree for that, NOT React Native's own `useColorScheme()`, which only
|
|
30
|
+
* reflects the raw OS setting and would miss an explicit override entirely.
|
|
32
31
|
*
|
|
33
32
|
* Phase 11 originally shipped with live in-place theme switching unverified
|
|
34
33
|
* (a `uiMode` toggle triggered a re-render but `Appearance.getColorScheme()`
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { C as ColorEntry, a as ColorScale, b as ColorsAPI, c as ContainerConfig, K as KbachConfig, T as ThemeConfig, d as ThemeMode, e as ThemeProvider, f as ThemeProviderProps, g as ThemeState, h as applyKbachConfig, i as defaultTheme, j as getGlobalDarkMode, k as getGlobalThemeMode, l as getTheme, r as resolveKbachConfig, s as setGlobalThemeMode, m as setTheme, n as subscribeGlobalDarkMode, t as toggleGlobalDarkMode, u as useColors, o as useTheme } from './useColors-CeP5_HvM.js';
|
|
2
2
|
import 'react';
|
|
3
3
|
|
|
4
4
|
type StyleValue = string | number | {
|
|
@@ -25,10 +25,9 @@ interface StyleObject {
|
|
|
25
25
|
* whenever the mode is `'system'` (its own default), so nothing regresses
|
|
26
26
|
* for apps that never touch the override API at all. This function itself
|
|
27
27
|
* has no subscription of its own, so nothing re-renders just because the
|
|
28
|
-
* store's value changed — call `
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
* and would miss an explicit override entirely.
|
|
28
|
+
* store's value changed — call `useTheme()` (its `isDark`) somewhere in
|
|
29
|
+
* the tree for that, NOT React Native's own `useColorScheme()`, which only
|
|
30
|
+
* reflects the raw OS setting and would miss an explicit override entirely.
|
|
32
31
|
*
|
|
33
32
|
* Phase 11 originally shipped with live in-place theme switching unverified
|
|
34
33
|
* (a `uiMode` toggle triggered a re-render but `Appearance.getColorScheme()`
|
package/dist/index.js
CHANGED
|
@@ -21,16 +21,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
21
21
|
var src_exports = {};
|
|
22
22
|
__export(src_exports, {
|
|
23
23
|
ThemeProvider: () => ThemeProvider,
|
|
24
|
+
applyKbachConfig: () => applyKbachConfig,
|
|
24
25
|
defaultTheme: () => defaultTheme,
|
|
25
26
|
getGlobalDarkMode: () => getGlobalDarkMode,
|
|
26
27
|
getGlobalThemeMode: () => getGlobalThemeMode,
|
|
27
28
|
getTheme: () => getTheme,
|
|
29
|
+
resolveKbachConfig: () => resolveKbachConfig,
|
|
28
30
|
resolveStyle: () => resolveStyle,
|
|
29
31
|
setGlobalThemeMode: () => setGlobalThemeMode,
|
|
30
32
|
setTheme: () => setTheme,
|
|
31
33
|
subscribeGlobalDarkMode: () => subscribeGlobalDarkMode,
|
|
32
34
|
toggleGlobalDarkMode: () => toggleGlobalDarkMode,
|
|
33
|
-
|
|
35
|
+
useColors: () => useColors,
|
|
34
36
|
useTheme: () => useTheme
|
|
35
37
|
});
|
|
36
38
|
module.exports = __toCommonJS(src_exports);
|
|
@@ -317,11 +319,13 @@ var defaultTheme = {
|
|
|
317
319
|
colors: PALETTE,
|
|
318
320
|
// Real Tailwind's default spacing scale in full — every step is exactly
|
|
319
321
|
// `n * 4px`, including the fractional `.5` steps (`1.5` -> 6px, `2.5` ->
|
|
320
|
-
// 10px, `3.5` -> 14px) and the "px" literal (a bare 1px).
|
|
321
|
-
//
|
|
322
|
-
//
|
|
323
|
-
// `
|
|
324
|
-
//
|
|
322
|
+
// 10px, `3.5` -> 14px) and the "px" literal (a bare 1px). Only the
|
|
323
|
+
// "usual stops", though — `jsEngine/shared.ts`'s `spacingPx` (and the
|
|
324
|
+
// native Rust dispatcher's own `spacing_px`) falls back to Tailwind v4's
|
|
325
|
+
// live `n * 4px` formula for any bare numeric step not listed here
|
|
326
|
+
// (`p-0.25`, `w-13`, ...), so this table names the common values and
|
|
327
|
+
// gives a theme override something to target, not the full resolvable
|
|
328
|
+
// set. Mirrors @kbach/react's theme.ts exactly.
|
|
325
329
|
spacing: {
|
|
326
330
|
"0": 0,
|
|
327
331
|
"px": 1,
|
|
@@ -366,7 +370,20 @@ var defaultTheme = {
|
|
|
366
370
|
xl: 1280,
|
|
367
371
|
"2xl": 1536
|
|
368
372
|
},
|
|
369
|
-
|
|
373
|
+
// Byte-for-byte the same three stacks
|
|
374
|
+
// packages/core-engine/src/resolvers/typography.rs's `font_family_value`
|
|
375
|
+
// falls back to. On native these three still effectively no-op (see
|
|
376
|
+
// `first_font_name`'s own doc comment for why a generic CSS keyword
|
|
377
|
+
// isn't a real loadable font) — only a caller-configured custom name
|
|
378
|
+
// changes native rendering; Expo Web uses the full stack as-is.
|
|
379
|
+
fontFamily: {
|
|
380
|
+
sans: 'ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji"',
|
|
381
|
+
serif: 'ui-serif, Georgia, Cambria, "Times New Roman", Times, serif',
|
|
382
|
+
mono: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace'
|
|
383
|
+
},
|
|
384
|
+
darkMode: "attribute",
|
|
385
|
+
// Empty by default, matching real Tailwind's own defaults.
|
|
386
|
+
container: {}
|
|
370
387
|
};
|
|
371
388
|
var activeTheme = defaultTheme;
|
|
372
389
|
var activeThemeJson = JSON.stringify(defaultTheme);
|
|
@@ -680,6 +697,12 @@ function parseClass(token) {
|
|
|
680
697
|
function decl(property, value) {
|
|
681
698
|
return { property, value };
|
|
682
699
|
}
|
|
700
|
+
function spacingPx(theme, value) {
|
|
701
|
+
const fromTable = theme.spacing[value];
|
|
702
|
+
if (fromTable !== void 0) return fromTable;
|
|
703
|
+
const n = Number(value);
|
|
704
|
+
return Number.isFinite(n) && value.trim() !== "" ? n * 4 : void 0;
|
|
705
|
+
}
|
|
683
706
|
function resolveLength(theme, parsed) {
|
|
684
707
|
if (parsed.negative) return null;
|
|
685
708
|
const value = parsed.value;
|
|
@@ -687,7 +710,7 @@ function resolveLength(theme, parsed) {
|
|
|
687
710
|
if (parsed.isArbitrary) return value;
|
|
688
711
|
if (value === "full") return "100%";
|
|
689
712
|
if (value === "auto") return "auto";
|
|
690
|
-
const px = theme
|
|
713
|
+
const px = spacingPx(theme, value);
|
|
691
714
|
return px === void 0 ? null : `${px}px`;
|
|
692
715
|
}
|
|
693
716
|
function resolveNegatableLength(theme, parsed) {
|
|
@@ -695,7 +718,7 @@ function resolveNegatableLength(theme, parsed) {
|
|
|
695
718
|
if (parsed.isArbitrary) return null;
|
|
696
719
|
const value = parsed.value;
|
|
697
720
|
if (value === null) return null;
|
|
698
|
-
const px = theme
|
|
721
|
+
const px = spacingPx(theme, value);
|
|
699
722
|
if (px === void 0) return null;
|
|
700
723
|
if (px === 0) return "0px";
|
|
701
724
|
return `-${px}px`;
|
|
@@ -1054,7 +1077,8 @@ function resolve2(parsed, theme) {
|
|
|
1054
1077
|
|
|
1055
1078
|
// src/jsEngine/resolvers/color.ts
|
|
1056
1079
|
function lookupHex(theme, key) {
|
|
1057
|
-
|
|
1080
|
+
const entry = theme.colors[key];
|
|
1081
|
+
return typeof entry === "string" ? entry : null;
|
|
1058
1082
|
}
|
|
1059
1083
|
|
|
1060
1084
|
// src/jsEngine/resolvers/border.ts
|
|
@@ -1620,71 +1644,184 @@ function resolveStyle(classString, pressed = false) {
|
|
|
1620
1644
|
return JSON.parse(json);
|
|
1621
1645
|
}
|
|
1622
1646
|
|
|
1623
|
-
// src/
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1647
|
+
// src/config.ts
|
|
1648
|
+
function parseHexRgb(hex) {
|
|
1649
|
+
const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(hex.trim());
|
|
1650
|
+
if (!m) return null;
|
|
1651
|
+
let h = m[1];
|
|
1652
|
+
if (h.length === 3) h = h.split("").map((c) => c + c).join("");
|
|
1653
|
+
const n = parseInt(h, 16);
|
|
1654
|
+
return [n >> 16 & 255, n >> 8 & 255, n & 255];
|
|
1655
|
+
}
|
|
1656
|
+
function applyOpacityToHex(hex, opacityText) {
|
|
1657
|
+
const rgb = parseHexRgb(hex);
|
|
1658
|
+
if (!rgb) return hex;
|
|
1659
|
+
const a = Number(opacityText) / 100;
|
|
1660
|
+
const clamped = Number.isFinite(a) ? Math.min(1, Math.max(0, a)) : 1;
|
|
1661
|
+
return `rgba(${rgb.join(",")},${clamped})`;
|
|
1662
|
+
}
|
|
1663
|
+
function resolveColorEntry(value, lookup) {
|
|
1664
|
+
const slash = value.indexOf("/");
|
|
1665
|
+
const name = slash === -1 ? value : value.slice(0, slash);
|
|
1666
|
+
const opacity = slash === -1 ? void 0 : value.slice(slash + 1);
|
|
1667
|
+
const base = lookup(name);
|
|
1668
|
+
if (base === void 0) return value;
|
|
1669
|
+
return opacity === void 0 ? base : applyOpacityToHex(base, opacity);
|
|
1670
|
+
}
|
|
1671
|
+
function resolveColors(extend, existing) {
|
|
1672
|
+
const resolved = {};
|
|
1673
|
+
const lookup = (name) => {
|
|
1674
|
+
const found = resolved[name] ?? existing[name];
|
|
1675
|
+
return typeof found === "string" ? found : void 0;
|
|
1676
|
+
};
|
|
1677
|
+
for (const [name, value] of Object.entries(extend)) {
|
|
1678
|
+
resolved[name] = resolveColorEntry(value, lookup);
|
|
1679
|
+
}
|
|
1680
|
+
return resolved;
|
|
1681
|
+
}
|
|
1682
|
+
function resolveKbachConfig(config) {
|
|
1683
|
+
let theme = { ...defaultTheme, ...config.theme };
|
|
1684
|
+
if (config.extend?.colors) {
|
|
1685
|
+
theme = { ...theme, colors: { ...theme.colors, ...resolveColors(config.extend.colors, theme.colors) } };
|
|
1686
|
+
}
|
|
1687
|
+
if (config.extend?.spacing) {
|
|
1688
|
+
theme = { ...theme, spacing: { ...theme.spacing, ...config.extend.spacing } };
|
|
1689
|
+
}
|
|
1690
|
+
if (config.extend?.screens) {
|
|
1691
|
+
theme = { ...theme, screens: { ...theme.screens, ...config.extend.screens } };
|
|
1692
|
+
}
|
|
1693
|
+
if (config.extend?.fontFamily) {
|
|
1694
|
+
theme = { ...theme, fontFamily: { ...theme.fontFamily, ...config.extend.fontFamily } };
|
|
1695
|
+
}
|
|
1696
|
+
if (config.extend?.container) {
|
|
1697
|
+
theme = { ...theme, container: { ...theme.container, ...config.extend.container } };
|
|
1698
|
+
}
|
|
1699
|
+
if (config.darkMode) {
|
|
1700
|
+
theme = { ...theme, darkMode: config.darkMode };
|
|
1701
|
+
}
|
|
1702
|
+
return theme;
|
|
1703
|
+
}
|
|
1704
|
+
function applyKbachConfig(config) {
|
|
1705
|
+
const theme = resolveKbachConfig(config);
|
|
1706
|
+
setTheme(theme);
|
|
1707
|
+
return theme;
|
|
1627
1708
|
}
|
|
1628
1709
|
|
|
1629
|
-
// src/
|
|
1630
|
-
var
|
|
1631
|
-
|
|
1632
|
-
// src/ThemeContext.tsx
|
|
1633
|
-
var import_react2 = require("react");
|
|
1634
|
-
var ThemeContext = (0, import_react2.createContext)(null);
|
|
1710
|
+
// src/useTheme.ts
|
|
1711
|
+
var import_react = require("react");
|
|
1635
1712
|
function useTheme() {
|
|
1636
|
-
const
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
return ctx;
|
|
1713
|
+
const isDark2 = (0, import_react.useSyncExternalStore)(subscribeGlobalDarkMode, getGlobalDarkMode);
|
|
1714
|
+
const mode2 = (0, import_react.useSyncExternalStore)(subscribeGlobalDarkMode, getGlobalThemeMode);
|
|
1715
|
+
return (0, import_react.useMemo)(
|
|
1716
|
+
() => ({ mode: mode2, isDark: isDark2, setMode: setGlobalThemeMode, toggle: toggleGlobalDarkMode }),
|
|
1717
|
+
[mode2, isDark2]
|
|
1718
|
+
);
|
|
1643
1719
|
}
|
|
1644
1720
|
|
|
1645
1721
|
// src/ThemeProvider.tsx
|
|
1722
|
+
var import_react2 = require("react");
|
|
1646
1723
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
1647
1724
|
var mountedProviderCount = 0;
|
|
1648
1725
|
var warnedMultipleProviders = false;
|
|
1649
1726
|
function ThemeProvider({ children, defaultMode = "system" }) {
|
|
1650
|
-
(0,
|
|
1727
|
+
(0, import_react2.useEffect)(() => {
|
|
1651
1728
|
mountedProviderCount++;
|
|
1652
1729
|
if (mountedProviderCount > 1 && !warnedMultipleProviders) {
|
|
1653
1730
|
warnedMultipleProviders = true;
|
|
1654
1731
|
console.warn(
|
|
1655
|
-
"[kbach] Multiple <ThemeProvider> instances are mounted at once. Dark-mode state is one global store (
|
|
1732
|
+
"[kbach] Multiple <ThemeProvider> instances are mounted at once. Dark-mode state is one global store useTheme() reads everywhere, not scoped per-provider, so their defaultMode seeds will fight over the same state."
|
|
1656
1733
|
);
|
|
1657
1734
|
}
|
|
1658
1735
|
return () => {
|
|
1659
1736
|
mountedProviderCount--;
|
|
1660
1737
|
};
|
|
1661
1738
|
}, []);
|
|
1662
|
-
const seeded = (0,
|
|
1663
|
-
(0,
|
|
1739
|
+
const seeded = (0, import_react2.useRef)(false);
|
|
1740
|
+
(0, import_react2.useEffect)(() => {
|
|
1664
1741
|
if (seeded.current) return;
|
|
1665
1742
|
seeded.current = true;
|
|
1666
1743
|
seedDefaultMode(defaultMode);
|
|
1667
1744
|
}, []);
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
);
|
|
1674
|
-
|
|
1745
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children });
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
// src/useColors.ts
|
|
1749
|
+
function parseHexRgb2(hex) {
|
|
1750
|
+
const m = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i.exec(hex.trim());
|
|
1751
|
+
if (!m) return null;
|
|
1752
|
+
let h = m[1];
|
|
1753
|
+
if (h.length === 3) h = h.split("").map((c) => c + c).join("");
|
|
1754
|
+
const n = parseInt(h, 16);
|
|
1755
|
+
return [n >> 16 & 255, n >> 8 & 255, n & 255];
|
|
1756
|
+
}
|
|
1757
|
+
function applyOpacity(color, opacity) {
|
|
1758
|
+
const a = Math.max(0, Math.min(1, opacity / 100));
|
|
1759
|
+
if (color.startsWith("#")) {
|
|
1760
|
+
const rgb = parseHexRgb2(color);
|
|
1761
|
+
return rgb ? `rgba(${rgb.join(",")},${a})` : color;
|
|
1762
|
+
}
|
|
1763
|
+
if (color.startsWith("rgb(")) return color.replace("rgb(", "rgba(").replace(")", `,${a})`);
|
|
1764
|
+
if (color.startsWith("rgba(")) return color.replace(/,\s*[\d.]+\)$/, `,${a})`);
|
|
1765
|
+
return color;
|
|
1766
|
+
}
|
|
1767
|
+
function resolveEntry(entry, isDark2) {
|
|
1768
|
+
return typeof entry === "string" ? entry : isDark2 ? entry.dark : entry.light;
|
|
1769
|
+
}
|
|
1770
|
+
function makeColorsProxy(theme, isDark2) {
|
|
1771
|
+
const alpha = (color, opacity) => opacity === void 0 ? color : applyOpacity(color, opacity);
|
|
1772
|
+
const cache = /* @__PURE__ */ new Map();
|
|
1773
|
+
function resolveNamed(key) {
|
|
1774
|
+
let name = key;
|
|
1775
|
+
let opacity;
|
|
1776
|
+
if (key.includes("/")) {
|
|
1777
|
+
const slash = key.indexOf("/");
|
|
1778
|
+
name = key.slice(0, slash);
|
|
1779
|
+
opacity = Number(key.slice(slash + 1));
|
|
1780
|
+
}
|
|
1781
|
+
const entry = theme.colors[name];
|
|
1782
|
+
if (entry === void 0) return void 0;
|
|
1783
|
+
const value = resolveEntry(entry, isDark2);
|
|
1784
|
+
return opacity === void 0 ? value : applyOpacity(value, opacity);
|
|
1785
|
+
}
|
|
1786
|
+
function makeFamilyProxy(family) {
|
|
1787
|
+
return new Proxy({}, {
|
|
1788
|
+
get(_, prop) {
|
|
1789
|
+
const key = String(prop);
|
|
1790
|
+
if (key === "then") return void 0;
|
|
1791
|
+
return resolveNamed(`${family}-${key}`);
|
|
1792
|
+
}
|
|
1793
|
+
});
|
|
1794
|
+
}
|
|
1795
|
+
return new Proxy({ alpha }, {
|
|
1796
|
+
get(_, prop) {
|
|
1797
|
+
const key = String(prop);
|
|
1798
|
+
if (key === "then") return void 0;
|
|
1799
|
+
if (key === "alpha") return alpha;
|
|
1800
|
+
const direct = resolveNamed(key);
|
|
1801
|
+
if (direct !== void 0) return direct;
|
|
1802
|
+
if (!cache.has(key)) cache.set(key, makeFamilyProxy(key));
|
|
1803
|
+
return cache.get(key);
|
|
1804
|
+
}
|
|
1805
|
+
});
|
|
1806
|
+
}
|
|
1807
|
+
function useColors() {
|
|
1808
|
+
const { isDark: isDark2 } = useTheme();
|
|
1809
|
+
return makeColorsProxy(getTheme(), isDark2);
|
|
1675
1810
|
}
|
|
1676
1811
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1677
1812
|
0 && (module.exports = {
|
|
1678
1813
|
ThemeProvider,
|
|
1814
|
+
applyKbachConfig,
|
|
1679
1815
|
defaultTheme,
|
|
1680
1816
|
getGlobalDarkMode,
|
|
1681
1817
|
getGlobalThemeMode,
|
|
1682
1818
|
getTheme,
|
|
1819
|
+
resolveKbachConfig,
|
|
1683
1820
|
resolveStyle,
|
|
1684
1821
|
setGlobalThemeMode,
|
|
1685
1822
|
setTheme,
|
|
1686
1823
|
subscribeGlobalDarkMode,
|
|
1687
1824
|
toggleGlobalDarkMode,
|
|
1688
|
-
|
|
1825
|
+
useColors,
|
|
1689
1826
|
useTheme
|
|
1690
1827
|
});
|