pejay-ui 1.3.4 → 1.4.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.
@@ -0,0 +1,322 @@
1
+ {
2
+ "form/input": {
3
+ "name": "Input",
4
+ "category": "form",
5
+ "files": [
6
+ "templates/form/input.tsx"
7
+ ],
8
+ "utils": [
9
+ "cn.ts"
10
+ ],
11
+ "peerDependencies": [
12
+ "clsx",
13
+ "tailwind-merge",
14
+ "lucide-react"
15
+ ],
16
+ "supportsCategory": true
17
+ },
18
+ "form/amount-input": {
19
+ "name": "AmountInput",
20
+ "category": "form",
21
+ "files": [
22
+ "templates/form/amount-input.tsx"
23
+ ],
24
+ "utils": [
25
+ "cn.ts"
26
+ ],
27
+ "peerDependencies": [
28
+ "clsx",
29
+ "tailwind-merge",
30
+ "lucide-react"
31
+ ],
32
+ "supportsCategory": true
33
+ },
34
+ "form/checkbox": {
35
+ "name": "Checkbox",
36
+ "category": "form",
37
+ "files": [
38
+ "templates/form/checkbox.tsx"
39
+ ],
40
+ "utils": [
41
+ "cn.ts"
42
+ ],
43
+ "peerDependencies": [
44
+ "clsx",
45
+ "tailwind-merge",
46
+ "lucide-react"
47
+ ],
48
+ "supportsCategory": true
49
+ },
50
+ "form/checkbox-group": {
51
+ "name": "CheckboxGroup",
52
+ "category": "form",
53
+ "files": [
54
+ "templates/form/checkbox-group.tsx"
55
+ ],
56
+ "utils": [
57
+ "cn.ts"
58
+ ],
59
+ "peerDependencies": [
60
+ "clsx",
61
+ "tailwind-merge"
62
+ ],
63
+ "dependencies": [
64
+ "form/checkbox"
65
+ ],
66
+ "supportsCategory": true
67
+ },
68
+ "form/date-picker": {
69
+ "name": "DatePicker",
70
+ "category": "form",
71
+ "files": [
72
+ "templates/form/date-picker.tsx"
73
+ ],
74
+ "utils": [
75
+ "cn.ts"
76
+ ],
77
+ "peerDependencies": [
78
+ "clsx",
79
+ "tailwind-merge",
80
+ "lucide-react",
81
+ "@floating-ui/react"
82
+ ],
83
+ "dependencies": [
84
+ "dropdown/select-input"
85
+ ],
86
+ "supportsCategory": true
87
+ },
88
+ "form/date-range-picker": {
89
+ "name": "DateRangePicker",
90
+ "category": "form",
91
+ "files": [
92
+ "templates/form/date-range-picker.tsx"
93
+ ],
94
+ "utils": [
95
+ "cn.ts"
96
+ ],
97
+ "peerDependencies": [
98
+ "clsx",
99
+ "tailwind-merge",
100
+ "lucide-react",
101
+ "@floating-ui/react"
102
+ ],
103
+ "dependencies": [
104
+ "dropdown/select-input"
105
+ ],
106
+ "supportsCategory": true
107
+ },
108
+ "form/email-input": {
109
+ "name": "EmailInput",
110
+ "category": "form",
111
+ "files": [
112
+ "templates/form/email-input.tsx"
113
+ ],
114
+ "utils": [
115
+ "cn.ts"
116
+ ],
117
+ "peerDependencies": [
118
+ "clsx",
119
+ "tailwind-merge",
120
+ "lucide-react"
121
+ ],
122
+ "supportsCategory": true
123
+ },
124
+ "form/file-input": {
125
+ "name": "FileInput",
126
+ "category": "form",
127
+ "files": [
128
+ "templates/form/file-input.tsx"
129
+ ],
130
+ "utils": [
131
+ "cn.ts"
132
+ ],
133
+ "peerDependencies": [
134
+ "clsx",
135
+ "tailwind-merge",
136
+ "lucide-react"
137
+ ],
138
+ "supportsCategory": true
139
+ },
140
+ "form/number-input": {
141
+ "name": "NumberInput",
142
+ "category": "form",
143
+ "files": [
144
+ "templates/form/number-input.tsx"
145
+ ],
146
+ "utils": [
147
+ "cn.ts"
148
+ ],
149
+ "peerDependencies": [
150
+ "clsx",
151
+ "tailwind-merge",
152
+ "lucide-react"
153
+ ],
154
+ "supportsCategory": true
155
+ },
156
+ "form/password-input": {
157
+ "name": "PasswordInput",
158
+ "category": "form",
159
+ "files": [
160
+ "templates/form/password-input.tsx"
161
+ ],
162
+ "utils": [
163
+ "cn.ts"
164
+ ],
165
+ "peerDependencies": [
166
+ "clsx",
167
+ "tailwind-merge",
168
+ "lucide-react"
169
+ ],
170
+ "supportsCategory": true
171
+ },
172
+ "form/phone-input": {
173
+ "name": "PhoneInput",
174
+ "category": "form",
175
+ "files": [
176
+ "templates/form/phone-input.tsx"
177
+ ],
178
+ "utils": [
179
+ "cn.ts"
180
+ ],
181
+ "peerDependencies": [
182
+ "clsx",
183
+ "tailwind-merge",
184
+ "lucide-react"
185
+ ],
186
+ "supportsCategory": true
187
+ },
188
+ "form/radio": {
189
+ "name": "Radio",
190
+ "category": "form",
191
+ "files": [
192
+ "templates/form/radio.tsx"
193
+ ],
194
+ "utils": [
195
+ "cn.ts"
196
+ ],
197
+ "peerDependencies": [
198
+ "clsx",
199
+ "tailwind-merge"
200
+ ],
201
+ "supportsCategory": true
202
+ },
203
+ "form/radio-group": {
204
+ "name": "RadioGroup",
205
+ "category": "form",
206
+ "files": [
207
+ "templates/form/radio-group.tsx"
208
+ ],
209
+ "utils": [
210
+ "cn.ts"
211
+ ],
212
+ "peerDependencies": [
213
+ "clsx",
214
+ "tailwind-merge"
215
+ ],
216
+ "dependencies": [
217
+ "form/radio"
218
+ ],
219
+ "supportsCategory": true
220
+ },
221
+ "form/range-slider": {
222
+ "name": "RangeSlider",
223
+ "category": "form",
224
+ "files": [
225
+ "templates/form/range-slider.tsx"
226
+ ],
227
+ "utils": [
228
+ "cn.ts"
229
+ ],
230
+ "peerDependencies": [
231
+ "clsx",
232
+ "tailwind-merge"
233
+ ],
234
+ "supportsCategory": true
235
+ },
236
+ "form/switch": {
237
+ "name": "Switch",
238
+ "category": "form",
239
+ "files": [
240
+ "templates/form/switch.tsx"
241
+ ],
242
+ "utils": [
243
+ "cn.ts"
244
+ ],
245
+ "peerDependencies": [
246
+ "clsx",
247
+ "tailwind-merge"
248
+ ],
249
+ "supportsCategory": true
250
+ },
251
+ "form/textarea": {
252
+ "name": "Textarea",
253
+ "category": "form",
254
+ "files": [
255
+ "templates/form/textarea.tsx"
256
+ ],
257
+ "utils": [
258
+ "cn.ts"
259
+ ],
260
+ "peerDependencies": [
261
+ "clsx",
262
+ "tailwind-merge"
263
+ ],
264
+ "supportsCategory": true
265
+ },
266
+ "form/time-picker": {
267
+ "name": "TimePicker",
268
+ "category": "form",
269
+ "files": [
270
+ "templates/form/time-picker.tsx"
271
+ ],
272
+ "utils": [
273
+ "cn.ts"
274
+ ],
275
+ "peerDependencies": [
276
+ "clsx",
277
+ "tailwind-merge",
278
+ "lucide-react",
279
+ "@floating-ui/react"
280
+ ],
281
+ "dependencies": [
282
+ "dropdown/select-input"
283
+ ],
284
+ "supportsCategory": true
285
+ },
286
+ "form/time-range-picker": {
287
+ "name": "TimeRangePicker",
288
+ "category": "form",
289
+ "files": [
290
+ "templates/form/time-range-picker.tsx"
291
+ ],
292
+ "utils": [
293
+ "cn.ts"
294
+ ],
295
+ "peerDependencies": [
296
+ "clsx",
297
+ "tailwind-merge",
298
+ "lucide-react",
299
+ "@floating-ui/react"
300
+ ],
301
+ "dependencies": [
302
+ "dropdown/select-input"
303
+ ],
304
+ "supportsCategory": true
305
+ },
306
+ "form/url-input": {
307
+ "name": "UrlInput",
308
+ "category": "form",
309
+ "files": [
310
+ "templates/form/url-input.tsx"
311
+ ],
312
+ "utils": [
313
+ "cn.ts"
314
+ ],
315
+ "peerDependencies": [
316
+ "clsx",
317
+ "tailwind-merge",
318
+ "lucide-react"
319
+ ],
320
+ "supportsCategory": true
321
+ }
322
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "layouts/lv1": {
3
+ "name": "AppLayout",
4
+ "category": "layouts",
5
+ "files": [
6
+ "templates/layouts/lv1/app-layout.tsx",
7
+ "templates/layouts/lv1/sidebar-menu.tsx",
8
+ "templates/layouts/lv1/index.ts"
9
+ ],
10
+ "utils": ["cn.ts"],
11
+ "peerDependencies": [
12
+ "clsx",
13
+ "tailwind-merge",
14
+ "lucide-react"
15
+ ],
16
+ "supportsCategory": true
17
+ }
18
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "overlays/portal": {
3
+ "name": "Portal",
4
+ "category": "overlays",
5
+ "files": ["templates/overlays/portal.tsx"],
6
+ "supportsCategory": true
7
+ }
8
+ }
@@ -0,0 +1,83 @@
1
+ {
2
+ "tanstack-query-client": {
3
+ "name": "TanstackQueryClient",
4
+ "category": "scaffold",
5
+ "subcategory": "tanstack-query",
6
+ "targetDirName": "tanstack-query",
7
+ "files": [
8
+ "templates/scaffolds/tanstack-query"
9
+ ],
10
+ "peerDependencies": [
11
+ "@tanstack/react-query"
12
+ ],
13
+ "supportsCategory": true
14
+ },
15
+ "react-router-client": {
16
+ "name": "ReactRouterClient",
17
+ "category": "scaffold",
18
+ "subcategory": "react-router",
19
+ "targetDirName": "react-router",
20
+ "files": [
21
+ "templates/scaffolds/react-router"
22
+ ],
23
+ "peerDependencies": [
24
+ "react-router-dom"
25
+ ],
26
+ "supportsCategory": true
27
+ },
28
+ "tanstack-router-client": {
29
+ "name": "TanstackRouterClient",
30
+ "category": "scaffold",
31
+ "subcategory": "tanstack-router",
32
+ "targetDirName": "tanstack-router",
33
+ "files": [
34
+ "templates/scaffolds/tanstack-router"
35
+ ],
36
+ "peerDependencies": [
37
+ "@tanstack/react-router"
38
+ ],
39
+ "supportsCategory": true
40
+ },
41
+ "axios-client": {
42
+ "name": "AxiosClient",
43
+ "category": "scaffold",
44
+ "subcategory": "axios",
45
+ "targetDirName": "axios",
46
+ "files": [
47
+ "templates/scaffolds/axios"
48
+ ],
49
+ "peerDependencies": [
50
+ "axios"
51
+ ],
52
+ "supportsCategory": true
53
+ },
54
+ "redux-store-client": {
55
+ "name": "ReduxStoreClient",
56
+ "category": "scaffold",
57
+ "subcategory": "redux-store",
58
+ "targetDirName": "redux-store",
59
+ "files": [
60
+ "templates/scaffolds/redux-store"
61
+ ],
62
+ "peerDependencies": [
63
+ "@reduxjs/toolkit",
64
+ "react-redux",
65
+ "redux-persist"
66
+ ],
67
+ "supportsCategory": true
68
+ },
69
+ "rtk-query-client": {
70
+ "name": "RtkQueryClient",
71
+ "category": "scaffold",
72
+ "subcategory": "rtk-query",
73
+ "targetDirName": "rtk-query",
74
+ "files": [
75
+ "templates/scaffolds/rtk-query"
76
+ ],
77
+ "peerDependencies": [
78
+ "@reduxjs/toolkit",
79
+ "react-redux"
80
+ ],
81
+ "supportsCategory": true
82
+ }
83
+ }
@@ -0,0 +1,10 @@
1
+ {
2
+ "toast": {
3
+ "name": "Toast",
4
+ "category": "toast",
5
+ "files": ["templates/toast"],
6
+ "utils": ["cn.ts"],
7
+ "dependencies": ["overlays/portal"],
8
+ "peerDependencies": ["clsx", "tailwind-merge", "lucide-react"]
9
+ }
10
+ }
@@ -0,0 +1 @@
1
+ export * from "./portal";
@@ -0,0 +1,26 @@
1
+ import { createPortal } from "react-dom";
2
+ import { useEffect, useState, type ReactNode } from "react";
3
+
4
+ interface PortalProps {
5
+ children: ReactNode;
6
+ }
7
+ export function Portal({ children }: PortalProps) {
8
+ const [container, setContainer] = useState<HTMLDivElement | null>(null);
9
+
10
+ useEffect(() => {
11
+ const div = document.createElement("div");
12
+ div.id = "dynamic-portal";
13
+ document.body.appendChild(div);
14
+ setContainer(div);
15
+
16
+ return () => {
17
+ if (div.parentNode) {
18
+ document.body.removeChild(div);
19
+ }
20
+ };
21
+ }, []);
22
+
23
+ if (!container) return null;
24
+
25
+ return createPortal(children, container);
26
+ }
@@ -0,0 +1,183 @@
1
+ # Toast Notification Component
2
+
3
+ A toast notification system featuring:
4
+ - **Fully Customizable Styling**: Complete visual control over status designs.
5
+ - **Interactive Gestures**: Swipe-to-dismiss drag support for touch and pointer events.
6
+ - **Built-in Theme Presets**: Ready-to-use themes for Success, Error, Warning, and Info alerts.
7
+ - **Smart Timers**: Auto-dismiss timers that pause when the user hovers over a toast.
8
+ - **Custom Rendering**: Bypasses the default style to render custom React components and functions.
9
+ - **Transitions**: Smooth entry/exit animations (slide and fade transitions).
10
+
11
+ ---
12
+
13
+ ## 1. Setup
14
+
15
+ To use the toast notification system, place the `<ToastContainer />` at the root of your application (typically in `App.tsx` or `main.tsx`).
16
+
17
+ ```tsx
18
+ import { ToastContainer } from "@/pejay-ui/components/toast";
19
+
20
+ export default function App() {
21
+ return (
22
+ <>
23
+ {/* Your App Routing/Content */}
24
+ <ToastContainer placement="top-right" animationType="fade" />
25
+ </>
26
+ );
27
+ }
28
+ ```
29
+
30
+ ### `<ToastContainer />` Props
31
+
32
+ | Prop | Type | Default | Description |
33
+ | :--- | :--- | :--- | :--- |
34
+ | `placement` | `"top-right" \| "top-left" \| "bottom-right" \| "bottom-left"` | `"top-right"` | The screen corner where notifications will stack. |
35
+ | `animationType` | `"fade" \| "slide"` | `"fade"` | The entrance and exit transition animation style. Can also be passed as `animation-type`. |
36
+
37
+ ---
38
+
39
+ ## 2. Usage & API
40
+
41
+ Import the `toast` function from the module:
42
+ ```ts
43
+ import { toast } from "@/pejay-ui/components/toast";
44
+ ```
45
+
46
+ ### Call Signatures
47
+
48
+ The status methods (`success`, `error`, `warning`, `info`) support two call signatures:
49
+
50
+ #### 1. Quick Message (String Only)
51
+ For displaying a single-line text message with default settings:
52
+ ```ts
53
+ toast.success("All changes saved!");
54
+ ```
55
+ You can also pass an optional configuration object as the second argument:
56
+ ```ts
57
+ toast.error("An error occurred", { duration: 5000, showClose: false });
58
+ ```
59
+
60
+ #### 2. Detailed Object Configuration
61
+ For full title and description control:
62
+ ```ts
63
+ toast.warning({
64
+ title: "Low Disk Space",
65
+ description: "You have less than 10% space remaining.",
66
+ duration: 6000
67
+ });
68
+ ```
69
+
70
+ ---
71
+
72
+ ### Shared Configuration Options (`ToastOptions`)
73
+ All toast methods accept an options object:
74
+
75
+ | Option | Type | Default | Description |
76
+ | :--- | :--- | :--- | :--- |
77
+ | `title` | `string` | — | Bold title text displayed in the toast. |
78
+ | `description` | `string` | — | Smaller detail text under the title. |
79
+ | `duration` | `number` | `4000` | Lifetime in milliseconds. Pass `Infinity` to disable auto-closing. |
80
+ | `showClose` | `boolean` | `true` | Whether to show the close cross button. |
81
+ | `dismiss` | `string` | — | An existing toast ID to dismiss before showing the new one. |
82
+ | `icon` | `React.ReactNode` | — | Custom React element to override the default status icon. |
83
+
84
+ ---
85
+
86
+ ## 3. Presets & Examples
87
+
88
+ ### A. Success Toast
89
+ Use for successful operations (submitting forms, saves, payments).
90
+ ```ts
91
+ toast.success({
92
+ title: "Payment Received",
93
+ description: "Your invoice #2093 has been paid successfully.",
94
+ duration: 4000,
95
+ });
96
+ ```
97
+
98
+ ### B. Error Toast
99
+ Use for failed requests, validation errors, or application crashes.
100
+ ```ts
101
+ toast.error({
102
+ title: "Upload Failed",
103
+ description: "The connection was lost. Please check your network and try again.",
104
+ duration: 6000,
105
+ showClose: true,
106
+ });
107
+ ```
108
+
109
+ ### C. Warning Toast
110
+ Use for alerts, soft errors, or actions requiring user attention.
111
+ ```ts
112
+ toast.warning({
113
+ title: "Unsaved Changes",
114
+ description: "Your work will be lost if you navigate away.",
115
+ duration: 5000,
116
+ });
117
+ ```
118
+
119
+ ### D. Info Toast
120
+ Use for general system notices or status updates.
121
+ ```ts
122
+ toast.info({
123
+ title: "System Maintenance",
124
+ description: "Scheduled maintenance will begin tonight at 12:00 AM EST.",
125
+ duration: Infinity, // Stays visible until manually closed
126
+ });
127
+ ```
128
+
129
+ ---
130
+
131
+ ## 4. Custom Toasts
132
+
133
+ For completely custom designs, use `toast.custom()`. This method bypasses default styling and allows you to render any React component.
134
+
135
+ ### Custom Example with Manual Dismissal
136
+ You can pass a function to the `content` property. It receives the unique `id` of the toast, allowing you to trigger a manual dismiss from inside your custom UI:
137
+
138
+ ```tsx
139
+ toast.custom({
140
+ id: "my-custom-toast", // Optional custom string ID
141
+ duration: 10000, // 10 seconds
142
+ content: (id) => (
143
+ <div className="flex flex-col gap-3 p-4 w-full bg-slate-900 border border-violet-500/30 rounded-xl shadow-lg">
144
+ <div className="flex flex-col gap-1">
145
+ <h4 className="text-sm font-semibold text-white">Importing Contacts</h4>
146
+ <p className="text-xs text-slate-400">Please wait while we process your file.</p>
147
+ </div>
148
+ <div className="flex gap-2 justify-end">
149
+ <button
150
+ onClick={() => toast.dismiss(id)}
151
+ className="px-3 py-1 bg-violet-600 hover:bg-violet-700 text-xs font-semibold text-white rounded-md transition-colors"
152
+ >
153
+ Cancel Import
154
+ </button>
155
+ </div>
156
+ </div>
157
+ )
158
+ });
159
+ ```
160
+
161
+ ## 5. Dismissing Toasts
162
+
163
+ Toasts can be dismissed programmatically in two ways:
164
+
165
+ ### 1. By ID via `toast.dismiss()`
166
+ You can manually trigger the removal of a toast at any time by calling `toast.dismiss(id)` with the ID returned when the toast was created:
167
+ ```ts
168
+ // Trigger the toast and capture its generated ID
169
+ const toastId = toast.info("Uploading file...", { duration: Infinity });
170
+
171
+ // Dismiss it later (e.g. once the file upload succeeds)
172
+ toast.dismiss(toastId);
173
+ ```
174
+
175
+ ### 2. Auto-Dismissing when Triggering a New Toast (via `dismiss` option)
176
+ You can automatically dismiss an active toast by passing its ID in the `dismiss` option of a new toast. This is useful for transitioning states (e.g., from a loading state to a success/error state):
177
+ ```ts
178
+ // 1. Show loading toast with a fixed ID
179
+ toast.info("Saving changes...", { id: "saving-progress" });
180
+
181
+ // 2. Trigger success toast, which dismisses "saving-progress" before rendering
182
+ toast.success("All changes saved!", { dismiss: "saving-progress" });
183
+ ```