feat: Обновление компонента Tooltip с изменением стиля на Tabler UI и улучшением позиционирования. Убрано вычисление координат, теперь подсказка позиционируется относительно триггера с использованием position: absolute.
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m37s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m37s
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import { useState, useRef, useEffect } from 'react'
|
||||
|
||||
/**
|
||||
* Tooltip компонент для отображения подсказок
|
||||
* Поддерживает keyboard shortcuts и различные позиции
|
||||
* Tooltip компонент в стиле Tabler UI
|
||||
* Использует position: absolute относительно trigger элемента
|
||||
*/
|
||||
function Tooltip({
|
||||
children,
|
||||
@@ -13,43 +13,14 @@ function Tooltip({
|
||||
className = ''
|
||||
}) {
|
||||
const [isVisible, setIsVisible] = useState(false)
|
||||
const [coords, setCoords] = useState({ x: 0, y: 0 })
|
||||
const timeoutRef = useRef(null)
|
||||
const triggerRef = useRef(null)
|
||||
|
||||
const showTooltip = (e) => {
|
||||
const showTooltip = () => {
|
||||
if (timeoutRef.current) clearTimeout(timeoutRef.current)
|
||||
|
||||
timeoutRef.current = setTimeout(() => {
|
||||
if (triggerRef.current) {
|
||||
const rect = triggerRef.current.getBoundingClientRect()
|
||||
let x = 0, y = 0
|
||||
|
||||
switch (position) {
|
||||
case 'top':
|
||||
x = rect.left + rect.width / 2
|
||||
y = rect.top
|
||||
break
|
||||
case 'bottom':
|
||||
x = rect.left + rect.width / 2
|
||||
y = rect.bottom
|
||||
break
|
||||
case 'left':
|
||||
x = rect.left
|
||||
y = rect.top + rect.height / 2
|
||||
break
|
||||
case 'right':
|
||||
x = rect.right
|
||||
y = rect.top + rect.height / 2
|
||||
break
|
||||
default:
|
||||
x = rect.left + rect.width / 2
|
||||
y = rect.top
|
||||
}
|
||||
|
||||
setCoords({ x, y })
|
||||
setIsVisible(true)
|
||||
}
|
||||
setIsVisible(true)
|
||||
}, delay)
|
||||
}
|
||||
|
||||
@@ -69,129 +40,94 @@ function Tooltip({
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<>
|
||||
<span
|
||||
ref={triggerRef}
|
||||
onMouseEnter={showTooltip}
|
||||
onMouseLeave={hideTooltip}
|
||||
onFocus={showTooltip}
|
||||
onBlur={hideTooltip}
|
||||
className={`tooltip-trigger ${className}`}
|
||||
style={{ position: 'relative', display: 'inline-block' }}
|
||||
>
|
||||
{children}
|
||||
</span>
|
||||
<span
|
||||
ref={triggerRef}
|
||||
onMouseEnter={showTooltip}
|
||||
onMouseLeave={hideTooltip}
|
||||
onFocus={showTooltip}
|
||||
onBlur={hideTooltip}
|
||||
className={`tooltip-trigger ${className}`}
|
||||
style={{ position: 'relative', display: 'inline-block' }}
|
||||
>
|
||||
{children}
|
||||
|
||||
{isVisible && (
|
||||
<div
|
||||
className={`tooltip-content tooltip-${position}`}
|
||||
className={`tooltip bs-tooltip-${position} show`}
|
||||
role="tooltip"
|
||||
style={{
|
||||
position: 'fixed',
|
||||
left: `${coords.x}px`,
|
||||
top: `${coords.y}px`,
|
||||
zIndex: 9999,
|
||||
pointerEvents: 'none'
|
||||
position: 'absolute',
|
||||
zIndex: 1070,
|
||||
display: 'block',
|
||||
margin: 0,
|
||||
pointerEvents: 'none',
|
||||
...(position === 'top' && {
|
||||
bottom: '100%',
|
||||
left: '50%',
|
||||
transform: 'translateX(-50%)',
|
||||
marginBottom: '8px'
|
||||
}),
|
||||
...(position === 'bottom' && {
|
||||
top: '100%',
|
||||
left: '50%',
|
||||
transform: 'translateX(-50%)',
|
||||
marginTop: '8px'
|
||||
}),
|
||||
...(position === 'left' && {
|
||||
right: '100%',
|
||||
top: '50%',
|
||||
transform: 'translateY(-50%)',
|
||||
marginRight: '8px'
|
||||
}),
|
||||
...(position === 'right' && {
|
||||
left: '100%',
|
||||
top: '50%',
|
||||
transform: 'translateY(-50%)',
|
||||
marginLeft: '8px'
|
||||
})
|
||||
}}
|
||||
>
|
||||
<div className="tooltip-arrow" style={(() => {
|
||||
const styles = {
|
||||
position: 'absolute',
|
||||
width: '8px',
|
||||
height: '8px',
|
||||
background: 'inherit'
|
||||
}
|
||||
if (position === 'top') {
|
||||
styles.bottom = '0'
|
||||
styles.left = '50%'
|
||||
styles.transform = 'translateX(-50%) translateY(50%) rotate(45deg)'
|
||||
} else if (position === 'bottom') {
|
||||
styles.top = '0'
|
||||
styles.left = '50%'
|
||||
styles.transform = 'translateX(-50%) translateY(-50%) rotate(45deg)'
|
||||
} else if (position === 'left') {
|
||||
styles.right = '0'
|
||||
styles.top = '50%'
|
||||
styles.transform = 'translateX(50%) translateY(-50%) rotate(45deg)'
|
||||
} else if (position === 'right') {
|
||||
styles.left = '0'
|
||||
styles.top = '50%'
|
||||
styles.transform = 'translateX(-50%) translateY(-50%) rotate(45deg)'
|
||||
}
|
||||
return styles
|
||||
})()}></div>
|
||||
<div className="tooltip-inner">
|
||||
<div className="tooltip-text">{content}</div>
|
||||
{content}
|
||||
{shortcut && (
|
||||
<kbd className="tooltip-shortcut ms-2">{shortcut}</kbd>
|
||||
<kbd className="ms-2" style={{
|
||||
background: 'rgba(255, 255, 255, 0.2)',
|
||||
padding: '0.125rem 0.375rem',
|
||||
borderRadius: '0.25rem',
|
||||
fontSize: '0.75rem',
|
||||
fontFamily: 'monospace'
|
||||
}}>{shortcut}</kbd>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<style jsx>{`
|
||||
.tooltip-content {
|
||||
animation: tooltipFadeIn 0.15s ease-out;
|
||||
}
|
||||
|
||||
.tooltip-top {
|
||||
transform: translate(-50%, calc(-100% - 8px));
|
||||
}
|
||||
|
||||
.tooltip-bottom {
|
||||
transform: translate(-50%, 8px);
|
||||
}
|
||||
|
||||
.tooltip-left {
|
||||
transform: translate(calc(-100% - 8px), -50%);
|
||||
}
|
||||
|
||||
.tooltip-right {
|
||||
transform: translate(8px, -50%);
|
||||
}
|
||||
|
||||
.tooltip-inner {
|
||||
background: var(--tblr-dark, #1e293b);
|
||||
color: white;
|
||||
padding: 0.5rem 0.75rem;
|
||||
border-radius: 0.375rem;
|
||||
font-size: 0.875rem;
|
||||
box-shadow: var(--shadow-lg);
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
max-width: 300px;
|
||||
}
|
||||
|
||||
.tooltip-shortcut {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
padding: 0.125rem 0.375rem;
|
||||
border-radius: 0.25rem;
|
||||
font-size: 0.75rem;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
@keyframes tooltipFadeIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, calc(-100% - 4px)) scale(0.95);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, calc(-100% - 8px)) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes tooltipFadeInTop {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, calc(-100% - 4px)) scale(0.95);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, calc(-100% - 8px)) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes tooltipFadeInBottom {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translate(-50%, 4px) scale(0.95);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, 8px) scale(1);
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip-content.tooltip-top {
|
||||
animation: tooltipFadeInTop 0.15s ease-out;
|
||||
}
|
||||
|
||||
.tooltip-content.tooltip-bottom {
|
||||
animation: tooltipFadeInBottom 0.15s ease-out;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
.tooltip-inner {
|
||||
background: var(--tblr-gray-800, #1e293b);
|
||||
}
|
||||
}
|
||||
`}</style>
|
||||
</>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user