@pie-lib/mask-markup 1.33.3-next.2 → 1.33.4-next.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.
Files changed (72) hide show
  1. package/CHANGELOG.md +6 -76
  2. package/lib/__tests__/drag-in-the-blank.test.js +129 -0
  3. package/lib/__tests__/index.test.js +42 -0
  4. package/lib/__tests__/mask.test.js +163 -0
  5. package/lib/__tests__/serialization.test.js +44 -0
  6. package/lib/__tests__/utils.js +14 -0
  7. package/lib/__tests__/with-mask.test.js +110 -0
  8. package/lib/choices/__tests__/index.test.js +101 -0
  9. package/lib/choices/choice.js +99 -204
  10. package/lib/choices/choice.js.map +1 -1
  11. package/lib/choices/index.js +22 -54
  12. package/lib/choices/index.js.map +1 -1
  13. package/lib/componentize.js +2 -6
  14. package/lib/componentize.js.map +1 -1
  15. package/lib/components/__tests__/blank.test.js +189 -0
  16. package/lib/components/__tests__/correct-input.test.js +132 -0
  17. package/lib/components/__tests__/dropdown.test.js +134 -0
  18. package/lib/components/__tests__/input.test.js +129 -0
  19. package/lib/components/blank.js +304 -362
  20. package/lib/components/blank.js.map +1 -1
  21. package/lib/components/correct-input.js +42 -66
  22. package/lib/components/correct-input.js.map +1 -1
  23. package/lib/components/dropdown.js +219 -258
  24. package/lib/components/dropdown.js.map +1 -1
  25. package/lib/components/input.js +11 -18
  26. package/lib/components/input.js.map +1 -1
  27. package/lib/constructed-response.js +39 -53
  28. package/lib/constructed-response.js.map +1 -1
  29. package/lib/customizable.js +6 -10
  30. package/lib/customizable.js.map +1 -1
  31. package/lib/drag-in-the-blank.js +141 -106
  32. package/lib/drag-in-the-blank.js.map +1 -1
  33. package/lib/index.js +1 -8
  34. package/lib/index.js.map +1 -1
  35. package/lib/inline-dropdown.js +5 -13
  36. package/lib/inline-dropdown.js.map +1 -1
  37. package/lib/mask.js +61 -119
  38. package/lib/mask.js.map +1 -1
  39. package/lib/serialization.js +9 -49
  40. package/lib/serialization.js.map +1 -1
  41. package/lib/with-mask.js +31 -59
  42. package/lib/with-mask.js.map +1 -1
  43. package/package.json +12 -20
  44. package/src/__tests__/drag-in-the-blank.test.js +66 -26
  45. package/src/__tests__/mask.test.js +147 -112
  46. package/src/__tests__/with-mask.test.js +44 -19
  47. package/src/choices/__tests__/index.test.js +38 -25
  48. package/src/choices/choice.jsx +86 -153
  49. package/src/choices/index.jsx +9 -3
  50. package/src/components/__tests__/blank.test.js +92 -156
  51. package/src/components/__tests__/correct-input.test.js +60 -19
  52. package/src/components/__tests__/dropdown.test.js +61 -19
  53. package/src/components/__tests__/input.test.js +72 -20
  54. package/src/components/blank.jsx +273 -272
  55. package/src/components/correct-input.jsx +33 -39
  56. package/src/components/dropdown.jsx +173 -161
  57. package/src/constructed-response.jsx +22 -18
  58. package/src/drag-in-the-blank.jsx +131 -42
  59. package/src/mask.jsx +38 -29
  60. package/src/with-mask.jsx +7 -4
  61. package/esm/index.css +0 -847
  62. package/esm/index.js +0 -195939
  63. package/esm/index.js.map +0 -1
  64. package/esm/package.json +0 -3
  65. package/src/__tests__/__snapshots__/drag-in-the-blank.test.js.snap +0 -316
  66. package/src/__tests__/__snapshots__/mask.test.js.snap +0 -55
  67. package/src/__tests__/__snapshots__/with-mask.test.js.snap +0 -62
  68. package/src/choices/__tests__/__snapshots__/index.test.js.snap +0 -209
  69. package/src/components/__tests__/__snapshots__/blank.test.js.snap +0 -111
  70. package/src/components/__tests__/__snapshots__/correct-input.test.js.snap +0 -64
  71. package/src/components/__tests__/__snapshots__/dropdown.test.js.snap +0 -136
  72. package/src/components/__tests__/__snapshots__/input.test.js.snap +0 -34
@@ -1,269 +1,248 @@
1
- import grey from '@material-ui/core/colors/grey';
2
- import React from 'react';
3
- import ReactDOM from 'react-dom';
1
+ import React, { useRef, useState, useEffect } from 'react';
4
2
  import PropTypes from 'prop-types';
5
3
  import { renderMath } from '@pie-lib/math-rendering';
6
4
  import debug from 'debug';
7
- import { DragSource, DropTarget } from '@pie-lib/drag';
8
- import { withStyles } from '@material-ui/core/styles';
9
- import Chip from '@material-ui/core/Chip';
5
+ import { useDraggable, useDroppable } from '@dnd-kit/core';
6
+ import { CSS } from '@dnd-kit/utilities';
7
+ import { styled } from '@mui/material/styles';
8
+ import Chip from '@mui/material/Chip';
10
9
  import classnames from 'classnames';
11
10
  import { color } from '@pie-lib/render-ui';
11
+ import { grey } from '@mui/material/colors';
12
12
 
13
13
  const log = debug('pie-lib:mask-markup:blank');
14
- export const DRAG_TYPE = 'MaskBlank';
15
14
 
16
- const useStyles = withStyles(() => ({
17
- content: {
18
- border: `solid 0px ${color.primary()}`,
19
- minWidth: '200px',
20
- touchAction: 'none',
15
+ const StyledContent = styled('span')(({ dragged, over }) => ({
16
+ border: `solid 0px ${color.primary()}`,
17
+ minWidth: '200px',
18
+ touchAction: 'none',
19
+ overflow: 'hidden',
20
+ whiteSpace: 'nowrap',
21
+ opacity: 1,
22
+ ...(over && {
23
+ whiteSpace: 'nowrap',
24
+ overflow: 'hidden',
25
+ }),
26
+ ...(dragged && {
27
+ opacity: 0.5,
28
+ }),
29
+ }));
30
+
31
+ const StyledChip = styled(Chip)(() => ({
32
+ backgroundColor: color.background(),
33
+ border: `2px dashed ${color.text()}`,
34
+ color: color.text(),
35
+ fontSize: 'inherit',
36
+ maxWidth: '374px',
37
+ position: 'relative',
38
+ borderRadius: '3px',
39
+ '&.over': {
40
+ whiteSpace: 'nowrap',
21
41
  overflow: 'hidden',
22
- whiteSpace: 'nowrap', // Prevent line wrapping
23
42
  },
24
- chip: {
25
- backgroundColor: color.background(),
26
- border: `2px dashed ${color.text()}`,
27
- color: color.text(),
28
- fontSize: 'inherit',
29
- maxWidth: '374px',
30
- position: 'relative',
31
- borderRadius: '3px',
43
+ '&.parentOver': {
44
+ border: `1px solid ${grey[500]}`,
45
+ backgroundColor: `${grey[300]}`,
32
46
  },
33
- chipLabel: {
34
- whiteSpace: 'normal',
35
- // Added for touch devices, for image content.
36
- // This will prevent the context menu from appearing and not allowing other interactions with the image.
37
- // If interactions with the image in the token will be requested we should handle only the context Menu.
38
- pointerEvents: 'none',
39
- '& img': {
40
- display: 'block',
41
- padding: '2px 0',
42
- },
43
- // Remove default <p> margins to ensure consistent spacing across all wrapped content (p, span, div, math)
44
- // Padding for top and bottom will instead be controlled by the container for consistent layout
45
- // Ensures consistent behavior with pie-api-browser, where marginTop is already removed by a Bootstrap stylesheet
46
- '& p': {
47
- marginTop: '0',
48
- marginBottom: '0',
49
- },
50
- '& mjx-frac': {
51
- fontSize: '120% !important',
52
- },
47
+ '&.correct': {
48
+ border: `solid 1px ${color.correct()}`,
53
49
  },
54
- hidden: {
55
- color: 'transparent',
56
- opacity: 0,
50
+ '&.incorrect': {
51
+ border: `solid 1px ${color.incorrect()}`,
57
52
  },
58
- dragged: {
59
- position: 'absolute',
60
- left: 16,
61
- maxWidth: '60px',
53
+ '&.Mui-disabled': {
54
+ opacity: 1,
62
55
  },
63
- correct: {
64
- border: `solid 1px ${color.correct()}`,
56
+ }));
57
+
58
+ const StyledChipLabel = styled('span')(() => ({
59
+ whiteSpace: 'normal',
60
+ // Added for touch devices, for image content.
61
+ // This will prevent the context menu from appearing and not allowing other interactions with the image.
62
+ // If interactions with the image in the token will be requested we should handle only the context Menu.
63
+ pointerEvents: 'none',
64
+ '& img': {
65
+ display: 'block',
66
+ padding: '2px 0',
65
67
  },
66
- incorrect: {
67
- border: `solid 1px ${color.incorrect()}`,
68
+ // Remove default <p> margins to ensure consistent spacing across all wrapped content (p, span, div, math)
69
+ // Padding for top and bottom will instead be controlled by the container for consistent layout
70
+ // Ensures consistent behavior with pie-api-browser, where marginTop is already removed by a Bootstrap stylesheet
71
+ '& p': {
72
+ marginTop: '0',
73
+ marginBottom: '0',
68
74
  },
69
- over: {
75
+ '& mjx-frac': {
76
+ fontSize: '120% !important',
77
+ },
78
+ '&.over': {
70
79
  whiteSpace: 'nowrap',
71
80
  overflow: 'hidden',
72
81
  },
73
- parentOver: {
74
- border: `1px solid ${grey[500]}`,
75
- backgroundColor: `${grey[300]}`,
82
+ '&.hidden': {
83
+ color: 'transparent',
84
+ opacity: 0,
85
+ },
86
+ '&.dragged': {
87
+ position: 'absolute',
88
+ left: 16,
89
+ maxWidth: '60px',
76
90
  },
77
91
  }));
78
92
 
79
- export class BlankContent extends React.Component {
80
- constructor() {
81
- super();
82
- this.state = {
83
- height: 0,
84
- width: 0,
85
- };
86
- }
87
-
88
- handleImageLoad = () => {
89
- this.updateDimensions();
93
+ function BlankContent({
94
+ disabled,
95
+ choice,
96
+ isOver,
97
+ isDragging,
98
+ dragItem,
99
+ correct,
100
+ emptyResponseAreaWidth,
101
+ emptyResponseAreaHeight,
102
+ }) {
103
+ const rootRef = useRef(null);
104
+ const spanRef = useRef(null);
105
+ const frozenRef = useRef(null); // to use during dragging to prevent flickering
106
+ const [dimensions, setDimensions] = useState({ height: 0, width: 0 });
107
+
108
+ const handleImageLoad = () => {
109
+ updateDimensions();
90
110
  };
91
111
 
92
- handleElements() {
93
- const imageElement = this.spanRef?.querySelector('img');
94
-
112
+ const handleElements = () => {
113
+ const imageElement = spanRef.current?.querySelector('img');
95
114
  if (imageElement) {
96
- imageElement.onload = this.handleImageLoad;
115
+ imageElement.onload = handleImageLoad;
97
116
  } else {
98
117
  setTimeout(() => {
99
- this.updateDimensions();
118
+ updateDimensions();
100
119
  }, 300);
101
120
  }
102
- }
103
-
104
- componentDidMount() {
105
- this.handleElements();
106
- if (this.rootRef) {
107
- this.rootRef.addEventListener('touchstart', this.handleTouchStart, { passive: false });
108
- }
109
- }
110
-
111
- componentDidUpdate(prevProps) {
112
- renderMath(this.rootRef);
113
- const { choice: currentChoice } = this.props;
114
- const { choice: prevChoice } = prevProps;
115
-
116
- if (JSON.stringify(currentChoice) !== JSON.stringify(prevChoice)) {
117
- if (!currentChoice) {
118
- this.setState({
119
- height: 0,
120
- width: 0,
121
- });
122
- return;
123
- }
124
- this.handleElements();
125
- }
126
- }
127
-
128
- componentWillUnmount() {
129
- if (this.rootRef) {
130
- this.rootRef.removeEventListener('touchstart', this.handleTouchStart);
131
- }
132
- }
133
-
134
- handleTouchStart = (e) => {
135
- e.preventDefault();
136
- this.touchStartTimer = setTimeout(() => {
137
- this.startDrag();
138
- }, 300); // Start drag after 300ms (touch and hold duration)
139
- };
140
-
141
- startDrag = () => {
142
- const { connectDragSource, disabled } = this.props;
143
- if (!disabled) {
144
- connectDragSource(this.rootRef);
145
- }
146
121
  };
147
122
 
148
- updateDimensions() {
149
- if (this.spanRef && this.rootRef) {
123
+ const updateDimensions = () => {
124
+ if (spanRef.current && rootRef.current) {
150
125
  // Temporarily set rootRef width to 'auto' for natural measurement
151
- this.rootRef.style.width = 'auto';
126
+ rootRef.current.style.width = 'auto';
152
127
 
153
128
  // Get the natural dimensions of the content
154
- const width = this.spanRef.offsetWidth || 0;
155
- const height = this.spanRef.offsetHeight || 0;
129
+ const width = spanRef.current.offsetWidth || 0;
130
+ const height = spanRef.current.offsetHeight || 0;
156
131
 
157
132
  const widthWithPadding = width + 24; // 12px padding on each side
158
133
  const heightWithPadding = height + 24; // 12px padding on top and bottom
159
134
 
160
- const responseAreaWidth = parseFloat(this.props.emptyResponseAreaWidth) || 0;
161
- const responseAreaHeight = parseFloat(this.props.emptyResponseAreaHeight) || 0;
135
+ const responseAreaWidth = parseFloat(emptyResponseAreaWidth) || 0;
136
+ const responseAreaHeight = parseFloat(emptyResponseAreaHeight) || 0;
162
137
 
163
138
  const adjustedWidth = widthWithPadding <= responseAreaWidth ? responseAreaWidth : widthWithPadding;
164
139
  const adjustedHeight = heightWithPadding <= responseAreaHeight ? responseAreaHeight : heightWithPadding;
165
140
 
166
- this.setState((prevState) => ({
141
+ setDimensions((prevState) => ({
167
142
  width: adjustedWidth > responseAreaWidth ? adjustedWidth : prevState.width,
168
143
  height: adjustedHeight > responseAreaHeight ? adjustedHeight : prevState.height,
169
144
  }));
170
145
 
171
- this.rootRef.style.width = `${adjustedWidth}px`;
172
- this.rootRef.style.height = `${adjustedHeight}px`;
146
+ rootRef.current.style.width = `${adjustedWidth}px`;
147
+ rootRef.current.style.height = `${adjustedHeight}px`;
173
148
  }
174
- }
175
-
176
- addDraggableFalseAttributes(parent) {
177
- parent.childNodes.forEach((elem) => {
178
- if (elem instanceof Element || elem instanceof HTMLDocument) {
179
- elem.setAttribute('draggable', false);
180
- }
181
- });
182
- }
149
+ };
183
150
 
184
- getRootDimensions() {
151
+ const getRootDimensions = () => {
185
152
  // Handle potential non-numeric values
186
- const responseAreaWidth = !isNaN(parseFloat(this.props.emptyResponseAreaWidth))
187
- ? parseFloat(this.props.emptyResponseAreaWidth)
188
- : 0;
189
- const responseAreaHeight = !isNaN(parseFloat(this.props.emptyResponseAreaHeight))
190
- ? parseFloat(this.props.emptyResponseAreaHeight)
191
- : 0;
153
+ const responseAreaWidth = !isNaN(parseFloat(emptyResponseAreaWidth)) ? parseFloat(emptyResponseAreaWidth) : 0;
154
+ const responseAreaHeight = !isNaN(parseFloat(emptyResponseAreaHeight)) ? parseFloat(emptyResponseAreaHeight) : 0;
192
155
 
193
156
  const rootStyle = {
194
- height: this.state.height || responseAreaHeight,
195
- width: this.state.width || responseAreaWidth,
157
+ height: dimensions.height || responseAreaHeight,
158
+ width: dimensions.width || responseAreaWidth,
196
159
  };
197
160
 
198
161
  // add minWidth, minHeight if width and height are not defined
199
- // minWidth, minHeight will be also in model in the future
200
162
  return {
201
163
  ...rootStyle,
202
164
  ...(responseAreaWidth ? {} : { minWidth: 90 }),
203
165
  ...(responseAreaHeight ? {} : { minHeight: 32 }),
204
166
  };
205
- }
206
-
207
- render() {
208
- const { disabled, choice, classes, isOver, dragItem, correct } = this.props;
209
- const draggedLabel = dragItem && isOver && dragItem.choice.value;
210
- const label = choice && choice.value;
211
-
212
- return (
213
- // TODO the Chip element is causing drag problems on touch devices. Avoid using Chip and consider refactoring the code. Keep in mind that Chip is a span with a button role, which interferes with seamless touch device dragging.
214
- <Chip
215
- clickable={false}
216
- disabled={true}
217
- ref={(ref) => {
218
- //eslint-disable-next-line
219
- this.rootRef = ReactDOM.findDOMNode(ref);
220
- }}
221
- component="span"
222
- label={
223
- <React.Fragment>
224
- <span
225
- className={classnames(classes.chipLabel, isOver && classes.over, {
226
- [classes.hidden]: draggedLabel,
227
- })}
228
- ref={(ref) => {
229
- if (ref) {
230
- //eslint-disable-next-line
231
- this.spanRef = ReactDOM.findDOMNode(ref);
232
- ref.innerHTML = label || '';
233
- this.addDraggableFalseAttributes(ref);
234
- }
235
- }}
236
- >
237
- {' '}
238
- </span>
239
- {draggedLabel && (
240
- <span
241
- className={classnames(classes.chipLabel, isOver && classes.over, classes.dragged)}
242
- ref={(ref) => {
243
- if (ref) {
244
- //eslint-disable-next-line
245
- this.spanRef = ReactDOM.findDOMNode(ref);
246
- ref.innerHTML = draggedLabel || '';
247
- this.addDraggableFalseAttributes(ref);
248
- }
249
- }}
250
- >
251
- {' '}
252
- </span>
253
- )}
254
- </React.Fragment>
167
+ };
168
+
169
+ useEffect(() => {
170
+ handleElements();
171
+ }, []);
172
+
173
+ // Render math for the placeholder/preview when dragging over
174
+ useEffect(() => {
175
+ if (rootRef.current) {
176
+ renderMath(rootRef.current);
177
+ }
178
+ }, [isOver, dragItem?.choice?.value]);
179
+
180
+ useEffect(() => {
181
+ if (!choice) {
182
+ setDimensions({ height: 0, width: 0 });
183
+ return;
184
+ }
185
+ handleElements();
186
+ }, [choice]);
187
+
188
+ useEffect(() => {
189
+ if (!isOver && !isDragging) {
190
+ frozenRef.current = {
191
+ width: rootRef.current.offsetWidth,
192
+ height: rootRef.current.offsetHeight,
193
+ };
194
+ }
195
+ }, [choice, isOver, isDragging]);
196
+
197
+ const draggedLabel = dragItem && isOver && dragItem.choice && dragItem.choice.value;
198
+ const label = choice && choice.value;
199
+ const style =
200
+ isOver || isDragging
201
+ ? {
202
+ width: frozenRef.current?.width,
203
+ height: frozenRef.current?.height,
255
204
  }
256
- className={classnames(classes.chip, isOver && classes.over, isOver && classes.parentOver, {
257
- [classes.correct]: correct !== undefined && correct,
258
- [classes.incorrect]: correct !== undefined && !correct,
259
- })}
260
- variant={disabled ? 'outlined' : undefined}
261
- style={{
262
- ...this.getRootDimensions(),
263
- }}
264
- />
265
- );
266
- }
205
+ : getRootDimensions();
206
+
207
+ return (
208
+ <StyledChip
209
+ clickable={false}
210
+ disabled={disabled}
211
+ ref={rootRef}
212
+ component="span"
213
+ label={
214
+ <React.Fragment>
215
+ <StyledChipLabel
216
+ ref={spanRef}
217
+ draggable={true}
218
+ className={classnames({
219
+ over: isOver,
220
+ hidden: draggedLabel,
221
+ })}
222
+ dangerouslySetInnerHTML={{ __html: label || '' }}
223
+ />
224
+ {draggedLabel && (
225
+ <StyledChipLabel
226
+ draggable={true}
227
+ className={classnames({
228
+ over: isOver,
229
+ dragged: true,
230
+ })}
231
+ dangerouslySetInnerHTML={{ __html: draggedLabel || '' }}
232
+ />
233
+ )}
234
+ </React.Fragment>
235
+ }
236
+ className={classnames({
237
+ over: isOver,
238
+ parentOver: isOver,
239
+ correct: correct !== undefined && correct,
240
+ incorrect: correct !== undefined && !correct,
241
+ })}
242
+ variant={disabled ? 'outlined' : undefined}
243
+ style={style}
244
+ />
245
+ );
267
246
  }
268
247
 
269
248
  BlankContent.defaultProps = {
@@ -276,85 +255,107 @@ BlankContent.propTypes = {
276
255
  disabled: PropTypes.bool,
277
256
  duplicates: PropTypes.bool,
278
257
  choice: PropTypes.object,
279
- classes: PropTypes.object,
280
258
  isOver: PropTypes.bool,
281
259
  dragItem: PropTypes.object,
282
260
  correct: PropTypes.bool,
283
261
  onChange: PropTypes.func,
284
262
  emptyResponseAreaWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
285
263
  emptyResponseAreaHeight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
264
+ instanceId: PropTypes.string,
286
265
  };
287
266
 
288
- const StyledBlankContent = useStyles(BlankContent);
289
-
290
- const connectedBlankContent = useStyles(({ connectDragSource, connectDropTarget, ...props }) => {
291
- const { classes, isOver } = props;
292
-
293
- return connectDropTarget(
294
- connectDragSource(
295
- <span className={classnames(classes.content, isOver && classes.over)}>
296
- <StyledBlankContent {...props} />
297
- </span>,
298
- ),
299
- );
300
- });
301
-
302
- const tileTarget = {
303
- drop(props, monitor) {
304
- const draggedItem = monitor.getItem();
267
+ // New functional component using @dnd-kit hooks
268
+ function DragDropBlank({
269
+ id,
270
+ disabled,
271
+ duplicates,
272
+ choice,
273
+ correct,
274
+ onChange,
275
+ emptyResponseAreaWidth,
276
+ emptyResponseAreaHeight,
277
+ instanceId,
278
+ }) {
279
+ // Setup draggable functionality
280
+ const {
281
+ attributes: dragAttributes,
282
+ listeners: dragListeners,
283
+ setNodeRef: setDragNodeRef,
284
+ transform,
285
+ isDragging,
286
+ } = useDraggable({
287
+ id: `mask-blank-drag-${id}`,
288
+ disabled: disabled || !choice,
289
+ data: {
290
+ id: id,
291
+ choice: choice,
292
+ instanceId: instanceId,
293
+ fromChoice: false, // This is from a blank, not from choices
294
+ type: 'MaskBlank',
295
+ },
296
+ });
297
+
298
+ // Setup droppable functionality
299
+ const { setNodeRef: setDropNodeRef, isOver, active: dragItem } = useDroppable({
300
+ id: `mask-blank-drop-${id}`,
301
+ data: {
302
+ id: id,
303
+ accepts: ['MaskBlank'],
304
+ instanceId: instanceId,
305
+ },
306
+ });
305
307
 
306
- log('props.instanceId', props.instanceId, 'draggedItem.instanceId:', draggedItem.instanceId);
308
+ // Combine refs for both drag and drop
309
+ const setNodeRef = (node) => {
310
+ setDragNodeRef(node);
311
+ setDropNodeRef(node);
312
+ };
307
313
 
308
- if (draggedItem.id !== props.id) {
309
- props.onChange(props.id, draggedItem.choice.id);
310
- }
314
+ const style = {
315
+ transform: CSS.Translate.toString(transform),
316
+ };
311
317
 
312
- return {
313
- dropped: draggedItem.id !== props.id,
314
- };
315
- },
316
- canDrop(props, monitor) {
317
- const draggedItem = monitor.getItem();
318
+ return (
319
+ <StyledContent
320
+ ref={setNodeRef}
321
+ style={style}
322
+ dragged={isDragging}
323
+ over={isOver}
324
+ {...dragAttributes}
325
+ {...dragListeners}
326
+ >
327
+ <BlankContent
328
+ id={id}
329
+ disabled={disabled}
330
+ duplicates={duplicates}
331
+ choice={choice}
332
+ isOver={isOver}
333
+ dragItem={dragItem?.data?.current}
334
+ correct={correct}
335
+ onChange={onChange}
336
+ emptyResponseAreaWidth={emptyResponseAreaWidth}
337
+ emptyResponseAreaHeight={emptyResponseAreaHeight}
338
+ instanceId={instanceId}
339
+ />
340
+ </StyledContent>
341
+ );
342
+ }
318
343
 
319
- return draggedItem.instanceId === props.instanceId;
320
- },
344
+ DragDropBlank.defaultProps = {
345
+ emptyResponseAreaWidth: 0,
346
+ emptyResponseAreaHeight: 0,
321
347
  };
322
348
 
323
- const DropTile = DropTarget(DRAG_TYPE, tileTarget, (connect, monitor) => ({
324
- connectDropTarget: connect.dropTarget(),
325
- isOver: monitor.isOver(),
326
- dragItem: monitor.getItem(),
327
- }))(connectedBlankContent);
328
-
329
- const tileSource = {
330
- canDrag(props) {
331
- return !props.disabled && !!props.choice;
332
- },
333
- beginDrag(props) {
334
- return {
335
- id: props.id,
336
- choice: props.choice,
337
- instanceId: props.instanceId,
338
- fromChoice: true,
339
- };
340
- },
341
- endDrag(props, monitor) {
342
- // this will be null if it did not drop
343
- const dropResult = monitor.getDropResult();
344
-
345
- if (!dropResult || dropResult.dropped) {
346
- const draggedItem = monitor.getItem();
347
-
348
- if (draggedItem.fromChoice) {
349
- props.onChange(props.id, undefined);
350
- }
351
- }
352
- },
349
+ DragDropBlank.propTypes = {
350
+ id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
351
+ disabled: PropTypes.bool,
352
+ duplicates: PropTypes.bool,
353
+ choice: PropTypes.object,
354
+ correct: PropTypes.bool,
355
+ onChange: PropTypes.func,
356
+ emptyResponseAreaWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
357
+ emptyResponseAreaHeight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
358
+ instanceId: PropTypes.string,
353
359
  };
354
360
 
355
- const DragDropTile = DragSource(DRAG_TYPE, tileSource, (connect, monitor) => ({
356
- connectDragSource: connect.dragSource(),
357
- isDragging: monitor.isDragging(),
358
- }))(DropTile);
359
-
360
- export default DragDropTile;
361
+ export default DragDropBlank;