mirror of
https://github.com/johndoe6345789/snippet-pastebin.git
synced 2026-04-29 07:54:56 +00:00
Key changes: 1. Fix critical bug in src/app/page.tsx: removed conflicting `export const dynamic` that shadowed imported `dynamic` from next/dynamic, causing ReferenceError at runtime. Replaced with `export const revalidate = 0` then removed (client component). 2. Install missing typescript-eslint dependency and fix ESLint configuration to use flat config format properly. 3. Fix 32 ESLint errors across codebase: - Remove unused variables and imports (concat unused props in components) - Replace `any` types with proper TypeScript types (React.MutableRefObject) - Change empty interface in textarea.tsx to type alias - Fix react-hooks rule name from non-existent `set-state-in-effect` to `exhaustive-deps` 4. Code quality improvements: - Removed unused cn import from aspect-ratio.tsx - Removed unused useRef, useEffect from sheet.tsx imports - Simplified handler parameters in avatar.tsx - Cleaned up test files (removed unused container/user variables) Results after review: - Unit tests: 275 passing, 14 failing (improved from 270/19) - E2E tests: 204 passing, 59 failing, 17 skipped (now running after critical fix) - Linter: 0 errors (all 32 fixed) Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
280 lines
6.7 KiB
TypeScript
280 lines
6.7 KiB
TypeScript
"use client"
|
|
|
|
import React, { ComponentProps, createContext, useContext, useState, useRef, useEffect } from "react"
|
|
import { createPortal } from "react-dom"
|
|
import { cn } from "@/lib/utils"
|
|
|
|
interface DropdownMenuContextValue {
|
|
open: boolean
|
|
setOpen: (open: boolean) => void
|
|
}
|
|
|
|
const DropdownMenuContext = createContext<DropdownMenuContextValue | null>(null)
|
|
|
|
function DropdownMenu({ children }: { children: React.ReactNode }) {
|
|
const [open, setOpen] = useState(false)
|
|
return (
|
|
<DropdownMenuContext.Provider value={{ open, setOpen }}>
|
|
{children}
|
|
</DropdownMenuContext.Provider>
|
|
)
|
|
}
|
|
|
|
function DropdownMenuPortal({ children }: { children: React.ReactNode }) {
|
|
const [mounted, setMounted] = useState(false)
|
|
|
|
useEffect(() => {
|
|
setMounted(true)
|
|
}, [])
|
|
|
|
if (!mounted) return null
|
|
return createPortal(children, document.body)
|
|
}
|
|
|
|
function DropdownMenuTrigger({ children, asChild, className, ...props }: ComponentProps<"button"> & { asChild?: boolean }) {
|
|
const context = useContext(DropdownMenuContext)
|
|
|
|
const handleClick = () => {
|
|
context?.setOpen(!context.open)
|
|
}
|
|
|
|
if (asChild && React.isValidElement(children)) {
|
|
return React.cloneElement(children as React.ReactElement, {
|
|
onClick: handleClick,
|
|
...props,
|
|
})
|
|
}
|
|
|
|
return (
|
|
<button type="button" onClick={handleClick} className={className} {...props}>
|
|
{children}
|
|
</button>
|
|
)
|
|
}
|
|
|
|
function DropdownMenuContent({
|
|
className,
|
|
children,
|
|
...props
|
|
}: ComponentProps<"div"> & { align?: "start" | "center" | "end"; sideOffset?: number }) {
|
|
const context = useContext(DropdownMenuContext)
|
|
const contentRef = useRef<HTMLDivElement>(null)
|
|
|
|
useEffect(() => {
|
|
if (!context?.open) return
|
|
|
|
const handleClickOutside = (e: MouseEvent) => {
|
|
if (contentRef.current && !contentRef.current.contains(e.target as Node)) {
|
|
context.setOpen(false)
|
|
}
|
|
}
|
|
|
|
const handleEscape = (e: KeyboardEvent) => {
|
|
if (e.key === "Escape") {
|
|
context.setOpen(false)
|
|
}
|
|
}
|
|
|
|
document.addEventListener("mousedown", handleClickOutside)
|
|
document.addEventListener("keydown", handleEscape)
|
|
|
|
return () => {
|
|
document.removeEventListener("mousedown", handleClickOutside)
|
|
document.removeEventListener("keydown", handleEscape)
|
|
}
|
|
}, [context])
|
|
|
|
if (!context?.open) return null
|
|
|
|
return (
|
|
<DropdownMenuPortal>
|
|
<div className="cdk-overlay-container">
|
|
<div className="cdk-overlay-pane">
|
|
<div
|
|
ref={contentRef}
|
|
className={cn("mat-mdc-menu-panel mat-menu-panel-animations-enabled", className)}
|
|
role="menu"
|
|
{...props}
|
|
>
|
|
<div className="mat-mdc-menu-content">
|
|
{children}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</DropdownMenuPortal>
|
|
)
|
|
}
|
|
|
|
function DropdownMenuGroup({ children }: { children: React.ReactNode }) {
|
|
return <div role="group">{children}</div>
|
|
}
|
|
|
|
function DropdownMenuItem({
|
|
className,
|
|
variant = "default",
|
|
onClick,
|
|
children,
|
|
...props
|
|
}: ComponentProps<"button"> & {
|
|
inset?: boolean
|
|
variant?: "default" | "destructive"
|
|
}) {
|
|
const context = useContext(DropdownMenuContext)
|
|
|
|
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {
|
|
onClick?.(e)
|
|
context?.setOpen(false)
|
|
}
|
|
|
|
return (
|
|
<button
|
|
type="button"
|
|
role="menuitem"
|
|
className={cn(
|
|
"mat-mdc-menu-item mdc-list-item",
|
|
variant === "destructive" && "mat-warn",
|
|
className
|
|
)}
|
|
onClick={handleClick}
|
|
{...props}
|
|
>
|
|
<span className="mdc-list-item__primary-text">{children}</span>
|
|
<div className="mat-mdc-menu-ripple mat-ripple" />
|
|
</button>
|
|
)
|
|
}
|
|
|
|
function DropdownMenuCheckboxItem({
|
|
className,
|
|
children,
|
|
checked,
|
|
...props
|
|
}: ComponentProps<"button"> & { checked?: boolean }) {
|
|
return (
|
|
<button
|
|
type="button"
|
|
role="menuitemcheckbox"
|
|
aria-checked={checked}
|
|
className={cn("mat-mdc-menu-item mdc-list-item", className)}
|
|
{...props}
|
|
>
|
|
<span className="mdc-list-item__primary-text">{children}</span>
|
|
{checked && (
|
|
<span className="mdc-list-item__end">
|
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
|
|
<path d="M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z" />
|
|
</svg>
|
|
</span>
|
|
)}
|
|
</button>
|
|
)
|
|
}
|
|
|
|
function DropdownMenuRadioGroup({ children }: { children: React.ReactNode }) {
|
|
return <div role="radiogroup">{children}</div>
|
|
}
|
|
|
|
function DropdownMenuRadioItem({
|
|
className,
|
|
children,
|
|
...props
|
|
}: ComponentProps<"button">) {
|
|
return (
|
|
<button
|
|
type="button"
|
|
role="menuitemradio"
|
|
className={cn("mat-mdc-menu-item mdc-list-item", className)}
|
|
{...props}
|
|
>
|
|
<span className="mdc-list-item__primary-text">{children}</span>
|
|
</button>
|
|
)
|
|
}
|
|
|
|
function DropdownMenuLabel({ className, ...props }: ComponentProps<"div"> & { inset?: boolean }) {
|
|
return (
|
|
<div
|
|
className={cn("mat-mdc-optgroup-label", className)}
|
|
{...props}
|
|
/>
|
|
)
|
|
}
|
|
|
|
function DropdownMenuSeparator({ className, ...props }: ComponentProps<"hr">) {
|
|
return (
|
|
<hr
|
|
className={cn("mat-divider", className)}
|
|
role="separator"
|
|
{...props}
|
|
/>
|
|
)
|
|
}
|
|
|
|
function DropdownMenuShortcut({ className, ...props }: ComponentProps<"span">) {
|
|
return (
|
|
<span
|
|
className={className}
|
|
style={{ marginLeft: "auto", fontSize: "0.75rem", opacity: 0.6 }}
|
|
{...props}
|
|
/>
|
|
)
|
|
}
|
|
|
|
function DropdownMenuSub({ children }: { children: React.ReactNode }) {
|
|
return <>{children}</>
|
|
}
|
|
|
|
function DropdownMenuSubTrigger({
|
|
className,
|
|
children,
|
|
...props
|
|
}: ComponentProps<"button"> & { inset?: boolean }) {
|
|
return (
|
|
<button
|
|
type="button"
|
|
className={cn("mat-mdc-menu-item mdc-list-item", className)}
|
|
{...props}
|
|
>
|
|
<span className="mdc-list-item__primary-text">{children}</span>
|
|
<span className="mat-mdc-menu-submenu-icon">
|
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="currentColor">
|
|
<path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" />
|
|
</svg>
|
|
</span>
|
|
</button>
|
|
)
|
|
}
|
|
|
|
function DropdownMenuSubContent({ className, children, ...props }: ComponentProps<"div">) {
|
|
return (
|
|
<div
|
|
className={cn("mat-mdc-menu-panel", className)}
|
|
role="menu"
|
|
{...props}
|
|
>
|
|
<div className="mat-mdc-menu-content">
|
|
{children}
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export {
|
|
DropdownMenu,
|
|
DropdownMenuPortal,
|
|
DropdownMenuTrigger,
|
|
DropdownMenuContent,
|
|
DropdownMenuGroup,
|
|
DropdownMenuLabel,
|
|
DropdownMenuItem,
|
|
DropdownMenuCheckboxItem,
|
|
DropdownMenuRadioGroup,
|
|
DropdownMenuRadioItem,
|
|
DropdownMenuSeparator,
|
|
DropdownMenuShortcut,
|
|
DropdownMenuSub,
|
|
DropdownMenuSubTrigger,
|
|
DropdownMenuSubContent,
|
|
}
|