@djangocfg/ui-core 2.1.36 → 2.1.38
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/package.json +2 -2
- package/src/components/button.tsx +17 -2
- package/src/components/sticky.tsx +32 -0
- package/src/components/toast.tsx +16 -2
- package/src/hooks/useToast.ts +19 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/ui-core",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.38",
|
|
4
4
|
"description": "Pure React UI component library without Next.js dependencies - for Electron, Vite, CRA apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ui-components",
|
|
@@ -102,7 +102,7 @@
|
|
|
102
102
|
"vaul": "1.1.2"
|
|
103
103
|
},
|
|
104
104
|
"devDependencies": {
|
|
105
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
105
|
+
"@djangocfg/typescript-config": "^2.1.38",
|
|
106
106
|
"@types/node": "^24.7.2",
|
|
107
107
|
"@types/react": "^19.1.0",
|
|
108
108
|
"@types/react-dom": "^19.1.0",
|
|
@@ -46,6 +46,21 @@ export interface ButtonProps
|
|
|
46
46
|
loading?: boolean
|
|
47
47
|
}
|
|
48
48
|
|
|
49
|
+
// Filter out SVG icons from children when loading
|
|
50
|
+
function filterIcons(children: React.ReactNode): React.ReactNode {
|
|
51
|
+
return React.Children.map(children, (child) => {
|
|
52
|
+
if (!React.isValidElement(child)) return child;
|
|
53
|
+
|
|
54
|
+
const type = child.type;
|
|
55
|
+
// Skip native svg or ForwardRef components (Lucide icons)
|
|
56
|
+
if (type === 'svg' || (typeof type === 'object' && type !== null)) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return child;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
49
64
|
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
50
65
|
({ className, variant, size, asChild = false, loading = false, onClick, children, disabled, ...props }, ref) => {
|
|
51
66
|
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
|
|
@@ -77,8 +92,8 @@ const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
|
|
77
92
|
disabled={disabled || loading}
|
|
78
93
|
{...props}
|
|
79
94
|
>
|
|
80
|
-
{loading && <Loader2 className="animate-spin" />}
|
|
81
|
-
{children}
|
|
95
|
+
{loading && <Loader2 className="size-4 animate-spin" />}
|
|
96
|
+
{loading ? filterIcons(children) : children}
|
|
82
97
|
</button>
|
|
83
98
|
)
|
|
84
99
|
}
|
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
"use client"
|
|
2
2
|
|
|
3
|
+
/*
|
|
4
|
+
* Sticky Component - react-sticky-box wrapper
|
|
5
|
+
*
|
|
6
|
+
* COMMON ISSUES & SOLUTIONS:
|
|
7
|
+
*
|
|
8
|
+
* 1. STICKY NOT WORKING
|
|
9
|
+
* Required structure:
|
|
10
|
+
* - Outer div: h-full overflow-y-auto (scrollable container)
|
|
11
|
+
* - Inner div: flex items-start min-h-full (flex container)
|
|
12
|
+
* - Main content: flex-1
|
|
13
|
+
* - Sticky: direct child of flex container
|
|
14
|
+
*
|
|
15
|
+
* 2. PAGE DOESN'T SCROLL
|
|
16
|
+
* Add "h-full overflow-y-auto" to outer container.
|
|
17
|
+
* Scrollable container must have defined height.
|
|
18
|
+
*
|
|
19
|
+
* 3. INSIDE ResizablePanel
|
|
20
|
+
* ResizablePanel has overflow-hidden. Add scrollable wrapper inside:
|
|
21
|
+
* <ResizablePanel>
|
|
22
|
+
* <div className="h-full overflow-y-auto">...</div>
|
|
23
|
+
* </ResizablePanel>
|
|
24
|
+
*
|
|
25
|
+
* 4. FLEX CONTAINER REQUIREMENTS
|
|
26
|
+
* - Use items-start (NOT items-stretch)
|
|
27
|
+
* - Sticky must be direct child of flex container
|
|
28
|
+
* - Main content should be flex-1
|
|
29
|
+
*
|
|
30
|
+
* 5. useNativeSticky vs react-sticky-box
|
|
31
|
+
* - useNativeSticky: CSS position:sticky, simpler but limited
|
|
32
|
+
* - Default: react-sticky-box, better for sidebars, handles tall content
|
|
33
|
+
*/
|
|
34
|
+
|
|
3
35
|
import * as React from 'react';
|
|
4
36
|
import StickyBox from 'react-sticky-box';
|
|
5
37
|
|
package/src/components/toast.tsx
CHANGED
|
@@ -32,6 +32,12 @@ const toastVariants = cva(
|
|
|
32
32
|
default: "border bg-background text-foreground",
|
|
33
33
|
destructive:
|
|
34
34
|
"destructive group border-destructive bg-destructive text-destructive-foreground",
|
|
35
|
+
success:
|
|
36
|
+
"success group border-green-600 bg-green-500 text-white",
|
|
37
|
+
warning:
|
|
38
|
+
"warning group border-yellow-600 bg-yellow-500 text-black",
|
|
39
|
+
info:
|
|
40
|
+
"info group border-blue-600 bg-blue-500 text-white",
|
|
35
41
|
},
|
|
36
42
|
},
|
|
37
43
|
defaultVariants: {
|
|
@@ -62,7 +68,11 @@ const ToastAction = React.forwardRef<
|
|
|
62
68
|
<ToastPrimitives.Action
|
|
63
69
|
ref={ref}
|
|
64
70
|
className={cn(
|
|
65
|
-
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50
|
|
71
|
+
"inline-flex h-8 shrink-0 items-center justify-center rounded-md border bg-transparent px-3 text-sm font-medium ring-offset-background transition-colors hover:bg-secondary focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
|
72
|
+
"group-[.destructive]:border-muted/40 group-[.destructive]:hover:border-destructive/30 group-[.destructive]:hover:bg-destructive group-[.destructive]:hover:text-destructive-foreground group-[.destructive]:focus:ring-destructive",
|
|
73
|
+
"group-[.success]:border-green-300/40 group-[.success]:hover:bg-green-600 group-[.success]:hover:text-white group-[.success]:focus:ring-green-400",
|
|
74
|
+
"group-[.warning]:border-yellow-600/40 group-[.warning]:hover:bg-yellow-600 group-[.warning]:hover:text-black group-[.warning]:focus:ring-yellow-400",
|
|
75
|
+
"group-[.info]:border-blue-300/40 group-[.info]:hover:bg-blue-600 group-[.info]:hover:text-white group-[.info]:focus:ring-blue-400",
|
|
66
76
|
className
|
|
67
77
|
)}
|
|
68
78
|
{...props}
|
|
@@ -77,7 +87,11 @@ const ToastClose = React.forwardRef<
|
|
|
77
87
|
<ToastPrimitives.Close
|
|
78
88
|
ref={ref}
|
|
79
89
|
className={cn(
|
|
80
|
-
"absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100
|
|
90
|
+
"absolute right-2 top-2 rounded-md p-1 text-foreground/50 opacity-0 transition-opacity hover:text-foreground focus:opacity-100 focus:outline-none focus:ring-2 group-hover:opacity-100",
|
|
91
|
+
"group-[.destructive]:text-red-300 group-[.destructive]:hover:text-red-50 group-[.destructive]:focus:ring-red-400 group-[.destructive]:focus:ring-offset-red-600",
|
|
92
|
+
"group-[.success]:text-green-100 group-[.success]:hover:text-white group-[.success]:focus:ring-green-300",
|
|
93
|
+
"group-[.warning]:text-yellow-800 group-[.warning]:hover:text-black group-[.warning]:focus:ring-yellow-600",
|
|
94
|
+
"group-[.info]:text-blue-100 group-[.info]:hover:text-white group-[.info]:focus:ring-blue-300",
|
|
81
95
|
className
|
|
82
96
|
)}
|
|
83
97
|
toast-close=""
|
package/src/hooks/useToast.ts
CHANGED
|
@@ -172,7 +172,7 @@ function dispatch(action: Action) {
|
|
|
172
172
|
|
|
173
173
|
type Toast = Omit<ToasterToast, "id">
|
|
174
174
|
|
|
175
|
-
function
|
|
175
|
+
function createToast({ duration = TOAST_DEFAULT_DURATION, ...props }: Toast) {
|
|
176
176
|
const id = genId()
|
|
177
177
|
|
|
178
178
|
const update = (props: ToasterToast) =>
|
|
@@ -206,6 +206,24 @@ function toast({ duration = TOAST_DEFAULT_DURATION, ...props }: Toast) {
|
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
+
// Main toast function with variant helpers
|
|
210
|
+
function toast(props: Toast) {
|
|
211
|
+
return createToast(props)
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Convenience methods for different variants
|
|
215
|
+
toast.success = (props: Omit<Toast, "variant">) =>
|
|
216
|
+
createToast({ ...props, variant: "success" })
|
|
217
|
+
|
|
218
|
+
toast.error = (props: Omit<Toast, "variant">) =>
|
|
219
|
+
createToast({ ...props, variant: "destructive" })
|
|
220
|
+
|
|
221
|
+
toast.warning = (props: Omit<Toast, "variant">) =>
|
|
222
|
+
createToast({ ...props, variant: "warning" })
|
|
223
|
+
|
|
224
|
+
toast.info = (props: Omit<Toast, "variant">) =>
|
|
225
|
+
createToast({ ...props, variant: "info" })
|
|
226
|
+
|
|
209
227
|
function useToast() {
|
|
210
228
|
const [state, setState] = React.useState<State>(memoryState)
|
|
211
229
|
|