fix(04): tooltip and dropdown overflow clipping
Tooltip uses fixed positioning on document.body to escape overflow contexts. Removed overflow-x:auto from container and SVG area that clipped tooltip top and dropdown focus ring. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
dac51a6702
commit
c90ad494b7
5 changed files with 15 additions and 15 deletions
|
|
@ -44,7 +44,6 @@
|
|||
.heatmap-wrapper .heatmap-svg-area {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.heatmap-wrapper .heatmap-filter {
|
||||
|
|
|
|||
|
|
@ -2188,9 +2188,10 @@ var KimaiHeatmap = (() => {
|
|||
});
|
||||
svg.selectAll(".month-label").data(months).join("text").attr("class", "heatmap-label month-label").attr("x", (d) => marginLeft + d.week * step).attr("y", marginTop - 6).text((d) => MONTH_FORMAT(d.date));
|
||||
svg.selectAll(".day-label").data(DAY_LABELS).join("text").attr("class", "heatmap-label day-label").attr("x", marginLeft - 6).attr("y", (_d, i) => marginTop + i * step + cellSize - 2).attr("text-anchor", "end").text((d) => d);
|
||||
document.querySelectorAll(".heatmap-tooltip").forEach((el) => el.remove());
|
||||
const tooltip = createTooltip();
|
||||
wrapper.style.position = "relative";
|
||||
wrapper.appendChild(tooltip);
|
||||
tooltip.style.position = "fixed";
|
||||
document.body.appendChild(tooltip);
|
||||
svg.selectAll(".heatmap-cell").data(cells).join("rect").attr(
|
||||
"class",
|
||||
(d) => d.entry ? "heatmap-cell" : "heatmap-cell heatmap-empty"
|
||||
|
|
@ -2200,9 +2201,8 @@ var KimaiHeatmap = (() => {
|
|||
tooltip.innerHTML = `<strong>${DISPLAY_FORMAT(d.date)}</strong><br>${hours}h (${count} entries)`;
|
||||
tooltip.style.display = "block";
|
||||
const rect = event.target.getBoundingClientRect();
|
||||
const wrapperRect = wrapper.getBoundingClientRect();
|
||||
tooltip.style.left = `${rect.left - wrapperRect.left + cellSize / 2}px`;
|
||||
tooltip.style.top = `${rect.top - wrapperRect.top - 40}px`;
|
||||
tooltip.style.left = `${rect.left + cellSize / 2}px`;
|
||||
tooltip.style.top = `${rect.top - tooltip.offsetHeight - 8}px`;
|
||||
}).on("mouseleave", function() {
|
||||
tooltip.style.display = "none";
|
||||
}).on("click", function(_event, d) {
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
data-url="{{ path('heatmap_data') }}"
|
||||
data-projects="{{ data.projects|json_encode }}"
|
||||
data-timesheet-url="{{ path('timesheet') }}"
|
||||
style="min-height: 150px; overflow-x: auto;">
|
||||
style="min-height: 150px;">
|
||||
</div>
|
||||
<script src="{{ asset('bundles/kimaiheatmap/heatmap.js') }}"></script>
|
||||
<script type="text/javascript">
|
||||
|
|
|
|||
|
|
@ -163,10 +163,12 @@ export function renderHeatmap(
|
|||
.attr('text-anchor', 'end')
|
||||
.text((d) => d);
|
||||
|
||||
// Tooltip
|
||||
// Tooltip (fixed positioning to escape overflow clipping)
|
||||
// Remove any stale tooltip from previous renders
|
||||
document.querySelectorAll('.heatmap-tooltip').forEach(el => el.remove());
|
||||
const tooltip = createTooltip();
|
||||
wrapper.style.position = 'relative';
|
||||
wrapper.appendChild(tooltip);
|
||||
tooltip.style.position = 'fixed';
|
||||
document.body.appendChild(tooltip);
|
||||
|
||||
// Cells
|
||||
svg
|
||||
|
|
@ -188,9 +190,8 @@ export function renderHeatmap(
|
|||
tooltip.style.display = 'block';
|
||||
|
||||
const rect = (event.target as SVGRectElement).getBoundingClientRect();
|
||||
const wrapperRect = wrapper.getBoundingClientRect();
|
||||
tooltip.style.left = `${rect.left - wrapperRect.left + cellSize / 2}px`;
|
||||
tooltip.style.top = `${rect.top - wrapperRect.top - 40}px`;
|
||||
tooltip.style.left = `${rect.left + cellSize / 2}px`;
|
||||
tooltip.style.top = `${rect.top - tooltip.offsetHeight - 8}px`;
|
||||
})
|
||||
.on('mouseleave', function () {
|
||||
tooltip.style.display = 'none';
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ describe('renderHeatmap', () => {
|
|||
// jsdom getBoundingClientRect returns zeros, which is fine for structure test
|
||||
rect!.dispatchEvent(event);
|
||||
|
||||
const tooltip = container.querySelector('.heatmap-tooltip') as HTMLDivElement;
|
||||
const tooltip = document.body.querySelector('.heatmap-tooltip') as HTMLDivElement;
|
||||
expect(tooltip).not.toBeNull();
|
||||
expect(tooltip.style.display).toBe('block');
|
||||
expect(tooltip.innerHTML).toContain('h');
|
||||
|
|
@ -110,7 +110,7 @@ describe('renderHeatmap', () => {
|
|||
rect!.dispatchEvent(new MouseEvent('mouseenter', { bubbles: true }));
|
||||
rect!.dispatchEvent(new MouseEvent('mouseleave', { bubbles: true }));
|
||||
|
||||
const tooltip = container.querySelector('.heatmap-tooltip') as HTMLDivElement;
|
||||
const tooltip = document.body.querySelector('.heatmap-tooltip') as HTMLDivElement;
|
||||
expect(tooltip.style.display).toBe('none');
|
||||
});
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue