@pie-element/image-cloze-association 10.3.0-beta.0 → 10.3.0

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.
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.closestDroppableKeyboardCoordinates = void 0;
7
+ var _core = require("@dnd-kit/core");
8
+ /**
9
+ * Custom keyboard coordinate getter for image-cloze-association's Tab-based placement.
10
+ *
11
+ * Tab/Shift+Tab cycle the dragged answer directly onto the next/previous enabled
12
+ * droppable — a response container (`response-container-{index}`) or the choices pool
13
+ * (`ica-board`) — sorted by on-screen position (top-to-bottom, then left-to-right),
14
+ * since response containers are absolutely positioned over an image rather than laid
15
+ * out as a simple list.
16
+ *
17
+ * Arrow keys are delegated to dnd-kit's own `defaultKeyboardCoordinateGetter`, leaving
18
+ * the existing free-form arrow-key dragging behavior completely unchanged.
19
+ */
20
+ const closestDroppableKeyboardCoordinates = (event, {
21
+ context,
22
+ currentCoordinates
23
+ }) => {
24
+ const {
25
+ code
26
+ } = event;
27
+ const isTab = code === 'Tab';
28
+ const isArrow = code === _core.KeyboardCode.Down || code === _core.KeyboardCode.Up || code === _core.KeyboardCode.Left || code === _core.KeyboardCode.Right;
29
+ if (!isTab && !isArrow) {
30
+ return undefined;
31
+ }
32
+ if (isArrow) {
33
+ return (0, _core.defaultKeyboardCoordinateGetter)(event, {
34
+ context,
35
+ currentCoordinates
36
+ });
37
+ }
38
+ event.preventDefault();
39
+ const {
40
+ droppableRects,
41
+ droppableContainers,
42
+ collisionRect
43
+ } = context;
44
+ if (!droppableRects || droppableRects.size === 0) {
45
+ return currentCoordinates;
46
+ }
47
+ const targets = [];
48
+ for (const [id, container] of droppableContainers) {
49
+ if (container?.disabled) continue;
50
+ const rect = droppableRects.get(id);
51
+ if (!rect) continue;
52
+ const center = {
53
+ x: rect.left + rect.width / 2,
54
+ y: rect.top + rect.height / 2
55
+ };
56
+ // Land the dragged item's own top-left corner at the target's center-left point,
57
+ // rather than at the target's own top-left corner (avoids overshooting into a
58
+ // neighboring droppable when the target is much wider than the dragged item).
59
+ const dropPosition = {
60
+ x: rect.left,
61
+ y: rect.top + rect.height / 2
62
+ };
63
+ targets.push({
64
+ id,
65
+ rect,
66
+ dropPosition,
67
+ center
68
+ });
69
+ }
70
+ if (targets.length === 0) {
71
+ return currentCoordinates;
72
+ }
73
+ const reverse = event.shiftKey;
74
+ targets.sort((a, b) => {
75
+ if (Math.abs(a.center.y - b.center.y) > 10) return a.center.y - b.center.y;
76
+ return a.center.x - b.center.x;
77
+ });
78
+
79
+ // Find the current target: whichever target's rect actually contains the dragged
80
+ // item's own center. This holds regardless of how the dragged item's size compares
81
+ // to the target's — a compact answer tile landed (per `dropPosition` above) at a much
82
+ // wider container's left edge is still contained within that container's rect.
83
+ // Comparing distances between reconstructed centers (as an earlier, buggy version of
84
+ // this same logic in match-list did) breaks down for exactly that shape: a
85
+ // reconstructed center can end up closer to a completely different droppable than to
86
+ // the one the item is actually sitting on, so the *next* press re-matches the wrong
87
+ // target and looks like it does nothing.
88
+ const draggedCenter = collisionRect ? {
89
+ x: collisionRect.left + collisionRect.width / 2,
90
+ y: collisionRect.top + collisionRect.height / 2
91
+ } : currentCoordinates;
92
+ let currentIndex = targets.findIndex(t => draggedCenter.x >= t.rect.left && draggedCenter.x <= t.rect.right && draggedCenter.y >= t.rect.top && draggedCenter.y <= t.rect.bottom);
93
+
94
+ // Fall back to nearest-by-dropPosition if the dragged item's center isn't strictly
95
+ // inside any target (e.g. mid-flight after a free arrow-key move).
96
+ if (currentIndex === -1) {
97
+ let minDist = Infinity;
98
+ for (let i = 0; i < targets.length; i++) {
99
+ const dist = distance(currentCoordinates, targets[i].dropPosition);
100
+ if (dist < minDist) {
101
+ minDist = dist;
102
+ currentIndex = i;
103
+ }
104
+ }
105
+ }
106
+ const nextIndex = reverse ? (currentIndex - 1 + targets.length) % targets.length : (currentIndex + 1) % targets.length;
107
+ return targets[nextIndex].dropPosition;
108
+ };
109
+ exports.closestDroppableKeyboardCoordinates = closestDroppableKeyboardCoordinates;
110
+ const distance = (a, b) => Math.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2);
111
+ //# sourceMappingURL=keyboard-coordinates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyboard-coordinates.js","names":["_core","require","closestDroppableKeyboardCoordinates","event","context","currentCoordinates","code","isTab","isArrow","KeyboardCode","Down","Up","Left","Right","undefined","defaultKeyboardCoordinateGetter","preventDefault","droppableRects","droppableContainers","collisionRect","size","targets","id","container","disabled","rect","get","center","x","left","width","y","top","height","dropPosition","push","length","reverse","shiftKey","sort","a","b","Math","abs","draggedCenter","currentIndex","findIndex","t","right","bottom","minDist","Infinity","i","dist","distance","nextIndex","exports","sqrt"],"sources":["../src/keyboard-coordinates.js"],"sourcesContent":["import { defaultKeyboardCoordinateGetter, KeyboardCode } from '@dnd-kit/core';\n\n/**\n * Custom keyboard coordinate getter for image-cloze-association's Tab-based placement.\n *\n * Tab/Shift+Tab cycle the dragged answer directly onto the next/previous enabled\n * droppable — a response container (`response-container-{index}`) or the choices pool\n * (`ica-board`) — sorted by on-screen position (top-to-bottom, then left-to-right),\n * since response containers are absolutely positioned over an image rather than laid\n * out as a simple list.\n *\n * Arrow keys are delegated to dnd-kit's own `defaultKeyboardCoordinateGetter`, leaving\n * the existing free-form arrow-key dragging behavior completely unchanged.\n */\nexport const closestDroppableKeyboardCoordinates = (event, { context, currentCoordinates }) => {\n const { code } = event;\n const isTab = code === 'Tab';\n const isArrow =\n code === KeyboardCode.Down || code === KeyboardCode.Up || code === KeyboardCode.Left || code === KeyboardCode.Right;\n\n if (!isTab && !isArrow) {\n return undefined;\n }\n\n if (isArrow) {\n return defaultKeyboardCoordinateGetter(event, { context, currentCoordinates });\n }\n\n event.preventDefault();\n\n const { droppableRects, droppableContainers, collisionRect } = context;\n\n if (!droppableRects || droppableRects.size === 0) {\n return currentCoordinates;\n }\n\n const targets = [];\n\n for (const [id, container] of droppableContainers) {\n if (container?.disabled) continue;\n\n const rect = droppableRects.get(id);\n\n if (!rect) continue;\n\n const center = {\n x: rect.left + rect.width / 2,\n y: rect.top + rect.height / 2,\n };\n // Land the dragged item's own top-left corner at the target's center-left point,\n // rather than at the target's own top-left corner (avoids overshooting into a\n // neighboring droppable when the target is much wider than the dragged item).\n const dropPosition = {\n x: rect.left,\n y: rect.top + rect.height / 2,\n };\n\n targets.push({ id, rect, dropPosition, center });\n }\n\n if (targets.length === 0) {\n return currentCoordinates;\n }\n\n const reverse = event.shiftKey;\n\n targets.sort((a, b) => {\n if (Math.abs(a.center.y - b.center.y) > 10) return a.center.y - b.center.y;\n return a.center.x - b.center.x;\n });\n\n // Find the current target: whichever target's rect actually contains the dragged\n // item's own center. This holds regardless of how the dragged item's size compares\n // to the target's — a compact answer tile landed (per `dropPosition` above) at a much\n // wider container's left edge is still contained within that container's rect.\n // Comparing distances between reconstructed centers (as an earlier, buggy version of\n // this same logic in match-list did) breaks down for exactly that shape: a\n // reconstructed center can end up closer to a completely different droppable than to\n // the one the item is actually sitting on, so the *next* press re-matches the wrong\n // target and looks like it does nothing.\n const draggedCenter = collisionRect\n ? { x: collisionRect.left + collisionRect.width / 2, y: collisionRect.top + collisionRect.height / 2 }\n : currentCoordinates;\n\n let currentIndex = targets.findIndex(\n (t) =>\n draggedCenter.x >= t.rect.left &&\n draggedCenter.x <= t.rect.right &&\n draggedCenter.y >= t.rect.top &&\n draggedCenter.y <= t.rect.bottom,\n );\n\n // Fall back to nearest-by-dropPosition if the dragged item's center isn't strictly\n // inside any target (e.g. mid-flight after a free arrow-key move).\n if (currentIndex === -1) {\n let minDist = Infinity;\n\n for (let i = 0; i < targets.length; i++) {\n const dist = distance(currentCoordinates, targets[i].dropPosition);\n\n if (dist < minDist) {\n minDist = dist;\n currentIndex = i;\n }\n }\n }\n\n const nextIndex = reverse\n ? (currentIndex - 1 + targets.length) % targets.length\n : (currentIndex + 1) % targets.length;\n\n return targets[nextIndex].dropPosition;\n};\n\nconst distance = (a, b) => Math.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2);\n"],"mappings":"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","ignoreList":[]}
@@ -46,6 +46,9 @@ const BaseContainer = (0, _styles.styled)('div')(() => ({
46
46
  },
47
47
  '&.baseIncorrect': {
48
48
  border: `2px solid ${_renderUi.color.incorrect()} !important`
49
+ },
50
+ '&.selected': {
51
+ opacity: 0.7
49
52
  }
50
53
  }));
51
54
  const StyledSpan = (0, _styles.styled)(_staticHtmlSpan.default)(() => ({
@@ -61,7 +64,10 @@ const PossibleResponse = ({
61
64
  data,
62
65
  onDragBegin,
63
66
  answerChoiceTransparency,
64
- isOverlay
67
+ isOverlay,
68
+ selectedResponse,
69
+ onSelectClick,
70
+ onPlacementClick
65
71
  }) => {
66
72
  const rootRef = (0, _react.useRef)(null);
67
73
  const longPressTimer = (0, _react.useRef)(null);
@@ -79,6 +85,25 @@ const PossibleResponse = ({
79
85
  },
80
86
  disabled: !canDrag
81
87
  });
88
+ const isSelected = !!selectedResponse && selectedResponse.id === data.id && selectedResponse.containerIndex === data.containerIndex;
89
+ const handleClick = e => {
90
+ if (!canDrag) return;
91
+ e.stopPropagation();
92
+ const isPlaced = data.containerIndex !== undefined;
93
+ if (isSelected) {
94
+ // Clicking the already-selected tile again deselects it.
95
+ onSelectClick?.(data);
96
+ } else if (selectedResponse && isPlaced) {
97
+ // Something else is selected, and this tile is already inside a container:
98
+ // place the selection into that same container (a swap/insert, handled by the
99
+ // existing handleOnAnswerSelect logic).
100
+ onPlacementClick?.(data.containerIndex);
101
+ } else {
102
+ // Nothing selected yet, or this is a pool item (pool items are never placement
103
+ // targets — the pool itself, in possible-responses.jsx, is): select this tile.
104
+ onSelectClick?.(data);
105
+ }
106
+ };
82
107
  const handleTouchEnd = () => {
83
108
  clearTimeout(longPressTimer.current);
84
109
  };
@@ -124,7 +149,8 @@ const PossibleResponse = ({
124
149
  const containerClassNames = (0, _classnames.default)({
125
150
  answerChoiceTransparency: answerChoiceTransparency && !isDragging,
126
151
  [correctnessClass]: !!correctnessClass,
127
- textAnswerChoiceStyle: !containsImage && !isOverlay
152
+ textAnswerChoiceStyle: !containsImage && !isOverlay,
153
+ selected: isSelected && !isDragging
128
154
  });
129
155
  const promptClassNames = (0, _classnames.default)({
130
156
  hiddenSpan: data.hidden
@@ -135,7 +161,8 @@ const PossibleResponse = ({
135
161
  ref: ref => {
136
162
  rootRef.current = ref;
137
163
  setNodeRef(ref);
138
- }
164
+ },
165
+ onClick: handleClick
139
166
  }, listeners, attributes), /*#__PURE__*/_react.default.createElement(StyledSpan, {
140
167
  html: data.value,
141
168
  className: promptClassNames
@@ -150,12 +177,16 @@ PossibleResponse.propTypes = {
150
177
  data: _propTypes.default.object.isRequired,
151
178
  onDragBegin: _propTypes.default.func.isRequired,
152
179
  answerChoiceTransparency: _propTypes.default.bool,
153
- isOverlay: _propTypes.default.bool
180
+ isOverlay: _propTypes.default.bool,
181
+ selectedResponse: _propTypes.default.object,
182
+ onSelectClick: _propTypes.default.func,
183
+ onPlacementClick: _propTypes.default.func
154
184
  };
155
185
  PossibleResponse.defaultProps = {
156
186
  containerStyle: {},
157
187
  answerChoiceTransparency: false,
158
- isOverlay: false
188
+ isOverlay: false,
189
+ selectedResponse: null
159
190
  };
160
191
  var _default = exports.default = PossibleResponse;
161
192
  //# sourceMappingURL=possible-response.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"possible-response.js","names":["_react","_interopRequireWildcard","require","_propTypes","_interopRequireDefault","_classnames","_styles","_core","_renderUi","_evaluationIcon","_staticHtmlSpan","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","BaseContainer","styled","position","backgroundColor","color","white","border","borderDark","display","alignItems","justifyContent","minHeight","width","pointerEvents","padding","margin","transparent","correct","incorrect","StyledSpan","StaticHTMLSpan","cursor","background","visibility","PossibleResponse","canDrag","containerStyle","data","onDragBegin","answerChoiceTransparency","isOverlay","rootRef","useRef","longPressTimer","setNodeRef","attributes","listeners","isDragging","useDraggable","id","value","containerIndex","disabled","handleTouchEnd","clearTimeout","current","handleTouchMove","handleTouchStart","preventDefault","setTimeout","useEffect","node","addEventListener","passive","removeEventListener","isCorrect","evaluationStyle","fontSize","bottom","right","correctnessClass","undefined","imgRegex","containsImage","test","containerClassNames","classNames","textAnswerChoiceStyle","promptClassNames","hiddenSpan","hidden","createElement","_extends2","className","style","ref","html","propTypes","PropTypes","bool","isRequired","object","func","defaultProps","_default","exports"],"sources":["../src/possible-response.jsx"],"sourcesContent":["import React, { useEffect, useRef } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport { styled } from '@mui/material/styles';\nimport { useDraggable } from '@dnd-kit/core';\nimport { color } from '@pie-lib/render-ui';\n\nimport EvaluationIcon from './evaluation-icon';\nimport StaticHTMLSpan from './static-html-span';\n\nconst BaseContainer = styled('div')(() => ({\n position: 'relative',\n backgroundColor: color.white(),\n border: `1px solid ${color.borderDark()}`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: '28px',\n width: 'fit-content',\n '& span img': {\n // Added for touch devices, for image content.\n // This will prevent the context menu from appearing and not allowing other interactions with the image.\n // If interactions with the image in the token will be requested we should handle only the context Menu.\n pointerEvents: 'none',\n },\n '&.textAnswerChoiceStyle': {\n padding: '0 10px',\n margin: '4px 6px !important',\n },\n '&.answerChoiceTransparency': {\n border: 'none',\n backgroundColor: `${color.transparent()}`,\n '&:hover': {\n border: `1px solid ${color.borderDark()}`,\n },\n },\n '&.baseCorrect': {\n border: `2px solid ${color.correct()} !important`,\n },\n '&.baseIncorrect': {\n border: `2px solid ${color.incorrect()} !important`,\n },\n}));\n\nconst StyledSpan = styled(StaticHTMLSpan)(() => ({\n cursor: 'grab',\n backgroundColor: color.background(),\n '&.hiddenSpan': {\n visibility: 'hidden',\n },\n}));\n\nconst PossibleResponse = ({ canDrag, containerStyle, data, onDragBegin, answerChoiceTransparency, isOverlay }) => {\n const rootRef = useRef(null);\n const longPressTimer = useRef(null);\n\n const { setNodeRef, attributes, listeners, isDragging } = useDraggable({\n id: `possible-response-${data.id}`,\n data: {\n id: data.id,\n value: data.value,\n containerIndex: data.containerIndex,\n },\n disabled: !canDrag,\n });\n\n const handleTouchEnd = () => {\n clearTimeout(longPressTimer.current);\n };\n\n const handleTouchMove = () => {\n clearTimeout(longPressTimer.current);\n };\n\n const handleTouchStart = (e) => {\n e.preventDefault();\n longPressTimer.current = setTimeout(() => {\n if (canDrag && rootRef.current) {\n onDragBegin(data);\n }\n }, 500); // start drag after 500ms (touch and hold duration) for chromebooks and other touch devices\n };\n\n useEffect(() => {\n const node = rootRef.current;\n\n if (!node) return;\n\n node.addEventListener('touchstart', handleTouchStart, { passive: false });\n node.addEventListener('touchend', handleTouchEnd);\n node.addEventListener('touchmove', handleTouchMove, { passive: false });\n\n return () => {\n node.removeEventListener('touchstart', handleTouchStart);\n node.removeEventListener('touchend', handleTouchEnd);\n node.removeEventListener('touchmove', handleTouchMove);\n };\n }, [canDrag, data]);\n\n const { isCorrect } = data || {};\n const evaluationStyle = {\n fontSize: 14,\n position: 'absolute',\n bottom: '3px',\n right: '3px',\n };\n const correctnessClass = isCorrect === true ? 'baseCorrect' : isCorrect === false ? 'baseIncorrect' : undefined;\n\n const imgRegex = /<img[^>]+src=\"([^\">]+)\"/;\n const containsImage = imgRegex.test(data.value);\n\n const containerClassNames = classNames({\n answerChoiceTransparency: answerChoiceTransparency && !isDragging,\n [correctnessClass]: !!correctnessClass,\n textAnswerChoiceStyle: !containsImage && !isOverlay,\n });\n\n const promptClassNames = classNames({ hiddenSpan: data.hidden });\n\n return (\n <BaseContainer\n className={containerClassNames}\n style={containerStyle}\n ref={(ref) => {\n rootRef.current = ref;\n setNodeRef(ref);\n }}\n {...listeners}\n {...attributes}\n >\n <StyledSpan html={data.value} className={promptClassNames} />\n <EvaluationIcon isCorrect={data.isCorrect} containerStyle={evaluationStyle} />\n </BaseContainer>\n );\n};\n\nPossibleResponse.propTypes = {\n canDrag: PropTypes.bool.isRequired,\n containerStyle: PropTypes.object,\n data: PropTypes.object.isRequired,\n onDragBegin: PropTypes.func.isRequired,\n answerChoiceTransparency: PropTypes.bool,\n isOverlay: PropTypes.bool,\n};\n\nPossibleResponse.defaultProps = {\n containerStyle: {},\n answerChoiceTransparency: false,\n isOverlay: false,\n};\n\nexport default PossibleResponse;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"possible-response.js","names":["_react","_interopRequireWildcard","require","_propTypes","_interopRequireDefault","_classnames","_styles","_core","_renderUi","_evaluationIcon","_staticHtmlSpan","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","BaseContainer","styled","position","backgroundColor","color","white","border","borderDark","display","alignItems","justifyContent","minHeight","width","pointerEvents","padding","margin","transparent","correct","incorrect","opacity","StyledSpan","StaticHTMLSpan","cursor","background","visibility","PossibleResponse","canDrag","containerStyle","data","onDragBegin","answerChoiceTransparency","isOverlay","selectedResponse","onSelectClick","onPlacementClick","rootRef","useRef","longPressTimer","setNodeRef","attributes","listeners","isDragging","useDraggable","id","value","containerIndex","disabled","isSelected","handleClick","stopPropagation","isPlaced","undefined","handleTouchEnd","clearTimeout","current","handleTouchMove","handleTouchStart","preventDefault","setTimeout","useEffect","node","addEventListener","passive","removeEventListener","isCorrect","evaluationStyle","fontSize","bottom","right","correctnessClass","imgRegex","containsImage","test","containerClassNames","classNames","textAnswerChoiceStyle","selected","promptClassNames","hiddenSpan","hidden","createElement","_extends2","className","style","ref","onClick","html","propTypes","PropTypes","bool","isRequired","object","func","defaultProps","_default","exports"],"sources":["../src/possible-response.jsx"],"sourcesContent":["import React, { useEffect, useRef } from 'react';\nimport PropTypes from 'prop-types';\nimport classNames from 'classnames';\nimport { styled } from '@mui/material/styles';\nimport { useDraggable } from '@dnd-kit/core';\nimport { color } from '@pie-lib/render-ui';\n\nimport EvaluationIcon from './evaluation-icon';\nimport StaticHTMLSpan from './static-html-span';\n\nconst BaseContainer = styled('div')(() => ({\n position: 'relative',\n backgroundColor: color.white(),\n border: `1px solid ${color.borderDark()}`,\n display: 'flex',\n alignItems: 'center',\n justifyContent: 'center',\n minHeight: '28px',\n width: 'fit-content',\n '& span img': {\n // Added for touch devices, for image content.\n // This will prevent the context menu from appearing and not allowing other interactions with the image.\n // If interactions with the image in the token will be requested we should handle only the context Menu.\n pointerEvents: 'none',\n },\n '&.textAnswerChoiceStyle': {\n padding: '0 10px',\n margin: '4px 6px !important',\n },\n '&.answerChoiceTransparency': {\n border: 'none',\n backgroundColor: `${color.transparent()}`,\n '&:hover': {\n border: `1px solid ${color.borderDark()}`,\n },\n },\n '&.baseCorrect': {\n border: `2px solid ${color.correct()} !important`,\n },\n '&.baseIncorrect': {\n border: `2px solid ${color.incorrect()} !important`,\n },\n '&.selected': {\n opacity: 0.7,\n },\n}));\n\nconst StyledSpan = styled(StaticHTMLSpan)(() => ({\n cursor: 'grab',\n backgroundColor: color.background(),\n '&.hiddenSpan': {\n visibility: 'hidden',\n },\n}));\n\nconst PossibleResponse = ({\n canDrag,\n containerStyle,\n data,\n onDragBegin,\n answerChoiceTransparency,\n isOverlay,\n selectedResponse,\n onSelectClick,\n onPlacementClick,\n}) => {\n const rootRef = useRef(null);\n const longPressTimer = useRef(null);\n\n const { setNodeRef, attributes, listeners, isDragging } = useDraggable({\n id: `possible-response-${data.id}`,\n data: {\n id: data.id,\n value: data.value,\n containerIndex: data.containerIndex,\n },\n disabled: !canDrag,\n });\n\n const isSelected =\n !!selectedResponse && selectedResponse.id === data.id && selectedResponse.containerIndex === data.containerIndex;\n\n const handleClick = (e) => {\n if (!canDrag) return;\n\n e.stopPropagation();\n\n const isPlaced = data.containerIndex !== undefined;\n\n if (isSelected) {\n // Clicking the already-selected tile again deselects it.\n onSelectClick?.(data);\n } else if (selectedResponse && isPlaced) {\n // Something else is selected, and this tile is already inside a container:\n // place the selection into that same container (a swap/insert, handled by the\n // existing handleOnAnswerSelect logic).\n onPlacementClick?.(data.containerIndex);\n } else {\n // Nothing selected yet, or this is a pool item (pool items are never placement\n // targets — the pool itself, in possible-responses.jsx, is): select this tile.\n onSelectClick?.(data);\n }\n };\n\n const handleTouchEnd = () => {\n clearTimeout(longPressTimer.current);\n };\n\n const handleTouchMove = () => {\n clearTimeout(longPressTimer.current);\n };\n\n const handleTouchStart = (e) => {\n e.preventDefault();\n longPressTimer.current = setTimeout(() => {\n if (canDrag && rootRef.current) {\n onDragBegin(data);\n }\n }, 500); // start drag after 500ms (touch and hold duration) for chromebooks and other touch devices\n };\n\n useEffect(() => {\n const node = rootRef.current;\n\n if (!node) return;\n\n node.addEventListener('touchstart', handleTouchStart, { passive: false });\n node.addEventListener('touchend', handleTouchEnd);\n node.addEventListener('touchmove', handleTouchMove, { passive: false });\n\n return () => {\n node.removeEventListener('touchstart', handleTouchStart);\n node.removeEventListener('touchend', handleTouchEnd);\n node.removeEventListener('touchmove', handleTouchMove);\n };\n }, [canDrag, data]);\n\n const { isCorrect } = data || {};\n const evaluationStyle = {\n fontSize: 14,\n position: 'absolute',\n bottom: '3px',\n right: '3px',\n };\n const correctnessClass = isCorrect === true ? 'baseCorrect' : isCorrect === false ? 'baseIncorrect' : undefined;\n\n const imgRegex = /<img[^>]+src=\"([^\">]+)\"/;\n const containsImage = imgRegex.test(data.value);\n\n const containerClassNames = classNames({\n answerChoiceTransparency: answerChoiceTransparency && !isDragging,\n [correctnessClass]: !!correctnessClass,\n textAnswerChoiceStyle: !containsImage && !isOverlay,\n selected: isSelected && !isDragging,\n });\n\n const promptClassNames = classNames({ hiddenSpan: data.hidden });\n\n return (\n <BaseContainer\n className={containerClassNames}\n style={containerStyle}\n ref={(ref) => {\n rootRef.current = ref;\n setNodeRef(ref);\n }}\n onClick={handleClick}\n {...listeners}\n {...attributes}\n >\n <StyledSpan html={data.value} className={promptClassNames} />\n <EvaluationIcon isCorrect={data.isCorrect} containerStyle={evaluationStyle} />\n </BaseContainer>\n );\n};\n\nPossibleResponse.propTypes = {\n canDrag: PropTypes.bool.isRequired,\n containerStyle: PropTypes.object,\n data: PropTypes.object.isRequired,\n onDragBegin: PropTypes.func.isRequired,\n answerChoiceTransparency: PropTypes.bool,\n isOverlay: PropTypes.bool,\n selectedResponse: PropTypes.object,\n onSelectClick: PropTypes.func,\n onPlacementClick: PropTypes.func,\n};\n\nPossibleResponse.defaultProps = {\n containerStyle: {},\n answerChoiceTransparency: false,\n isOverlay: false,\n selectedResponse: null,\n};\n\nexport default PossibleResponse;\n"],"mappings":"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","ignoreList":[]}
@@ -27,24 +27,41 @@ const PossibleResponses = ({
27
27
  answerChoiceTransparency,
28
28
  customStyle,
29
29
  isVertical,
30
- minHeight
31
- }) => /*#__PURE__*/_react.default.createElement(BaseContainer, {
32
- style: customStyle
33
- }, /*#__PURE__*/_react.default.createElement(_drag.ICADroppablePlaceholder, {
34
- id: "ica-board",
35
- disabled: !canDrag,
36
- isVerticalPool: isVertical,
37
- minHeight: minHeight
38
- }, (data || []).map(item => /*#__PURE__*/_react.default.createElement(_possibleResponse.default, {
39
- canDrag: canDrag,
40
- key: item.id,
41
- data: item,
42
- onDragBegin: onDragBegin,
43
- answerChoiceTransparency: answerChoiceTransparency,
44
- containerStyle: {
45
- margin: '4px'
46
- }
47
- }))));
30
+ minHeight,
31
+ selectedResponse,
32
+ onSelectClick,
33
+ onPlacementClick
34
+ }) => {
35
+ const handlePoolClick = () => {
36
+ if (!canDrag) return;
37
+ if (selectedResponse) {
38
+ // `undefined` containerIndex means "the pool" — root.jsx's placeSelectedResponse
39
+ // routes it to handleOnAnswerRemove.
40
+ onPlacementClick?.(undefined);
41
+ }
42
+ };
43
+ return /*#__PURE__*/_react.default.createElement(BaseContainer, {
44
+ style: customStyle,
45
+ onClick: handlePoolClick
46
+ }, /*#__PURE__*/_react.default.createElement(_drag.ICADroppablePlaceholder, {
47
+ id: "ica-board",
48
+ disabled: !canDrag,
49
+ isVerticalPool: isVertical,
50
+ minHeight: minHeight
51
+ }, (data || []).map(item => /*#__PURE__*/_react.default.createElement(_possibleResponse.default, {
52
+ canDrag: canDrag,
53
+ key: item.id,
54
+ data: item,
55
+ onDragBegin: onDragBegin,
56
+ answerChoiceTransparency: answerChoiceTransparency,
57
+ containerStyle: {
58
+ margin: '4px'
59
+ },
60
+ selectedResponse: selectedResponse,
61
+ onSelectClick: onSelectClick,
62
+ onPlacementClick: onPlacementClick
63
+ }))));
64
+ };
48
65
  PossibleResponses.propTypes = {
49
66
  canDrag: _propTypes.default.bool.isRequired,
50
67
  data: _propTypes.default.array.isRequired,
@@ -52,7 +69,10 @@ PossibleResponses.propTypes = {
52
69
  answerChoiceTransparency: _propTypes.default.bool,
53
70
  customStyle: _propTypes.default.object,
54
71
  isVertical: _propTypes.default.bool,
55
- minHeight: _propTypes.default.number
72
+ minHeight: _propTypes.default.number,
73
+ selectedResponse: _propTypes.default.object,
74
+ onSelectClick: _propTypes.default.func,
75
+ onPlacementClick: _propTypes.default.func
56
76
  };
57
77
  var _default = exports.default = PossibleResponses;
58
78
  //# sourceMappingURL=possible-responses.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"possible-responses.js","names":["_react","_interopRequireDefault","require","_propTypes","_styles","_renderUi","_drag","_possibleResponse","BaseContainer","styled","theme","backgroundColor","color","background","margin","spacing","display","alignItems","width","PossibleResponses","canDrag","data","onDragBegin","answerChoiceTransparency","customStyle","isVertical","minHeight","default","createElement","style","ICADroppablePlaceholder","id","disabled","isVerticalPool","map","item","key","containerStyle","propTypes","PropTypes","bool","isRequired","array","func","object","number","_default","exports"],"sources":["../src/possible-responses.jsx"],"sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\nimport { styled } from '@mui/material/styles';\nimport { color } from '@pie-lib/render-ui';\nimport { ICADroppablePlaceholder } from '@pie-lib/drag';\n\nimport PossibleResponse from './possible-response';\n\nconst BaseContainer = styled('div')(({ theme }) => ({\n backgroundColor: color.background(),\n margin: theme.spacing(2),\n display: 'flex',\n alignItems: 'center',\n width: 'fit-content',\n}));\n\nconst PossibleResponses = ({\n canDrag,\n data,\n onDragBegin,\n answerChoiceTransparency,\n customStyle,\n isVertical,\n minHeight,\n}) => (\n <BaseContainer style={customStyle}>\n <ICADroppablePlaceholder id=\"ica-board\" disabled={!canDrag} isVerticalPool={isVertical} minHeight={minHeight}>\n {(data || []).map((item) => (\n <PossibleResponse\n canDrag={canDrag}\n key={item.id}\n data={item}\n onDragBegin={onDragBegin}\n answerChoiceTransparency={answerChoiceTransparency}\n containerStyle={{ margin: '4px' }}\n />\n ))}\n </ICADroppablePlaceholder>\n </BaseContainer>\n);\n\nPossibleResponses.propTypes = {\n canDrag: PropTypes.bool.isRequired,\n data: PropTypes.array.isRequired,\n onDragBegin: PropTypes.func.isRequired,\n answerChoiceTransparency: PropTypes.bool,\n customStyle: PropTypes.object,\n isVertical: PropTypes.bool,\n minHeight: PropTypes.number,\n};\n\nexport default PossibleResponses;\n"],"mappings":";;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,UAAA,GAAAF,sBAAA,CAAAC,OAAA;AACA,IAAAE,OAAA,GAAAF,OAAA;AACA,IAAAG,SAAA,GAAAH,OAAA;AACA,IAAAI,KAAA,GAAAJ,OAAA;AAEA,IAAAK,iBAAA,GAAAN,sBAAA,CAAAC,OAAA;AAEA,MAAMM,aAAa,GAAG,IAAAC,cAAM,EAAC,KAAK,CAAC,CAAC,CAAC;EAAEC;AAAM,CAAC,MAAM;EAClDC,eAAe,EAAEC,eAAK,CAACC,UAAU,CAAC,CAAC;EACnCC,MAAM,EAAEJ,KAAK,CAACK,OAAO,CAAC,CAAC,CAAC;EACxBC,OAAO,EAAE,MAAM;EACfC,UAAU,EAAE,QAAQ;EACpBC,KAAK,EAAE;AACT,CAAC,CAAC,CAAC;AAEH,MAAMC,iBAAiB,GAAGA,CAAC;EACzBC,OAAO;EACPC,IAAI;EACJC,WAAW;EACXC,wBAAwB;EACxBC,WAAW;EACXC,UAAU;EACVC;AACF,CAAC,kBACC1B,MAAA,CAAA2B,OAAA,CAAAC,aAAA,CAACpB,aAAa;EAACqB,KAAK,EAAEL;AAAY,gBAChCxB,MAAA,CAAA2B,OAAA,CAAAC,aAAA,CAACtB,KAAA,CAAAwB,uBAAuB;EAACC,EAAE,EAAC,WAAW;EAACC,QAAQ,EAAE,CAACZ,OAAQ;EAACa,cAAc,EAAER,UAAW;EAACC,SAAS,EAAEA;AAAU,GAC1G,CAACL,IAAI,IAAI,EAAE,EAAEa,GAAG,CAAEC,IAAI,iBACrBnC,MAAA,CAAA2B,OAAA,CAAAC,aAAA,CAACrB,iBAAA,CAAAoB,OAAgB;EACfP,OAAO,EAAEA,OAAQ;EACjBgB,GAAG,EAAED,IAAI,CAACJ,EAAG;EACbV,IAAI,EAAEc,IAAK;EACXb,WAAW,EAAEA,WAAY;EACzBC,wBAAwB,EAAEA,wBAAyB;EACnDc,cAAc,EAAE;IAAEvB,MAAM,EAAE;EAAM;AAAE,CACnC,CACF,CACsB,CACZ,CAChB;AAEDK,iBAAiB,CAACmB,SAAS,GAAG;EAC5BlB,OAAO,EAAEmB,kBAAS,CAACC,IAAI,CAACC,UAAU;EAClCpB,IAAI,EAAEkB,kBAAS,CAACG,KAAK,CAACD,UAAU;EAChCnB,WAAW,EAAEiB,kBAAS,CAACI,IAAI,CAACF,UAAU;EACtClB,wBAAwB,EAAEgB,kBAAS,CAACC,IAAI;EACxChB,WAAW,EAAEe,kBAAS,CAACK,MAAM;EAC7BnB,UAAU,EAAEc,kBAAS,CAACC,IAAI;EAC1Bd,SAAS,EAAEa,kBAAS,CAACM;AACvB,CAAC;AAAC,IAAAC,QAAA,GAAAC,OAAA,CAAApB,OAAA,GAEaR,iBAAiB","ignoreList":[]}
1
+ {"version":3,"file":"possible-responses.js","names":["_react","_interopRequireDefault","require","_propTypes","_styles","_renderUi","_drag","_possibleResponse","BaseContainer","styled","theme","backgroundColor","color","background","margin","spacing","display","alignItems","width","PossibleResponses","canDrag","data","onDragBegin","answerChoiceTransparency","customStyle","isVertical","minHeight","selectedResponse","onSelectClick","onPlacementClick","handlePoolClick","undefined","default","createElement","style","onClick","ICADroppablePlaceholder","id","disabled","isVerticalPool","map","item","key","containerStyle","propTypes","PropTypes","bool","isRequired","array","func","object","number","_default","exports"],"sources":["../src/possible-responses.jsx"],"sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\nimport { styled } from '@mui/material/styles';\nimport { color } from '@pie-lib/render-ui';\nimport { ICADroppablePlaceholder } from '@pie-lib/drag';\n\nimport PossibleResponse from './possible-response';\n\nconst BaseContainer = styled('div')(({ theme }) => ({\n backgroundColor: color.background(),\n margin: theme.spacing(2),\n display: 'flex',\n alignItems: 'center',\n width: 'fit-content',\n}));\n\nconst PossibleResponses = ({\n canDrag,\n data,\n onDragBegin,\n answerChoiceTransparency,\n customStyle,\n isVertical,\n minHeight,\n selectedResponse,\n onSelectClick,\n onPlacementClick,\n}) => {\n const handlePoolClick = () => {\n if (!canDrag) return;\n\n if (selectedResponse) {\n // `undefined` containerIndex means \"the pool\" — root.jsx's placeSelectedResponse\n // routes it to handleOnAnswerRemove.\n onPlacementClick?.(undefined);\n }\n };\n\n return (\n <BaseContainer style={customStyle} onClick={handlePoolClick}>\n <ICADroppablePlaceholder id=\"ica-board\" disabled={!canDrag} isVerticalPool={isVertical} minHeight={minHeight}>\n {(data || []).map((item) => (\n <PossibleResponse\n canDrag={canDrag}\n key={item.id}\n data={item}\n onDragBegin={onDragBegin}\n answerChoiceTransparency={answerChoiceTransparency}\n containerStyle={{ margin: '4px' }}\n selectedResponse={selectedResponse}\n onSelectClick={onSelectClick}\n onPlacementClick={onPlacementClick}\n />\n ))}\n </ICADroppablePlaceholder>\n </BaseContainer>\n );\n};\n\nPossibleResponses.propTypes = {\n canDrag: PropTypes.bool.isRequired,\n data: PropTypes.array.isRequired,\n onDragBegin: PropTypes.func.isRequired,\n answerChoiceTransparency: PropTypes.bool,\n customStyle: PropTypes.object,\n isVertical: PropTypes.bool,\n minHeight: PropTypes.number,\n selectedResponse: PropTypes.object,\n onSelectClick: PropTypes.func,\n onPlacementClick: PropTypes.func,\n};\n\nexport default PossibleResponses;\n"],"mappings":";;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,UAAA,GAAAF,sBAAA,CAAAC,OAAA;AACA,IAAAE,OAAA,GAAAF,OAAA;AACA,IAAAG,SAAA,GAAAH,OAAA;AACA,IAAAI,KAAA,GAAAJ,OAAA;AAEA,IAAAK,iBAAA,GAAAN,sBAAA,CAAAC,OAAA;AAEA,MAAMM,aAAa,GAAG,IAAAC,cAAM,EAAC,KAAK,CAAC,CAAC,CAAC;EAAEC;AAAM,CAAC,MAAM;EAClDC,eAAe,EAAEC,eAAK,CAACC,UAAU,CAAC,CAAC;EACnCC,MAAM,EAAEJ,KAAK,CAACK,OAAO,CAAC,CAAC,CAAC;EACxBC,OAAO,EAAE,MAAM;EACfC,UAAU,EAAE,QAAQ;EACpBC,KAAK,EAAE;AACT,CAAC,CAAC,CAAC;AAEH,MAAMC,iBAAiB,GAAGA,CAAC;EACzBC,OAAO;EACPC,IAAI;EACJC,WAAW;EACXC,wBAAwB;EACxBC,WAAW;EACXC,UAAU;EACVC,SAAS;EACTC,gBAAgB;EAChBC,aAAa;EACbC;AACF,CAAC,KAAK;EACJ,MAAMC,eAAe,GAAGA,CAAA,KAAM;IAC5B,IAAI,CAACV,OAAO,EAAE;IAEd,IAAIO,gBAAgB,EAAE;MACpB;MACA;MACAE,gBAAgB,GAAGE,SAAS,CAAC;IAC/B;EACF,CAAC;EAED,oBACE/B,MAAA,CAAAgC,OAAA,CAAAC,aAAA,CAACzB,aAAa;IAAC0B,KAAK,EAAEV,WAAY;IAACW,OAAO,EAAEL;EAAgB,gBAC1D9B,MAAA,CAAAgC,OAAA,CAAAC,aAAA,CAAC3B,KAAA,CAAA8B,uBAAuB;IAACC,EAAE,EAAC,WAAW;IAACC,QAAQ,EAAE,CAAClB,OAAQ;IAACmB,cAAc,EAAEd,UAAW;IAACC,SAAS,EAAEA;EAAU,GAC1G,CAACL,IAAI,IAAI,EAAE,EAAEmB,GAAG,CAAEC,IAAI,iBACrBzC,MAAA,CAAAgC,OAAA,CAAAC,aAAA,CAAC1B,iBAAA,CAAAyB,OAAgB;IACfZ,OAAO,EAAEA,OAAQ;IACjBsB,GAAG,EAAED,IAAI,CAACJ,EAAG;IACbhB,IAAI,EAAEoB,IAAK;IACXnB,WAAW,EAAEA,WAAY;IACzBC,wBAAwB,EAAEA,wBAAyB;IACnDoB,cAAc,EAAE;MAAE7B,MAAM,EAAE;IAAM,CAAE;IAClCa,gBAAgB,EAAEA,gBAAiB;IACnCC,aAAa,EAAEA,aAAc;IAC7BC,gBAAgB,EAAEA;EAAiB,CACpC,CACF,CACsB,CACZ,CAAC;AAEpB,CAAC;AAEDV,iBAAiB,CAACyB,SAAS,GAAG;EAC5BxB,OAAO,EAAEyB,kBAAS,CAACC,IAAI,CAACC,UAAU;EAClC1B,IAAI,EAAEwB,kBAAS,CAACG,KAAK,CAACD,UAAU;EAChCzB,WAAW,EAAEuB,kBAAS,CAACI,IAAI,CAACF,UAAU;EACtCxB,wBAAwB,EAAEsB,kBAAS,CAACC,IAAI;EACxCtB,WAAW,EAAEqB,kBAAS,CAACK,MAAM;EAC7BzB,UAAU,EAAEoB,kBAAS,CAACC,IAAI;EAC1BpB,SAAS,EAAEmB,kBAAS,CAACM,MAAM;EAC3BxB,gBAAgB,EAAEkB,kBAAS,CAACK,MAAM;EAClCtB,aAAa,EAAEiB,kBAAS,CAACI,IAAI;EAC7BpB,gBAAgB,EAAEgB,kBAAS,CAACI;AAC9B,CAAC;AAAC,IAAAG,QAAA,GAAAC,OAAA,CAAArB,OAAA,GAEab,iBAAiB","ignoreList":[]}
package/lib/root.js CHANGED
@@ -23,10 +23,17 @@ var _interactiveSection = _interopRequireDefault(require("./interactive-section"
23
23
  var _possibleResponses2 = _interopRequireDefault(require("./possible-responses"));
24
24
  var _utilsCorrectness = require("./utils-correctness");
25
25
  var _possibleResponse = _interopRequireDefault(require("./possible-response"));
26
+ var _keyboardCoordinates = require("./keyboard-coordinates");
26
27
  const {
27
28
  translator
28
29
  } = _translator.default;
29
30
  const generateId = () => Math.random().toString(36).substring(2) + new Date().getTime().toString(36);
31
+
32
+ // A click that lands right after a real drag gesture ends (pointer drag-and-drop, or
33
+ // the browser's own synthetic click for a keyboard Space/Enter) must be ignored by the
34
+ // click-to-select/click-to-place handlers below, or it would immediately reopen or
35
+ // re-trigger a selection for a drag that just completed.
36
+ const CLICK_AFTER_DRAG_GUARD_MS = 250;
30
37
  const StyledUiLayout = (0, _styles.styled)(_renderUi.UiLayout)({
31
38
  color: _renderUi.color.text(),
32
39
  backgroundColor: _renderUi.color.background(),
@@ -56,7 +63,8 @@ class ImageClozeAssociationComponent extends _react.default.Component {
56
63
  if (active?.data?.current) {
57
64
  this.setState({
58
65
  draggingElement: active.data.current,
59
- isValidDrop: false
66
+ isValidDrop: false,
67
+ selectedResponse: active.data.current
60
68
  });
61
69
  }
62
70
  });
@@ -84,6 +92,8 @@ class ImageClozeAssociationComponent extends _react.default.Component {
84
92
  },
85
93
  isValidDrop: shouldDisableAnimation
86
94
  });
95
+ this.cancelSelection();
96
+ this.lastDragEndAt = Date.now();
87
97
  if (!over || !active) {
88
98
  return;
89
99
  }
@@ -91,13 +101,102 @@ class ImageClozeAssociationComponent extends _react.default.Component {
91
101
  return;
92
102
  }
93
103
  if (over.id === 'ica-board') {
94
- this.handleOnAnswerRemove(draggedItem);
104
+ if (draggedItem.containerIndex !== undefined) {
105
+ this.handleOnAnswerRemove(draggedItem);
106
+ }
95
107
  return;
96
108
  }
97
109
  if (responseArea) {
98
110
  this.handleOnAnswerSelect(draggedItem, responseArea.containerIndex);
99
111
  }
100
112
  });
113
+ (0, _defineProperty2.default)(this, "onDragCancel", () => {
114
+ this.setState({
115
+ draggingElement: {
116
+ id: '',
117
+ value: ''
118
+ }
119
+ });
120
+ this.cancelSelection();
121
+ this.lastDragEndAt = Date.now();
122
+ });
123
+ (0, _defineProperty2.default)(this, "isSameResponse", (a, b) => !!a && !!b && a.id === b.id && a.containerIndex === b.containerIndex);
124
+ // Click-to-select semantics: selecting the currently-selected response again clears
125
+ // the selection instead of re-selecting it.
126
+ (0, _defineProperty2.default)(this, "toggleResponseSelection", data => {
127
+ this.setState(state => ({
128
+ selectedResponse: this.isSameResponse(state.selectedResponse, data) ? null : data
129
+ }));
130
+ });
131
+ (0, _defineProperty2.default)(this, "cancelSelection", () => {
132
+ this.setState({
133
+ selectedResponse: null
134
+ });
135
+ });
136
+ // If a real dnd-kit drag (started via keyboard Space/Enter) is still live when a
137
+ // click completes the placement below, it needs to be cleanly ended — otherwise
138
+ // dnd-kit would still think a drag is in progress. Escape is already configured as
139
+ // this sensor's cancel key (see the keyboardCodes passed to DragProvider below), and
140
+ // dispatching it as a real DOM KeyboardEvent is how dnd-kit's own document-level
141
+ // listener is reached from outside its sensor.
142
+ //
143
+ // Only dispatch when a drag is actually live (draggingElement.id is truthy) — this is
144
+ // a synthetic Escape keydown on `document`, so an unconditional dispatch would also be
145
+ // observed by any other document-level Escape listener (host player modals/dialogs,
146
+ // or another mounted instance of this same component) even when nothing here actually
147
+ // needed cancelling.
148
+ (0, _defineProperty2.default)(this, "endAnyLiveKeyboardDrag", () => {
149
+ if (!this.state.draggingElement.id) {
150
+ return;
151
+ }
152
+ document.dispatchEvent(new KeyboardEvent('keydown', {
153
+ code: 'Escape',
154
+ bubbles: true,
155
+ cancelable: true
156
+ }));
157
+ });
158
+ (0, _defineProperty2.default)(this, "placeSelectedResponse", containerIndex => {
159
+ const {
160
+ selectedResponse
161
+ } = this.state;
162
+ if (!selectedResponse) {
163
+ return;
164
+ }
165
+ if (containerIndex === undefined) {
166
+ // Placing into the pool = removing it from wherever it currently is
167
+ if (selectedResponse.containerIndex !== undefined) {
168
+ this.handleOnAnswerRemove(selectedResponse);
169
+ }
170
+ } else {
171
+ this.handleOnAnswerSelect(selectedResponse, containerIndex);
172
+ }
173
+ this.cancelSelection();
174
+ this.endAnyLiveKeyboardDrag();
175
+ this.lastDragEndAt = Date.now();
176
+ });
177
+ (0, _defineProperty2.default)(this, "isClickSoonAfterDragEnd", () => Date.now() - this.lastDragEndAt < CLICK_AFTER_DRAG_GUARD_MS);
178
+ (0, _defineProperty2.default)(this, "onResponseClick", data => {
179
+ if (this.isClickSoonAfterDragEnd()) {
180
+ return;
181
+ }
182
+
183
+ // A click that selects/deselects/switches a tile must end any dnd-kit drag that's
184
+ // still live from an earlier keyboard Space/Enter pick-up first — otherwise dnd-kit
185
+ // keeps thinking that earlier item is being dragged (it ignores new sensor
186
+ // activation while a drag is active) while selectedResponse visually points at
187
+ // whatever this click just selected. Ending the stale drag first (rather than
188
+ // after) matters: ending it also cancels the current selection as a side effect
189
+ // (see onDragCancel above), so doing it before
190
+ // toggleResponseSelection lets this click's own selection be the one that sticks.
191
+ this.endAnyLiveKeyboardDrag();
192
+ this.toggleResponseSelection(data);
193
+ });
194
+ (0, _defineProperty2.default)(this, "onPlacementClick", containerIndex => {
195
+ if (this.isClickSoonAfterDragEnd()) {
196
+ return;
197
+ }
198
+ this.placeSelectedResponse(containerIndex);
199
+ });
101
200
  (0, _defineProperty2.default)(this, "renderDragOverlay", () => {
102
201
  const {
103
202
  draggingElement
@@ -288,8 +387,10 @@ class ImageClozeAssociationComponent extends _react.default.Component {
288
387
  })),
289
388
  maxResponsePerZone: _maxResponsePerZone || 1,
290
389
  showCorrect: false,
291
- isValidDrop: false
390
+ isValidDrop: false,
391
+ selectedResponse: null
292
392
  };
393
+ this.lastDragEndAt = 0;
293
394
  }
294
395
  render() {
295
396
  const {
@@ -370,7 +471,10 @@ class ImageClozeAssociationComponent extends _react.default.Component {
370
471
  responseAreaFill,
371
472
  responseContainerPadding,
372
473
  imageDropTargetPadding,
373
- maxResponsePerZone
474
+ maxResponsePerZone,
475
+ selectedResponse: this.state.selectedResponse,
476
+ onSelectClick: this.onResponseClick,
477
+ onPlacementClick: this.onPlacementClick
374
478
  };
375
479
  const renderImage = () => /*#__PURE__*/_react.default.createElement(_imageContainer.default, (0, _extends2.default)({}, sharedImageProps, {
376
480
  canDrag: showCorrect && showToggle ? false : !disabled,
@@ -391,12 +495,22 @@ class ImageClozeAssociationComponent extends _react.default.Component {
391
495
  minWidth: isVertical ? '130px' : image?.width || 'fit-content'
392
496
  },
393
497
  isVertical: isVertical,
394
- minHeight: isVertical ? image?.height : undefined
498
+ minHeight: isVertical ? image?.height : undefined,
499
+ selectedResponse: this.state.selectedResponse,
500
+ onSelectClick: this.onResponseClick,
501
+ onPlacementClick: this.onPlacementClick
395
502
  }));
396
503
  };
397
504
  return /*#__PURE__*/_react.default.createElement(_drag.DragProvider, {
398
505
  onDragStart: this.onDragStart,
399
- onDragEnd: this.onDragEnd
506
+ onDragEnd: this.onDragEnd,
507
+ onDragCancel: this.onDragCancel,
508
+ keyboardCoordinateGetter: _keyboardCoordinates.closestDroppableKeyboardCoordinates,
509
+ keyboardCodes: {
510
+ start: ['Space', 'Enter'],
511
+ cancel: ['Escape'],
512
+ end: ['Space', 'Enter']
513
+ }
400
514
  }, /*#__PURE__*/_react.default.createElement(StyledUiLayout, {
401
515
  extraCSSRules: extraCSSRules,
402
516
  id: 'main-container',