@pie-lib/mask-markup 2.0.0-beta.1 → 2.0.0-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.
- package/CHANGELOG.json +1 -871
- package/CHANGELOG.md +434 -32
- package/LICENSE.md +5 -0
- package/NEXT.CHANGELOG.json +1 -0
- package/lib/choices/choice.js +101 -129
- package/lib/choices/choice.js.map +1 -1
- package/lib/choices/index.js +28 -48
- package/lib/choices/index.js.map +1 -1
- package/lib/componentize.js +2 -6
- package/lib/componentize.js.map +1 -1
- package/lib/components/blank.js +315 -246
- package/lib/components/blank.js.map +1 -1
- package/lib/components/correct-input.js +47 -66
- package/lib/components/correct-input.js.map +1 -1
- package/lib/components/dropdown.js +399 -156
- package/lib/components/dropdown.js.map +1 -1
- package/lib/components/input.js +15 -19
- package/lib/components/input.js.map +1 -1
- package/lib/constructed-response.js +81 -28
- package/lib/constructed-response.js.map +1 -1
- package/lib/customizable.js +44 -0
- package/lib/customizable.js.map +1 -0
- package/lib/drag-in-the-blank.js +160 -96
- package/lib/drag-in-the-blank.js.map +1 -1
- package/lib/index.js +8 -7
- package/lib/index.js.map +1 -1
- package/lib/inline-dropdown.js +10 -14
- package/lib/inline-dropdown.js.map +1 -1
- package/lib/mask.js +93 -101
- package/lib/mask.js.map +1 -1
- package/lib/serialization.js +36 -81
- package/lib/serialization.js.map +1 -1
- package/lib/with-mask.js +53 -49
- package/lib/with-mask.js.map +1 -1
- package/package.json +26 -15
- package/src/__tests__/drag-in-the-blank.test.js +111 -0
- package/src/__tests__/index.test.js +39 -0
- package/src/__tests__/mask.test.js +187 -0
- package/src/__tests__/serialization.test.js +54 -0
- package/src/__tests__/utils.js +1 -0
- package/src/__tests__/with-mask.test.js +76 -0
- package/src/choices/__tests__/index.test.js +75 -0
- package/src/choices/choice.jsx +84 -83
- package/src/choices/index.jsx +25 -15
- package/src/components/__tests__/blank.test.js +138 -0
- package/src/components/__tests__/correct-input.test.js +90 -0
- package/src/components/__tests__/dropdown.test.js +93 -0
- package/src/components/__tests__/input.test.js +102 -0
- package/src/components/blank.jsx +319 -195
- package/src/components/correct-input.jsx +45 -46
- package/src/components/dropdown.jsx +374 -139
- package/src/components/input.jsx +6 -3
- package/src/constructed-response.jsx +81 -18
- package/src/customizable.jsx +35 -0
- package/src/drag-in-the-blank.jsx +159 -47
- package/src/index.js +3 -1
- package/src/inline-dropdown.jsx +6 -3
- package/src/mask.jsx +75 -30
- package/src/serialization.js +37 -44
- package/src/with-mask.jsx +36 -3
- package/README.md +0 -14
- package/lib/new-serialization.js +0 -320
- package/lib/parse-html.js +0 -16
- package/lib/test-serializer.js +0 -215
- package/src/new-serialization.jsx +0 -291
- package/src/parse-html.js +0 -8
- package/src/test-serializer.js +0 -163
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
// import Input from './components/input';
|
|
3
|
+
import { withMask } from './with-mask';
|
|
4
|
+
|
|
5
|
+
// eslint-disable-next-line react/display-name
|
|
6
|
+
export default withMask('input', (props) => (node, data, onChange) => {
|
|
7
|
+
const dataset = node.data ? node.data.dataset || {} : {};
|
|
8
|
+
if (dataset.component === 'input') {
|
|
9
|
+
// eslint-disable-next-line react/prop-types
|
|
10
|
+
// const { adjustedLimit, disabled, feedback, showCorrectAnswer, maxLength, spellCheck } = props;
|
|
11
|
+
|
|
12
|
+
// the first answer is the correct one
|
|
13
|
+
// eslint-disable-next-line react/prop-types
|
|
14
|
+
// const correctAnswer = ((props.choices && dataset && props.choices[dataset.id]) || [])[0];
|
|
15
|
+
// const finalValue = showCorrectAnswer ? correctAnswer && correctAnswer.label : data[dataset.id] || '';
|
|
16
|
+
// const width = maxLength && maxLength[dataset.id];
|
|
17
|
+
|
|
18
|
+
return props.customMarkMarkupComponent(dataset.id);
|
|
19
|
+
// return (
|
|
20
|
+
// <Input
|
|
21
|
+
// key={`${node.type}-input-${dataset.id}`}
|
|
22
|
+
// correct={feedback && feedback[dataset.id] && feedback[dataset.id] === 'correct'}
|
|
23
|
+
// disabled={showCorrectAnswer || disabled}
|
|
24
|
+
// value={finalValue}
|
|
25
|
+
// id={dataset.id}
|
|
26
|
+
// onChange={onChange}
|
|
27
|
+
// showCorrectAnswer={showCorrectAnswer}
|
|
28
|
+
// width={width}
|
|
29
|
+
// charactersLimit={adjustedLimit ? width : 25}
|
|
30
|
+
// isConstructedResponse={true}
|
|
31
|
+
// spellCheck={spellCheck}
|
|
32
|
+
// />
|
|
33
|
+
// );
|
|
34
|
+
}
|
|
35
|
+
});
|
|
@@ -1,17 +1,31 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import {
|
|
3
|
+
import { DragProvider } from '@pie-lib/drag';
|
|
4
|
+
import { DragOverlay, closestCenter } from '@dnd-kit/core';
|
|
5
|
+
|
|
4
6
|
import Choices from './choices';
|
|
7
|
+
import Choice from './choices/choice';
|
|
5
8
|
import Blank from './components/blank';
|
|
6
9
|
import { withMask } from './with-mask';
|
|
7
10
|
|
|
8
|
-
const Masked = withMask('blank', props => (node, data, onChange) => {
|
|
9
|
-
const dataset = node.data
|
|
10
|
-
|
|
11
|
+
const Masked = withMask('blank', (props) => (node, data, onChange) => {
|
|
12
|
+
const dataset = node.data?.dataset || {};
|
|
11
13
|
if (dataset.component === 'blank') {
|
|
12
|
-
|
|
14
|
+
// eslint-disable-next-line react/prop-types
|
|
15
|
+
const {
|
|
16
|
+
disabled,
|
|
17
|
+
duplicates,
|
|
18
|
+
correctResponse,
|
|
19
|
+
feedback,
|
|
20
|
+
showCorrectAnswer,
|
|
21
|
+
emptyResponseAreaWidth,
|
|
22
|
+
emptyResponseAreaHeight,
|
|
23
|
+
instanceId,
|
|
24
|
+
isDragging
|
|
25
|
+
} = props;
|
|
13
26
|
const choiceId = showCorrectAnswer ? correctResponse[dataset.id] : data[dataset.id];
|
|
14
|
-
|
|
27
|
+
// eslint-disable-next-line react/prop-types
|
|
28
|
+
const choice = choiceId && props.choices.find((c) => c.id === choiceId);
|
|
15
29
|
|
|
16
30
|
return (
|
|
17
31
|
<Blank
|
|
@@ -21,48 +35,131 @@ const Masked = withMask('blank', props => (node, data, onChange) => {
|
|
|
21
35
|
duplicates={duplicates}
|
|
22
36
|
choice={choice}
|
|
23
37
|
id={dataset.id}
|
|
24
|
-
|
|
38
|
+
emptyResponseAreaWidth={emptyResponseAreaWidth}
|
|
39
|
+
emptyResponseAreaHeight={emptyResponseAreaHeight}
|
|
40
|
+
onChange={(id, choiceId) => {
|
|
41
|
+
const newData = { ...data };
|
|
42
|
+
if (choiceId === undefined) {
|
|
43
|
+
delete newData[id];
|
|
44
|
+
} else {
|
|
45
|
+
newData[id] = choiceId;
|
|
46
|
+
}
|
|
47
|
+
onChange(newData);
|
|
48
|
+
}}
|
|
49
|
+
instanceId={instanceId}
|
|
50
|
+
isDragging={isDragging}
|
|
25
51
|
/>
|
|
26
52
|
);
|
|
27
53
|
}
|
|
28
54
|
});
|
|
29
55
|
|
|
30
56
|
export default class DragInTheBlank extends React.Component {
|
|
57
|
+
constructor(props) {
|
|
58
|
+
super(props);
|
|
59
|
+
this.state = {
|
|
60
|
+
activeDragItem: null,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
31
64
|
static propTypes = {
|
|
32
65
|
markup: PropTypes.string,
|
|
33
66
|
layout: PropTypes.object,
|
|
34
67
|
choicesPosition: PropTypes.string,
|
|
35
|
-
choices: PropTypes.
|
|
36
|
-
PropTypes.shape({ label: PropTypes.string, value: PropTypes.string })
|
|
37
|
-
),
|
|
68
|
+
choices: PropTypes.array,
|
|
38
69
|
value: PropTypes.object,
|
|
39
70
|
onChange: PropTypes.func,
|
|
40
71
|
duplicates: PropTypes.bool,
|
|
41
72
|
disabled: PropTypes.bool,
|
|
42
73
|
feedback: PropTypes.object,
|
|
43
74
|
correctResponse: PropTypes.object,
|
|
44
|
-
showCorrectAnswer: PropTypes.bool
|
|
75
|
+
showCorrectAnswer: PropTypes.bool,
|
|
76
|
+
emptyResponseAreaWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
77
|
+
emptyResponseAreaHeight: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
78
|
+
instanceId: PropTypes.string,
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
static defaultProps = {
|
|
82
|
+
instanceId: 'drag-in-the-blank',
|
|
45
83
|
};
|
|
46
84
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
85
|
+
handleDragStart = (event) => {
|
|
86
|
+
const { active } = event;
|
|
87
|
+
|
|
88
|
+
if (active?.data?.current) {
|
|
89
|
+
this.setState({
|
|
90
|
+
activeDragItem: active.data.current,
|
|
91
|
+
});
|
|
50
92
|
}
|
|
51
|
-
}
|
|
93
|
+
};
|
|
52
94
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
95
|
+
renderDragOverlay = () => {
|
|
96
|
+
const { activeDragItem } = this.state;
|
|
97
|
+
if (!activeDragItem) return null;
|
|
98
|
+
|
|
99
|
+
if (activeDragItem.type === 'MaskBlank') {
|
|
100
|
+
return (
|
|
101
|
+
<Choice
|
|
102
|
+
disabled={activeDragItem.disabled}
|
|
103
|
+
choice={activeDragItem.choice}
|
|
104
|
+
instanceId={activeDragItem.instanceId}
|
|
105
|
+
/>
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return null;
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
handleDragEnd = (event) => {
|
|
113
|
+
const { active, over } = event;
|
|
114
|
+
const { onChange, value } = this.props;
|
|
115
|
+
|
|
116
|
+
if (!over || !active || !onChange) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
const draggedData = active.data.current;
|
|
121
|
+
const dropData = over.data.current;
|
|
122
|
+
|
|
123
|
+
if (draggedData?.type === 'MaskBlank' && dropData?.accepts?.includes('MaskBlank')) {
|
|
124
|
+
const draggedItem = draggedData;
|
|
125
|
+
const targetId = dropData.id;
|
|
56
126
|
|
|
57
|
-
|
|
127
|
+
// drop from choice to blank (placing choice into response)
|
|
128
|
+
if (draggedItem.fromChoice === true) {
|
|
129
|
+
const newValue = { ...value };
|
|
130
|
+
newValue[targetId] = draggedItem.choice.id;
|
|
131
|
+
onChange(newValue);
|
|
132
|
+
} else if (dropData.toChoiceBoard === true) {
|
|
133
|
+
// handle drop from blank to choice board (removal from blank)
|
|
134
|
+
const newValue = { ...value };
|
|
135
|
+
delete newValue[draggedItem.id];
|
|
136
|
+
onChange(newValue);
|
|
137
|
+
}
|
|
138
|
+
// handle drop from blank to blank (changing position)
|
|
139
|
+
else if (draggedItem.id !== targetId) {
|
|
140
|
+
const newValue = { ...value };
|
|
141
|
+
newValue[targetId] = draggedItem.choice.id;
|
|
142
|
+
delete newValue[draggedItem.id];
|
|
143
|
+
onChange(newValue);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
this.setState({ activeDragItem: null });
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
getPositionDirection = (choicePosition) => {
|
|
58
150
|
let flexDirection;
|
|
151
|
+
let justifyContent;
|
|
152
|
+
let alignItems;
|
|
59
153
|
|
|
60
154
|
switch (choicePosition) {
|
|
61
155
|
case 'left':
|
|
62
156
|
flexDirection = 'row';
|
|
157
|
+
alignItems = 'center';
|
|
63
158
|
break;
|
|
64
159
|
case 'right':
|
|
65
160
|
flexDirection = 'row-reverse';
|
|
161
|
+
justifyContent = 'flex-end';
|
|
162
|
+
alignItems = 'center';
|
|
66
163
|
break;
|
|
67
164
|
case 'below':
|
|
68
165
|
flexDirection = 'column-reverse';
|
|
@@ -73,14 +170,13 @@ export default class DragInTheBlank extends React.Component {
|
|
|
73
170
|
break;
|
|
74
171
|
}
|
|
75
172
|
|
|
76
|
-
return flexDirection;
|
|
173
|
+
return { flexDirection, justifyContent, alignItems };
|
|
77
174
|
};
|
|
78
175
|
|
|
79
176
|
render() {
|
|
80
177
|
const {
|
|
81
178
|
markup,
|
|
82
179
|
duplicates,
|
|
83
|
-
layout,
|
|
84
180
|
value,
|
|
85
181
|
onChange,
|
|
86
182
|
choicesPosition,
|
|
@@ -88,37 +184,53 @@ export default class DragInTheBlank extends React.Component {
|
|
|
88
184
|
correctResponse,
|
|
89
185
|
disabled,
|
|
90
186
|
feedback,
|
|
91
|
-
showCorrectAnswer
|
|
187
|
+
showCorrectAnswer,
|
|
188
|
+
emptyResponseAreaWidth,
|
|
189
|
+
emptyResponseAreaHeight,
|
|
190
|
+
layout,
|
|
191
|
+
instanceId
|
|
92
192
|
} = this.props;
|
|
93
193
|
|
|
94
194
|
const choicePosition = choicesPosition || 'below';
|
|
95
|
-
const style = {
|
|
96
|
-
display: 'flex',
|
|
97
|
-
flexDirection: this.getPositionDirection(choicePosition)
|
|
98
|
-
};
|
|
195
|
+
const style = { display: 'flex', minWidth: '100px', ...this.getPositionDirection(choicePosition) };
|
|
99
196
|
|
|
100
197
|
return (
|
|
101
|
-
<
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
198
|
+
<DragProvider
|
|
199
|
+
onDragStart={this.handleDragStart}
|
|
200
|
+
onDragEnd={this.handleDragEnd}
|
|
201
|
+
collisionDetection={closestCenter}
|
|
202
|
+
>
|
|
203
|
+
<div ref={(ref) => (this.rootRef = ref)} style={style}>
|
|
204
|
+
<Choices
|
|
205
|
+
choicePosition={choicePosition}
|
|
206
|
+
choices={choices}
|
|
207
|
+
value={value}
|
|
208
|
+
duplicates={duplicates}
|
|
209
|
+
disabled={disabled}
|
|
210
|
+
instanceId={instanceId}
|
|
211
|
+
/>
|
|
212
|
+
<Masked
|
|
213
|
+
elementType="drag-in-the-blank"
|
|
214
|
+
markup={markup}
|
|
215
|
+
layout={layout}
|
|
216
|
+
value={value}
|
|
217
|
+
choices={choices}
|
|
218
|
+
onChange={onChange}
|
|
219
|
+
disabled={disabled}
|
|
220
|
+
duplicates={duplicates}
|
|
221
|
+
feedback={feedback}
|
|
222
|
+
correctResponse={correctResponse}
|
|
223
|
+
showCorrectAnswer={showCorrectAnswer}
|
|
224
|
+
emptyResponseAreaWidth={emptyResponseAreaWidth}
|
|
225
|
+
emptyResponseAreaHeight={emptyResponseAreaHeight}
|
|
226
|
+
instanceId={instanceId}
|
|
227
|
+
isDragging={!!this.state.activeDragItem}
|
|
228
|
+
/>
|
|
229
|
+
<DragOverlay style={{ pointerEvents: "none" }}>
|
|
230
|
+
{this.renderDragOverlay()}
|
|
231
|
+
</DragOverlay>
|
|
232
|
+
</div>
|
|
233
|
+
</DragProvider>
|
|
122
234
|
);
|
|
123
235
|
}
|
|
124
236
|
}
|
package/src/index.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { withMask, buildLayoutFromMarkup } from './with-mask';
|
|
2
2
|
import DragInTheBlank from './drag-in-the-blank';
|
|
3
3
|
import ConstructedResponse from './constructed-response';
|
|
4
|
+
import Customizable from './customizable';
|
|
4
5
|
import InlineDropdown from './inline-dropdown';
|
|
5
6
|
import componentize from './componentize';
|
|
6
7
|
|
|
@@ -10,5 +11,6 @@ export {
|
|
|
10
11
|
DragInTheBlank,
|
|
11
12
|
ConstructedResponse,
|
|
12
13
|
InlineDropdown,
|
|
13
|
-
componentize
|
|
14
|
+
componentize,
|
|
15
|
+
Customizable,
|
|
14
16
|
};
|
package/src/inline-dropdown.jsx
CHANGED
|
@@ -2,12 +2,13 @@ import React from 'react';
|
|
|
2
2
|
import Dropdown from './components/dropdown';
|
|
3
3
|
import { withMask } from './with-mask';
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
// eslint-disable-next-line react/display-name
|
|
6
|
+
export default withMask('dropdown', (props) => (node, data, onChange) => {
|
|
6
7
|
const dataset = node.data ? node.data.dataset || {} : {};
|
|
7
8
|
if (dataset.component === 'dropdown') {
|
|
9
|
+
// eslint-disable-next-line react/prop-types
|
|
8
10
|
const { choices, disabled, feedback, showCorrectAnswer } = props;
|
|
9
|
-
const correctAnswer =
|
|
10
|
-
choices && choices[dataset.id] && choices[dataset.id].find(c => c.correct);
|
|
11
|
+
const correctAnswer = choices && choices[dataset.id] && choices[dataset.id].find((c) => c.correct);
|
|
11
12
|
const finalChoice = showCorrectAnswer ? correctAnswer && correctAnswer.value : data[dataset.id];
|
|
12
13
|
|
|
13
14
|
return (
|
|
@@ -16,10 +17,12 @@ export default withMask('dropdown', props => (node, data, onChange) => {
|
|
|
16
17
|
correct={feedback && feedback[dataset.id] && feedback[dataset.id] === 'correct'}
|
|
17
18
|
disabled={disabled || showCorrectAnswer}
|
|
18
19
|
value={finalChoice}
|
|
20
|
+
correctValue={showCorrectAnswer ? correctAnswer && correctAnswer.label : undefined}
|
|
19
21
|
id={dataset.id}
|
|
20
22
|
onChange={onChange}
|
|
21
23
|
choices={choices[dataset.id]}
|
|
22
24
|
showCorrectAnswer={showCorrectAnswer}
|
|
25
|
+
singleQuery={Object.keys(choices).length == 1}
|
|
23
26
|
/>
|
|
24
27
|
);
|
|
25
28
|
}
|
package/src/mask.jsx
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import get from 'lodash/get';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { styled } from '@mui/material/styles';
|
|
5
|
+
import { renderMath } from '@pie-lib/math-rendering';
|
|
6
6
|
import { MARK_TAGS } from './serialization';
|
|
7
7
|
|
|
8
|
-
const Paragraph =
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
8
|
+
const Paragraph = styled('div')(({ theme }) => ({
|
|
9
|
+
paddingTop: theme.spacing(2),
|
|
10
|
+
paddingBottom: theme.spacing(2),
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
const Spacer = styled('span')(() => ({
|
|
14
|
+
display: 'inline-block',
|
|
15
|
+
width: '.75em',
|
|
16
|
+
}));
|
|
14
17
|
|
|
15
18
|
const restrictWhitespaceTypes = ['tbody', 'tr'];
|
|
16
19
|
|
|
@@ -25,25 +28,33 @@ const addText = (parentNode, text) => {
|
|
|
25
28
|
}
|
|
26
29
|
};
|
|
27
30
|
|
|
28
|
-
const getMark = n => {
|
|
29
|
-
const
|
|
31
|
+
const getMark = (n) => {
|
|
32
|
+
const mark = n.leaves.find((leave) => get(leave, 'marks', []).length);
|
|
33
|
+
|
|
34
|
+
if (mark) {
|
|
35
|
+
return mark.marks[0];
|
|
36
|
+
}
|
|
30
37
|
|
|
31
|
-
return
|
|
38
|
+
return null;
|
|
32
39
|
};
|
|
33
40
|
|
|
34
|
-
export const renderChildren = (layout, value, onChange, rootRenderChildren, parentNode) => {
|
|
41
|
+
export const renderChildren = (layout, value, onChange, rootRenderChildren, parentNode, elementType) => {
|
|
35
42
|
if (!value) {
|
|
36
43
|
return null;
|
|
37
44
|
}
|
|
38
45
|
|
|
39
46
|
const children = [];
|
|
40
47
|
|
|
41
|
-
(layout.
|
|
42
|
-
const key = `${n.type}-${index}`;
|
|
48
|
+
(layout.nodes || []).forEach((n, index) => {
|
|
49
|
+
const key = n.type ? `${n.type}-${index}` : `${index}`;
|
|
43
50
|
|
|
44
51
|
if (n.isMath) {
|
|
45
52
|
children.push(
|
|
46
|
-
<span
|
|
53
|
+
<span
|
|
54
|
+
dangerouslySetInnerHTML={{
|
|
55
|
+
__html: `<math displaystyle="true">${n.nodes[0].innerHTML}</math>`,
|
|
56
|
+
}}
|
|
57
|
+
/>,
|
|
47
58
|
);
|
|
48
59
|
return children;
|
|
49
60
|
}
|
|
@@ -52,12 +63,19 @@ export const renderChildren = (layout, value, onChange, rootRenderChildren, pare
|
|
|
52
63
|
const c = rootRenderChildren(n, value, onChange);
|
|
53
64
|
if (c) {
|
|
54
65
|
children.push(c);
|
|
66
|
+
if (parentNode?.type !== 'td' && elementType === 'drag-in-the-blank') {
|
|
67
|
+
children.push(<Spacer key={`spacer-${index}`} />);
|
|
68
|
+
}
|
|
55
69
|
return;
|
|
56
70
|
}
|
|
57
71
|
}
|
|
58
72
|
|
|
59
|
-
if (
|
|
60
|
-
const content = n.
|
|
73
|
+
if (n.object === 'text') {
|
|
74
|
+
const content = n.leaves.reduce((acc, l) => {
|
|
75
|
+
const t = l.text;
|
|
76
|
+
const extraText = addText(parentNode, t);
|
|
77
|
+
return extraText ? acc + extraText : acc;
|
|
78
|
+
}, '');
|
|
61
79
|
const mark = getMark(n);
|
|
62
80
|
|
|
63
81
|
if (mark) {
|
|
@@ -67,24 +85,27 @@ export const renderChildren = (layout, value, onChange, rootRenderChildren, pare
|
|
|
67
85
|
if (MARK_TAGS[markKey] === mark.type) {
|
|
68
86
|
const Tag = markKey;
|
|
69
87
|
|
|
70
|
-
children.push(<Tag>{content}</Tag>);
|
|
88
|
+
children.push(<Tag key={key}>{content}</Tag>);
|
|
71
89
|
break;
|
|
72
90
|
}
|
|
73
91
|
}
|
|
74
92
|
} else if (content.length > 0) {
|
|
75
93
|
children.push(content);
|
|
94
|
+
if (parentNode?.type !== 'td' && elementType === 'drag-in-the-blank') {
|
|
95
|
+
children.push(<Spacer key={`spacer-${index}`} />);
|
|
96
|
+
}
|
|
76
97
|
}
|
|
77
98
|
} else {
|
|
78
|
-
const subNodes = renderChildren(n, value, onChange, rootRenderChildren, n);
|
|
99
|
+
const subNodes = renderChildren(n, value, onChange, rootRenderChildren, n, elementType);
|
|
79
100
|
if (n.type === 'p' || n.type === 'paragraph') {
|
|
80
101
|
children.push(<Paragraph key={key}>{subNodes}</Paragraph>);
|
|
81
102
|
} else {
|
|
82
103
|
const Tag = n.type;
|
|
83
|
-
if (n.
|
|
104
|
+
if (n.nodes && n.nodes.length > 0) {
|
|
84
105
|
children.push(
|
|
85
106
|
<Tag key={key} {...n.data.attributes}>
|
|
86
107
|
{subNodes}
|
|
87
|
-
</Tag
|
|
108
|
+
</Tag>,
|
|
88
109
|
);
|
|
89
110
|
} else {
|
|
90
111
|
children.push(<Tag key={key} {...n.data.attributes} />);
|
|
@@ -95,32 +116,56 @@ export const renderChildren = (layout, value, onChange, rootRenderChildren, pare
|
|
|
95
116
|
return children;
|
|
96
117
|
};
|
|
97
118
|
|
|
98
|
-
const MaskContainer =
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
}
|
|
119
|
+
const MaskContainer = styled('div')(() => ({
|
|
120
|
+
display: 'initial',
|
|
121
|
+
'&:not(.MathJax) table': {
|
|
122
|
+
borderCollapse: 'collapse',
|
|
123
|
+
},
|
|
124
|
+
// align table content to left as per STAR requirement PD-3687
|
|
125
|
+
'&:not(.MathJax) table td, &:not(.MathJax) table th': {
|
|
126
|
+
padding: '8px 12px',
|
|
127
|
+
textAlign: 'left',
|
|
128
|
+
},
|
|
129
|
+
}));
|
|
103
130
|
|
|
104
131
|
/**
|
|
105
132
|
* Renders a layout that uses the slate.js Value model structure.
|
|
106
133
|
*/
|
|
107
134
|
export default class Mask extends React.Component {
|
|
135
|
+
constructor(props) {
|
|
136
|
+
super(props);
|
|
137
|
+
this.internalContainerRef = React.createRef();
|
|
138
|
+
}
|
|
139
|
+
|
|
108
140
|
static propTypes = {
|
|
109
141
|
renderChildren: PropTypes.func,
|
|
110
142
|
layout: PropTypes.object,
|
|
111
143
|
value: PropTypes.object,
|
|
112
|
-
onChange: PropTypes.func
|
|
144
|
+
onChange: PropTypes.func,
|
|
145
|
+
elementType: PropTypes.string,
|
|
146
|
+
containerRef: PropTypes.oneOfType([
|
|
147
|
+
PropTypes.func,
|
|
148
|
+
PropTypes.shape({ current: PropTypes.instanceOf(Element) }),
|
|
149
|
+
]),
|
|
113
150
|
};
|
|
114
151
|
|
|
152
|
+
componentDidMount() {
|
|
153
|
+
const containerRef = this.props.containerRef || this.internalContainerRef;
|
|
154
|
+
if (containerRef.current && typeof renderMath === 'function') {
|
|
155
|
+
renderMath(containerRef.current);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
115
159
|
handleChange = (id, value) => {
|
|
116
160
|
const data = { ...this.props.value, [id]: value };
|
|
117
161
|
this.props.onChange(data);
|
|
118
162
|
};
|
|
119
163
|
|
|
120
164
|
render() {
|
|
121
|
-
const { value, layout } = this.props;
|
|
122
|
-
const children = renderChildren(layout, value, this.handleChange, this.props.renderChildren);
|
|
165
|
+
const { value, layout, elementType, containerRef } = this.props;
|
|
166
|
+
const children = renderChildren(layout, value, this.handleChange, this.props.renderChildren, null, elementType);
|
|
167
|
+
const ref = containerRef || this.internalContainerRef;
|
|
123
168
|
|
|
124
|
-
return <MaskContainer>{children}</MaskContainer>;
|
|
169
|
+
return <MaskContainer ref={ref}>{children}</MaskContainer>;
|
|
125
170
|
}
|
|
126
171
|
}
|