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) {