🔄 refactor: Migrate to react-resizable-panels v4 with Artifacts Header polish (#12356)
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run

* chore: Update react-resizable-panels dependency to version 4.7.4

- Upgraded the "react-resizable-panels" package in package-lock.json, package.json, and client package.json files to ensure compatibility with the latest features and improvements.
- Adjusted peer dependencies for React and ReactDOM to align with the new version requirements.

* refactor: Update Share and SidePanel components to `react-resizable-panels` v4

- Refactored the ShareArtifactsContainer to utilize a new layout change handler, enhancing artifact panel resizing functionality.
- Updated ArtifactsPanel to use the new `usePanelRef` hook, improving panel reference management.
- Simplified SidePanelGroup by removing unnecessary layout normalization and integrating default layout handling with localStorage.
- Removed the deprecated `normalizeLayout` utility function to streamline the codebase.
- Adjusted Resizable components to ensure consistent sizing and layout behavior across panels.

* style: Enhance scrollbar appearance across application

- Added custom scrollbar styles to both artifacts and markdown files, improving aesthetics and user experience.
- Implemented dark mode adjustments for scrollbar visibility, ensuring consistency across different color schemes.

* style: Standardize button sizes and layout in Artifacts components

- Updated button dimensions to a consistent height of 9 units across various components including Artifacts, Code, and DownloadArtifact.
- Adjusted padding and layout properties in the Artifacts header for improved visual consistency.
- Enhanced the Radio component to accept a new `buttonClassName` prop for better customization of button styles.

* chore: import order
This commit is contained in:
Danny Avila 2026-03-22 02:21:27 -04:00 committed by GitHub
parent 733a9364c0
commit 676641f3da
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
14 changed files with 92 additions and 118 deletions

View file

@ -13,6 +13,7 @@ interface RadioProps {
onChange?: (value: string) => void;
disabled?: boolean;
className?: string;
buttonClassName?: string;
fullWidth?: boolean;
'aria-labelledby'?: string;
}
@ -23,6 +24,7 @@ const Radio = memo(function Radio({
onChange,
disabled = false,
className = '',
buttonClassName = '',
fullWidth = false,
'aria-labelledby': ariaLabelledBy,
}: RadioProps) {
@ -45,7 +47,7 @@ const Radio = memo(function Radio({
if (selectedButton && container) {
const containerRect = container.getBoundingClientRect();
const buttonRect = selectedButton.getBoundingClientRect();
const offsetLeft = buttonRect.left - containerRect.left - 4;
const offsetLeft = buttonRect.left - containerRect.left;
setBackgroundStyle({
width: `${buttonRect.width}px`,
transform: `translateX(${offsetLeft}px)`,
@ -94,13 +96,13 @@ const Radio = memo(function Radio({
return (
<div
className={`relative ${fullWidth ? 'flex' : 'inline-flex'} items-center rounded-lg bg-muted p-1 ${className}`}
className={`relative ${fullWidth ? 'flex' : 'inline-flex'} items-center rounded-lg bg-muted ${className}`}
role="radiogroup"
aria-labelledby={ariaLabelledBy}
>
{selectedIndex >= 0 && isMounted && (
<div
className="pointer-events-none absolute inset-y-1 rounded-md border border-border/50 bg-background shadow-sm transition-all duration-300 ease-out"
className="pointer-events-none absolute inset-y-0 rounded-md border border-border/50 bg-background shadow-sm transition-all duration-300 ease-out"
style={backgroundStyle}
/>
)}
@ -117,7 +119,7 @@ const Radio = memo(function Radio({
disabled={disabled}
className={`relative z-10 flex h-[34px] items-center justify-center gap-2 rounded-md px-4 text-sm font-medium transition-colors duration-150 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring ${
currentValue === option.value ? 'text-foreground' : 'text-foreground'
} ${disabled ? 'cursor-not-allowed opacity-50' : ''} ${fullWidth ? 'flex-1' : ''}`}
} ${disabled ? 'cursor-not-allowed opacity-50' : ''} ${fullWidth ? 'flex-1' : ''} ${buttonClassName}`}
>
{option.icon && (
<span className="flex-shrink-0" aria-hidden="true">

View file

@ -1,30 +1,24 @@
import { GripVertical } from 'lucide-react';
import * as ResizablePrimitive from 'react-resizable-panels';
import { Group, Panel, Separator } from 'react-resizable-panels';
import type { ComponentProps } from 'react';
import { cn } from '~/utils';
const ResizablePanelGroup = ({
className = '',
...props
}: React.ComponentProps<typeof ResizablePrimitive.PanelGroup>) => (
<ResizablePrimitive.PanelGroup
className={cn('flex h-full w-full data-[panel-group-direction=vertical]:flex-col', className)}
{...props}
/>
const ResizablePanelGroup = ({ className = '', ...props }: ComponentProps<typeof Group>) => (
<Group className={cn('h-full w-full', className)} {...props} />
);
const ResizablePanel = ResizablePrimitive.Panel;
const ResizablePanel = Panel;
const ResizableHandle = ({
withHandle,
className = '',
...props
}: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
}: ComponentProps<typeof Separator> & {
withHandle?: boolean;
}) => (
<ResizablePrimitive.PanelResizeHandle
<Separator
className={cn(
'relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90',
'relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1',
className,
)}
{...props}
@ -34,29 +28,29 @@ const ResizableHandle = ({
<GripVertical className="h-2.5 w-2.5" />
</div>
)}
</ResizablePrimitive.PanelResizeHandle>
</Separator>
);
const ResizableHandleAlt = ({
withHandle,
className = '',
...props
}: React.ComponentProps<typeof ResizablePrimitive.PanelResizeHandle> & {
}: ComponentProps<typeof Separator> & {
withHandle?: boolean;
}) => (
<ResizablePrimitive.PanelResizeHandle
<Separator
className={cn(
'group relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1 data-[panel-group-direction=vertical]:h-px data-[panel-group-direction=vertical]:w-full data-[panel-group-direction=vertical]:after:left-0 data-[panel-group-direction=vertical]:after:h-1 data-[panel-group-direction=vertical]:after:w-full data-[panel-group-direction=vertical]:after:-translate-y-1/2 data-[panel-group-direction=vertical]:after:translate-x-0 [&[data-panel-group-direction=vertical]>div]:rotate-90',
'group relative flex w-px items-center justify-center bg-border after:absolute after:inset-y-0 after:left-1/2 after:w-1 after:-translate-x-1/2 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-1',
className,
)}
{...props}
>
{withHandle && (
<div className="invisible z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border group-hover:visible group-active:visible group-data-[resize-handle-active]:visible">
<div className="invisible z-10 flex h-4 w-3 items-center justify-center rounded-sm border bg-border group-hover:visible group-active:visible group-data-[separator=active]:visible">
<GripVertical className="h-2.5 w-2.5" />
</div>
)}
</ResizablePrimitive.PanelResizeHandle>
</Separator>
);
export { ResizablePanelGroup, ResizablePanel, ResizableHandle, ResizableHandleAlt };