@pie-element/match-list 7.1.7 → 7.1.9

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.
@@ -1 +1 @@
1
- {"version":3,"file":"droppable-placeholder.js","names":["_react","_interopRequireDefault","require","_propTypes","_core","_styles","_drag","Container","styled","theme","alignItems","display","flexDirection","flexWrap","justifyContent","marginTop","spacing","marginBottom","minHeight","transition","DroppablePlaceholder","id","disabled","children","rest","setNodeRef","isOver","useDroppable","data","type","default","createElement","_extends2","ref","style","backgroundColor","MatchDroppablePlaceholder","propTypes","PropTypes","oneOfType","string","number","bool","node","_default","exports"],"sources":["../src/droppable-placeholder.jsx"],"sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\nimport { useDroppable } from '@dnd-kit/core';\nimport { styled } from '@mui/material/styles';\nimport { MatchDroppablePlaceholder } from '@pie-lib/drag';\n\nconst Container = styled('div')(({ theme }) => ({\n alignItems: 'center',\n display: 'flex',\n flexDirection: 'row',\n flexWrap: 'wrap',\n justifyContent: 'space-between',\n marginTop: theme.spacing(1),\n marginBottom: theme.spacing(1),\n minHeight: 50,\n transition: 'background-color 200ms ease',\n}));\n\nexport function DroppablePlaceholder({ id, disabled, children, ...rest }) {\n const { setNodeRef, isOver } = useDroppable({\n id: id || 'choices-pool',\n data: { type: 'choices-pool' },\n disabled,\n });\n\n return (\n <Container\n ref={setNodeRef}\n style={{ backgroundColor: isOver ? 'rgba(0,0,0,0.05)' : 'transparent' }}\n {...rest}\n >\n <MatchDroppablePlaceholder id={id} disabled={disabled}>\n {children}\n </MatchDroppablePlaceholder>\n </Container>\n );\n}\n\nDroppablePlaceholder.propTypes = {\n id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n disabled: PropTypes.bool,\n children: PropTypes.node,\n};\n\nexport default DroppablePlaceholder;\n"],"mappings":";;;;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,UAAA,GAAAF,sBAAA,CAAAC,OAAA;AACA,IAAAE,KAAA,GAAAF,OAAA;AACA,IAAAG,OAAA,GAAAH,OAAA;AACA,IAAAI,KAAA,GAAAJ,OAAA;AAEA,MAAMK,SAAS,GAAG,IAAAC,cAAM,EAAC,KAAK,CAAC,CAAC,CAAC;EAAEC;AAAM,CAAC,MAAM;EAC5CC,UAAU,EAAE,QAAQ;EACpBC,OAAO,EAAE,MAAM;EACfC,aAAa,EAAE,KAAK;EACpBC,QAAQ,EAAE,MAAM;EAChBC,cAAc,EAAE,eAAe;EAC/BC,SAAS,EAAEN,KAAK,CAACO,OAAO,CAAC,CAAC,CAAC;EAC3BC,YAAY,EAAER,KAAK,CAACO,OAAO,CAAC,CAAC,CAAC;EAC9BE,SAAS,EAAE,EAAE;EACbC,UAAU,EAAE;AAChB,CAAC,CAAC,CAAC;AAEI,SAASC,oBAAoBA,CAAC;EAAEC,EAAE;EAAEC,QAAQ;EAAEC,QAAQ;EAAE,GAAGC;AAAK,CAAC,EAAE;EACtE,MAAM;IAAEC,UAAU;IAAEC;EAAO,CAAC,GAAG,IAAAC,kBAAY,EAAC;IACxCN,EAAE,EAAEA,EAAE,IAAI,cAAc;IACxBO,IAAI,EAAE;MAAEC,IAAI,EAAE;IAAe,CAAC;IAC9BP;EACJ,CAAC,CAAC;EAEF,oBACItB,MAAA,CAAA8B,OAAA,CAAAC,aAAA,CAACxB,SAAS,MAAAyB,SAAA,CAAAF,OAAA;IACNG,GAAG,EAAER,UAAW;IAChBS,KAAK,EAAE;MAAEC,eAAe,EAAET,MAAM,GAAG,kBAAkB,GAAG;IAAc;EAAE,GACpEF,IAAI,gBAERxB,MAAA,CAAA8B,OAAA,CAAAC,aAAA,CAACzB,KAAA,CAAA8B,yBAAyB;IAACf,EAAE,EAAEA,EAAG;IAACC,QAAQ,EAAEA;EAAS,GACjDC,QACsB,CACpB,CAAC;AAEpB;AAEAH,oBAAoB,CAACiB,SAAS,GAAG;EAC7BhB,EAAE,EAAEiB,kBAAS,CAACC,SAAS,CAAC,CAACD,kBAAS,CAACE,MAAM,EAAEF,kBAAS,CAACG,MAAM,CAAC,CAAC;EAC7DnB,QAAQ,EAAEgB,kBAAS,CAACI,IAAI;EACxBnB,QAAQ,EAAEe,kBAAS,CAACK;AACxB,CAAC;AAAC,IAAAC,QAAA,GAAAC,OAAA,CAAAf,OAAA,GAEaV,oBAAoB","ignoreList":[]}
1
+ {"version":3,"file":"droppable-placeholder.js","names":["_react","_interopRequireDefault","require","_propTypes","_core","_styles","_drag","Container","styled","theme","alignItems","display","flexDirection","flexWrap","justifyContent","marginTop","spacing","marginBottom","minHeight","transition","DroppablePlaceholder","id","disabled","children","onPlacementClick","rest","setNodeRef","isOver","useDroppable","data","type","handleClick","default","createElement","_extends2","ref","onClick","style","backgroundColor","MatchDroppablePlaceholder","propTypes","PropTypes","oneOfType","string","number","bool","node","func","_default","exports"],"sources":["../src/droppable-placeholder.jsx"],"sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\nimport { useDroppable } from '@dnd-kit/core';\nimport { styled } from '@mui/material/styles';\nimport { MatchDroppablePlaceholder } from '@pie-lib/drag';\n\nconst Container = styled('div')(({ theme }) => ({\n alignItems: 'center',\n display: 'flex',\n flexDirection: 'row',\n flexWrap: 'wrap',\n justifyContent: 'space-between',\n marginTop: theme.spacing(1),\n marginBottom: theme.spacing(1),\n minHeight: 50,\n transition: 'background-color 200ms ease',\n}));\n\nexport function DroppablePlaceholder({ id, disabled, children, onPlacementClick, ...rest }) {\n const { setNodeRef, isOver } = useDroppable({\n id: id || 'choices-pool',\n data: { type: 'choices-pool' },\n disabled,\n });\n\n const handleClick = () => {\n if (disabled) {\n return;\n }\n\n onPlacementClick?.({ type: 'choices-pool' });\n };\n\n return (\n <Container\n ref={setNodeRef}\n onClick={handleClick}\n style={{ backgroundColor: isOver ? 'rgba(0,0,0,0.05)' : 'transparent' }}\n {...rest}\n >\n <MatchDroppablePlaceholder id={id} disabled={disabled}>\n {children}\n </MatchDroppablePlaceholder>\n </Container>\n );\n}\n\nDroppablePlaceholder.propTypes = {\n id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),\n disabled: PropTypes.bool,\n children: PropTypes.node,\n onPlacementClick: PropTypes.func,\n};\n\nexport default DroppablePlaceholder;\n"],"mappings":";;;;;;;;;AAAA,IAAAA,MAAA,GAAAC,sBAAA,CAAAC,OAAA;AACA,IAAAC,UAAA,GAAAF,sBAAA,CAAAC,OAAA;AACA,IAAAE,KAAA,GAAAF,OAAA;AACA,IAAAG,OAAA,GAAAH,OAAA;AACA,IAAAI,KAAA,GAAAJ,OAAA;AAEA,MAAMK,SAAS,GAAG,IAAAC,cAAM,EAAC,KAAK,CAAC,CAAC,CAAC;EAAEC;AAAM,CAAC,MAAM;EAC5CC,UAAU,EAAE,QAAQ;EACpBC,OAAO,EAAE,MAAM;EACfC,aAAa,EAAE,KAAK;EACpBC,QAAQ,EAAE,MAAM;EAChBC,cAAc,EAAE,eAAe;EAC/BC,SAAS,EAAEN,KAAK,CAACO,OAAO,CAAC,CAAC,CAAC;EAC3BC,YAAY,EAAER,KAAK,CAACO,OAAO,CAAC,CAAC,CAAC;EAC9BE,SAAS,EAAE,EAAE;EACbC,UAAU,EAAE;AAChB,CAAC,CAAC,CAAC;AAEI,SAASC,oBAAoBA,CAAC;EAAEC,EAAE;EAAEC,QAAQ;EAAEC,QAAQ;EAAEC,gBAAgB;EAAE,GAAGC;AAAK,CAAC,EAAE;EACxF,MAAM;IAAEC,UAAU;IAAEC;EAAO,CAAC,GAAG,IAAAC,kBAAY,EAAC;IACxCP,EAAE,EAAEA,EAAE,IAAI,cAAc;IACxBQ,IAAI,EAAE;MAAEC,IAAI,EAAE;IAAe,CAAC;IAC9BR;EACJ,CAAC,CAAC;EAEF,MAAMS,WAAW,GAAGA,CAAA,KAAM;IACtB,IAAIT,QAAQ,EAAE;MACZ;IACF;IAEAE,gBAAgB,GAAG;MAAEM,IAAI,EAAE;IAAe,CAAC,CAAC;EAChD,CAAC;EAED,oBACI9B,MAAA,CAAAgC,OAAA,CAAAC,aAAA,CAAC1B,SAAS,MAAA2B,SAAA,CAAAF,OAAA;IACNG,GAAG,EAAET,UAAW;IAChBU,OAAO,EAAEL,WAAY;IACrBM,KAAK,EAAE;MAAEC,eAAe,EAAEX,MAAM,GAAG,kBAAkB,GAAG;IAAc;EAAE,GACpEF,IAAI,gBAERzB,MAAA,CAAAgC,OAAA,CAAAC,aAAA,CAAC3B,KAAA,CAAAiC,yBAAyB;IAAClB,EAAE,EAAEA,EAAG;IAACC,QAAQ,EAAEA;EAAS,GACjDC,QACsB,CACpB,CAAC;AAEpB;AAEAH,oBAAoB,CAACoB,SAAS,GAAG;EAC7BnB,EAAE,EAAEoB,kBAAS,CAACC,SAAS,CAAC,CAACD,kBAAS,CAACE,MAAM,EAAEF,kBAAS,CAACG,MAAM,CAAC,CAAC;EAC7DtB,QAAQ,EAAEmB,kBAAS,CAACI,IAAI;EACxBtB,QAAQ,EAAEkB,kBAAS,CAACK,IAAI;EACxBtB,gBAAgB,EAAEiB,kBAAS,CAACM;AAChC,CAAC;AAAC,IAAAC,QAAA,GAAAC,OAAA,CAAAjB,OAAA,GAEaZ,oBAAoB","ignoreList":[]}
@@ -0,0 +1,147 @@
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
+ const ARROW_STEP = 25;
9
+
10
+ /**
11
+ * Custom keyboard coordinate getter for non-sortable drag-and-drop.
12
+ *
13
+ * Tab/Shift+Tab cycle the dragged item directly onto the next/previous droppable
14
+ * (response area or the choices pool), in DOM order, placing the dragged item's own
15
+ * top-left corner at the target's center-left point. Arrow keys are left doing plain
16
+ * free-form movement (nudging the dragged item by a fixed step, same as dnd-kit's own
17
+ * default keyboard behavior) rather than jumping between droppables — collision
18
+ * detection (rectIntersection) still picks up whatever the item ends up actually
19
+ * overlapping.
20
+ */
21
+ const closestDroppableKeyboardCoordinates = (event, {
22
+ active,
23
+ context,
24
+ currentCoordinates
25
+ }) => {
26
+ const {
27
+ code
28
+ } = event;
29
+ const isTab = code === 'Tab';
30
+ const isArrow = code === _core.KeyboardCode.Down || code === _core.KeyboardCode.Up || code === _core.KeyboardCode.Left || code === _core.KeyboardCode.Right;
31
+ if (!isTab && !isArrow) {
32
+ return undefined;
33
+ }
34
+ event.preventDefault();
35
+ if (isArrow) {
36
+ switch (code) {
37
+ case _core.KeyboardCode.Down:
38
+ return {
39
+ ...currentCoordinates,
40
+ y: currentCoordinates.y + ARROW_STEP
41
+ };
42
+ case _core.KeyboardCode.Up:
43
+ return {
44
+ ...currentCoordinates,
45
+ y: currentCoordinates.y - ARROW_STEP
46
+ };
47
+ case _core.KeyboardCode.Right:
48
+ return {
49
+ ...currentCoordinates,
50
+ x: currentCoordinates.x + ARROW_STEP
51
+ };
52
+ case _core.KeyboardCode.Left:
53
+ return {
54
+ ...currentCoordinates,
55
+ x: currentCoordinates.x - ARROW_STEP
56
+ };
57
+ default:
58
+ return currentCoordinates;
59
+ }
60
+ }
61
+ const {
62
+ droppableRects,
63
+ droppableContainers,
64
+ collisionRect
65
+ } = context;
66
+ if (!droppableRects || droppableRects.size === 0) {
67
+ return currentCoordinates;
68
+ }
69
+
70
+ // `currentCoordinates` is the top-left of the dragged item's collision rect (not its
71
+ // center), so derive the dragged item's center in the same frame before comparing it
72
+ // against droppable centers below. Returning a droppable's *center* as the next
73
+ // coordinates (as opposed to its top-left) would shift the dragged item's top-left to
74
+ // that center, overshooting the target by roughly half its size and causing
75
+ // dnd-kit to resolve collisions against a neighboring droppable instead.
76
+ const draggedHalfSize = {
77
+ x: (collisionRect?.width || 0) / 2,
78
+ y: (collisionRect?.height || 0) / 2
79
+ };
80
+ const currentCenter = {
81
+ x: currentCoordinates.x + draggedHalfSize.x,
82
+ y: currentCoordinates.y + draggedHalfSize.y
83
+ };
84
+
85
+ // A placed answer ("target") is itself a droppable for its own prompt slot
86
+ // ("drop-{promptId}"). That self drop-zone must never be treated as a navigable
87
+ // target: it sits under the dragged item, so a tiny (even sub-pixel) discrepancy
88
+ // between its measured rect and the dragged item's own rect is enough to make it
89
+ // register as the "closest" candidate, which reads as the drag being stuck.
90
+ // Exclude it outright rather than relying on a distance threshold.
91
+ const activeData = active?.data?.current;
92
+ const ownDropId = activeData?.promptId != null ? `drop-${activeData.promptId}` : undefined;
93
+
94
+ // Collect top-left and center of all enabled droppable containers
95
+ const targets = [];
96
+ for (const [id, container] of droppableContainers) {
97
+ if (container?.disabled) continue;
98
+ if (id === ownDropId) continue;
99
+ const rect = droppableRects.get(id);
100
+ if (!rect) continue;
101
+ const center = {
102
+ x: rect.left + rect.width / 2,
103
+ y: rect.top + rect.height / 2
104
+ };
105
+ // Land the dragged item's own top-left corner at the target's center-left point,
106
+ // rather than at the target's own top-left corner.
107
+ const dropPosition = {
108
+ x: rect.left,
109
+ y: rect.top + rect.height / 2
110
+ };
111
+ targets.push({
112
+ id,
113
+ dropPosition,
114
+ center
115
+ });
116
+ }
117
+ if (targets.length === 0) {
118
+ return currentCoordinates;
119
+ }
120
+
121
+ // Tab/Shift+Tab: cycle through targets in DOM order (sorted top-to-bottom, left-to-right)
122
+ const reverse = event.shiftKey;
123
+
124
+ // Sort targets by position (top to bottom, then left to right)
125
+ targets.sort((a, b) => {
126
+ if (Math.abs(a.center.y - b.center.y) > 10) return a.center.y - b.center.y;
127
+ return a.center.x - b.center.x;
128
+ });
129
+
130
+ // Find the current target (closest to current coordinates)
131
+ let currentIndex = 0;
132
+ let minDist = Infinity;
133
+ for (let i = 0; i < targets.length; i++) {
134
+ const dist = distance(currentCenter, targets[i].center);
135
+ if (dist < minDist) {
136
+ minDist = dist;
137
+ currentIndex = i;
138
+ }
139
+ }
140
+
141
+ // Move to next/previous
142
+ const nextIndex = reverse ? (currentIndex - 1 + targets.length) % targets.length : (currentIndex + 1) % targets.length;
143
+ return targets[nextIndex].dropPosition;
144
+ };
145
+ exports.closestDroppableKeyboardCoordinates = closestDroppableKeyboardCoordinates;
146
+ const distance = (a, b) => Math.sqrt((a.x - b.x) ** 2 + (a.y - b.y) ** 2);
147
+ //# sourceMappingURL=keyboard-coordinates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"keyboard-coordinates.js","names":["_core","require","ARROW_STEP","closestDroppableKeyboardCoordinates","event","active","context","currentCoordinates","code","isTab","isArrow","KeyboardCode","Down","Up","Left","Right","undefined","preventDefault","y","x","droppableRects","droppableContainers","collisionRect","size","draggedHalfSize","width","height","currentCenter","activeData","data","current","ownDropId","promptId","targets","id","container","disabled","rect","get","center","left","top","dropPosition","push","length","reverse","shiftKey","sort","a","b","Math","abs","currentIndex","minDist","Infinity","i","dist","distance","nextIndex","exports","sqrt"],"sources":["../src/keyboard-coordinates.js"],"sourcesContent":["import { KeyboardCode } from '@dnd-kit/core';\n\nconst ARROW_STEP = 25;\n\n/**\n * Custom keyboard coordinate getter for non-sortable drag-and-drop.\n *\n * Tab/Shift+Tab cycle the dragged item directly onto the next/previous droppable\n * (response area or the choices pool), in DOM order, placing the dragged item's own\n * top-left corner at the target's center-left point. Arrow keys are left doing plain\n * free-form movement (nudging the dragged item by a fixed step, same as dnd-kit's own\n * default keyboard behavior) rather than jumping between droppables — collision\n * detection (rectIntersection) still picks up whatever the item ends up actually\n * overlapping.\n */\nexport const closestDroppableKeyboardCoordinates = (event, { active, 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 event.preventDefault();\n\n if (isArrow) {\n switch (code) {\n case KeyboardCode.Down:\n return { ...currentCoordinates, y: currentCoordinates.y + ARROW_STEP };\n\n case KeyboardCode.Up:\n return { ...currentCoordinates, y: currentCoordinates.y - ARROW_STEP };\n\n case KeyboardCode.Right:\n return { ...currentCoordinates, x: currentCoordinates.x + ARROW_STEP };\n\n case KeyboardCode.Left:\n return { ...currentCoordinates, x: currentCoordinates.x - ARROW_STEP };\n\n default:\n return currentCoordinates;\n }\n }\n\n const { droppableRects, droppableContainers, collisionRect } = context;\n\n if (!droppableRects || droppableRects.size === 0) {\n return currentCoordinates;\n }\n\n // `currentCoordinates` is the top-left of the dragged item's collision rect (not its\n // center), so derive the dragged item's center in the same frame before comparing it\n // against droppable centers below. Returning a droppable's *center* as the next\n // coordinates (as opposed to its top-left) would shift the dragged item's top-left to\n // that center, overshooting the target by roughly half its size and causing\n // dnd-kit to resolve collisions against a neighboring droppable instead.\n const draggedHalfSize = {\n x: (collisionRect?.width || 0) / 2,\n y: (collisionRect?.height || 0) / 2,\n };\n const currentCenter = {\n x: currentCoordinates.x + draggedHalfSize.x,\n y: currentCoordinates.y + draggedHalfSize.y,\n };\n\n // A placed answer (\"target\") is itself a droppable for its own prompt slot\n // (\"drop-{promptId}\"). That self drop-zone must never be treated as a navigable\n // target: it sits under the dragged item, so a tiny (even sub-pixel) discrepancy\n // between its measured rect and the dragged item's own rect is enough to make it\n // register as the \"closest\" candidate, which reads as the drag being stuck.\n // Exclude it outright rather than relying on a distance threshold.\n const activeData = active?.data?.current;\n const ownDropId = activeData?.promptId != null ? `drop-${activeData.promptId}` : undefined;\n\n // Collect top-left and center of all enabled droppable containers\n const targets = [];\n\n for (const [id, container] of droppableContainers) {\n if (container?.disabled) continue;\n\n if (id === ownDropId) 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.\n const dropPosition = {\n x: rect.left,\n y: rect.top + rect.height / 2,\n };\n\n targets.push({ id, dropPosition, center });\n }\n\n if (targets.length === 0) {\n return currentCoordinates;\n }\n\n // Tab/Shift+Tab: cycle through targets in DOM order (sorted top-to-bottom, left-to-right)\n const reverse = event.shiftKey;\n\n // Sort targets by position (top to bottom, then left to right)\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 (closest to current coordinates)\n let currentIndex = 0;\n let minDist = Infinity;\n\n for (let i = 0; i < targets.length; i++) {\n const dist = distance(currentCenter, targets[i].center);\n\n if (dist < minDist) {\n minDist = dist;\n currentIndex = i;\n }\n }\n\n // Move to next/previous\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":[]}
package/lib/main.js CHANGED
@@ -11,6 +11,7 @@ var _propTypes = _interopRequireDefault(require("prop-types"));
11
11
  var _drag = require("@pie-lib/drag");
12
12
  var _core = require("@dnd-kit/core");
13
13
  var _modifiers = require("@dnd-kit/modifiers");
14
+ var _keyboardCoordinates = require("./keyboard-coordinates");
14
15
  var _correctAnswerToggle = _interopRequireDefault(require("@pie-lib/correct-answer-toggle"));
15
16
  var _renderUi = require("@pie-lib/render-ui");
16
17
  var _styles = require("@mui/material/styles");
@@ -18,6 +19,39 @@ var _lodashEs = require("lodash-es");
18
19
  var _answerArea = _interopRequireDefault(require("./answer-area"));
19
20
  var _choicesList = _interopRequireDefault(require("./choices-list"));
20
21
  var _answer = require("./answer");
22
+ // A click that lands right after a real drag gesture ends (pointer drag-and-drop, or
23
+ // the browser's own synthetic click for a keyboard Space/Enter) must be ignored by the
24
+ // new click-to-select/click-to-place handlers below, or it would immediately reopen or
25
+ // re-trigger a selection for a drag that just completed.
26
+ const CLICK_AFTER_DRAG_GUARD_MS = 250;
27
+ const sensors = [
28
+ // Without an activationConstraint, dnd-kit's PointerSensor calls its internal
29
+ // handleStart() synchronously on pointerdown, before any movement — meaning a plain
30
+ // click is itself "activated" as a drag. Once activated, dnd-kit adds a capture-phase
31
+ // document click listener that calls stopPropagation() (to suppress the native
32
+ // "ghost click" a real drag leaves behind), which also swallows the click for a
33
+ // gesture with zero movement, before it ever reaches our own onClick handlers below.
34
+ // Requiring 8px of movement (matching @pie-lib/drag's DragProvider convention used
35
+ // elsewhere in this codebase) defers activation until an actual drag gesture is
36
+ // underway, so a plain click passes through untouched.
37
+ {
38
+ sensor: _core.PointerSensor,
39
+ options: {
40
+ activationConstraint: {
41
+ distance: 8
42
+ }
43
+ }
44
+ }, {
45
+ sensor: _core.KeyboardSensor,
46
+ options: {
47
+ coordinateGetter: _keyboardCoordinates.closestDroppableKeyboardCoordinates,
48
+ keyboardCodes: {
49
+ start: [_core.KeyboardCode.Space, _core.KeyboardCode.Enter],
50
+ cancel: [_core.KeyboardCode.Esc],
51
+ end: [_core.KeyboardCode.Space, _core.KeyboardCode.Enter]
52
+ }
53
+ }
54
+ }];
21
55
  const MainContainer = (0, _styles.styled)('div')({
22
56
  display: 'flex',
23
57
  flexDirection: 'column',
@@ -25,6 +59,19 @@ const MainContainer = (0, _styles.styled)('div')({
25
59
  color: _renderUi.color.text(),
26
60
  backgroundColor: _renderUi.color.background()
27
61
  });
62
+ const InteractiveRegion = (0, _styles.styled)('div')({
63
+ width: '100%',
64
+ overflowX: 'auto',
65
+ overflowY: 'hidden'
66
+ });
67
+
68
+ // A block child of a scroll port is sized to the scroll port, so it has to opt out explicitly for
69
+ // the content to be able to overflow. min-content keeps the rows and the pool the same width.
70
+ const InteractiveRegionContent = (0, _styles.styled)('div')({
71
+ display: 'flex',
72
+ flexDirection: 'column',
73
+ minWidth: 'min-content'
74
+ });
28
75
  class Main extends _react.default.Component {
29
76
  constructor(props) {
30
77
  super(props);
@@ -51,22 +98,19 @@ class Main extends _react.default.Component {
51
98
  rect
52
99
  }
53
100
  });
101
+ this.selectAnswer(active.data.current);
54
102
  }
55
103
  });
56
- (0, _defineProperty2.default)(this, "onPlaceAnswer", event => {
104
+ (0, _defineProperty2.default)(this, "onDragCancel", () => {
57
105
  this.setState({
58
106
  draggingElement: null
59
107
  });
60
- const {
61
- active,
62
- over
63
- } = event;
64
- if (!active) {
65
- return;
66
- }
67
- const activeData = active.data.current;
68
- const overData = over?.data.current;
69
- if (!activeData) {
108
+ this.cancelSelection();
109
+ this.lastDragEndAt = Date.now();
110
+ });
111
+ // Pure placement logic
112
+ (0, _defineProperty2.default)(this, "placeAnswer", (activeData, overData) => {
113
+ if (!activeData || !overData) {
70
114
  return;
71
115
  }
72
116
  const {
@@ -93,9 +137,9 @@ class Main extends _react.default.Component {
93
137
  const sourcePromptId = activeData.promptId;
94
138
 
95
139
  // Handle dropping onto a drop zone
96
- if (overData && overData.type === 'drop-zone' && overData.promptId != null) {
140
+ if (overData.type === 'drop-zone' && overData.promptId != null) {
97
141
  const targetPromptId = overData.promptId;
98
- if (activeData.type === 'choice' && overData.type === 'drop-zone' && targetPromptId !== undefined) {
142
+ if (activeData.type === 'choice' && targetPromptId !== undefined) {
99
143
  // check if this choice is already placed somewhere
100
144
  const existingPlacement = (0, _lodashEs.findKey)(session.value, val => val === answerId);
101
145
  if (existingPlacement && !duplicates) {
@@ -126,6 +170,88 @@ class Main extends _react.default.Component {
126
170
  onSessionChange(session);
127
171
  }
128
172
  });
173
+ (0, _defineProperty2.default)(this, "onPlaceAnswer", event => {
174
+ this.setState({
175
+ draggingElement: null
176
+ });
177
+ const {
178
+ active,
179
+ over
180
+ } = event;
181
+ if (!active) {
182
+ return;
183
+ }
184
+ const activeData = active.data.current;
185
+ const overData = over?.data.current;
186
+ if (!activeData) {
187
+ return;
188
+ }
189
+ this.placeAnswer(activeData, overData);
190
+ this.cancelSelection();
191
+ this.lastDragEndAt = Date.now();
192
+ });
193
+ (0, _defineProperty2.default)(this, "isSameAnswer", (a, b) => !!a && !!b && a.type === b.type && a.id === b.id && a.promptId === b.promptId);
194
+ // Unconditionally selects (used by the drag-start mirror, and internally when
195
+ // switching from one choice to another).
196
+ (0, _defineProperty2.default)(this, "selectAnswer", data => {
197
+ this.setState({
198
+ selectedAnswer: data
199
+ });
200
+ });
201
+ // Click-to-select semantics: selecting the currently-selected answer again clears
202
+ // the selection instead of re-selecting it.
203
+ (0, _defineProperty2.default)(this, "toggleAnswerSelection", data => {
204
+ this.setState(state => ({
205
+ selectedAnswer: this.isSameAnswer(state.selectedAnswer, data) ? null : data
206
+ }));
207
+ });
208
+ (0, _defineProperty2.default)(this, "cancelSelection", () => {
209
+ this.setState({
210
+ selectedAnswer: null
211
+ });
212
+ });
213
+ // If a real dnd-kit drag (started via keyboard Space/Enter) is still live when a
214
+ // click completes the placement below, it needs to be cleanly ended — otherwise
215
+ // dnd-kit would still think a drag is in progress (still listening for Tab/arrow/
216
+ // Space/Escape, still showing the drag overlay) for a placement the click already
217
+ // performed. Escape is already configured as this sensor's cancel key, and
218
+ // dispatching it as a real DOM KeyboardEvent is how dnd-kit's own document-level
219
+ // listener is reached from outside its sensor. onDragCancel is intentionally not
220
+ // wired to redo any placement — it only resets local UI state — so this is safe to
221
+ // call unconditionally, including when no drag is actually live (dnd-kit simply has
222
+ // no listener attached in that case, and the dispatch is a no-op).
223
+ (0, _defineProperty2.default)(this, "endAnyLiveKeyboardDrag", () => {
224
+ document.dispatchEvent(new KeyboardEvent('keydown', {
225
+ code: 'Escape',
226
+ bubbles: true,
227
+ cancelable: true
228
+ }));
229
+ });
230
+ (0, _defineProperty2.default)(this, "placeSelectedAnswer", overData => {
231
+ const {
232
+ selectedAnswer
233
+ } = this.state;
234
+ if (!selectedAnswer) {
235
+ return;
236
+ }
237
+ this.placeAnswer(selectedAnswer, overData);
238
+ this.cancelSelection();
239
+ this.endAnyLiveKeyboardDrag();
240
+ this.lastDragEndAt = Date.now();
241
+ });
242
+ (0, _defineProperty2.default)(this, "isClickSoonAfterDragEnd", () => Date.now() - this.lastDragEndAt < CLICK_AFTER_DRAG_GUARD_MS);
243
+ (0, _defineProperty2.default)(this, "onChoiceClick", data => {
244
+ if (this.isClickSoonAfterDragEnd()) {
245
+ return;
246
+ }
247
+ this.toggleAnswerSelection(data);
248
+ });
249
+ (0, _defineProperty2.default)(this, "onPlacementClick", overData => {
250
+ if (this.isClickSoonAfterDragEnd()) {
251
+ return;
252
+ }
253
+ this.placeSelectedAnswer(overData);
254
+ });
129
255
  (0, _defineProperty2.default)(this, "toggleShowCorrect", () => {
130
256
  this.setState({
131
257
  showCorrectAnswer: !this.state.showCorrectAnswer
@@ -151,8 +277,10 @@ class Main extends _react.default.Component {
151
277
  this.instanceId = (0, _lodashEs.uniqueId)();
152
278
  this.state = {
153
279
  showCorrectAnswer: false,
154
- draggingElement: null
280
+ draggingElement: null,
281
+ selectedAnswer: null
155
282
  };
283
+ this.lastDragEndAt = 0;
156
284
  }
157
285
  onRemoveAnswer(id) {
158
286
  const {
@@ -178,10 +306,80 @@ class Main extends _react.default.Component {
178
306
  prompt,
179
307
  language
180
308
  } = config;
309
+
310
+ // Helpers for accessible announcements
311
+ const getChoiceLabel = dragId => {
312
+ // dragId is like "choice-123" or "target-123"
313
+ const answerId = String(dragId).replace(/^(choice|target)-/, '');
314
+ const answer = config.answers.find(a => String(a.id) === answerId);
315
+ if (answer?.title) {
316
+ // Strip HTML tags for screen reader
317
+ const text = answer.title.replace(/<[^>]*>/g, '').trim();
318
+ return text || `Answer ${answerId}`;
319
+ }
320
+ return `Answer ${answerId}`;
321
+ };
322
+ const getDropTargetLabel = dropId => {
323
+ // dropId is like "drop-456" or "choices-pool"
324
+ if (dropId === 'choices-pool') {
325
+ return {
326
+ label: 'Choices list',
327
+ choiceId: null
328
+ };
329
+ }
330
+ const promptId = String(dropId).replace(/^drop-/, '');
331
+ const promptItem = config.prompts.find(p => String(p.id) === promptId);
332
+ const label = promptItem?.title ? `Response area for ${promptItem.title.replace(/<[^>]*>/g, '').trim()}` : `Response area ${promptId}`;
333
+ const choiceId = session.value?.[promptId];
334
+ return {
335
+ label,
336
+ choiceId: choiceId || null
337
+ };
338
+ };
339
+ const announcements = {
340
+ onDragStart({
341
+ active
342
+ }) {
343
+ return `Picked up ${getChoiceLabel(active.id)}. Use Tab to move between response areas, then press Space or Enter to drop.`;
344
+ },
345
+ onDragOver({
346
+ active,
347
+ over
348
+ }) {
349
+ if (!over) {
350
+ return `${getChoiceLabel(active.id)} is not over a response area.`;
351
+ }
352
+ const target = getDropTargetLabel(over.id);
353
+ const content = target.choiceId ? `Currently contains ${getChoiceLabel(target.choiceId)}.` : 'Currently empty.';
354
+ return `Over ${target.label}. ${content}`;
355
+ },
356
+ onDragEnd({
357
+ active,
358
+ over
359
+ }) {
360
+ if (!over) {
361
+ return `${getChoiceLabel(active.id)} was returned to its original position.`;
362
+ }
363
+ return `Dropped ${getChoiceLabel(active.id)} in ${getDropTargetLabel(over.id).label}.`;
364
+ },
365
+ onDragCancel({
366
+ active
367
+ }) {
368
+ return `Cancelled. ${getChoiceLabel(active.id)} was returned to its original position.`;
369
+ }
370
+ };
181
371
  return /*#__PURE__*/_react.default.createElement(_core.DndContext, {
372
+ sensors: sensors,
373
+ collisionDetection: _core.rectIntersection,
182
374
  onDragStart: this.onDragStart,
183
375
  onDragEnd: this.onPlaceAnswer,
184
- modifiers: [_modifiers.restrictToFirstScrollableAncestor]
376
+ onDragCancel: this.onDragCancel,
377
+ modifiers: [_modifiers.restrictToFirstScrollableAncestor],
378
+ accessibility: {
379
+ screenReaderInstructions: {
380
+ draggable: 'Press Space or Enter to pick up this answer choice. Once picked up, use Tab or Shift+Tab to cycle through response areas, or use arrow keys to move it freely. Press Space or Enter to drop, or Escape to cancel. You can also click an answer choice to select it, then click a response area to place it there.'
381
+ }
382
+ }
185
383
  }, /*#__PURE__*/_react.default.createElement(MainContainer, null, /*#__PURE__*/_react.default.createElement(_renderUi.PreviewPrompt, {
186
384
  className: "prompt",
187
385
  prompt: prompt
@@ -190,20 +388,26 @@ class Main extends _react.default.Component {
190
388
  toggled: showCorrectAnswer,
191
389
  onToggle: this.toggleShowCorrect,
192
390
  language: language
193
- }), /*#__PURE__*/_react.default.createElement(_answerArea.default, {
391
+ }), /*#__PURE__*/_react.default.createElement(InteractiveRegion, null, /*#__PURE__*/_react.default.createElement(InteractiveRegionContent, null, /*#__PURE__*/_react.default.createElement(_answerArea.default, {
194
392
  instanceId: this.instanceId,
195
393
  model: model,
196
394
  session: session,
197
395
  onRemoveAnswer: id => this.onRemoveAnswer(id),
198
396
  disabled: mode !== 'gather',
199
- showCorrect: showCorrectAnswer
397
+ showCorrect: showCorrectAnswer,
398
+ selectedAnswer: this.state.selectedAnswer,
399
+ onChoiceClick: this.onChoiceClick,
400
+ onPlacementClick: this.onPlacementClick
200
401
  }), /*#__PURE__*/_react.default.createElement(_choicesList.default, {
201
402
  instanceId: this.instanceId,
202
403
  model: model,
203
404
  session: session,
204
405
  disabled: mode !== 'gather',
205
- onRemoveAnswer: id => this.onRemoveAnswer(id)
206
- }), model.correctness && model.feedback && !showCorrectAnswer && /*#__PURE__*/_react.default.createElement(_renderUi.Feedback, {
406
+ onRemoveAnswer: id => this.onRemoveAnswer(id),
407
+ selectedAnswer: this.state.selectedAnswer,
408
+ onChoiceClick: this.onChoiceClick,
409
+ onPlacementClick: this.onPlacementClick
410
+ }))), model.correctness && model.feedback && !showCorrectAnswer && /*#__PURE__*/_react.default.createElement(_renderUi.Feedback, {
207
411
  correctness: model.correctness.correctness,
208
412
  feedback: model.feedback
209
413
  })), /*#__PURE__*/_react.default.createElement(_core.DragOverlay, null, this.renderDragOverlay()));
package/lib/main.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"main.js","names":["_react","_interopRequireDefault","require","_propTypes","_drag","_core","_modifiers","_correctAnswerToggle","_renderUi","_styles","_lodashEs","_answerArea","_choicesList","_answer","MainContainer","styled","display","flexDirection","justifyContent","color","text","backgroundColor","background","Main","React","Component","constructor","props","_defineProperty2","default","event","active","data","current","rect","node","width","height","getBoundingClientRect","setState","draggingElement","over","activeData","overData","session","onSessionChange","model","config","duplicates","isUndefined","value","type","promptId","undefined","answerId","id","sourcePromptId","targetPromptId","existingPlacement","findKey","val","swap","targetHasItem","temp","showCorrectAnswer","state","createElement","Answer","title","disabled","isDragging","style","boxSizing","instanceId","uniqueId","onRemoveAnswer","render","mode","prompt","language","DndContext","onDragStart","onDragEnd","onPlaceAnswer","modifiers","restrictToFirstScrollableAncestor","PreviewPrompt","className","show","toggled","onToggle","toggleShowCorrect","showCorrect","correctness","feedback","Feedback","DragOverlay","renderDragOverlay","exports","PropTypes","object","isRequired","func","string","_default"],"sources":["../src/main.jsx"],"sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\nimport { swap } from '@pie-lib/drag';\nimport { DndContext, DragOverlay } from '@dnd-kit/core';\nimport { restrictToFirstScrollableAncestor } from '@dnd-kit/modifiers';\nimport CorrectAnswerToggle from '@pie-lib/correct-answer-toggle';\nimport { color, Feedback, PreviewPrompt } from '@pie-lib/render-ui';\nimport { styled } from '@mui/material/styles';\nimport { findKey, isUndefined, uniqueId } from 'lodash-es';\nimport AnswerArea from './answer-area';\nimport ChoicesList from './choices-list';\nimport { Answer } from './answer';\n\nconst MainContainer = styled('div')({\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n color: color.text(),\n backgroundColor: color.background(),\n});\n\nexport class Main extends React.Component {\n static propTypes = {\n session: PropTypes.object.isRequired,\n onSessionChange: PropTypes.func,\n model: PropTypes.object.isRequired,\n prompt: PropTypes.string,\n };\n\n constructor(props) {\n super(props);\n\n this.instanceId = uniqueId();\n this.state = {\n showCorrectAnswer: false,\n draggingElement: null,\n };\n }\n\n onRemoveAnswer(id) {\n const { session, onSessionChange } = this.props;\n\n session.value[id] = undefined;\n\n onSessionChange(session);\n }\n\n onDragStart = (event) => {\n const { active } = event;\n\n if (active?.data?.current) {\n let rect = null;\n const node = active.node?.current;\n\n if (node) {\n const { width, height } = node.getBoundingClientRect();\n rect = { width, height };\n }\n\n this.setState({\n draggingElement: { ...active.data.current, rect },\n });\n }\n };\n\n onPlaceAnswer = (event) => {\n this.setState({ draggingElement: null });\n const { active, over } = event;\n\n if (!active) {\n return;\n }\n\n const activeData = active.data.current;\n const overData = over?.data.current;\n\n if (!activeData) {\n return;\n }\n\n const { session, onSessionChange, model } = this.props;\n const {\n config: { duplicates },\n } = model;\n\n if (isUndefined(session.value)) {\n session.value = {};\n }\n\n // dropping a placed answer back to the choices pool = remove it\n if (overData.type === 'choices-pool' && activeData.promptId !== undefined) {\n session.value[activeData.promptId] = undefined;\n onSessionChange(session);\n return;\n }\n\n const answerId = activeData.id;\n const sourcePromptId = activeData.promptId;\n\n // Handle dropping onto a drop zone\n if (overData && overData.type === 'drop-zone' && overData.promptId != null) {\n const targetPromptId = overData.promptId;\n\n if (activeData.type === 'choice' && overData.type === 'drop-zone' && targetPromptId !== undefined) {\n // check if this choice is already placed somewhere\n const existingPlacement = findKey(session.value, (val) => val === answerId);\n\n if (existingPlacement && !duplicates) {\n // swap if duplicates not allowed\n session.value = swap(session.value, existingPlacement, targetPromptId);\n } else {\n // place answer\n session.value[targetPromptId] = answerId;\n }\n }\n // Handle moving a placed item (target) to another drop zone\n else if (activeData.type === 'target' && sourcePromptId != null) {\n // If moving to a different placeholder\n if (sourcePromptId !== targetPromptId) {\n const targetHasItem = session.value[targetPromptId] != null;\n\n if (targetHasItem && !duplicates) {\n // swap items between placeholders\n const temp = session.value[targetPromptId];\n session.value[targetPromptId] = answerId;\n session.value[sourcePromptId] = temp;\n } else if (!targetHasItem) {\n // move item to empty placeholder\n session.value[targetPromptId] = answerId;\n delete session.value[sourcePromptId];\n }\n }\n }\n\n onSessionChange(session);\n }\n };\n\n toggleShowCorrect = () => {\n this.setState({ showCorrectAnswer: !this.state.showCorrectAnswer });\n };\n\n renderDragOverlay = () => {\n const { draggingElement } = this.state;\n\n if (!draggingElement) return null;\n\n return (\n <Answer\n id={draggingElement.id}\n title={draggingElement.value}\n disabled={false}\n isDragging={false}\n style={\n draggingElement.rect\n ? { width: draggingElement.rect.width, height: draggingElement.rect.height, boxSizing: 'border-box' }\n : {}\n }\n />\n );\n };\n\n render() {\n const { showCorrectAnswer } = this.state;\n const { model, session } = this.props;\n const { config, mode } = model;\n const { prompt, language } = config;\n\n return (\n <DndContext\n onDragStart={this.onDragStart}\n onDragEnd={this.onPlaceAnswer}\n modifiers={[restrictToFirstScrollableAncestor]}\n >\n <MainContainer>\n <PreviewPrompt className=\"prompt\" prompt={prompt} />\n\n <CorrectAnswerToggle\n show={mode === 'evaluate'}\n toggled={showCorrectAnswer}\n onToggle={this.toggleShowCorrect}\n language={language}\n />\n\n <AnswerArea\n instanceId={this.instanceId}\n model={model}\n session={session}\n onRemoveAnswer={(id) => this.onRemoveAnswer(id)}\n disabled={mode !== 'gather'}\n showCorrect={showCorrectAnswer}\n />\n\n <ChoicesList\n instanceId={this.instanceId}\n model={model}\n session={session}\n disabled={mode !== 'gather'}\n onRemoveAnswer={(id) => this.onRemoveAnswer(id)}\n />\n\n {model.correctness && model.feedback && !showCorrectAnswer && (\n <Feedback correctness={model.correctness.correctness} feedback={model.feedback} />\n )}\n </MainContainer>\n <DragOverlay>{this.renderDragOverlay()}</DragOverlay>\n </DndContext>\n );\n }\n}\n\nexport default Main;\n"],"mappings":"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","ignoreList":[]}
1
+ {"version":3,"file":"main.js","names":["_react","_interopRequireDefault","require","_propTypes","_drag","_core","_modifiers","_keyboardCoordinates","_correctAnswerToggle","_renderUi","_styles","_lodashEs","_answerArea","_choicesList","_answer","CLICK_AFTER_DRAG_GUARD_MS","sensors","sensor","PointerSensor","options","activationConstraint","distance","KeyboardSensor","coordinateGetter","closestDroppableKeyboardCoordinates","keyboardCodes","start","KeyboardCode","Space","Enter","cancel","Esc","end","MainContainer","styled","display","flexDirection","justifyContent","color","text","backgroundColor","background","InteractiveRegion","width","overflowX","overflowY","InteractiveRegionContent","minWidth","Main","React","Component","constructor","props","_defineProperty2","default","event","active","data","current","rect","node","height","getBoundingClientRect","setState","draggingElement","selectAnswer","cancelSelection","lastDragEndAt","Date","now","activeData","overData","session","onSessionChange","model","config","duplicates","isUndefined","value","type","promptId","undefined","answerId","id","sourcePromptId","targetPromptId","existingPlacement","findKey","val","swap","targetHasItem","temp","over","placeAnswer","a","b","selectedAnswer","state","isSameAnswer","document","dispatchEvent","KeyboardEvent","code","bubbles","cancelable","endAnyLiveKeyboardDrag","isClickSoonAfterDragEnd","toggleAnswerSelection","placeSelectedAnswer","showCorrectAnswer","createElement","Answer","title","disabled","isDragging","style","boxSizing","instanceId","uniqueId","onRemoveAnswer","render","mode","prompt","language","getChoiceLabel","dragId","String","replace","answer","answers","find","trim","getDropTargetLabel","dropId","label","choiceId","promptItem","prompts","p","announcements","onDragStart","onDragOver","target","content","onDragEnd","onDragCancel","DndContext","collisionDetection","rectIntersection","onPlaceAnswer","modifiers","restrictToFirstScrollableAncestor","accessibility","screenReaderInstructions","draggable","PreviewPrompt","className","show","toggled","onToggle","toggleShowCorrect","showCorrect","onChoiceClick","onPlacementClick","correctness","feedback","Feedback","DragOverlay","renderDragOverlay","exports","PropTypes","object","isRequired","func","string","_default"],"sources":["../src/main.jsx"],"sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\nimport { swap } from '@pie-lib/drag';\nimport { DndContext, DragOverlay, PointerSensor, KeyboardSensor, KeyboardCode, rectIntersection } from '@dnd-kit/core';\nimport { restrictToFirstScrollableAncestor } from '@dnd-kit/modifiers';\nimport { closestDroppableKeyboardCoordinates } from './keyboard-coordinates';\nimport CorrectAnswerToggle from '@pie-lib/correct-answer-toggle';\nimport { color, Feedback, PreviewPrompt } from '@pie-lib/render-ui';\nimport { styled } from '@mui/material/styles';\nimport { findKey, isUndefined, uniqueId } from 'lodash-es';\nimport AnswerArea from './answer-area';\nimport ChoicesList from './choices-list';\nimport { Answer } from './answer';\n\n// A click that lands right after a real drag gesture ends (pointer drag-and-drop, or\n// the browser's own synthetic click for a keyboard Space/Enter) must be ignored by the\n// new click-to-select/click-to-place handlers below, or it would immediately reopen or\n// re-trigger a selection for a drag that just completed.\nconst CLICK_AFTER_DRAG_GUARD_MS = 250;\n\nconst sensors = [\n // Without an activationConstraint, dnd-kit's PointerSensor calls its internal\n // handleStart() synchronously on pointerdown, before any movement — meaning a plain\n // click is itself \"activated\" as a drag. Once activated, dnd-kit adds a capture-phase\n // document click listener that calls stopPropagation() (to suppress the native\n // \"ghost click\" a real drag leaves behind), which also swallows the click for a\n // gesture with zero movement, before it ever reaches our own onClick handlers below.\n // Requiring 8px of movement (matching @pie-lib/drag's DragProvider convention used\n // elsewhere in this codebase) defers activation until an actual drag gesture is\n // underway, so a plain click passes through untouched.\n { sensor: PointerSensor, options: { activationConstraint: { distance: 8 } } },\n {\n sensor: KeyboardSensor,\n options: {\n coordinateGetter: closestDroppableKeyboardCoordinates,\n keyboardCodes: {\n start: [KeyboardCode.Space, KeyboardCode.Enter],\n cancel: [KeyboardCode.Esc],\n end: [KeyboardCode.Space, KeyboardCode.Enter],\n },\n },\n },\n];\n\nconst MainContainer = styled('div')({\n display: 'flex',\n flexDirection: 'column',\n justifyContent: 'center',\n color: color.text(),\n backgroundColor: color.background(),\n});\n\nconst InteractiveRegion = styled('div')({\n width: '100%',\n overflowX: 'auto',\n overflowY: 'hidden',\n});\n\n// A block child of a scroll port is sized to the scroll port, so it has to opt out explicitly for\n// the content to be able to overflow. min-content keeps the rows and the pool the same width.\nconst InteractiveRegionContent = styled('div')({\n display: 'flex',\n flexDirection: 'column',\n minWidth: 'min-content',\n});\n\nexport class Main extends React.Component {\n static propTypes = {\n session: PropTypes.object.isRequired,\n onSessionChange: PropTypes.func,\n model: PropTypes.object.isRequired,\n prompt: PropTypes.string,\n };\n\n constructor(props) {\n super(props);\n\n this.instanceId = uniqueId();\n this.state = {\n showCorrectAnswer: false,\n draggingElement: null,\n selectedAnswer: null,\n };\n this.lastDragEndAt = 0;\n }\n\n onRemoveAnswer(id) {\n const { session, onSessionChange } = this.props;\n\n session.value[id] = undefined;\n\n onSessionChange(session);\n }\n\n onDragStart = (event) => {\n const { active } = event;\n\n if (active?.data?.current) {\n let rect = null;\n const node = active.node?.current;\n\n if (node) {\n const { width, height } = node.getBoundingClientRect();\n rect = { width, height };\n }\n\n this.setState({\n draggingElement: { ...active.data.current, rect },\n });\n this.selectAnswer(active.data.current);\n }\n };\n\n onDragCancel = () => {\n this.setState({ draggingElement: null });\n this.cancelSelection();\n this.lastDragEndAt = Date.now();\n };\n\n // Pure placement logic\n placeAnswer = (activeData, overData) => {\n if (!activeData || !overData) {\n return;\n }\n\n const { session, onSessionChange, model } = this.props;\n const {\n config: { duplicates },\n } = model;\n\n if (isUndefined(session.value)) {\n session.value = {};\n }\n\n // dropping a placed answer back to the choices pool = remove it\n if (overData.type === 'choices-pool' && activeData.promptId !== undefined) {\n session.value[activeData.promptId] = undefined;\n onSessionChange(session);\n return;\n }\n\n const answerId = activeData.id;\n const sourcePromptId = activeData.promptId;\n\n // Handle dropping onto a drop zone\n if (overData.type === 'drop-zone' && overData.promptId != null) {\n const targetPromptId = overData.promptId;\n\n if (activeData.type === 'choice' && targetPromptId !== undefined) {\n // check if this choice is already placed somewhere\n const existingPlacement = findKey(session.value, (val) => val === answerId);\n\n if (existingPlacement && !duplicates) {\n // swap if duplicates not allowed\n session.value = swap(session.value, existingPlacement, targetPromptId);\n } else {\n // place answer\n session.value[targetPromptId] = answerId;\n }\n }\n // Handle moving a placed item (target) to another drop zone\n else if (activeData.type === 'target' && sourcePromptId != null) {\n // If moving to a different placeholder\n if (sourcePromptId !== targetPromptId) {\n const targetHasItem = session.value[targetPromptId] != null;\n\n if (targetHasItem && !duplicates) {\n // swap items between placeholders\n const temp = session.value[targetPromptId];\n session.value[targetPromptId] = answerId;\n session.value[sourcePromptId] = temp;\n } else if (!targetHasItem) {\n // move item to empty placeholder\n session.value[targetPromptId] = answerId;\n delete session.value[sourcePromptId];\n }\n }\n }\n\n onSessionChange(session);\n }\n };\n\n onPlaceAnswer = (event) => {\n this.setState({ draggingElement: null });\n const { active, over } = event;\n\n if (!active) {\n return;\n }\n\n const activeData = active.data.current;\n const overData = over?.data.current;\n\n if (!activeData) {\n return;\n }\n\n this.placeAnswer(activeData, overData);\n this.cancelSelection();\n this.lastDragEndAt = Date.now();\n };\n\n isSameAnswer = (a, b) => !!a && !!b && a.type === b.type && a.id === b.id && a.promptId === b.promptId;\n\n // Unconditionally selects (used by the drag-start mirror, and internally when\n // switching from one choice to another).\n selectAnswer = (data) => {\n this.setState({ selectedAnswer: data });\n };\n\n // Click-to-select semantics: selecting the currently-selected answer again clears\n // the selection instead of re-selecting it.\n toggleAnswerSelection = (data) => {\n this.setState((state) => ({\n selectedAnswer: this.isSameAnswer(state.selectedAnswer, data) ? null : data,\n }));\n };\n\n cancelSelection = () => {\n this.setState({ selectedAnswer: null });\n };\n\n // If a real dnd-kit drag (started via keyboard Space/Enter) is still live when a\n // click completes the placement below, it needs to be cleanly ended — otherwise\n // dnd-kit would still think a drag is in progress (still listening for Tab/arrow/\n // Space/Escape, still showing the drag overlay) for a placement the click already\n // performed. Escape is already configured as this sensor's cancel key, and\n // dispatching it as a real DOM KeyboardEvent is how dnd-kit's own document-level\n // listener is reached from outside its sensor. onDragCancel is intentionally not\n // wired to redo any placement — it only resets local UI state — so this is safe to\n // call unconditionally, including when no drag is actually live (dnd-kit simply has\n // no listener attached in that case, and the dispatch is a no-op).\n endAnyLiveKeyboardDrag = () => {\n document.dispatchEvent(new KeyboardEvent('keydown', { code: 'Escape', bubbles: true, cancelable: true }));\n };\n\n placeSelectedAnswer = (overData) => {\n const { selectedAnswer } = this.state;\n\n if (!selectedAnswer) {\n return;\n }\n\n this.placeAnswer(selectedAnswer, overData);\n this.cancelSelection();\n this.endAnyLiveKeyboardDrag();\n this.lastDragEndAt = Date.now();\n };\n\n isClickSoonAfterDragEnd = () => Date.now() - this.lastDragEndAt < CLICK_AFTER_DRAG_GUARD_MS;\n\n onChoiceClick = (data) => {\n if (this.isClickSoonAfterDragEnd()) {\n return;\n }\n\n this.toggleAnswerSelection(data);\n };\n\n onPlacementClick = (overData) => {\n if (this.isClickSoonAfterDragEnd()) {\n return;\n }\n\n this.placeSelectedAnswer(overData);\n };\n\n toggleShowCorrect = () => {\n this.setState({ showCorrectAnswer: !this.state.showCorrectAnswer });\n };\n\n renderDragOverlay = () => {\n const { draggingElement } = this.state;\n\n if (!draggingElement) return null;\n\n return (\n <Answer\n id={draggingElement.id}\n title={draggingElement.value}\n disabled={false}\n isDragging={false}\n style={\n draggingElement.rect\n ? { width: draggingElement.rect.width, height: draggingElement.rect.height, boxSizing: 'border-box' }\n : {}\n }\n />\n );\n };\n\n render() {\n const { showCorrectAnswer } = this.state;\n const { model, session } = this.props;\n const { config, mode } = model;\n const { prompt, language } = config;\n\n // Helpers for accessible announcements\n const getChoiceLabel = (dragId) => {\n // dragId is like \"choice-123\" or \"target-123\"\n const answerId = String(dragId).replace(/^(choice|target)-/, '');\n const answer = config.answers.find((a) => String(a.id) === answerId);\n\n if (answer?.title) {\n // Strip HTML tags for screen reader\n const text = answer.title.replace(/<[^>]*>/g, '').trim();\n return text || `Answer ${answerId}`;\n }\n\n return `Answer ${answerId}`;\n };\n\n const getDropTargetLabel = (dropId) => {\n // dropId is like \"drop-456\" or \"choices-pool\"\n if (dropId === 'choices-pool') {\n return { label: 'Choices list', choiceId: null };\n }\n\n const promptId = String(dropId).replace(/^drop-/, '');\n const promptItem = config.prompts.find((p) => String(p.id) === promptId);\n const label = promptItem?.title\n ? `Response area for ${promptItem.title.replace(/<[^>]*>/g, '').trim()}`\n : `Response area ${promptId}`;\n const choiceId = session.value?.[promptId];\n\n return { label, choiceId: choiceId || null };\n };\n\n const announcements = {\n onDragStart({ active }) {\n return `Picked up ${getChoiceLabel(active.id)}. Use Tab to move between response areas, then press Space or Enter to drop.`;\n },\n\n onDragOver({ active, over }) {\n if (!over) {\n return `${getChoiceLabel(active.id)} is not over a response area.`;\n }\n\n const target = getDropTargetLabel(over.id);\n const content = target.choiceId ? `Currently contains ${getChoiceLabel(target.choiceId)}.` : 'Currently empty.';\n\n return `Over ${target.label}. ${content}`;\n },\n\n onDragEnd({ active, over }) {\n if (!over) {\n return `${getChoiceLabel(active.id)} was returned to its original position.`;\n }\n\n return `Dropped ${getChoiceLabel(active.id)} in ${getDropTargetLabel(over.id).label}.`;\n },\n\n onDragCancel({ active }) {\n return `Cancelled. ${getChoiceLabel(active.id)} was returned to its original position.`;\n },\n };\n\n return (\n <DndContext\n sensors={sensors}\n collisionDetection={rectIntersection}\n onDragStart={this.onDragStart}\n onDragEnd={this.onPlaceAnswer}\n onDragCancel={this.onDragCancel}\n modifiers={[restrictToFirstScrollableAncestor]}\n accessibility={{\n screenReaderInstructions: {\n draggable:\n 'Press Space or Enter to pick up this answer choice. Once picked up, use Tab or Shift+Tab to cycle through response areas, or use arrow keys to move it freely. Press Space or Enter to drop, or Escape to cancel. You can also click an answer choice to select it, then click a response area to place it there.',\n },\n }}\n >\n <MainContainer>\n <PreviewPrompt className=\"prompt\" prompt={prompt} />\n\n <CorrectAnswerToggle\n show={mode === 'evaluate'}\n toggled={showCorrectAnswer}\n onToggle={this.toggleShowCorrect}\n language={language}\n />\n\n <InteractiveRegion>\n <InteractiveRegionContent>\n <AnswerArea\n instanceId={this.instanceId}\n model={model}\n session={session}\n onRemoveAnswer={(id) => this.onRemoveAnswer(id)}\n disabled={mode !== 'gather'}\n showCorrect={showCorrectAnswer}\n selectedAnswer={this.state.selectedAnswer}\n onChoiceClick={this.onChoiceClick}\n onPlacementClick={this.onPlacementClick}\n />\n\n <ChoicesList\n instanceId={this.instanceId}\n model={model}\n session={session}\n disabled={mode !== 'gather'}\n onRemoveAnswer={(id) => this.onRemoveAnswer(id)}\n selectedAnswer={this.state.selectedAnswer}\n onChoiceClick={this.onChoiceClick}\n onPlacementClick={this.onPlacementClick}\n />\n </InteractiveRegionContent>\n </InteractiveRegion>\n\n {model.correctness && model.feedback && !showCorrectAnswer && (\n <Feedback correctness={model.correctness.correctness} feedback={model.feedback} />\n )}\n </MainContainer>\n <DragOverlay>{this.renderDragOverlay()}</DragOverlay>\n </DndContext>\n );\n }\n}\n\nexport default Main;\n"],"mappings":"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","ignoreList":[]}
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
7
- "version": "7.1.7",
7
+ "version": "7.1.9",
8
8
  "description": "",
9
9
  "scripts": {
10
10
  "test": "echo \"Error: no test specified\" && exit 1",
@@ -19,7 +19,7 @@
19
19
  "@mui/material": "^7.3.4",
20
20
  "@pie-framework/pie-player-events": "^0.1.0",
21
21
  "@pie-lib/correct-answer-toggle": "4.0.5",
22
- "@pie-lib/drag": "4.0.6",
22
+ "@pie-lib/drag": "4.1.0",
23
23
  "@pie-lib/math-rendering": "5.1.0",
24
24
  "@pie-lib/render-ui": "6.1.3",
25
25
  "debug": "^4.1.1",
@@ -30,7 +30,7 @@
30
30
  },
31
31
  "author": "",
32
32
  "license": "ISC",
33
- "gitHead": "3da9547e82ab80b9119ef5854e3593c3e040309d",
33
+ "gitHead": "0f939adae5927fe0a54d21a4a98e224775562406",
34
34
  "main": "lib/index.js",
35
35
  "module": "src/index.js"
36
36
  }