@djangocfg/ui-core 2.1.338 → 2.1.340
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 +4 -4
- package/src/components/overlay/dialog/index.tsx +1 -1
- package/src/components/overlay/drawer/index.tsx +35 -10
- package/src/components/overlay/hover-card/index.tsx +1 -0
- package/src/components/overlay/popover/index.tsx +1 -0
- package/src/components/overlay/sheet/index.tsx +1 -0
- package/src/components/overlay/side-panel/index.tsx +1 -0
- package/src/components/overlay/tooltip/index.tsx +1 -0
- package/src/hooks/media/useMediaQuery.ts +9 -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.340",
|
|
4
4
|
"description": "Pure React UI component library without Next.js dependencies - for Electron, Vite, CRA apps",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ui-components",
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
"playground": "playground dev"
|
|
92
92
|
},
|
|
93
93
|
"peerDependencies": {
|
|
94
|
-
"@djangocfg/i18n": "^2.1.
|
|
94
|
+
"@djangocfg/i18n": "^2.1.340",
|
|
95
95
|
"consola": "^3.4.2",
|
|
96
96
|
"lucide-react": "^0.545.0",
|
|
97
97
|
"moment": "^2.30.1",
|
|
@@ -160,9 +160,9 @@
|
|
|
160
160
|
"vaul": "1.1.2"
|
|
161
161
|
},
|
|
162
162
|
"devDependencies": {
|
|
163
|
-
"@djangocfg/i18n": "^2.1.
|
|
163
|
+
"@djangocfg/i18n": "^2.1.340",
|
|
164
164
|
"@djangocfg/playground": "workspace:*",
|
|
165
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
165
|
+
"@djangocfg/typescript-config": "^2.1.340",
|
|
166
166
|
"@types/node": "^24.7.2",
|
|
167
167
|
"@types/react": "^19.1.0",
|
|
168
168
|
"@types/react-dom": "^19.1.0",
|
|
@@ -58,6 +58,7 @@ const DialogContent = React.forwardRef<
|
|
|
58
58
|
<DialogOverlay />
|
|
59
59
|
<DialogPrimitive.Content
|
|
60
60
|
ref={ref}
|
|
61
|
+
aria-describedby={undefined}
|
|
61
62
|
className={cn(
|
|
62
63
|
"fixed z-600 bg-background duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
63
64
|
fullscreen
|
|
@@ -68,7 +69,6 @@ const DialogContent = React.forwardRef<
|
|
|
68
69
|
{...props}
|
|
69
70
|
>
|
|
70
71
|
{children}
|
|
71
|
-
<DialogPrimitive.Description className="sr-only" />
|
|
72
72
|
{closeButton === undefined ? (
|
|
73
73
|
<DialogPrimitive.Close className="absolute right-4 top-4 cursor-pointer rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
|
74
74
|
<Cross2Icon className="h-4 w-4" />
|
|
@@ -6,17 +6,36 @@ import { Drawer as DrawerPrimitive } from 'vaul';
|
|
|
6
6
|
import { cn } from '../../../lib/utils';
|
|
7
7
|
import { useIsMobile } from '../../../hooks/media/useMobile';
|
|
8
8
|
|
|
9
|
+
// Direction context lets <DrawerContent /> inherit the Root's direction without
|
|
10
|
+
// callers having to pass it twice (a frequent rebase / refactor footgun).
|
|
11
|
+
const DrawerDirectionContext = React.createContext<'bottom' | 'right' | 'left' | 'top' | undefined>(undefined);
|
|
12
|
+
|
|
13
|
+
/** @internal — used by DrawerContent to inherit `direction` from the Root. */
|
|
14
|
+
export const useDrawerDirection = () => React.useContext(DrawerDirectionContext);
|
|
15
|
+
|
|
9
16
|
const Drawer = ({
|
|
10
|
-
shouldScaleBackground
|
|
11
|
-
direction,
|
|
17
|
+
shouldScaleBackground,
|
|
18
|
+
direction = 'bottom',
|
|
12
19
|
...props
|
|
13
|
-
}: React.ComponentProps<typeof DrawerPrimitive.Root> & { direction?: 'bottom' | 'right' | 'left' | 'top' }) =>
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
}: React.ComponentProps<typeof DrawerPrimitive.Root> & { direction?: 'bottom' | 'right' | 'left' | 'top' }) => {
|
|
21
|
+
// vaul's body-scale animation is a mobile-bottom-sheet effect by design.
|
|
22
|
+
// Applying it to side drawers (right/left) keeps the <body> transformed for
|
|
23
|
+
// ~300ms during open, which on heavy pages stalls the main thread *before*
|
|
24
|
+
// any data fetch the consumer kicks off in response to opening — so the
|
|
25
|
+
// network panel shows the request appearing only after the scale finishes.
|
|
26
|
+
// Default to enabled only for bottom sheets; callers can still override.
|
|
27
|
+
const resolvedScale = shouldScaleBackground ?? direction === 'bottom';
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<DrawerDirectionContext.Provider value={direction}>
|
|
31
|
+
<DrawerPrimitive.Root
|
|
32
|
+
shouldScaleBackground={resolvedScale}
|
|
33
|
+
direction={direction}
|
|
34
|
+
{...props}
|
|
35
|
+
/>
|
|
36
|
+
</DrawerDirectionContext.Provider>
|
|
37
|
+
);
|
|
38
|
+
};
|
|
20
39
|
Drawer.displayName = "Drawer"
|
|
21
40
|
|
|
22
41
|
const DrawerTrigger = DrawerPrimitive.Trigger
|
|
@@ -134,7 +153,7 @@ const DrawerContent = React.forwardRef<
|
|
|
134
153
|
>(({
|
|
135
154
|
className,
|
|
136
155
|
children,
|
|
137
|
-
direction
|
|
156
|
+
direction: directionProp,
|
|
138
157
|
size = 'md',
|
|
139
158
|
width,
|
|
140
159
|
height,
|
|
@@ -147,6 +166,11 @@ const DrawerContent = React.forwardRef<
|
|
|
147
166
|
onSizeChange,
|
|
148
167
|
...props
|
|
149
168
|
}, ref) => {
|
|
169
|
+
// Inherit direction from the Drawer Root when not explicitly overridden.
|
|
170
|
+
// This avoids the common bug where `<Drawer direction="right">` is paired
|
|
171
|
+
// with a `<DrawerContent />` that silently falls back to "bottom".
|
|
172
|
+
const inherited = useDrawerDirection();
|
|
173
|
+
const direction = directionProp ?? inherited ?? 'bottom';
|
|
150
174
|
const isVertical = direction === 'bottom' || direction === 'top';
|
|
151
175
|
const isMobile = useIsMobile();
|
|
152
176
|
const resizeEnabled = resizable && (!resizableOnDesktopOnly || !isMobile);
|
|
@@ -242,6 +266,7 @@ const DrawerContent = React.forwardRef<
|
|
|
242
266
|
<DrawerOverlay />
|
|
243
267
|
<DrawerPrimitive.Content
|
|
244
268
|
ref={ref}
|
|
269
|
+
aria-describedby={undefined}
|
|
245
270
|
className={cn(
|
|
246
271
|
"fixed z-500 flex flex-col bg-background",
|
|
247
272
|
directionStyles[direction],
|
|
@@ -109,6 +109,7 @@ const SidePanelContent = React.forwardRef<
|
|
|
109
109
|
<DrawerPrimitive.Portal>
|
|
110
110
|
<DrawerPrimitive.Content
|
|
111
111
|
ref={ref}
|
|
112
|
+
aria-describedby={undefined}
|
|
112
113
|
className={cn(
|
|
113
114
|
'fixed z-500 flex flex-col bg-background shadow-2xl shadow-black/20',
|
|
114
115
|
'h-full max-w-[95vw]',
|
|
@@ -19,6 +19,7 @@ const TooltipContent = React.forwardRef<
|
|
|
19
19
|
<TooltipPrimitive.Portal>
|
|
20
20
|
<TooltipPrimitive.Content
|
|
21
21
|
ref={ref}
|
|
22
|
+
aria-describedby={undefined}
|
|
22
23
|
sideOffset={sideOffset}
|
|
23
24
|
className={cn(
|
|
24
25
|
"z-[700] overflow-hidden rounded-md border border-border bg-popover px-3 py-1.5 text-xs text-popover-foreground shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
@@ -29,10 +29,18 @@ export type Breakpoint = keyof typeof BREAKPOINTS
|
|
|
29
29
|
* const isLandscape = useMediaQuery('(orientation: landscape)')
|
|
30
30
|
*/
|
|
31
31
|
export function useMediaQuery(query: string): boolean {
|
|
32
|
-
|
|
32
|
+
// Lazy initializer: read the real match on first render in the browser
|
|
33
|
+
// so we never paint a "desktop" frame on a phone (and vice-versa) before
|
|
34
|
+
// the first effect runs. SSR / non-browser → false.
|
|
35
|
+
const [matches, setMatches] = useState<boolean>(() => {
|
|
36
|
+
if (typeof window === 'undefined') return false
|
|
37
|
+
return window.matchMedia(query).matches
|
|
38
|
+
})
|
|
33
39
|
|
|
34
40
|
useEffect(() => {
|
|
35
41
|
const mediaQuery = window.matchMedia(query)
|
|
42
|
+
// Re-sync once on mount in case the lazy initializer was skipped
|
|
43
|
+
// (e.g. hydration mismatch where SSR gave false).
|
|
36
44
|
setMatches(mediaQuery.matches)
|
|
37
45
|
const handler = (event: MediaQueryListEvent) => setMatches(event.matches)
|
|
38
46
|
mediaQuery.addEventListener('change', handler)
|