@djangocfg/ui-core 2.1.338 → 2.1.339

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/ui-core",
3
- "version": "2.1.338",
3
+ "version": "2.1.339",
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.338",
94
+ "@djangocfg/i18n": "^2.1.339",
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.338",
163
+ "@djangocfg/i18n": "^2.1.339",
164
164
  "@djangocfg/playground": "workspace:*",
165
- "@djangocfg/typescript-config": "^2.1.338",
165
+ "@djangocfg/typescript-config": "^2.1.339",
166
166
  "@types/node": "^24.7.2",
167
167
  "@types/react": "^19.1.0",
168
168
  "@types/react-dom": "^19.1.0",
@@ -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 = true,
11
- direction,
17
+ shouldScaleBackground,
18
+ direction = 'bottom',
12
19
  ...props
13
- }: React.ComponentProps<typeof DrawerPrimitive.Root> & { direction?: 'bottom' | 'right' | 'left' | 'top' }) => (
14
- <DrawerPrimitive.Root
15
- shouldScaleBackground={shouldScaleBackground}
16
- direction={direction}
17
- {...props}
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 = 'bottom',
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);
@@ -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
- const [matches, setMatches] = useState<boolean>(false)
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)