@nexub/react-native 0.0.0-stage → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +111 -2
- package/lib/module/components/actions.js +222 -0
- package/lib/module/components/actions.js.map +1 -0
- package/lib/module/components/containers.js +292 -0
- package/lib/module/components/containers.js.map +1 -0
- package/lib/module/components/display.js +266 -0
- package/lib/module/components/display.js.map +1 -0
- package/lib/module/components/feedback.js +464 -0
- package/lib/module/components/feedback.js.map +1 -0
- package/lib/module/components/inputs.js +746 -0
- package/lib/module/components/inputs.js.map +1 -0
- package/lib/module/components/mobile.js +811 -0
- package/lib/module/components/mobile.js.map +1 -0
- package/lib/module/components/overlays.js +418 -0
- package/lib/module/components/overlays.js.map +1 -0
- package/lib/module/components/shared.js +57 -0
- package/lib/module/components/shared.js.map +1 -0
- package/lib/module/hooks/useControllableState.js +23 -0
- package/lib/module/hooks/useControllableState.js.map +1 -0
- package/lib/module/index.js +30 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/patterns/app.js +709 -0
- package/lib/module/patterns/app.js.map +1 -0
- package/lib/module/patterns/auth.js +224 -0
- package/lib/module/patterns/auth.js.map +1 -0
- package/lib/module/patterns/index.js +7 -0
- package/lib/module/patterns/index.js.map +1 -0
- package/lib/module/patterns/money.js +419 -0
- package/lib/module/patterns/money.js.map +1 -0
- package/lib/module/primitives/Icon.js +17 -0
- package/lib/module/primitives/Icon.js.map +1 -0
- package/lib/module/primitives/Layout.js +79 -0
- package/lib/module/primitives/Layout.js.map +1 -0
- package/lib/module/primitives/Pressable.js +77 -0
- package/lib/module/primitives/Pressable.js.map +1 -0
- package/lib/module/primitives/ScreenContainer.js +58 -0
- package/lib/module/primitives/ScreenContainer.js.map +1 -0
- package/lib/module/primitives/Surface.js +57 -0
- package/lib/module/primitives/Surface.js.map +1 -0
- package/lib/module/primitives/Text.js +70 -0
- package/lib/module/primitives/Text.js.map +1 -0
- package/lib/module/theme/ThemeProvider.js +127 -0
- package/lib/module/theme/ThemeProvider.js.map +1 -0
- package/lib/module/theme/fonts.js +56 -0
- package/lib/module/theme/fonts.js.map +1 -0
- package/lib/module/theme/haptics.js +56 -0
- package/lib/module/theme/haptics.js.map +1 -0
- package/lib/module/theme/navigation.js +99 -0
- package/lib/module/theme/navigation.js.map +1 -0
- package/lib/typescript/components/actions.d.ts +53 -0
- package/lib/typescript/components/actions.d.ts.map +1 -0
- package/lib/typescript/components/containers.d.ts +59 -0
- package/lib/typescript/components/containers.d.ts.map +1 -0
- package/lib/typescript/components/display.d.ts +62 -0
- package/lib/typescript/components/display.d.ts.map +1 -0
- package/lib/typescript/components/feedback.d.ts +93 -0
- package/lib/typescript/components/feedback.d.ts.map +1 -0
- package/lib/typescript/components/inputs.d.ts +141 -0
- package/lib/typescript/components/inputs.d.ts.map +1 -0
- package/lib/typescript/components/mobile.d.ts +173 -0
- package/lib/typescript/components/mobile.d.ts.map +1 -0
- package/lib/typescript/components/overlays.d.ts +74 -0
- package/lib/typescript/components/overlays.d.ts.map +1 -0
- package/lib/typescript/components/shared.d.ts +20 -0
- package/lib/typescript/components/shared.d.ts.map +1 -0
- package/lib/typescript/hooks/useControllableState.d.ts +6 -0
- package/lib/typescript/hooks/useControllableState.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +37 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/patterns/app.d.ts +139 -0
- package/lib/typescript/patterns/app.d.ts.map +1 -0
- package/lib/typescript/patterns/auth.d.ts +54 -0
- package/lib/typescript/patterns/auth.d.ts.map +1 -0
- package/lib/typescript/patterns/index.d.ts +7 -0
- package/lib/typescript/patterns/index.d.ts.map +1 -0
- package/lib/typescript/patterns/money.d.ts +106 -0
- package/lib/typescript/patterns/money.d.ts.map +1 -0
- package/lib/typescript/primitives/Icon.d.ts +12 -0
- package/lib/typescript/primitives/Icon.d.ts.map +1 -0
- package/lib/typescript/primitives/Layout.d.ts +26 -0
- package/lib/typescript/primitives/Layout.d.ts.map +1 -0
- package/lib/typescript/primitives/Pressable.d.ts +21 -0
- package/lib/typescript/primitives/Pressable.d.ts.map +1 -0
- package/lib/typescript/primitives/ScreenContainer.d.ts +25 -0
- package/lib/typescript/primitives/ScreenContainer.d.ts.map +1 -0
- package/lib/typescript/primitives/Surface.d.ts +23 -0
- package/lib/typescript/primitives/Surface.d.ts.map +1 -0
- package/lib/typescript/primitives/Text.d.ts +21 -0
- package/lib/typescript/primitives/Text.d.ts.map +1 -0
- package/lib/typescript/theme/ThemeProvider.d.ts +69 -0
- package/lib/typescript/theme/ThemeProvider.d.ts.map +1 -0
- package/lib/typescript/theme/fonts.d.ts +25 -0
- package/lib/typescript/theme/fonts.d.ts.map +1 -0
- package/lib/typescript/theme/haptics.d.ts +3 -0
- package/lib/typescript/theme/haptics.d.ts.map +1 -0
- package/lib/typescript/theme/navigation.d.ts +158 -0
- package/lib/typescript/theme/navigation.d.ts.map +1 -0
- package/package.json +138 -3
- package/src/components/actions.tsx +259 -0
- package/src/components/containers.tsx +341 -0
- package/src/components/display.tsx +314 -0
- package/src/components/feedback.tsx +522 -0
- package/src/components/inputs.tsx +851 -0
- package/src/components/mobile.tsx +879 -0
- package/src/components/overlays.tsx +485 -0
- package/src/components/shared.ts +54 -0
- package/src/hooks/useControllableState.ts +27 -0
- package/src/index.ts +175 -0
- package/src/patterns/app.tsx +715 -0
- package/src/patterns/auth.tsx +266 -0
- package/src/patterns/index.ts +57 -0
- package/src/patterns/money.tsx +458 -0
- package/src/primitives/Icon.tsx +15 -0
- package/src/primitives/Layout.tsx +71 -0
- package/src/primitives/Pressable.tsx +94 -0
- package/src/primitives/ScreenContainer.tsx +65 -0
- package/src/primitives/Surface.tsx +75 -0
- package/src/primitives/Text.tsx +79 -0
- package/src/theme/ThemeProvider.tsx +210 -0
- package/src/theme/fonts.ts +52 -0
- package/src/theme/haptics.ts +57 -0
- package/src/theme/navigation.ts +68 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { native, type NativeRoles } from '@nexub/tokens/native';
|
|
3
|
+
import { type ContrastLevel, type Direction, type GlassMode, type NexubMessages, type Product } from '@nexub/core';
|
|
4
|
+
import { type HapticToken } from './haptics.js';
|
|
5
|
+
import type { FontSource } from './fonts.js';
|
|
6
|
+
export type Scheme = 'light' | 'dark';
|
|
7
|
+
export type Roles = {
|
|
8
|
+
-readonly [K in keyof NativeRoles]: string;
|
|
9
|
+
};
|
|
10
|
+
export type RoleName = keyof Roles;
|
|
11
|
+
export type ElevationLevel = 0 | 1 | 2 | 3;
|
|
12
|
+
export interface NexubTheme {
|
|
13
|
+
scheme: Scheme;
|
|
14
|
+
contrast: ContrastLevel;
|
|
15
|
+
product: Product | undefined;
|
|
16
|
+
/** Colour roles, already resolved for scheme, contrast, product and seed. */
|
|
17
|
+
roles: Roles;
|
|
18
|
+
/** Every native token (spacing, shape, size, type, state, motion). */
|
|
19
|
+
tokens: typeof native;
|
|
20
|
+
/** `boxShadow` for an elevation level, undefined for 0. */
|
|
21
|
+
elevation: (level: ElevationLevel) => string | undefined;
|
|
22
|
+
/** Effective glass: 'off' when the user has Reduce Transparency on. */
|
|
23
|
+
glass: GlassMode;
|
|
24
|
+
reducedMotion: boolean;
|
|
25
|
+
haptics: boolean;
|
|
26
|
+
fonts: FontSource;
|
|
27
|
+
locale: string;
|
|
28
|
+
dir: Direction;
|
|
29
|
+
messages: NexubMessages;
|
|
30
|
+
}
|
|
31
|
+
export interface NexubNativeProviderProps {
|
|
32
|
+
/** @default 'system' */
|
|
33
|
+
scheme?: Scheme | 'system';
|
|
34
|
+
/** 'system' = iOS Increase Contrast / Android high-contrast text → 'high'. @default 'system' */
|
|
35
|
+
contrast?: ContrastLevel | 'system';
|
|
36
|
+
/** Product brand: remaps the tertiary role family. */
|
|
37
|
+
product?: Product;
|
|
38
|
+
/** White-label seed colour (#rgb / #rrggbb); regenerates the `seedTarget` family. */
|
|
39
|
+
seed?: string;
|
|
40
|
+
/** @default 'primary' */
|
|
41
|
+
seedTarget?: 'primary' | 'tertiary';
|
|
42
|
+
/** Glass intensity (the app persists the user's choice). @default 'balanced' */
|
|
43
|
+
glass?: GlassMode;
|
|
44
|
+
/** Haptics on/off (user setting). @default true */
|
|
45
|
+
haptics?: boolean;
|
|
46
|
+
/** 'nexub' needs `nexubFonts` loaded; 'system' uses the platform font. @default 'nexub' */
|
|
47
|
+
fonts?: FontSource;
|
|
48
|
+
/** BCP 47 locale for Intl formatting. @default 'en' */
|
|
49
|
+
locale?: string;
|
|
50
|
+
/** @default derived from `locale` */
|
|
51
|
+
dir?: Direction;
|
|
52
|
+
/** Overrides for the default English strings. */
|
|
53
|
+
messages?: Partial<NexubMessages>;
|
|
54
|
+
children?: React.ReactNode;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Theme, accessibility preferences, locale and strings for every
|
|
58
|
+
* @nexub/react-native component. Wrap the app once, inside the safe-area provider.
|
|
59
|
+
*/
|
|
60
|
+
export declare function NexubNativeProvider({ scheme: schemeProp, contrast: contrastProp, product, seed, seedTarget, glass, haptics, fonts, locale, dir, messages, children, }: NexubNativeProviderProps): React.JSX.Element;
|
|
61
|
+
/** The active theme. Throws outside NexubNativeProvider. */
|
|
62
|
+
export declare function useTheme(): NexubTheme;
|
|
63
|
+
/** Shorthand for `useTheme().roles`. */
|
|
64
|
+
export declare const useRoles: () => Roles;
|
|
65
|
+
/** The active strings: defaults merged with the provider's overrides. */
|
|
66
|
+
export declare const useNexubMessages: () => NexubMessages;
|
|
67
|
+
/** Plays a semantic haptic, unless the user turned haptics off. */
|
|
68
|
+
export declare function useHaptics(): (token: HapticToken) => void;
|
|
69
|
+
//# sourceMappingURL=ThemeProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ThemeProvider.d.ts","sourceRoot":"","sources":["../../../src/theme/ThemeProvider.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export declare const nexubFonts: {
|
|
2
|
+
Inter_400Regular: number;
|
|
3
|
+
Inter_500Medium: number;
|
|
4
|
+
Inter_600SemiBold: number;
|
|
5
|
+
Inter_700Bold: number;
|
|
6
|
+
PlusJakartaSans_600SemiBold: number;
|
|
7
|
+
PlusJakartaSans_700Bold: number;
|
|
8
|
+
PlusJakartaSans_800ExtraBold: number;
|
|
9
|
+
GeistMono_400Regular: number;
|
|
10
|
+
};
|
|
11
|
+
export type FontFamily = 'sans' | 'display' | 'mono';
|
|
12
|
+
export type FontSource = 'nexub' | 'system';
|
|
13
|
+
/**
|
|
14
|
+
* Style for a family + weight. With static files the weight lives in the file
|
|
15
|
+
* name, so `fontWeight` is only set for the system font (Android picks the
|
|
16
|
+
* wrong file when both are set).
|
|
17
|
+
*/
|
|
18
|
+
export declare function fontStyle(family: FontFamily, weight: number, source: FontSource): {
|
|
19
|
+
fontWeight: "400";
|
|
20
|
+
fontFamily?: undefined;
|
|
21
|
+
} | {
|
|
22
|
+
fontFamily: string | undefined;
|
|
23
|
+
fontWeight?: undefined;
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=fonts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fonts.d.ts","sourceRoot":"","sources":["../../../src/theme/fonts.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,UAAU;;;;;;;;;CAStB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC;AACrD,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,QAAQ,CAAC;AAiB5C;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU;gBACd,KAAK;;;;;EAGtE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"haptics.d.ts","sourceRoot":"","sources":["../../../src/theme/haptics.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,WAAW,GACrB,WAAW,GAAG,UAAU,GAAG,WAAW,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAqBrF,wBAAgB,UAAU,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CA6BnD"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { type NexubTheme } from './ThemeProvider.js';
|
|
2
|
+
/** Native stack `screenOptions`: large titles on a surface-coloured native header, Nexub type and tint. */
|
|
3
|
+
export declare function nexubStackOptions(theme: NexubTheme): {
|
|
4
|
+
headerLargeTitle: boolean;
|
|
5
|
+
headerTransparent: boolean;
|
|
6
|
+
headerShadowVisible: boolean;
|
|
7
|
+
headerLargeTitleShadowVisible: boolean;
|
|
8
|
+
headerTintColor: string;
|
|
9
|
+
headerStyle: {
|
|
10
|
+
backgroundColor: string;
|
|
11
|
+
};
|
|
12
|
+
headerTitleStyle: {
|
|
13
|
+
fontWeight: "400";
|
|
14
|
+
fontFamily?: undefined;
|
|
15
|
+
color: string;
|
|
16
|
+
} | {
|
|
17
|
+
fontFamily: string | undefined;
|
|
18
|
+
fontWeight?: undefined;
|
|
19
|
+
color: string;
|
|
20
|
+
};
|
|
21
|
+
headerLargeTitleStyle: {
|
|
22
|
+
fontWeight: "400";
|
|
23
|
+
fontFamily?: undefined;
|
|
24
|
+
color: string;
|
|
25
|
+
} | {
|
|
26
|
+
fontFamily: string | undefined;
|
|
27
|
+
fontWeight?: undefined;
|
|
28
|
+
color: string;
|
|
29
|
+
};
|
|
30
|
+
contentStyle: {
|
|
31
|
+
backgroundColor: string;
|
|
32
|
+
};
|
|
33
|
+
};
|
|
34
|
+
/** React Navigation `theme` (also Expo Router's ThemeProvider). */
|
|
35
|
+
export declare function nexubNavigationTheme(theme: NexubTheme): {
|
|
36
|
+
dark: boolean;
|
|
37
|
+
colors: {
|
|
38
|
+
primary: string;
|
|
39
|
+
background: string;
|
|
40
|
+
card: string;
|
|
41
|
+
text: string;
|
|
42
|
+
border: string;
|
|
43
|
+
notification: string;
|
|
44
|
+
};
|
|
45
|
+
fonts: {
|
|
46
|
+
regular: {
|
|
47
|
+
fontFamily: string;
|
|
48
|
+
fontWeight: "400";
|
|
49
|
+
};
|
|
50
|
+
medium: {
|
|
51
|
+
fontFamily: string;
|
|
52
|
+
fontWeight: "400";
|
|
53
|
+
};
|
|
54
|
+
bold: {
|
|
55
|
+
fontFamily: string;
|
|
56
|
+
fontWeight: "400";
|
|
57
|
+
};
|
|
58
|
+
heavy: {
|
|
59
|
+
fontFamily: string;
|
|
60
|
+
fontWeight: "400";
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
/** Colours for native tab bars (Expo Router NativeTabs / react-native-bottom-tabs). */
|
|
65
|
+
export declare function nexubTabsOptions(theme: NexubTheme): {
|
|
66
|
+
tintColor: string;
|
|
67
|
+
inactiveTintColor: string;
|
|
68
|
+
backgroundColor: string;
|
|
69
|
+
badgeBackgroundColor: string;
|
|
70
|
+
labelStyle: {
|
|
71
|
+
fontSize: number;
|
|
72
|
+
fontWeight: "400";
|
|
73
|
+
fontFamily?: undefined;
|
|
74
|
+
} | {
|
|
75
|
+
fontSize: number;
|
|
76
|
+
fontFamily: string | undefined;
|
|
77
|
+
fontWeight?: undefined;
|
|
78
|
+
};
|
|
79
|
+
};
|
|
80
|
+
/** All three for the current theme: `const nav = useNexubNavigation()`. */
|
|
81
|
+
export declare function useNexubNavigation(): {
|
|
82
|
+
stack: {
|
|
83
|
+
headerLargeTitle: boolean;
|
|
84
|
+
headerTransparent: boolean;
|
|
85
|
+
headerShadowVisible: boolean;
|
|
86
|
+
headerLargeTitleShadowVisible: boolean;
|
|
87
|
+
headerTintColor: string;
|
|
88
|
+
headerStyle: {
|
|
89
|
+
backgroundColor: string;
|
|
90
|
+
};
|
|
91
|
+
headerTitleStyle: {
|
|
92
|
+
fontWeight: "400";
|
|
93
|
+
fontFamily?: undefined;
|
|
94
|
+
color: string;
|
|
95
|
+
} | {
|
|
96
|
+
fontFamily: string | undefined;
|
|
97
|
+
fontWeight?: undefined;
|
|
98
|
+
color: string;
|
|
99
|
+
};
|
|
100
|
+
headerLargeTitleStyle: {
|
|
101
|
+
fontWeight: "400";
|
|
102
|
+
fontFamily?: undefined;
|
|
103
|
+
color: string;
|
|
104
|
+
} | {
|
|
105
|
+
fontFamily: string | undefined;
|
|
106
|
+
fontWeight?: undefined;
|
|
107
|
+
color: string;
|
|
108
|
+
};
|
|
109
|
+
contentStyle: {
|
|
110
|
+
backgroundColor: string;
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
theme: {
|
|
114
|
+
dark: boolean;
|
|
115
|
+
colors: {
|
|
116
|
+
primary: string;
|
|
117
|
+
background: string;
|
|
118
|
+
card: string;
|
|
119
|
+
text: string;
|
|
120
|
+
border: string;
|
|
121
|
+
notification: string;
|
|
122
|
+
};
|
|
123
|
+
fonts: {
|
|
124
|
+
regular: {
|
|
125
|
+
fontFamily: string;
|
|
126
|
+
fontWeight: "400";
|
|
127
|
+
};
|
|
128
|
+
medium: {
|
|
129
|
+
fontFamily: string;
|
|
130
|
+
fontWeight: "400";
|
|
131
|
+
};
|
|
132
|
+
bold: {
|
|
133
|
+
fontFamily: string;
|
|
134
|
+
fontWeight: "400";
|
|
135
|
+
};
|
|
136
|
+
heavy: {
|
|
137
|
+
fontFamily: string;
|
|
138
|
+
fontWeight: "400";
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
tabs: {
|
|
143
|
+
tintColor: string;
|
|
144
|
+
inactiveTintColor: string;
|
|
145
|
+
backgroundColor: string;
|
|
146
|
+
badgeBackgroundColor: string;
|
|
147
|
+
labelStyle: {
|
|
148
|
+
fontSize: number;
|
|
149
|
+
fontWeight: "400";
|
|
150
|
+
fontFamily?: undefined;
|
|
151
|
+
} | {
|
|
152
|
+
fontSize: number;
|
|
153
|
+
fontFamily: string | undefined;
|
|
154
|
+
fontWeight?: undefined;
|
|
155
|
+
};
|
|
156
|
+
};
|
|
157
|
+
};
|
|
158
|
+
//# sourceMappingURL=navigation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"navigation.d.ts","sourceRoot":"","sources":["../../../src/theme/navigation.ts"],"names":[],"mappings":"AAGA,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,oBAAiB,CAAC;AAE5D,2GAA2G;AAC3G,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAelD;AAED,mEAAmE;AACnE,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,UAAU;;;;;;;;;;;;;wBAMlB,KAAK;;;;wBAAL,KAAK;;;;wBAAL,KAAK;;;;wBAAL,KAAK;;;EAexC;AAED,uFAAuF;AACvF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU;;;;;;;;;;;;;;EASjD;AAED,2EAA2E;AAC3E,wBAAgB,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4BA9BE,KAAK;;;;4BAAL,KAAK;;;;4BAAL,KAAK;;;;4BAAL,KAAK;;;;;;;;;;;;;;;;;;;EAqCxC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,141 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nexub/react-native",
|
|
3
|
-
"version": "
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "2.1.0",
|
|
4
|
+
"description": "React Native components for Nexub Design System — native chrome, Nexub content. Same tokens, brands and prop names as @nexub/react, for Expo and bare React Native apps.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://github.com/Nexub-AI/nexub-ds#readme",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/Nexub-AI/nexub-ds.git",
|
|
10
|
+
"directory": "packages/react-native"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"react-native",
|
|
14
|
+
"expo",
|
|
15
|
+
"components",
|
|
16
|
+
"design-system",
|
|
17
|
+
"nexub"
|
|
18
|
+
],
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"src",
|
|
24
|
+
"lib",
|
|
25
|
+
"!src/__tests__"
|
|
26
|
+
],
|
|
27
|
+
"sideEffects": false,
|
|
28
|
+
"main": "./lib/module/index.js",
|
|
29
|
+
"types": "./lib/typescript/index.d.ts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"source": "./src/index.ts",
|
|
33
|
+
"types": "./lib/typescript/index.d.ts",
|
|
34
|
+
"default": "./lib/module/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./patterns": {
|
|
37
|
+
"source": "./src/patterns/index.ts",
|
|
38
|
+
"types": "./lib/typescript/patterns/index.d.ts",
|
|
39
|
+
"default": "./lib/module/patterns/index.js"
|
|
40
|
+
},
|
|
41
|
+
"./package.json": "./package.json"
|
|
42
|
+
},
|
|
43
|
+
"react-native-builder-bob": {
|
|
44
|
+
"source": "src",
|
|
45
|
+
"output": "lib",
|
|
46
|
+
"targets": [
|
|
47
|
+
[
|
|
48
|
+
"module",
|
|
49
|
+
{
|
|
50
|
+
"esm": true
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
[
|
|
54
|
+
"typescript",
|
|
55
|
+
{
|
|
56
|
+
"project": "tsconfig.build.json"
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
]
|
|
60
|
+
},
|
|
61
|
+
"dependencies": {
|
|
62
|
+
"@expo-google-fonts/geist-mono": "^0.4.3",
|
|
63
|
+
"@expo-google-fonts/inter": "^0.4.2",
|
|
64
|
+
"@expo-google-fonts/plus-jakarta-sans": "^0.4.2",
|
|
65
|
+
"lucide-react-native": "^1.64.0",
|
|
66
|
+
"@nexub/core": "2.1.0",
|
|
67
|
+
"@nexub/icons": "2.1.0",
|
|
68
|
+
"@nexub/tokens": "2.1.0"
|
|
69
|
+
},
|
|
70
|
+
"peerDependencies": {
|
|
71
|
+
"expo-glass-effect": ">=57.0.0",
|
|
72
|
+
"expo-haptics": ">=57.0.0",
|
|
73
|
+
"react": ">=19.1.0",
|
|
74
|
+
"react-native": ">=0.86.0",
|
|
75
|
+
"react-native-reanimated": ">=4.5.0",
|
|
76
|
+
"react-native-safe-area-context": ">=5.6.0",
|
|
77
|
+
"react-native-svg": ">=15.0.0",
|
|
78
|
+
"@react-native-community/datetimepicker": ">=8.4.0",
|
|
79
|
+
"expo-screen-capture": ">=57.0.0"
|
|
80
|
+
},
|
|
81
|
+
"peerDependenciesMeta": {
|
|
82
|
+
"expo-glass-effect": {
|
|
83
|
+
"optional": true
|
|
84
|
+
},
|
|
85
|
+
"expo-haptics": {
|
|
86
|
+
"optional": true
|
|
87
|
+
},
|
|
88
|
+
"@react-native-community/datetimepicker": {
|
|
89
|
+
"optional": true
|
|
90
|
+
},
|
|
91
|
+
"expo-screen-capture": {
|
|
92
|
+
"optional": true
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"devDependencies": {
|
|
96
|
+
"@testing-library/react-native": "^14.1.0",
|
|
97
|
+
"@types/jest": "^30.0.0",
|
|
98
|
+
"@types/react": "~19.3.0",
|
|
99
|
+
"expo": "~58.0.21",
|
|
100
|
+
"expo-glass-effect": "~58.0.5",
|
|
101
|
+
"expo-haptics": "~58.0.7",
|
|
102
|
+
"jest": "^30.2.0",
|
|
103
|
+
"jest-expo": "~58.0.13",
|
|
104
|
+
"react": "19.3.0",
|
|
105
|
+
"react-native": "0.88.1",
|
|
106
|
+
"react-native-builder-bob": "^0.44.1",
|
|
107
|
+
"react-native-reanimated": "4.7.1",
|
|
108
|
+
"react-native-safe-area-context": "~5.10.1",
|
|
109
|
+
"react-native-svg": "15.16.0",
|
|
110
|
+
"react-native-worklets": "0.13.0",
|
|
111
|
+
"typescript": "^5.9.3",
|
|
112
|
+
"@react-native-community/datetimepicker": "9.2.1",
|
|
113
|
+
"expo-screen-capture": "~58.0.6"
|
|
114
|
+
},
|
|
115
|
+
"jest": {
|
|
116
|
+
"preset": "jest-expo",
|
|
117
|
+
"roots": [
|
|
118
|
+
"<rootDir>/src"
|
|
119
|
+
],
|
|
120
|
+
"setupFiles": [
|
|
121
|
+
"<rootDir>/jest.setup.js"
|
|
122
|
+
],
|
|
123
|
+
"transformIgnorePatterns": [
|
|
124
|
+
"node_modules/(?!(\\.pnpm|((jest-)?react-native|@react-native(-community)?)|expo(nent)?|@expo(nent)?/.*|@expo-google-fonts/.*|react-navigation|@react-navigation/.*|react-native-svg|lucide-react-native|@nexub/.*|@material/.*))"
|
|
125
|
+
],
|
|
126
|
+
"transform": {
|
|
127
|
+
"^.+\\.mjs$": "babel-jest"
|
|
128
|
+
},
|
|
129
|
+
"moduleNameMapper": {
|
|
130
|
+
"^react$": "<rootDir>/node_modules/react",
|
|
131
|
+
"^react/(.*)$": "<rootDir>/node_modules/react/$1"
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
"scripts": {
|
|
135
|
+
"build": "bob build",
|
|
136
|
+
"clean": "rm -rf lib",
|
|
137
|
+
"typecheck": "tsc --noEmit",
|
|
138
|
+
"lint": "eslint src",
|
|
139
|
+
"test": "jest"
|
|
140
|
+
}
|
|
6
141
|
}
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { ActivityIndicator, View, type StyleProp, type ViewStyle } from 'react-native';
|
|
3
|
+
import type { ControlSize, ToneValue } from '@nexub/core';
|
|
4
|
+
import type { NativeIconProps } from '@nexub/icons/native';
|
|
5
|
+
import { Pressable, type PressableProps } from '../primitives/Pressable';
|
|
6
|
+
import { Surface } from '../primitives/Surface';
|
|
7
|
+
import { Text } from '../primitives/Text';
|
|
8
|
+
import { useTheme, type RoleName } from '../theme/ThemeProvider';
|
|
9
|
+
import type { HapticToken } from '../theme/haptics';
|
|
10
|
+
import { TONE_ROLES, controlHeight, disabledOpacity, hitSlopFor } from './shared';
|
|
11
|
+
|
|
12
|
+
export type ButtonVariant = 'filled' | 'tonal' | 'outlined' | 'text' | 'glass';
|
|
13
|
+
|
|
14
|
+
// [container role | undefined, content role]
|
|
15
|
+
const VARIANT: Record<ButtonVariant, [RoleName | undefined, RoleName]> = {
|
|
16
|
+
filled: ['primary', 'on-primary'],
|
|
17
|
+
tonal: ['secondary-container', 'on-secondary-container'],
|
|
18
|
+
outlined: [undefined, 'on-surface'],
|
|
19
|
+
text: [undefined, 'primary'],
|
|
20
|
+
glass: [undefined, 'on-surface'],
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const LABEL: Record<ControlSize, 'label-md' | 'label-lg' | 'title-md'> = {
|
|
24
|
+
xs: 'label-md',
|
|
25
|
+
sm: 'label-md',
|
|
26
|
+
md: 'label-lg',
|
|
27
|
+
lg: 'label-lg',
|
|
28
|
+
xl: 'title-md',
|
|
29
|
+
};
|
|
30
|
+
const PAD: Record<ControlSize, number> = { xs: 10, sm: 14, md: 20, lg: 24, xl: 28 };
|
|
31
|
+
const ICON: Record<ControlSize, NativeIconProps['size']> = {
|
|
32
|
+
xs: 'xs',
|
|
33
|
+
sm: 'sm',
|
|
34
|
+
md: 'sm',
|
|
35
|
+
lg: 'md',
|
|
36
|
+
xl: 'md',
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export interface ButtonProps extends Omit<PressableProps, 'children'> {
|
|
40
|
+
children: React.ReactNode;
|
|
41
|
+
/** @default 'filled' */
|
|
42
|
+
variant?: ButtonVariant;
|
|
43
|
+
/** Solid semantic or product colour (overrides the variant colour). */
|
|
44
|
+
tone?: ToneValue;
|
|
45
|
+
/** The control ladder. Primary actions on mobile use 'lg' (48). @default 'md' */
|
|
46
|
+
size?: ControlSize;
|
|
47
|
+
/** Shows a spinner, blocks presses and announces `loadingLabel`. */
|
|
48
|
+
loading?: boolean;
|
|
49
|
+
loadingLabel?: string;
|
|
50
|
+
fullWidth?: boolean;
|
|
51
|
+
leadingIcon?: React.ComponentType<NativeIconProps>;
|
|
52
|
+
trailingIcon?: React.ComponentType<NativeIconProps>;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Capsule button. One `filled` (or toned) action per screen; the rest tonal/outlined/text. */
|
|
56
|
+
export function Button({
|
|
57
|
+
children,
|
|
58
|
+
variant = 'filled',
|
|
59
|
+
tone,
|
|
60
|
+
size = 'md',
|
|
61
|
+
loading,
|
|
62
|
+
loadingLabel,
|
|
63
|
+
fullWidth,
|
|
64
|
+
leadingIcon: Leading,
|
|
65
|
+
trailingIcon: Trailing,
|
|
66
|
+
disabled,
|
|
67
|
+
style,
|
|
68
|
+
accessibilityLabel,
|
|
69
|
+
...rest
|
|
70
|
+
}: ButtonProps) {
|
|
71
|
+
const theme = useTheme();
|
|
72
|
+
const { roles } = theme;
|
|
73
|
+
const [bgRole, fgRole] = tone ? TONE_ROLES[tone] : VARIANT[variant];
|
|
74
|
+
const height = controlHeight(theme, size);
|
|
75
|
+
const fg = roles[fgRole];
|
|
76
|
+
const inactive = disabled || loading;
|
|
77
|
+
const label = typeof children === 'string' ? children : undefined;
|
|
78
|
+
|
|
79
|
+
const body = (
|
|
80
|
+
<View
|
|
81
|
+
style={{
|
|
82
|
+
flexDirection: 'row',
|
|
83
|
+
alignItems: 'center',
|
|
84
|
+
justifyContent: 'center',
|
|
85
|
+
gap: 8,
|
|
86
|
+
opacity: disabled ? disabledOpacity(theme) : 1,
|
|
87
|
+
}}
|
|
88
|
+
>
|
|
89
|
+
{loading ? (
|
|
90
|
+
<ActivityIndicator size="small" color={fg} />
|
|
91
|
+
) : (
|
|
92
|
+
Leading && <Leading size={ICON[size]} color={fg} />
|
|
93
|
+
)}
|
|
94
|
+
{typeof children === 'string' ? (
|
|
95
|
+
<Text variant={LABEL[size]} style={{ color: fg }} numberOfLines={1}>
|
|
96
|
+
{children}
|
|
97
|
+
</Text>
|
|
98
|
+
) : (
|
|
99
|
+
children
|
|
100
|
+
)}
|
|
101
|
+
{!loading && Trailing && <Trailing size={ICON[size]} color={fg} />}
|
|
102
|
+
</View>
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
const shape: StyleProp<ViewStyle> = [
|
|
106
|
+
{
|
|
107
|
+
height,
|
|
108
|
+
paddingHorizontal: PAD[size],
|
|
109
|
+
borderRadius: theme.tokens.shape.control,
|
|
110
|
+
justifyContent: 'center',
|
|
111
|
+
alignSelf: fullWidth ? 'stretch' : 'flex-start',
|
|
112
|
+
backgroundColor: bgRole ? roles[bgRole] : 'transparent',
|
|
113
|
+
},
|
|
114
|
+
variant === 'outlined' && !tone && { borderWidth: 1, borderColor: roles['outline-variant'] },
|
|
115
|
+
disabled && bgRole && { backgroundColor: roles['on-surface'] + '1f' }, // disabled-container 12%
|
|
116
|
+
style,
|
|
117
|
+
];
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<Pressable
|
|
121
|
+
accessibilityLabel={accessibilityLabel ?? (loading && loadingLabel ? loadingLabel : label)}
|
|
122
|
+
accessibilityState={{ disabled: !!inactive, busy: !!loading }}
|
|
123
|
+
disabled={inactive}
|
|
124
|
+
hitSlop={hitSlopFor(height)}
|
|
125
|
+
stateLayer={fgRole}
|
|
126
|
+
style={
|
|
127
|
+
variant === 'glass' && !tone ? { alignSelf: fullWidth ? 'stretch' : 'flex-start' } : shape
|
|
128
|
+
}
|
|
129
|
+
{...rest}
|
|
130
|
+
>
|
|
131
|
+
{variant === 'glass' && !tone ? (
|
|
132
|
+
<Surface
|
|
133
|
+
material="glass"
|
|
134
|
+
radius="control"
|
|
135
|
+
style={[{ height, paddingHorizontal: PAD[size], justifyContent: 'center' }, style]}
|
|
136
|
+
>
|
|
137
|
+
{body}
|
|
138
|
+
</Surface>
|
|
139
|
+
) : (
|
|
140
|
+
body
|
|
141
|
+
)}
|
|
142
|
+
</Pressable>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export interface IconButtonProps extends Omit<PressableProps, 'children'> {
|
|
147
|
+
icon: React.ComponentType<NativeIconProps>;
|
|
148
|
+
/** Required: the accessible name (what it does, not "button"). */
|
|
149
|
+
label: string;
|
|
150
|
+
/** @default 'text' */
|
|
151
|
+
variant?: ButtonVariant;
|
|
152
|
+
tone?: ToneValue;
|
|
153
|
+
/** @default 'md' */
|
|
154
|
+
size?: ControlSize;
|
|
155
|
+
/** Toggle state for icon toggles (favourite, mute). */
|
|
156
|
+
selected?: boolean;
|
|
157
|
+
haptic?: HapticToken;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Circular icon-only button; always 44pt+ to touch. */
|
|
161
|
+
export function IconButton({
|
|
162
|
+
icon: Glyph,
|
|
163
|
+
label,
|
|
164
|
+
variant = 'text',
|
|
165
|
+
tone,
|
|
166
|
+
size = 'md',
|
|
167
|
+
selected,
|
|
168
|
+
disabled,
|
|
169
|
+
style,
|
|
170
|
+
...rest
|
|
171
|
+
}: IconButtonProps) {
|
|
172
|
+
const theme = useTheme();
|
|
173
|
+
const [bgRole, fgRole] = tone ? TONE_ROLES[tone] : VARIANT[variant];
|
|
174
|
+
const fgSelected: RoleName = selected
|
|
175
|
+
? 'primary'
|
|
176
|
+
: variant === 'text' && !tone
|
|
177
|
+
? 'on-surface-variant'
|
|
178
|
+
: fgRole;
|
|
179
|
+
const height = controlHeight(theme, size);
|
|
180
|
+
return (
|
|
181
|
+
<Pressable
|
|
182
|
+
accessibilityLabel={label}
|
|
183
|
+
accessibilityState={{ disabled: !!disabled, selected }}
|
|
184
|
+
disabled={disabled}
|
|
185
|
+
hitSlop={hitSlopFor(height)}
|
|
186
|
+
stateLayer={fgRole}
|
|
187
|
+
style={[
|
|
188
|
+
{
|
|
189
|
+
width: height,
|
|
190
|
+
height,
|
|
191
|
+
borderRadius: height / 2,
|
|
192
|
+
alignItems: 'center',
|
|
193
|
+
justifyContent: 'center',
|
|
194
|
+
backgroundColor: bgRole ? theme.roles[bgRole] : 'transparent',
|
|
195
|
+
opacity: disabled ? disabledOpacity(theme) : 1,
|
|
196
|
+
},
|
|
197
|
+
variant === 'outlined' && { borderWidth: 1, borderColor: theme.roles['outline-variant'] },
|
|
198
|
+
style,
|
|
199
|
+
]}
|
|
200
|
+
{...rest}
|
|
201
|
+
>
|
|
202
|
+
<Glyph
|
|
203
|
+
size={ICON[size] === 'xs' ? 'sm' : size === 'xl' ? 'lg' : 'md'}
|
|
204
|
+
color={theme.roles[fgSelected]}
|
|
205
|
+
/>
|
|
206
|
+
</Pressable>
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export interface ButtonGroupProps {
|
|
211
|
+
children: React.ReactNode;
|
|
212
|
+
/** 'stack' puts actions full-width in a column (bottom of forms). @default 'row' */
|
|
213
|
+
direction?: 'row' | 'stack';
|
|
214
|
+
style?: StyleProp<ViewStyle>;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** Related actions together. In a stack, put the primary action first. */
|
|
218
|
+
export function ButtonGroup({ children, direction = 'row', style }: ButtonGroupProps) {
|
|
219
|
+
const { tokens } = useTheme();
|
|
220
|
+
return (
|
|
221
|
+
<View
|
|
222
|
+
style={[
|
|
223
|
+
direction === 'row'
|
|
224
|
+
? { flexDirection: 'row', flexWrap: 'wrap', gap: tokens.spacing[2] }
|
|
225
|
+
: { gap: tokens.spacing[3], alignItems: 'stretch' },
|
|
226
|
+
style,
|
|
227
|
+
]}
|
|
228
|
+
>
|
|
229
|
+
{direction === 'stack'
|
|
230
|
+
? React.Children.map(children, (c) =>
|
|
231
|
+
React.isValidElement<ButtonProps>(c) ? React.cloneElement(c, { fullWidth: true }) : c,
|
|
232
|
+
)
|
|
233
|
+
: children}
|
|
234
|
+
</View>
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export interface LinkProps extends Omit<PressableProps, 'children'> {
|
|
239
|
+
children: string;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** Inline text action. Opens nothing by itself: pass `onPress` (e.g. router.push / Linking.openURL). */
|
|
243
|
+
export function Link({ children, style, ...rest }: LinkProps) {
|
|
244
|
+
return (
|
|
245
|
+
<Pressable
|
|
246
|
+
accessibilityRole="link"
|
|
247
|
+
accessibilityLabel={children}
|
|
248
|
+
stateLayer={false}
|
|
249
|
+
pressScale={false}
|
|
250
|
+
hitSlop={8}
|
|
251
|
+
style={style}
|
|
252
|
+
{...rest}
|
|
253
|
+
>
|
|
254
|
+
<Text variant="label-lg" color="primary" style={{ textDecorationLine: 'underline' }}>
|
|
255
|
+
{children}
|
|
256
|
+
</Text>
|
|
257
|
+
</Pressable>
|
|
258
|
+
);
|
|
259
|
+
}
|