@kbach/react 0.1.0
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/dist/chunk-FUSJKUE7.mjs +100 -0
- package/dist/chunk-IZK5HMWK.mjs +85 -0
- package/dist/index.d.mts +185 -0
- package/dist/index.d.ts +185 -0
- package/dist/index.js +516 -0
- package/dist/index.mjs +421 -0
- package/dist/jsx-dev-runtime.d.mts +19 -0
- package/dist/jsx-dev-runtime.d.ts +19 -0
- package/dist/jsx-dev-runtime.js +211 -0
- package/dist/jsx-dev-runtime.mjs +15 -0
- package/dist/jsx-runtime.d.mts +17 -0
- package/dist/jsx-runtime.d.ts +17 -0
- package/dist/jsx-runtime.js +206 -0
- package/dist/jsx-runtime.mjs +11 -0
- package/package.json +59 -0
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import {
|
|
2
|
+
InteractiveWrapper,
|
|
3
|
+
useGlobalDarkMode
|
|
4
|
+
} from "./chunk-IZK5HMWK.mjs";
|
|
5
|
+
|
|
6
|
+
// src/jsx-runtime.tsx
|
|
7
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment } from "react/jsx-runtime";
|
|
8
|
+
import { isWeb, getConfig, resolve, flatten as flatten2 } from "@kbach/core";
|
|
9
|
+
|
|
10
|
+
// src/DarkWrapper.tsx
|
|
11
|
+
import React from "react";
|
|
12
|
+
import { flatten } from "@kbach/core";
|
|
13
|
+
var DarkWrapper = React.forwardRef(
|
|
14
|
+
function DarkWrapper2({ Component, resolvedStyle, style: styleProp, children, ...rest }, ref) {
|
|
15
|
+
const isDark = useGlobalDarkMode();
|
|
16
|
+
const computedStyle = flatten(resolvedStyle, isDark);
|
|
17
|
+
const finalStyle = styleProp ? Array.isArray(styleProp) ? Object.assign({}, computedStyle, ...styleProp) : { ...computedStyle, ...styleProp } : computedStyle;
|
|
18
|
+
const props = { ref, ...rest, style: finalStyle };
|
|
19
|
+
return Array.isArray(children) ? React.createElement(Component, props, ...children) : React.createElement(Component, props, children);
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
DarkWrapper.displayName = "Kbach.DarkWrapper";
|
|
23
|
+
|
|
24
|
+
// src/jsx-runtime.tsx
|
|
25
|
+
var MODE_BUCKET_RE = /^(not-)?(dark|light)(:(not-)?(dark|light))*$/;
|
|
26
|
+
function hasInteractiveBuckets(resolved) {
|
|
27
|
+
return Object.keys(resolved).some((key) => {
|
|
28
|
+
if (key === "base") return false;
|
|
29
|
+
if (/^(sm|md|lg|xl|2xl)$/.test(key)) return false;
|
|
30
|
+
if (MODE_BUCKET_RE.test(key)) return false;
|
|
31
|
+
return true;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
var CONSUMED_PROPS = /* @__PURE__ */ new Set(["className", "tw", "__kbachStyles", "__kbachClasses"]);
|
|
35
|
+
function omitConsumed(props) {
|
|
36
|
+
const out = {};
|
|
37
|
+
for (const key of Object.keys(props)) {
|
|
38
|
+
if (!CONSUMED_PROPS.has(key)) out[key] = props[key];
|
|
39
|
+
}
|
|
40
|
+
return out;
|
|
41
|
+
}
|
|
42
|
+
function mergeStyle(computed, userStyle) {
|
|
43
|
+
if (!userStyle) return computed;
|
|
44
|
+
if (Array.isArray(userStyle)) return Object.assign({}, computed, ...userStyle);
|
|
45
|
+
return { ...computed, ...userStyle };
|
|
46
|
+
}
|
|
47
|
+
function makeElement(isStaticChildren, type, props, key) {
|
|
48
|
+
return (isStaticChildren ? _jsxs : _jsx)(type, props, key);
|
|
49
|
+
}
|
|
50
|
+
function processElement(type, rawProps, key, isStaticChildren) {
|
|
51
|
+
if (!rawProps) return _jsx(type, null, key);
|
|
52
|
+
const { className, tw: twProp, __kbachStyles, __kbachClasses } = rawProps;
|
|
53
|
+
const classStr = className ?? twProp ?? __kbachClasses;
|
|
54
|
+
if (!classStr && !__kbachStyles) {
|
|
55
|
+
return makeElement(isStaticChildren, type, rawProps, key);
|
|
56
|
+
}
|
|
57
|
+
const config = getConfig();
|
|
58
|
+
const resolved = __kbachStyles ?? (classStr ? resolve(classStr, config.theme, config.darkMode) : {});
|
|
59
|
+
const { style: userStyle, ...passProps } = omitConsumed(rawProps);
|
|
60
|
+
if (hasInteractiveBuckets(resolved)) {
|
|
61
|
+
return _jsx(InteractiveWrapper, {
|
|
62
|
+
Component: type,
|
|
63
|
+
resolvedStyle: resolved,
|
|
64
|
+
...isWeb && classStr ? { className: classStr } : {},
|
|
65
|
+
style: userStyle,
|
|
66
|
+
...passProps
|
|
67
|
+
}, key);
|
|
68
|
+
}
|
|
69
|
+
const hasModeVariants = Object.keys(resolved).some(
|
|
70
|
+
(k) => k !== "base" && MODE_BUCKET_RE.test(k)
|
|
71
|
+
);
|
|
72
|
+
if (hasModeVariants) {
|
|
73
|
+
return _jsx(DarkWrapper, {
|
|
74
|
+
Component: type,
|
|
75
|
+
resolvedStyle: resolved,
|
|
76
|
+
...isWeb && classStr ? { className: classStr } : {},
|
|
77
|
+
style: userStyle,
|
|
78
|
+
...passProps
|
|
79
|
+
}, key);
|
|
80
|
+
}
|
|
81
|
+
const computedStyle = flatten2(resolved, false);
|
|
82
|
+
const finalStyle = mergeStyle(computedStyle, userStyle);
|
|
83
|
+
return makeElement(isStaticChildren, type, {
|
|
84
|
+
...passProps,
|
|
85
|
+
style: finalStyle,
|
|
86
|
+
...isWeb && classStr ? { className: classStr } : {}
|
|
87
|
+
}, key);
|
|
88
|
+
}
|
|
89
|
+
function jsx(type, props, key) {
|
|
90
|
+
return processElement(type, props, key, false);
|
|
91
|
+
}
|
|
92
|
+
function jsxs(type, props, key) {
|
|
93
|
+
return processElement(type, props, key, true);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export {
|
|
97
|
+
Fragment,
|
|
98
|
+
jsx,
|
|
99
|
+
jsxs
|
|
100
|
+
};
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
2
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
3
|
+
}) : x)(function(x) {
|
|
4
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
5
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
// src/useGlobalDarkMode.ts
|
|
9
|
+
import React from "react";
|
|
10
|
+
import { getGlobalDarkMode, subscribeGlobalDarkMode } from "@kbach/core";
|
|
11
|
+
var useSyncExternalStore = React.useSyncExternalStore ?? function useSyncExternalStoreFallback(subscribe, getSnapshot, _getServerSnapshot) {
|
|
12
|
+
const [, forceUpdate] = React.useReducer((n) => n + 1, 0);
|
|
13
|
+
React.useEffect(() => subscribe(forceUpdate), [subscribe]);
|
|
14
|
+
return getSnapshot();
|
|
15
|
+
};
|
|
16
|
+
function useGlobalDarkMode() {
|
|
17
|
+
return useSyncExternalStore(
|
|
18
|
+
subscribeGlobalDarkMode,
|
|
19
|
+
getGlobalDarkMode,
|
|
20
|
+
() => false
|
|
21
|
+
// SSR: default light
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// src/InteractiveWrapper.tsx
|
|
26
|
+
import React2, { forwardRef, useState, useCallback, useMemo } from "react";
|
|
27
|
+
import { flatten, isWeb } from "@kbach/core";
|
|
28
|
+
function chain(original, extra) {
|
|
29
|
+
return (...args) => {
|
|
30
|
+
original?.(...args);
|
|
31
|
+
extra();
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
var InteractiveWrapper = forwardRef(
|
|
35
|
+
function InteractiveWrapper2({
|
|
36
|
+
Component,
|
|
37
|
+
resolvedStyle,
|
|
38
|
+
className,
|
|
39
|
+
style: styleProp,
|
|
40
|
+
onPressIn,
|
|
41
|
+
onPressOut,
|
|
42
|
+
onMouseEnter,
|
|
43
|
+
onMouseLeave,
|
|
44
|
+
onFocus,
|
|
45
|
+
onBlur,
|
|
46
|
+
...rest
|
|
47
|
+
}, ref) {
|
|
48
|
+
const isDark = useGlobalDarkMode();
|
|
49
|
+
const [pressed, setPressed] = useState(false);
|
|
50
|
+
const [hovered, setHovered] = useState(false);
|
|
51
|
+
const [focused, setFocused] = useState(false);
|
|
52
|
+
const handlePressIn = useCallback(chain(onPressIn, () => setPressed(true)), [onPressIn]);
|
|
53
|
+
const handlePressOut = useCallback(chain(onPressOut, () => setPressed(false)), [onPressOut]);
|
|
54
|
+
const handleMouseEnter = useCallback(chain(onMouseEnter, () => setHovered(true)), [onMouseEnter]);
|
|
55
|
+
const handleMouseLeave = useCallback(chain(onMouseLeave, () => setHovered(false)), [onMouseLeave]);
|
|
56
|
+
const handleFocus = useCallback(chain(onFocus, () => setFocused(true)), [onFocus]);
|
|
57
|
+
const handleBlur = useCallback(chain(onBlur, () => setFocused(false)), [onBlur]);
|
|
58
|
+
const computedStyle = useMemo(
|
|
59
|
+
() => flatten(resolvedStyle, isDark, { pressed, hover: hovered, focus: focused }),
|
|
60
|
+
[resolvedStyle, isDark, pressed, hovered, focused]
|
|
61
|
+
);
|
|
62
|
+
const finalStyle = styleProp ? Array.isArray(styleProp) ? Object.assign({}, computedStyle, ...styleProp) : { ...computedStyle, ...styleProp } : computedStyle;
|
|
63
|
+
const { children, ...restWithoutChildren } = rest;
|
|
64
|
+
const componentProps = {
|
|
65
|
+
ref,
|
|
66
|
+
...restWithoutChildren,
|
|
67
|
+
style: finalStyle,
|
|
68
|
+
...isWeb && className ? { className } : {},
|
|
69
|
+
onPressIn: handlePressIn,
|
|
70
|
+
onPressOut: handlePressOut,
|
|
71
|
+
onMouseEnter: handleMouseEnter,
|
|
72
|
+
onMouseLeave: handleMouseLeave,
|
|
73
|
+
onFocus: handleFocus,
|
|
74
|
+
onBlur: handleBlur
|
|
75
|
+
};
|
|
76
|
+
return Array.isArray(children) ? React2.createElement(Component, componentProps, ...children) : React2.createElement(Component, componentProps, children);
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
InteractiveWrapper.displayName = "Kbach.InteractiveWrapper";
|
|
80
|
+
|
|
81
|
+
export {
|
|
82
|
+
__require,
|
|
83
|
+
useGlobalDarkMode,
|
|
84
|
+
InteractiveWrapper
|
|
85
|
+
};
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import React__default, { ReactNode, ComponentType, ForwardRefExoticComponent } from 'react';
|
|
3
|
+
import * as _kbach_core from '@kbach/core';
|
|
4
|
+
import { ThemeMode, ResolvedConfig, FrameworkConfig, StyleValue, ResolvedStyle } from '@kbach/core';
|
|
5
|
+
export { FrameworkConfig, ParsedClass, PluginAPI, ResolvedConfig, ResolvedStyle, StyleValue, ThemeConfig, ThemeMode, defaultColors, defaultTheme, flatten, getConfig, parseClass, parseClasses, resolve, updateConfig } from '@kbach/core';
|
|
6
|
+
|
|
7
|
+
interface ThemeContextValue {
|
|
8
|
+
/** The user-selected mode ('light' | 'dark' | 'system') */
|
|
9
|
+
mode: ThemeMode;
|
|
10
|
+
/** The effective resolved mode (never 'system') */
|
|
11
|
+
resolvedMode: 'light' | 'dark';
|
|
12
|
+
/** Convenience boolean */
|
|
13
|
+
isDark: boolean;
|
|
14
|
+
/** Change the theme mode programmatically */
|
|
15
|
+
setMode: (mode: ThemeMode) => void;
|
|
16
|
+
/** Toggle between light and dark (ignores system) */
|
|
17
|
+
toggle: () => void;
|
|
18
|
+
/** The fully resolved framework config (theme values, darkMode strategy, etc.) */
|
|
19
|
+
config: ResolvedConfig;
|
|
20
|
+
}
|
|
21
|
+
declare const ThemeContext: React.Context<ThemeContextValue | null>;
|
|
22
|
+
declare function useTheme(): ThemeContextValue;
|
|
23
|
+
|
|
24
|
+
interface ThemeProviderProps {
|
|
25
|
+
children: ReactNode;
|
|
26
|
+
/** Default mode on first render. Falls back to persisted value, then 'system'. */
|
|
27
|
+
defaultMode?: ThemeMode;
|
|
28
|
+
/** Override the config (useful for per-tree config). Defaults to global getConfig(). */
|
|
29
|
+
config?: FrameworkConfig;
|
|
30
|
+
/** Disable persistence to localStorage / AsyncStorage */
|
|
31
|
+
disablePersistence?: boolean;
|
|
32
|
+
}
|
|
33
|
+
declare function ThemeProvider({ children, defaultMode, config: configOverride, disablePersistence, }: ThemeProviderProps): React__default.JSX.Element;
|
|
34
|
+
|
|
35
|
+
type ToggleVariant = 'button' | 'switch' | 'icon-button';
|
|
36
|
+
interface ThemeToggleProps {
|
|
37
|
+
/** Visual variant. Default: 'button' */
|
|
38
|
+
variant?: ToggleVariant;
|
|
39
|
+
/** Override label text (button variant) */
|
|
40
|
+
label?: string;
|
|
41
|
+
/** Custom light-mode label */
|
|
42
|
+
lightLabel?: string;
|
|
43
|
+
/** Custom dark-mode label */
|
|
44
|
+
darkLabel?: string;
|
|
45
|
+
/** Show system mode option */
|
|
46
|
+
includeSystem?: boolean;
|
|
47
|
+
/** Custom styles applied to the root container */
|
|
48
|
+
style?: object;
|
|
49
|
+
/** Custom styles for the label text */
|
|
50
|
+
labelStyle?: object;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Drop-in theme toggle. Works on web and React Native.
|
|
54
|
+
*
|
|
55
|
+
* ```tsx
|
|
56
|
+
* <ThemeToggle />
|
|
57
|
+
* <ThemeToggle variant="switch" />
|
|
58
|
+
* <ThemeToggle variant="icon-button" lightLabel="☀️" darkLabel="🌙" />
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
declare function ThemeToggle({ variant, label, lightLabel, darkLabel, includeSystem, style, labelStyle, }: ThemeToggleProps): React__default.JSX.Element;
|
|
62
|
+
|
|
63
|
+
interface StyledProps {
|
|
64
|
+
/** Additional utility classes applied on top of the base classes */
|
|
65
|
+
tw?: string;
|
|
66
|
+
/** Merged with resolved tw styles; applied last */
|
|
67
|
+
style?: StyleValue | StyleValue[];
|
|
68
|
+
}
|
|
69
|
+
type OmittedKeys = 'style';
|
|
70
|
+
/**
|
|
71
|
+
* Create a styled component from any React / React Native component.
|
|
72
|
+
*
|
|
73
|
+
* ```tsx
|
|
74
|
+
* const Card = styled(View, 'bg-white dark:bg-gray-800 rounded-xl p-4 shadow-md');
|
|
75
|
+
* const Button = styled(TouchableOpacity, 'bg-blue-500 pressed:bg-blue-700 dark:bg-blue-600 rounded-lg p-3');
|
|
76
|
+
*
|
|
77
|
+
* // Use it:
|
|
78
|
+
* <Card tw="mt-4">...</Card>
|
|
79
|
+
* <Button onPress={handlePress} tw="w-full" />
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
declare function styled<T extends ComponentType<any>>(Component: T, baseClasses?: string): ForwardRefExoticComponent<Omit<React__default.ComponentPropsWithRef<T>, OmittedKeys> & StyledProps>;
|
|
83
|
+
|
|
84
|
+
interface InteractionState {
|
|
85
|
+
hover?: boolean;
|
|
86
|
+
focus?: boolean;
|
|
87
|
+
/** Maps to 'pressed' and 'active' modifiers */
|
|
88
|
+
pressed?: boolean;
|
|
89
|
+
active?: boolean;
|
|
90
|
+
disabled?: boolean;
|
|
91
|
+
checked?: boolean;
|
|
92
|
+
visited?: boolean;
|
|
93
|
+
placeholder?: boolean;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Resolve a utility class string to a style object for the current theme + state.
|
|
97
|
+
*
|
|
98
|
+
* ```tsx
|
|
99
|
+
* // Basic usage
|
|
100
|
+
* const styles = useStyles('bg-white dark:bg-gray-900 p-4');
|
|
101
|
+
*
|
|
102
|
+
* // With interaction state
|
|
103
|
+
* const [pressed, setPressed] = useState(false);
|
|
104
|
+
* const styles = useStyles('bg-blue-500 pressed:bg-blue-700', { pressed });
|
|
105
|
+
*
|
|
106
|
+
* // Multiple class strings (merged left-to-right)
|
|
107
|
+
* const styles = useStyles(['bg-white p-4', 'dark:bg-gray-900 rounded-xl']);
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
declare function useStyles(classString: string | string[], state?: InteractionState): StyleValue;
|
|
111
|
+
/**
|
|
112
|
+
* Returns the full ResolvedStyle bucket map (base, dark, hover, …).
|
|
113
|
+
* Useful when you need to apply styles selectively or pass them to Animated.
|
|
114
|
+
*/
|
|
115
|
+
declare function useResolvedStyle(classString: string | string[]): _kbach_core.ResolvedStyle;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Subscribe to the global dark-mode store with React's concurrent-safe
|
|
119
|
+
* useSyncExternalStore so that any component using className/tw re-renders
|
|
120
|
+
* immediately when the theme changes — without needing ThemeContext.
|
|
121
|
+
*/
|
|
122
|
+
declare function useGlobalDarkMode(): boolean;
|
|
123
|
+
|
|
124
|
+
interface InteractiveWrapperProps {
|
|
125
|
+
/** The real component to render (View, TouchableOpacity, div, a third-party button…) */
|
|
126
|
+
Component: React__default.ComponentType<any> | string;
|
|
127
|
+
/** Pre-resolved style buckets from resolve() */
|
|
128
|
+
resolvedStyle: ResolvedStyle;
|
|
129
|
+
/** On web: original class string so CSS pseudo-rules still fire */
|
|
130
|
+
className?: string;
|
|
131
|
+
/** Extra style prop passed by the user */
|
|
132
|
+
style?: StyleValue | StyleValue[];
|
|
133
|
+
children?: React__default.ReactNode;
|
|
134
|
+
onPressIn?: (...args: any[]) => void;
|
|
135
|
+
onPressOut?: (...args: any[]) => void;
|
|
136
|
+
onMouseEnter?: (...args: any[]) => void;
|
|
137
|
+
onMouseLeave?: (...args: any[]) => void;
|
|
138
|
+
onFocus?: (...args: any[]) => void;
|
|
139
|
+
onBlur?: (...args: any[]) => void;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Thin wrapper rendered automatically by the JSX runtime whenever a className/tw
|
|
143
|
+
* string contains interactive modifiers (hover:, pressed:, focus:, active:, …).
|
|
144
|
+
*
|
|
145
|
+
* Manages interaction state locally and flattens the correct style bucket on
|
|
146
|
+
* every render. The wrapped component sees a plain `style` prop — it never
|
|
147
|
+
* knows it was wrapped.
|
|
148
|
+
*
|
|
149
|
+
* Refs are forwarded so the host component's imperative API still works.
|
|
150
|
+
*/
|
|
151
|
+
declare const InteractiveWrapper: React__default.ForwardRefExoticComponent<InteractiveWrapperProps & React__default.RefAttributes<unknown>>;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Resolve a utility class string outside of a React component.
|
|
155
|
+
*
|
|
156
|
+
* On **native** — returns a StyleValue (style object) for the given mode.
|
|
157
|
+
* On **web** — injects CSS and returns the original class string (use as className).
|
|
158
|
+
*
|
|
159
|
+
* ```ts
|
|
160
|
+
* // Inside a component use useStyles() instead.
|
|
161
|
+
* // tw() is useful for StyleSheet.create() calls and static values.
|
|
162
|
+
*
|
|
163
|
+
* const styles = StyleSheet.create({
|
|
164
|
+
* container: tw('flex-1 bg-white p-4') as any,
|
|
165
|
+
* });
|
|
166
|
+
*
|
|
167
|
+
* // Web: use as className
|
|
168
|
+
* <div className={tw('bg-white dark:bg-gray-900 p-4') as string} />
|
|
169
|
+
* ```
|
|
170
|
+
*
|
|
171
|
+
* @param classString Space-separated utility classes
|
|
172
|
+
* @param isDark Whether dark mode is active (default: false)
|
|
173
|
+
*/
|
|
174
|
+
declare function tw(classString: string, isDark?: boolean): StyleValue | string;
|
|
175
|
+
/**
|
|
176
|
+
* Conditionally join class names. Falsy values are ignored.
|
|
177
|
+
*
|
|
178
|
+
* ```ts
|
|
179
|
+
* cx('bg-white p-4', isActive && 'border-2 border-blue-500', undefined)
|
|
180
|
+
* // → 'bg-white p-4 border-2 border-blue-500'
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
declare function cx(...classes: Array<string | false | null | undefined>): string;
|
|
184
|
+
|
|
185
|
+
export { type InteractionState, InteractiveWrapper, type InteractiveWrapperProps, type StyledProps, ThemeContext, type ThemeContextValue, ThemeProvider, type ThemeProviderProps, ThemeToggle, type ThemeToggleProps, type ToggleVariant, cx, styled, tw, useGlobalDarkMode, useResolvedStyle, useStyles, useTheme };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import React__default, { ReactNode, ComponentType, ForwardRefExoticComponent } from 'react';
|
|
3
|
+
import * as _kbach_core from '@kbach/core';
|
|
4
|
+
import { ThemeMode, ResolvedConfig, FrameworkConfig, StyleValue, ResolvedStyle } from '@kbach/core';
|
|
5
|
+
export { FrameworkConfig, ParsedClass, PluginAPI, ResolvedConfig, ResolvedStyle, StyleValue, ThemeConfig, ThemeMode, defaultColors, defaultTheme, flatten, getConfig, parseClass, parseClasses, resolve, updateConfig } from '@kbach/core';
|
|
6
|
+
|
|
7
|
+
interface ThemeContextValue {
|
|
8
|
+
/** The user-selected mode ('light' | 'dark' | 'system') */
|
|
9
|
+
mode: ThemeMode;
|
|
10
|
+
/** The effective resolved mode (never 'system') */
|
|
11
|
+
resolvedMode: 'light' | 'dark';
|
|
12
|
+
/** Convenience boolean */
|
|
13
|
+
isDark: boolean;
|
|
14
|
+
/** Change the theme mode programmatically */
|
|
15
|
+
setMode: (mode: ThemeMode) => void;
|
|
16
|
+
/** Toggle between light and dark (ignores system) */
|
|
17
|
+
toggle: () => void;
|
|
18
|
+
/** The fully resolved framework config (theme values, darkMode strategy, etc.) */
|
|
19
|
+
config: ResolvedConfig;
|
|
20
|
+
}
|
|
21
|
+
declare const ThemeContext: React.Context<ThemeContextValue | null>;
|
|
22
|
+
declare function useTheme(): ThemeContextValue;
|
|
23
|
+
|
|
24
|
+
interface ThemeProviderProps {
|
|
25
|
+
children: ReactNode;
|
|
26
|
+
/** Default mode on first render. Falls back to persisted value, then 'system'. */
|
|
27
|
+
defaultMode?: ThemeMode;
|
|
28
|
+
/** Override the config (useful for per-tree config). Defaults to global getConfig(). */
|
|
29
|
+
config?: FrameworkConfig;
|
|
30
|
+
/** Disable persistence to localStorage / AsyncStorage */
|
|
31
|
+
disablePersistence?: boolean;
|
|
32
|
+
}
|
|
33
|
+
declare function ThemeProvider({ children, defaultMode, config: configOverride, disablePersistence, }: ThemeProviderProps): React__default.JSX.Element;
|
|
34
|
+
|
|
35
|
+
type ToggleVariant = 'button' | 'switch' | 'icon-button';
|
|
36
|
+
interface ThemeToggleProps {
|
|
37
|
+
/** Visual variant. Default: 'button' */
|
|
38
|
+
variant?: ToggleVariant;
|
|
39
|
+
/** Override label text (button variant) */
|
|
40
|
+
label?: string;
|
|
41
|
+
/** Custom light-mode label */
|
|
42
|
+
lightLabel?: string;
|
|
43
|
+
/** Custom dark-mode label */
|
|
44
|
+
darkLabel?: string;
|
|
45
|
+
/** Show system mode option */
|
|
46
|
+
includeSystem?: boolean;
|
|
47
|
+
/** Custom styles applied to the root container */
|
|
48
|
+
style?: object;
|
|
49
|
+
/** Custom styles for the label text */
|
|
50
|
+
labelStyle?: object;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Drop-in theme toggle. Works on web and React Native.
|
|
54
|
+
*
|
|
55
|
+
* ```tsx
|
|
56
|
+
* <ThemeToggle />
|
|
57
|
+
* <ThemeToggle variant="switch" />
|
|
58
|
+
* <ThemeToggle variant="icon-button" lightLabel="☀️" darkLabel="🌙" />
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
declare function ThemeToggle({ variant, label, lightLabel, darkLabel, includeSystem, style, labelStyle, }: ThemeToggleProps): React__default.JSX.Element;
|
|
62
|
+
|
|
63
|
+
interface StyledProps {
|
|
64
|
+
/** Additional utility classes applied on top of the base classes */
|
|
65
|
+
tw?: string;
|
|
66
|
+
/** Merged with resolved tw styles; applied last */
|
|
67
|
+
style?: StyleValue | StyleValue[];
|
|
68
|
+
}
|
|
69
|
+
type OmittedKeys = 'style';
|
|
70
|
+
/**
|
|
71
|
+
* Create a styled component from any React / React Native component.
|
|
72
|
+
*
|
|
73
|
+
* ```tsx
|
|
74
|
+
* const Card = styled(View, 'bg-white dark:bg-gray-800 rounded-xl p-4 shadow-md');
|
|
75
|
+
* const Button = styled(TouchableOpacity, 'bg-blue-500 pressed:bg-blue-700 dark:bg-blue-600 rounded-lg p-3');
|
|
76
|
+
*
|
|
77
|
+
* // Use it:
|
|
78
|
+
* <Card tw="mt-4">...</Card>
|
|
79
|
+
* <Button onPress={handlePress} tw="w-full" />
|
|
80
|
+
* ```
|
|
81
|
+
*/
|
|
82
|
+
declare function styled<T extends ComponentType<any>>(Component: T, baseClasses?: string): ForwardRefExoticComponent<Omit<React__default.ComponentPropsWithRef<T>, OmittedKeys> & StyledProps>;
|
|
83
|
+
|
|
84
|
+
interface InteractionState {
|
|
85
|
+
hover?: boolean;
|
|
86
|
+
focus?: boolean;
|
|
87
|
+
/** Maps to 'pressed' and 'active' modifiers */
|
|
88
|
+
pressed?: boolean;
|
|
89
|
+
active?: boolean;
|
|
90
|
+
disabled?: boolean;
|
|
91
|
+
checked?: boolean;
|
|
92
|
+
visited?: boolean;
|
|
93
|
+
placeholder?: boolean;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Resolve a utility class string to a style object for the current theme + state.
|
|
97
|
+
*
|
|
98
|
+
* ```tsx
|
|
99
|
+
* // Basic usage
|
|
100
|
+
* const styles = useStyles('bg-white dark:bg-gray-900 p-4');
|
|
101
|
+
*
|
|
102
|
+
* // With interaction state
|
|
103
|
+
* const [pressed, setPressed] = useState(false);
|
|
104
|
+
* const styles = useStyles('bg-blue-500 pressed:bg-blue-700', { pressed });
|
|
105
|
+
*
|
|
106
|
+
* // Multiple class strings (merged left-to-right)
|
|
107
|
+
* const styles = useStyles(['bg-white p-4', 'dark:bg-gray-900 rounded-xl']);
|
|
108
|
+
* ```
|
|
109
|
+
*/
|
|
110
|
+
declare function useStyles(classString: string | string[], state?: InteractionState): StyleValue;
|
|
111
|
+
/**
|
|
112
|
+
* Returns the full ResolvedStyle bucket map (base, dark, hover, …).
|
|
113
|
+
* Useful when you need to apply styles selectively or pass them to Animated.
|
|
114
|
+
*/
|
|
115
|
+
declare function useResolvedStyle(classString: string | string[]): _kbach_core.ResolvedStyle;
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Subscribe to the global dark-mode store with React's concurrent-safe
|
|
119
|
+
* useSyncExternalStore so that any component using className/tw re-renders
|
|
120
|
+
* immediately when the theme changes — without needing ThemeContext.
|
|
121
|
+
*/
|
|
122
|
+
declare function useGlobalDarkMode(): boolean;
|
|
123
|
+
|
|
124
|
+
interface InteractiveWrapperProps {
|
|
125
|
+
/** The real component to render (View, TouchableOpacity, div, a third-party button…) */
|
|
126
|
+
Component: React__default.ComponentType<any> | string;
|
|
127
|
+
/** Pre-resolved style buckets from resolve() */
|
|
128
|
+
resolvedStyle: ResolvedStyle;
|
|
129
|
+
/** On web: original class string so CSS pseudo-rules still fire */
|
|
130
|
+
className?: string;
|
|
131
|
+
/** Extra style prop passed by the user */
|
|
132
|
+
style?: StyleValue | StyleValue[];
|
|
133
|
+
children?: React__default.ReactNode;
|
|
134
|
+
onPressIn?: (...args: any[]) => void;
|
|
135
|
+
onPressOut?: (...args: any[]) => void;
|
|
136
|
+
onMouseEnter?: (...args: any[]) => void;
|
|
137
|
+
onMouseLeave?: (...args: any[]) => void;
|
|
138
|
+
onFocus?: (...args: any[]) => void;
|
|
139
|
+
onBlur?: (...args: any[]) => void;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Thin wrapper rendered automatically by the JSX runtime whenever a className/tw
|
|
143
|
+
* string contains interactive modifiers (hover:, pressed:, focus:, active:, …).
|
|
144
|
+
*
|
|
145
|
+
* Manages interaction state locally and flattens the correct style bucket on
|
|
146
|
+
* every render. The wrapped component sees a plain `style` prop — it never
|
|
147
|
+
* knows it was wrapped.
|
|
148
|
+
*
|
|
149
|
+
* Refs are forwarded so the host component's imperative API still works.
|
|
150
|
+
*/
|
|
151
|
+
declare const InteractiveWrapper: React__default.ForwardRefExoticComponent<InteractiveWrapperProps & React__default.RefAttributes<unknown>>;
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Resolve a utility class string outside of a React component.
|
|
155
|
+
*
|
|
156
|
+
* On **native** — returns a StyleValue (style object) for the given mode.
|
|
157
|
+
* On **web** — injects CSS and returns the original class string (use as className).
|
|
158
|
+
*
|
|
159
|
+
* ```ts
|
|
160
|
+
* // Inside a component use useStyles() instead.
|
|
161
|
+
* // tw() is useful for StyleSheet.create() calls and static values.
|
|
162
|
+
*
|
|
163
|
+
* const styles = StyleSheet.create({
|
|
164
|
+
* container: tw('flex-1 bg-white p-4') as any,
|
|
165
|
+
* });
|
|
166
|
+
*
|
|
167
|
+
* // Web: use as className
|
|
168
|
+
* <div className={tw('bg-white dark:bg-gray-900 p-4') as string} />
|
|
169
|
+
* ```
|
|
170
|
+
*
|
|
171
|
+
* @param classString Space-separated utility classes
|
|
172
|
+
* @param isDark Whether dark mode is active (default: false)
|
|
173
|
+
*/
|
|
174
|
+
declare function tw(classString: string, isDark?: boolean): StyleValue | string;
|
|
175
|
+
/**
|
|
176
|
+
* Conditionally join class names. Falsy values are ignored.
|
|
177
|
+
*
|
|
178
|
+
* ```ts
|
|
179
|
+
* cx('bg-white p-4', isActive && 'border-2 border-blue-500', undefined)
|
|
180
|
+
* // → 'bg-white p-4 border-2 border-blue-500'
|
|
181
|
+
* ```
|
|
182
|
+
*/
|
|
183
|
+
declare function cx(...classes: Array<string | false | null | undefined>): string;
|
|
184
|
+
|
|
185
|
+
export { type InteractionState, InteractiveWrapper, type InteractiveWrapperProps, type StyledProps, ThemeContext, type ThemeContextValue, ThemeProvider, type ThemeProviderProps, ThemeToggle, type ThemeToggleProps, type ToggleVariant, cx, styled, tw, useGlobalDarkMode, useResolvedStyle, useStyles, useTheme };
|