@spelyco/react-native 1.0.0-alpha.1 → 1.0.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 (76) hide show
  1. package/README.md +102 -36
  2. package/dist/bootUnistyles.d.ts +2 -0
  3. package/dist/bootUnistyles.d.ts.map +1 -0
  4. package/dist/components/ActionIcon/ActionIcon.d.ts +37 -0
  5. package/dist/components/ActionIcon/ActionIcon.d.ts.map +1 -0
  6. package/dist/components/Box/Box.d.ts +20 -0
  7. package/dist/components/Box/Box.d.ts.map +1 -0
  8. package/dist/components/Box/index.d.ts +2 -0
  9. package/dist/components/Box/index.d.ts.map +1 -0
  10. package/dist/components/Button/Button.d.ts +1 -1
  11. package/dist/components/Button/Button.d.ts.map +1 -1
  12. package/dist/components/Text/Text.d.ts +12 -0
  13. package/dist/components/Text/Text.d.ts.map +1 -0
  14. package/dist/components/Text/index.d.ts +2 -0
  15. package/dist/components/Text/index.d.ts.map +1 -0
  16. package/dist/components/index.d.ts +3 -1
  17. package/dist/components/index.d.ts.map +1 -1
  18. package/dist/hooks/index.d.ts +3 -0
  19. package/dist/hooks/index.d.ts.map +1 -0
  20. package/dist/hooks/useSpelycoColorScheme.d.ts +14 -0
  21. package/dist/hooks/useSpelycoColorScheme.d.ts.map +1 -0
  22. package/dist/index.d.ts +5 -2
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/provider/SpelycoProvider.d.ts +11 -0
  25. package/dist/provider/SpelycoProvider.d.ts.map +1 -0
  26. package/dist/provider/index.d.ts +4 -0
  27. package/dist/provider/index.d.ts.map +1 -0
  28. package/dist/provider/toNavigationTheme.d.ts +20 -0
  29. package/dist/provider/toNavigationTheme.d.ts.map +1 -0
  30. package/dist/provider/toUnistylesTheme.d.ts +24 -0
  31. package/dist/provider/toUnistylesTheme.d.ts.map +1 -0
  32. package/dist/store/colorScheme.d.ts +31 -0
  33. package/dist/store/colorScheme.d.ts.map +1 -0
  34. package/dist/store/index.d.ts +2 -0
  35. package/dist/store/index.d.ts.map +1 -0
  36. package/dist/types.d.ts +5 -4
  37. package/dist/types.d.ts.map +1 -1
  38. package/package.json +11 -8
  39. package/src/bootUnistyles.ts +27 -0
  40. package/src/components/ActionIcon/ActionIcon.test.ts +59 -0
  41. package/src/components/ActionIcon/ActionIcon.tsx +54 -0
  42. package/src/components/Box/Box.test.ts +42 -0
  43. package/src/components/Box/Box.tsx +48 -0
  44. package/src/components/Box/index.ts +1 -0
  45. package/src/components/Button/Button.test.ts +22 -19
  46. package/src/components/Button/Button.tsx +36 -31
  47. package/src/components/Text/Text.test.ts +59 -0
  48. package/src/components/Text/Text.tsx +61 -0
  49. package/src/components/Text/index.ts +1 -0
  50. package/src/components/index.ts +3 -1
  51. package/src/hooks/index.ts +2 -0
  52. package/src/hooks/useSpelycoColorScheme.ts +33 -0
  53. package/src/index.ts +13 -12
  54. package/src/provider/SpelycoProvider.tsx +102 -0
  55. package/src/provider/index.ts +3 -0
  56. package/src/provider/toNavigationTheme.ts +41 -0
  57. package/src/provider/toUnistylesTheme.ts +58 -0
  58. package/src/store/colorScheme.test.ts +105 -0
  59. package/src/store/colorScheme.ts +63 -0
  60. package/src/store/index.ts +5 -0
  61. package/src/types.ts +5 -4
  62. package/dist/configure.d.ts +0 -2
  63. package/dist/configure.d.ts.map +0 -1
  64. package/dist/themes/dark.d.ts +0 -3
  65. package/dist/themes/dark.d.ts.map +0 -1
  66. package/dist/themes/index.d.ts +0 -12
  67. package/dist/themes/index.d.ts.map +0 -1
  68. package/dist/themes/light.d.ts +0 -29
  69. package/dist/themes/light.d.ts.map +0 -1
  70. package/dist/unistyles.d.ts +0 -8
  71. package/dist/unistyles.d.ts.map +0 -1
  72. package/src/configure.ts +0 -3
  73. package/src/themes/dark.ts +0 -29
  74. package/src/themes/index.ts +0 -13
  75. package/src/themes/light.ts +0 -55
  76. package/src/unistyles.ts +0 -27
package/README.md CHANGED
@@ -8,6 +8,9 @@ React Native UI components for Spelyco, powered by [Unistyles 3](https://www.uni
8
8
 
9
9
  ```bash
10
10
  bun add @spelyco/react-native \
11
+ @react-native-async-storage/async-storage \
12
+ expo-status-bar \
13
+ expo-system-ui \
11
14
  react-native-unistyles \
12
15
  react-native-edge-to-edge \
13
16
  react-native-nitro-modules \
@@ -44,48 +47,36 @@ module.exports = function (api) {
44
47
  };
45
48
  ```
46
49
 
47
- ### 2. TypeScript theme augmentation (recommended)
50
+ ### 2. Wrap your app with `SpelycoProvider`
48
51
 
49
- Because TypeScript module augmentations don't auto-propagate from `node_modules` packages, add a one-time augmentation file in your app so Unistyles' `StyleSheet.create((theme) => ...)` knows the theme shape:
50
-
51
- ```ts
52
- // unistyles.d.ts (anywhere TypeScript picks it up, e.g. project root)
53
- import type { AppBreakpoints, AppTheme } from "@spelyco/react-native";
54
-
55
- declare module "react-native-unistyles" {
56
- export interface UnistylesThemes {
57
- light: AppTheme;
58
- dark: AppTheme;
59
- }
60
- export interface UnistylesBreakpoints extends AppBreakpoints {}
61
- }
62
- ```
63
-
64
- ### 3. Configure Unistyles at app startup
65
-
66
- Add this **as the very first line** of your entry file (e.g. `app/_layout.tsx` for Expo Router):
52
+ `SpelycoProvider` boots Unistyles, owns the color scheme state (zustand + AsyncStorage persistence), and applies the status/system bars from the theme. Put it at the root — for Expo Router that means `app/_layout.tsx`:
67
53
 
68
54
  ```tsx
69
- import "@spelyco/react-native/configure";
70
-
55
+ // app/_layout.tsx
56
+ import { SpelycoProvider } from "@spelyco/react-native";
71
57
  import { Stack } from "expo-router";
72
58
 
73
59
  export default function RootLayout() {
74
- return <Stack screenOptions={{ headerShown: false }} />;
60
+ return (
61
+ <SpelycoProvider>
62
+ <Stack screenOptions={{ headerShown: false }} />
63
+ </SpelycoProvider>
64
+ );
75
65
  }
76
66
  ```
77
67
 
78
- `@spelyco/react-native/configure` is a side-effect import that runs `StyleSheet.configure` with the bundled themes before any component using `StyleSheet.create` is loaded. It enables `adaptiveThemes` (OS color scheme drives the active theme).
79
-
80
- For full control (custom themes, pinned initial theme, etc.) skip the side-effect import and call `configureUnistyles` yourself **before** importing any component that uses styles:
68
+ Pass a partial `theme` to override anything in `DEFAULT_THEME`, and `defaultColorScheme` to pin the first-launch preference (defaults to `"auto"`).
81
69
 
82
70
  ```tsx
83
- import { configureUnistyles } from "@spelyco/react-native";
84
-
85
- configureUnistyles({ adaptiveThemes: false, initialTheme: "dark" });
71
+ <SpelycoProvider
72
+ theme={{ primaryColor: "brand", defaultRadius: "lg" }}
73
+ defaultColorScheme="dark"
74
+ >
75
+ <Stack />
76
+ </SpelycoProvider>
86
77
  ```
87
78
 
88
- ### 4. New Architecture
79
+ ### 3. New Architecture
89
80
 
90
81
  Unistyles 3 requires React Native's New Architecture. Make sure your `app.json` (Expo) has:
91
82
 
@@ -97,17 +88,54 @@ Unistyles 3 requires React Native's New Architecture. Make sure your `app.json`
97
88
 
98
89
  ## Components
99
90
 
91
+ ### `Box`
92
+
93
+ A `View` primitive with shorthand spacing props.
94
+
95
+ ```tsx
96
+ import { Box } from "@spelyco/react-native";
97
+
98
+ <Box p="md" gap="sm" bg="#f4f4f5">
99
+ {/* children */}
100
+ </Box>
101
+ ```
102
+
103
+ | Prop | Type | Description |
104
+ | --- | --- | --- |
105
+ | `p` / `px` / `py` | `"xs" \| "sm" \| "md" \| "lg" \| "xl" \| number` | Padding |
106
+ | `m` / `mx` / `my` | `"xs" \| "sm" \| "md" \| "lg" \| "xl" \| number` | Margin |
107
+ | `gap` | same as above | Flex gap |
108
+ | `bg` | `string` | Background color (hex) |
109
+ | `...rest` | `ViewProps` | Any RN `View` prop |
110
+
111
+ ### `Text`
112
+
113
+ A `Text` primitive with size/weight tokens. Color auto-resolves from the active color scheme unless you provide one.
114
+
115
+ ```tsx
116
+ import { Text } from "@spelyco/react-native";
117
+
118
+ <Text size="xl" weight="bold">Heading</Text>
119
+ <Text size="sm">Body copy</Text>
120
+ <Text color="#ef4444">Inline override</Text>
121
+ ```
122
+
123
+ | Prop | Type | Default | Description |
124
+ | --- | --- | --- | --- |
125
+ | `size` | `"xs" \| "sm" \| "md" \| "lg" \| "xl"` | `"md"` | Maps to `theme.fontSizes` |
126
+ | `weight` | `"normal" \| "medium" \| "bold"` | `"normal"` | |
127
+ | `color` | `string` | scheme-aware default | Hex color |
128
+ | `...rest` | `TextProps` | — | Any RN `Text` prop |
129
+
100
130
  ### `Button`
101
131
 
102
132
  ```tsx
103
133
  import { Button } from "@spelyco/react-native";
104
134
 
105
- <Button label="Tap me" />
106
135
  <Button label="Primary" variant="primary" />
107
136
  <Button label="Secondary" variant="secondary" />
108
137
  <Button label="Ghost" variant="ghost" />
109
138
  <Button label="Small" size="sm" />
110
- <Button label="Large" size="lg" />
111
139
  <Button label="Disabled" disabled />
112
140
  <Button label="Save" onPress={() => console.log("saved")} />
113
141
  ```
@@ -122,15 +150,50 @@ import { Button } from "@spelyco/react-native";
122
150
 
123
151
  ---
124
152
 
125
- ## Theme
153
+ ## Color scheme
126
154
 
127
- Re-exports for the default themes:
155
+ `SpelycoProvider` tracks the user preference (`light`/`dark`/`auto`) in a zustand store, persists it via AsyncStorage, and listens to OS appearance changes.
128
156
 
129
- ```ts
130
- import { lightTheme, darkTheme, breakpoints, type AppTheme } from "@spelyco/react-native";
157
+ ```tsx
158
+ import { useSpelycoColorScheme } from "@spelyco/react-native";
159
+
160
+ function ThemeToggle() {
161
+ const {
162
+ colorScheme, // user preference: 'light' | 'dark' | 'auto'
163
+ computedColorScheme, // resolved scheme actually applied: 'light' | 'dark'
164
+ setColorScheme,
165
+ toggleColorScheme,
166
+ clearColorScheme, // reset to 'auto'
167
+ } = useSpelycoColorScheme();
168
+
169
+ return (
170
+ <Button
171
+ label={`Switch to ${computedColorScheme === "dark" ? "light" : "dark"}`}
172
+ onPress={toggleColorScheme}
173
+ />
174
+ );
175
+ }
176
+ ```
177
+
178
+ ---
179
+
180
+ ## Theming
181
+
182
+ Customize defaults via `theme.components[ComponentName].defaultProps`:
183
+
184
+ ```tsx
185
+ <SpelycoProvider
186
+ theme={{
187
+ components: {
188
+ Button: Button.extend({ defaultProps: { variant: "ghost" } }),
189
+ },
190
+ }}
191
+ >
192
+ {/* every <Button> now defaults to variant="ghost" */}
193
+ </SpelycoProvider>
131
194
  ```
132
195
 
133
- For now these are minimal placeholders (colors, spacing, radii). A proper design-system release will follow in a subsequent version.
196
+ Theme tokens (`colors`, `spacing`, `radius`, `fontSizes`, `lineHeights`, `shadows`, `breakpoints`, `systemBars`, `other`) all flow through the same `theme` prop. See `@spelyco/react-lib` for the full `SpelycoTheme` contract.
134
197
 
135
198
  ---
136
199
 
@@ -144,6 +207,9 @@ For now these are minimal placeholders (colors, spacing, radii). A proper design
144
207
  | `react-native-edge-to-edge` | `*` |
145
208
  | `react-native-nitro-modules` | `*` |
146
209
  | `react-native-reanimated` | `*` |
210
+ | `@react-native-async-storage/async-storage` | `*` |
211
+ | `expo-status-bar` | `*` |
212
+ | `expo-system-ui` | `*` |
147
213
 
148
214
  ---
149
215
 
@@ -0,0 +1,2 @@
1
+ import "./types";
2
+ //# sourceMappingURL=bootUnistyles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootUnistyles.d.ts","sourceRoot":"","sources":["../src/bootUnistyles.ts"],"names":[],"mappings":"AAGA,OAAO,SAAS,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { type PressableProps } from "react-native";
2
+ import { type UnistylesVariants } from "react-native-unistyles";
3
+ type ActionIconVariants = UnistylesVariants<typeof styles>;
4
+ export type ActionIconProps = PressableProps & ActionIconVariants;
5
+ export declare const ActionIcon: import("@spelyco/react-lib").SpelycoComponent<ActionIconProps>;
6
+ declare const styles: {
7
+ root: {
8
+ opacity: number;
9
+ } & {
10
+ backgroundColor: string;
11
+ } & {
12
+ backgroundColor: string;
13
+ } & {
14
+ backgroundColor: string;
15
+ } & {
16
+ width: number;
17
+ height: number;
18
+ } & {
19
+ width: number;
20
+ height: number;
21
+ } & {
22
+ width: number;
23
+ height: number;
24
+ } & {
25
+ borderRadius: number;
26
+ alignItems: "center";
27
+ justifyContent: "center";
28
+ };
29
+ } & {
30
+ useVariants: (variants: {
31
+ variant?: "transparent" | "subtle" | "filled" | undefined;
32
+ size?: "sm" | "md" | "lg" | undefined;
33
+ disabled?: boolean | "true" | undefined;
34
+ }) => void;
35
+ };
36
+ export {};
37
+ //# sourceMappingURL=ActionIcon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActionIcon.d.ts","sourceRoot":"","sources":["../../../src/components/ActionIcon/ActionIcon.tsx"],"names":[],"mappings":"AACA,OAAO,EAAa,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EAAc,KAAK,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE5E,KAAK,kBAAkB,GAAG,iBAAiB,CAAC,OAAO,MAAM,CAAC,CAAC;AAE3D,MAAM,MAAM,eAAe,GAAG,cAAc,GAAG,kBAAkB,CAAC;AAElE,eAAO,MAAM,UAAU,gEAgBrB,CAAC;AAEH,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2BT,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { type SpelycoSize } from "@spelyco/react-lib";
2
+ import { type ViewProps } from "react-native";
3
+ type SpacingToken = SpelycoSize | number;
4
+ export interface BoxProps extends ViewProps {
5
+ /** padding shorthand */
6
+ p?: SpacingToken;
7
+ px?: SpacingToken;
8
+ py?: SpacingToken;
9
+ /** margin shorthand */
10
+ m?: SpacingToken;
11
+ mx?: SpacingToken;
12
+ my?: SpacingToken;
13
+ /** Flex gap between children */
14
+ gap?: SpacingToken;
15
+ /** Background color (hex). Theme palette tokens land in a later phase. */
16
+ bg?: string;
17
+ }
18
+ export declare const Box: import("@spelyco/react-lib").SpelycoComponent<BoxProps>;
19
+ export {};
20
+ //# sourceMappingURL=Box.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Box.d.ts","sourceRoot":"","sources":["../../../src/components/Box/Box.tsx"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,WAAW,EAGjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAQ,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAEpD,KAAK,YAAY,GAAG,WAAW,GAAG,MAAM,CAAC;AAEzC,MAAM,WAAW,QAAS,SAAQ,SAAS;IACzC,wBAAwB;IACxB,CAAC,CAAC,EAAE,YAAY,CAAC;IACjB,EAAE,CAAC,EAAE,YAAY,CAAC;IAClB,EAAE,CAAC,EAAE,YAAY,CAAC;IAClB,uBAAuB;IACvB,CAAC,CAAC,EAAE,YAAY,CAAC;IACjB,EAAE,CAAC,EAAE,YAAY,CAAC;IAClB,EAAE,CAAC,EAAE,YAAY,CAAC;IAClB,gCAAgC;IAChC,GAAG,CAAC,EAAE,YAAY,CAAC;IACnB,0EAA0E;IAC1E,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAQD,eAAO,MAAM,GAAG,yDAgBd,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { Box, type BoxProps } from "./Box";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Box/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAC"}
@@ -4,7 +4,7 @@ type ButtonVariants = UnistylesVariants<typeof styles>;
4
4
  export type ButtonProps = Omit<PressableProps, "children"> & ButtonVariants & {
5
5
  label: string;
6
6
  };
7
- export declare const Button: ({ label, variant, size, disabled, style, ...rest }: ButtonProps) => import("react/jsx-runtime").JSX.Element;
7
+ export declare const Button: import("@spelyco/react-lib").SpelycoComponent<ButtonProps>;
8
8
  declare const styles: {
9
9
  root: {
10
10
  opacity: number;
@@ -1 +1 @@
1
- {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../src/components/Button/Button.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,EAAc,KAAK,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE5E,KAAK,cAAc,GAAG,iBAAiB,CAAC,OAAO,MAAM,CAAC,CAAC;AAEvD,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,EAAE,UAAU,CAAC,GACxD,cAAc,GAAG;IACf,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEJ,eAAO,MAAM,MAAM,GAAI,oDAOpB,WAAW,4CAab,CAAC;AAEF,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuDT,CAAC"}
1
+ {"version":3,"file":"Button.d.ts","sourceRoot":"","sources":["../../../src/components/Button/Button.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,OAAO,EAAc,KAAK,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAE5E,KAAK,cAAc,GAAG,iBAAiB,CAAC,OAAO,MAAM,CAAC,CAAC;AAEvD,MAAM,MAAM,WAAW,GAAG,IAAI,CAAC,cAAc,EAAE,UAAU,CAAC,GACxD,cAAc,GAAG;IACf,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEJ,eAAO,MAAM,MAAM,4DAwBjB,CAAC;AAEH,QAAA,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuDT,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { type SpelycoSize } from "@spelyco/react-lib";
2
+ import { type TextProps as RNTextProps } from "react-native";
3
+ export type TextWeight = "normal" | "medium" | "bold";
4
+ export interface TextProps extends RNTextProps {
5
+ size?: SpelycoSize;
6
+ weight?: TextWeight;
7
+ /** Direct hex color. When omitted, auto-resolves to the neutral text color
8
+ * for the active color scheme. */
9
+ color?: string;
10
+ }
11
+ export declare const Text: import("@spelyco/react-lib").SpelycoComponent<TextProps>;
12
+ //# sourceMappingURL=Text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Text.d.ts","sourceRoot":"","sources":["../../../src/components/Text/Text.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAmB,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACvE,OAAO,EAAkB,KAAK,SAAS,IAAI,WAAW,EAAE,MAAM,cAAc,CAAC;AAG7E,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEtD,MAAM,WAAW,SAAU,SAAQ,WAAW;IAC5C,IAAI,CAAC,EAAE,WAAW,CAAC;IACnB,MAAM,CAAC,EAAE,UAAU,CAAC;IACpB;uCACmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,eAAO,MAAM,IAAI,0DAWf,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { Text, type TextProps, type TextWeight } from "./Text";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Text/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,QAAQ,CAAC"}
@@ -1,2 +1,4 @@
1
- export { Button } from "./Button";
1
+ export { Box, type BoxProps } from "./Box";
2
+ export { Button, type ButtonProps } from "./Button";
3
+ export { Text, type TextProps, type TextWeight } from "./Text";
2
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,KAAK,QAAQ,EAAE,MAAM,OAAO,CAAC;AAC3C,OAAO,EAAE,MAAM,EAAE,KAAK,WAAW,EAAE,MAAM,UAAU,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,EAAE,MAAM,QAAQ,CAAC"}
@@ -0,0 +1,3 @@
1
+ export type { UseSpelycoColorSchemeReturn } from "./useSpelycoColorScheme";
2
+ export { useSpelycoColorScheme } from "./useSpelycoColorScheme";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;AAC3E,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { SpelycoColorScheme, SpelycoComputedColorScheme } from "@spelyco/react-lib";
2
+ export interface UseSpelycoColorSchemeReturn {
3
+ /** User preference: 'light' | 'dark' | 'auto'. */
4
+ colorScheme: SpelycoColorScheme;
5
+ /** Resolved scheme actually applied: 'light' | 'dark'. */
6
+ computedColorScheme: SpelycoComputedColorScheme;
7
+ setColorScheme: (scheme: SpelycoColorScheme) => void;
8
+ /** Cycles light ↔ dark. If currently 'auto', toggles from the OS value. */
9
+ toggleColorScheme: () => void;
10
+ /** Resets back to 'auto' (follow OS). */
11
+ clearColorScheme: () => void;
12
+ }
13
+ export declare const useSpelycoColorScheme: () => UseSpelycoColorSchemeReturn;
14
+ //# sourceMappingURL=useSpelycoColorScheme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSpelycoColorScheme.d.ts","sourceRoot":"","sources":["../../src/hooks/useSpelycoColorScheme.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAGzF,MAAM,WAAW,2BAA2B;IAC1C,kDAAkD;IAClD,WAAW,EAAE,kBAAkB,CAAC;IAChC,0DAA0D;IAC1D,mBAAmB,EAAE,0BAA0B,CAAC;IAChD,cAAc,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACrD,2EAA2E;IAC3E,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,yCAAyC;IACzC,gBAAgB,EAAE,MAAM,IAAI,CAAC;CAC9B;AAED,eAAO,MAAM,qBAAqB,QAAO,2BAiBxC,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,4 +1,7 @@
1
+ import "./bootUnistyles";
2
+ export * from "@spelyco/react-lib";
1
3
  export * from "./components";
2
- export { type AppBreakpoints, type AppTheme, breakpoints, darkTheme, lightTheme, } from "./themes";
3
- export { type ConfigureUnistylesOptions, configureUnistyles, type UnistylesInitialTheme, } from "./unistyles";
4
+ export * from "./hooks";
5
+ export * from "./provider";
6
+ export * from "./store";
4
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAC;AAC7B,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,WAAW,EACX,SAAS,EACT,UAAU,GACX,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,KAAK,yBAAyB,EAC9B,kBAAkB,EAClB,KAAK,qBAAqB,GAC3B,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,iBAAiB,CAAC;AAKzB,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC"}
@@ -0,0 +1,11 @@
1
+ import { type SpelycoColorScheme, type SpelycoThemeOverride } from "@spelyco/react-lib";
2
+ import { type ReactNode } from "react";
3
+ export interface SpelycoProviderProps {
4
+ /** Partial theme override merged on top of `DEFAULT_THEME`. */
5
+ theme?: SpelycoThemeOverride;
6
+ /** User-facing default if no persisted preference exists. */
7
+ defaultColorScheme?: SpelycoColorScheme;
8
+ children: ReactNode;
9
+ }
10
+ export declare function SpelycoProvider({ theme: themeOverride, defaultColorScheme, children, }: SpelycoProviderProps): import("react/jsx-runtime").JSX.Element;
11
+ //# sourceMappingURL=SpelycoProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SpelycoProvider.d.ts","sourceRoot":"","sources":["../../src/provider/SpelycoProvider.tsx"],"names":[],"mappings":"AACA,OAAO,EAEL,KAAK,kBAAkB,EAEvB,KAAK,oBAAoB,EAC1B,MAAM,oBAAoB,CAAC;AAE5B,OAAO,EAAE,KAAK,SAAS,EAAgC,MAAM,OAAO,CAAC;AAWrE,MAAM,WAAW,oBAAoB;IACnC,+DAA+D;IAC/D,KAAK,CAAC,EAAE,oBAAoB,CAAC;IAC7B,6DAA6D;IAC7D,kBAAkB,CAAC,EAAE,kBAAkB,CAAC;IACxC,QAAQ,EAAE,SAAS,CAAC;CACrB;AAED,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EAAE,aAAa,EACpB,kBAA2B,EAC3B,QAAQ,GACT,EAAE,oBAAoB,2CAsEtB"}
@@ -0,0 +1,4 @@
1
+ export { SpelycoProvider, type SpelycoProviderProps } from "./SpelycoProvider";
2
+ export { toNavigationTheme } from "./toNavigationTheme";
3
+ export { type SpelycoUnistylesTheme, toUnistylesTheme } from "./toUnistylesTheme";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/provider/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,KAAK,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC/E,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,KAAK,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { type Theme } from "@react-navigation/native";
2
+ import type { SpelycoComputedColorScheme, SpelycoTheme } from "@spelyco/react-lib";
3
+ /**
4
+ * Adapts a `SpelycoTheme` into a `@react-navigation/native` `Theme` so the
5
+ * drawer chrome, screen background, headers, dividers and route transitions
6
+ * pick up Spelyco's palette automatically.
7
+ *
8
+ * Colour mapping (10-shade tuples):
9
+ * primary → resolved primary hex (from `theme.primary`)
10
+ * background → neutral[0] / neutral[9]
11
+ * card → neutral[1] / neutral[8] (headers, tab/drawer surface)
12
+ * text → neutral[9] / neutral[0]
13
+ * border → neutral[2] / neutral[7]
14
+ * notification→ red[6] / red[4] (badge/alert colour)
15
+ *
16
+ * Fonts pass through React Navigation's defaults — Phase 1 will wire them to
17
+ * `theme.fontFamily`/`fontFamilyMono` once a typography contract lands.
18
+ */
19
+ export declare function toNavigationTheme(theme: SpelycoTheme, scheme: SpelycoComputedColorScheme): Theme;
20
+ //# sourceMappingURL=toNavigationTheme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toNavigationTheme.d.ts","sourceRoot":"","sources":["../../src/provider/toNavigationTheme.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,KAAK,EAAE,MAAM,0BAA0B,CAAC;AACpE,OAAO,KAAK,EAAE,0BAA0B,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEnF;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,EAAE,MAAM,EAAE,0BAA0B,GAAG,KAAK,CAqBhG"}
@@ -0,0 +1,24 @@
1
+ import type { SpelycoColors, SpelycoComputedColorScheme, SpelycoFontSizes, SpelycoLineHeights, SpelycoRadius, SpelycoShadows, SpelycoSpacing, SpelycoTheme } from "@spelyco/react-lib";
2
+ /**
3
+ * The shape consumed by Unistyles' `StyleSheet.configure({ themes })`. Each
4
+ * scheme gets its own copy with `colorScheme` and a precomputed `primary`
5
+ * color so component styles can do `theme.primary` without recomputing shades.
6
+ */
7
+ export interface SpelycoUnistylesTheme {
8
+ colorScheme: SpelycoComputedColorScheme;
9
+ colors: SpelycoColors;
10
+ spacing: SpelycoSpacing;
11
+ radius: SpelycoRadius;
12
+ fontSizes: SpelycoFontSizes;
13
+ lineHeights: SpelycoLineHeights;
14
+ shadows: SpelycoShadows;
15
+ primaryColor: string;
16
+ /** Shade index resolved for this color scheme. */
17
+ primaryShade: number;
18
+ /** `colors[primaryColor][primaryShade]` — the actual hex used by components. */
19
+ primary: string;
20
+ fontFamily: string;
21
+ fontFamilyMono: string;
22
+ }
23
+ export declare function toUnistylesTheme(theme: SpelycoTheme, scheme: SpelycoComputedColorScheme): SpelycoUnistylesTheme;
24
+ //# sourceMappingURL=toUnistylesTheme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toUnistylesTheme.d.ts","sourceRoot":"","sources":["../../src/provider/toUnistylesTheme.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,0BAA0B,EAC1B,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,cAAc,EACd,cAAc,EACd,YAAY,EACb,MAAM,oBAAoB,CAAC;AAE5B;;;;GAIG;AACH,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,0BAA0B,CAAC;IACxC,MAAM,EAAE,aAAa,CAAC;IACtB,OAAO,EAAE,cAAc,CAAC;IACxB,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,gBAAgB,CAAC;IAC5B,WAAW,EAAE,kBAAkB,CAAC;IAChC,OAAO,EAAE,cAAc,CAAC;IACxB,YAAY,EAAE,MAAM,CAAC;IACrB,kDAAkD;IAClD,YAAY,EAAE,MAAM,CAAC;IACrB,gFAAgF;IAChF,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,YAAY,EACnB,MAAM,EAAE,0BAA0B,GACjC,qBAAqB,CAqBvB"}
@@ -0,0 +1,31 @@
1
+ import type { SpelycoColorScheme, SpelycoComputedColorScheme } from "@spelyco/react-lib";
2
+ interface ColorSchemeState {
3
+ /** User preference: 'light' | 'dark' | 'auto'. Persisted. */
4
+ colorScheme: SpelycoColorScheme;
5
+ /** Current OS color scheme. Tracked via Appearance, not persisted. */
6
+ systemColorScheme: SpelycoComputedColorScheme;
7
+ setColorScheme: (scheme: SpelycoColorScheme) => void;
8
+ toggleColorScheme: () => void;
9
+ clearColorScheme: () => void;
10
+ }
11
+ export declare const useColorSchemeStore: import("zustand").UseBoundStore<Omit<import("zustand").StoreApi<ColorSchemeState>, "setState" | "persist"> & {
12
+ setState(partial: ColorSchemeState | Partial<ColorSchemeState> | ((state: ColorSchemeState) => ColorSchemeState | Partial<ColorSchemeState>), replace?: false | undefined): unknown;
13
+ setState(state: ColorSchemeState | ((state: ColorSchemeState) => ColorSchemeState), replace: true): unknown;
14
+ persist: {
15
+ setOptions: (options: Partial<import("zustand/middleware").PersistOptions<ColorSchemeState, unknown, unknown>>) => void;
16
+ clearStorage: () => void;
17
+ rehydrate: () => Promise<void> | void;
18
+ hasHydrated: () => boolean;
19
+ onHydrate: (fn: (state: ColorSchemeState) => void) => () => void;
20
+ onFinishHydration: (fn: (state: ColorSchemeState) => void) => () => void;
21
+ getOptions: () => Partial<import("zustand/middleware").PersistOptions<ColorSchemeState, unknown, unknown>>;
22
+ };
23
+ }>;
24
+ /**
25
+ * Subscribes the store to OS color scheme changes. Idempotent — calling more
26
+ * than once is a no-op. Should be invoked once from `SpelycoProvider`.
27
+ */
28
+ export declare const setupColorSchemeListener: () => void;
29
+ export declare const teardownColorSchemeListener: () => void;
30
+ export {};
31
+ //# sourceMappingURL=colorScheme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"colorScheme.d.ts","sourceRoot":"","sources":["../../src/store/colorScheme.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,0BAA0B,EAAE,MAAM,oBAAoB,CAAC;AAKzF,UAAU,gBAAgB;IACxB,6DAA6D;IAC7D,WAAW,EAAE,kBAAkB,CAAC;IAChC,sEAAsE;IACtE,iBAAiB,EAAE,0BAA0B,CAAC;IAC9C,cAAc,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;IACrD,iBAAiB,EAAE,MAAM,IAAI,CAAC;IAC9B,gBAAgB,EAAE,MAAM,IAAI,CAAC;CAC9B;AASD,eAAO,MAAM,mBAAmB;;;;;;;;;;;;EAmB/B,CAAC;AAIF;;;GAGG;AACH,eAAO,MAAM,wBAAwB,YAOpC,CAAC;AAEF,eAAO,MAAM,2BAA2B,YAGvC,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { setupColorSchemeListener, teardownColorSchemeListener, useColorSchemeStore, } from "./colorScheme";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/store/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,wBAAwB,EACxB,2BAA2B,EAC3B,mBAAmB,GACpB,MAAM,eAAe,CAAC"}
package/dist/types.d.ts CHANGED
@@ -1,10 +1,11 @@
1
- import type { AppBreakpoints, AppTheme } from "./themes";
1
+ import type { SpelycoBreakpoints } from "@spelyco/react-lib";
2
+ import type { SpelycoUnistylesTheme } from "./provider/toUnistylesTheme";
2
3
  declare module "react-native-unistyles" {
3
4
  interface UnistylesThemes {
4
- light: AppTheme;
5
- dark: AppTheme;
5
+ light: SpelycoUnistylesTheme;
6
+ dark: SpelycoUnistylesTheme;
6
7
  }
7
- interface UnistylesBreakpoints extends AppBreakpoints {
8
+ interface UnistylesBreakpoints extends SpelycoBreakpoints {
8
9
  }
9
10
  }
10
11
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAEzD,OAAO,QAAQ,wBAAwB,CAAC;IACtC,UAAiB,eAAe;QAC9B,KAAK,EAAE,QAAQ,CAAC;QAChB,IAAI,EAAE,QAAQ,CAAC;KAChB;IACD,UAAiB,oBAAqB,SAAQ,cAAc;KAAG;CAChE"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,6BAA6B,CAAC;AAEzE,OAAO,QAAQ,wBAAwB,CAAC;IACtC,UAAiB,eAAe;QAC9B,KAAK,EAAE,qBAAqB,CAAC;QAC7B,IAAI,EAAE,qBAAqB,CAAC;KAC7B;IACD,UAAiB,oBAAqB,SAAQ,kBAAkB;KAAG;CACpE"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@spelyco/react-native",
3
- "version": "1.0.0-alpha.1",
3
+ "version": "1.0.0",
4
4
  "description": "React Native UI components for Spelyco, powered by Unistyles 3",
5
5
  "keywords": [
6
6
  "react-native",
@@ -20,12 +20,6 @@
20
20
  "react-native": "./src/index.ts",
21
21
  "import": "./src/index.ts",
22
22
  "require": "./src/index.ts"
23
- },
24
- "./configure": {
25
- "types": "./dist/configure.d.ts",
26
- "react-native": "./src/configure.ts",
27
- "import": "./src/configure.ts",
28
- "require": "./src/configure.ts"
29
23
  }
30
24
  },
31
25
  "files": [
@@ -42,6 +36,10 @@
42
36
  "clean": "rm -rf dist"
43
37
  },
44
38
  "peerDependencies": {
39
+ "@react-native-async-storage/async-storage": "*",
40
+ "@react-navigation/native": "^7",
41
+ "expo-status-bar": "*",
42
+ "expo-system-ui": "*",
45
43
  "react": ">=18",
46
44
  "react-native": ">=0.76",
47
45
  "react-native-edge-to-edge": "*",
@@ -50,11 +48,16 @@
50
48
  "react-native-unistyles": "^3.2.4"
51
49
  },
52
50
  "dependencies": {
53
- "@spelyco/react-lib": "1.2.0"
51
+ "@spelyco/react-lib": "1.3.0",
52
+ "zustand": "^5.0.2"
54
53
  },
55
54
  "devDependencies": {
55
+ "@react-native-async-storage/async-storage": "^2.2.0",
56
+ "@react-navigation/native": "^7.2.2",
56
57
  "@spelyco/tsconfig": "*",
57
58
  "@types/react": "^19.2.14",
59
+ "expo-status-bar": "~55.0.6",
60
+ "expo-system-ui": "~55.0.18",
58
61
  "react": "^19.2.4",
59
62
  "react-native": "^0.83.6",
60
63
  "react-native-edge-to-edge": "^1.8.1",
@@ -0,0 +1,27 @@
1
+ import { DEFAULT_THEME } from "@spelyco/react-lib";
2
+ import { StyleSheet } from "react-native-unistyles";
3
+ import { toUnistylesTheme } from "./provider/toUnistylesTheme";
4
+ import "./types";
5
+
6
+ /**
7
+ * Boots Unistyles with the default theme at module-load time.
8
+ *
9
+ * `StyleSheet.configure` must run before any `StyleSheet.create` call,
10
+ * otherwise Unistyles emits "StyleSheet.configure was not called" warnings.
11
+ * Component files (e.g. `Button.tsx`) invoke `StyleSheet.create` at module
12
+ * evaluation, so configuration cannot wait for `SpelycoProvider` to mount.
13
+ *
14
+ * The side-effect here is loaded by `src/index.ts` ahead of any component
15
+ * re-exports, guaranteeing the correct boot order.
16
+ *
17
+ * Theme overrides passed to `<SpelycoProvider theme={...}>` are applied later
18
+ * via `UnistylesRuntime.updateTheme()` once the provider mounts.
19
+ */
20
+ StyleSheet.configure({
21
+ themes: {
22
+ light: toUnistylesTheme(DEFAULT_THEME, "light"),
23
+ dark: toUnistylesTheme(DEFAULT_THEME, "dark"),
24
+ },
25
+ breakpoints: DEFAULT_THEME.breakpoints,
26
+ settings: { initialTheme: "light" },
27
+ });