fix: mobile/touch UX for toolbar buttons and ghost tool placement
- Switch ghost tracking from mousemove to pointermove (fires for touch/pen/mouse) - Add cancel button (✕) on ghost outline for mobile (no ESC key available) - Center ghost on viewport for touch devices instead of (0,0) - Add touch-action: manipulation to all toolbar buttons (eliminates 300ms tap delay) - Bump mobile touch targets to 44px min-height with larger padding Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
74b15ba1b7
commit
c8e63b5c9f
|
|
@ -62,6 +62,7 @@
|
||||||
transition: background 0.2s;
|
transition: background 0.2s;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
touch-action: manipulation;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar-group-toggle:hover {
|
.toolbar-group-toggle:hover {
|
||||||
|
|
@ -102,6 +103,7 @@
|
||||||
text-align: left;
|
text-align: left;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
transition: background 0.15s;
|
transition: background 0.15s;
|
||||||
|
touch-action: manipulation;
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar-dropdown button:hover {
|
.toolbar-dropdown button:hover {
|
||||||
|
|
@ -160,6 +162,7 @@
|
||||||
text-align: left;
|
text-align: left;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
transition: background 0.15s;
|
transition: background 0.15s;
|
||||||
|
touch-action: manipulation;
|
||||||
}
|
}
|
||||||
|
|
||||||
#toolbar-panel-body button:hover {
|
#toolbar-panel-body button:hover {
|
||||||
|
|
@ -196,6 +199,7 @@
|
||||||
transition: background 0.2s;
|
transition: background 0.2s;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
|
touch-action: manipulation;
|
||||||
}
|
}
|
||||||
|
|
||||||
#toolbar > button:hover {
|
#toolbar > button:hover {
|
||||||
|
|
@ -844,8 +848,9 @@
|
||||||
#toolbar .toolbar-group-toggle {
|
#toolbar .toolbar-group-toggle {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 10px 12px;
|
padding: 12px 14px;
|
||||||
font-size: 13px;
|
font-size: 14px;
|
||||||
|
min-height: 44px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#toolbar .toolbar-dropdown {
|
#toolbar .toolbar-dropdown {
|
||||||
|
|
@ -856,14 +861,16 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#toolbar .toolbar-dropdown button {
|
#toolbar .toolbar-dropdown button {
|
||||||
padding: 10px 12px;
|
padding: 12px 14px;
|
||||||
font-size: 13px;
|
font-size: 14px;
|
||||||
|
min-height: 44px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#toolbar > button {
|
#toolbar > button {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 10px 12px;
|
padding: 12px 14px;
|
||||||
|
min-height: 44px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#toolbar .toolbar-sep {
|
#toolbar .toolbar-sep {
|
||||||
|
|
@ -2183,7 +2190,30 @@
|
||||||
transform: translate(-50%, -50%);
|
transform: translate(-50%, -50%);
|
||||||
transition: width 0.1s, height 0.1s;
|
transition: width 0.1s, height 0.1s;
|
||||||
`;
|
`;
|
||||||
|
const cancelBtn = document.createElement("button");
|
||||||
|
cancelBtn.textContent = "✕";
|
||||||
|
cancelBtn.style.cssText = `
|
||||||
|
position: absolute; top: -16px; right: -16px;
|
||||||
|
width: 32px; height: 32px; border-radius: 50%;
|
||||||
|
border: 2px solid #14b8a6; background: white; color: #14b8a6;
|
||||||
|
font-size: 16px; font-weight: bold; cursor: pointer;
|
||||||
|
pointer-events: auto; z-index: 10000;
|
||||||
|
display: flex; align-items: center; justify-content: center;
|
||||||
|
box-shadow: 0 2px 8px rgba(0,0,0,0.15);
|
||||||
|
`;
|
||||||
|
cancelBtn.addEventListener("pointerdown", (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
clearPendingTool();
|
||||||
|
});
|
||||||
|
ghostEl.appendChild(cancelBtn);
|
||||||
document.body.appendChild(ghostEl);
|
document.body.appendChild(ghostEl);
|
||||||
|
|
||||||
|
// Center ghost for touch devices (no mousemove fires after toolbar tap)
|
||||||
|
if (window.matchMedia("(pointer: coarse)").matches) {
|
||||||
|
ghostEl.style.left = (window.innerWidth / 2) + "px";
|
||||||
|
ghostEl.style.top = (window.innerHeight / 2) + "px";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function clearPendingTool() {
|
function clearPendingTool() {
|
||||||
|
|
@ -2193,7 +2223,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// Track ghost position
|
// Track ghost position
|
||||||
document.addEventListener("mousemove", (e) => {
|
document.addEventListener("pointermove", (e) => {
|
||||||
if (ghostEl) {
|
if (ghostEl) {
|
||||||
ghostEl.style.left = e.clientX + "px";
|
ghostEl.style.left = e.clientX + "px";
|
||||||
ghostEl.style.top = e.clientY + "px";
|
ghostEl.style.top = e.clientY + "px";
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue