@kbach/react 0.6.15 → 0.6.16
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 +90 -262
- package/dist/{chunk-YH2IOSKT.mjs → chunk-GJSZUC6Q.mjs} +81 -46
- package/dist/{chunk-THJIAZ6E.mjs → chunk-YUX2JPTM.mjs} +12 -10
- package/dist/index.js +141 -63
- package/dist/index.mjs +67 -18
- package/dist/jsx-dev-runtime.js +82 -58
- package/dist/jsx-dev-runtime.mjs +2 -2
- package/dist/jsx-runtime.js +82 -58
- package/dist/jsx-runtime.mjs +2 -2
- package/dist/vite-plugin.js +23 -27
- package/dist/vite-plugin.mjs +23 -27
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -898,25 +898,6 @@ function resolveColor(value, colors, isArbitrary) {
|
|
|
898
898
|
}
|
|
899
899
|
}
|
|
900
900
|
}
|
|
901
|
-
if (hex && !hex.startsWith("#") && !hex.startsWith("rgb") && hex !== "transparent" && hex !== "currentColor") {
|
|
902
|
-
if (hex in colors) {
|
|
903
|
-
const alias = colors[hex];
|
|
904
|
-
if (typeof alias === "string") hex = alias;
|
|
905
|
-
else if (typeof alias === "object" && "6" in alias) hex = alias["6"] ?? hex;
|
|
906
|
-
} else {
|
|
907
|
-
const aliasLastDash = hex.lastIndexOf("-");
|
|
908
|
-
if (aliasLastDash > 0) {
|
|
909
|
-
const aliasColorName = hex.slice(0, aliasLastDash);
|
|
910
|
-
const aliasShade = hex.slice(aliasLastDash + 1);
|
|
911
|
-
const aliasScale = colors[aliasColorName];
|
|
912
|
-
if (aliasScale && typeof aliasScale === "object") {
|
|
913
|
-
hex = aliasScale[aliasShade] ?? null;
|
|
914
|
-
} else if (typeof aliasScale === "string") {
|
|
915
|
-
hex = aliasScale;
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
}
|
|
919
|
-
}
|
|
920
901
|
if (!hex) return null;
|
|
921
902
|
if (!opacityPart) {
|
|
922
903
|
if (!getEffectiveIsWeb() && hex.startsWith("#") && hex.length === 9) {
|
|
@@ -932,6 +913,8 @@ function resolveColor(value, colors, isArbitrary) {
|
|
|
932
913
|
alpha = parseFloat(opacityPart) / 100;
|
|
933
914
|
}
|
|
934
915
|
if (isNaN(alpha)) return hex;
|
|
916
|
+
if (alpha < 0) alpha = 0;
|
|
917
|
+
else if (alpha > 1) alpha = 1;
|
|
935
918
|
return hexToRgba(hex, alpha);
|
|
936
919
|
}
|
|
937
920
|
function parseHexRgb(hex) {
|
|
@@ -2629,6 +2612,14 @@ function getBuiltinStandaloneNames() {
|
|
|
2629
2612
|
}
|
|
2630
2613
|
|
|
2631
2614
|
// src/core/parser.ts
|
|
2615
|
+
var UNSAFE_ARBITRARY_VALUE = /[{};\\]|\/\*|\*\//;
|
|
2616
|
+
function isSafeArbitraryValue(value) {
|
|
2617
|
+
if (!UNSAFE_ARBITRARY_VALUE.test(value)) return true;
|
|
2618
|
+
if (process.env.NODE_ENV !== "production") {
|
|
2619
|
+
kbachWarn(`Unsafe arbitrary value rejected: "${value}"`);
|
|
2620
|
+
}
|
|
2621
|
+
return false;
|
|
2622
|
+
}
|
|
2632
2623
|
function parseClass(className) {
|
|
2633
2624
|
const trimmed = className.trim();
|
|
2634
2625
|
if (!trimmed) return null;
|
|
@@ -2667,6 +2658,7 @@ function parseClass(className) {
|
|
|
2667
2658
|
if (bracketStart > 0 && remaining[bracketStart - 1] === "-" && remaining.endsWith("]")) {
|
|
2668
2659
|
const utility = remaining.slice(0, bracketStart - 1);
|
|
2669
2660
|
const value = remaining.slice(bracketStart + 1, -1).replace(/_/g, " ");
|
|
2661
|
+
if (!isSafeArbitraryValue(value)) return null;
|
|
2670
2662
|
return { original: trimmed, modifiers, negative, important, utility, value, isArbitrary: true };
|
|
2671
2663
|
}
|
|
2672
2664
|
if (remaining.endsWith("]") && bracketStart === -1) {
|
|
@@ -2676,6 +2668,7 @@ function parseClass(className) {
|
|
|
2676
2668
|
}
|
|
2677
2669
|
if (remaining.startsWith("[") && remaining.endsWith("]")) {
|
|
2678
2670
|
const value = remaining.slice(1, -1).replace(/_/g, " ");
|
|
2671
|
+
if (!isSafeArbitraryValue(value)) return null;
|
|
2679
2672
|
return { original: trimmed, modifiers, negative, important, utility: "", value, isArbitrary: true };
|
|
2680
2673
|
}
|
|
2681
2674
|
if (getBuiltinStandaloneNames().has(remaining)) {
|
|
@@ -2842,17 +2835,20 @@ function getDefaultFontFamily() {
|
|
|
2842
2835
|
return globalThis[FONT_KEY];
|
|
2843
2836
|
}
|
|
2844
2837
|
var _styleEl = null;
|
|
2838
|
+
var _ruleIndexByKey = /* @__PURE__ */ new Map();
|
|
2845
2839
|
function evictInjectedRule(rule) {
|
|
2840
|
+
const idx = _ruleIndexByKey.get(rule);
|
|
2841
|
+
_ruleIndexByKey.delete(rule);
|
|
2842
|
+
if (idx === void 0) return;
|
|
2846
2843
|
const sheet = _styleEl?.sheet;
|
|
2847
2844
|
if (!sheet) return;
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
}
|
|
2845
|
+
try {
|
|
2846
|
+
sheet.deleteRule(idx);
|
|
2847
|
+
} catch {
|
|
2848
|
+
return;
|
|
2849
|
+
}
|
|
2850
|
+
for (const [key, i] of _ruleIndexByKey) {
|
|
2851
|
+
if (i > idx) _ruleIndexByKey.set(key, i - 1);
|
|
2856
2852
|
}
|
|
2857
2853
|
}
|
|
2858
2854
|
var _injectedRules = new LRUCache(5e4, evictInjectedRule);
|
|
@@ -2872,11 +2868,15 @@ function getStyleEl() {
|
|
|
2872
2868
|
}
|
|
2873
2869
|
function injectRule(rule) {
|
|
2874
2870
|
if (isRuntimeCSSDisabled()) return;
|
|
2875
|
-
if (_injectedRules.
|
|
2876
|
-
_injectedRules.set(rule, true);
|
|
2871
|
+
if (_injectedRules.get(rule)) return;
|
|
2877
2872
|
try {
|
|
2878
2873
|
const sheet = getStyleEl().sheet;
|
|
2879
|
-
if (sheet)
|
|
2874
|
+
if (sheet) {
|
|
2875
|
+
const idx = sheet.cssRules.length;
|
|
2876
|
+
sheet.insertRule(rule, idx);
|
|
2877
|
+
_ruleIndexByKey.set(rule, idx);
|
|
2878
|
+
_injectedRules.set(rule, true);
|
|
2879
|
+
}
|
|
2880
2880
|
} catch {
|
|
2881
2881
|
}
|
|
2882
2882
|
}
|
|
@@ -3145,6 +3145,7 @@ function flatten(resolved, isDark, state = {}, breakpoints = /* @__PURE__ */ new
|
|
|
3145
3145
|
}
|
|
3146
3146
|
function clearCache() {
|
|
3147
3147
|
_injectedRules.clear();
|
|
3148
|
+
_ruleIndexByKey.clear();
|
|
3148
3149
|
if (_styleEl) {
|
|
3149
3150
|
_styleEl.remove();
|
|
3150
3151
|
_styleEl = null;
|
|
@@ -3444,6 +3445,8 @@ var useSyncExternalStore = import_react3.default.useSyncExternalStore ?? functio
|
|
|
3444
3445
|
// src/ThemeProvider.tsx
|
|
3445
3446
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
3446
3447
|
var STORAGE_KEY = "kbach-theme";
|
|
3448
|
+
var _mountedProviderCount = 0;
|
|
3449
|
+
var _warnedMultipleProviders = false;
|
|
3447
3450
|
function loadPersistedMode() {
|
|
3448
3451
|
try {
|
|
3449
3452
|
if (isWeb) return localStorage.getItem(STORAGE_KEY);
|
|
@@ -3495,6 +3498,18 @@ function ThemeProvider({
|
|
|
3495
3498
|
const [resolvedConfig, setResolvedConfig] = (0, import_react4.useState)(
|
|
3496
3499
|
() => configOverride ? buildConfig(configOverride) : getConfig()
|
|
3497
3500
|
);
|
|
3501
|
+
(0, import_react4.useEffect)(() => {
|
|
3502
|
+
_mountedProviderCount++;
|
|
3503
|
+
if (process.env.NODE_ENV !== "production" && _mountedProviderCount > 1 && !_warnedMultipleProviders) {
|
|
3504
|
+
_warnedMultipleProviders = true;
|
|
3505
|
+
kbachWarn(
|
|
3506
|
+
"Multiple <ThemeProvider> instances are mounted at once. Dark mode and responsive width are shared through one global store, so whichever provider rendered most recently wins for every consumer \u2014 nested or per-section theming is not isolated between providers."
|
|
3507
|
+
);
|
|
3508
|
+
}
|
|
3509
|
+
return () => {
|
|
3510
|
+
_mountedProviderCount--;
|
|
3511
|
+
};
|
|
3512
|
+
}, []);
|
|
3498
3513
|
const [webWidth, setWebWidth] = (0, import_react4.useState)(0);
|
|
3499
3514
|
const effectiveWidth = windowWidthProp ?? (isWeb ? webWidth : 0);
|
|
3500
3515
|
const numericScreens = (0, import_react4.useMemo)(() => {
|
|
@@ -3547,6 +3562,17 @@ function ThemeProvider({
|
|
|
3547
3562
|
const persisted = loadPersistedMode();
|
|
3548
3563
|
if (persisted) _setMode(persisted);
|
|
3549
3564
|
}, []);
|
|
3565
|
+
(0, import_react4.useEffect)(() => {
|
|
3566
|
+
if (disablePersistence || !isWeb || typeof window === "undefined") return;
|
|
3567
|
+
const onStorage = (e) => {
|
|
3568
|
+
if (e.key !== STORAGE_KEY || e.newValue == null) return;
|
|
3569
|
+
if (e.newValue === "light" || e.newValue === "dark" || e.newValue === "system") {
|
|
3570
|
+
_setMode(e.newValue);
|
|
3571
|
+
}
|
|
3572
|
+
};
|
|
3573
|
+
window.addEventListener("storage", onStorage);
|
|
3574
|
+
return () => window.removeEventListener("storage", onStorage);
|
|
3575
|
+
}, [disablePersistence]);
|
|
3550
3576
|
const setMode = (0, import_react4.useCallback)((next) => {
|
|
3551
3577
|
_setMode(next);
|
|
3552
3578
|
if (!disablePersistence) persistMode(next);
|
|
@@ -3595,6 +3621,9 @@ function KbachReset() {
|
|
|
3595
3621
|
var import_react5 = __toESM(require("react"));
|
|
3596
3622
|
|
|
3597
3623
|
// src/useGlobalDarkMode.ts
|
|
3624
|
+
var NOOP_SUB = (_) => () => {
|
|
3625
|
+
};
|
|
3626
|
+
var FALSE_SNAP = () => false;
|
|
3598
3627
|
function useGlobalDarkMode() {
|
|
3599
3628
|
return useSyncExternalStore(
|
|
3600
3629
|
subscribeGlobalDarkMode,
|
|
@@ -3603,9 +3632,16 @@ function useGlobalDarkMode() {
|
|
|
3603
3632
|
// SSR: default light
|
|
3604
3633
|
);
|
|
3605
3634
|
}
|
|
3635
|
+
function useConditionalGlobalDarkMode(active) {
|
|
3636
|
+
return useSyncExternalStore(
|
|
3637
|
+
active ? subscribeGlobalDarkMode : NOOP_SUB,
|
|
3638
|
+
active ? getGlobalDarkMode : FALSE_SNAP,
|
|
3639
|
+
FALSE_SNAP
|
|
3640
|
+
);
|
|
3641
|
+
}
|
|
3606
3642
|
|
|
3607
3643
|
// src/useGlobalWidth.ts
|
|
3608
|
-
var
|
|
3644
|
+
var NOOP_SUB2 = (_) => () => {
|
|
3609
3645
|
};
|
|
3610
3646
|
var ZERO_SNAP = () => 0;
|
|
3611
3647
|
var EMPTY_BREAKPOINTS = /* @__PURE__ */ new Set();
|
|
@@ -3646,7 +3682,7 @@ function useGlobalWidth() {
|
|
|
3646
3682
|
}
|
|
3647
3683
|
function useConditionalWidth(active) {
|
|
3648
3684
|
return useSyncExternalStore(
|
|
3649
|
-
active ? isWeb ? subscribeWebWidth : subscribeGlobalWidth :
|
|
3685
|
+
active ? isWeb ? subscribeWebWidth : subscribeGlobalWidth : NOOP_SUB2,
|
|
3650
3686
|
active ? isWeb ? getWebWidth : getGlobalWidth : ZERO_SNAP,
|
|
3651
3687
|
ZERO_SNAP
|
|
3652
3688
|
);
|
|
@@ -4007,34 +4043,55 @@ function styled(Component, baseClasses = "") {
|
|
|
4007
4043
|
const disabled = !!props.disabled;
|
|
4008
4044
|
const checked = !!props.checked;
|
|
4009
4045
|
const { config } = useTheme();
|
|
4010
|
-
const
|
|
4046
|
+
const isWebPlatform = getEffectiveIsWeb();
|
|
4047
|
+
const isDark = useConditionalGlobalDarkMode(!isWebPlatform);
|
|
4011
4048
|
const [pressed, setPressed] = (0, import_react5.useState)(false);
|
|
4012
4049
|
const [hovered, setHovered] = (0, import_react5.useState)(false);
|
|
4013
4050
|
const [focused, setFocused] = (0, import_react5.useState)(false);
|
|
4014
|
-
const handlePressIn = (0, import_react5.useCallback)(chain(onPressIn, () =>
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
const
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
const
|
|
4021
|
-
|
|
4022
|
-
|
|
4023
|
-
const
|
|
4051
|
+
const handlePressIn = (0, import_react5.useCallback)(chain(onPressIn, () => {
|
|
4052
|
+
if (!isWebPlatform) setPressed(true);
|
|
4053
|
+
}), [onPressIn, isWebPlatform]);
|
|
4054
|
+
const handlePressOut = (0, import_react5.useCallback)(chain(onPressOut, () => {
|
|
4055
|
+
if (!isWebPlatform) setPressed(false);
|
|
4056
|
+
}), [onPressOut, isWebPlatform]);
|
|
4057
|
+
const handlePointerDown = (0, import_react5.useCallback)(chain(onPointerDown, () => {
|
|
4058
|
+
if (!isWebPlatform) setPressed(true);
|
|
4059
|
+
}), [onPointerDown, isWebPlatform]);
|
|
4060
|
+
const handlePointerUp = (0, import_react5.useCallback)(chain(onPointerUp, () => {
|
|
4061
|
+
if (!isWebPlatform) setPressed(false);
|
|
4062
|
+
}), [onPointerUp, isWebPlatform]);
|
|
4063
|
+
const handlePointerLeave = (0, import_react5.useCallback)(chain(onPointerLeave, () => {
|
|
4064
|
+
if (!isWebPlatform) setPressed(false);
|
|
4065
|
+
}), [onPointerLeave, isWebPlatform]);
|
|
4066
|
+
const handlePointerCancel = (0, import_react5.useCallback)(chain(onPointerCancel, () => {
|
|
4067
|
+
if (!isWebPlatform) setPressed(false);
|
|
4068
|
+
}), [onPointerCancel, isWebPlatform]);
|
|
4069
|
+
const handleMouseEnter = (0, import_react5.useCallback)(chain(onMouseEnter, () => {
|
|
4070
|
+
if (!isWebPlatform) setHovered(true);
|
|
4071
|
+
}), [onMouseEnter, isWebPlatform]);
|
|
4072
|
+
const handleMouseLeave = (0, import_react5.useCallback)(chain(onMouseLeave, () => {
|
|
4073
|
+
if (!isWebPlatform) setHovered(false);
|
|
4074
|
+
}), [onMouseLeave, isWebPlatform]);
|
|
4075
|
+
const handleFocus = (0, import_react5.useCallback)(chain(onFocus, () => {
|
|
4076
|
+
if (!isWebPlatform) setFocused(true);
|
|
4077
|
+
}), [onFocus, isWebPlatform]);
|
|
4078
|
+
const handleBlur = (0, import_react5.useCallback)(chain(onBlur, () => {
|
|
4079
|
+
if (!isWebPlatform) setFocused(false);
|
|
4080
|
+
}), [onBlur, isWebPlatform]);
|
|
4024
4081
|
const combined = extraClasses ? `${baseClasses} ${extraClasses}` : baseClasses;
|
|
4025
4082
|
const resolved = (0, import_react5.useMemo)(() => resolve(combined, config.theme, config.darkMode), [combined, config.theme, config.darkMode]);
|
|
4026
4083
|
const hasInteractive = (0, import_react5.useMemo)(() => hasInteractiveBuckets(resolved), [resolved]);
|
|
4027
4084
|
const needsWidth = hasResponsiveBuckets(resolved);
|
|
4028
|
-
const width = useConditionalWidth(needsWidth);
|
|
4085
|
+
const width = useConditionalWidth(needsWidth && !isWebPlatform);
|
|
4029
4086
|
const breakpoints = needsWidth ? getActiveBreakpoints(width) : EMPTY_BREAKPOINTS;
|
|
4030
4087
|
const computedStyle = (0, import_react5.useMemo)(
|
|
4031
|
-
() =>
|
|
4088
|
+
() => isWebPlatform ? {} : flatten(resolved, isDark, { pressed, hover: hovered, focus: focused, disabled, checked }, breakpoints),
|
|
4032
4089
|
[resolved, isDark, pressed, hovered, focused, disabled, checked, width]
|
|
4033
4090
|
// eslint-disable-line react-hooks/exhaustive-deps
|
|
4034
4091
|
);
|
|
4035
4092
|
const extraStyle = Array.isArray(styleProp) ? Object.assign({}, ...styleProp) : styleProp;
|
|
4036
|
-
const finalStyle =
|
|
4037
|
-
const webTag =
|
|
4093
|
+
const finalStyle = isWebPlatform ? extraStyle ?? void 0 : extraStyle ? { ...computedStyle, ...extraStyle } : computedStyle;
|
|
4094
|
+
const webTag = isWebPlatform ? getWebTag(Component, rest) : null;
|
|
4038
4095
|
const effectiveComponent = webTag ?? Component;
|
|
4039
4096
|
const componentName2 = Component.displayName ?? Component.name ?? "";
|
|
4040
4097
|
const effectiveRest = webTag && componentName2 ? transformToWebProps(componentName2, webTag, rest) : rest;
|
|
@@ -4043,7 +4100,7 @@ function styled(Component, baseClasses = "") {
|
|
|
4043
4100
|
...effectiveRest,
|
|
4044
4101
|
style: finalStyle,
|
|
4045
4102
|
// className lets injected CSS rules (group-hover:, before:, print:, etc.) match the element.
|
|
4046
|
-
...
|
|
4103
|
+
...isWebPlatform && combined ? { className: normalizeClassString(combined) } : {},
|
|
4047
4104
|
// Only attach state-tracking handlers when interactive modifiers are present.
|
|
4048
4105
|
// Always forward user-provided handlers to avoid silently swallowing them.
|
|
4049
4106
|
// Gated on isNative, not isWeb: isWeb is false during SSR too (no `window` there),
|
|
@@ -4151,27 +4208,48 @@ var InteractiveWrapper = (0, import_react8.forwardRef)(
|
|
|
4151
4208
|
onBlur,
|
|
4152
4209
|
...rest
|
|
4153
4210
|
}, ref) {
|
|
4154
|
-
const
|
|
4211
|
+
const isWebPlatform = getEffectiveIsWeb();
|
|
4212
|
+
const isDark = useConditionalGlobalDarkMode(!isWebPlatform);
|
|
4155
4213
|
const needsWidth = hasResponsiveBuckets(resolvedStyle);
|
|
4156
|
-
const width = useConditionalWidth(needsWidth);
|
|
4214
|
+
const width = useConditionalWidth(needsWidth && !isWebPlatform);
|
|
4157
4215
|
const breakpoints = needsWidth ? getActiveBreakpoints(width) : EMPTY_BREAKPOINTS;
|
|
4158
4216
|
const [pressed, setPressed] = (0, import_react8.useState)(false);
|
|
4159
4217
|
const [hovered, setHovered] = (0, import_react8.useState)(false);
|
|
4160
4218
|
const [focused, setFocused] = (0, import_react8.useState)(false);
|
|
4161
|
-
const handlePressIn = (0, import_react8.useCallback)(chain(onPressIn, () =>
|
|
4162
|
-
|
|
4163
|
-
|
|
4164
|
-
const
|
|
4165
|
-
|
|
4166
|
-
|
|
4167
|
-
const
|
|
4168
|
-
|
|
4169
|
-
|
|
4170
|
-
const
|
|
4219
|
+
const handlePressIn = (0, import_react8.useCallback)(chain(onPressIn, () => {
|
|
4220
|
+
if (!isWebPlatform) setPressed(true);
|
|
4221
|
+
}), [onPressIn, isWebPlatform]);
|
|
4222
|
+
const handlePressOut = (0, import_react8.useCallback)(chain(onPressOut, () => {
|
|
4223
|
+
if (!isWebPlatform) setPressed(false);
|
|
4224
|
+
}), [onPressOut, isWebPlatform]);
|
|
4225
|
+
const handlePointerDown = (0, import_react8.useCallback)(chain(onPointerDown, () => {
|
|
4226
|
+
if (!isWebPlatform) setPressed(true);
|
|
4227
|
+
}), [onPointerDown, isWebPlatform]);
|
|
4228
|
+
const handlePointerUp = (0, import_react8.useCallback)(chain(onPointerUp, () => {
|
|
4229
|
+
if (!isWebPlatform) setPressed(false);
|
|
4230
|
+
}), [onPointerUp, isWebPlatform]);
|
|
4231
|
+
const handlePointerLeave = (0, import_react8.useCallback)(chain(onPointerLeave, () => {
|
|
4232
|
+
if (!isWebPlatform) setPressed(false);
|
|
4233
|
+
}), [onPointerLeave, isWebPlatform]);
|
|
4234
|
+
const handlePointerCancel = (0, import_react8.useCallback)(chain(onPointerCancel, () => {
|
|
4235
|
+
if (!isWebPlatform) setPressed(false);
|
|
4236
|
+
}), [onPointerCancel, isWebPlatform]);
|
|
4237
|
+
const handleMouseEnter = (0, import_react8.useCallback)(chain(onMouseEnter, () => {
|
|
4238
|
+
if (!isWebPlatform) setHovered(true);
|
|
4239
|
+
}), [onMouseEnter, isWebPlatform]);
|
|
4240
|
+
const handleMouseLeave = (0, import_react8.useCallback)(chain(onMouseLeave, () => {
|
|
4241
|
+
if (!isWebPlatform) setHovered(false);
|
|
4242
|
+
}), [onMouseLeave, isWebPlatform]);
|
|
4243
|
+
const handleFocus = (0, import_react8.useCallback)(chain(onFocus, () => {
|
|
4244
|
+
if (!isWebPlatform) setFocused(true);
|
|
4245
|
+
}), [onFocus, isWebPlatform]);
|
|
4246
|
+
const handleBlur = (0, import_react8.useCallback)(chain(onBlur, () => {
|
|
4247
|
+
if (!isWebPlatform) setFocused(false);
|
|
4248
|
+
}), [onBlur, isWebPlatform]);
|
|
4171
4249
|
const { children, disabled, checked, ...restForComponent } = rest;
|
|
4172
4250
|
const computedStyle = (0, import_react8.useMemo)(
|
|
4173
4251
|
() => {
|
|
4174
|
-
if (
|
|
4252
|
+
if (isWebPlatform) return {};
|
|
4175
4253
|
const s = flatten(resolvedStyle, isDark, { pressed, hover: hovered, focus: focused, disabled: !!disabled, checked: !!checked }, breakpoints);
|
|
4176
4254
|
stripInternalMarkers(s);
|
|
4177
4255
|
if (typeof Component !== "string") stripWebOnlyProps(s);
|
|
@@ -4179,7 +4257,7 @@ var InteractiveWrapper = (0, import_react8.forwardRef)(
|
|
|
4179
4257
|
},
|
|
4180
4258
|
[resolvedStyle, isDark, pressed, hovered, focused, width, disabled, checked]
|
|
4181
4259
|
);
|
|
4182
|
-
const skipComputedInline =
|
|
4260
|
+
const skipComputedInline = isWebPlatform;
|
|
4183
4261
|
const finalStyle = skipComputedInline ? styleProp ?? void 0 : styleProp ? Array.isArray(styleProp) ? Object.assign({}, computedStyle, ...styleProp) : { ...computedStyle, ...styleProp } : computedStyle;
|
|
4184
4262
|
const componentProps = {
|
|
4185
4263
|
ref,
|
|
@@ -4221,7 +4299,7 @@ InteractiveWrapper.displayName = "Kbach.InteractiveWrapper";
|
|
|
4221
4299
|
function kb(classString, isDark = false) {
|
|
4222
4300
|
const config = getConfig();
|
|
4223
4301
|
const resolved = resolve(classString, config.theme, config.darkMode);
|
|
4224
|
-
if (
|
|
4302
|
+
if (getEffectiveIsWeb()) {
|
|
4225
4303
|
return classString;
|
|
4226
4304
|
}
|
|
4227
4305
|
return flatten(resolved, isDark);
|
package/dist/index.mjs
CHANGED
|
@@ -13,12 +13,14 @@ import {
|
|
|
13
13
|
flatten,
|
|
14
14
|
getActiveBreakpoints,
|
|
15
15
|
getConfig,
|
|
16
|
+
getEffectiveIsWeb,
|
|
16
17
|
getWebTag,
|
|
17
18
|
hasInteractiveBuckets,
|
|
18
19
|
hasResponsiveBuckets,
|
|
19
20
|
initConfig,
|
|
20
21
|
isNative,
|
|
21
22
|
isWeb,
|
|
23
|
+
kbachWarn,
|
|
22
24
|
normalizeClassString,
|
|
23
25
|
onConfigChange,
|
|
24
26
|
parseClass,
|
|
@@ -35,11 +37,12 @@ import {
|
|
|
35
37
|
syncGlobalWidth,
|
|
36
38
|
transformToWebProps,
|
|
37
39
|
updateConfig,
|
|
40
|
+
useConditionalGlobalDarkMode,
|
|
38
41
|
useConditionalWidth,
|
|
39
42
|
useGlobalDarkMode,
|
|
40
43
|
useGlobalWidth,
|
|
41
44
|
useSyncExternalStore
|
|
42
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-GJSZUC6Q.mjs";
|
|
43
46
|
|
|
44
47
|
// src/context.tsx
|
|
45
48
|
import { createContext, useContext } from "react";
|
|
@@ -125,6 +128,8 @@ import {
|
|
|
125
128
|
} from "react";
|
|
126
129
|
import { jsx } from "react/jsx-runtime";
|
|
127
130
|
var STORAGE_KEY = "kbach-theme";
|
|
131
|
+
var _mountedProviderCount = 0;
|
|
132
|
+
var _warnedMultipleProviders = false;
|
|
128
133
|
function loadPersistedMode() {
|
|
129
134
|
try {
|
|
130
135
|
if (isWeb) return localStorage.getItem(STORAGE_KEY);
|
|
@@ -176,6 +181,18 @@ function ThemeProvider({
|
|
|
176
181
|
const [resolvedConfig, setResolvedConfig] = useState(
|
|
177
182
|
() => configOverride ? buildConfig(configOverride) : getConfig()
|
|
178
183
|
);
|
|
184
|
+
useEffect(() => {
|
|
185
|
+
_mountedProviderCount++;
|
|
186
|
+
if (process.env.NODE_ENV !== "production" && _mountedProviderCount > 1 && !_warnedMultipleProviders) {
|
|
187
|
+
_warnedMultipleProviders = true;
|
|
188
|
+
kbachWarn(
|
|
189
|
+
"Multiple <ThemeProvider> instances are mounted at once. Dark mode and responsive width are shared through one global store, so whichever provider rendered most recently wins for every consumer \u2014 nested or per-section theming is not isolated between providers."
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
return () => {
|
|
193
|
+
_mountedProviderCount--;
|
|
194
|
+
};
|
|
195
|
+
}, []);
|
|
179
196
|
const [webWidth, setWebWidth] = useState(0);
|
|
180
197
|
const effectiveWidth = windowWidthProp ?? (isWeb ? webWidth : 0);
|
|
181
198
|
const numericScreens = useMemo2(() => {
|
|
@@ -228,6 +245,17 @@ function ThemeProvider({
|
|
|
228
245
|
const persisted = loadPersistedMode();
|
|
229
246
|
if (persisted) _setMode(persisted);
|
|
230
247
|
}, []);
|
|
248
|
+
useEffect(() => {
|
|
249
|
+
if (disablePersistence || !isWeb || typeof window === "undefined") return;
|
|
250
|
+
const onStorage = (e) => {
|
|
251
|
+
if (e.key !== STORAGE_KEY || e.newValue == null) return;
|
|
252
|
+
if (e.newValue === "light" || e.newValue === "dark" || e.newValue === "system") {
|
|
253
|
+
_setMode(e.newValue);
|
|
254
|
+
}
|
|
255
|
+
};
|
|
256
|
+
window.addEventListener("storage", onStorage);
|
|
257
|
+
return () => window.removeEventListener("storage", onStorage);
|
|
258
|
+
}, [disablePersistence]);
|
|
231
259
|
const setMode = useCallback((next) => {
|
|
232
260
|
_setMode(next);
|
|
233
261
|
if (!disablePersistence) persistMode(next);
|
|
@@ -300,34 +328,55 @@ function styled(Component, baseClasses = "") {
|
|
|
300
328
|
const disabled = !!props.disabled;
|
|
301
329
|
const checked = !!props.checked;
|
|
302
330
|
const { config } = useTheme();
|
|
303
|
-
const
|
|
331
|
+
const isWebPlatform = getEffectiveIsWeb();
|
|
332
|
+
const isDark = useConditionalGlobalDarkMode(!isWebPlatform);
|
|
304
333
|
const [pressed, setPressed] = useState2(false);
|
|
305
334
|
const [hovered, setHovered] = useState2(false);
|
|
306
335
|
const [focused, setFocused] = useState2(false);
|
|
307
|
-
const handlePressIn = useCallback2(chain(onPressIn, () =>
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
const
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
const
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
const
|
|
336
|
+
const handlePressIn = useCallback2(chain(onPressIn, () => {
|
|
337
|
+
if (!isWebPlatform) setPressed(true);
|
|
338
|
+
}), [onPressIn, isWebPlatform]);
|
|
339
|
+
const handlePressOut = useCallback2(chain(onPressOut, () => {
|
|
340
|
+
if (!isWebPlatform) setPressed(false);
|
|
341
|
+
}), [onPressOut, isWebPlatform]);
|
|
342
|
+
const handlePointerDown = useCallback2(chain(onPointerDown, () => {
|
|
343
|
+
if (!isWebPlatform) setPressed(true);
|
|
344
|
+
}), [onPointerDown, isWebPlatform]);
|
|
345
|
+
const handlePointerUp = useCallback2(chain(onPointerUp, () => {
|
|
346
|
+
if (!isWebPlatform) setPressed(false);
|
|
347
|
+
}), [onPointerUp, isWebPlatform]);
|
|
348
|
+
const handlePointerLeave = useCallback2(chain(onPointerLeave, () => {
|
|
349
|
+
if (!isWebPlatform) setPressed(false);
|
|
350
|
+
}), [onPointerLeave, isWebPlatform]);
|
|
351
|
+
const handlePointerCancel = useCallback2(chain(onPointerCancel, () => {
|
|
352
|
+
if (!isWebPlatform) setPressed(false);
|
|
353
|
+
}), [onPointerCancel, isWebPlatform]);
|
|
354
|
+
const handleMouseEnter = useCallback2(chain(onMouseEnter, () => {
|
|
355
|
+
if (!isWebPlatform) setHovered(true);
|
|
356
|
+
}), [onMouseEnter, isWebPlatform]);
|
|
357
|
+
const handleMouseLeave = useCallback2(chain(onMouseLeave, () => {
|
|
358
|
+
if (!isWebPlatform) setHovered(false);
|
|
359
|
+
}), [onMouseLeave, isWebPlatform]);
|
|
360
|
+
const handleFocus = useCallback2(chain(onFocus, () => {
|
|
361
|
+
if (!isWebPlatform) setFocused(true);
|
|
362
|
+
}), [onFocus, isWebPlatform]);
|
|
363
|
+
const handleBlur = useCallback2(chain(onBlur, () => {
|
|
364
|
+
if (!isWebPlatform) setFocused(false);
|
|
365
|
+
}), [onBlur, isWebPlatform]);
|
|
317
366
|
const combined = extraClasses ? `${baseClasses} ${extraClasses}` : baseClasses;
|
|
318
367
|
const resolved = useMemo3(() => resolve(combined, config.theme, config.darkMode), [combined, config.theme, config.darkMode]);
|
|
319
368
|
const hasInteractive = useMemo3(() => hasInteractiveBuckets(resolved), [resolved]);
|
|
320
369
|
const needsWidth = hasResponsiveBuckets(resolved);
|
|
321
|
-
const width = useConditionalWidth(needsWidth);
|
|
370
|
+
const width = useConditionalWidth(needsWidth && !isWebPlatform);
|
|
322
371
|
const breakpoints = needsWidth ? getActiveBreakpoints(width) : EMPTY_BREAKPOINTS;
|
|
323
372
|
const computedStyle = useMemo3(
|
|
324
|
-
() =>
|
|
373
|
+
() => isWebPlatform ? {} : flatten(resolved, isDark, { pressed, hover: hovered, focus: focused, disabled, checked }, breakpoints),
|
|
325
374
|
[resolved, isDark, pressed, hovered, focused, disabled, checked, width]
|
|
326
375
|
// eslint-disable-line react-hooks/exhaustive-deps
|
|
327
376
|
);
|
|
328
377
|
const extraStyle = Array.isArray(styleProp) ? Object.assign({}, ...styleProp) : styleProp;
|
|
329
|
-
const finalStyle =
|
|
330
|
-
const webTag =
|
|
378
|
+
const finalStyle = isWebPlatform ? extraStyle ?? void 0 : extraStyle ? { ...computedStyle, ...extraStyle } : computedStyle;
|
|
379
|
+
const webTag = isWebPlatform ? getWebTag(Component, rest) : null;
|
|
331
380
|
const effectiveComponent = webTag ?? Component;
|
|
332
381
|
const componentName2 = Component.displayName ?? Component.name ?? "";
|
|
333
382
|
const effectiveRest = webTag && componentName2 ? transformToWebProps(componentName2, webTag, rest) : rest;
|
|
@@ -336,7 +385,7 @@ function styled(Component, baseClasses = "") {
|
|
|
336
385
|
...effectiveRest,
|
|
337
386
|
style: finalStyle,
|
|
338
387
|
// className lets injected CSS rules (group-hover:, before:, print:, etc.) match the element.
|
|
339
|
-
...
|
|
388
|
+
...isWebPlatform && combined ? { className: normalizeClassString(combined) } : {},
|
|
340
389
|
// Only attach state-tracking handlers when interactive modifiers are present.
|
|
341
390
|
// Always forward user-provided handlers to avoid silently swallowing them.
|
|
342
391
|
// Gated on isNative, not isWeb: isWeb is false during SSR too (no `window` there),
|
|
@@ -428,7 +477,7 @@ function useResponsive() {
|
|
|
428
477
|
function kb(classString, isDark = false) {
|
|
429
478
|
const config = getConfig();
|
|
430
479
|
const resolved = resolve(classString, config.theme, config.darkMode);
|
|
431
|
-
if (
|
|
480
|
+
if (getEffectiveIsWeb()) {
|
|
432
481
|
return classString;
|
|
433
482
|
}
|
|
434
483
|
return flatten(resolved, isDark);
|