Skip to content

Commit 049ab1b

Browse files
committed
refine component
1 parent 41be1cb commit 049ab1b

File tree

2 files changed

+189
-186
lines changed

2 files changed

+189
-186
lines changed

packages/next/src/next-devtools/dev-overlay/components/overview/segment-explorer.tsx

Lines changed: 6 additions & 186 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
import { useState, useRef, useEffect } from 'react'
2-
import { createPortal } from 'react-dom'
31
import { useSegmentTree, type SegmentTrieNode } from '../../segment-explorer'
42
import { css } from '../../utils/css'
53
import { cx } from '../../utils/cx'
4+
import {
5+
Tooltip,
6+
styles as tooltipStyles,
7+
} from '../../../userspace/components/tooltip'
68

79
const BUILTIN_PREFIX = '__next_builtin__'
810

@@ -138,12 +140,12 @@ function PageSegmentTreeLayerPresentation({
138140
>
139141
{fileName}
140142
{isBuiltin && (
141-
<TooltipSpan
143+
<Tooltip
142144
direction="right"
143145
title={`The default Next.js not found is being shown. You can customize this page by adding your own ${fileName} file to the app/ directory.`}
144146
>
145147
<InfoIcon />
146-
</TooltipSpan>
148+
</Tooltip>
147149
)}
148150
</span>
149151
)
@@ -179,102 +181,6 @@ function PageSegmentTreeLayerPresentation({
179181
)
180182
}
181183

182-
const tooltipStyles = `
183-
.tooltip-wrapper {
184-
position: relative;
185-
display: inline-block;
186-
}
187-
188-
.tooltip {
189-
position: absolute;
190-
background: var(--color-gray-1000);
191-
color: var(--color-gray-100);
192-
padding: 6px 12px;
193-
border-radius: 8px;
194-
font-size: 14px;
195-
line-height: 1.4;
196-
white-space: nowrap;
197-
min-width: 200px;
198-
white-space: normal;
199-
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
200-
pointer-events: none;
201-
}
202-
203-
.tooltip-arrow {
204-
position: absolute;
205-
width: 0;
206-
height: 0;
207-
}
208-
209-
/* Top direction */
210-
.tooltip--top {
211-
bottom: 100%;
212-
left: 50%;
213-
transform: translateX(-50%);
214-
margin-bottom: 8px;
215-
}
216-
217-
.tooltip-arrow--top {
218-
top: 100%;
219-
left: 50%;
220-
transform: translateX(-50%);
221-
border-left: 6px solid transparent;
222-
border-right: 6px solid transparent;
223-
border-top: 6px solid var(--color-gray-1000);
224-
}
225-
226-
/* Bottom direction */
227-
.tooltip--bottom {
228-
top: 100%;
229-
left: 50%;
230-
transform: translateX(-50%);
231-
margin-top: 8px;
232-
}
233-
234-
.tooltip-arrow--bottom {
235-
bottom: 100%;
236-
left: 50%;
237-
transform: translateX(-50%);
238-
border-left: 6px solid transparent;
239-
border-right: 6px solid transparent;
240-
border-bottom: 6px solid var(--color-gray-1000);
241-
}
242-
243-
/* Left direction */
244-
.tooltip--left {
245-
right: 100%;
246-
top: 50%;
247-
transform: translateY(-50%);
248-
margin-right: 8px;
249-
}
250-
251-
.tooltip-arrow--left {
252-
left: 100%;
253-
top: 50%;
254-
transform: translateY(-50%);
255-
border-top: 6px solid transparent;
256-
border-bottom: 6px solid transparent;
257-
border-left: 6px solid var(--color-gray-1000);
258-
}
259-
260-
/* Right direction */
261-
.tooltip--right {
262-
left: 100%;
263-
top: 50%;
264-
transform: translateY(-50%);
265-
margin-left: 8px;
266-
}
267-
268-
.tooltip-arrow--right {
269-
right: 100%;
270-
top: 50%;
271-
transform: translateY(-50%);
272-
border-top: 6px solid transparent;
273-
border-bottom: 6px solid transparent;
274-
border-right: 6px solid var(--color-gray-1000);
275-
}
276-
`
277-
278184
export const DEV_TOOLS_INFO_RENDER_FILES_STYLES = css`
279185
.segment-explorer-content {
280186
font-size: var(--size-14);
@@ -414,89 +320,3 @@ function InfoIcon(props: React.SVGProps<SVGSVGElement>) {
414320
</svg>
415321
)
416322
}
417-
418-
type TooltipDirection = 'top' | 'bottom' | 'left' | 'right'
419-
420-
function TooltipSpan({
421-
children,
422-
title,
423-
direction = 'top',
424-
}: {
425-
children: React.ReactNode
426-
title: string
427-
direction: TooltipDirection
428-
}) {
429-
const [isVisible, setIsVisible] = useState(false)
430-
const [position, setPosition] = useState({ top: 0, left: 0 })
431-
const wrapperRef = useRef<HTMLSpanElement>(null)
432-
433-
useEffect(() => {
434-
if (isVisible && wrapperRef.current) {
435-
const rect = wrapperRef.current.getBoundingClientRect()
436-
const scrollTop = window.scrollY || document.documentElement.scrollTop
437-
const scrollLeft = window.scrollX || document.documentElement.scrollLeft
438-
439-
setPosition({
440-
top: rect.top + scrollTop,
441-
left: rect.left + scrollLeft,
442-
})
443-
}
444-
}, [isVisible])
445-
446-
const handleMouseEnter = () => {
447-
setIsVisible(true)
448-
}
449-
450-
const handleMouseLeave = () => {
451-
setIsVisible(false)
452-
}
453-
454-
const tooltip = isVisible ? (
455-
<div
456-
className="custom-tooltip-portal"
457-
style={{
458-
position: 'absolute',
459-
top: position.top,
460-
left: position.left,
461-
width: wrapperRef.current?.offsetWidth || 0,
462-
height: wrapperRef.current?.offsetHeight || 0,
463-
pointerEvents: 'none',
464-
zIndex: 99999,
465-
}}
466-
>
467-
<div className={cx('custom-tooltip', `custom-tooltip--${direction}`)}>
468-
{title}
469-
<div
470-
className={cx(
471-
'custom-tooltip-arrow',
472-
`custom-tooltip-arrow--${direction}`
473-
)}
474-
/>
475-
</div>
476-
</div>
477-
) : null
478-
479-
const [shadowRootRef] = useState<ShadowRoot | null>(() => {
480-
const portal = document.querySelector('nextjs-portal')
481-
if (!portal) return null
482-
return portal.shadowRoot as ShadowRoot
483-
})
484-
485-
if (!shadowRootRef) return null
486-
487-
return (
488-
<>
489-
<span
490-
ref={wrapperRef}
491-
className="tooltip-wrapper"
492-
onMouseEnter={handleMouseEnter}
493-
onMouseLeave={handleMouseLeave}
494-
>
495-
{children}
496-
</span>
497-
{typeof document !== 'undefined' &&
498-
tooltip &&
499-
createPortal(tooltip, shadowRootRef)}
500-
</>
501-
)
502-
}

0 commit comments

Comments
 (0)