@native-mate/core 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.
Files changed (111) hide show
  1. package/dist/index.d.ts +17 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +15 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/primitives/Icon/Icon.d.ts +4 -0
  6. package/dist/primitives/Icon/Icon.d.ts.map +1 -0
  7. package/dist/primitives/Icon/Icon.js +10 -0
  8. package/dist/primitives/Icon/Icon.js.map +1 -0
  9. package/dist/primitives/Icon/Icon.types.d.ts +8 -0
  10. package/dist/primitives/Icon/Icon.types.d.ts.map +1 -0
  11. package/dist/primitives/Icon/Icon.types.js +2 -0
  12. package/dist/primitives/Icon/Icon.types.js.map +1 -0
  13. package/dist/primitives/Separator/Separator.d.ts +4 -0
  14. package/dist/primitives/Separator/Separator.d.ts.map +1 -0
  15. package/dist/primitives/Separator/Separator.js +16 -0
  16. package/dist/primitives/Separator/Separator.js.map +1 -0
  17. package/dist/primitives/Separator/Separator.types.d.ts +6 -0
  18. package/dist/primitives/Separator/Separator.types.d.ts.map +1 -0
  19. package/dist/primitives/Separator/Separator.types.js +2 -0
  20. package/dist/primitives/Separator/Separator.types.js.map +1 -0
  21. package/dist/primitives/Spinner/Spinner.d.ts +4 -0
  22. package/dist/primitives/Spinner/Spinner.d.ts.map +1 -0
  23. package/dist/primitives/Spinner/Spinner.js +31 -0
  24. package/dist/primitives/Spinner/Spinner.js.map +1 -0
  25. package/dist/primitives/Spinner/Spinner.types.d.ts +5 -0
  26. package/dist/primitives/Spinner/Spinner.types.d.ts.map +1 -0
  27. package/dist/primitives/Spinner/Spinner.types.js +2 -0
  28. package/dist/primitives/Spinner/Spinner.types.js.map +1 -0
  29. package/dist/primitives/Text/Text.d.ts +4 -0
  30. package/dist/primitives/Text/Text.d.ts.map +1 -0
  31. package/dist/primitives/Text/Text.js +27 -0
  32. package/dist/primitives/Text/Text.js.map +1 -0
  33. package/dist/primitives/Text/Text.types.d.ts +14 -0
  34. package/dist/primitives/Text/Text.types.d.ts.map +1 -0
  35. package/dist/primitives/Text/Text.types.js +2 -0
  36. package/dist/primitives/Text/Text.types.js.map +1 -0
  37. package/dist/theme/ThemeContext.d.ts +4 -0
  38. package/dist/theme/ThemeContext.d.ts.map +1 -0
  39. package/dist/theme/ThemeContext.js +5 -0
  40. package/dist/theme/ThemeContext.js.map +1 -0
  41. package/dist/theme/ThemeProvider.d.ts +14 -0
  42. package/dist/theme/ThemeProvider.d.ts.map +1 -0
  43. package/dist/theme/ThemeProvider.js +11 -0
  44. package/dist/theme/ThemeProvider.js.map +1 -0
  45. package/dist/theme/makeStyles.d.ts +6 -0
  46. package/dist/theme/makeStyles.d.ts.map +1 -0
  47. package/dist/theme/makeStyles.js +10 -0
  48. package/dist/theme/makeStyles.js.map +1 -0
  49. package/dist/theme/useTheme.d.ts +3 -0
  50. package/dist/theme/useTheme.d.ts.map +1 -0
  51. package/dist/theme/useTheme.js +6 -0
  52. package/dist/theme/useTheme.js.map +1 -0
  53. package/dist/tokens/index.d.ts +15 -0
  54. package/dist/tokens/index.d.ts.map +1 -0
  55. package/dist/tokens/index.js +18 -0
  56. package/dist/tokens/index.js.map +1 -0
  57. package/dist/tokens/presets/midnight.d.ts +3 -0
  58. package/dist/tokens/presets/midnight.d.ts.map +1 -0
  59. package/dist/tokens/presets/midnight.js +23 -0
  60. package/dist/tokens/presets/midnight.js.map +1 -0
  61. package/dist/tokens/presets/rose.d.ts +3 -0
  62. package/dist/tokens/presets/rose.d.ts.map +1 -0
  63. package/dist/tokens/presets/rose.js +23 -0
  64. package/dist/tokens/presets/rose.js.map +1 -0
  65. package/dist/tokens/presets/slate.d.ts +3 -0
  66. package/dist/tokens/presets/slate.d.ts.map +1 -0
  67. package/dist/tokens/presets/slate.js +23 -0
  68. package/dist/tokens/presets/slate.js.map +1 -0
  69. package/dist/tokens/presets/zinc.d.ts +3 -0
  70. package/dist/tokens/presets/zinc.d.ts.map +1 -0
  71. package/dist/tokens/presets/zinc.js +36 -0
  72. package/dist/tokens/presets/zinc.js.map +1 -0
  73. package/dist/tokens/types.d.ts +109 -0
  74. package/dist/tokens/types.d.ts.map +1 -0
  75. package/dist/tokens/types.js +2 -0
  76. package/dist/tokens/types.js.map +1 -0
  77. package/dist/utils/platform.d.ts +17 -0
  78. package/dist/utils/platform.d.ts.map +1 -0
  79. package/dist/utils/platform.js +19 -0
  80. package/dist/utils/platform.js.map +1 -0
  81. package/dist/utils/useBreakpoint.d.ts +3 -0
  82. package/dist/utils/useBreakpoint.d.ts.map +1 -0
  83. package/dist/utils/useBreakpoint.js +10 -0
  84. package/dist/utils/useBreakpoint.js.map +1 -0
  85. package/package.json +31 -0
  86. package/src/__tests__/makeStyles.test.ts +56 -0
  87. package/src/__tests__/perf.test.ts +46 -0
  88. package/src/__tests__/platform.test.ts +34 -0
  89. package/src/__tests__/theme.test.ts +58 -0
  90. package/src/__tests__/tokens.test.ts +105 -0
  91. package/src/index.ts +27 -0
  92. package/src/primitives/Icon/Icon.tsx +11 -0
  93. package/src/primitives/Icon/Icon.types.ts +7 -0
  94. package/src/primitives/Separator/Separator.tsx +22 -0
  95. package/src/primitives/Separator/Separator.types.ts +6 -0
  96. package/src/primitives/Spinner/Spinner.tsx +50 -0
  97. package/src/primitives/Spinner/Spinner.types.ts +4 -0
  98. package/src/primitives/Text/Text.tsx +45 -0
  99. package/src/primitives/Text/Text.types.ts +15 -0
  100. package/src/theme/ThemeContext.ts +6 -0
  101. package/src/theme/ThemeProvider.tsx +27 -0
  102. package/src/theme/makeStyles.ts +15 -0
  103. package/src/theme/useTheme.ts +7 -0
  104. package/src/tokens/index.ts +29 -0
  105. package/src/tokens/presets/midnight.ts +24 -0
  106. package/src/tokens/presets/rose.ts +24 -0
  107. package/src/tokens/presets/slate.ts +24 -0
  108. package/src/tokens/presets/zinc.ts +37 -0
  109. package/src/tokens/types.ts +72 -0
  110. package/src/utils/platform.ts +20 -0
  111. package/src/utils/useBreakpoint.ts +10 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zinc.js","sourceRoot":"","sources":["../../../src/tokens/presets/zinc.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,109 @@
1
+ export interface ColorToken {
2
+ light: string;
3
+ dark: string;
4
+ }
5
+ export interface TokenColors {
6
+ background: ColorToken;
7
+ surface: ColorToken;
8
+ surfaceRaised: ColorToken;
9
+ border: ColorToken;
10
+ primary: ColorToken;
11
+ onPrimary: ColorToken;
12
+ foreground: ColorToken;
13
+ onBackground: ColorToken;
14
+ onSurface: ColorToken;
15
+ muted: ColorToken;
16
+ destructive: ColorToken;
17
+ onDestructive: ColorToken;
18
+ success: ColorToken;
19
+ onSuccess: ColorToken;
20
+ warning: ColorToken;
21
+ onWarning: ColorToken;
22
+ }
23
+ export interface TokenSet {
24
+ colors: TokenColors;
25
+ spacing: {
26
+ xs: number;
27
+ sm: number;
28
+ md: number;
29
+ lg: number;
30
+ xl: number;
31
+ '2xl': number;
32
+ '3xl': number;
33
+ };
34
+ radius: {
35
+ sm: number;
36
+ md: number;
37
+ lg: number;
38
+ xl: number;
39
+ full: number;
40
+ };
41
+ typography: {
42
+ size: {
43
+ xs: number;
44
+ sm: number;
45
+ md: number;
46
+ lg: number;
47
+ xl: number;
48
+ '2xl': number;
49
+ '3xl': number;
50
+ };
51
+ weight: {
52
+ regular: string;
53
+ medium: string;
54
+ semibold: string;
55
+ bold: string;
56
+ };
57
+ lineHeight: {
58
+ tight: number;
59
+ normal: number;
60
+ relaxed: number;
61
+ };
62
+ };
63
+ animation: {
64
+ speed: {
65
+ fast: number;
66
+ normal: number;
67
+ slow: number;
68
+ };
69
+ easing: {
70
+ standard: readonly [number, number, number, number];
71
+ decelerate: readonly [number, number, number, number];
72
+ spring: {
73
+ damping: number;
74
+ stiffness: number;
75
+ mass: number;
76
+ };
77
+ };
78
+ };
79
+ }
80
+ export type ResolvedColors = {
81
+ [K in keyof TokenColors]: string;
82
+ };
83
+ export interface ResolvedTheme {
84
+ colors: ResolvedColors;
85
+ spacing: TokenSet['spacing'];
86
+ radius: TokenSet['radius'];
87
+ typography: TokenSet['typography'];
88
+ animation: TokenSet['animation'];
89
+ colorScheme: 'light' | 'dark';
90
+ }
91
+ export type ThemePreset = 'zinc' | 'slate' | 'rose' | 'midnight';
92
+ export interface NativeMateTokenOverrides {
93
+ colors?: Partial<ResolvedColors>;
94
+ spacing?: Partial<TokenSet['spacing']>;
95
+ radius?: Partial<TokenSet['radius']>;
96
+ animation?: {
97
+ speed?: Partial<TokenSet['animation']['speed']>;
98
+ };
99
+ }
100
+ export interface NativeMateConfig {
101
+ theme: ThemePreset;
102
+ componentsDir: string;
103
+ registry: string;
104
+ tokens?: {
105
+ light?: NativeMateTokenOverrides;
106
+ dark?: NativeMateTokenOverrides;
107
+ };
108
+ }
109
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/tokens/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tokens/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,17 @@
1
+ export declare function shadow(level?: 1 | 2 | 3 | 4): {
2
+ shadowColor: string;
3
+ shadowOpacity: number;
4
+ shadowRadius: number;
5
+ shadowOffset: {
6
+ width: number;
7
+ height: number;
8
+ };
9
+ elevation?: undefined;
10
+ } | {
11
+ elevation: number;
12
+ shadowColor?: undefined;
13
+ shadowOpacity?: undefined;
14
+ shadowRadius?: undefined;
15
+ shadowOffset?: undefined;
16
+ };
17
+ //# sourceMappingURL=platform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/utils/platform.ts"],"names":[],"mappings":"AAEA,wBAAgB,MAAM,CAAC,KAAK,GAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAK;;;;;;;;;;;;;;;EAiB9C"}
@@ -0,0 +1,19 @@
1
+ import { Platform } from 'react-native';
2
+ export function shadow(level = 1) {
3
+ const config = {
4
+ 1: { opacity: 0.06, radius: 4, offsetY: 1, elevation: 2 },
5
+ 2: { opacity: 0.10, radius: 8, offsetY: 2, elevation: 4 },
6
+ 3: { opacity: 0.14, radius: 16, offsetY: 4, elevation: 8 },
7
+ 4: { opacity: 0.18, radius: 24, offsetY: 8, elevation: 12 },
8
+ }[level];
9
+ if (Platform.OS === 'ios') {
10
+ return {
11
+ shadowColor: '#000',
12
+ shadowOpacity: config.opacity,
13
+ shadowRadius: config.radius,
14
+ shadowOffset: { width: 0, height: config.offsetY },
15
+ };
16
+ }
17
+ return { elevation: config.elevation };
18
+ }
19
+ //# sourceMappingURL=platform.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.js","sourceRoot":"","sources":["../../src/utils/platform.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAEvC,MAAM,UAAU,MAAM,CAAC,QAAuB,CAAC;IAC7C,MAAM,MAAM,GAAG;QACb,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAG,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE;QAC1D,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,EAAG,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE;QAC1D,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE;QAC1D,CAAC,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE;KAC5D,CAAC,KAAK,CAAC,CAAA;IAER,IAAI,QAAQ,CAAC,EAAE,KAAK,KAAK,EAAE,CAAC;QAC1B,OAAO;YACL,WAAW,EAAE,MAAM;YACnB,aAAa,EAAE,MAAM,CAAC,OAAO;YAC7B,YAAY,EAAE,MAAM,CAAC,MAAM;YAC3B,YAAY,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,EAAE;SACnD,CAAA;IACH,CAAC;IACD,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,CAAA;AACxC,CAAC"}
@@ -0,0 +1,3 @@
1
+ export type Breakpoint = 'sm' | 'md' | 'lg';
2
+ export declare function useBreakpoint(): Breakpoint;
3
+ //# sourceMappingURL=useBreakpoint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useBreakpoint.d.ts","sourceRoot":"","sources":["../../src/utils/useBreakpoint.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAA;AAE3C,wBAAgB,aAAa,IAAI,UAAU,CAK1C"}
@@ -0,0 +1,10 @@
1
+ import { useWindowDimensions } from 'react-native';
2
+ export function useBreakpoint() {
3
+ const { width } = useWindowDimensions();
4
+ if (width >= 1024)
5
+ return 'lg';
6
+ if (width >= 768)
7
+ return 'md';
8
+ return 'sm';
9
+ }
10
+ //# sourceMappingURL=useBreakpoint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useBreakpoint.js","sourceRoot":"","sources":["../../src/utils/useBreakpoint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAA;AAIlD,MAAM,UAAU,aAAa;IAC3B,MAAM,EAAE,KAAK,EAAE,GAAG,mBAAmB,EAAE,CAAA;IACvC,IAAI,KAAK,IAAI,IAAI;QAAE,OAAO,IAAI,CAAA;IAC9B,IAAI,KAAK,IAAI,GAAG;QAAE,OAAO,IAAI,CAAA;IAC7B,OAAO,IAAI,CAAA;AACb,CAAC"}
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "@native-mate/core",
3
+ "version": "0.1.0",
4
+ "description": "Token system, ThemeProvider, and primitive components for native-mate",
5
+ "main": "./dist/index.js",
6
+ "types": "./dist/index.d.ts",
7
+ "files": ["dist", "src"],
8
+ "license": "MIT",
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "https://github.com/native-mate/native-mate",
12
+ "directory": "packages/core"
13
+ },
14
+ "keywords": ["react-native", "expo", "ui", "theme", "tokens", "native-mate"],
15
+ "scripts": {
16
+ "build": "tsc --project tsconfig.json",
17
+ "test": "cd ../.. && npx vitest run --config vitest.config.ts packages/core",
18
+ "lint": "tsc --noEmit"
19
+ },
20
+ "peerDependencies": {
21
+ "react": ">=18.0.0",
22
+ "react-native": ">=0.73.0",
23
+ "react-native-reanimated": ">=3.0.0"
24
+ },
25
+ "devDependencies": {
26
+ "react": "18.2.0",
27
+ "react-native": "0.73.6",
28
+ "react-native-reanimated": "^3.6.0",
29
+ "typescript": "^5.4.0"
30
+ }
31
+ }
@@ -0,0 +1,56 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { resolveTokens, zinc } from '../tokens'
3
+ import { makeStyles } from '../theme/makeStyles'
4
+
5
+ // makeStyles is a factory that returns a hook. We can't call hooks outside
6
+ // React, but we CAN verify the factory itself and the styles it produces.
7
+
8
+ describe('makeStyles', () => {
9
+ it('returns a function (hook)', () => {
10
+ const useStyles = makeStyles((theme) => ({
11
+ container: { backgroundColor: theme.colors.background },
12
+ }))
13
+ expect(typeof useStyles).toBe('function')
14
+ })
15
+
16
+ it('factory receives a theme and returns style objects', () => {
17
+ const theme = resolveTokens(zinc, 'dark')
18
+ const factory = (t: typeof theme) => ({
19
+ box: { padding: t.spacing.md, borderRadius: t.radius.md },
20
+ })
21
+ const styles = factory(theme)
22
+ expect(styles.box.padding).toBe(12)
23
+ expect(styles.box.borderRadius).toBe(10)
24
+ })
25
+
26
+ it('factory can access all token categories', () => {
27
+ const theme = resolveTokens(zinc, 'dark')
28
+ const factory = (t: typeof theme) => ({
29
+ text: {
30
+ color: t.colors.foreground,
31
+ fontSize: t.typography.size.md,
32
+ fontWeight: t.typography.weight.bold,
33
+ lineHeight: t.typography.lineHeight.normal,
34
+ },
35
+ animated: {
36
+ // animation tokens are accessible
37
+ opacity: t.animation.speed.fast > 0 ? 1 : 0,
38
+ },
39
+ })
40
+ const styles = factory(theme)
41
+ expect(styles.text.color).toBe('#fafafa')
42
+ expect(styles.text.fontSize).toBe(15)
43
+ expect(styles.text.fontWeight).toBe('700')
44
+ expect(styles.animated.opacity).toBe(1)
45
+ })
46
+
47
+ it('produces different styles for different presets', () => {
48
+ const darkTheme = resolveTokens(zinc, 'dark')
49
+ const lightTheme = resolveTokens(zinc, 'light')
50
+ const factory = (t: typeof darkTheme) => ({
51
+ bg: { backgroundColor: t.colors.background },
52
+ })
53
+ expect(factory(darkTheme).bg.backgroundColor).toBe('#070709')
54
+ expect(factory(lightTheme).bg.backgroundColor).toBe('#ffffff')
55
+ })
56
+ })
@@ -0,0 +1,46 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { resolveTokens, zinc, slate, rose, midnight, presets } from '../tokens'
3
+
4
+ describe('performance', () => {
5
+ it('resolveTokens runs 10,000 times under 200ms', () => {
6
+ const start = performance.now()
7
+ for (let i = 0; i < 10_000; i++) {
8
+ resolveTokens(zinc, i % 2 === 0 ? 'dark' : 'light')
9
+ }
10
+ const elapsed = performance.now() - start
11
+ expect(elapsed).toBeLessThan(200)
12
+ })
13
+
14
+ it('resolveTokens with overrides runs 10,000 times under 300ms', () => {
15
+ const overrides = { colors: { primary: '#6366f1' }, spacing: { lg: 20 } }
16
+ const start = performance.now()
17
+ for (let i = 0; i < 10_000; i++) {
18
+ resolveTokens(zinc, 'dark', overrides)
19
+ }
20
+ const elapsed = performance.now() - start
21
+ expect(elapsed).toBeLessThan(300)
22
+ })
23
+
24
+ it('all 4 presets × 2 modes (80,000 calls) under 1s', () => {
25
+ const allPresets = [zinc, slate, rose, midnight]
26
+ const start = performance.now()
27
+ for (let i = 0; i < 10_000; i++) {
28
+ for (const preset of allPresets) {
29
+ resolveTokens(preset, 'dark')
30
+ resolveTokens(preset, 'light')
31
+ }
32
+ }
33
+ const elapsed = performance.now() - start
34
+ expect(elapsed).toBeLessThan(1000)
35
+ })
36
+
37
+ it('resolved theme object is consistently shaped', () => {
38
+ const theme = resolveTokens(zinc, 'dark')
39
+ const colorKeys = Object.keys(theme.colors)
40
+ // Verify across all presets
41
+ for (const preset of Object.values(presets)) {
42
+ const t = resolveTokens(preset, 'dark')
43
+ expect(Object.keys(t.colors).sort()).toEqual(colorKeys.sort())
44
+ }
45
+ })
46
+ })
@@ -0,0 +1,34 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { Platform } from 'react-native'
3
+ import { shadow } from '../utils/platform'
4
+
5
+ describe('shadow()', () => {
6
+ it('returns elevation on Android', () => {
7
+ Object.defineProperty(Platform, 'OS', { get: () => 'android', configurable: true })
8
+ const s = shadow(2)
9
+ expect(s).toHaveProperty('elevation')
10
+ expect((s as { elevation: number }).elevation).toBe(4)
11
+ })
12
+
13
+ it('returns shadowColor and shadowOffset on iOS', () => {
14
+ Object.defineProperty(Platform, 'OS', { get: () => 'ios', configurable: true })
15
+ const s = shadow(1)
16
+ expect(s).toHaveProperty('shadowColor')
17
+ expect(s).toHaveProperty('shadowOffset')
18
+ expect(s).toHaveProperty('shadowOpacity')
19
+ expect(s).toHaveProperty('shadowRadius')
20
+ })
21
+
22
+ it('level 1 has lower shadow than level 4', () => {
23
+ Object.defineProperty(Platform, 'OS', { get: () => 'android', configurable: true })
24
+ const s1 = shadow(1) as { elevation: number }
25
+ const s4 = shadow(4) as { elevation: number }
26
+ expect(s4.elevation).toBeGreaterThan(s1.elevation)
27
+ })
28
+
29
+ it('returns elevation object on non-ios (android fallback)', () => {
30
+ Object.defineProperty(Platform, 'OS', { get: () => 'android', configurable: true })
31
+ const s = shadow(3) as { elevation: number }
32
+ expect(s.elevation).toBe(8)
33
+ })
34
+ })
@@ -0,0 +1,58 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { defaultTheme, ThemeContext } from '../theme/ThemeContext'
3
+ import { resolveTokens, zinc, presets } from '../tokens'
4
+
5
+ describe('ThemeContext', () => {
6
+ it('defaultTheme is zinc light', () => {
7
+ const expected = resolveTokens(zinc, 'light')
8
+ expect(defaultTheme.colorScheme).toBe('light')
9
+ expect(defaultTheme.colors.background).toBe(expected.colors.background)
10
+ expect(defaultTheme.colors.foreground).toBe(expected.colors.foreground)
11
+ })
12
+
13
+ it('defaultTheme has all required token categories', () => {
14
+ expect(defaultTheme).toHaveProperty('colors')
15
+ expect(defaultTheme).toHaveProperty('spacing')
16
+ expect(defaultTheme).toHaveProperty('radius')
17
+ expect(defaultTheme).toHaveProperty('typography')
18
+ expect(defaultTheme).toHaveProperty('animation')
19
+ expect(defaultTheme).toHaveProperty('colorScheme')
20
+ })
21
+
22
+ it('ThemeContext is a valid React context', () => {
23
+ expect(ThemeContext).toHaveProperty('Provider')
24
+ expect(ThemeContext).toHaveProperty('Consumer')
25
+ })
26
+ })
27
+
28
+ describe('ThemeProvider logic', () => {
29
+ it('forcedColorScheme dark resolves dark tokens', () => {
30
+ const theme = resolveTokens(presets.zinc, 'dark')
31
+ expect(theme.colorScheme).toBe('dark')
32
+ expect(theme.colors.background).toBe('#070709')
33
+ })
34
+
35
+ it('forcedColorScheme light resolves light tokens', () => {
36
+ const theme = resolveTokens(presets.zinc, 'light')
37
+ expect(theme.colorScheme).toBe('light')
38
+ expect(theme.colors.background).toBe('#ffffff')
39
+ })
40
+
41
+ it('each preset resolves to different primary colors', () => {
42
+ const themes = Object.entries(presets).map(([name, preset]) => ({
43
+ name,
44
+ primary: resolveTokens(preset, 'dark').colors.primary,
45
+ }))
46
+ const primaries = new Set(themes.map((t) => t.primary))
47
+ // At least 3 unique primaries across 4 presets (zinc and slate may share)
48
+ expect(primaries.size).toBeGreaterThanOrEqual(3)
49
+ })
50
+
51
+ it('overrides are applied per-mode', () => {
52
+ const darkOverrides = { colors: { primary: '#ff0000' } }
53
+ const darkTheme = resolveTokens(presets.zinc, 'dark', darkOverrides)
54
+ const lightTheme = resolveTokens(presets.zinc, 'light')
55
+ expect(darkTheme.colors.primary).toBe('#ff0000')
56
+ expect(lightTheme.colors.primary).not.toBe('#ff0000')
57
+ })
58
+ })
@@ -0,0 +1,105 @@
1
+ import { describe, it, expect } from 'vitest'
2
+ import { resolveTokens, zinc, slate, rose, midnight, presets } from '../tokens'
3
+
4
+ describe('resolveTokens', () => {
5
+ it('resolves zinc dark mode correctly', () => {
6
+ const theme = resolveTokens(zinc, 'dark')
7
+ expect(theme.colors.background).toBe('#070709')
8
+ expect(theme.colors.foreground).toBe('#fafafa')
9
+ expect(theme.colorScheme).toBe('dark')
10
+ })
11
+
12
+ it('resolves zinc light mode correctly', () => {
13
+ const theme = resolveTokens(zinc, 'light')
14
+ expect(theme.colors.background).toBe('#ffffff')
15
+ expect(theme.colors.foreground).toBe('#09090b')
16
+ expect(theme.colorScheme).toBe('light')
17
+ })
18
+
19
+ it('returns non-color tokens unchanged', () => {
20
+ const theme = resolveTokens(zinc, 'dark')
21
+ expect(theme.spacing.lg).toBe(16)
22
+ expect(theme.spacing.xl).toBe(24)
23
+ expect(theme.radius.md).toBe(10)
24
+ expect(theme.typography.size.md).toBe(15)
25
+ expect(theme.typography.weight.bold).toBe('700')
26
+ })
27
+
28
+ it('lineHeight values are absolute pixels, not multipliers', () => {
29
+ const theme = resolveTokens(zinc, 'dark')
30
+ expect(theme.typography.lineHeight.tight).toBe(18)
31
+ expect(theme.typography.lineHeight.normal).toBe(22)
32
+ expect(theme.typography.lineHeight.relaxed).toBe(28)
33
+ })
34
+
35
+ it('applies color overrides', () => {
36
+ const theme = resolveTokens(zinc, 'dark', {
37
+ colors: { primary: '#6366f1' },
38
+ })
39
+ expect(theme.colors.primary).toBe('#6366f1')
40
+ expect(theme.colors.background).toBe('#070709') // unchanged
41
+ })
42
+
43
+ it('applies spacing overrides', () => {
44
+ const theme = resolveTokens(zinc, 'dark', {
45
+ spacing: { lg: 20 },
46
+ })
47
+ expect(theme.spacing.lg).toBe(20)
48
+ expect(theme.spacing.sm).toBe(8) // unchanged
49
+ })
50
+
51
+ it('applies radius overrides', () => {
52
+ const theme = resolveTokens(zinc, 'dark', {
53
+ radius: { md: 8 },
54
+ })
55
+ expect(theme.radius.md).toBe(8)
56
+ expect(theme.radius.full).toBe(9999) // unchanged
57
+ })
58
+
59
+ it('applies animation speed overrides', () => {
60
+ const theme = resolveTokens(zinc, 'dark', {
61
+ animation: { speed: { fast: 100 } },
62
+ })
63
+ expect(theme.animation.speed.fast).toBe(100)
64
+ expect(theme.animation.speed.normal).toBe(250) // unchanged
65
+ })
66
+ })
67
+
68
+ describe('presets', () => {
69
+ it('exports all 4 presets', () => {
70
+ expect(presets).toHaveProperty('zinc')
71
+ expect(presets).toHaveProperty('slate')
72
+ expect(presets).toHaveProperty('rose')
73
+ expect(presets).toHaveProperty('midnight')
74
+ })
75
+
76
+ it('slate dark background differs from zinc', () => {
77
+ const zincTheme = resolveTokens(zinc, 'dark')
78
+ const slateTheme = resolveTokens(slate, 'dark')
79
+ expect(slateTheme.colors.background).not.toBe(zincTheme.colors.background)
80
+ })
81
+
82
+ it('rose primary differs from zinc primary in dark mode', () => {
83
+ const zincTheme = resolveTokens(zinc, 'dark')
84
+ const roseTheme = resolveTokens(rose, 'dark')
85
+ expect(roseTheme.colors.primary).not.toBe(zincTheme.colors.primary)
86
+ })
87
+
88
+ it('all presets share same spacing, radius, and typography', () => {
89
+ const zincTheme = resolveTokens(zinc, 'dark')
90
+ const midnightTheme = resolveTokens(midnight, 'dark')
91
+ expect(midnightTheme.spacing).toEqual(zincTheme.spacing)
92
+ expect(midnightTheme.radius).toEqual(zincTheme.radius)
93
+ expect(midnightTheme.typography).toEqual(zincTheme.typography)
94
+ })
95
+
96
+ it('every preset color token resolves to a hex string', () => {
97
+ for (const preset of Object.values(presets)) {
98
+ const theme = resolveTokens(preset, 'dark')
99
+ for (const [key, value] of Object.entries(theme.colors)) {
100
+ expect(typeof value).toBe('string')
101
+ expect(value.startsWith('#')).toBe(true)
102
+ }
103
+ }
104
+ })
105
+ })
package/src/index.ts ADDED
@@ -0,0 +1,27 @@
1
+ // Theme
2
+ export { ThemeProvider } from './theme/ThemeProvider'
3
+ export { useTheme } from './theme/useTheme'
4
+ export { makeStyles } from './theme/makeStyles'
5
+
6
+ // Tokens
7
+ export { presets, resolveTokens, zinc, slate, rose, midnight } from './tokens'
8
+ export type {
9
+ TokenSet, ResolvedTheme, ThemePreset,
10
+ NativeMateConfig, NativeMateTokenOverrides,
11
+ TokenColors, ColorToken, ResolvedColors,
12
+ } from './tokens/types'
13
+
14
+ // Primitives
15
+ export { Text } from './primitives/Text/Text'
16
+ export { Icon } from './primitives/Icon/Icon'
17
+ export { Spinner } from './primitives/Spinner/Spinner'
18
+ export { Separator } from './primitives/Separator/Separator'
19
+ export type { TextProps, TextVariant, TextSize, TextWeight } from './primitives/Text/Text.types'
20
+ export type { IconProps } from './primitives/Icon/Icon.types'
21
+ export type { SpinnerProps } from './primitives/Spinner/Spinner.types'
22
+ export type { SeparatorProps } from './primitives/Separator/Separator.types'
23
+
24
+ // Utils
25
+ export { shadow } from './utils/platform'
26
+ export { useBreakpoint } from './utils/useBreakpoint'
27
+ export type { Breakpoint } from './utils/useBreakpoint'
@@ -0,0 +1,11 @@
1
+ import React from 'react'
2
+ import { useTheme } from '../../theme/useTheme'
3
+ import type { IconProps } from './Icon.types'
4
+
5
+ const sizePx = { xs: 14, sm: 16, md: 20, lg: 24, xl: 32 }
6
+
7
+ export const Icon: React.FC<IconProps> = ({ as: IconComponent, name, size = 'md', color, ...rest }) => {
8
+ const theme = useTheme()
9
+ if (!IconComponent) return null
10
+ return <IconComponent name={name} size={sizePx[size]} color={color ?? theme.colors.foreground} {...rest} />
11
+ }
@@ -0,0 +1,7 @@
1
+ export interface IconProps {
2
+ as?: React.ComponentType<any>
3
+ name?: string
4
+ size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'
5
+ color?: string
6
+ [key: string]: any
7
+ }
@@ -0,0 +1,22 @@
1
+ import React from 'react'
2
+ import { View } from 'react-native'
3
+ import { useTheme } from '../../theme/useTheme'
4
+ import type { SeparatorProps } from './Separator.types'
5
+
6
+ export const Separator: React.FC<SeparatorProps> = ({ orientation = 'horizontal', style }) => {
7
+ const theme = useTheme()
8
+ return (
9
+ <View
10
+ accessible={false}
11
+ style={[
12
+ {
13
+ backgroundColor: theme.colors.border,
14
+ ...(orientation === 'horizontal'
15
+ ? { height: 1, width: '100%' }
16
+ : { width: 1, height: '100%' }),
17
+ },
18
+ style,
19
+ ]}
20
+ />
21
+ )
22
+ }
@@ -0,0 +1,6 @@
1
+ import type { ViewStyle } from 'react-native'
2
+
3
+ export interface SeparatorProps {
4
+ orientation?: 'horizontal' | 'vertical'
5
+ style?: ViewStyle
6
+ }
@@ -0,0 +1,50 @@
1
+ import React, { useEffect } from 'react'
2
+ import { View } from 'react-native'
3
+ import Animated, {
4
+ useSharedValue,
5
+ useAnimatedStyle,
6
+ withRepeat,
7
+ withTiming,
8
+ Easing,
9
+ } from 'react-native-reanimated'
10
+ import { useTheme } from '../../theme/useTheme'
11
+ import type { SpinnerProps } from './Spinner.types'
12
+
13
+ const sizes = { sm: 16, md: 24, lg: 32 }
14
+
15
+ export const Spinner: React.FC<SpinnerProps> = ({ size = 'md', color }) => {
16
+ const theme = useTheme()
17
+ const rotation = useSharedValue(0)
18
+ const px = sizes[size]
19
+ const spinnerColor = color ?? theme.colors.primary
20
+
21
+ useEffect(() => {
22
+ rotation.value = withRepeat(
23
+ withTiming(360, { duration: 900, easing: Easing.linear }),
24
+ -1,
25
+ false,
26
+ )
27
+ }, [])
28
+
29
+ const animatedStyle = useAnimatedStyle(() => ({
30
+ transform: [{ rotate: `${rotation.value}deg` }],
31
+ }))
32
+
33
+ return (
34
+ <View style={{ width: px, height: px }}>
35
+ <Animated.View
36
+ style={[
37
+ animatedStyle,
38
+ {
39
+ width: px,
40
+ height: px,
41
+ borderRadius: px / 2,
42
+ borderWidth: 2,
43
+ borderColor: spinnerColor,
44
+ borderTopColor: 'transparent',
45
+ },
46
+ ]}
47
+ />
48
+ </View>
49
+ )
50
+ }