fix: Correct cursor position calculation for touch events (#20748)

* improve cursor position on mobile

* force ci re-run

* force ci re-run

* replace addEventListner with removeEventListener on unmount
This commit is contained in:
KDSBrowne 2024-09-18 14:03:52 -04:00 committed by GitHub
parent 5b12b35265
commit ce9b10aefe
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -28,6 +28,13 @@ const TOOL_CURSORS = {
grabbing: 'grabbing', grabbing: 'grabbing',
moving: 'move', moving: 'move',
}; };
// Offset native tldraw eraser animation container
const setOverlayPosition = () => {
const overlay = document.getElementsByClassName('tl-overlay')[0];
if (overlay) overlay.style.left = '0px';
};
const Cursors = (props) => { const Cursors = (props) => {
const cursorWrapper = React.useRef(); const cursorWrapper = React.useRef();
const [active, setActive] = React.useState(false); const [active, setActive] = React.useState(false);
@ -100,122 +107,123 @@ const Cursors = (props) => {
const banners = document.querySelectorAll('[data-test="notificationBannerBar"]'); const banners = document.querySelectorAll('[data-test="notificationBannerBar"]');
let yOffset = 0; let yOffset = 0;
let xOffset = 0; let xOffset = 0;
const calcPresOffset = () => { const calcPresOffset = () => {
yOffset const presContainerHeight = parseFloat(presentationContainer?.style?.height);
+= (parseFloat(presentationContainer?.style?.height) const presHeight = parseFloat(presentation?.style?.height);
- (parseFloat(presentation?.style?.height) const presToolbarHeight = currentUser.presenter ? PRES_TOOLBAR_HEIGHT : 0;
+ (currentUser.presenter ? PRES_TOOLBAR_HEIGHT : 0))
) / 2; yOffset += (presContainerHeight - (presHeight + presToolbarHeight)) / 2;
xOffset
+= (parseFloat(presentationContainer?.style?.width) const presContainerWidth = parseFloat(presentationContainer?.style?.width);
- parseFloat(presentation?.style?.width) const presWidth = parseFloat(presentation?.style?.width);
) / 2;
xOffset += (presContainerWidth - presWidth) / 2;
}; };
// If the presentation container is the full screen element we don't
// need any offsets // If the presentation container is the full screen element we don't need any offsets
const { webkitFullscreenElement, fullscreenElement } = document; const { webkitFullscreenElement, fullscreenElement } = document;
const fsEl = webkitFullscreenElement || fullscreenElement; const fsEl = webkitFullscreenElement || fullscreenElement;
if (fsEl?.getAttribute('data-test') === 'presentationContainer') { if (fsEl?.getAttribute('data-test') === 'presentationContainer') {
calcPresOffset(); calcPresOffset();
return setPos({ x: x - xOffset, y: y - yOffset });
}
if (nav) yOffset += parseFloat(nav?.style?.height);
if (panel) xOffset += parseFloat(panel?.style?.width);
if (subPanel) xOffset += parseFloat(subPanel?.style?.width);
// offset native tldraw eraser animation container
const overlay = document.getElementsByClassName('tl-overlay')[0];
if (overlay) overlay.style.left = '0px';
if (type === 'touchmove') {
calcPresOffset();
if (!active) {
setActive(true);
}
const newX = event?.changedTouches[0]?.clientX - xOffset;
const newY = event?.changedTouches[0]?.clientY - yOffset;
return setPos({ x: newX, y: newY });
}
if (document?.documentElement?.dir === 'rtl') {
xOffset = 0;
if (presentationContainer && presentation) {
calcPresOffset();
}
if (sl.includes('custom')) {
if (webcams) {
if (camPosition === 'contentTop' || !camPosition) {
yOffset += (parseFloat(webcams?.style?.height || 0) + BOTTOM_CAM_HANDLE_HEIGHT);
}
if (camPosition === 'contentBottom') {
yOffset -= BOTTOM_CAM_HANDLE_HEIGHT;
}
if (camPosition === 'contentRight') {
xOffset += (parseFloat(webcams?.style?.width || 0) + SMALL_OFFSET);
}
}
}
if (sl?.includes('smart')) {
if (panel || subPanel) {
const dockPos = webcams?.getAttribute('data-position');
if (dockPos === 'contentTop') {
yOffset += (parseFloat(webcams?.style?.height || 0) + SMALL_OFFSET);
}
}
}
if (webcams && sl?.includes('videoFocus')) {
xOffset += parseFloat(nav?.style?.width);
yOffset += (parseFloat(panel?.style?.height || 0) - XL_OFFSET);
}
} else { } else {
if (sl.includes('custom')) { const calculateOffsets = () => {
if (webcams) { if (nav) yOffset += parseFloat(nav?.style?.height);
if (camPosition === 'contentTop' || !camPosition) { if (panel) xOffset += parseFloat(panel?.style?.width);
yOffset += (parseFloat(webcams?.style?.height) || 0) + XS_OFFSET; if (subPanel) xOffset += parseFloat(subPanel?.style?.width);
}
if (camPosition === 'contentBottom') {
yOffset -= BOTTOM_CAM_HANDLE_HEIGHT;
}
if (camPosition === 'contentLeft') {
xOffset += (parseFloat(webcams?.style?.width) || 0) + SMALL_OFFSET;
}
}
}
if (sl.includes('smart')) { if (document?.documentElement?.dir === 'rtl') {
if (panel || subPanel) { xOffset = 0;
const dockPos = webcams?.getAttribute('data-position'); if (presentationContainer && presentation) {
if (dockPos === 'contentLeft') { calcPresOffset();
xOffset += (parseFloat(webcams?.style?.width || 0) + SMALL_OFFSET);
} }
if (dockPos === 'contentTop') { if (sl.includes('custom')) {
yOffset += (parseFloat(webcams?.style?.height || 0) + SMALL_OFFSET); if (webcams) {
if (camPosition === 'contentTop' || !camPosition) {
yOffset += (parseFloat(webcams?.style?.height || 0) + BOTTOM_CAM_HANDLE_HEIGHT);
}
if (camPosition === 'contentBottom') {
yOffset -= BOTTOM_CAM_HANDLE_HEIGHT;
}
if (camPosition === 'contentRight') {
xOffset += (parseFloat(webcams?.style?.width || 0) + SMALL_OFFSET);
}
}
}
if (sl?.includes('smart')) {
if (panel || subPanel) {
const dockPos = webcams?.getAttribute('data-position');
if (dockPos === 'contentTop') {
yOffset += (parseFloat(webcams?.style?.height || 0) + SMALL_OFFSET);
}
}
}
if (webcams && sl?.includes('videoFocus')) {
xOffset += parseFloat(nav?.style?.width);
yOffset += (parseFloat(panel?.style?.height || 0) - XL_OFFSET);
}
} else {
if (sl.includes('custom')) {
if (webcams) {
if (camPosition === 'contentTop' || !camPosition) {
yOffset += (parseFloat(webcams?.style?.height) || 0) + XS_OFFSET;
}
if (camPosition === 'contentBottom') {
yOffset -= BOTTOM_CAM_HANDLE_HEIGHT;
}
if (camPosition === 'contentLeft') {
xOffset += (parseFloat(webcams?.style?.width) || 0) + SMALL_OFFSET;
}
}
}
if (sl.includes('smart')) {
if (panel || subPanel) {
const dockPos = webcams?.getAttribute('data-position');
if (dockPos === 'contentLeft') {
xOffset += (parseFloat(webcams?.style?.width || 0) + SMALL_OFFSET);
}
if (dockPos === 'contentTop') {
yOffset += (parseFloat(webcams?.style?.height || 0) + SMALL_OFFSET);
}
}
if (!panel && !subPanel) {
if (webcams) {
xOffset = parseFloat(webcams?.style?.width || 0) + SMALL_OFFSET;
}
}
}
if (sl?.includes('videoFocus')) {
if (webcams) {
xOffset = parseFloat(subPanel?.style?.width);
yOffset = parseFloat(panel?.style?.height);
}
}
if (presentationContainer && presentation) {
calcPresOffset();
} }
} }
if (!panel && !subPanel) {
if (webcams) { if (banners) {
xOffset = parseFloat(webcams?.style?.width || 0) + SMALL_OFFSET; banners.forEach((el) => {
} yOffset += parseFloat(window.getComputedStyle(el).height);
});
} }
} };
if (sl?.includes('videoFocus')) {
if (webcams) { calculateOffsets();
xOffset = parseFloat(subPanel?.style?.width);
yOffset = parseFloat(panel?.style?.height);
}
}
if (presentationContainer && presentation) {
calcPresOffset();
}
} }
if (banners) { const posX = type === 'touchmove' ? event.changedTouches[0].clientX : x;
banners.forEach((el) => { const posY = type === 'touchmove' ? event.changedTouches[0].clientY : y;
yOffset += parseFloat(window.getComputedStyle(el).height);
}); if (type === 'touchmove' && !active) {
setActive(true);
} }
return setPos({ x: event.x - xOffset, y: event.y - yOffset }); setOverlayPosition();
return setPos({ x: posX - xOffset, y: posY - yOffset });
}; };
React.useEffect(() => { React.useEffect(() => {
@ -231,7 +239,7 @@ const Cursors = (props) => {
return () => { return () => {
currentCursor?.removeEventListener('mouseenter', start); currentCursor?.removeEventListener('mouseenter', start);
currentCursor?.addEventListener('touchstart', start); currentCursor?.removeEventListener('touchstart', start);
currentCursor?.removeEventListener('mouseleave', end); currentCursor?.removeEventListener('mouseleave', end);
currentCursor?.removeEventListener('mousedown', handleGrabbing); currentCursor?.removeEventListener('mousedown', handleGrabbing);
currentCursor?.removeEventListener('mouseup', handleReleaseGrab); currentCursor?.removeEventListener('mouseup', handleReleaseGrab);