diff --git a/common/changes/@itwin/appui-layout-react/touch-fix_2024-01-23-14-22.json b/common/changes/@itwin/appui-layout-react/touch-fix_2024-01-23-14-22.json new file mode 100644 index 00000000000..2a2f2cad808 --- /dev/null +++ b/common/changes/@itwin/appui-layout-react/touch-fix_2024-01-23-14-22.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/appui-layout-react", + "comment": "Fix touch issue when dragging a widget with SVG icon.", + "type": "none" + } + ], + "packageName": "@itwin/appui-layout-react" +} \ No newline at end of file diff --git a/test-apps/appui-test-app/appui-test-providers/src/ui/providers/WidgetApiStageUiItemsProvider.tsx b/test-apps/appui-test-app/appui-test-providers/src/ui/providers/WidgetApiStageUiItemsProvider.tsx index ff843cb50de..5d25f8291bc 100644 --- a/test-apps/appui-test-app/appui-test-providers/src/ui/providers/WidgetApiStageUiItemsProvider.tsx +++ b/test-apps/appui-test-app/appui-test-providers/src/ui/providers/WidgetApiStageUiItemsProvider.tsx @@ -18,6 +18,14 @@ import { Widget, WidgetState, } from "@itwin/appui-react"; +import { + SvgTextAlignCenter, + SvgTextAlignJustify, + SvgTextAlignLeft, + SvgTextAlignRight, + SvgUser, + SvgUsers, +} from "@itwin/itwinui-icons-react"; import { getToggleCustomOverlayCommandItemDef, WidgetApiStage, @@ -135,7 +143,7 @@ export class WidgetApiStageUiItemsProvider implements UiItemsProvider { widgets.push({ id: "WR-A", label: "WR-A", - icon: "icon-text-align-text-align-left", + icon: , canPopout: true, defaultState: WidgetState.Open, content:

Right WR-A

, @@ -144,7 +152,7 @@ export class WidgetApiStageUiItemsProvider implements UiItemsProvider { widgets.push({ id: "WR-B", label: "WR-B", - icon: "icon-text-align-text-align-right", + icon: , canPopout: true, defaultState: WidgetState.Hidden, content:

Right WR-B

, @@ -153,14 +161,14 @@ export class WidgetApiStageUiItemsProvider implements UiItemsProvider { widgets.push({ id: "WR-1", label: "WR-1", - icon: "icon-text-align-text-align-center", + icon: , canPopout: false, content:

Right WR-1

, }); widgets.push({ id: "WR-2", label: "WR-2", - icon: "icon-text-align-text-align-justify", + icon: , defaultState: WidgetState.Open, canPopout: true, content:

Right WR-2

, @@ -169,14 +177,14 @@ export class WidgetApiStageUiItemsProvider implements UiItemsProvider { widgets.push({ id: "WR-3", label: "WR-3", - icon: "icon-user", + icon: , canPopout: true, content:

Right WR-3

, }); widgets.push({ id: "WR-4", label: "WR-4", - icon: "icon-users", + icon: , canPopout: true, defaultState: WidgetState.Open, content:

Right WR-4

, diff --git a/ui/appui-layout-react/src/appui-layout-react/base/usePointerCaptor.tsx b/ui/appui-layout-react/src/appui-layout-react/base/usePointerCaptor.tsx index b0ac4f5eef8..d0155c383e7 100644 --- a/ui/appui-layout-react/src/appui-layout-react/base/usePointerCaptor.tsx +++ b/ui/appui-layout-react/src/appui-layout-react/base/usePointerCaptor.tsx @@ -75,15 +75,18 @@ export const usePointerCaptor = ( isDown.current && dragManager.handleDragEnd(); isDown.current = false; touchTarget = null; - if (e.target instanceof HTMLElement) { - e.target.removeEventListener("touchmove", targetTouchMove); - e.target.removeEventListener("touchend", touchEnd); + if (e.target instanceof Element) { + e.target.removeEventListener( + "touchmove", + targetTouchMove as EventListener + ); + e.target.removeEventListener("touchend", touchEnd as EventListener); } document.removeEventListener("touchmove", documentTouchMove); document.removeEventListener("touchend", documentTouchEnd); }; const documentTouchEnd = (e: TouchEvent) => { - // Do not handle document touch move if it was handled by target handler. + // Do not handle document touch end if it was handled by target handler. if (touchTarget === e.target) return; touchEnd(e); }; @@ -92,11 +95,15 @@ export const usePointerCaptor = ( if (e.touches.length !== 1) return; touchTarget = e.target; // In case of implicit pointer capture attach to event target. - if (e.target instanceof HTMLElement) { - e.target.addEventListener("touchmove", targetTouchMove); - e.target.addEventListener("touchend", touchEnd); + if (e.target instanceof Element) { + e.target.addEventListener( + "touchmove", + targetTouchMove as EventListener + ); + e.target.addEventListener("touchend", touchEnd as EventListener); } - // Add to document in case the target looses capture (i.e. is removed) + + // Add to document in case the target loses capture (i.e. is removed) document.addEventListener("touchmove", documentTouchMove); document.addEventListener("touchend", documentTouchEnd); onPointerDown && onPointerDown(e.touches[0], e); diff --git a/ui/appui-layout-react/src/appui-layout-react/state/NineZoneStateReducer.ts b/ui/appui-layout-react/src/appui-layout-react/state/NineZoneStateReducer.ts index 8a77cfcc46c..12c714d1b72 100644 --- a/ui/appui-layout-react/src/appui-layout-react/state/NineZoneStateReducer.ts +++ b/ui/appui-layout-react/src/appui-layout-react/state/NineZoneStateReducer.ts @@ -494,6 +494,7 @@ export function NineZoneStateReducer( }); } case "WIDGET_TAB_DRAG_START": { + assert(!state.draggedTab); const tabId = action.id; let home: PanelWidgetRestoreState; if (action.floatingWidgetId) {