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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Idriss Garfa
4
+ Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ of this software and associated documentation files (the "Software"), to deal
6
+ in the Software without restriction, including without limitation the rights
7
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the Software is
9
+ furnished to do so, subject to the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be included in all
12
+ copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,376 @@
1
+ # React Native Sooner
2
+
3
+ An opinionated toast component for React Native inspired by [Sonner](https://sonner.emilkowal.ski/).
4
+
5
+ ## Features
6
+
7
+ - **Minimalist design** - Clean, modern toast notifications
8
+ - **Smooth animations** - Spring and timing animations powered by Reanimated
9
+ - **Swipe to dismiss** - Native gesture support with elastic resistance
10
+ - **Dark mode** - Automatic theme detection
11
+ - **Cross-platform** - iOS, Android, and Expo
12
+ - **Simple API** - Just `toast("Hello!")` anywhere
13
+ - **Promise toasts** - Loading, success, and error states
14
+ - **Rich colors** - Optional vibrant backgrounds
15
+ - **Multi-toast support** - Queue management with visible limit
16
+ - **Haptic feedback** - Optional haptics for toast events
17
+ - **Accessibility** - Screen reader announcements and labels
18
+ - **Performant** - 60fps animations with worklet-based gestures
19
+ - **Highly customizable** - Styles, icons, and animations
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install react-native-sooner
25
+ ```
26
+
27
+ ### Peer Dependencies
28
+
29
+ ```bash
30
+ npm install react-native-reanimated react-native-gesture-handler react-native-safe-area-context
31
+
32
+ # Optional: for SVG icons
33
+ npm install react-native-svg
34
+
35
+ # Optional: for haptic feedback
36
+ npm install expo-haptics
37
+ ```
38
+
39
+ Make sure to follow the installation instructions for each peer dependency:
40
+ - [react-native-reanimated](https://docs.swmansion.com/react-native-reanimated/docs/fundamentals/getting-started/)
41
+ - [react-native-gesture-handler](https://docs.swmansion.com/react-native-gesture-handler/docs/fundamentals/installation/)
42
+ - [react-native-safe-area-context](https://github.com/th3rdwave/react-native-safe-area-context#installation)
43
+
44
+ ## Quick Start
45
+
46
+ ### 1. Add the Toaster component
47
+
48
+ ```tsx
49
+ import { Toaster } from 'react-native-sooner';
50
+ import { GestureHandlerRootView } from 'react-native-gesture-handler';
51
+ import { SafeAreaProvider } from 'react-native-safe-area-context';
52
+
53
+ export default function App() {
54
+ return (
55
+ <GestureHandlerRootView style={{ flex: 1 }}>
56
+ <SafeAreaProvider>
57
+ <YourApp />
58
+ <Toaster />
59
+ </SafeAreaProvider>
60
+ </GestureHandlerRootView>
61
+ );
62
+ }
63
+ ```
64
+
65
+ ### 2. Show toasts anywhere
66
+
67
+ ```tsx
68
+ import { toast } from 'react-native-sooner';
69
+
70
+ function MyComponent() {
71
+ return (
72
+ <Button
73
+ title="Show Toast"
74
+ onPress={() => toast('Hello World!')}
75
+ />
76
+ );
77
+ }
78
+ ```
79
+
80
+ ## API
81
+
82
+ ### Basic Usage
83
+
84
+ ```tsx
85
+ // Default toast
86
+ toast('Hello World!');
87
+
88
+ // With description
89
+ toast('Event created', {
90
+ description: 'Your event has been scheduled',
91
+ });
92
+ ```
93
+
94
+ ### Toast Variants
95
+
96
+ ```tsx
97
+ toast.success('Success!');
98
+ toast.error('Something went wrong');
99
+ toast.warning('Please check your input');
100
+ toast.info('New update available');
101
+ toast.loading('Uploading...');
102
+ ```
103
+
104
+ ### Promise Toast
105
+
106
+ ```tsx
107
+ toast.promise(
108
+ fetchData(),
109
+ {
110
+ loading: 'Loading data...',
111
+ success: (data) => `Loaded ${data.count} items`,
112
+ error: (err) => `Error: ${err.message}`,
113
+ }
114
+ );
115
+ ```
116
+
117
+ ### Update Toast
118
+
119
+ ```tsx
120
+ const toastId = toast.loading('Uploading...');
121
+
122
+ // Update the toast later
123
+ toast.update(toastId, {
124
+ type: 'success',
125
+ title: 'Upload complete!',
126
+ });
127
+ ```
128
+
129
+ ### With Actions
130
+
131
+ ```tsx
132
+ toast('File deleted', {
133
+ action: {
134
+ label: 'Undo',
135
+ onClick: () => restoreFile(),
136
+ },
137
+ cancel: {
138
+ label: 'Dismiss',
139
+ onClick: () => {},
140
+ },
141
+ });
142
+ ```
143
+
144
+ ### Custom Duration
145
+
146
+ ```tsx
147
+ // 10 seconds
148
+ toast('Long toast', { duration: 10000 });
149
+
150
+ // Never auto-dismiss
151
+ toast('Sticky toast', { duration: Infinity });
152
+ ```
153
+
154
+ ### Important Toasts
155
+
156
+ Important toasts won't be hidden when the visible toast limit is reached:
157
+
158
+ ```tsx
159
+ toast.error('Critical error!', { important: true });
160
+ ```
161
+
162
+ ### Dismiss Programmatically
163
+
164
+ ```tsx
165
+ const toastId = toast('Loading...');
166
+
167
+ // Dismiss specific toast
168
+ toast.dismiss(toastId);
169
+
170
+ // Dismiss all toasts
171
+ toast.dismiss();
172
+ ```
173
+
174
+ ### Callbacks
175
+
176
+ ```tsx
177
+ toast('Hello', {
178
+ onDismiss: (t) => console.log('Toast dismissed:', t.id),
179
+ onAutoClose: (t) => console.log('Toast auto-closed:', t.id),
180
+ });
181
+ ```
182
+
183
+ ## Toaster Props
184
+
185
+ | Prop | Type | Default | Description |
186
+ |------|------|---------|-------------|
187
+ | `position` | `Position` | `"top-center"` | Toast position on screen |
188
+ | `theme` | `"light" \| "dark" \| "system"` | `"system"` | Color theme |
189
+ | `duration` | `number` | `4000` | Default duration in ms |
190
+ | `visibleToasts` | `number` | `3` | Max visible toasts |
191
+ | `gap` | `number` | `12` | Gap between toasts |
192
+ | `offset` | `object` | `{ top: 52, bottom: 52, left: 16, right: 16 }` | Screen edge offsets |
193
+ | `swipeToDismiss` | `boolean` | `true` | Enable swipe gestures |
194
+ | `swipeDirection` | `SwipeDirection \| SwipeDirection[]` | `["left", "right"]` | Swipe directions |
195
+ | `pauseOnAppBackground` | `boolean` | `true` | Pause timer when app backgrounds |
196
+ | `richColors` | `boolean` | `false` | Vibrant backgrounds |
197
+ | `closeButton` | `boolean` | `false` | Show close button |
198
+ | `hapticFeedback` | `boolean` | `false` | Enable haptic feedback |
199
+ | `icons` | `ToastIcons` | - | Custom icons |
200
+ | `toastStyles` | `ToastStyles` | - | Default styles for toasts |
201
+ | `containerStyle` | `ViewStyle` | - | Container style |
202
+ | `animation` | `AnimationConfig` | - | Animation configuration |
203
+ | `toasterId` | `string` | - | ID for multiple Toaster instances |
204
+
205
+ ### Position Options
206
+
207
+ - `"top-left"` / `"top-center"` / `"top-right"`
208
+ - `"bottom-left"` / `"bottom-center"` / `"bottom-right"`
209
+
210
+ ### Animation Configuration
211
+
212
+ ```tsx
213
+ <Toaster
214
+ animation={{
215
+ duration: 350, // Entry animation duration (ms)
216
+ exitDuration: 200, // Exit animation duration (ms)
217
+ useSpring: true, // Use spring animation for entry
218
+ damping: 18, // Spring damping
219
+ stiffness: 140, // Spring stiffness
220
+ mass: 1, // Spring mass
221
+ }}
222
+ />
223
+ ```
224
+
225
+ Per-toast animation:
226
+
227
+ ```tsx
228
+ toast('Custom animation', {
229
+ animation: {
230
+ duration: 500,
231
+ useSpring: false,
232
+ },
233
+ });
234
+ ```
235
+
236
+ ## Haptic Feedback
237
+
238
+ Enable haptic feedback for toast events (requires `expo-haptics`):
239
+
240
+ ```tsx
241
+ <Toaster hapticFeedback />
242
+ ```
243
+
244
+ Haptics are triggered on:
245
+ - Toast appearance (light impact, or notification type for success/warning/error)
246
+ - Action button press (medium impact)
247
+ - Cancel button press (light impact)
248
+
249
+ ## Accessibility
250
+
251
+ Toasts automatically announce to screen readers. Customize accessibility:
252
+
253
+ ```tsx
254
+ toast('Order placed', {
255
+ accessibility: {
256
+ announceToScreenReader: true, // default: true
257
+ accessibilityLabel: 'Your order has been successfully placed',
258
+ },
259
+ });
260
+ ```
261
+
262
+ ## Styling
263
+
264
+ ### Custom Toast Styles
265
+
266
+ ```tsx
267
+ toast('Styled toast', {
268
+ styles: {
269
+ container: { backgroundColor: '#1a1a1a' },
270
+ title: { color: '#fff', fontWeight: 'bold' },
271
+ description: { color: '#888' },
272
+ },
273
+ });
274
+ ```
275
+
276
+ ### Global Styles via Toaster
277
+
278
+ ```tsx
279
+ <Toaster
280
+ toastStyles={{
281
+ container: { borderRadius: 20 },
282
+ title: { fontFamily: 'Inter-Medium' },
283
+ }}
284
+ />
285
+ ```
286
+
287
+ ### Available Style Keys
288
+
289
+ - `container` - Toast container
290
+ - `content` - Content wrapper
291
+ - `title` - Title text
292
+ - `description` - Description text
293
+ - `actionButton` - Action button
294
+ - `actionButtonText` - Action button text
295
+ - `cancelButton` - Cancel button
296
+ - `cancelButtonText` - Cancel button text
297
+ - `closeButton` - Close button
298
+
299
+ ### Custom Icons
300
+
301
+ ```tsx
302
+ <Toaster
303
+ icons={{
304
+ success: <MySuccessIcon />,
305
+ error: <MyErrorIcon />,
306
+ warning: <MyWarningIcon />,
307
+ info: <MyInfoIcon />,
308
+ loading: <MySpinner />,
309
+ }}
310
+ />
311
+ ```
312
+
313
+ Per-toast icon:
314
+
315
+ ```tsx
316
+ toast('Custom icon', {
317
+ icon: <MyIcon />,
318
+ });
319
+ ```
320
+
321
+ ## Multiple Toaster Instances
322
+
323
+ Use `toasterId` to target specific Toaster instances:
324
+
325
+ ```tsx
326
+ // In your layout
327
+ <Toaster toasterId="main" position="top-center" />
328
+ <Toaster toasterId="bottom" position="bottom-center" />
329
+
330
+ // Show toast in specific toaster
331
+ toast('Top notification', { toasterId: 'main' });
332
+ toast('Bottom notification', { toasterId: 'bottom' });
333
+ ```
334
+
335
+ ## Hooks
336
+
337
+ ### useSooner / useToastState
338
+
339
+ Access toast state in components:
340
+
341
+ ```tsx
342
+ import { useSooner } from 'react-native-sooner';
343
+
344
+ function ToastCounter() {
345
+ const { toasts } = useSooner();
346
+ return <Text>Active toasts: {toasts.length}</Text>;
347
+ }
348
+ ```
349
+
350
+ ## Expo Support
351
+
352
+ React Native Sooner works with Expo out of the box:
353
+
354
+ ```bash
355
+ npx expo install react-native-reanimated react-native-gesture-handler react-native-safe-area-context react-native-svg expo-haptics
356
+ ```
357
+
358
+ ## TypeScript
359
+
360
+ Full TypeScript support with exported types:
361
+
362
+ ```tsx
363
+ import type {
364
+ ToastT,
365
+ ToastType,
366
+ Position,
367
+ ToasterProps,
368
+ AnimationConfig,
369
+ ToastStyles,
370
+ ToastIcons,
371
+ } from 'react-native-sooner';
372
+ ```
373
+
374
+ ## License
375
+
376
+ MIT
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+
3
+ export const ANIMATION_DEFAULTS = {
4
+ duration: 350,
5
+ exitDuration: 200,
6
+ useSpring: true,
7
+ damping: 18,
8
+ stiffness: 140,
9
+ mass: 1
10
+ };
11
+ export const ENTRY_OFFSET = 40;
12
+ export const SWIPE_THRESHOLD = 60;
13
+ export const VELOCITY_THRESHOLD = 500;
14
+ export const DAMPING_FACTOR = 0.5;
15
+ export const SWIPE_EXIT_DISTANCE = 300;
16
+ export const SNAP_BACK_DURATION = 150;
17
+ export const DEFAULT_ICON_SIZE = 20;
18
+ export const DISMISSED_CACHE_MAX_SIZE = 100;
19
+ export const DISMISSED_CACHE_CLEANUP_THRESHOLD = 50;
20
+ export const toastDefaults = {
21
+ duration: 4000,
22
+ position: "top-center",
23
+ gap: 12,
24
+ offset: {
25
+ top: 52,
26
+ bottom: 52,
27
+ left: 16,
28
+ right: 16
29
+ },
30
+ swipeToDismiss: true,
31
+ swipeDirection: ["left", "right"],
32
+ theme: "system",
33
+ richColors: false,
34
+ closeButton: false,
35
+ dismissible: true,
36
+ pauseOnAppBackground: true,
37
+ visibleToasts: 3,
38
+ hapticFeedback: false
39
+ };
40
+ //# sourceMappingURL=constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["ANIMATION_DEFAULTS","duration","exitDuration","useSpring","damping","stiffness","mass","ENTRY_OFFSET","SWIPE_THRESHOLD","VELOCITY_THRESHOLD","DAMPING_FACTOR","SWIPE_EXIT_DISTANCE","SNAP_BACK_DURATION","DEFAULT_ICON_SIZE","DISMISSED_CACHE_MAX_SIZE","DISMISSED_CACHE_CLEANUP_THRESHOLD","toastDefaults","position","gap","offset","top","bottom","left","right","swipeToDismiss","swipeDirection","theme","richColors","closeButton","dismissible","pauseOnAppBackground","visibleToasts","hapticFeedback"],"sourceRoot":"..\\..\\src","sources":["constants.ts"],"mappings":";;AAEA,OAAO,MAAMA,kBAA6C,GAAG;EAC3DC,QAAQ,EAAE,GAAG;EACbC,YAAY,EAAE,GAAG;EACjBC,SAAS,EAAE,IAAI;EACfC,OAAO,EAAE,EAAE;EACXC,SAAS,EAAE,GAAG;EACdC,IAAI,EAAE;AACR,CAAU;AAEV,OAAO,MAAMC,YAAY,GAAG,EAAE;AAE9B,OAAO,MAAMC,eAAe,GAAG,EAAE;AACjC,OAAO,MAAMC,kBAAkB,GAAG,GAAG;AACrC,OAAO,MAAMC,cAAc,GAAG,GAAG;AACjC,OAAO,MAAMC,mBAAmB,GAAG,GAAG;AACtC,OAAO,MAAMC,kBAAkB,GAAG,GAAG;AAErC,OAAO,MAAMC,iBAAiB,GAAG,EAAE;AAEnC,OAAO,MAAMC,wBAAwB,GAAG,GAAG;AAC3C,OAAO,MAAMC,iCAAiC,GAAG,EAAE;AAEnD,OAAO,MAAMC,aAAa,GAAG;EAC3Bf,QAAQ,EAAE,IAAI;EACdgB,QAAQ,EAAE,YAAwB;EAClCC,GAAG,EAAE,EAAE;EACPC,MAAM,EAAE;IACNC,GAAG,EAAE,EAAE;IACPC,MAAM,EAAE,EAAE;IACVC,IAAI,EAAE,EAAE;IACRC,KAAK,EAAE;EACT,CAAC;EACDC,cAAc,EAAE,IAAI;EACpBC,cAAc,EAAE,CAAC,MAAM,EAAE,OAAO,CAAqB;EACrDC,KAAK,EAAE,QAAiB;EACxBC,UAAU,EAAE,KAAK;EACjBC,WAAW,EAAE,KAAK;EAClBC,WAAW,EAAE,IAAI;EACjBC,oBAAoB,EAAE,IAAI;EAC1BC,aAAa,EAAE,CAAC;EAChBC,cAAc,EAAE;AAClB,CAAU","ignoreList":[]}
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ import React, { createContext, useContext } from "react";
4
+ import { jsx as _jsx } from "react/jsx-runtime";
5
+ const ToasterContext = /*#__PURE__*/createContext(null);
6
+ export function ToasterProvider({
7
+ children,
8
+ value
9
+ }) {
10
+ return /*#__PURE__*/_jsx(ToasterContext.Provider, {
11
+ value: value,
12
+ children: children
13
+ });
14
+ }
15
+ export function useToasterContext() {
16
+ const context = useContext(ToasterContext);
17
+ if (!context) {
18
+ throw new Error("useToasterContext must be used within a ToasterProvider");
19
+ }
20
+ return context;
21
+ }
22
+ export function useToasterContextOptional() {
23
+ return useContext(ToasterContext);
24
+ }
25
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["React","createContext","useContext","jsx","_jsx","ToasterContext","ToasterProvider","children","value","Provider","useToasterContext","context","Error","useToasterContextOptional"],"sourceRoot":"..\\..\\src","sources":["context.tsx"],"mappings":";;AAAA,OAAOA,KAAK,IAAIC,aAAa,EAAEC,UAAU,QAAQ,OAAO;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAezD,MAAMC,cAAc,gBAAGJ,aAAa,CAA6B,IAAI,CAAC;AAEtE,OAAO,SAASK,eAAeA,CAAC;EAC9BC,QAAQ;EACRC;AAIF,CAAC,EAAE;EACD,oBAAOJ,IAAA,CAACC,cAAc,CAACI,QAAQ;IAACD,KAAK,EAAEA,KAAM;IAAAD,QAAA,EAAEA;EAAQ,CAA0B,CAAC;AACpF;AAEA,OAAO,SAASG,iBAAiBA,CAAA,EAAwB;EACvD,MAAMC,OAAO,GAAGT,UAAU,CAACG,cAAc,CAAC;EAC1C,IAAI,CAACM,OAAO,EAAE;IACZ,MAAM,IAAIC,KAAK,CAAC,yDAAyD,CAAC;EAC5E;EACA,OAAOD,OAAO;AAChB;AAEA,OAAO,SAASE,yBAAyBA,CAAA,EAA+B;EACtE,OAAOX,UAAU,CAACG,cAAc,CAAC;AACnC","ignoreList":[]}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+
3
+ import { Easing } from "react-native-reanimated";
4
+ export const easeOutQuad = Easing.bezier(0.25, 0.46, 0.45, 0.94);
5
+ export const easeOutCubic = Easing.bezier(0.215, 0.61, 0.355, 1);
6
+ export const easeInOutCubic = Easing.bezier(0.645, 0.045, 0.355, 1);
7
+ export const easeOutCirc = Easing.bezier(0.075, 0.82, 0.165, 1);
8
+ export const easeOutExpo = Easing.bezier(0.19, 1, 0.22, 1);
9
+ //# sourceMappingURL=easings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Easing","easeOutQuad","bezier","easeOutCubic","easeInOutCubic","easeOutCirc","easeOutExpo"],"sourceRoot":"..\\..\\src","sources":["easings.ts"],"mappings":";;AAAA,SAASA,MAAM,QAAQ,yBAAyB;AAEhD,OAAO,MAAMC,WAAW,GAAGD,MAAM,CAACE,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC;AAChE,OAAO,MAAMC,YAAY,GAAGH,MAAM,CAACE,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAChE,OAAO,MAAME,cAAc,GAAGJ,MAAM,CAACE,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;AACnE,OAAO,MAAMG,WAAW,GAAGL,MAAM,CAACE,MAAM,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;AAC/D,OAAO,MAAMI,WAAW,GAAGN,MAAM,CAACE,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC","ignoreList":[]}
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+
3
+ import { Gesture, GestureDetector } from "react-native-gesture-handler";
4
+ import Animated, { runOnJS, useAnimatedStyle, useSharedValue, withTiming } from "react-native-reanimated";
5
+ import { DAMPING_FACTOR, SWIPE_THRESHOLD, VELOCITY_THRESHOLD } from "./constants.js";
6
+ import { jsx as _jsx } from "react/jsx-runtime";
7
+ export function SwipeHandler({
8
+ children,
9
+ enabled,
10
+ swipeDirection,
11
+ onDismiss,
12
+ style
13
+ }) {
14
+ const translateX = useSharedValue(0);
15
+ const opacity = useSharedValue(1);
16
+ const isDragging = useSharedValue(false);
17
+ const canSwipeLeft = swipeDirection.includes("left");
18
+ const canSwipeRight = swipeDirection.includes("right");
19
+ const panGesture = Gesture.Pan().enabled(enabled).onStart(() => {
20
+ "worklet";
21
+
22
+ isDragging.value = true;
23
+ }).onUpdate(event => {
24
+ "worklet";
25
+
26
+ const {
27
+ translationX
28
+ } = event;
29
+ if (canSwipeLeft && translationX < 0) {
30
+ translateX.value = translationX;
31
+ } else if (canSwipeRight && translationX > 0) {
32
+ translateX.value = translationX;
33
+ }
34
+ if (Math.abs(translateX.value) > SWIPE_THRESHOLD) {
35
+ const excess = Math.abs(translateX.value) - SWIPE_THRESHOLD;
36
+ const direction = translateX.value > 0 ? 1 : -1;
37
+ translateX.value = direction * (SWIPE_THRESHOLD + excess * DAMPING_FACTOR);
38
+ }
39
+ }).onEnd(event => {
40
+ "worklet";
41
+
42
+ isDragging.value = false;
43
+ const shouldDismiss = Math.abs(event.translationX) > SWIPE_THRESHOLD || Math.abs(event.velocityX) > VELOCITY_THRESHOLD;
44
+ if (shouldDismiss) {
45
+ const direction = event.translationX > 0 ? 1 : -1;
46
+ translateX.value = withTiming(direction * 300, {
47
+ duration: 200
48
+ });
49
+ opacity.value = withTiming(0, {
50
+ duration: 200
51
+ });
52
+ runOnJS(onDismiss)();
53
+ } else {
54
+ translateX.value = withTiming(0, {
55
+ duration: 150
56
+ });
57
+ }
58
+ });
59
+ const animatedStyle = useAnimatedStyle(() => ({
60
+ transform: [{
61
+ translateX: translateX.value
62
+ }],
63
+ opacity: opacity.value
64
+ }));
65
+ return /*#__PURE__*/_jsx(GestureDetector, {
66
+ gesture: panGesture,
67
+ children: /*#__PURE__*/_jsx(Animated.View, {
68
+ style: style ? [style, animatedStyle] : animatedStyle,
69
+ children: children
70
+ })
71
+ });
72
+ }
73
+ export function useSwipeGesture(enabled, swipeDirection, onDismiss) {
74
+ const translateX = useSharedValue(0);
75
+ const opacity = useSharedValue(1);
76
+ const canSwipeLeft = swipeDirection.includes("left");
77
+ const canSwipeRight = swipeDirection.includes("right");
78
+ const gesture = Gesture.Pan().enabled(enabled).onUpdate(event => {
79
+ "worklet";
80
+
81
+ const {
82
+ translationX
83
+ } = event;
84
+ if (canSwipeLeft && translationX < 0) {
85
+ translateX.value = translationX;
86
+ } else if (canSwipeRight && translationX > 0) {
87
+ translateX.value = translationX;
88
+ }
89
+ if (Math.abs(translateX.value) > SWIPE_THRESHOLD) {
90
+ const excess = Math.abs(translateX.value) - SWIPE_THRESHOLD;
91
+ const direction = translateX.value > 0 ? 1 : -1;
92
+ translateX.value = direction * (SWIPE_THRESHOLD + excess * DAMPING_FACTOR);
93
+ }
94
+ }).onEnd(event => {
95
+ "worklet";
96
+
97
+ const shouldDismiss = Math.abs(event.translationX) > SWIPE_THRESHOLD || Math.abs(event.velocityX) > VELOCITY_THRESHOLD;
98
+ if (shouldDismiss) {
99
+ const direction = event.translationX > 0 ? 1 : -1;
100
+ translateX.value = withTiming(direction * 300, {
101
+ duration: 200
102
+ });
103
+ opacity.value = withTiming(0, {
104
+ duration: 200
105
+ });
106
+ runOnJS(onDismiss)();
107
+ } else {
108
+ translateX.value = withTiming(0, {
109
+ duration: 150
110
+ });
111
+ }
112
+ });
113
+ return {
114
+ gesture,
115
+ translateX,
116
+ opacity
117
+ };
118
+ }
119
+ //# sourceMappingURL=gestures.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["Gesture","GestureDetector","Animated","runOnJS","useAnimatedStyle","useSharedValue","withTiming","DAMPING_FACTOR","SWIPE_THRESHOLD","VELOCITY_THRESHOLD","jsx","_jsx","SwipeHandler","children","enabled","swipeDirection","onDismiss","style","translateX","opacity","isDragging","canSwipeLeft","includes","canSwipeRight","panGesture","Pan","onStart","value","onUpdate","event","translationX","Math","abs","excess","direction","onEnd","shouldDismiss","velocityX","duration","animatedStyle","transform","gesture","View","useSwipeGesture"],"sourceRoot":"..\\..\\src","sources":["gestures.tsx"],"mappings":";;AAEA,SAASA,OAAO,EAAEC,eAAe,QAAQ,8BAA8B;AACvE,OAAOC,QAAQ,IACbC,OAAO,EACPC,gBAAgB,EAChBC,cAAc,EACdC,UAAU,QACL,yBAAyB;AAChC,SAASC,cAAc,EAAEC,eAAe,EAAEC,kBAAkB,QAAQ,gBAAa;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAWlF,OAAO,SAASC,YAAYA,CAAC;EAC3BC,QAAQ;EACRC,OAAO;EACPC,cAAc;EACdC,SAAS;EACTC;AACiB,CAAC,EAAE;EACpB,MAAMC,UAAU,GAAGb,cAAc,CAAC,CAAC,CAAC;EACpC,MAAMc,OAAO,GAAGd,cAAc,CAAC,CAAC,CAAC;EACjC,MAAMe,UAAU,GAAGf,cAAc,CAAC,KAAK,CAAC;EAExC,MAAMgB,YAAY,GAAGN,cAAc,CAACO,QAAQ,CAAC,MAAM,CAAC;EACpD,MAAMC,aAAa,GAAGR,cAAc,CAACO,QAAQ,CAAC,OAAO,CAAC;EAEtD,MAAME,UAAU,GAAGxB,OAAO,CAACyB,GAAG,CAAC,CAAC,CAC7BX,OAAO,CAACA,OAAO,CAAC,CAChBY,OAAO,CAAC,MAAM;IACb,SAAS;;IACTN,UAAU,CAACO,KAAK,GAAG,IAAI;EACzB,CAAC,CAAC,CACDC,QAAQ,CAAEC,KAAK,IAAK;IACnB,SAAS;;IACT,MAAM;MAAEC;IAAa,CAAC,GAAGD,KAAK;IAE9B,IAAIR,YAAY,IAAIS,YAAY,GAAG,CAAC,EAAE;MACpCZ,UAAU,CAACS,KAAK,GAAGG,YAAY;IACjC,CAAC,MAAM,IAAIP,aAAa,IAAIO,YAAY,GAAG,CAAC,EAAE;MAC5CZ,UAAU,CAACS,KAAK,GAAGG,YAAY;IACjC;IAEA,IAAIC,IAAI,CAACC,GAAG,CAACd,UAAU,CAACS,KAAK,CAAC,GAAGnB,eAAe,EAAE;MAChD,MAAMyB,MAAM,GAAGF,IAAI,CAACC,GAAG,CAACd,UAAU,CAACS,KAAK,CAAC,GAAGnB,eAAe;MAC3D,MAAM0B,SAAS,GAAGhB,UAAU,CAACS,KAAK,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;MAC/CT,UAAU,CAACS,KAAK,GAAGO,SAAS,IAAI1B,eAAe,GAAGyB,MAAM,GAAG1B,cAAc,CAAC;IAC5E;EACF,CAAC,CAAC,CACD4B,KAAK,CAAEN,KAAK,IAAK;IAChB,SAAS;;IACTT,UAAU,CAACO,KAAK,GAAG,KAAK;IAExB,MAAMS,aAAa,GACjBL,IAAI,CAACC,GAAG,CAACH,KAAK,CAACC,YAAY,CAAC,GAAGtB,eAAe,IAC9CuB,IAAI,CAACC,GAAG,CAACH,KAAK,CAACQ,SAAS,CAAC,GAAG5B,kBAAkB;IAEhD,IAAI2B,aAAa,EAAE;MACjB,MAAMF,SAAS,GAAGL,KAAK,CAACC,YAAY,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;MACjDZ,UAAU,CAACS,KAAK,GAAGrB,UAAU,CAAC4B,SAAS,GAAG,GAAG,EAAE;QAAEI,QAAQ,EAAE;MAAI,CAAC,CAAC;MACjEnB,OAAO,CAACQ,KAAK,GAAGrB,UAAU,CAAC,CAAC,EAAE;QAAEgC,QAAQ,EAAE;MAAI,CAAC,CAAC;MAChDnC,OAAO,CAACa,SAAS,CAAC,CAAC,CAAC;IACtB,CAAC,MAAM;MACLE,UAAU,CAACS,KAAK,GAAGrB,UAAU,CAAC,CAAC,EAAE;QAAEgC,QAAQ,EAAE;MAAI,CAAC,CAAC;IACrD;EACF,CAAC,CAAC;EAEJ,MAAMC,aAAa,GAAGnC,gBAAgB,CAAC,OAAO;IAC5CoC,SAAS,EAAE,CAAC;MAAEtB,UAAU,EAAEA,UAAU,CAACS;IAAM,CAAC,CAAC;IAC7CR,OAAO,EAAEA,OAAO,CAACQ;EACnB,CAAC,CAAC,CAAC;EAEH,oBACEhB,IAAA,CAACV,eAAe;IAACwC,OAAO,EAAEjB,UAAW;IAAAX,QAAA,eACnCF,IAAA,CAACT,QAAQ,CAACwC,IAAI;MAACzB,KAAK,EAAEA,KAAK,GAAG,CAACA,KAAK,EAAEsB,aAAa,CAAC,GAAGA,aAAc;MAAA1B,QAAA,EAClEA;IAAQ,CACI;EAAC,CACD,CAAC;AAEtB;AAEA,OAAO,SAAS8B,eAAeA,CAC7B7B,OAAgB,EAChBC,cAAgC,EAChCC,SAAqB,EACrB;EACA,MAAME,UAAU,GAAGb,cAAc,CAAC,CAAC,CAAC;EACpC,MAAMc,OAAO,GAAGd,cAAc,CAAC,CAAC,CAAC;EAEjC,MAAMgB,YAAY,GAAGN,cAAc,CAACO,QAAQ,CAAC,MAAM,CAAC;EACpD,MAAMC,aAAa,GAAGR,cAAc,CAACO,QAAQ,CAAC,OAAO,CAAC;EAEtD,MAAMmB,OAAO,GAAGzC,OAAO,CAACyB,GAAG,CAAC,CAAC,CAC1BX,OAAO,CAACA,OAAO,CAAC,CAChBc,QAAQ,CAAEC,KAAK,IAAK;IACnB,SAAS;;IACT,MAAM;MAAEC;IAAa,CAAC,GAAGD,KAAK;IAE9B,IAAIR,YAAY,IAAIS,YAAY,GAAG,CAAC,EAAE;MACpCZ,UAAU,CAACS,KAAK,GAAGG,YAAY;IACjC,CAAC,MAAM,IAAIP,aAAa,IAAIO,YAAY,GAAG,CAAC,EAAE;MAC5CZ,UAAU,CAACS,KAAK,GAAGG,YAAY;IACjC;IAEA,IAAIC,IAAI,CAACC,GAAG,CAACd,UAAU,CAACS,KAAK,CAAC,GAAGnB,eAAe,EAAE;MAChD,MAAMyB,MAAM,GAAGF,IAAI,CAACC,GAAG,CAACd,UAAU,CAACS,KAAK,CAAC,GAAGnB,eAAe;MAC3D,MAAM0B,SAAS,GAAGhB,UAAU,CAACS,KAAK,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;MAC/CT,UAAU,CAACS,KAAK,GAAGO,SAAS,IAAI1B,eAAe,GAAGyB,MAAM,GAAG1B,cAAc,CAAC;IAC5E;EACF,CAAC,CAAC,CACD4B,KAAK,CAAEN,KAAK,IAAK;IAChB,SAAS;;IACT,MAAMO,aAAa,GACjBL,IAAI,CAACC,GAAG,CAACH,KAAK,CAACC,YAAY,CAAC,GAAGtB,eAAe,IAC9CuB,IAAI,CAACC,GAAG,CAACH,KAAK,CAACQ,SAAS,CAAC,GAAG5B,kBAAkB;IAEhD,IAAI2B,aAAa,EAAE;MACjB,MAAMF,SAAS,GAAGL,KAAK,CAACC,YAAY,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;MACjDZ,UAAU,CAACS,KAAK,GAAGrB,UAAU,CAAC4B,SAAS,GAAG,GAAG,EAAE;QAAEI,QAAQ,EAAE;MAAI,CAAC,CAAC;MACjEnB,OAAO,CAACQ,KAAK,GAAGrB,UAAU,CAAC,CAAC,EAAE;QAAEgC,QAAQ,EAAE;MAAI,CAAC,CAAC;MAChDnC,OAAO,CAACa,SAAS,CAAC,CAAC,CAAC;IACtB,CAAC,MAAM;MACLE,UAAU,CAACS,KAAK,GAAGrB,UAAU,CAAC,CAAC,EAAE;QAAEgC,QAAQ,EAAE;MAAI,CAAC,CAAC;IACrD;EACF,CAAC,CAAC;EAEJ,OAAO;IAAEG,OAAO;IAAEvB,UAAU;IAAEC;EAAQ,CAAC;AACzC","ignoreList":[]}
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+
3
+ export { useAppState } from "./use-app-state.js";
4
+ export { usePauseableTimer } from "./use-pauseable-timer.js";
5
+ export { useToastState } from "./use-toast-state.js";
6
+
7
+ // Backwards compatibility alias
8
+ export { useToastState as useSooner } from "./use-toast-state.js";
9
+ //# sourceMappingURL=hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useAppState","usePauseableTimer","useToastState","useSooner"],"sourceRoot":"..\\..\\src","sources":["hooks.ts"],"mappings":";;AAAA,SAASA,WAAW,QAAQ,oBAAiB;AAC7C,SAASC,iBAAiB,QAAQ,0BAAuB;AACzD,SAASC,aAAa,QAAQ,sBAAmB;;AAEjD;AACA,SAASA,aAAa,IAAIC,SAAS,QAAQ,sBAAmB","ignoreList":[]}