@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.
Files changed (124) hide show
  1. package/README.md +111 -2
  2. package/lib/module/components/actions.js +222 -0
  3. package/lib/module/components/actions.js.map +1 -0
  4. package/lib/module/components/containers.js +292 -0
  5. package/lib/module/components/containers.js.map +1 -0
  6. package/lib/module/components/display.js +266 -0
  7. package/lib/module/components/display.js.map +1 -0
  8. package/lib/module/components/feedback.js +464 -0
  9. package/lib/module/components/feedback.js.map +1 -0
  10. package/lib/module/components/inputs.js +746 -0
  11. package/lib/module/components/inputs.js.map +1 -0
  12. package/lib/module/components/mobile.js +811 -0
  13. package/lib/module/components/mobile.js.map +1 -0
  14. package/lib/module/components/overlays.js +418 -0
  15. package/lib/module/components/overlays.js.map +1 -0
  16. package/lib/module/components/shared.js +57 -0
  17. package/lib/module/components/shared.js.map +1 -0
  18. package/lib/module/hooks/useControllableState.js +23 -0
  19. package/lib/module/hooks/useControllableState.js.map +1 -0
  20. package/lib/module/index.js +30 -0
  21. package/lib/module/index.js.map +1 -0
  22. package/lib/module/package.json +1 -0
  23. package/lib/module/patterns/app.js +709 -0
  24. package/lib/module/patterns/app.js.map +1 -0
  25. package/lib/module/patterns/auth.js +224 -0
  26. package/lib/module/patterns/auth.js.map +1 -0
  27. package/lib/module/patterns/index.js +7 -0
  28. package/lib/module/patterns/index.js.map +1 -0
  29. package/lib/module/patterns/money.js +419 -0
  30. package/lib/module/patterns/money.js.map +1 -0
  31. package/lib/module/primitives/Icon.js +17 -0
  32. package/lib/module/primitives/Icon.js.map +1 -0
  33. package/lib/module/primitives/Layout.js +79 -0
  34. package/lib/module/primitives/Layout.js.map +1 -0
  35. package/lib/module/primitives/Pressable.js +77 -0
  36. package/lib/module/primitives/Pressable.js.map +1 -0
  37. package/lib/module/primitives/ScreenContainer.js +58 -0
  38. package/lib/module/primitives/ScreenContainer.js.map +1 -0
  39. package/lib/module/primitives/Surface.js +57 -0
  40. package/lib/module/primitives/Surface.js.map +1 -0
  41. package/lib/module/primitives/Text.js +70 -0
  42. package/lib/module/primitives/Text.js.map +1 -0
  43. package/lib/module/theme/ThemeProvider.js +127 -0
  44. package/lib/module/theme/ThemeProvider.js.map +1 -0
  45. package/lib/module/theme/fonts.js +56 -0
  46. package/lib/module/theme/fonts.js.map +1 -0
  47. package/lib/module/theme/haptics.js +56 -0
  48. package/lib/module/theme/haptics.js.map +1 -0
  49. package/lib/module/theme/navigation.js +99 -0
  50. package/lib/module/theme/navigation.js.map +1 -0
  51. package/lib/typescript/components/actions.d.ts +53 -0
  52. package/lib/typescript/components/actions.d.ts.map +1 -0
  53. package/lib/typescript/components/containers.d.ts +59 -0
  54. package/lib/typescript/components/containers.d.ts.map +1 -0
  55. package/lib/typescript/components/display.d.ts +62 -0
  56. package/lib/typescript/components/display.d.ts.map +1 -0
  57. package/lib/typescript/components/feedback.d.ts +93 -0
  58. package/lib/typescript/components/feedback.d.ts.map +1 -0
  59. package/lib/typescript/components/inputs.d.ts +141 -0
  60. package/lib/typescript/components/inputs.d.ts.map +1 -0
  61. package/lib/typescript/components/mobile.d.ts +173 -0
  62. package/lib/typescript/components/mobile.d.ts.map +1 -0
  63. package/lib/typescript/components/overlays.d.ts +74 -0
  64. package/lib/typescript/components/overlays.d.ts.map +1 -0
  65. package/lib/typescript/components/shared.d.ts +20 -0
  66. package/lib/typescript/components/shared.d.ts.map +1 -0
  67. package/lib/typescript/hooks/useControllableState.d.ts +6 -0
  68. package/lib/typescript/hooks/useControllableState.d.ts.map +1 -0
  69. package/lib/typescript/index.d.ts +37 -0
  70. package/lib/typescript/index.d.ts.map +1 -0
  71. package/lib/typescript/package.json +1 -0
  72. package/lib/typescript/patterns/app.d.ts +139 -0
  73. package/lib/typescript/patterns/app.d.ts.map +1 -0
  74. package/lib/typescript/patterns/auth.d.ts +54 -0
  75. package/lib/typescript/patterns/auth.d.ts.map +1 -0
  76. package/lib/typescript/patterns/index.d.ts +7 -0
  77. package/lib/typescript/patterns/index.d.ts.map +1 -0
  78. package/lib/typescript/patterns/money.d.ts +106 -0
  79. package/lib/typescript/patterns/money.d.ts.map +1 -0
  80. package/lib/typescript/primitives/Icon.d.ts +12 -0
  81. package/lib/typescript/primitives/Icon.d.ts.map +1 -0
  82. package/lib/typescript/primitives/Layout.d.ts +26 -0
  83. package/lib/typescript/primitives/Layout.d.ts.map +1 -0
  84. package/lib/typescript/primitives/Pressable.d.ts +21 -0
  85. package/lib/typescript/primitives/Pressable.d.ts.map +1 -0
  86. package/lib/typescript/primitives/ScreenContainer.d.ts +25 -0
  87. package/lib/typescript/primitives/ScreenContainer.d.ts.map +1 -0
  88. package/lib/typescript/primitives/Surface.d.ts +23 -0
  89. package/lib/typescript/primitives/Surface.d.ts.map +1 -0
  90. package/lib/typescript/primitives/Text.d.ts +21 -0
  91. package/lib/typescript/primitives/Text.d.ts.map +1 -0
  92. package/lib/typescript/theme/ThemeProvider.d.ts +69 -0
  93. package/lib/typescript/theme/ThemeProvider.d.ts.map +1 -0
  94. package/lib/typescript/theme/fonts.d.ts +25 -0
  95. package/lib/typescript/theme/fonts.d.ts.map +1 -0
  96. package/lib/typescript/theme/haptics.d.ts +3 -0
  97. package/lib/typescript/theme/haptics.d.ts.map +1 -0
  98. package/lib/typescript/theme/navigation.d.ts +158 -0
  99. package/lib/typescript/theme/navigation.d.ts.map +1 -0
  100. package/package.json +138 -3
  101. package/src/components/actions.tsx +259 -0
  102. package/src/components/containers.tsx +341 -0
  103. package/src/components/display.tsx +314 -0
  104. package/src/components/feedback.tsx +522 -0
  105. package/src/components/inputs.tsx +851 -0
  106. package/src/components/mobile.tsx +879 -0
  107. package/src/components/overlays.tsx +485 -0
  108. package/src/components/shared.ts +54 -0
  109. package/src/hooks/useControllableState.ts +27 -0
  110. package/src/index.ts +175 -0
  111. package/src/patterns/app.tsx +715 -0
  112. package/src/patterns/auth.tsx +266 -0
  113. package/src/patterns/index.ts +57 -0
  114. package/src/patterns/money.tsx +458 -0
  115. package/src/primitives/Icon.tsx +15 -0
  116. package/src/primitives/Layout.tsx +71 -0
  117. package/src/primitives/Pressable.tsx +94 -0
  118. package/src/primitives/ScreenContainer.tsx +65 -0
  119. package/src/primitives/Surface.tsx +75 -0
  120. package/src/primitives/Text.tsx +79 -0
  121. package/src/theme/ThemeProvider.tsx +210 -0
  122. package/src/theme/fonts.ts +52 -0
  123. package/src/theme/haptics.ts +57 -0
  124. package/src/theme/navigation.ts +68 -0
@@ -0,0 +1,266 @@
1
+ import * as React from 'react';
2
+ import { View } from 'react-native';
3
+ import { Lock, ShieldCheck } from '@nexub/icons/native';
4
+ import { Button } from '../components/actions';
5
+ import { PasswordInput, TextField } from '../components/inputs';
6
+ import { Banner } from '../components/feedback';
7
+ import { OTPInput, StickyFooter } from '../components/mobile';
8
+ import { ScreenContainer } from '../primitives/ScreenContainer';
9
+ import { Text, Heading } from '../primitives/Text';
10
+ import { useTheme } from '../theme/ThemeProvider';
11
+
12
+ export interface AuthScreenProps {
13
+ /** Brand mark above the title. */
14
+ logo?: React.ReactNode;
15
+ title: string;
16
+ description?: string;
17
+ children: React.ReactNode;
18
+ /** Primary action(s), kept above the keyboard. */
19
+ footer: React.ReactNode;
20
+ /** Error from the last attempt (announced). */
21
+ error?: string;
22
+ }
23
+
24
+ /** Frame for sign-in, sign-up and verification screens (web AuthCard, full screen). */
25
+ export function AuthScreen({ logo, title, description, children, footer, error }: AuthScreenProps) {
26
+ const { tokens } = useTheme();
27
+ return (
28
+ <StickyFooter footer={footer}>
29
+ <ScreenContainer
30
+ edges={['top', 'left', 'right']}
31
+ gap="6"
32
+ contentStyle={{ paddingTop: tokens.spacing[10] }}
33
+ >
34
+ <View style={{ gap: tokens.spacing[2] }}>
35
+ {logo}
36
+ <Heading variant="headline-md">{title}</Heading>
37
+ {description && (
38
+ <Text variant="body-md" color="on-surface-variant">
39
+ {description}
40
+ </Text>
41
+ )}
42
+ </View>
43
+ {error && <Banner tone="danger">{error}</Banner>}
44
+ <View style={{ gap: tokens.spacing[4] }}>{children}</View>
45
+ </ScreenContainer>
46
+ </StickyFooter>
47
+ );
48
+ }
49
+
50
+ export interface SignInScreenProps {
51
+ onSubmit: (email: string, password: string) => void;
52
+ /** Offer passkey/biometric sign-in (name the method: "Sign in with Face ID"). */
53
+ biometricLabel?: string;
54
+ onBiometric?: () => void;
55
+ onForgotPassword?: () => void;
56
+ onCreateAccount?: () => void;
57
+ loading?: boolean;
58
+ error?: string;
59
+ logo?: React.ReactNode;
60
+ /** Copy overrides. */
61
+ title?: string;
62
+ submitLabel?: string;
63
+ }
64
+
65
+ /** Email + password sign-in with platform autofill, plus an optional biometric/passkey path. */
66
+ export function SignInScreen({
67
+ onSubmit,
68
+ biometricLabel,
69
+ onBiometric,
70
+ onForgotPassword,
71
+ onCreateAccount,
72
+ loading,
73
+ error,
74
+ logo,
75
+ title = 'Sign in',
76
+ submitLabel = 'Sign in',
77
+ }: SignInScreenProps) {
78
+ const [email, setEmail] = React.useState('');
79
+ const [password, setPassword] = React.useState('');
80
+ return (
81
+ <AuthScreen
82
+ logo={logo}
83
+ title={title}
84
+ error={error}
85
+ footer={
86
+ <>
87
+ <Button
88
+ size="lg"
89
+ fullWidth
90
+ loading={loading}
91
+ disabled={!email || !password}
92
+ onPress={() => onSubmit(email, password)}
93
+ >
94
+ {submitLabel}
95
+ </Button>
96
+ {onBiometric && biometricLabel && (
97
+ <Button
98
+ size="lg"
99
+ fullWidth
100
+ variant="tonal"
101
+ leadingIcon={ShieldCheck}
102
+ onPress={onBiometric}
103
+ >
104
+ {biometricLabel}
105
+ </Button>
106
+ )}
107
+ {onCreateAccount && (
108
+ <Button size="lg" fullWidth variant="text" onPress={onCreateAccount}>
109
+ Create an account
110
+ </Button>
111
+ )}
112
+ </>
113
+ }
114
+ >
115
+ <TextField
116
+ label="Email"
117
+ value={email}
118
+ onChangeText={setEmail}
119
+ keyboardType="email-address"
120
+ autoCapitalize="none"
121
+ autoCorrect={false}
122
+ autoComplete="email"
123
+ textContentType="username"
124
+ returnKeyType="next"
125
+ />
126
+ <PasswordInput
127
+ label="Password"
128
+ value={password}
129
+ onChangeText={setPassword}
130
+ returnKeyType="go"
131
+ onSubmitEditing={() => email && password && onSubmit(email, password)}
132
+ />
133
+ {onForgotPassword && (
134
+ <Button
135
+ variant="text"
136
+ size="sm"
137
+ onPress={onForgotPassword}
138
+ style={{ alignSelf: 'flex-end' }}
139
+ >
140
+ Forgot password?
141
+ </Button>
142
+ )}
143
+ </AuthScreen>
144
+ );
145
+ }
146
+
147
+ export interface VerifyCodeScreenProps {
148
+ /** Where the code went, e.g. "+65 •••• 4821". */
149
+ destination: string;
150
+ onComplete: (code: string) => void;
151
+ onResend: () => void;
152
+ /** Seconds before Resend is allowed again. @default 30 */
153
+ resendAfter?: number;
154
+ length?: number;
155
+ error?: string;
156
+ }
157
+
158
+ /** One-time code entry (SMS autofill ready) with a resend countdown. */
159
+ export function VerifyCodeScreen({
160
+ destination,
161
+ onComplete,
162
+ onResend,
163
+ resendAfter = 30,
164
+ length = 6,
165
+ error,
166
+ }: VerifyCodeScreenProps) {
167
+ const [left, setLeft] = React.useState(resendAfter);
168
+ React.useEffect(() => {
169
+ if (left <= 0) return;
170
+ const t = setTimeout(() => setLeft(left - 1), 1000);
171
+ return () => clearTimeout(t);
172
+ }, [left]);
173
+ return (
174
+ <AuthScreen
175
+ title="Enter the code"
176
+ description={`We sent a ${length}-digit code to ${destination}.`}
177
+ footer={
178
+ <Button
179
+ size="lg"
180
+ fullWidth
181
+ variant="text"
182
+ disabled={left > 0}
183
+ onPress={() => {
184
+ setLeft(resendAfter);
185
+ onResend();
186
+ }}
187
+ >
188
+ {left > 0 ? `Resend code in ${left}s` : 'Resend code'}
189
+ </Button>
190
+ }
191
+ >
192
+ <OTPInput
193
+ label="Verification code"
194
+ length={length}
195
+ onComplete={onComplete}
196
+ error={error}
197
+ autoFocus
198
+ />
199
+ </AuthScreen>
200
+ );
201
+ }
202
+
203
+ export interface LockScreenProps {
204
+ /** "Unlock with Face ID" / "Unlock with fingerprint" (name the method). */
205
+ unlockLabel: string;
206
+ onUnlock: () => void;
207
+ /** Fallback to the app passcode or password. */
208
+ onUsePasscode?: () => void;
209
+ logo?: React.ReactNode;
210
+ appName?: string;
211
+ }
212
+
213
+ /** Biometric unlock on app open/resume, with a passcode fallback. */
214
+ export function LockScreen({
215
+ unlockLabel,
216
+ onUnlock,
217
+ onUsePasscode,
218
+ logo,
219
+ appName,
220
+ }: LockScreenProps) {
221
+ const { roles, tokens } = useTheme();
222
+ return (
223
+ <StickyFooter
224
+ footer={
225
+ <>
226
+ <Button size="lg" fullWidth leadingIcon={ShieldCheck} onPress={onUnlock}>
227
+ {unlockLabel}
228
+ </Button>
229
+ {onUsePasscode && (
230
+ <Button size="lg" fullWidth variant="text" onPress={onUsePasscode}>
231
+ Use passcode
232
+ </Button>
233
+ )}
234
+ </>
235
+ }
236
+ >
237
+ <View
238
+ style={{
239
+ flex: 1,
240
+ alignItems: 'center',
241
+ justifyContent: 'center',
242
+ gap: tokens.spacing[4],
243
+ padding: tokens.spacing[6],
244
+ }}
245
+ >
246
+ {logo ?? (
247
+ <View
248
+ style={{
249
+ width: 72,
250
+ height: 72,
251
+ borderRadius: 36,
252
+ alignItems: 'center',
253
+ justifyContent: 'center',
254
+ backgroundColor: roles['primary-container'],
255
+ }}
256
+ >
257
+ <Lock size="xl" color={roles['on-primary-container']} />
258
+ </View>
259
+ )}
260
+ <Heading variant="headline-sm" style={{ textAlign: 'center' }}>
261
+ {appName ? `${appName} is locked` : 'Locked'}
262
+ </Heading>
263
+ </View>
264
+ </StickyFooter>
265
+ );
266
+ }
@@ -0,0 +1,57 @@
1
+ // @nexub/react-native/patterns — screen templates built only from public components.
2
+ export { AuthScreen, SignInScreen, VerifyCodeScreen, LockScreen } from './auth';
3
+ export type {
4
+ AuthScreenProps,
5
+ SignInScreenProps,
6
+ VerifyCodeScreenProps,
7
+ LockScreenProps,
8
+ } from './auth';
9
+ export {
10
+ FlowStep,
11
+ AmountStep,
12
+ ReviewStep,
13
+ ActivityList,
14
+ TransactionDetail,
15
+ ResultScreen,
16
+ } from './money';
17
+ export type {
18
+ FlowStepProps,
19
+ Quote,
20
+ AmountStepProps,
21
+ ReviewRow,
22
+ ReviewStepProps,
23
+ Transaction,
24
+ ActivityListProps,
25
+ TransactionDetailProps,
26
+ ResultScreenProps,
27
+ } from './money';
28
+ export {
29
+ OnboardingScreen,
30
+ PermissionPrimer,
31
+ SettingsScreen,
32
+ AppearanceSection,
33
+ ProfileHeader,
34
+ NotificationsInbox,
35
+ SearchScreen,
36
+ ChatScreen,
37
+ PaywallScreen,
38
+ AppSwitcherSheet,
39
+ } from './app';
40
+ export type {
41
+ OnboardingSlide,
42
+ OnboardingScreenProps,
43
+ PermissionPrimerProps,
44
+ SettingsGroup,
45
+ SettingsScreenProps,
46
+ AppearanceSectionProps,
47
+ ProfileHeaderProps,
48
+ NotificationEntry,
49
+ NotificationsInboxProps,
50
+ SearchScreenProps,
51
+ ChatMessage,
52
+ ChatScreenProps,
53
+ Plan,
54
+ PaywallScreenProps,
55
+ NexubApp,
56
+ AppSwitcherSheetProps,
57
+ } from './app';