native-variants 0.1.63 → 0.1.69
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/LICENSE +21 -21
- package/README.md +125 -125
- package/dist/example.js +1 -0
- package/dist/index.d.ts +17 -8
- package/dist/index.js +72 -22
- package/dist/index.js.map +1 -1
- package/dist/lib/cn.d.ts +82 -2
- package/dist/lib/cn.js +138 -8
- package/dist/lib/cn.js.map +1 -1
- package/dist/lib/create-nva.d.ts +209 -6
- package/dist/lib/create-nva.js +460 -47
- package/dist/lib/create-nva.js.map +1 -1
- package/dist/lib/media-query.d.ts +84 -2
- package/dist/lib/media-query.js +103 -9
- package/dist/lib/media-query.js.map +1 -1
- package/dist/provider/create-provider.d.ts +44 -4
- package/dist/provider/create-provider.js +1 -1
- package/dist/provider/create-provider.jsx +110 -9
- package/dist/provider/create-provider.jsx.map +1 -1
- package/dist/provider/theme-provider.d.ts +266 -0
- package/dist/provider/theme-provider.js +1 -0
- package/dist/provider/theme-provider.jsx +328 -0
- package/dist/provider/theme-provider.jsx.map +1 -0
- package/dist/tokens/default-tokens.d.ts +2737 -0
- package/dist/tokens/default-tokens.js +1067 -0
- package/dist/tokens/default-tokens.js.map +1 -0
- package/dist/types.d.ts +318 -3
- package/dist/utils/alpha.d.ts +68 -0
- package/dist/utils/alpha.js +147 -4
- package/dist/utils/alpha.js.map +1 -1
- package/dist/utils/compose-text.d.ts +64 -2
- package/dist/utils/compose-text.js +103 -3
- package/dist/utils/compose-text.js.map +1 -1
- package/package.json +1 -1
- package/dist/utils/compose-refs.d.ts +0 -4
- package/dist/utils/compose-refs.js +0 -39
- package/dist/utils/compose-refs.js.map +0 -1
|
@@ -1,2 +1,84 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Width Query - Calculates a width value based on screen percentage.
|
|
3
|
+
* Returns a pixel-rounded value proportional to screen width.
|
|
4
|
+
*
|
|
5
|
+
* @param widthPercent - Percentage of screen width (0-100) as number or string
|
|
6
|
+
* @returns Pixel value rounded to nearest pixel ratio
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* // Get 50% of screen width
|
|
11
|
+
* const halfWidth = wq(50);
|
|
12
|
+
*
|
|
13
|
+
* // Using string percentage
|
|
14
|
+
* const quarterWidth = wq("25");
|
|
15
|
+
*
|
|
16
|
+
* // In styles
|
|
17
|
+
* const styles = {
|
|
18
|
+
* container: {
|
|
19
|
+
* width: wq(80), // 80% of screen width
|
|
20
|
+
* marginHorizontal: wq(10), // 10% margin on each side
|
|
21
|
+
* }
|
|
22
|
+
* };
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function wq(widthPercent: number | string): number;
|
|
26
|
+
/**
|
|
27
|
+
* Height Query - Calculates a height value based on screen percentage.
|
|
28
|
+
* Returns a pixel-rounded value proportional to screen height.
|
|
29
|
+
*
|
|
30
|
+
* @param heightPercent - Percentage of screen height (0-100) as number or string
|
|
31
|
+
* @returns Pixel value rounded to nearest pixel ratio
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```ts
|
|
35
|
+
* // Get 50% of screen height
|
|
36
|
+
* const halfHeight = hq(50);
|
|
37
|
+
*
|
|
38
|
+
* // Using string percentage
|
|
39
|
+
* const quarterHeight = hq("25");
|
|
40
|
+
*
|
|
41
|
+
* // In styles
|
|
42
|
+
* const styles = {
|
|
43
|
+
* hero: {
|
|
44
|
+
* height: hq(40), // 40% of screen height
|
|
45
|
+
* minHeight: hq(30), // Minimum 30% of screen height
|
|
46
|
+
* }
|
|
47
|
+
* };
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
export declare function hq(heightPercent: number | string): number;
|
|
51
|
+
/**
|
|
52
|
+
* Gets the current screen dimensions.
|
|
53
|
+
* Useful for calculations that need both width and height.
|
|
54
|
+
*
|
|
55
|
+
* @returns Object containing screen width and height in pixels
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* ```ts
|
|
59
|
+
* const { width, height } = getScreenDimensions();
|
|
60
|
+
* const isLandscape = width > height;
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare function getScreenDimensions(): {
|
|
64
|
+
width: number;
|
|
65
|
+
height: number;
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Calculates a responsive font size based on screen width.
|
|
69
|
+
* Ensures text scales appropriately across different device sizes.
|
|
70
|
+
*
|
|
71
|
+
* @param baseFontSize - The base font size in pixels
|
|
72
|
+
* @param scaleFactor - Optional scale factor (default: 0.5, meaning 50% responsive)
|
|
73
|
+
* @returns Scaled font size rounded to nearest pixel
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```ts
|
|
77
|
+
* // Responsive font that scales with screen size
|
|
78
|
+
* const titleSize = responsiveFontSize(24);
|
|
79
|
+
*
|
|
80
|
+
* // Less responsive (only 30% scaling)
|
|
81
|
+
* const subtitleSize = responsiveFontSize(18, 0.3);
|
|
82
|
+
* ```
|
|
83
|
+
*/
|
|
84
|
+
export declare function responsiveFontSize(baseFontSize: number, scaleFactor?: number): number;
|
package/dist/lib/media-query.js
CHANGED
|
@@ -1,19 +1,113 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.wq = wq;
|
|
4
|
+
exports.hq = hq;
|
|
5
|
+
exports.getScreenDimensions = getScreenDimensions;
|
|
6
|
+
exports.responsiveFontSize = responsiveFontSize;
|
|
4
7
|
const react_native_1 = require("react-native");
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
+
/**
|
|
9
|
+
* Current screen dimensions.
|
|
10
|
+
* These values are captured at module load time.
|
|
11
|
+
* For responsive updates, consider using useWindowDimensions hook instead.
|
|
12
|
+
*/
|
|
13
|
+
const screenWidth = react_native_1.Dimensions.get("window").width;
|
|
14
|
+
const screenHeight = react_native_1.Dimensions.get("window").height;
|
|
15
|
+
/**
|
|
16
|
+
* Width Query - Calculates a width value based on screen percentage.
|
|
17
|
+
* Returns a pixel-rounded value proportional to screen width.
|
|
18
|
+
*
|
|
19
|
+
* @param widthPercent - Percentage of screen width (0-100) as number or string
|
|
20
|
+
* @returns Pixel value rounded to nearest pixel ratio
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* // Get 50% of screen width
|
|
25
|
+
* const halfWidth = wq(50);
|
|
26
|
+
*
|
|
27
|
+
* // Using string percentage
|
|
28
|
+
* const quarterWidth = wq("25");
|
|
29
|
+
*
|
|
30
|
+
* // In styles
|
|
31
|
+
* const styles = {
|
|
32
|
+
* container: {
|
|
33
|
+
* width: wq(80), // 80% of screen width
|
|
34
|
+
* marginHorizontal: wq(10), // 10% margin on each side
|
|
35
|
+
* }
|
|
36
|
+
* };
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
function wq(widthPercent) {
|
|
8
40
|
const elemWidth = typeof widthPercent === "number" ? widthPercent : parseFloat(widthPercent);
|
|
9
41
|
return react_native_1.PixelRatio.roundToNearestPixel((screenWidth * elemWidth) / 100);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Height Query - Calculates a height value based on screen percentage.
|
|
45
|
+
* Returns a pixel-rounded value proportional to screen height.
|
|
46
|
+
*
|
|
47
|
+
* @param heightPercent - Percentage of screen height (0-100) as number or string
|
|
48
|
+
* @returns Pixel value rounded to nearest pixel ratio
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* // Get 50% of screen height
|
|
53
|
+
* const halfHeight = hq(50);
|
|
54
|
+
*
|
|
55
|
+
* // Using string percentage
|
|
56
|
+
* const quarterHeight = hq("25");
|
|
57
|
+
*
|
|
58
|
+
* // In styles
|
|
59
|
+
* const styles = {
|
|
60
|
+
* hero: {
|
|
61
|
+
* height: hq(40), // 40% of screen height
|
|
62
|
+
* minHeight: hq(30), // Minimum 30% of screen height
|
|
63
|
+
* }
|
|
64
|
+
* };
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
function hq(heightPercent) {
|
|
13
68
|
const elemHeight = typeof heightPercent === "number"
|
|
14
69
|
? heightPercent
|
|
15
70
|
: parseFloat(heightPercent);
|
|
16
71
|
return react_native_1.PixelRatio.roundToNearestPixel((screenHeight * elemHeight) / 100);
|
|
17
|
-
}
|
|
18
|
-
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Gets the current screen dimensions.
|
|
75
|
+
* Useful for calculations that need both width and height.
|
|
76
|
+
*
|
|
77
|
+
* @returns Object containing screen width and height in pixels
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```ts
|
|
81
|
+
* const { width, height } = getScreenDimensions();
|
|
82
|
+
* const isLandscape = width > height;
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
function getScreenDimensions() {
|
|
86
|
+
return {
|
|
87
|
+
width: screenWidth,
|
|
88
|
+
height: screenHeight,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Calculates a responsive font size based on screen width.
|
|
93
|
+
* Ensures text scales appropriately across different device sizes.
|
|
94
|
+
*
|
|
95
|
+
* @param baseFontSize - The base font size in pixels
|
|
96
|
+
* @param scaleFactor - Optional scale factor (default: 0.5, meaning 50% responsive)
|
|
97
|
+
* @returns Scaled font size rounded to nearest pixel
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```ts
|
|
101
|
+
* // Responsive font that scales with screen size
|
|
102
|
+
* const titleSize = responsiveFontSize(24);
|
|
103
|
+
*
|
|
104
|
+
* // Less responsive (only 30% scaling)
|
|
105
|
+
* const subtitleSize = responsiveFontSize(18, 0.3);
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
function responsiveFontSize(baseFontSize, scaleFactor = 0.5) {
|
|
109
|
+
const scale = screenWidth / 375; // Base scale on iPhone 8/SE width
|
|
110
|
+
const newSize = baseFontSize + (baseFontSize * (scale - 1) * scaleFactor);
|
|
111
|
+
return react_native_1.PixelRatio.roundToNearestPixel(newSize);
|
|
112
|
+
}
|
|
19
113
|
//# sourceMappingURL=media-query.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"media-query.js","sourceRoot":"","sources":["../../src/lib/media-query.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"media-query.js","sourceRoot":"","sources":["../../src/lib/media-query.ts"],"names":[],"mappings":";;AAkCA,gBAKC;AA0BD,gBAOC;AAcD,kDAKC;AAmBD,gDAOC;AArHD,+CAAsD;AAEtD;;;;GAIG;AACH,MAAM,WAAW,GAAG,yBAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC;AACnD,MAAM,YAAY,GAAG,yBAAU,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,SAAgB,EAAE,CAAC,YAA6B;IAC9C,MAAM,SAAS,GACb,OAAO,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;IAE7E,OAAO,yBAAU,CAAC,mBAAmB,CAAC,CAAC,WAAW,GAAG,SAAS,CAAC,GAAG,GAAG,CAAC,CAAC;AACzE,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,SAAgB,EAAE,CAAC,aAA8B;IAC/C,MAAM,UAAU,GACd,OAAO,aAAa,KAAK,QAAQ;QAC/B,CAAC,CAAC,aAAa;QACf,CAAC,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;IAEhC,OAAO,yBAAU,CAAC,mBAAmB,CAAC,CAAC,YAAY,GAAG,UAAU,CAAC,GAAG,GAAG,CAAC,CAAC;AAC3E,CAAC;AAED;;;;;;;;;;;GAWG;AACH,SAAgB,mBAAmB;IACjC,OAAO;QACL,KAAK,EAAE,WAAW;QAClB,MAAM,EAAE,YAAY;KACrB,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,SAAgB,kBAAkB,CAChC,YAAoB,EACpB,cAAsB,GAAG;IAEzB,MAAM,KAAK,GAAG,WAAW,GAAG,GAAG,CAAC,CAAC,kCAAkC;IACnE,MAAM,OAAO,GAAG,YAAY,GAAG,CAAC,YAAY,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC;IAC1E,OAAO,yBAAU,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC;AACjD,CAAC"}
|
|
@@ -1,7 +1,47 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import React from "react";
|
|
2
|
+
/**
|
|
3
|
+
* Creates a type-safe context with provider and hook.
|
|
4
|
+
* Useful for creating component-level contexts for sharing props.
|
|
5
|
+
*
|
|
6
|
+
* @template T - The type of props to share via context
|
|
7
|
+
* @returns Object containing CTXProvider component and useCTX hook
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* // Define props type
|
|
12
|
+
* type ButtonContextProps = {
|
|
13
|
+
* size: "sm" | "md" | "lg";
|
|
14
|
+
* variant: "primary" | "secondary";
|
|
15
|
+
* disabled?: boolean;
|
|
16
|
+
* };
|
|
17
|
+
*
|
|
18
|
+
* // Create context
|
|
19
|
+
* const { CTXProvider: ButtonProvider, useCTX: useButtonContext } =
|
|
20
|
+
* createCTX<ButtonContextProps>();
|
|
21
|
+
*
|
|
22
|
+
* // Use in parent component
|
|
23
|
+
* function ButtonGroup({ children }) {
|
|
24
|
+
* return (
|
|
25
|
+
* <ButtonProvider props={{ size: "md", variant: "primary" }}>
|
|
26
|
+
* {children}
|
|
27
|
+
* </ButtonProvider>
|
|
28
|
+
* );
|
|
29
|
+
* }
|
|
30
|
+
*
|
|
31
|
+
* // Use in child component
|
|
32
|
+
* function ButtonText() {
|
|
33
|
+
* const context = useButtonContext();
|
|
34
|
+
* // context?.size, context?.variant, etc.
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export declare function createCTX<T>(): {
|
|
39
|
+
/** Provider component that makes context available to children */
|
|
40
|
+
CTXProvider: ({ children, props, }: React.PropsWithChildren<{
|
|
4
41
|
props: T;
|
|
5
|
-
}) =>
|
|
42
|
+
}>) => React.JSX.Element;
|
|
43
|
+
/** Hook to optionally consume context (returns undefined if outside provider) */
|
|
6
44
|
useCTX: () => T | undefined;
|
|
45
|
+
/** Hook that requires context (throws if outside provider) */
|
|
46
|
+
useRequiredCTX: (componentName?: string) => T;
|
|
7
47
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createContext,useContext,useMemo}from"react";export
|
|
1
|
+
import React,{createContext,useContext,useMemo}from"react";export function createCTX(){const Context=createContext(undefined);function CTXProvider({children,props}){const value=useMemo(()=>({props}),[props]);return React.createElement(Context.Provider,{value:value},children)}function useCTX(){const context=useContext(Context);if(!context){return undefined}return context.props}function useRequiredCTX(componentName="Component"){const context=useContext(Context);if(!context){throw new Error(`${componentName} must be used within a CTXProvider. `+`Make sure to wrap your component tree with the appropriate provider.`)}return context.props}return{CTXProvider,useCTX,useRequiredCTX}}
|
|
@@ -1,24 +1,125 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
2
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.createCTX =
|
|
4
|
-
const react_1 = require("react");
|
|
5
|
-
|
|
36
|
+
exports.createCTX = createCTX;
|
|
37
|
+
const react_1 = __importStar(require("react"));
|
|
38
|
+
/**
|
|
39
|
+
* Creates a type-safe context with provider and hook.
|
|
40
|
+
* Useful for creating component-level contexts for sharing props.
|
|
41
|
+
*
|
|
42
|
+
* @template T - The type of props to share via context
|
|
43
|
+
* @returns Object containing CTXProvider component and useCTX hook
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* // Define props type
|
|
48
|
+
* type ButtonContextProps = {
|
|
49
|
+
* size: "sm" | "md" | "lg";
|
|
50
|
+
* variant: "primary" | "secondary";
|
|
51
|
+
* disabled?: boolean;
|
|
52
|
+
* };
|
|
53
|
+
*
|
|
54
|
+
* // Create context
|
|
55
|
+
* const { CTXProvider: ButtonProvider, useCTX: useButtonContext } =
|
|
56
|
+
* createCTX<ButtonContextProps>();
|
|
57
|
+
*
|
|
58
|
+
* // Use in parent component
|
|
59
|
+
* function ButtonGroup({ children }) {
|
|
60
|
+
* return (
|
|
61
|
+
* <ButtonProvider props={{ size: "md", variant: "primary" }}>
|
|
62
|
+
* {children}
|
|
63
|
+
* </ButtonProvider>
|
|
64
|
+
* );
|
|
65
|
+
* }
|
|
66
|
+
*
|
|
67
|
+
* // Use in child component
|
|
68
|
+
* function ButtonText() {
|
|
69
|
+
* const context = useButtonContext();
|
|
70
|
+
* // context?.size, context?.variant, etc.
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
function createCTX() {
|
|
6
75
|
const Context = (0, react_1.createContext)(undefined);
|
|
7
|
-
|
|
76
|
+
/**
|
|
77
|
+
* Context Provider component.
|
|
78
|
+
* Wraps children and provides the props value to all descendants.
|
|
79
|
+
*
|
|
80
|
+
* @param children - React children nodes
|
|
81
|
+
* @param props - The props object to provide to context consumers
|
|
82
|
+
*/
|
|
83
|
+
function CTXProvider({ children, props, }) {
|
|
8
84
|
const value = (0, react_1.useMemo)(() => ({ props }), [props]);
|
|
9
85
|
return <Context.Provider value={value}>{children}</Context.Provider>;
|
|
10
|
-
}
|
|
11
|
-
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Hook to consume the context value.
|
|
89
|
+
* Returns undefined if used outside of a CTXProvider.
|
|
90
|
+
*
|
|
91
|
+
* @returns The context props or undefined if outside provider
|
|
92
|
+
*/
|
|
93
|
+
function useCTX() {
|
|
12
94
|
const context = (0, react_1.useContext)(Context);
|
|
13
95
|
if (!context) {
|
|
14
96
|
return undefined;
|
|
15
97
|
}
|
|
16
98
|
return context.props;
|
|
17
|
-
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Hook that requires context to be present.
|
|
102
|
+
* Throws an error if used outside of a CTXProvider.
|
|
103
|
+
*
|
|
104
|
+
* @param componentName - Name of the component using the hook (for error messages)
|
|
105
|
+
* @returns The context props (guaranteed to be defined)
|
|
106
|
+
* @throws Error if used outside of CTXProvider
|
|
107
|
+
*/
|
|
108
|
+
function useRequiredCTX(componentName = "Component") {
|
|
109
|
+
const context = (0, react_1.useContext)(Context);
|
|
110
|
+
if (!context) {
|
|
111
|
+
throw new Error(`${componentName} must be used within a CTXProvider. ` +
|
|
112
|
+
`Make sure to wrap your component tree with the appropriate provider.`);
|
|
113
|
+
}
|
|
114
|
+
return context.props;
|
|
115
|
+
}
|
|
18
116
|
return {
|
|
117
|
+
/** Provider component that makes context available to children */
|
|
19
118
|
CTXProvider,
|
|
119
|
+
/** Hook to optionally consume context (returns undefined if outside provider) */
|
|
20
120
|
useCTX,
|
|
121
|
+
/** Hook that requires context (throws if outside provider) */
|
|
122
|
+
useRequiredCTX,
|
|
21
123
|
};
|
|
22
|
-
}
|
|
23
|
-
exports.createCTX = createCTX;
|
|
124
|
+
}
|
|
24
125
|
//# sourceMappingURL=create-provider.jsx.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-provider.jsx","sourceRoot":"","sources":["../../src/provider/create-provider.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"create-provider.jsx","sourceRoot":"","sources":["../../src/provider/create-provider.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgDA,8BAgEC;AAhHD,+CAAkE;AAYlE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,SAAgB,SAAS;IACvB,MAAM,OAAO,GAAG,IAAA,qBAAa,EAAgC,SAAS,CAAC,CAAC;IAExE;;;;;;OAMG;IACH,SAAS,WAAW,CAAC,EACnB,QAAQ,EACR,KAAK,GACiC;QACtC,MAAM,KAAK,GAAG,IAAA,eAAO,EAAC,GAAG,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QAElD,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IACvE,CAAC;IAED;;;;;OAKG;IACH,SAAS,MAAM;QACb,MAAM,OAAO,GAAG,IAAA,kBAAU,EAAC,OAAO,CAAC,CAAC;QAEpC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,SAAS,CAAC;QACnB,CAAC;QAED,OAAO,OAAO,CAAC,KAAK,CAAC;IACvB,CAAC;IAED;;;;;;;OAOG;IACH,SAAS,cAAc,CAAC,gBAAwB,WAAW;QACzD,MAAM,OAAO,GAAG,IAAA,kBAAU,EAAC,OAAO,CAAC,CAAC;QAEpC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,GAAG,aAAa,sCAAsC;gBACtD,sEAAsE,CACvE,CAAC;QACJ,CAAC;QAED,OAAO,OAAO,CAAC,KAAK,CAAC;IACvB,CAAC;IAED,OAAO;QACL,kEAAkE;QAClE,WAAW;QACX,iFAAiF;QACjF,MAAM;QACN,8DAA8D;QAC9D,cAAc;KACf,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import type { ColorSchemeConfig } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Color scheme options for the theme.
|
|
5
|
+
*/
|
|
6
|
+
export type ColorScheme = "light" | "dark";
|
|
7
|
+
/**
|
|
8
|
+
* Theme mode options.
|
|
9
|
+
* - "light": Always use light theme
|
|
10
|
+
* - "dark": Always use dark theme
|
|
11
|
+
* - "system": Follow system preference
|
|
12
|
+
*/
|
|
13
|
+
export type ThemeMode = ColorScheme | "system";
|
|
14
|
+
/**
|
|
15
|
+
* Theme context value interface.
|
|
16
|
+
*
|
|
17
|
+
* @template T - The colors type
|
|
18
|
+
*/
|
|
19
|
+
export interface ThemeContextValue<T extends Record<string, string>> {
|
|
20
|
+
/** Current color scheme (resolved from mode) */
|
|
21
|
+
colorScheme: ColorScheme;
|
|
22
|
+
/** Current theme mode setting */
|
|
23
|
+
mode: ThemeMode;
|
|
24
|
+
/** Whether dark mode is active */
|
|
25
|
+
isDark: boolean;
|
|
26
|
+
/** Current theme colors based on color scheme */
|
|
27
|
+
colors: T;
|
|
28
|
+
/** Set theme mode */
|
|
29
|
+
setMode: (mode: ThemeMode) => void;
|
|
30
|
+
/** Toggle between light and dark (ignores system) */
|
|
31
|
+
toggle: () => void;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Props for ThemeProvider component.
|
|
35
|
+
*
|
|
36
|
+
* @template T - The colors type
|
|
37
|
+
*/
|
|
38
|
+
export interface ThemeProviderProps<T extends Record<string, string>> {
|
|
39
|
+
/** Child components */
|
|
40
|
+
children: React.ReactNode;
|
|
41
|
+
/**
|
|
42
|
+
* Color scheme configuration with default (light) and dark colors.
|
|
43
|
+
* Get this from createNVA's colorScheme output.
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```tsx
|
|
47
|
+
* const { colorScheme } = createNVA({
|
|
48
|
+
* theme: {
|
|
49
|
+
* colors: {
|
|
50
|
+
* default: { primary: "#000" },
|
|
51
|
+
* dark: { primary: "#fff" },
|
|
52
|
+
* },
|
|
53
|
+
* },
|
|
54
|
+
* });
|
|
55
|
+
*
|
|
56
|
+
* <ThemeProvider colors={colorScheme}>
|
|
57
|
+
* <App />
|
|
58
|
+
* </ThemeProvider>
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
colors: ColorSchemeConfig<T>;
|
|
62
|
+
/** Initial theme mode (default: "system") */
|
|
63
|
+
defaultMode?: ThemeMode;
|
|
64
|
+
/** Custom storage get function for persisting theme preference */
|
|
65
|
+
onGetStorage?: () => Promise<ThemeMode | null>;
|
|
66
|
+
/** Custom storage set function for persisting theme preference */
|
|
67
|
+
onSetStorage?: (mode: ThemeMode) => Promise<void>;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* ThemeProvider component.
|
|
71
|
+
* Provides theme context with dark/light mode support.
|
|
72
|
+
*
|
|
73
|
+
* **Important:** This provider requires colors to be passed explicitly.
|
|
74
|
+
* Get colors from createNVA's colorScheme output.
|
|
75
|
+
*
|
|
76
|
+
* @template T - The colors type
|
|
77
|
+
*
|
|
78
|
+
* @example
|
|
79
|
+
* ```tsx
|
|
80
|
+
* // 1. Create your theme with createNVA
|
|
81
|
+
* const { theme, colorScheme, styled } = createNVA({
|
|
82
|
+
* theme: {
|
|
83
|
+
* colors: {
|
|
84
|
+
* default: {
|
|
85
|
+
* background: "#ffffff",
|
|
86
|
+
* foreground: "#000000",
|
|
87
|
+
* primary: "#3b82f6",
|
|
88
|
+
* },
|
|
89
|
+
* dark: {
|
|
90
|
+
* background: "#0a0a0a",
|
|
91
|
+
* foreground: "#ffffff",
|
|
92
|
+
* primary: "#60a5fa",
|
|
93
|
+
* },
|
|
94
|
+
* },
|
|
95
|
+
* },
|
|
96
|
+
* });
|
|
97
|
+
*
|
|
98
|
+
* // 2. Wrap your app with ThemeProvider
|
|
99
|
+
* function App() {
|
|
100
|
+
* return (
|
|
101
|
+
* <ThemeProvider colors={colorScheme}>
|
|
102
|
+
* <MyApp />
|
|
103
|
+
* </ThemeProvider>
|
|
104
|
+
* );
|
|
105
|
+
* }
|
|
106
|
+
*
|
|
107
|
+
* // 3. Use colors in components
|
|
108
|
+
* function MyComponent() {
|
|
109
|
+
* const { colors, isDark, toggle } = useTheme();
|
|
110
|
+
*
|
|
111
|
+
* return (
|
|
112
|
+
* <View style={{ backgroundColor: colors.background }}>
|
|
113
|
+
* <Text style={{ color: colors.foreground }}>
|
|
114
|
+
* {isDark ? "Dark Mode" : "Light Mode"}
|
|
115
|
+
* </Text>
|
|
116
|
+
* <Button onPress={toggle} title="Toggle" />
|
|
117
|
+
* </View>
|
|
118
|
+
* );
|
|
119
|
+
* }
|
|
120
|
+
*
|
|
121
|
+
* // With AsyncStorage persistence
|
|
122
|
+
* import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
123
|
+
*
|
|
124
|
+
* <ThemeProvider
|
|
125
|
+
* colors={colorScheme}
|
|
126
|
+
* defaultMode="system"
|
|
127
|
+
* onGetStorage={async () => {
|
|
128
|
+
* const mode = await AsyncStorage.getItem("theme-mode");
|
|
129
|
+
* return mode as ThemeMode | null;
|
|
130
|
+
* }}
|
|
131
|
+
* onSetStorage={async (mode) => {
|
|
132
|
+
* await AsyncStorage.setItem("theme-mode", mode);
|
|
133
|
+
* }}
|
|
134
|
+
* >
|
|
135
|
+
* <App />
|
|
136
|
+
* </ThemeProvider>
|
|
137
|
+
* ```
|
|
138
|
+
*/
|
|
139
|
+
export declare function ThemeProvider<T extends Record<string, string>>({ children, colors, defaultMode, onGetStorage, onSetStorage, }: ThemeProviderProps<T>): React.JSX.Element | null;
|
|
140
|
+
/**
|
|
141
|
+
* Hook to access theme context.
|
|
142
|
+
* Must be used within a ThemeProvider.
|
|
143
|
+
*
|
|
144
|
+
* @template T - The colors type
|
|
145
|
+
* @returns Theme context value with colors and controls
|
|
146
|
+
* @throws Error if used outside ThemeProvider
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```tsx
|
|
150
|
+
* function MyComponent() {
|
|
151
|
+
* const { colors, isDark, toggle, setMode } = useTheme<MyColors>();
|
|
152
|
+
*
|
|
153
|
+
* return (
|
|
154
|
+
* <View style={{ backgroundColor: colors.background }}>
|
|
155
|
+
* <Text style={{ color: colors.foreground }}>
|
|
156
|
+
* Current mode: {isDark ? "Dark" : "Light"}
|
|
157
|
+
* </Text>
|
|
158
|
+
* <Button onPress={toggle} title="Toggle Theme" />
|
|
159
|
+
* <Button onPress={() => setMode("system")} title="Use System" />
|
|
160
|
+
* </View>
|
|
161
|
+
* );
|
|
162
|
+
* }
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
export declare function useTheme<T extends Record<string, string>>(): ThemeContextValue<T>;
|
|
166
|
+
/**
|
|
167
|
+
* Hook to access only theme colors.
|
|
168
|
+
* Convenience wrapper around useTheme that returns just the colors.
|
|
169
|
+
*
|
|
170
|
+
* @template T - The colors type
|
|
171
|
+
* @returns Current theme colors
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```tsx
|
|
175
|
+
* function MyComponent() {
|
|
176
|
+
* const colors = useThemeColors<MyColors>();
|
|
177
|
+
*
|
|
178
|
+
* return (
|
|
179
|
+
* <View style={{ backgroundColor: colors.background }}>
|
|
180
|
+
* <Text style={{ color: colors.primary }}>Hello</Text>
|
|
181
|
+
* </View>
|
|
182
|
+
* );
|
|
183
|
+
* }
|
|
184
|
+
* ```
|
|
185
|
+
*/
|
|
186
|
+
export declare function useThemeColors<T extends Record<string, string>>(): T;
|
|
187
|
+
/**
|
|
188
|
+
* Hook to check if dark mode is active.
|
|
189
|
+
* Convenience wrapper for quick dark mode checks.
|
|
190
|
+
*
|
|
191
|
+
* @returns Boolean indicating if dark mode is active
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* ```tsx
|
|
195
|
+
* function MyComponent() {
|
|
196
|
+
* const isDark = useIsDark();
|
|
197
|
+
*
|
|
198
|
+
* return (
|
|
199
|
+
* <Image source={isDark ? darkLogo : lightLogo} />
|
|
200
|
+
* );
|
|
201
|
+
* }
|
|
202
|
+
* ```
|
|
203
|
+
*/
|
|
204
|
+
export declare function useIsDark(): boolean;
|
|
205
|
+
/**
|
|
206
|
+
* Hook to get the current color scheme.
|
|
207
|
+
* Returns "light" or "dark" based on current theme.
|
|
208
|
+
*
|
|
209
|
+
* @returns Current color scheme
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```tsx
|
|
213
|
+
* function MyComponent() {
|
|
214
|
+
* const colorScheme = useColorScheme();
|
|
215
|
+
*
|
|
216
|
+
* return (
|
|
217
|
+
* <StatusBar barStyle={colorScheme === "dark" ? "light-content" : "dark-content"} />
|
|
218
|
+
* );
|
|
219
|
+
* }
|
|
220
|
+
* ```
|
|
221
|
+
*/
|
|
222
|
+
export declare function useColorScheme(): ColorScheme;
|
|
223
|
+
/**
|
|
224
|
+
* Creates a themed style helper that automatically uses current theme colors.
|
|
225
|
+
* Useful for creating styled components with theme access.
|
|
226
|
+
*
|
|
227
|
+
* @template T - The colors type
|
|
228
|
+
* @template S - The styles record type
|
|
229
|
+
* @param styleFactory - Function that receives colors and returns styles
|
|
230
|
+
* @returns Hook that returns computed styles
|
|
231
|
+
*
|
|
232
|
+
* @example
|
|
233
|
+
* ```tsx
|
|
234
|
+
* type MyColors = { card: string; border: string; cardForeground: string };
|
|
235
|
+
*
|
|
236
|
+
* const useCardStyles = createThemedStyles<MyColors, {
|
|
237
|
+
* container: ViewStyle;
|
|
238
|
+
* title: TextStyle;
|
|
239
|
+
* }>((colors) => ({
|
|
240
|
+
* container: {
|
|
241
|
+
* backgroundColor: colors.card,
|
|
242
|
+
* borderColor: colors.border,
|
|
243
|
+
* borderWidth: 1,
|
|
244
|
+
* borderRadius: 8,
|
|
245
|
+
* padding: 16,
|
|
246
|
+
* },
|
|
247
|
+
* title: {
|
|
248
|
+
* color: colors.cardForeground,
|
|
249
|
+
* fontSize: 18,
|
|
250
|
+
* fontWeight: "600",
|
|
251
|
+
* },
|
|
252
|
+
* }));
|
|
253
|
+
*
|
|
254
|
+
* function Card({ title, children }) {
|
|
255
|
+
* const styles = useCardStyles();
|
|
256
|
+
*
|
|
257
|
+
* return (
|
|
258
|
+
* <View style={styles.container}>
|
|
259
|
+
* <Text style={styles.title}>{title}</Text>
|
|
260
|
+
* {children}
|
|
261
|
+
* </View>
|
|
262
|
+
* );
|
|
263
|
+
* }
|
|
264
|
+
* ```
|
|
265
|
+
*/
|
|
266
|
+
export declare function createThemedStyles<T extends Record<string, string>, S extends Record<string, object>>(styleFactory: (colors: T) => S): () => S;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import React,{createContext,useCallback,useContext,useEffect,useMemo,useState}from"react";import{Appearance}from"react-native";const ThemeContext=createContext(undefined);function resolveColorScheme(mode,systemScheme){if(mode==="system"){return systemScheme==="dark"?"dark":"light"}return mode}export function ThemeProvider({children,colors,defaultMode="system",onGetStorage,onSetStorage}){const[mode,setModeState]=useState(defaultMode);const[systemScheme,setSystemScheme]=useState(Appearance.getColorScheme());const[isHydrated,setIsHydrated]=useState(!onGetStorage);useEffect(()=>{if(onGetStorage){onGetStorage().then(storedMode=>{if(storedMode){setModeState(storedMode)}setIsHydrated(true)})}},[onGetStorage]);useEffect(()=>{const subscription=Appearance.addChangeListener(({colorScheme})=>{setSystemScheme(colorScheme)});return()=>subscription.remove()},[]);const setMode=useCallback(newMode=>{setModeState(newMode);if(onSetStorage){onSetStorage(newMode)}},[onSetStorage]);const toggle=useCallback(()=>{const currentScheme=resolveColorScheme(mode,systemScheme);const newMode=currentScheme==="light"?"dark":"light";setMode(newMode)},[mode,systemScheme,setMode]);const value=useMemo(()=>{const colorScheme=resolveColorScheme(mode,systemScheme);return{colorScheme,mode,isDark:colorScheme==="dark",colors:colorScheme==="dark"?colors.dark:colors.default,setMode,toggle}},[mode,systemScheme,colors,setMode,toggle]);if(!isHydrated){return null}return React.createElement(ThemeContext.Provider,{value:value},children)}export function useTheme(){const context=useContext(ThemeContext);if(!context){throw new Error("useTheme must be used within a ThemeProvider. "+"Make sure to wrap your app with <ThemeProvider colors={colorScheme}>.")}return context}export function useThemeColors(){const{colors}=useTheme();return colors}export function useIsDark(){const{isDark}=useTheme();return isDark}export function useColorScheme(){const{colorScheme}=useTheme();return colorScheme}export function createThemedStyles(styleFactory){return function useThemedStyles(){const{colors}=useTheme();return useMemo(()=>styleFactory(colors),[colors])}}
|