@cloudscape-design/board-components 3.0.110 → 3.0.112

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/board/styles.css.js +5 -5
  2. package/board/styles.scoped.css +8 -8
  3. package/board/styles.selectors.js +5 -5
  4. package/board-item/interfaces.d.ts +4 -0
  5. package/board-item/interfaces.js.map +1 -1
  6. package/board-item/internal.d.ts +1 -1
  7. package/board-item/internal.js +18 -2
  8. package/board-item/internal.js.map +1 -1
  9. package/board-item/styles.css.js +11 -11
  10. package/board-item/styles.scoped.css +13 -15
  11. package/board-item/styles.selectors.js +11 -11
  12. package/internal/api-docs/components/board-item.js +11 -1
  13. package/internal/drag-handle/index.d.ts +7 -2
  14. package/internal/drag-handle/index.js +10 -4
  15. package/internal/drag-handle/index.js.map +1 -1
  16. package/internal/drag-handle/styles.css.js +2 -2
  17. package/internal/drag-handle/styles.scoped.css +13 -22
  18. package/internal/drag-handle/styles.selectors.js +2 -2
  19. package/internal/{handle → drag-handle/test-classes}/styles.css.js +1 -1
  20. package/internal/drag-handle/test-classes/styles.scoped.css +7 -0
  21. package/internal/{handle → drag-handle/test-classes}/styles.selectors.js +1 -1
  22. package/internal/environment.js +1 -1
  23. package/internal/environment.json +1 -1
  24. package/internal/generated/styles/tokens.js +222 -222
  25. package/internal/generated/theming/index.cjs +232 -232
  26. package/internal/generated/theming/index.cjs.d.ts +2 -2
  27. package/internal/generated/theming/index.d.ts +2 -2
  28. package/internal/generated/theming/index.js +232 -232
  29. package/internal/global-drag-state-styles/index.js +8 -3
  30. package/internal/global-drag-state-styles/index.js.map +1 -1
  31. package/internal/item-container/index.d.ts +67 -5
  32. package/internal/item-container/index.js +147 -118
  33. package/internal/item-container/index.js.map +1 -1
  34. package/internal/item-container/utils.d.ts +37 -0
  35. package/internal/item-container/utils.js +63 -0
  36. package/internal/item-container/utils.js.map +1 -0
  37. package/internal/manifest.json +1 -1
  38. package/internal/resize-handle/index.d.ts +6 -2
  39. package/internal/resize-handle/index.js +10 -4
  40. package/internal/resize-handle/index.js.map +1 -1
  41. package/internal/resize-handle/styles.css.js +2 -2
  42. package/internal/resize-handle/styles.scoped.css +13 -22
  43. package/internal/resize-handle/styles.selectors.js +2 -2
  44. package/internal/resize-handle/test-classes/styles.css.js +6 -0
  45. package/internal/resize-handle/test-classes/styles.scoped.css +7 -0
  46. package/internal/resize-handle/test-classes/styles.selectors.js +7 -0
  47. package/package.json +1 -1
  48. package/internal/handle/index.d.ts +0 -3
  49. package/internal/handle/index.js +0 -18
  50. package/internal/handle/index.js.map +0 -1
  51. package/internal/handle/styles.scoped.css +0 -15
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/internal/global-drag-state-styles/index.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sCAAsC;AACtC,OAAO,EAAmB,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEpF,OAAO,MAAM,MAAM,iBAAiB,CAAC;AAErC,SAAS,WAAW,CAAC,KAAY;IAC/B,MAAM,IAAI,KAAK,CAAC,oBAAoB,GAAG,KAAK,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,KAAK,CAAC,EAAE,SAAS,EAAE,eAAe,EAAmB;IAC5D,QAAQ,SAAS,EAAE;QACjB,KAAK,QAAQ,CAAC;QACd,KAAK,SAAS;YACZ,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC;YACxD,MAAM;QACR,KAAK,QAAQ;YACX,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAC;YAC1D,MAAM;QACR;YACE,oEAAoE;YACpE,WAAW,CAAC,SAAS,CAAC,CAAC;KAC1B;IAED,IAAI,eAAe,KAAK,SAAS,EAAE;QACjC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC;KAC1D;AACH,CAAC;AAED,SAAS,QAAQ;IACf,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC;AACxH,CAAC;AAED,MAAM,UAAU,wBAAwB;IACtC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACpC,mBAAmB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IACzC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC1C,CAAC","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nimport { DragAndDropData, useDragSubscription } from \"../dnd-controller/controller\";\n\nimport styles from \"./styles.css.js\";\n\nfunction assertNever(value: never) {\n throw new Error(\"Unexpected value: \" + value);\n}\n\nfunction setup({ operation, interactionType }: DragAndDropData) {\n switch (operation) {\n case \"insert\":\n case \"reorder\":\n document.body.classList.add(styles[\"show-grab-cursor\"]);\n break;\n case \"resize\":\n document.body.classList.add(styles[\"show-resize-cursor\"]);\n break;\n default:\n // there will be a type error if not all operation types are handled\n assertNever(operation);\n }\n\n if (interactionType === \"pointer\") {\n document.body.classList.add(styles[\"disable-selection\"]);\n }\n}\n\nfunction teardown() {\n document.body.classList.remove(styles[\"show-grab-cursor\"], styles[\"show-resize-cursor\"], styles[\"disable-selection\"]);\n}\n\nexport function useGlobalDragStateStyles() {\n useDragSubscription(\"start\", setup);\n useDragSubscription(\"discard\", teardown);\n useDragSubscription(\"submit\", teardown);\n}\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/internal/global-drag-state-styles/index.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,sCAAsC;AACtC,OAAO,EAAmB,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEpF,OAAO,MAAM,MAAM,iBAAiB,CAAC;AAErC,SAAS,WAAW,CAAC,KAAY;IAC/B,MAAM,IAAI,KAAK,CAAC,oBAAoB,GAAG,KAAK,CAAC,CAAC;AAChD,CAAC;AAED,SAAS,KAAK,CAAC,EAAE,SAAS,EAAE,eAAe,EAAmB;IAC5D,MAAM,oBAAoB,GAAG,eAAe,KAAK,SAAS,CAAC;IAC3D,QAAQ,SAAS,EAAE;QACjB,KAAK,QAAQ,CAAC;QACd,KAAK,SAAS;YACZ,IAAI,oBAAoB,EAAE;gBACxB,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,kBAAkB,CAAC,CAAC,CAAC;aACzD;YACD,MAAM;QACR,KAAK,QAAQ;YACX,IAAI,oBAAoB,EAAE;gBACxB,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,oBAAoB,CAAC,CAAC,CAAC;aAC3D;YACD,MAAM;QACR;YACE,oEAAoE;YACpE,WAAW,CAAC,SAAS,CAAC,CAAC;KAC1B;IAED,IAAI,oBAAoB,EAAE;QACxB,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC;KAC1D;AACH,CAAC;AAED,SAAS,QAAQ;IACf,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC,EAAE,MAAM,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC,mBAAmB,CAAC,CAAC,CAAC;AACxH,CAAC;AAED,MAAM,UAAU,wBAAwB;IACtC,mBAAmB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACpC,mBAAmB,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IACzC,mBAAmB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC1C,CAAC","sourcesContent":["// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.\n// SPDX-License-Identifier: Apache-2.0\nimport { DragAndDropData, useDragSubscription } from \"../dnd-controller/controller\";\n\nimport styles from \"./styles.css.js\";\n\nfunction assertNever(value: never) {\n throw new Error(\"Unexpected value: \" + value);\n}\n\nfunction setup({ operation, interactionType }: DragAndDropData) {\n const isPointerInteraction = interactionType === \"pointer\";\n switch (operation) {\n case \"insert\":\n case \"reorder\":\n if (isPointerInteraction) {\n document.body.classList.add(styles[\"show-grab-cursor\"]);\n }\n break;\n case \"resize\":\n if (isPointerInteraction) {\n document.body.classList.add(styles[\"show-resize-cursor\"]);\n }\n break;\n default:\n // there will be a type error if not all operation types are handled\n assertNever(operation);\n }\n\n if (isPointerInteraction) {\n document.body.classList.add(styles[\"disable-selection\"]);\n }\n}\n\nfunction teardown() {\n document.body.classList.remove(styles[\"show-grab-cursor\"], styles[\"show-resize-cursor\"], styles[\"disable-selection\"]);\n}\n\nexport function useGlobalDragStateStyles() {\n useDragSubscription(\"start\", setup);\n useDragSubscription(\"discard\", teardown);\n useDragSubscription(\"submit\", teardown);\n}\n"]}
@@ -1,23 +1,84 @@
1
1
  import { KeyboardEvent, PointerEvent as ReactPointerEvent, ReactNode, RefObject } from "react";
2
- import { DropTargetContext } from "../dnd-controller/controller";
3
- import { BoardItemDefinitionBase, Direction, Transform } from "../interfaces";
2
+ import { DropTargetContext, InteractionType, Operation } from "../dnd-controller/controller";
3
+ import { BoardItemDefinitionBase, Direction, ItemId, Transform } from "../interfaces";
4
4
  export interface ItemContainerRef {
5
5
  focusDragHandle(): void;
6
6
  }
7
+ export type HandleActiveState = null | "pointer" | "uap";
7
8
  interface ItemContextType {
9
+ /**
10
+ * Flag indicating if a drag or resize interaction is currently active.
11
+ */
8
12
  isActive: boolean;
13
+ /**
14
+ * Flag indicating if the item is currently hidden.
15
+ * (When a board item is moved from the palette to the board and the transition is not submitted)
16
+ */
17
+ isHidden: boolean;
9
18
  dragHandle: {
10
- ref: RefObject<HTMLButtonElement>;
19
+ /**
20
+ * Ref to the drag button. Used to focus the drag handle when moving an item
21
+ * from the palette to the board via keyboard or UAP actions.
22
+ */
23
+ ref: RefObject<HTMLDivElement>;
24
+ /**
25
+ * Listen to pointerDown events on the drag handle.
26
+ * Used to start a transition and attach global event handlers.
27
+ */
11
28
  onPointerDown(event: ReactPointerEvent): void;
29
+ /**
30
+ * Listen to keyDown events on the drag handle.
31
+ */
12
32
  onKeyDown(event: KeyboardEvent): void;
13
- isActive: boolean;
33
+ /**
34
+ * Indicating if drag handle is active.
35
+ */
36
+ activeState: HandleActiveState;
37
+ /**
38
+ * Listen to UAP direction button clicks.
39
+ */
40
+ onDirectionClick(direction: KeyboardEvent["key"], operation: HandleOperation): void;
41
+ /**
42
+ * Flag indicating if the UAP buttons should be shown. E.g. when a item is moved from
43
+ * the palette via keyboard or UAP to the board.
44
+ */
45
+ initialShowButtons?: boolean;
14
46
  };
15
47
  resizeHandle: null | {
48
+ /**
49
+ * Listen to pointerDown events on the drag handle.
50
+ * Used to start a transition and attach global event handlers.
51
+ */
16
52
  onPointerDown(event: ReactPointerEvent): void;
53
+ /**
54
+ * Listen to keyDown events on the drag handle.
55
+ */
17
56
  onKeyDown(event: KeyboardEvent): void;
18
- isActive: boolean;
57
+ /**
58
+ * Indicating if resize handle is active.
59
+ */
60
+ activeState: HandleActiveState;
61
+ /**
62
+ * Listen to UAP direction button clicks.
63
+ */
64
+ onDirectionClick(direction: KeyboardEvent["key"], operation: HandleOperation): void;
19
65
  };
20
66
  }
67
+ export interface Transition {
68
+ itemId: ItemId;
69
+ operation: Operation;
70
+ interactionType: InteractionType;
71
+ sizeTransform: null | {
72
+ width: number;
73
+ height: number;
74
+ };
75
+ positionTransform: null | {
76
+ x: number;
77
+ y: number;
78
+ };
79
+ hasDropTarget?: boolean;
80
+ }
81
+ export type HandleOperation = "drag" | "resize";
21
82
  export declare const ItemContext: import("react").Context<ItemContextType | null>;
22
83
  export declare function useItemContext(): ItemContextType;
23
84
  /**
@@ -50,4 +111,5 @@ export interface ItemContainerProps {
50
111
  isRtl: () => boolean;
51
112
  }
52
113
  export declare const ItemContainer: import("react").ForwardRefExoticComponent<ItemContainerProps & import("react").RefAttributes<ItemContainerRef>>;
114
+ export declare const CLICK_DRAG_THRESHOLD = 3;
53
115
  export {};
@@ -1,17 +1,19 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3
3
  // SPDX-License-Identifier: Apache-2.0
4
- import { createContext, forwardRef, useContext, useEffect, useImperativeHandle, useRef, useState, } from "react";
4
+ import { createContext, forwardRef, useContext, useImperativeHandle, useRef, useState, } from "react";
5
5
  import { createPortal } from "react-dom";
6
6
  import { CSS as CSSUtil } from "@dnd-kit/utilities";
7
7
  import clsx from "clsx";
8
- import { getLogicalBoundingClientRect, getLogicalClientX } from "@cloudscape-design/component-toolkit/internal";
8
+ import { getLogicalBoundingClientRect } from "@cloudscape-design/component-toolkit/internal";
9
+ import { useInternalDragHandleInteractionState, } from "@cloudscape-design/components/internal/do-not-use/drag-handle";
9
10
  import { useDraggable, useDragSubscription, } from "../dnd-controller/controller";
10
11
  import { Coordinates } from "../utils/coordinates";
11
12
  import { getNormalizedElementRect } from "../utils/screen";
12
13
  import { throttle } from "../utils/throttle";
13
14
  import { getCollisionRect } from "./get-collision-rect";
14
15
  import { getNextDroppable } from "./get-next-droppable";
16
+ import { calculateInitialPointerData, determineHandleActiveState, getDndOperationType, hasPointerMovedBeyondThreshold, } from "./utils";
15
17
  import styles from "./styles.css.js";
16
18
  export const ItemContext = createContext(null);
17
19
  export function useItemContext() {
@@ -22,8 +24,13 @@ export function useItemContext() {
22
24
  return ctx;
23
25
  }
24
26
  export const ItemContainer = forwardRef(ItemContainerComponent);
27
+ // The amount of distance after pointer down that the cursor is allowed to
28
+ // jitter for a subsequent mouseup to still register as a "press" instead of
29
+ // a drag. A little allowance is needed for usability reasons, but this number
30
+ // isn't set in stone.
31
+ export const CLICK_DRAG_THRESHOLD = 3;
25
32
  function ItemContainerComponent({ item, placed, acquired, inTransition, transform, getItemSize, onKeyMove, children, isRtl }, ref) {
26
- var _a, _b, _c, _d, _e, _f;
33
+ var _a, _b, _c, _d;
27
34
  const originalSizeRef = useRef({ width: 0, height: 0 });
28
35
  const pointerOffsetRef = useRef(new Coordinates({ x: 0, y: 0 }));
29
36
  const pointerBoundariesRef = useRef(null);
@@ -31,6 +38,7 @@ function ItemContainerComponent({ item, placed, acquired, inTransition, transfor
31
38
  const [isHidden, setIsHidden] = useState(false);
32
39
  const muteEventsRef = useRef(false);
33
40
  const itemRef = useRef(null);
41
+ const initialPointerDownPosition = useRef();
34
42
  const draggableApi = useDraggable({
35
43
  draggableItem: item,
36
44
  getCollisionRect: (operation, coordinates, dropTarget) => {
@@ -78,70 +86,30 @@ function ItemContainerComponent({ item, placed, acquired, inTransition, transfor
78
86
  setIsHidden(false);
79
87
  muteEventsRef.current = false;
80
88
  });
81
- // During the transition listen to pointer move and pointer up events to update/submit transition.
82
- const transitionInteractionType = (_a = transition === null || transition === void 0 ? void 0 : transition.interactionType) !== null && _a !== void 0 ? _a : null;
83
- const transitionItemId = (_b = transition === null || transition === void 0 ? void 0 : transition.itemId) !== null && _b !== void 0 ? _b : null;
84
- useEffect(() => {
85
- const onPointerMove = throttle((event) => {
86
- var _a, _b, _c, _d;
87
- const coordinates = Coordinates.fromEvent(event, { isRtl: isRtl() });
88
- draggableApi.updateTransition(new Coordinates({
89
- x: Math.max(coordinates.x, (_b = (_a = pointerBoundariesRef.current) === null || _a === void 0 ? void 0 : _a.x) !== null && _b !== void 0 ? _b : Number.NEGATIVE_INFINITY),
90
- y: Math.max(coordinates.y, (_d = (_c = pointerBoundariesRef.current) === null || _c === void 0 ? void 0 : _c.y) !== null && _d !== void 0 ? _d : Number.NEGATIVE_INFINITY),
91
- }));
92
- }, 10);
93
- const onPointerUp = () => {
94
- onPointerMove.cancel();
95
- draggableApi.submitTransition();
96
- };
97
- if (transitionInteractionType === "pointer" && transitionItemId === item.id) {
98
- window.addEventListener("pointermove", onPointerMove);
99
- window.addEventListener("pointerup", onPointerUp);
100
- }
101
- return () => {
102
- window.removeEventListener("pointermove", onPointerMove);
103
- window.removeEventListener("pointerup", onPointerUp);
104
- };
105
- // draggableApi is not expected to change
106
- // eslint-disable-next-line react-hooks/exhaustive-deps
107
- }, [item.id, transitionInteractionType, transitionItemId]);
108
- useEffect(() => {
109
- if (transitionInteractionType === "keyboard" && transitionItemId === item.id) {
110
- const onPointerDown = () => draggableApi.submitTransition();
111
- window.addEventListener("pointerdown", onPointerDown, true);
112
- return () => {
113
- window.removeEventListener("pointerdown", onPointerDown, true);
114
- };
115
- }
116
- // draggableApi is not expected to change
117
- // eslint-disable-next-line react-hooks/exhaustive-deps
118
- }, [item.id, transitionInteractionType, transitionItemId]);
119
- function onKeyboardTransitionToggle(operation) {
89
+ // Handles incremental transition logic shared between different keyboard and UAP interactions.
90
+ function handleIncrementalTransition(operation, submitExisting = false) {
120
91
  // The acquired item is a copy and does not have the transition state.
121
92
  // However, pressing "Space" or "Enter" on the acquired item must submit the active transition.
122
93
  if (acquired) {
123
94
  return draggableApi.submitTransition();
124
95
  }
125
- // Create new transition if missing.
126
- if (!transition) {
127
- const rect = getNormalizedElementRect(itemRef.current);
128
- const coordinates = new Coordinates({
129
- x: operation === "drag" ? rect.left : rect.right,
130
- y: operation === "drag" ? rect.top : rect.bottom,
131
- });
132
- if (operation === "drag" && !placed) {
133
- draggableApi.start("insert", "keyboard", coordinates);
134
- }
135
- else if (operation === "drag") {
136
- draggableApi.start("reorder", "keyboard", coordinates);
137
- }
138
- else {
139
- draggableApi.start("resize", "keyboard", coordinates);
140
- }
96
+ // Submit existing transition if requested and one exists
97
+ if (submitExisting && transition) {
98
+ return draggableApi.submitTransition();
99
+ }
100
+ const rect = getNormalizedElementRect(itemRef.current);
101
+ const coordinates = new Coordinates({
102
+ x: operation === "drag" ? rect.left : rect.right,
103
+ y: operation === "drag" ? rect.top : rect.bottom,
104
+ });
105
+ if (operation === "drag" && !placed) {
106
+ draggableApi.start("insert", "keyboard", coordinates);
107
+ }
108
+ else if (operation === "drag") {
109
+ draggableApi.start("reorder", "keyboard", coordinates);
141
110
  }
142
- // Submit a transition if existing.
143
111
  else {
144
- draggableApi.submitTransition();
112
+ draggableApi.start("resize", "keyboard", coordinates);
145
113
  }
146
114
  }
147
115
  function handleInsert(direction) {
@@ -165,18 +133,17 @@ function ItemContainerComponent({ item, placed, acquired, inTransition, transfor
165
133
  setIsHidden(true);
166
134
  muteEventsRef.current = true;
167
135
  }
168
- function onHandleKeyDown(operation, event) {
136
+ function handleDirectionalMovement(direction, operation) {
169
137
  const canInsert = transition && operation === "drag" && !placed;
170
138
  const canNavigate = transition || operation === "drag";
171
- // The insert is handled by the item and the navigation is delegated to the containing layout.
172
- const move = (direction) => {
173
- if (canInsert) {
174
- handleInsert(direction);
175
- }
176
- else if (canNavigate) {
177
- onKeyMove === null || onKeyMove === void 0 ? void 0 : onKeyMove(direction);
178
- }
179
- };
139
+ if (canInsert) {
140
+ handleInsert(direction);
141
+ }
142
+ else if (canNavigate) {
143
+ onKeyMove === null || onKeyMove === void 0 ? void 0 : onKeyMove(direction);
144
+ }
145
+ }
146
+ function onHandleKeyDown(operation, event) {
180
147
  const discard = () => {
181
148
  if (transition || acquired) {
182
149
  draggableApi.discardTransition();
@@ -184,16 +151,16 @@ function ItemContainerComponent({ item, placed, acquired, inTransition, transfor
184
151
  };
185
152
  switch (event.key) {
186
153
  case "ArrowUp":
187
- return move("up");
154
+ return handleDirectionalMovement("up", operation);
188
155
  case "ArrowDown":
189
- return move("down");
156
+ return handleDirectionalMovement("down", operation);
190
157
  case "ArrowLeft":
191
- return move("left");
158
+ return handleDirectionalMovement("left", operation);
192
159
  case "ArrowRight":
193
- return move("right");
160
+ return handleDirectionalMovement("right", operation);
194
161
  case " ":
195
162
  case "Enter":
196
- return onKeyboardTransitionToggle(operation);
163
+ return handleIncrementalTransition(operation, true);
197
164
  case "Escape":
198
165
  return discard();
199
166
  }
@@ -202,45 +169,72 @@ function ItemContainerComponent({ item, placed, acquired, inTransition, transfor
202
169
  // When drag- or resize handle on palette or board item loses focus the transition must be submitted with two exceptions:
203
170
  // 1. If the last interaction is not "keyboard" (the user clicked on another handle issuing a new transition);
204
171
  // 2. If the item is acquired by the board (in that case the focus moves to the board item which is expected, palette item is hidden and all events handlers must be muted).
205
- if (transition && transition.interactionType === "keyboard" && !muteEventsRef.current) {
172
+ selectedHook.current.processBlur();
173
+ initialPointerDownPosition.current = undefined;
174
+ if (acquired || (transition && transition.interactionType === "keyboard" && !muteEventsRef.current)) {
206
175
  draggableApi.submitTransition();
207
176
  }
208
177
  }
209
- function onDragHandlePointerDown(event) {
210
- // Calculate the offset between item's top-left corner and the pointer landing position.
211
- const rect = getLogicalBoundingClientRect(itemRef.current);
212
- const clientX = getLogicalClientX(event, isRtl());
213
- const clientY = event.clientY;
214
- pointerOffsetRef.current = new Coordinates({
215
- x: clientX - rect.insetInlineStart,
216
- y: clientY - rect.insetBlockStart,
217
- });
218
- originalSizeRef.current = { width: rect.inlineSize, height: rect.blockSize };
219
- pointerBoundariesRef.current = null;
220
- draggableApi.start(!placed ? "insert" : "reorder", "pointer", Coordinates.fromEvent(event, { isRtl: isRtl() }));
178
+ function handleGlobalPointerMove(event) {
179
+ if (hasPointerMovedBeyondThreshold(event, initialPointerDownPosition.current)) {
180
+ selectedHook.current.processPointerMove(event);
181
+ }
221
182
  }
222
- function onDragHandleKeyDown(event) {
223
- onHandleKeyDown("drag", event);
183
+ function handleGlobalPointerUp(event) {
184
+ selectedHook.current.processPointerUp(event);
185
+ initialPointerDownPosition.current = undefined;
186
+ // Clean up global listeners after interaction ends
187
+ window.removeEventListener("pointermove", handleGlobalPointerMove);
188
+ window.removeEventListener("pointerup", handleGlobalPointerUp);
189
+ }
190
+ function onDragHandlePointerDown(event, operation) {
191
+ // Prevent UI issues when right-clicking: in such a case the OS context menu will be shown and
192
+ // the board while the board-item is active. Because of the context menu under the pointer,
193
+ // onPointerUp is not called anymore. In such a case the board item would stuck in onPointerUp.
194
+ if (event.button !== 0) {
195
+ return;
196
+ }
197
+ initialPointerDownPosition.current = { x: event.clientX, y: event.clientY };
198
+ if (operation === "drag") {
199
+ selectedHook.current = dragInteractionHook;
200
+ }
201
+ else {
202
+ selectedHook.current = resizeInteractionHook;
203
+ }
204
+ selectedHook.current.processPointerDown(event.nativeEvent);
205
+ // If pointerdown is on our button, start listening for global move and up
206
+ window.addEventListener("pointermove", handleGlobalPointerMove);
207
+ window.addEventListener("pointerup", handleGlobalPointerUp);
224
208
  }
225
- function onResizeHandlePointerDown(event) {
226
- // Calculate the offset between item's bottom-right corner and the pointer landing position.
227
- const rect = getLogicalBoundingClientRect(itemRef.current);
228
- const clientX = getLogicalClientX(event, isRtl());
229
- const clientY = event.clientY;
230
- pointerOffsetRef.current = new Coordinates({ x: clientX - rect.insetInlineEnd, y: clientY - rect.insetBlockEnd });
209
+ function handlePointerInteractionStart(event, operation) {
210
+ const currentItemElement = itemRef.current;
211
+ if (!currentItemElement) {
212
+ console.warn("ItemContainer: itemRef.current is not available on interaction start.");
213
+ return;
214
+ }
215
+ const rect = getLogicalBoundingClientRect(currentItemElement);
231
216
  originalSizeRef.current = { width: rect.inlineSize, height: rect.blockSize };
232
- // Calculate boundaries below which the cursor cannot move.
233
- const minWidth = getItemSize(null).minWidth;
234
- const minHeight = getItemSize(null).minHeight;
235
- pointerBoundariesRef.current = new Coordinates({
236
- x: clientX - rect.inlineSize + minWidth,
237
- y: clientY - rect.blockSize + minHeight,
217
+ const { pointerOffset, pointerBoundaries } = calculateInitialPointerData({
218
+ event,
219
+ operation,
220
+ rect,
221
+ getMinSize: () => getItemSize(null),
222
+ isRtl: isRtl(),
238
223
  });
239
- draggableApi.start("resize", "pointer", Coordinates.fromEvent(event, { isRtl: isRtl() }));
240
- }
241
- function onResizeHandleKeyDown(event) {
242
- onHandleKeyDown("resize", event);
224
+ pointerOffsetRef.current = pointerOffset;
225
+ pointerBoundariesRef.current = pointerBoundaries;
226
+ const dndOperation = getDndOperationType(operation, placed);
227
+ const startCoordinates = Coordinates.fromEvent(event, { isRtl: isRtl() });
228
+ draggableApi.start(dndOperation, "pointer", startCoordinates);
243
229
  }
230
+ const onHandleDndTransitionActive = throttle((event) => {
231
+ var _a, _b, _c, _d;
232
+ const coordinates = Coordinates.fromEvent(event, { isRtl: isRtl() });
233
+ draggableApi.updateTransition(new Coordinates({
234
+ x: Math.max(coordinates.x, (_b = (_a = pointerBoundariesRef.current) === null || _a === void 0 ? void 0 : _a.x) !== null && _b !== void 0 ? _b : Number.NEGATIVE_INFINITY),
235
+ y: Math.max(coordinates.y, (_d = (_c = pointerBoundariesRef.current) === null || _c === void 0 ? void 0 : _c.y) !== null && _d !== void 0 ? _d : Number.NEGATIVE_INFINITY),
236
+ }));
237
+ }, 10);
244
238
  const itemTransitionStyle = {};
245
239
  const itemTransitionClassNames = [];
246
240
  if (inTransition) {
@@ -249,10 +243,10 @@ function ItemContainerComponent({ item, placed, acquired, inTransition, transfor
249
243
  if (transition && transition.interactionType === "pointer") {
250
244
  // Adjust the dragged/resized item to the pointer's location.
251
245
  itemTransitionClassNames.push(transition.operation === "resize" ? styles.resized : styles.dragged);
252
- itemTransitionStyle.insetInlineStart = (_c = transition.positionTransform) === null || _c === void 0 ? void 0 : _c.x;
253
- itemTransitionStyle.insetBlockStart = (_d = transition.positionTransform) === null || _d === void 0 ? void 0 : _d.y;
254
- itemTransitionStyle.inlineSize = (_e = transition.sizeTransform) === null || _e === void 0 ? void 0 : _e.width;
255
- itemTransitionStyle.blockSize = (_f = transition.sizeTransform) === null || _f === void 0 ? void 0 : _f.height;
246
+ itemTransitionStyle.insetInlineStart = (_a = transition.positionTransform) === null || _a === void 0 ? void 0 : _a.x;
247
+ itemTransitionStyle.insetBlockStart = (_b = transition.positionTransform) === null || _b === void 0 ? void 0 : _b.y;
248
+ itemTransitionStyle.inlineSize = (_c = transition.sizeTransform) === null || _c === void 0 ? void 0 : _c.width;
249
+ itemTransitionStyle.blockSize = (_d = transition.sizeTransform) === null || _d === void 0 ? void 0 : _d.height;
256
250
  itemTransitionStyle.pointerEvents = "none";
257
251
  }
258
252
  if (isHidden) {
@@ -279,27 +273,62 @@ function ItemContainerComponent({ item, placed, acquired, inTransition, transfor
279
273
  }
280
274
  const dragHandleRef = useRef(null);
281
275
  useImperativeHandle(ref, () => ({
282
- focusDragHandle: () => { var _a; return (_a = dragHandleRef.current) === null || _a === void 0 ? void 0 : _a.focus(); },
276
+ focusDragHandle: () => {
277
+ var _a;
278
+ return (_a = dragHandleRef.current) === null || _a === void 0 ? void 0 : _a.focus();
279
+ },
283
280
  }));
281
+ const dragHookProps = {
282
+ onDndStartAction: (event) => handlePointerInteractionStart(event, "drag"),
283
+ onDndActiveAction: onHandleDndTransitionActive,
284
+ onDndEndAction: () => transition && draggableApi.submitTransition(),
285
+ onUapActionStartAction: () => handleIncrementalTransition("drag"),
286
+ };
287
+ const resizeHookProps = {
288
+ onDndStartAction: (event) => handlePointerInteractionStart(event, "resize"),
289
+ onDndActiveAction: onHandleDndTransitionActive,
290
+ onDndEndAction: () => transition && draggableApi.submitTransition(),
291
+ onUapActionStartAction: () => handleIncrementalTransition("resize"),
292
+ };
293
+ const dragInteractionHook = useInternalDragHandleInteractionState(dragHookProps);
294
+ const resizeInteractionHook = useInternalDragHandleInteractionState(resizeHookProps);
295
+ // We use a ref to the hook for the handle which is currently active. Distinguishment is managed in the handle button's onPointerDown callback.
296
+ const selectedHook = useRef(dragInteractionHook);
284
297
  const isActive = (!!transition && !isHidden) || !!acquired;
285
- const shouldUsePortal = (transition === null || transition === void 0 ? void 0 : transition.operation) === "insert" && (transition === null || transition === void 0 ? void 0 : transition.interactionType) === "pointer";
298
+ const shouldUsePortal = (transition === null || transition === void 0 ? void 0 : transition.operation) === "insert" &&
299
+ (transition === null || transition === void 0 ? void 0 : transition.interactionType) === "pointer" &&
300
+ selectedHook.current.interaction.value === "dnd-active";
286
301
  const childrenRef = useRef(null);
287
302
  if (!inTransition || isActive) {
288
303
  childrenRef.current = children(!!(transition === null || transition === void 0 ? void 0 : transition.hasDropTarget));
289
304
  }
290
305
  const content = (_jsx("div", { ref: itemRef, className: clsx(styles.root, ...itemTransitionClassNames), style: itemTransitionStyle, "data-item-id": item.id, onBlur: onBlur, children: _jsx(ItemContext.Provider, { value: {
291
306
  isActive,
307
+ isHidden,
292
308
  dragHandle: {
293
309
  ref: dragHandleRef,
294
- onPointerDown: onDragHandlePointerDown,
295
- onKeyDown: onDragHandleKeyDown,
296
- isActive: isActive && (transition === null || transition === void 0 ? void 0 : transition.operation) === "reorder",
310
+ onPointerDown: (e) => onDragHandlePointerDown(e, "drag"),
311
+ onKeyDown: (event) => onHandleKeyDown("drag", event),
312
+ activeState: determineHandleActiveState({
313
+ isHandleActive: isActive,
314
+ currentTransition: transition,
315
+ interactionHookValue: dragInteractionHook.interaction.value,
316
+ targetOperation: "reorder",
317
+ }),
318
+ onDirectionClick: handleDirectionalMovement,
319
+ initialShowButtons: dragInteractionHook.interaction.value === "uap-action-start" || (inTransition && acquired),
297
320
  },
298
321
  resizeHandle: placed
299
322
  ? {
300
- onPointerDown: onResizeHandlePointerDown,
301
- onKeyDown: onResizeHandleKeyDown,
302
- isActive: isActive && (transition === null || transition === void 0 ? void 0 : transition.operation) === "resize",
323
+ onPointerDown: (e) => onDragHandlePointerDown(e, "resize"),
324
+ onKeyDown: (event) => onHandleKeyDown("resize", event),
325
+ activeState: determineHandleActiveState({
326
+ isHandleActive: isActive,
327
+ currentTransition: transition,
328
+ interactionHookValue: resizeInteractionHook.interaction.value,
329
+ targetOperation: "resize",
330
+ }),
331
+ onDirectionClick: handleDirectionalMovement,
303
332
  }
304
333
  : null,
305
334
  }, children: childrenRef.current }) }));