v2.3.1
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
.wx-button.wx-TyZ1fHBj {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border: none;
|
||||
outline: none;
|
||||
border-radius: 50%;
|
||||
cursor: pointer;
|
||||
|
||||
padding-top: 7px;
|
||||
}
|
||||
|
||||
.wx-primary.wx-TyZ1fHBj {
|
||||
color: var(--wx-color-primary-font);
|
||||
background-color: var(--wx-color-primary);
|
||||
}
|
||||
|
||||
.wx-primary.wx-TyZ1fHBj:hover {
|
||||
background-color: #0b9db1;
|
||||
}
|
||||
|
||||
.wx-transparent.wx-TyZ1fHBj {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
|
||||
color: var(--wx-color-primary-font);
|
||||
background-color: rgba(99, 99, 99, 0.45);
|
||||
}
|
||||
|
||||
.wx-transparent.wx-TyZ1fHBj:hover {
|
||||
background-color: rgba(69, 69, 69, 0.45);
|
||||
}
|
||||
|
||||
.wx-button-icon.wx-TyZ1fHBj {
|
||||
font-size: 20px;
|
||||
padding-top: 2px;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import './IconButton.css';
|
||||
|
||||
export default function IconButton({
|
||||
appearance = 'primary',
|
||||
icon = '',
|
||||
onClick,
|
||||
}) {
|
||||
return (
|
||||
<button className={`wx-TyZ1fHBj wx-button ${appearance}`} onClick={onClick}>
|
||||
{icon ? <i className={`wx-TyZ1fHBj wx-button-icon ${icon}`}></i> : null}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
.wx-tooltip-area.wx-KG0Lwsqo {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.wx-gantt-tooltip {
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
box-shadow: var(--wx-box-shadow);
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wx-gantt-tooltip-text.wx-KG0Lwsqo {
|
||||
padding: 6px 10px;
|
||||
background-color: var(--wx-tooltip-background);
|
||||
font: var(--wx-tooltip-font);
|
||||
color: var(--wx-tooltip-font-color);
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
import { useState, useEffect, useRef } from 'react';
|
||||
import './Tooltip.css';
|
||||
|
||||
function Tooltip(props) {
|
||||
const { api, content: Content, children } = props;
|
||||
|
||||
const areaRef = useRef(null);
|
||||
const tooltipNodeRef = useRef(null);
|
||||
|
||||
const [areaCoords, setAreaCoords] = useState({});
|
||||
const [tooltipData, setTooltipData] = useState(null);
|
||||
const [pos, setPos] = useState({});
|
||||
|
||||
function findAttribute(node) {
|
||||
while (node) {
|
||||
if (node.getAttribute) {
|
||||
const id = node.getAttribute('data-tooltip-id');
|
||||
const at = node.getAttribute('data-tooltip-at');
|
||||
const tooltip = node.getAttribute('data-tooltip');
|
||||
if (id || tooltip) return { id, tooltip, target: node, at };
|
||||
}
|
||||
node = node.parentNode;
|
||||
}
|
||||
|
||||
return { id: null, tooltip: null, target: null, at: null };
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const tooltipNode = tooltipNodeRef.current;
|
||||
if (tooltipNode && pos && (pos.text || Content)) {
|
||||
const tooltipCoords = tooltipNode.getBoundingClientRect();
|
||||
|
||||
let updated = false;
|
||||
let newLeft = pos.left;
|
||||
let newTop = pos.top;
|
||||
|
||||
if (tooltipCoords.right >= areaCoords.right) {
|
||||
newLeft = areaCoords.width - tooltipCoords.width - 5;
|
||||
updated = true;
|
||||
}
|
||||
if (tooltipCoords.bottom >= areaCoords.bottom) {
|
||||
newTop = pos.top - (tooltipCoords.bottom - areaCoords.bottom + 2);
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (updated) {
|
||||
setPos((prev) => {
|
||||
if (!prev) return prev;
|
||||
return { ...prev, left: newLeft, top: newTop };
|
||||
});
|
||||
}
|
||||
}
|
||||
}, [pos, areaCoords, Content]);
|
||||
|
||||
const timerRef = useRef(null);
|
||||
const TIMEOUT = 300;
|
||||
const debounce = (code) => {
|
||||
clearTimeout(timerRef.current);
|
||||
timerRef.current = setTimeout(() => {
|
||||
code();
|
||||
}, TIMEOUT);
|
||||
};
|
||||
|
||||
function move(e) {
|
||||
let { id, tooltip, target, at } = findAttribute(e.target);
|
||||
setPos(null);
|
||||
setTooltipData(null);
|
||||
|
||||
if (!tooltip) {
|
||||
if (!id) {
|
||||
clearTimeout(timerRef.current);
|
||||
return;
|
||||
} else {
|
||||
tooltip = getTaskText(id);
|
||||
}
|
||||
}
|
||||
|
||||
const clientX = e.clientX;
|
||||
|
||||
debounce(() => {
|
||||
if (id) {
|
||||
setTooltipData(getTaskObj(prepareId(id)));
|
||||
}
|
||||
|
||||
const targetCoords = target.getBoundingClientRect();
|
||||
const areaEl = areaRef.current;
|
||||
const areaRect = areaEl
|
||||
? areaEl.getBoundingClientRect()
|
||||
: { top: 0, left: 0, right: 0, bottom: 0, width: 0, height: 0 };
|
||||
|
||||
let top, left;
|
||||
if (at === 'left') {
|
||||
top = targetCoords.top + 5 - areaRect.top;
|
||||
left = targetCoords.right + 5 - areaRect.left;
|
||||
} else {
|
||||
top = targetCoords.top + targetCoords.height - areaRect.top;
|
||||
left = clientX - areaRect.left;
|
||||
}
|
||||
|
||||
setAreaCoords(areaRect);
|
||||
setPos({ top, left, text: tooltip });
|
||||
});
|
||||
}
|
||||
|
||||
function getTaskObj(id) {
|
||||
return api?.getTask(prepareId(id)) || null;
|
||||
}
|
||||
|
||||
function getTaskText(id) {
|
||||
return getTaskObj(id)?.text || '';
|
||||
}
|
||||
|
||||
function prepareId(id) {
|
||||
const numId = parseInt(id);
|
||||
return isNaN(numId) ? id : numId;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className="wx-KG0Lwsqo wx-tooltip-area"
|
||||
ref={areaRef}
|
||||
onMouseMove={move}
|
||||
>
|
||||
{pos && (pos.text || Content) ? (
|
||||
<div
|
||||
className="wx-KG0Lwsqo wx-gantt-tooltip"
|
||||
ref={tooltipNodeRef}
|
||||
style={{ top: `${pos.top}px`, left: `${pos.left}px` }}
|
||||
>
|
||||
{Content ? (
|
||||
<Content data={getTaskObj(tooltipData)} />
|
||||
) : pos.text ? (
|
||||
<div className="wx-KG0Lwsqo wx-gantt-tooltip-text">{pos.text}</div>
|
||||
) : null}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Tooltip;
|
||||
Reference in New Issue
Block a user