Skip to content

Commit 6a2302e

Browse files
committed
fix: add radix polyfill to prevent useLayoutEffect error in deployed environment
- Added radix-utils polyfill that ensures React.useLayoutEffect is available - Added polyfill import to all Radix UI components - Prevents 'Cannot read properties of undefined (reading useLayoutEffect)' error
1 parent b546180 commit 6a2302e

File tree

7 files changed

+83
-76
lines changed

7 files changed

+83
-76
lines changed

src/components/ui/dialog.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
'use client';
22

3+
// Import the polyfill early
4+
import '../../lib/utils/radix-utils';
5+
36
import * as React from 'react';
47
import * as DialogPrimitive from '@radix-ui/react-dialog';
58
import { X } from 'lucide-react';

src/components/ui/dropdown-menu.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
'use client';
2+
3+
// Import the polyfill early
4+
import '../../lib/utils/radix-utils';
5+
16
import * as React from 'react';
27
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
38
import { cn } from '@/lib/utils';

src/components/ui/label.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
'use client';
22

3+
// Import the polyfill early
4+
import '../../lib/utils/radix-utils';
5+
36
import * as React from 'react';
47
import * as LabelPrimitive from '@radix-ui/react-label';
58
import { cva, type VariantProps } from 'class-variance-authority';

src/components/ui/popover.tsx

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,34 @@
11
'use client';
22

3+
// Import the polyfill early
4+
import '../../lib/utils/radix-utils';
5+
36
import * as React from 'react';
4-
// Commenting out to test if this is causing the useLayoutEffect error
5-
// import * as PopoverPrimitive from '@radix-ui/react-popover';
7+
import * as PopoverPrimitive from '@radix-ui/react-popover';
68

79
import { cn } from '@/lib/utils';
810

9-
// Creating mock components to replace Radix UI Popover
10-
const Popover: React.FC<{ children: React.ReactNode }> = ({ children }) => <>{children}</>;
11-
const PopoverTrigger: React.FC<{ children: React.ReactNode }> = ({ children }) => <>{children}</>;
12-
const PopoverContent: React.FC<{ children: React.ReactNode, className?: string }> = ({ children, className }) =>
13-
<div className={cn('hidden', className)}>{children}</div>;
11+
const Popover = PopoverPrimitive.Root;
12+
13+
const PopoverTrigger = PopoverPrimitive.Trigger;
1414

15-
// Commenting out the original implementation
16-
// const Popover = PopoverPrimitive.Root;
17-
// const PopoverTrigger = PopoverPrimitive.Trigger;
18-
// const PopoverContent = React.forwardRef<
19-
// React.ElementRef<typeof PopoverPrimitive.Content>,
20-
// React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
21-
// >(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
22-
// <PopoverPrimitive.Portal>
23-
// <PopoverPrimitive.Content
24-
// ref={ref}
25-
// align={align}
26-
// sideOffset={sideOffset}
27-
// className={cn(
28-
// 'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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-
// className
30-
// )}
31-
// {...props}
32-
// />
33-
// </PopoverPrimitive.Portal>
34-
// ));
35-
// PopoverContent.displayName = PopoverPrimitive.Content.displayName;
15+
const PopoverContent = React.forwardRef<
16+
React.ElementRef<typeof PopoverPrimitive.Content>,
17+
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
18+
>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
19+
<PopoverPrimitive.Portal>
20+
<PopoverPrimitive.Content
21+
ref={ref}
22+
align={align}
23+
sideOffset={sideOffset}
24+
className={cn(
25+
'z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-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',
26+
className
27+
)}
28+
{...props}
29+
/>
30+
</PopoverPrimitive.Portal>
31+
));
32+
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
3633

3734
export { Popover, PopoverTrigger, PopoverContent };

src/components/ui/tooltip.tsx

Lines changed: 25 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,33 @@
11
'use client';
22

3+
// Import the polyfill early
4+
import '../../lib/utils/radix-utils';
5+
36
import * as React from 'react';
4-
// Commenting out to test if this is causing the useLayoutEffect error
5-
// import * as TooltipPrimitive from '@radix-ui/react-tooltip';
7+
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
68

79
import { cn } from '@/lib/utils';
810

9-
// Creating mock components to replace Radix UI Tooltip
10-
// This will disable all tooltips but will let us test if they're causing the error
11-
type TooltipProviderProps = { children: React.ReactNode };
12-
const TooltipProvider: React.FC<TooltipProviderProps> = ({ children }) => <>{children}</>;
13-
14-
type TooltipProps = { children: React.ReactNode };
15-
const Tooltip: React.FC<TooltipProps> = ({ children }) => <>{children}</>;
16-
17-
type TooltipTriggerProps = { children: React.ReactNode, asChild?: boolean };
18-
const TooltipTrigger: React.FC<TooltipTriggerProps> = ({ children }) => <>{children}</>;
19-
20-
type TooltipContentProps = {
21-
children: React.ReactNode,
22-
className?: string,
23-
sideOffset?: number,
24-
[key: string]: any
25-
};
26-
const TooltipContent = React.forwardRef<HTMLDivElement, TooltipContentProps>(
27-
({ children, className, ...props }, ref) => (
28-
<div ref={ref} className={cn('hidden', className)} {...props}>
29-
{children}
30-
</div>
31-
)
32-
);
33-
TooltipContent.displayName = 'TooltipContent';
34-
35-
// Commenting out the original implementation
36-
// const TooltipProvider = TooltipPrimitive.Provider;
37-
// const Tooltip = TooltipPrimitive.Root;
38-
// const TooltipTrigger = TooltipPrimitive.Trigger;
39-
// const TooltipContent = React.forwardRef<
40-
// React.ElementRef<typeof TooltipPrimitive.Content>,
41-
// React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
42-
// >(({ className, sideOffset = 4, ...props }, ref) => (
43-
// <TooltipPrimitive.Content
44-
// ref={ref}
45-
// sideOffset={sideOffset}
46-
// className={cn(
47-
// 'z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm 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',
48-
// className
49-
// )}
50-
// {...props}
51-
// />
52-
// ));
53-
// TooltipContent.displayName = TooltipPrimitive.Content.displayName;
11+
const TooltipProvider = TooltipPrimitive.Provider;
12+
13+
const Tooltip = TooltipPrimitive.Root;
14+
15+
const TooltipTrigger = TooltipPrimitive.Trigger;
16+
17+
const TooltipContent = React.forwardRef<
18+
React.ElementRef<typeof TooltipPrimitive.Content>,
19+
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
20+
>(({ className, sideOffset = 4, ...props }, ref) => (
21+
<TooltipPrimitive.Content
22+
ref={ref}
23+
sideOffset={sideOffset}
24+
className={cn(
25+
'z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm 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',
26+
className
27+
)}
28+
{...props}
29+
/>
30+
));
31+
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
5432

5533
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };

src/lib/utils/radix-utils.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* Polyfills for Radix UI components that use useLayoutEffect
3+
* This helps prevent the "Cannot read properties of undefined (reading 'useLayoutEffect')" error
4+
* in certain environments like SSR or when window.React isn't properly set
5+
*/
6+
7+
// Apply React useLayoutEffect polyfill
8+
if (typeof window !== 'undefined') {
9+
// We're in the browser, so we can safely create a React object on window
10+
// This ensures that libraries that expect to find React on window won't break
11+
// @ts-ignore - intentionally modifying window
12+
window.React = window.React || {};
13+
// @ts-ignore - intentionally modifying window.React
14+
window.React.useLayoutEffect = window.React.useLayoutEffect || window.React.useEffect || function() { return function() {}; };
15+
}
16+
17+
// Export a dummy function to make TypeScript happy when importing this module
18+
export default function ensureRadixPolyfill() {
19+
// This function does nothing, it just ensures the side effects above are executed
20+
return true;
21+
}

src/main.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// Import the polyfill first, before any other imports
2-
import './lib/utils/react-polyfill';
2+
import './lib/utils/radix-utils';
33

44
import { StrictMode } from 'react';
55
import { createRoot } from 'react-dom/client';

0 commit comments

Comments
 (0)