@spelyco/react-native 0.0.1-e4f7457e-alpha → 1.0.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,13 +1,96 @@
1
1
  # @spelyco/react-native
2
2
 
3
- React Native UI components for Spelyco mobile projects.
3
+ React Native UI components for Spelyco, powered by [Unistyles 3](https://www.unistyl.es).
4
4
 
5
5
  ---
6
6
 
7
7
  ## Install
8
8
 
9
9
  ```bash
10
- bun add @spelyco/react-native @spelyco/react-lib react react-native
10
+ bun add @spelyco/react-native \
11
+ react-native-unistyles \
12
+ react-native-edge-to-edge \
13
+ react-native-nitro-modules \
14
+ react-native-reanimated
15
+ ```
16
+
17
+ This package is published as TypeScript source. Your bundler (Metro for React Native / Expo) transpiles it directly. Make sure your Babel config processes it (see [Setup](#setup) below).
18
+
19
+ ---
20
+
21
+ ## Setup
22
+
23
+ ### 1. Babel plugin (required)
24
+
25
+ Unistyles 3 ships a Babel plugin that wires up the C++ shadow tree bindings. Because this package is shipped as source, you must include it in `autoProcessPaths` so the plugin processes our files inside `node_modules`.
26
+
27
+ `babel.config.js`:
28
+
29
+ ```js
30
+ module.exports = function (api) {
31
+ api.cache(true);
32
+ return {
33
+ presets: ["babel-preset-expo"],
34
+ plugins: [
35
+ [
36
+ "react-native-unistyles/plugin",
37
+ {
38
+ root: "src",
39
+ autoProcessPaths: ["@spelyco/react-native"],
40
+ },
41
+ ],
42
+ ],
43
+ };
44
+ };
45
+ ```
46
+
47
+ ### 2. TypeScript theme augmentation (recommended)
48
+
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):
67
+
68
+ ```tsx
69
+ import "@spelyco/react-native/configure";
70
+
71
+ import { Stack } from "expo-router";
72
+
73
+ export default function RootLayout() {
74
+ return <Stack screenOptions={{ headerShown: false }} />;
75
+ }
76
+ ```
77
+
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:
81
+
82
+ ```tsx
83
+ import { configureUnistyles } from "@spelyco/react-native";
84
+
85
+ configureUnistyles({ adaptiveThemes: false, initialTheme: "dark" });
86
+ ```
87
+
88
+ ### 4. New Architecture
89
+
90
+ Unistyles 3 requires React Native's New Architecture. Make sure your `app.json` (Expo) has:
91
+
92
+ ```json
93
+ { "expo": { "newArchEnabled": true } }
11
94
  ```
12
95
 
13
96
  ---
@@ -16,47 +99,38 @@ bun add @spelyco/react-native @spelyco/react-lib react react-native
16
99
 
17
100
  ### `Button`
18
101
 
19
- A basic button built on React Native's `Pressable`. Supports variants and sizes.
20
-
21
102
  ```tsx
22
103
  import { Button } from "@spelyco/react-native";
23
104
 
24
- // Default
25
105
  <Button label="Tap me" />
26
-
27
- // Variants
28
106
  <Button label="Primary" variant="primary" />
29
107
  <Button label="Secondary" variant="secondary" />
30
108
  <Button label="Ghost" variant="ghost" />
31
-
32
- // Sizes
33
109
  <Button label="Small" size="sm" />
34
110
  <Button label="Large" size="lg" />
35
-
36
- // Disabled
37
111
  <Button label="Disabled" disabled />
38
-
39
- // With onPress
40
112
  <Button label="Save" onPress={() => console.log("saved")} />
41
113
  ```
42
114
 
43
- **Props:**
44
-
45
115
  | Prop | Type | Default | Description |
46
116
  | --- | --- | --- | --- |
47
- | `label` | `string` | required | The button text |
117
+ | `label` | `string` | required | Button text |
48
118
  | `variant` | `"primary" \| "secondary" \| "ghost"` | `"primary"` | Visual style |
49
- | `size` | `"sm" \| "md" \| "lg"` | `"md"` | Padding size |
119
+ | `size` | `"sm" \| "md" \| "lg"` | `"md"` | Padding/font size |
50
120
  | `disabled` | `boolean` | `false` | Disable the button |
51
- | `...rest` | `PressableProps` | — | Any React Native Pressable prop |
121
+ | `...rest` | `PressableProps` | — | Any RN `Pressable` prop |
52
122
 
53
- **Variants:**
123
+ ---
54
124
 
55
- | Variant | Background |
56
- | --- | --- |
57
- | `primary` | Indigo (`#6366f1`) |
58
- | `secondary` | Light gray (`#e5e7eb`) |
59
- | `ghost` | Transparent |
125
+ ## Theme
126
+
127
+ Re-exports for the default themes:
128
+
129
+ ```ts
130
+ import { lightTheme, darkTheme, breakpoints, type AppTheme } from "@spelyco/react-native";
131
+ ```
132
+
133
+ For now these are minimal placeholders (colors, spacing, radii). A proper design-system release will follow in a subsequent version.
60
134
 
61
135
  ---
62
136
 
@@ -65,7 +139,11 @@ import { Button } from "@spelyco/react-native";
65
139
  | Package | Version |
66
140
  | --- | --- |
67
141
  | `react` | `>=18` |
68
- | `react-native` | `>=0.73` |
142
+ | `react-native` | `>=0.76` |
143
+ | `react-native-unistyles` | `^3.2.4` |
144
+ | `react-native-edge-to-edge` | `*` |
145
+ | `react-native-nitro-modules` | `*` |
146
+ | `react-native-reanimated` | `*` |
69
147
 
70
148
  ---
71
149
 
@@ -0,0 +1,59 @@
1
+ import type { PressableProps } from "react-native";
2
+ import { type UnistylesVariants } from "react-native-unistyles";
3
+ type ButtonVariants = UnistylesVariants<typeof styles>;
4
+ export type ButtonProps = Omit<PressableProps, "children"> & ButtonVariants & {
5
+ label: string;
6
+ };
7
+ export declare const Button: ({ label, variant, size, disabled, style, ...rest }: ButtonProps) => import("react/jsx-runtime").JSX.Element;
8
+ declare const styles: {
9
+ root: {
10
+ opacity: number;
11
+ } & {
12
+ backgroundColor: string;
13
+ } & {
14
+ backgroundColor: string;
15
+ } & {
16
+ backgroundColor: string;
17
+ borderWidth: number;
18
+ borderColor: string;
19
+ } & {
20
+ paddingHorizontal: number;
21
+ paddingVertical: number;
22
+ } & {
23
+ paddingHorizontal: number;
24
+ paddingVertical: number;
25
+ } & {
26
+ paddingHorizontal: number;
27
+ paddingVertical: number;
28
+ } & {
29
+ borderRadius: number;
30
+ alignItems: "center";
31
+ justifyContent: "center";
32
+ };
33
+ label: {
34
+ color: string;
35
+ } & {
36
+ color: string;
37
+ } & {
38
+ color: string;
39
+ } & {
40
+ fontSize: number;
41
+ } & {
42
+ fontSize: number;
43
+ } & {
44
+ fontSize: number;
45
+ } & {
46
+ fontWeight: "600";
47
+ };
48
+ } & {
49
+ useVariants: (variants: {
50
+ variant?: "primary" | "secondary" | "ghost" | undefined;
51
+ size?: "sm" | "md" | "lg" | undefined;
52
+ disabled?: boolean | "true" | undefined;
53
+ } | {
54
+ variant?: "primary" | "secondary" | "ghost" | undefined;
55
+ size?: "sm" | "md" | "lg" | undefined;
56
+ }) => void;
57
+ };
58
+ export {};
59
+ //# sourceMappingURL=Button.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,3 @@
1
+ export type { ButtonProps } from "./Button";
2
+ export { Button } from "./Button";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/Button/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,WAAW,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { Button } from "./Button";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=configure.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"configure.d.ts","sourceRoot":"","sources":["../src/configure.ts"],"names":[],"mappings":""}
package/dist/index.d.ts CHANGED
@@ -1,11 +1,4 @@
1
- import * as react from 'react';
2
- import { PressableProps } from 'react-native';
3
-
4
- interface ButtonProps extends PressableProps {
5
- variant?: "primary" | "secondary" | "ghost";
6
- size?: "sm" | "md" | "lg";
7
- label: string;
8
- }
9
- declare function Button({ variant, size, label, style, ...props }: ButtonProps): react.JSX.Element;
10
-
11
- export { Button };
1
+ export * from "./components";
2
+ export { type AppBreakpoints, type AppTheme, breakpoints, darkTheme, lightTheme, } from "./themes";
3
+ export { type ConfigureUnistylesOptions, configureUnistyles, type UnistylesInitialTheme, } from "./unistyles";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,3 @@
1
+ import type { AppTheme } from "./light";
2
+ export declare const darkTheme: AppTheme;
3
+ //# sourceMappingURL=dark.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dark.d.ts","sourceRoot":"","sources":["../../src/themes/dark.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAExC,eAAO,MAAM,SAAS,EAAE,QA0BvB,CAAC"}
@@ -0,0 +1,12 @@
1
+ export { darkTheme } from "./dark";
2
+ export type { AppTheme } from "./light";
3
+ export { lightTheme } from "./light";
4
+ export declare const breakpoints: {
5
+ readonly xs: 0;
6
+ readonly sm: 360;
7
+ readonly md: 768;
8
+ readonly lg: 1024;
9
+ readonly xl: 1280;
10
+ };
11
+ export type AppBreakpoints = typeof breakpoints;
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/themes/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACnC,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAErC,eAAO,MAAM,WAAW;;;;;;CAMd,CAAC;AAEX,MAAM,MAAM,cAAc,GAAG,OAAO,WAAW,CAAC"}
@@ -0,0 +1,29 @@
1
+ export interface AppTheme {
2
+ colors: {
3
+ primary: string;
4
+ onPrimary: string;
5
+ secondary: string;
6
+ onSecondary: string;
7
+ ghost: string;
8
+ onGhost: string;
9
+ background: string;
10
+ text: string;
11
+ border: string;
12
+ disabled: string;
13
+ };
14
+ spacing: {
15
+ xs: number;
16
+ sm: number;
17
+ md: number;
18
+ lg: number;
19
+ xl: number;
20
+ };
21
+ radii: {
22
+ sm: number;
23
+ md: number;
24
+ lg: number;
25
+ pill: number;
26
+ };
27
+ }
28
+ export declare const lightTheme: AppTheme;
29
+ //# sourceMappingURL=light.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"light.d.ts","sourceRoot":"","sources":["../../src/themes/light.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE;QACN,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;QAClB,SAAS,EAAE,MAAM,CAAC;QAClB,WAAW,EAAE,MAAM,CAAC;QACpB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,MAAM,EAAE,MAAM,CAAC;QACf,QAAQ,EAAE,MAAM,CAAC;KAClB,CAAC;IACF,OAAO,EAAE;QACP,EAAE,EAAE,MAAM,CAAC;QACX,EAAE,EAAE,MAAM,CAAC;QACX,EAAE,EAAE,MAAM,CAAC;QACX,EAAE,EAAE,MAAM,CAAC;QACX,EAAE,EAAE,MAAM,CAAC;KACZ,CAAC;IACF,KAAK,EAAE;QACL,EAAE,EAAE,MAAM,CAAC;QACX,EAAE,EAAE,MAAM,CAAC;QACX,EAAE,EAAE,MAAM,CAAC;QACX,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,eAAO,MAAM,UAAU,EAAE,QA0BxB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { AppBreakpoints, AppTheme } from "./themes";
2
+ declare module "react-native-unistyles" {
3
+ interface UnistylesThemes {
4
+ light: AppTheme;
5
+ dark: AppTheme;
6
+ }
7
+ interface UnistylesBreakpoints extends AppBreakpoints {
8
+ }
9
+ }
10
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,8 @@
1
+ import "./types";
2
+ export type UnistylesInitialTheme = "light" | "dark";
3
+ export interface ConfigureUnistylesOptions {
4
+ initialTheme?: UnistylesInitialTheme;
5
+ adaptiveThemes?: boolean;
6
+ }
7
+ export declare const configureUnistyles: ({ initialTheme, adaptiveThemes, }?: ConfigureUnistylesOptions) => void;
8
+ //# sourceMappingURL=unistyles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"unistyles.d.ts","sourceRoot":"","sources":["../src/unistyles.ts"],"names":[],"mappings":"AAGA,OAAO,SAAS,CAAC;AAEjB,MAAM,MAAM,qBAAqB,GAAG,OAAO,GAAG,MAAM,CAAC;AAErD,MAAM,WAAW,yBAAyB;IACxC,YAAY,CAAC,EAAE,qBAAqB,CAAC;IACrC,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAOD,eAAO,MAAM,kBAAkB,GAAI,oCAGhC,yBAA8B,SAMhC,CAAC"}
package/package.json CHANGED
@@ -1,30 +1,40 @@
1
1
  {
2
2
  "name": "@spelyco/react-native",
3
- "version": "0.0.1-e4f7457e-alpha",
4
- "description": "React Native UI components for Spelyco",
3
+ "version": "1.0.0-alpha.1",
4
+ "description": "React Native UI components for Spelyco, powered by Unistyles 3",
5
5
  "keywords": [
6
6
  "react-native",
7
7
  "ui",
8
8
  "components",
9
- "spelyco"
9
+ "spelyco",
10
+ "unistyles"
10
11
  ],
11
12
  "license": "MIT",
12
- "main": "./dist/index.js",
13
- "module": "./dist/index.mjs",
13
+ "main": "./src/index.ts",
14
+ "module": "./src/index.ts",
15
+ "react-native": "./src/index.ts",
14
16
  "types": "./dist/index.d.ts",
15
17
  "exports": {
16
18
  ".": {
17
19
  "types": "./dist/index.d.ts",
18
- "import": "./dist/index.mjs",
19
- "require": "./dist/index.js"
20
+ "react-native": "./src/index.ts",
21
+ "import": "./src/index.ts",
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"
20
29
  }
21
30
  },
22
31
  "files": [
32
+ "src",
23
33
  "dist"
24
34
  ],
25
35
  "scripts": {
26
- "build": "tsup",
27
- "dev": "tsup --watch",
36
+ "build": "tsc -p tsconfig.build.json",
37
+ "dev": "tsc -p tsconfig.build.json --watch",
28
38
  "lint": "biome check src/",
29
39
  "lint:fix": "biome check --write src/",
30
40
  "test": "vitest run --passWithNoTests",
@@ -33,7 +43,11 @@
33
43
  },
34
44
  "peerDependencies": {
35
45
  "react": ">=18",
36
- "react-native": ">=0.73"
46
+ "react-native": ">=0.76",
47
+ "react-native-edge-to-edge": "*",
48
+ "react-native-nitro-modules": "*",
49
+ "react-native-reanimated": "*",
50
+ "react-native-unistyles": "^3.2.4"
37
51
  },
38
52
  "dependencies": {
39
53
  "@spelyco/react-lib": "1.2.0"
@@ -42,8 +56,11 @@
42
56
  "@spelyco/tsconfig": "*",
43
57
  "@types/react": "^19.2.14",
44
58
  "react": "^19.2.4",
45
- "react-native": "^0.84.1",
46
- "tsup": "^8.3.5",
59
+ "react-native": "^0.83.6",
60
+ "react-native-edge-to-edge": "^1.8.1",
61
+ "react-native-nitro-modules": "^0.35.6",
62
+ "react-native-reanimated": "^4.2.1",
63
+ "react-native-unistyles": "^3.2.4",
47
64
  "vitest": "^4.1.1"
48
65
  }
49
66
  }
@@ -0,0 +1,45 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+
3
+ vi.mock("react-native", () => ({
4
+ Pressable: "Pressable",
5
+ Text: "Text",
6
+ }));
7
+
8
+ vi.mock("react-native-unistyles", () => {
9
+ type StylesObject = Record<string, unknown>;
10
+ return {
11
+ StyleSheet: {
12
+ create: (stylesFn: ((theme: unknown) => StylesObject) | StylesObject) => {
13
+ const styles =
14
+ typeof stylesFn === "function"
15
+ ? stylesFn({
16
+ colors: {
17
+ primary: "#000",
18
+ onPrimary: "#fff",
19
+ secondary: "#000",
20
+ onSecondary: "#fff",
21
+ ghost: "transparent",
22
+ onGhost: "#000",
23
+ border: "#000",
24
+ },
25
+ spacing: { xs: 4, sm: 8, md: 12, lg: 16, xl: 24 },
26
+ radii: { sm: 4, md: 8, lg: 12, pill: 999 },
27
+ })
28
+ : stylesFn;
29
+ return Object.assign({}, styles, { useVariants: () => undefined });
30
+ },
31
+ },
32
+ };
33
+ });
34
+
35
+ const { Button } = await import("./Button");
36
+
37
+ describe("Button", () => {
38
+ it("is exported as a function", () => {
39
+ expect(typeof Button).toBe("function");
40
+ });
41
+
42
+ it("has a name of Button", () => {
43
+ expect(Button.name).toBe("Button");
44
+ });
45
+ });
@@ -0,0 +1,89 @@
1
+ import type { PressableProps } from "react-native";
2
+ import { Pressable, Text } from "react-native";
3
+ import { StyleSheet, type UnistylesVariants } from "react-native-unistyles";
4
+
5
+ type ButtonVariants = UnistylesVariants<typeof styles>;
6
+
7
+ export type ButtonProps = Omit<PressableProps, "children"> &
8
+ ButtonVariants & {
9
+ label: string;
10
+ };
11
+
12
+ export const Button = ({
13
+ label,
14
+ variant = "primary",
15
+ size = "md",
16
+ disabled,
17
+ style,
18
+ ...rest
19
+ }: ButtonProps) => {
20
+ styles.useVariants({ variant, size, disabled: disabled ?? false });
21
+
22
+ return (
23
+ <Pressable
24
+ accessibilityRole="button"
25
+ disabled={disabled}
26
+ style={(state) => [styles.root, typeof style === "function" ? style(state) : style]}
27
+ {...rest}
28
+ >
29
+ <Text style={styles.label}>{label}</Text>
30
+ </Pressable>
31
+ );
32
+ };
33
+
34
+ const styles = StyleSheet.create((theme) => ({
35
+ root: {
36
+ alignItems: "center",
37
+ justifyContent: "center",
38
+ borderRadius: theme.radii.md,
39
+ variants: {
40
+ variant: {
41
+ primary: {
42
+ backgroundColor: theme.colors.primary,
43
+ },
44
+ secondary: {
45
+ backgroundColor: theme.colors.secondary,
46
+ },
47
+ ghost: {
48
+ backgroundColor: theme.colors.ghost,
49
+ borderWidth: 1,
50
+ borderColor: theme.colors.border,
51
+ },
52
+ },
53
+ size: {
54
+ sm: {
55
+ paddingHorizontal: theme.spacing.md,
56
+ paddingVertical: theme.spacing.xs,
57
+ },
58
+ md: {
59
+ paddingHorizontal: theme.spacing.lg,
60
+ paddingVertical: theme.spacing.sm,
61
+ },
62
+ lg: {
63
+ paddingHorizontal: theme.spacing.xl,
64
+ paddingVertical: theme.spacing.md,
65
+ },
66
+ },
67
+ disabled: {
68
+ true: {
69
+ opacity: 0.5,
70
+ },
71
+ },
72
+ },
73
+ },
74
+ label: {
75
+ fontWeight: "600",
76
+ variants: {
77
+ variant: {
78
+ primary: { color: theme.colors.onPrimary },
79
+ secondary: { color: theme.colors.onSecondary },
80
+ ghost: { color: theme.colors.onGhost },
81
+ },
82
+ size: {
83
+ sm: { fontSize: 14 },
84
+ md: { fontSize: 16 },
85
+ lg: { fontSize: 18 },
86
+ },
87
+ },
88
+ },
89
+ }));
@@ -0,0 +1,2 @@
1
+ export type { ButtonProps } from "./Button";
2
+ export { Button } from "./Button";
@@ -0,0 +1 @@
1
+ export { Button } from "./Button";
@@ -0,0 +1,3 @@
1
+ import { configureUnistyles } from "./unistyles";
2
+
3
+ configureUnistyles();
package/src/index.ts ADDED
@@ -0,0 +1,13 @@
1
+ export * from "./components";
2
+ export {
3
+ type AppBreakpoints,
4
+ type AppTheme,
5
+ breakpoints,
6
+ darkTheme,
7
+ lightTheme,
8
+ } from "./themes";
9
+ export {
10
+ type ConfigureUnistylesOptions,
11
+ configureUnistyles,
12
+ type UnistylesInitialTheme,
13
+ } from "./unistyles";
@@ -0,0 +1,29 @@
1
+ import type { AppTheme } from "./light";
2
+
3
+ export const darkTheme: AppTheme = {
4
+ colors: {
5
+ primary: "#818cf8",
6
+ onPrimary: "#0b1020",
7
+ secondary: "#1f2937",
8
+ onSecondary: "#f9fafb",
9
+ ghost: "transparent",
10
+ onGhost: "#f9fafb",
11
+ background: "#0b1020",
12
+ text: "#f9fafb",
13
+ border: "#374151",
14
+ disabled: "#4b5563",
15
+ },
16
+ spacing: {
17
+ xs: 4,
18
+ sm: 8,
19
+ md: 12,
20
+ lg: 16,
21
+ xl: 24,
22
+ },
23
+ radii: {
24
+ sm: 4,
25
+ md: 8,
26
+ lg: 12,
27
+ pill: 999,
28
+ },
29
+ };
@@ -0,0 +1,13 @@
1
+ export { darkTheme } from "./dark";
2
+ export type { AppTheme } from "./light";
3
+ export { lightTheme } from "./light";
4
+
5
+ export const breakpoints = {
6
+ xs: 0,
7
+ sm: 360,
8
+ md: 768,
9
+ lg: 1024,
10
+ xl: 1280,
11
+ } as const;
12
+
13
+ export type AppBreakpoints = typeof breakpoints;
@@ -0,0 +1,55 @@
1
+ export interface AppTheme {
2
+ colors: {
3
+ primary: string;
4
+ onPrimary: string;
5
+ secondary: string;
6
+ onSecondary: string;
7
+ ghost: string;
8
+ onGhost: string;
9
+ background: string;
10
+ text: string;
11
+ border: string;
12
+ disabled: string;
13
+ };
14
+ spacing: {
15
+ xs: number;
16
+ sm: number;
17
+ md: number;
18
+ lg: number;
19
+ xl: number;
20
+ };
21
+ radii: {
22
+ sm: number;
23
+ md: number;
24
+ lg: number;
25
+ pill: number;
26
+ };
27
+ }
28
+
29
+ export const lightTheme: AppTheme = {
30
+ colors: {
31
+ primary: "#6366f1",
32
+ onPrimary: "#ffffff",
33
+ secondary: "#e5e7eb",
34
+ onSecondary: "#111827",
35
+ ghost: "transparent",
36
+ onGhost: "#111827",
37
+ background: "#ffffff",
38
+ text: "#111827",
39
+ border: "#d1d5db",
40
+ disabled: "#9ca3af",
41
+ },
42
+ spacing: {
43
+ xs: 4,
44
+ sm: 8,
45
+ md: 12,
46
+ lg: 16,
47
+ xl: 24,
48
+ },
49
+ radii: {
50
+ sm: 4,
51
+ md: 8,
52
+ lg: 12,
53
+ pill: 999,
54
+ },
55
+ };
package/src/types.ts ADDED
@@ -0,0 +1,9 @@
1
+ import type { AppBreakpoints, AppTheme } from "./themes";
2
+
3
+ declare module "react-native-unistyles" {
4
+ export interface UnistylesThemes {
5
+ light: AppTheme;
6
+ dark: AppTheme;
7
+ }
8
+ export interface UnistylesBreakpoints extends AppBreakpoints {}
9
+ }
@@ -0,0 +1,27 @@
1
+ import { StyleSheet } from "react-native-unistyles";
2
+ import { breakpoints, darkTheme, lightTheme } from "./themes";
3
+
4
+ import "./types";
5
+
6
+ export type UnistylesInitialTheme = "light" | "dark";
7
+
8
+ export interface ConfigureUnistylesOptions {
9
+ initialTheme?: UnistylesInitialTheme;
10
+ adaptiveThemes?: boolean;
11
+ }
12
+
13
+ const themes = {
14
+ light: lightTheme,
15
+ dark: darkTheme,
16
+ };
17
+
18
+ export const configureUnistyles = ({
19
+ initialTheme = "light",
20
+ adaptiveThemes = true,
21
+ }: ConfigureUnistylesOptions = {}) => {
22
+ StyleSheet.configure({
23
+ themes,
24
+ breakpoints,
25
+ settings: adaptiveThemes ? { adaptiveThemes: true } : { initialTheme },
26
+ });
27
+ };
package/dist/index.d.mts DELETED
@@ -1,11 +0,0 @@
1
- import * as react from 'react';
2
- import { PressableProps } from 'react-native';
3
-
4
- interface ButtonProps extends PressableProps {
5
- variant?: "primary" | "secondary" | "ghost";
6
- size?: "sm" | "md" | "lg";
7
- label: string;
8
- }
9
- declare function Button({ variant, size, label, style, ...props }: ButtonProps): react.JSX.Element;
10
-
11
- export { Button };
package/dist/index.js DELETED
@@ -1,28 +0,0 @@
1
- 'use strict';
2
-
3
- var reactNative = require('react-native');
4
-
5
- // src/components/Button/Button.tsx
6
- function Button({ variant = "primary", size = "md", label, style, ...props }) {
7
- return /* @__PURE__ */ React.createElement(reactNative.Pressable, { style: [styles.base, styles[variant], styles[size], style], ...props }, /* @__PURE__ */ React.createElement(reactNative.Text, { style: styles.label }, label));
8
- }
9
- var styles = reactNative.StyleSheet.create({
10
- base: {
11
- alignItems: "center",
12
- justifyContent: "center",
13
- borderRadius: 8
14
- },
15
- label: {
16
- fontWeight: "600"
17
- },
18
- primary: { backgroundColor: "#6366f1" },
19
- secondary: { backgroundColor: "#e5e7eb" },
20
- ghost: { backgroundColor: "transparent" },
21
- sm: { paddingHorizontal: 12, paddingVertical: 6 },
22
- md: { paddingHorizontal: 16, paddingVertical: 10 },
23
- lg: { paddingHorizontal: 24, paddingVertical: 14 }
24
- });
25
-
26
- exports.Button = Button;
27
- //# sourceMappingURL=index.js.map
28
- //# sourceMappingURL=index.js.map
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/Button/Button.tsx"],"names":["Pressable","Text","StyleSheet"],"mappings":";;;;;AASO,SAAS,MAAA,CAAO,EAAE,OAAA,GAAU,SAAA,EAAW,IAAA,GAAO,MAAM,KAAA,EAAO,KAAA,EAAO,GAAG,KAAA,EAAM,EAAgB;AAChG,EAAA,uBACE,KAAA,CAAA,aAAA,CAACA,yBAAU,KAAA,EAAO,CAAC,OAAO,IAAA,EAAM,MAAA,CAAO,OAAO,CAAA,EAAG,MAAA,CAAO,IAAI,GAAG,KAAkB,CAAA,EAAI,GAAG,KAAA,EAAA,kBACtF,KAAA,CAAA,aAAA,CAACC,oBAAK,KAAA,EAAO,MAAA,CAAO,KAAA,EAAA,EAAQ,KAAM,CACpC,CAAA;AAEJ;AAEA,IAAM,MAAA,GAASC,uBAAW,MAAA,CAAO;AAAA,EAC/B,IAAA,EAAM;AAAA,IACJ,UAAA,EAAY,QAAA;AAAA,IACZ,cAAA,EAAgB,QAAA;AAAA,IAChB,YAAA,EAAc;AAAA,GAChB;AAAA,EACA,KAAA,EAAO;AAAA,IACL,UAAA,EAAY;AAAA,GACd;AAAA,EACA,OAAA,EAAS,EAAE,eAAA,EAAiB,SAAA,EAAU;AAAA,EACtC,SAAA,EAAW,EAAE,eAAA,EAAiB,SAAA,EAAU;AAAA,EACxC,KAAA,EAAO,EAAE,eAAA,EAAiB,aAAA,EAAc;AAAA,EACxC,EAAA,EAAI,EAAE,iBAAA,EAAmB,EAAA,EAAI,iBAAiB,CAAA,EAAE;AAAA,EAChD,EAAA,EAAI,EAAE,iBAAA,EAAmB,EAAA,EAAI,iBAAiB,EAAA,EAAG;AAAA,EACjD,EAAA,EAAI,EAAE,iBAAA,EAAmB,EAAA,EAAI,iBAAiB,EAAA;AAChD,CAAC,CAAA","file":"index.js","sourcesContent":["import type { PressableProps, TextStyle, ViewStyle } from \"react-native\";\nimport { Pressable, StyleSheet, Text } from \"react-native\";\n\nexport interface ButtonProps extends PressableProps {\n variant?: \"primary\" | \"secondary\" | \"ghost\";\n size?: \"sm\" | \"md\" | \"lg\";\n label: string;\n}\n\nexport function Button({ variant = \"primary\", size = \"md\", label, style, ...props }: ButtonProps) {\n return (\n <Pressable style={[styles.base, styles[variant], styles[size], style as ViewStyle]} {...props}>\n <Text style={styles.label}>{label}</Text>\n </Pressable>\n );\n}\n\nconst styles = StyleSheet.create({\n base: {\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: 8,\n },\n label: {\n fontWeight: \"600\",\n } as TextStyle,\n primary: { backgroundColor: \"#6366f1\" } as ViewStyle,\n secondary: { backgroundColor: \"#e5e7eb\" } as ViewStyle,\n ghost: { backgroundColor: \"transparent\" } as ViewStyle,\n sm: { paddingHorizontal: 12, paddingVertical: 6 } as ViewStyle,\n md: { paddingHorizontal: 16, paddingVertical: 10 } as ViewStyle,\n lg: { paddingHorizontal: 24, paddingVertical: 14 } as ViewStyle,\n});\n"]}
package/dist/index.mjs DELETED
@@ -1,26 +0,0 @@
1
- import { StyleSheet, Pressable, Text } from 'react-native';
2
-
3
- // src/components/Button/Button.tsx
4
- function Button({ variant = "primary", size = "md", label, style, ...props }) {
5
- return /* @__PURE__ */ React.createElement(Pressable, { style: [styles.base, styles[variant], styles[size], style], ...props }, /* @__PURE__ */ React.createElement(Text, { style: styles.label }, label));
6
- }
7
- var styles = StyleSheet.create({
8
- base: {
9
- alignItems: "center",
10
- justifyContent: "center",
11
- borderRadius: 8
12
- },
13
- label: {
14
- fontWeight: "600"
15
- },
16
- primary: { backgroundColor: "#6366f1" },
17
- secondary: { backgroundColor: "#e5e7eb" },
18
- ghost: { backgroundColor: "transparent" },
19
- sm: { paddingHorizontal: 12, paddingVertical: 6 },
20
- md: { paddingHorizontal: 16, paddingVertical: 10 },
21
- lg: { paddingHorizontal: 24, paddingVertical: 14 }
22
- });
23
-
24
- export { Button };
25
- //# sourceMappingURL=index.mjs.map
26
- //# sourceMappingURL=index.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/components/Button/Button.tsx"],"names":[],"mappings":";;;AASO,SAAS,MAAA,CAAO,EAAE,OAAA,GAAU,SAAA,EAAW,IAAA,GAAO,MAAM,KAAA,EAAO,KAAA,EAAO,GAAG,KAAA,EAAM,EAAgB;AAChG,EAAA,uBACE,KAAA,CAAA,aAAA,CAAC,aAAU,KAAA,EAAO,CAAC,OAAO,IAAA,EAAM,MAAA,CAAO,OAAO,CAAA,EAAG,MAAA,CAAO,IAAI,GAAG,KAAkB,CAAA,EAAI,GAAG,KAAA,EAAA,kBACtF,KAAA,CAAA,aAAA,CAAC,QAAK,KAAA,EAAO,MAAA,CAAO,KAAA,EAAA,EAAQ,KAAM,CACpC,CAAA;AAEJ;AAEA,IAAM,MAAA,GAAS,WAAW,MAAA,CAAO;AAAA,EAC/B,IAAA,EAAM;AAAA,IACJ,UAAA,EAAY,QAAA;AAAA,IACZ,cAAA,EAAgB,QAAA;AAAA,IAChB,YAAA,EAAc;AAAA,GAChB;AAAA,EACA,KAAA,EAAO;AAAA,IACL,UAAA,EAAY;AAAA,GACd;AAAA,EACA,OAAA,EAAS,EAAE,eAAA,EAAiB,SAAA,EAAU;AAAA,EACtC,SAAA,EAAW,EAAE,eAAA,EAAiB,SAAA,EAAU;AAAA,EACxC,KAAA,EAAO,EAAE,eAAA,EAAiB,aAAA,EAAc;AAAA,EACxC,EAAA,EAAI,EAAE,iBAAA,EAAmB,EAAA,EAAI,iBAAiB,CAAA,EAAE;AAAA,EAChD,EAAA,EAAI,EAAE,iBAAA,EAAmB,EAAA,EAAI,iBAAiB,EAAA,EAAG;AAAA,EACjD,EAAA,EAAI,EAAE,iBAAA,EAAmB,EAAA,EAAI,iBAAiB,EAAA;AAChD,CAAC,CAAA","file":"index.mjs","sourcesContent":["import type { PressableProps, TextStyle, ViewStyle } from \"react-native\";\nimport { Pressable, StyleSheet, Text } from \"react-native\";\n\nexport interface ButtonProps extends PressableProps {\n variant?: \"primary\" | \"secondary\" | \"ghost\";\n size?: \"sm\" | \"md\" | \"lg\";\n label: string;\n}\n\nexport function Button({ variant = \"primary\", size = \"md\", label, style, ...props }: ButtonProps) {\n return (\n <Pressable style={[styles.base, styles[variant], styles[size], style as ViewStyle]} {...props}>\n <Text style={styles.label}>{label}</Text>\n </Pressable>\n );\n}\n\nconst styles = StyleSheet.create({\n base: {\n alignItems: \"center\",\n justifyContent: \"center\",\n borderRadius: 8,\n },\n label: {\n fontWeight: \"600\",\n } as TextStyle,\n primary: { backgroundColor: \"#6366f1\" } as ViewStyle,\n secondary: { backgroundColor: \"#e5e7eb\" } as ViewStyle,\n ghost: { backgroundColor: \"transparent\" } as ViewStyle,\n sm: { paddingHorizontal: 12, paddingVertical: 6 } as ViewStyle,\n md: { paddingHorizontal: 16, paddingVertical: 10 } as ViewStyle,\n lg: { paddingHorizontal: 24, paddingVertical: 14 } as ViewStyle,\n});\n"]}