diff --git a/packages/kbn-grid-layout/grid/grid_panel/drag_handle.tsx b/packages/kbn-grid-layout/grid/grid_panel/drag_handle.tsx index f175cf227a7e5..4554ebc6d7908 100644 --- a/packages/kbn-grid-layout/grid/grid_panel/drag_handle.tsx +++ b/packages/kbn-grid-layout/grid/grid_panel/drag_handle.tsx @@ -13,7 +13,13 @@ import { EuiIcon, useEuiTheme } from '@elastic/eui'; import { css } from '@emotion/react'; import { euiThemeVars } from '@kbn/ui-theme'; import { i18n } from '@kbn/i18n'; -import { GridLayoutStateManager, PanelInteractionEvent } from '../types'; +import { + GridLayoutStateManager, + PanelInteractionEvent, + UserInteractionEvent, + UserMouseEvent, + UserTouchEvent, +} from '../types'; export interface DragHandleApi { setDragHandles: (refs: Array) => void; @@ -25,7 +31,7 @@ export const DragHandle = React.forwardRef< gridLayoutStateManager: GridLayoutStateManager; interactionStart: ( type: PanelInteractionEvent['type'] | 'drop', - e: MouseEvent | React.MouseEvent + e: UserInteractionEvent ) => void; } >(({ gridLayoutStateManager, interactionStart }, ref) => { @@ -36,11 +42,11 @@ export const DragHandle = React.forwardRef< const dragHandleRefs = useRef>([]); /** - * We need to memoize the `onMouseDown` callback so that we don't assign a new `onMouseDown` event handler + * We need to memoize the `onMouseDown`, `onTouchStart` and `onTouchEnd` callbacks so that we don't assign a new event handler * every time `setDragHandles` is called */ const onMouseDown = useCallback( - (e: MouseEvent | React.MouseEvent) => { + (e: UserMouseEvent) => { if (gridLayoutStateManager.accessMode$.getValue() !== 'EDIT' || e.button !== 0) { // ignore anything but left clicks, and ignore clicks when not in edit mode return; @@ -50,25 +56,46 @@ export const DragHandle = React.forwardRef< }, [interactionStart, gridLayoutStateManager.accessMode$] ); + const onTouchStart = useCallback( + (e: UserTouchEvent) => { + e.stopPropagation(); + interactionStart('drag', e); + }, + [interactionStart] + ); + const onTouchEnd = useCallback( + (e: UserTouchEvent) => { + e.stopPropagation(); + interactionStart('drop', e); + }, + [interactionStart] + ); const setDragHandles = useCallback( (dragHandles: Array) => { + if (gridLayoutStateManager.accessMode$.getValue() !== 'EDIT') { + return; + } setDragHandleCount(dragHandles.length); dragHandleRefs.current = dragHandles; for (const handle of dragHandles) { if (handle === null) return; handle.addEventListener('mousedown', onMouseDown, { passive: true }); + handle.addEventListener('touchstart', onTouchStart, { passive: false }); + handle.addEventListener('touchend', onTouchEnd, { passive: true }); } removeEventListenersRef.current = () => { for (const handle of dragHandles) { if (handle === null) return; handle.removeEventListener('mousedown', onMouseDown); + handle.removeEventListener('touchstart', onTouchStart); + handle.removeEventListener('touchend', onTouchEnd); } }; }, - [onMouseDown] + [onMouseDown, onTouchStart, onTouchEnd, gridLayoutStateManager.accessMode$] ); useEffect(() => { @@ -125,12 +152,12 @@ export const DragHandle = React.forwardRef< display: none; } `} - onMouseDown={(e) => { - interactionStart('drag', e); - }} + onMouseDown={onMouseDown} onMouseUp={(e) => { interactionStart('drop', e); }} + onTouchStart={onTouchStart} + onTouchEnd={onTouchEnd} > diff --git a/packages/kbn-grid-layout/grid/grid_panel/grid_panel.tsx b/packages/kbn-grid-layout/grid/grid_panel/grid_panel.tsx index c30e6ecc996eb..5d56827514356 100644 --- a/packages/kbn-grid-layout/grid/grid_panel/grid_panel.tsx +++ b/packages/kbn-grid-layout/grid/grid_panel/grid_panel.tsx @@ -13,7 +13,7 @@ import { combineLatest, skip } from 'rxjs'; import { css } from '@emotion/react'; import { euiThemeVars } from '@kbn/ui-theme'; -import { GridLayoutStateManager, PanelInteractionEvent } from '../types'; +import { GridLayoutStateManager, UserInteractionEvent, PanelInteractionEvent } from '../types'; import { getKeysInOrder } from '../utils/resolve_grid_row'; import { DragHandle, DragHandleApi } from './drag_handle'; import { ResizeHandle } from './resize_handle'; @@ -25,10 +25,7 @@ export interface GridPanelProps { panelId: string, setDragHandles?: (refs: Array) => void ) => React.ReactNode; - interactionStart: ( - type: PanelInteractionEvent['type'] | 'drop', - e: MouseEvent | React.MouseEvent - ) => void; + interactionStart: (type: PanelInteractionEvent['type'] | 'drop', e: UserInteractionEvent) => void; gridLayoutStateManager: GridLayoutStateManager; } diff --git a/packages/kbn-grid-layout/grid/grid_panel/resize_handle.tsx b/packages/kbn-grid-layout/grid/grid_panel/resize_handle.tsx index ffee2f2764ed0..62db1c8eb86be 100644 --- a/packages/kbn-grid-layout/grid/grid_panel/resize_handle.tsx +++ b/packages/kbn-grid-layout/grid/grid_panel/resize_handle.tsx @@ -12,15 +12,12 @@ import { css } from '@emotion/react'; import { i18n } from '@kbn/i18n'; import { euiThemeVars } from '@kbn/ui-theme'; import React from 'react'; -import { PanelInteractionEvent } from '../types'; +import { UserInteractionEvent, PanelInteractionEvent } from '../types'; export const ResizeHandle = ({ interactionStart, }: { - interactionStart: ( - type: PanelInteractionEvent['type'] | 'drop', - e: MouseEvent | React.MouseEvent - ) => void; + interactionStart: (type: PanelInteractionEvent['type'] | 'drop', e: UserInteractionEvent) => void; }) => { return (