1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
"use client"
import * as React from "react"
import { useRouter, usePathname } from "next/navigation"
import { ArrowLeft } from "lucide-react"
import { Button } from "@/components/ui/button"
import { cn } from "@/lib/utils"
/**
* BackButton 컴포넌트 - 세그먼트를 동적으로 제거하여 상위 경로로 이동
*
* 사용 예시:
*
* // 기본 사용 (1개 세그먼트 제거)
* <BackButton>목록으로</BackButton>
*
* // 2개 세그먼트 제거 (/a/b/c/d -> /a/b)
* <BackButton segmentsToRemove={2}>상위 목록으로</BackButton>
*
* // 커스텀 경로로 이동
* <BackButton customPath="/dashboard">대시보드로</BackButton>
*
* // 아이콘 없이 사용
* <BackButton showIcon={false}>돌아가기</BackButton>
*
* // 커스텀 스타일링
* <BackButton className="text-blue-600" variant="outline">
* 이전 페이지
* </BackButton>
*/
interface BackButtonProps extends React.ComponentPropsWithoutRef<typeof Button> {
/**
* 제거할 세그먼트 개수 (기본값: 1)
* 예: segmentsToRemove=1이면 /a/b/c -> /a/b
* segmentsToRemove=2이면 /a/b/c -> /a
*/
segmentsToRemove?: number
/**
* 버튼에 표시할 텍스트 (기본값: "목록으로")
*/
children?: React.ReactNode
/**
* 아이콘을 표시할지 여부 (기본값: true)
*/
showIcon?: boolean
/**
* 커스텀 경로를 지정할 경우 (segmentsToRemove 대신 사용)
*/
customPath?: string
}
export const BackButton = React.forwardRef<
React.ElementRef<typeof Button>,
BackButtonProps
>(({
segmentsToRemove = 1,
children = "Go Back",
showIcon = true,
customPath,
className,
onClick,
...props
}, ref) => {
const router = useRouter()
const pathname = usePathname()
const handleClick = React.useCallback((event: React.MouseEvent<HTMLButtonElement>) => {
// 커스텀 onClick이 있으면 먼저 실행
if (onClick) {
onClick(event)
// preventDefault가 호출되었으면 기본 동작 중단
if (event.defaultPrevented) {
return
}
}
let targetPath: string
if (customPath) {
targetPath = customPath
} else {
// 현재 경로에서 세그먼트 제거
const segments = pathname.split('/').filter(Boolean)
const newSegments = segments.slice(0, -segmentsToRemove)
targetPath = newSegments.length > 0 ? `/${newSegments.join('/')}` : '/'
}
router.push(targetPath)
}, [router, pathname, segmentsToRemove, customPath, onClick])
return (
<Button
ref={ref}
variant="ghost"
className={cn(
"flex items-center text-primary hover:text-primary/80 transition-colors p-0 h-auto",
className
)}
onClick={handleClick}
{...props}
>
{showIcon && <ArrowLeft className="mr-1 h-4 w-4" />}
<span>{children}</span>
</Button>
)
})
BackButton.displayName = "BackButton"
|