react-toast-native 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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 M Adhitya
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,124 @@
1
+ # react-toast-native
2
+
3
+ [![MIT License](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
4
+ [![GitHub](https://img.shields.io/badge/GitHub-iamadhitya1-blue?logo=github)](https://github.com/iamadhitya1)
5
+ ![Zero Dependencies](https://img.shields.io/badge/dependencies-0-brightgreen)
6
+ ![React](https://img.shields.io/badge/React-17%2B-61DAFB?logo=react)
7
+
8
+ > Lightweight toast notifications for React. Zero dependencies. 4 types. Fully customizable.
9
+
10
+ **2 exports. ~80 lines. No config needed.**
11
+
12
+ ---
13
+
14
+ ## Features
15
+
16
+ - ✅ `success`, `error`, `info`, `warning` types
17
+ - ✅ Custom icons per toast
18
+ - ✅ Top or bottom positioning
19
+ - ✅ Auto-dismiss with configurable duration
20
+ - ✅ Click to dismiss
21
+ - ✅ Max visible toasts limit
22
+ - ✅ Custom color schemes
23
+ - ✅ Slide-in animation
24
+ - ✅ Zero dependencies — pure React + inline styles
25
+
26
+ ---
27
+
28
+ ## Install
29
+
30
+ ```bash
31
+ npm install react-toast-native
32
+ ```
33
+
34
+ ---
35
+
36
+ ## Usage
37
+
38
+ ### 1. Wrap your app
39
+
40
+ ```jsx
41
+ import { ToastProvider } from 'react-toast-native'
42
+
43
+ export default function App() {
44
+ return (
45
+ <ToastProvider>
46
+ <YourApp />
47
+ </ToastProvider>
48
+ )
49
+ }
50
+ ```
51
+
52
+ ### 2. Use anywhere
53
+
54
+ ```jsx
55
+ import { useToast } from 'react-toast-native'
56
+
57
+ function MyComponent() {
58
+ const { toast } = useToast()
59
+
60
+ return (
61
+ <button onClick={() => toast({ message: 'Saved!', type: 'success' })}>
62
+ Save
63
+ </button>
64
+ )
65
+ }
66
+ ```
67
+
68
+ ---
69
+
70
+ ## Toast options
71
+
72
+ ```jsx
73
+ toast({
74
+ message: 'Something went wrong', // required
75
+ type: 'error', // 'success' | 'error' | 'info' | 'warning'
76
+ duration: 4000, // ms — 0 = persistent (default: 3000)
77
+ icon: '🔥', // override default icon
78
+ })
79
+ ```
80
+
81
+ ---
82
+
83
+ ## ToastProvider props
84
+
85
+ | Prop | Type | Default | Description |
86
+ |------|------|---------|-------------|
87
+ | `position` | `string` | `'top'` | `'top'` or `'bottom'` |
88
+ | `maxToasts` | `number` | `3` | Max toasts visible at once |
89
+ | `colors` | `object` | see below | Override colors per type |
90
+
91
+ ### Custom colors
92
+
93
+ ```jsx
94
+ <ToastProvider
95
+ colors={{
96
+ success: { bg: 'rgba(0,20,10,0.95)', border: 'rgba(0,200,100,0.3)', text: '#00c864' },
97
+ error: { bg: 'rgba(20,0,0,0.95)', border: 'rgba(255,50,50,0.3)', text: '#ff3232' },
98
+ }}
99
+ >
100
+ ```
101
+
102
+ ---
103
+
104
+ ## Dismiss programmatically
105
+
106
+ ```jsx
107
+ const { toast, dismiss } = useToast()
108
+
109
+ const id = toast({ message: 'Loading…', type: 'info', duration: 0 })
110
+ // later:
111
+ dismiss(id)
112
+ ```
113
+
114
+ ---
115
+
116
+ ## Used in Production
117
+
118
+ Built from the real implementation powering **[Sage](https://joinsage.vercel.app)** and the full **[Rewrite Labs](https://rewritelabs.vercel.app)** app suite.
119
+
120
+ ---
121
+
122
+ ## License
123
+
124
+ MIT © 2025 [M Adhitya](https://github.com/iamadhitya1)
package/package.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "react-toast-native",
3
+ "version": "1.0.0",
4
+ "description": "Lightweight toast notifications for React. Zero dependencies, 4 types, fully customizable.",
5
+ "type": "module",
6
+ "main": "./src/index.js",
7
+ "exports": { ".": "./src/index.js" },
8
+ "files": ["src", "README.md", "LICENSE"],
9
+ "keywords": ["react", "toast", "notification", "alert", "snackbar", "zero-dependency"],
10
+ "author": "M Adhitya",
11
+ "license": "MIT",
12
+ "peerDependencies": { "react": ">=17.0.0" },
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "https://github.com/iamadhitya1/react-toast-native"
16
+ }
17
+ }
@@ -0,0 +1,135 @@
1
+ import React, { useState, useCallback, createContext, useContext } from 'react'
2
+
3
+ const ToastContext = createContext(null)
4
+
5
+ const ICONS = {
6
+ success: '✓',
7
+ error: '✕',
8
+ info: 'ℹ',
9
+ warning: '⚠',
10
+ }
11
+
12
+ const COLORS = {
13
+ success: { bg: 'rgba(13,26,16,0.97)', border: 'rgba(82,183,136,0.3)', text: '#52B788' },
14
+ error: { bg: 'rgba(26,13,13,0.97)', border: 'rgba(240,96,96,0.3)', text: '#f06060' },
15
+ info: { bg: 'rgba(13,20,32,0.97)', border: 'rgba(96,160,255,0.3)', text: '#60a0ff' },
16
+ warning: { bg: 'rgba(26,20,0,0.97)', border: 'rgba(240,180,41,0.3)', text: '#F0B429' },
17
+ }
18
+
19
+ /**
20
+ * ToastProvider — wrap your app with this.
21
+ *
22
+ * @param {object} props
23
+ * @param {node} props.children
24
+ * @param {string} props.position - 'top' | 'bottom' (default: 'top')
25
+ * @param {number} props.maxToasts - max visible at once (default: 3)
26
+ * @param {object} props.colors - override color scheme per type
27
+ */
28
+ export function ToastProvider({
29
+ children,
30
+ position = 'top',
31
+ maxToasts = 3,
32
+ colors = {},
33
+ }) {
34
+ const [toasts, setToasts] = useState([])
35
+
36
+ const toast = useCallback(({
37
+ message,
38
+ type = 'success',
39
+ duration = 3000,
40
+ icon,
41
+ }) => {
42
+ const id = Date.now() + Math.random()
43
+ setToasts(prev => {
44
+ const next = [...prev, { id, message, type, icon }]
45
+ return next.slice(-maxToasts)
46
+ })
47
+ if (duration > 0) {
48
+ setTimeout(() => {
49
+ setToasts(prev => prev.filter(t => t.id !== id))
50
+ }, duration)
51
+ }
52
+ return id
53
+ }, [maxToasts])
54
+
55
+ const dismiss = useCallback((id) => {
56
+ setToasts(prev => prev.filter(t => t.id !== id))
57
+ }, [])
58
+
59
+ const mergedColors = { ...COLORS, ...colors }
60
+
61
+ const positionStyle = position === 'bottom'
62
+ ? { bottom: 16, top: 'auto' }
63
+ : { top: 16 }
64
+
65
+ return (
66
+ <ToastContext.Provider value={{ toast, dismiss }}>
67
+ {children}
68
+ <div style={{
69
+ position: 'fixed',
70
+ left: '50%',
71
+ transform: 'translateX(-50%)',
72
+ zIndex: 9999,
73
+ display: 'flex',
74
+ flexDirection: 'column',
75
+ gap: 8,
76
+ width: '100%',
77
+ maxWidth: 360,
78
+ padding: '0 16px',
79
+ pointerEvents: 'none',
80
+ ...positionStyle,
81
+ }}>
82
+ {toasts.map(t => {
83
+ const c = mergedColors[t.type] || mergedColors.info
84
+ return (
85
+ <div
86
+ key={t.id}
87
+ onClick={() => dismiss(t.id)}
88
+ style={{
89
+ display: 'flex',
90
+ alignItems: 'center',
91
+ gap: 10,
92
+ padding: '12px 16px',
93
+ borderRadius: 16,
94
+ border: `1px solid ${c.border}`,
95
+ background: c.bg,
96
+ backdropFilter: 'blur(12px)',
97
+ color: c.text,
98
+ fontSize: 13,
99
+ fontWeight: 500,
100
+ boxShadow: '0 4px 24px rgba(0,0,0,0.4)',
101
+ pointerEvents: 'auto',
102
+ cursor: 'pointer',
103
+ animation: 'rtn-slide-in 0.2s ease',
104
+ fontFamily: 'inherit',
105
+ }}
106
+ >
107
+ <span style={{ fontSize: 14, flexShrink: 0 }}>
108
+ {t.icon || ICONS[t.type] || ICONS.info}
109
+ </span>
110
+ <span style={{ flex: 1, color: 'rgba(255,255,255,0.85)' }}>{t.message}</span>
111
+ </div>
112
+ )
113
+ })}
114
+ </div>
115
+ <style>{`
116
+ @keyframes rtn-slide-in {
117
+ from { opacity: 0; transform: translateY(-8px); }
118
+ to { opacity: 1; transform: translateY(0); }
119
+ }
120
+ `}</style>
121
+ </ToastContext.Provider>
122
+ )
123
+ }
124
+
125
+ /**
126
+ * useToast — returns { toast, dismiss } from the nearest ToastProvider.
127
+ *
128
+ * toast({ message, type, duration, icon })
129
+ * dismiss(id)
130
+ */
131
+ export function useToast() {
132
+ const ctx = useContext(ToastContext)
133
+ if (!ctx) throw new Error('useToast must be used inside <ToastProvider>')
134
+ return ctx
135
+ }
package/src/index.js ADDED
@@ -0,0 +1 @@
1
+ export { ToastProvider, useToast } from './ToastProvider.jsx'