react-native-sooner 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 (80) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +376 -0
  3. package/lib/module/constants.js +40 -0
  4. package/lib/module/constants.js.map +1 -0
  5. package/lib/module/context.js +25 -0
  6. package/lib/module/context.js.map +1 -0
  7. package/lib/module/easings.js +9 -0
  8. package/lib/module/easings.js.map +1 -0
  9. package/lib/module/gestures.js +119 -0
  10. package/lib/module/gestures.js.map +1 -0
  11. package/lib/module/hooks.js +9 -0
  12. package/lib/module/hooks.js.map +1 -0
  13. package/lib/module/icons.js +332 -0
  14. package/lib/module/icons.js.map +1 -0
  15. package/lib/module/index.js +13 -0
  16. package/lib/module/index.js.map +1 -0
  17. package/lib/module/package.json +1 -0
  18. package/lib/module/state.js +200 -0
  19. package/lib/module/state.js.map +1 -0
  20. package/lib/module/theme.js +189 -0
  21. package/lib/module/theme.js.map +1 -0
  22. package/lib/module/toast.js +362 -0
  23. package/lib/module/toast.js.map +1 -0
  24. package/lib/module/toaster.js +198 -0
  25. package/lib/module/toaster.js.map +1 -0
  26. package/lib/module/types.js +4 -0
  27. package/lib/module/types.js.map +1 -0
  28. package/lib/module/use-app-state.js +13 -0
  29. package/lib/module/use-app-state.js.map +1 -0
  30. package/lib/module/use-pauseable-timer.js +18 -0
  31. package/lib/module/use-pauseable-timer.js.map +1 -0
  32. package/lib/module/use-toast-state.js +37 -0
  33. package/lib/module/use-toast-state.js.map +1 -0
  34. package/lib/typescript/package.json +1 -0
  35. package/lib/typescript/src/constants.d.ts +32 -0
  36. package/lib/typescript/src/constants.d.ts.map +1 -0
  37. package/lib/typescript/src/context.d.ts +20 -0
  38. package/lib/typescript/src/context.d.ts.map +1 -0
  39. package/lib/typescript/src/easings.d.ts +6 -0
  40. package/lib/typescript/src/easings.d.ts.map +1 -0
  41. package/lib/typescript/src/gestures.d.ts +17 -0
  42. package/lib/typescript/src/gestures.d.ts.map +1 -0
  43. package/lib/typescript/src/hooks.d.ts +5 -0
  44. package/lib/typescript/src/hooks.d.ts.map +1 -0
  45. package/lib/typescript/src/icons.d.ts +15 -0
  46. package/lib/typescript/src/icons.d.ts.map +1 -0
  47. package/lib/typescript/src/index.d.ts +12 -0
  48. package/lib/typescript/src/index.d.ts.map +1 -0
  49. package/lib/typescript/src/state.d.ts +66 -0
  50. package/lib/typescript/src/state.d.ts.map +1 -0
  51. package/lib/typescript/src/theme.d.ts +163 -0
  52. package/lib/typescript/src/theme.d.ts.map +1 -0
  53. package/lib/typescript/src/toast.d.ts +3 -0
  54. package/lib/typescript/src/toast.d.ts.map +1 -0
  55. package/lib/typescript/src/toaster.d.ts +3 -0
  56. package/lib/typescript/src/toaster.d.ts.map +1 -0
  57. package/lib/typescript/src/types.d.ts +264 -0
  58. package/lib/typescript/src/types.d.ts.map +1 -0
  59. package/lib/typescript/src/use-app-state.d.ts +3 -0
  60. package/lib/typescript/src/use-app-state.d.ts.map +1 -0
  61. package/lib/typescript/src/use-pauseable-timer.d.ts +2 -0
  62. package/lib/typescript/src/use-pauseable-timer.d.ts.map +1 -0
  63. package/lib/typescript/src/use-toast-state.d.ts +7 -0
  64. package/lib/typescript/src/use-toast-state.d.ts.map +1 -0
  65. package/package.json +152 -0
  66. package/src/constants.ts +44 -0
  67. package/src/context.tsx +38 -0
  68. package/src/easings.ts +7 -0
  69. package/src/gestures.tsx +135 -0
  70. package/src/hooks.ts +3 -0
  71. package/src/icons.tsx +227 -0
  72. package/src/index.tsx +48 -0
  73. package/src/state.ts +262 -0
  74. package/src/theme.ts +170 -0
  75. package/src/toast.tsx +429 -0
  76. package/src/toaster.tsx +221 -0
  77. package/src/types.ts +311 -0
  78. package/src/use-app-state.ts +15 -0
  79. package/src/use-pauseable-timer.ts +24 -0
  80. package/src/use-toast-state.ts +43 -0
package/src/types.ts ADDED
@@ -0,0 +1,311 @@
1
+ import type { ReactNode } from "react";
2
+ import type { AccessibilityRole, StyleProp, TextStyle, ViewStyle } from "react-native";
3
+
4
+ /**
5
+ * Toast variant types
6
+ */
7
+ export type ToastType =
8
+ | "default"
9
+ | "success"
10
+ | "error"
11
+ | "warning"
12
+ | "info"
13
+ | "loading";
14
+
15
+ /**
16
+ * Position of the toast on screen
17
+ */
18
+ export type Position =
19
+ | "top-left"
20
+ | "top-center"
21
+ | "top-right"
22
+ | "bottom-left"
23
+ | "bottom-center"
24
+ | "bottom-right";
25
+
26
+ /**
27
+ * Swipe direction to dismiss
28
+ */
29
+ export type SwipeDirection = "left" | "right" | "up" | "down";
30
+
31
+ /**
32
+ * Theme options
33
+ */
34
+ export type Theme = "light" | "dark" | "system";
35
+
36
+ /**
37
+ * Resolved theme (without system)
38
+ */
39
+ export type ResolvedTheme = "light" | "dark";
40
+
41
+ /**
42
+ * Action button configuration
43
+ */
44
+ export interface Action {
45
+ label: string;
46
+ onClick: (toast: ToastT) => void;
47
+ style?: StyleProp<ViewStyle>;
48
+ textStyle?: StyleProp<TextStyle>;
49
+ }
50
+
51
+ /**
52
+ * Promise data for toast.promise()
53
+ */
54
+ export interface PromiseData<T = unknown> {
55
+ loading: string | ReactNode;
56
+ success: string | ReactNode | ((data: T) => string | ReactNode);
57
+ error: string | ReactNode | ((error: unknown) => string | ReactNode);
58
+ finally?: () => void;
59
+ }
60
+
61
+ /**
62
+ * Custom icons for toast types
63
+ */
64
+ export interface ToastIcons {
65
+ success?: ReactNode;
66
+ error?: ReactNode;
67
+ warning?: ReactNode;
68
+ info?: ReactNode;
69
+ loading?: ReactNode;
70
+ }
71
+
72
+ /**
73
+ * Custom styles for toast parts
74
+ */
75
+ export interface ToastStyles {
76
+ container?: StyleProp<ViewStyle>;
77
+ content?: StyleProp<ViewStyle>;
78
+ title?: StyleProp<TextStyle>;
79
+ description?: StyleProp<TextStyle>;
80
+ actionButton?: StyleProp<ViewStyle>;
81
+ actionButtonText?: StyleProp<TextStyle>;
82
+ cancelButton?: StyleProp<ViewStyle>;
83
+ cancelButtonText?: StyleProp<TextStyle>;
84
+ closeButton?: StyleProp<ViewStyle>;
85
+ }
86
+
87
+ /**
88
+ * Animation configuration
89
+ */
90
+ export interface AnimationConfig {
91
+ /** Entry animation duration in ms @default 350 */
92
+ duration?: number;
93
+ /** Exit animation duration in ms @default 200 */
94
+ exitDuration?: number;
95
+ /** Use spring animation for entry @default true */
96
+ useSpring?: boolean;
97
+ /** Spring damping @default 18 */
98
+ damping?: number;
99
+ /** Spring stiffness @default 140 */
100
+ stiffness?: number;
101
+ /** Spring mass @default 1 */
102
+ mass?: number;
103
+ }
104
+
105
+ /**
106
+ * Accessibility configuration
107
+ */
108
+ export interface AccessibilityConfig {
109
+ /** Accessibility role @default "alert" */
110
+ role?: AccessibilityRole;
111
+ /** Whether to announce toast to screen readers @default true */
112
+ announceToScreenReader?: boolean;
113
+ /** Custom accessibility label */
114
+ accessibilityLabel?: string;
115
+ }
116
+
117
+ /**
118
+ * Internal toast data structure
119
+ */
120
+ export interface ToastT {
121
+ id: string | number;
122
+ type: ToastType;
123
+ title: string | ReactNode;
124
+ description?: string | ReactNode;
125
+ icon?: ReactNode;
126
+ duration?: number;
127
+ dismissible?: boolean;
128
+ action?: Action;
129
+ cancel?: Action;
130
+ onDismiss?: (toast: ToastT) => void;
131
+ onAutoClose?: (toast: ToastT) => void;
132
+ styles?: ToastStyles;
133
+ /** Mark toast as important (won't be auto-dismissed when queue is full) */
134
+ important?: boolean;
135
+ /** Toaster ID to target specific Toaster instance */
136
+ toasterId?: string;
137
+ /** Internal: timestamp when created */
138
+ createdAt: number;
139
+ /** Internal: whether this toast is being dismissed */
140
+ dismissed?: boolean;
141
+ /** Animation configuration for this toast */
142
+ animation?: AnimationConfig;
143
+ /** Accessibility configuration */
144
+ accessibility?: AccessibilityConfig;
145
+ }
146
+
147
+ /**
148
+ * Options for updating a toast
149
+ */
150
+ export type UpdateToastOptions = Partial<Omit<ToastT, "id" | "createdAt">>;
151
+
152
+ /**
153
+ * External toast options (what users pass to toast())
154
+ */
155
+ export type ExternalToast = Omit<ToastT, "id" | "type" | "title" | "createdAt"> & {
156
+ /** Optional custom ID for the toast */
157
+ id?: string | number;
158
+ };
159
+
160
+ /**
161
+ * Toast height tracking for stacking
162
+ */
163
+ export interface HeightT {
164
+ toastId: string | number;
165
+ height: number;
166
+ }
167
+
168
+ /**
169
+ * Toaster component props
170
+ */
171
+ export interface ToasterProps {
172
+ /**
173
+ * Position of toasts on screen
174
+ * @default "top-center"
175
+ */
176
+ position?: Position;
177
+
178
+ /**
179
+ * Theme for toasts
180
+ * @default "system"
181
+ */
182
+ theme?: Theme;
183
+
184
+ /**
185
+ * Maximum number of visible toasts (excess queued)
186
+ * @default 5
187
+ */
188
+ visibleToasts?: number;
189
+
190
+ /**
191
+ * Default duration in milliseconds
192
+ * @default 3000
193
+ */
194
+ duration?: number;
195
+
196
+ /**
197
+ * Gap between toasts in pixels
198
+ * @default 12
199
+ */
200
+ gap?: number;
201
+
202
+ /**
203
+ * Offset from screen edges
204
+ * @default { top: 52, bottom: 52, left: 16, right: 16 }
205
+ */
206
+ offset?: {
207
+ top?: number;
208
+ bottom?: number;
209
+ left?: number;
210
+ right?: number;
211
+ };
212
+
213
+ /**
214
+ * Enable swipe to dismiss
215
+ * @default true
216
+ */
217
+ swipeToDismiss?: boolean;
218
+
219
+ /**
220
+ * Swipe direction(s) to dismiss
221
+ * @default ["left", "right"]
222
+ */
223
+ swipeDirection?: SwipeDirection | SwipeDirection[];
224
+
225
+ /**
226
+ * Pause toast timer when app is in background
227
+ * @default true
228
+ */
229
+ pauseOnAppBackground?: boolean;
230
+
231
+ /**
232
+ * Custom icons for toast types
233
+ */
234
+ icons?: ToastIcons;
235
+
236
+ /**
237
+ * Default styles for all toasts
238
+ */
239
+ toastStyles?: ToastStyles;
240
+
241
+ /**
242
+ * Custom container style
243
+ */
244
+ containerStyle?: StyleProp<ViewStyle>;
245
+
246
+ /**
247
+ * Rich colors mode (more vibrant backgrounds)
248
+ * @default false
249
+ */
250
+ richColors?: boolean;
251
+
252
+ /**
253
+ * Close button on toasts
254
+ * @default false
255
+ */
256
+ closeButton?: boolean;
257
+
258
+ /**
259
+ * Only show toasts with matching toasterId
260
+ */
261
+ toasterId?: string;
262
+
263
+ /**
264
+ * Default animation configuration
265
+ */
266
+ animation?: AnimationConfig;
267
+
268
+ /**
269
+ * Enable haptic feedback on toast actions
270
+ * @default false
271
+ */
272
+ hapticFeedback?: boolean;
273
+ }
274
+
275
+ /**
276
+ * Individual toast component props (internal)
277
+ */
278
+ export interface ToastProps {
279
+ toast: ToastT;
280
+ position: Position;
281
+ gap: number;
282
+ swipeToDismiss: boolean;
283
+ swipeDirection: SwipeDirection[];
284
+ theme: ResolvedTheme;
285
+ richColors: boolean;
286
+ closeButton: boolean;
287
+ icons?: ToastIcons;
288
+ defaultStyles?: ToastStyles;
289
+ defaultAnimation?: AnimationConfig;
290
+ onDismiss: (toastId: string | number) => void;
291
+ /** Default duration for auto-dismiss */
292
+ duration: number;
293
+ /** Pause timer when app goes to background */
294
+ pauseOnAppBackground: boolean;
295
+ hapticFeedback?: boolean;
296
+ }
297
+
298
+ /**
299
+ * Toast state subscriber callback
300
+ */
301
+ export type ToastStateSubscriber = (toast: ToastT) => void;
302
+
303
+ /**
304
+ * Toast dismiss subscriber callback
305
+ */
306
+ export type ToastDismissSubscriber = (toastId: string | number | undefined) => void;
307
+
308
+ /**
309
+ * Toast update subscriber callback
310
+ */
311
+ export type ToastUpdateSubscriber = (toast: ToastT) => void;
@@ -0,0 +1,15 @@
1
+ import { useEffect, useState } from "react";
2
+ import { AppState, type AppStateStatus } from "react-native";
3
+
4
+ export function useAppState(): AppStateStatus {
5
+ const [appState, setAppState] = useState<AppStateStatus>(
6
+ AppState.currentState as AppStateStatus
7
+ );
8
+
9
+ useEffect(() => {
10
+ const subscription = AppState.addEventListener("change", setAppState);
11
+ return () => subscription.remove();
12
+ }, []);
13
+
14
+ return appState;
15
+ }
@@ -0,0 +1,24 @@
1
+ import { useEffect } from "react";
2
+ import { useAppState } from "./use-app-state";
3
+
4
+ export function usePauseableTimer(
5
+ callback: () => void,
6
+ duration: number,
7
+ enabled: boolean,
8
+ pauseOnBackground: boolean
9
+ ): void {
10
+ const appState = useAppState();
11
+
12
+ useEffect(() => {
13
+ if (!enabled || duration <= 0 || duration === Number.POSITIVE_INFINITY) {
14
+ return;
15
+ }
16
+
17
+ if (pauseOnBackground && appState !== "active") {
18
+ return;
19
+ }
20
+
21
+ const timer = setTimeout(callback, duration);
22
+ return () => clearTimeout(timer);
23
+ }, [callback, duration, enabled, pauseOnBackground, appState]);
24
+ }
@@ -0,0 +1,43 @@
1
+ import { useCallback, useEffect, useRef, useState } from "react";
2
+ import { ToastState } from "./state";
3
+ import type { ToastT } from "./types";
4
+
5
+ export function useToastState() {
6
+ const [toasts, setToasts] = useState<ToastT[]>(() => ToastState.getToasts());
7
+ const toastsRef = useRef(toasts);
8
+ toastsRef.current = toasts;
9
+
10
+ useEffect(() => {
11
+ const unsubscribeCreate = ToastState.subscribe(() => {
12
+ setToasts(ToastState.getToasts());
13
+ });
14
+
15
+ const unsubscribeDismiss = ToastState.subscribeToDismiss(() => {
16
+ setToasts(ToastState.getToasts());
17
+ });
18
+
19
+ const unsubscribeUpdate = ToastState.subscribeToUpdate(() => {
20
+ setToasts(ToastState.getToasts());
21
+ });
22
+
23
+ return () => {
24
+ unsubscribeCreate();
25
+ unsubscribeDismiss();
26
+ unsubscribeUpdate();
27
+ };
28
+ }, []);
29
+
30
+ const getToast = useCallback((id: string | number) => {
31
+ return toastsRef.current.find((t) => t.id === id);
32
+ }, []);
33
+
34
+ const isActive = useCallback((id: string | number) => {
35
+ return toastsRef.current.some((t) => t.id === id);
36
+ }, []);
37
+
38
+ return {
39
+ toasts,
40
+ getToast,
41
+ isActive,
42
+ };
43
+ }