@pie-lib/mask-markup 2.0.0-beta.2 → 2.1.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.
Files changed (80) hide show
  1. package/CHANGELOG.json +1 -871
  2. package/CHANGELOG.md +296 -2
  3. package/LICENSE.md +5 -0
  4. package/NEXT.CHANGELOG.json +1 -0
  5. package/lib/__tests__/drag-in-the-blank.test.js +129 -0
  6. package/lib/__tests__/index.test.js +42 -0
  7. package/lib/__tests__/mask.test.js +163 -0
  8. package/lib/__tests__/serialization.test.js +44 -0
  9. package/lib/__tests__/utils.js +14 -0
  10. package/lib/__tests__/with-mask.test.js +110 -0
  11. package/lib/choices/__tests__/index.test.js +101 -0
  12. package/lib/choices/choice.js +100 -119
  13. package/lib/choices/choice.js.map +1 -1
  14. package/lib/choices/index.js +24 -20
  15. package/lib/choices/index.js.map +1 -1
  16. package/lib/componentize.js +2 -3
  17. package/lib/componentize.js.map +1 -1
  18. package/lib/components/__tests__/blank.test.js +189 -0
  19. package/lib/components/__tests__/correct-input.test.js +132 -0
  20. package/lib/components/__tests__/dropdown.test.js +134 -0
  21. package/lib/components/__tests__/input.test.js +129 -0
  22. package/lib/components/blank.js +316 -222
  23. package/lib/components/blank.js.map +1 -1
  24. package/lib/components/correct-input.js +40 -43
  25. package/lib/components/correct-input.js.map +1 -1
  26. package/lib/components/dropdown.js +394 -125
  27. package/lib/components/dropdown.js.map +1 -1
  28. package/lib/components/input.js +2 -3
  29. package/lib/components/input.js.map +1 -1
  30. package/lib/constructed-response.js +83 -27
  31. package/lib/constructed-response.js.map +1 -1
  32. package/lib/customizable.js +44 -0
  33. package/lib/customizable.js.map +1 -0
  34. package/lib/drag-in-the-blank.js +155 -62
  35. package/lib/drag-in-the-blank.js.map +1 -1
  36. package/lib/index.js +8 -1
  37. package/lib/index.js.map +1 -1
  38. package/lib/inline-dropdown.js +5 -4
  39. package/lib/inline-dropdown.js.map +1 -1
  40. package/lib/mask.js +90 -57
  41. package/lib/mask.js.map +1 -1
  42. package/lib/serialization.js +31 -43
  43. package/lib/serialization.js.map +1 -1
  44. package/lib/with-mask.js +49 -21
  45. package/lib/with-mask.js.map +1 -1
  46. package/package.json +18 -15
  47. package/src/__tests__/drag-in-the-blank.test.js +111 -0
  48. package/src/__tests__/index.test.js +39 -0
  49. package/src/__tests__/mask.test.js +187 -0
  50. package/src/__tests__/serialization.test.js +54 -0
  51. package/src/__tests__/utils.js +1 -0
  52. package/src/__tests__/with-mask.test.js +76 -0
  53. package/src/choices/__tests__/index.test.js +75 -0
  54. package/src/choices/choice.jsx +83 -96
  55. package/src/choices/index.jsx +11 -5
  56. package/src/components/__tests__/blank.test.js +138 -0
  57. package/src/components/__tests__/correct-input.test.js +90 -0
  58. package/src/components/__tests__/dropdown.test.js +93 -0
  59. package/src/components/__tests__/input.test.js +102 -0
  60. package/src/components/blank.jsx +316 -204
  61. package/src/components/correct-input.jsx +37 -38
  62. package/src/components/dropdown.jsx +371 -125
  63. package/src/constructed-response.jsx +71 -18
  64. package/src/customizable.jsx +35 -0
  65. package/src/drag-in-the-blank.jsx +152 -40
  66. package/src/index.js +10 -1
  67. package/src/inline-dropdown.jsx +2 -0
  68. package/src/mask.jsx +71 -25
  69. package/src/serialization.js +22 -34
  70. package/src/with-mask.jsx +43 -3
  71. package/README.md +0 -14
  72. package/lib/new-serialization.js +0 -267
  73. package/lib/new-serialization.js.map +0 -1
  74. package/lib/parse-html.js +0 -17
  75. package/lib/parse-html.js.map +0 -1
  76. package/lib/test-serializer.js +0 -164
  77. package/lib/test-serializer.js.map +0 -1
  78. package/src/new-serialization.jsx +0 -291
  79. package/src/parse-html.js +0 -8
  80. package/src/test-serializer.js +0 -163
@@ -1,16 +1,28 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { renderMath } from '@pie-lib/math-rendering';
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
- // eslint-disable-next-line react/display-name
9
11
  const Masked = withMask('blank', (props) => (node, data, onChange) => {
10
- const dataset = node.data ? node.data.dataset || {} : {};
12
+ const dataset = node.data?.dataset || {};
11
13
  if (dataset.component === 'blank') {
12
14
  // eslint-disable-next-line react/prop-types
13
- const { disabled, duplicates, correctResponse, feedback, showCorrectAnswer } = props;
15
+ const {
16
+ disabled,
17
+ duplicates,
18
+ correctResponse,
19
+ feedback,
20
+ showCorrectAnswer,
21
+ emptyResponseAreaWidth,
22
+ emptyResponseAreaHeight,
23
+ instanceId,
24
+ isDragging
25
+ } = props;
14
26
  const choiceId = showCorrectAnswer ? correctResponse[dataset.id] : data[dataset.id];
15
27
  // eslint-disable-next-line react/prop-types
16
28
  const choice = choiceId && props.choices.find((c) => c.id === choiceId);
@@ -23,18 +35,37 @@ const Masked = withMask('blank', (props) => (node, data, onChange) => {
23
35
  duplicates={duplicates}
24
36
  choice={choice}
25
37
  id={dataset.id}
26
- onChange={onChange}
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}
27
51
  />
28
52
  );
29
53
  }
30
54
  });
31
55
 
32
56
  export default class DragInTheBlank extends React.Component {
57
+ constructor(props) {
58
+ super(props);
59
+ this.state = {
60
+ activeDragItem: null,
61
+ };
62
+ }
63
+
33
64
  static propTypes = {
34
65
  markup: PropTypes.string,
35
66
  layout: PropTypes.object,
36
67
  choicesPosition: PropTypes.string,
37
- choices: PropTypes.arrayOf(PropTypes.shape({ label: PropTypes.string, value: PropTypes.string })),
68
+ choices: PropTypes.array,
38
69
  value: PropTypes.object,
39
70
  onChange: PropTypes.func,
40
71
  duplicates: PropTypes.bool,
@@ -42,27 +73,93 @@ export default class DragInTheBlank extends React.Component {
42
73
  feedback: PropTypes.object,
43
74
  correctResponse: PropTypes.object,
44
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
- UNSAFE_componentWillReceiveProps() {
48
- if (this.rootRef) {
49
- renderMath(this.rootRef);
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
- componentDidUpdate() {
54
- renderMath(this.rootRef);
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;
126
+
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
+ };
56
148
 
57
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,
@@ -89,36 +185,52 @@ export default class DragInTheBlank extends React.Component {
89
185
  disabled,
90
186
  feedback,
91
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
- <div ref={(ref) => ref && (this.rootRef = ref)} style={style}>
102
- <Choices
103
- choicePosition={choicePosition}
104
- duplicates={duplicates}
105
- choices={choices}
106
- value={value}
107
- disabled={disabled}
108
- />
109
- <Masked
110
- markup={markup}
111
- layout={layout}
112
- value={value}
113
- choices={choices}
114
- onChange={onChange}
115
- disabled={disabled}
116
- duplicates={duplicates}
117
- feedback={feedback}
118
- correctResponse={correctResponse}
119
- showCorrectAnswer={showCorrectAnswer}
120
- />
121
- </div>
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,7 +1,16 @@
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
 
7
- export { withMask, buildLayoutFromMarkup, DragInTheBlank, ConstructedResponse, InlineDropdown, componentize };
8
+ export {
9
+ withMask,
10
+ buildLayoutFromMarkup,
11
+ DragInTheBlank,
12
+ ConstructedResponse,
13
+ InlineDropdown,
14
+ componentize,
15
+ Customizable,
16
+ };
@@ -17,10 +17,12 @@ export default withMask('dropdown', (props) => (node, data, onChange) => {
17
17
  correct={feedback && feedback[dataset.id] && feedback[dataset.id] === 'correct'}
18
18
  disabled={disabled || showCorrectAnswer}
19
19
  value={finalChoice}
20
+ correctValue={showCorrectAnswer ? correctAnswer && correctAnswer.label : undefined}
20
21
  id={dataset.id}
21
22
  onChange={onChange}
22
23
  choices={choices[dataset.id]}
23
24
  showCorrectAnswer={showCorrectAnswer}
25
+ singleQuery={Object.keys(choices).length == 1}
24
26
  />
25
27
  );
26
28
  }
package/src/mask.jsx CHANGED
@@ -1,15 +1,19 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { Text } from 'slate';
4
- import { withStyles } from '@material-ui/core/styles';
3
+ import get from 'lodash/get';
4
+ import { styled } from '@mui/material/styles';
5
+ import { renderMath } from '@pie-lib/math-rendering';
5
6
  import { MARK_TAGS } from './serialization';
6
7
 
7
- const Paragraph = withStyles((theme) => ({
8
- para: {
9
- paddingTop: 2 * theme.spacing.unit,
10
- paddingBottom: 2 * theme.spacing.unit,
11
- },
12
- }))((props) => <div className={props.classes.para}>{props.children}</div>);
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
+ }));
13
17
 
14
18
  const restrictWhitespaceTypes = ['tbody', 'tr'];
15
19
 
@@ -25,24 +29,32 @@ const addText = (parentNode, text) => {
25
29
  };
26
30
 
27
31
  const getMark = (n) => {
28
- const markTags = Object.values(MARK_TAGS);
32
+ const mark = n.leaves.find((leave) => get(leave, 'marks', []).length);
33
+
34
+ if (mark) {
35
+ return mark.marks[0];
36
+ }
29
37
 
30
- return markTags.includes(n.type);
38
+ return null;
31
39
  };
32
40
 
33
- export const renderChildren = (layout, value, onChange, rootRenderChildren, parentNode) => {
41
+ export const renderChildren = (layout, value, onChange, rootRenderChildren, parentNode, elementType) => {
34
42
  if (!value) {
35
43
  return null;
36
44
  }
37
45
 
38
46
  const children = [];
39
47
 
40
- (layout.children || []).forEach((n, index) => {
41
- const key = `${n.type}-${index}`;
48
+ (layout.nodes || []).forEach((n, index) => {
49
+ const key = n.type ? `${n.type}-${index}` : `${index}`;
42
50
 
43
51
  if (n.isMath) {
44
52
  children.push(
45
- <span dangerouslySetInnerHTML={{ __html: `<math displaystyle="true">${n.children[0].innerHTML}</math>` }} />,
53
+ <span
54
+ dangerouslySetInnerHTML={{
55
+ __html: `<math displaystyle="true">${n.nodes[0].innerHTML}</math>`,
56
+ }}
57
+ />,
46
58
  );
47
59
  return children;
48
60
  }
@@ -51,12 +63,19 @@ export const renderChildren = (layout, value, onChange, rootRenderChildren, pare
51
63
  const c = rootRenderChildren(n, value, onChange);
52
64
  if (c) {
53
65
  children.push(c);
66
+ if (parentNode?.type !== 'td' && elementType === 'drag-in-the-blank') {
67
+ children.push(<Spacer key={`spacer-${index}`} />);
68
+ }
54
69
  return;
55
70
  }
56
71
  }
57
72
 
58
- if (Text.isText(n)) {
59
- const content = n.text;
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
+ }, '');
60
79
  const mark = getMark(n);
61
80
 
62
81
  if (mark) {
@@ -72,14 +91,17 @@ export const renderChildren = (layout, value, onChange, rootRenderChildren, pare
72
91
  }
73
92
  } else if (content.length > 0) {
74
93
  children.push(content);
94
+ if (parentNode?.type !== 'td' && elementType === 'drag-in-the-blank') {
95
+ children.push(<Spacer key={`spacer-${index}`} />);
96
+ }
75
97
  }
76
98
  } else {
77
- const subNodes = renderChildren(n, value, onChange, rootRenderChildren, n);
99
+ const subNodes = renderChildren(n, value, onChange, rootRenderChildren, n, elementType);
78
100
  if (n.type === 'p' || n.type === 'paragraph') {
79
101
  children.push(<Paragraph key={key}>{subNodes}</Paragraph>);
80
102
  } else {
81
103
  const Tag = n.type;
82
- if (Tag !== 'source' && n.children && n.children.length > 0) {
104
+ if (n.nodes && n.nodes.length > 0) {
83
105
  children.push(
84
106
  <Tag key={key} {...n.data.attributes}>
85
107
  {subNodes}
@@ -94,32 +116,56 @@ export const renderChildren = (layout, value, onChange, rootRenderChildren, pare
94
116
  return children;
95
117
  };
96
118
 
97
- const MaskContainer = withStyles(() => ({
98
- main: {
99
- display: 'initial',
119
+ const MaskContainer = styled('div')(() => ({
120
+ display: 'initial',
121
+ '&:not(.MathJax) table': {
122
+ borderCollapse: 'collapse',
100
123
  },
101
- }))((props) => <div className={props.classes.main}>{props.children}</div>);
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
+ }));
102
130
 
103
131
  /**
104
132
  * Renders a layout that uses the slate.js Value model structure.
105
133
  */
106
134
  export default class Mask extends React.Component {
135
+ constructor(props) {
136
+ super(props);
137
+ this.internalContainerRef = React.createRef();
138
+ }
139
+
107
140
  static propTypes = {
108
141
  renderChildren: PropTypes.func,
109
142
  layout: PropTypes.object,
110
143
  value: PropTypes.object,
111
144
  onChange: PropTypes.func,
145
+ elementType: PropTypes.string,
146
+ containerRef: PropTypes.oneOfType([
147
+ PropTypes.func,
148
+ PropTypes.shape({ current: PropTypes.instanceOf(Element) }),
149
+ ]),
112
150
  };
113
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
+
114
159
  handleChange = (id, value) => {
115
160
  const data = { ...this.props.value, [id]: value };
116
161
  this.props.onChange(data);
117
162
  };
118
163
 
119
164
  render() {
120
- const { value, layout } = this.props;
121
- 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;
122
168
 
123
- return <MaskContainer>{children}</MaskContainer>;
169
+ return <MaskContainer ref={ref}>{children}</MaskContainer>;
124
170
  }
125
171
  }
@@ -1,10 +1,7 @@
1
- import React from 'react';
2
- import { jsx } from 'slate-hyperscript';
1
+ import Html from 'slate-html-serializer';
3
2
  import { object as toStyleObject } from 'to-style';
4
3
  import debug from 'debug';
5
4
 
6
- import Html from './test-serializer';
7
-
8
5
  const log = debug('@pie-lib:mask-markup:serialization');
9
6
 
10
7
  const INLINE = ['span'];
@@ -108,13 +105,13 @@ export const MARK_TAGS = {
108
105
  const marks = {
109
106
  deserialize(el, next) {
110
107
  const mark = MARK_TAGS[el.tagName.toLowerCase()];
111
-
112
- if (!mark) {
113
- return;
114
- }
115
-
108
+ if (!mark) return;
116
109
  log('[deserialize] mark: ', mark);
117
- return jsx('text', { type: mark }, next(el.childNodes));
110
+ return {
111
+ object: 'mark',
112
+ type: mark,
113
+ nodes: next(el.childNodes),
114
+ };
118
115
  },
119
116
  };
120
117
 
@@ -130,7 +127,10 @@ const rules = [
130
127
  }
131
128
 
132
129
  if (el.nodeType === TEXT_NODE) {
133
- return jsx('text', el.textContent);
130
+ return {
131
+ object: 'text',
132
+ leaves: [{ text: el.textContent }],
133
+ };
134
134
  }
135
135
 
136
136
  const type = el.tagName.toLowerCase();
@@ -142,33 +142,21 @@ const rules = [
142
142
  }
143
143
 
144
144
  const allAttrs = attributes.reduce(attributesToMap(el), { ...normalAttrs });
145
+ const object = getObject(type);
145
146
 
146
147
  if (el.tagName.toLowerCase() === 'math') {
147
- return jsx('element', {
148
- type: 'mathml',
149
- data: {
150
- html: el.innerHTML,
151
- },
152
- });
153
-
154
- // return {
155
- // isMath: true,
156
- // nodes: [el]
157
- // };
158
- }
159
-
160
- if (el.tagName.toLowerCase() === 'br') {
161
- return jsx('element', { type, data: {} });
148
+ return {
149
+ isMath: true,
150
+ nodes: [el],
151
+ };
162
152
  }
163
153
 
164
- return jsx(
165
- 'element',
166
- {
167
- type,
168
- data: { dataset: { ...el.dataset }, attributes: { ...allAttrs } },
169
- },
170
- next(el.childNodes),
171
- );
154
+ return {
155
+ object,
156
+ type,
157
+ data: { dataset: { ...el.dataset }, attributes: { ...allAttrs } },
158
+ nodes: next(el.childNodes),
159
+ };
172
160
  },
173
161
  },
174
162
  ];
package/src/with-mask.jsx CHANGED
@@ -7,7 +7,7 @@ import { deserialize } from './serialization';
7
7
  export const buildLayoutFromMarkup = (markup, type) => {
8
8
  const { markup: processed } = componentize(markup, type);
9
9
  const value = deserialize(processed);
10
- return value;
10
+ return value.document;
11
11
  };
12
12
 
13
13
  export const withMask = (type, renderChildren) => {
@@ -23,13 +23,53 @@ export const withMask = (type, renderChildren) => {
23
23
  layout: PropTypes.object,
24
24
  value: PropTypes.object,
25
25
  onChange: PropTypes.func,
26
+ customMarkMarkupComponent: PropTypes.func,
27
+ elementType: PropTypes.string,
26
28
  };
27
29
 
30
+ constructor(props) {
31
+ super(props);
32
+ this.containerRef = React.createRef();
33
+ }
34
+
35
+ componentDidUpdate(prevProps) {
36
+ if (this.props.markup !== prevProps.markup) {
37
+ const domNode = this.containerRef.current;
38
+ const mathElements = domNode && domNode.querySelectorAll('[data-latex][data-math-handled="true"]');
39
+
40
+ // Clean up for fresh MathJax processing
41
+ (mathElements || []).forEach((el) => {
42
+ // Remove the MathJax container to allow for clean updates
43
+ const mjxContainer = el.querySelector('mjx-container');
44
+
45
+ if (mjxContainer) {
46
+ el.removeChild(mjxContainer);
47
+ }
48
+
49
+ // Update the innerHTML to match the raw LaTeX data, ensuring it is reprocessed correctly
50
+ const latexCode = el.getAttribute('data-raw');
51
+ el.innerHTML = latexCode;
52
+
53
+ // Remove the attribute to signal that MathJax should reprocess this element
54
+ el.removeAttribute('data-math-handled');
55
+ });
56
+ }
57
+ }
58
+
28
59
  render() {
29
- const { markup, layout, value, onChange } = this.props;
60
+ const { markup, layout, value, onChange, elementType } = this.props;
30
61
 
31
62
  const maskLayout = layout ? layout : buildLayoutFromMarkup(markup, type);
32
- return <Mask layout={maskLayout} value={value} onChange={onChange} renderChildren={renderChildren(this.props)} />;
63
+ return (
64
+ <Mask
65
+ containerRef={this.containerRef}
66
+ elementType={elementType}
67
+ layout={maskLayout}
68
+ value={value}
69
+ onChange={onChange}
70
+ renderChildren={renderChildren(this.props)}
71
+ />
72
+ );
33
73
  }
34
74
  };
35
75
  };
package/README.md DELETED
@@ -1,14 +0,0 @@
1
- # mask-markup
2
-
3
- ## issues
4
-
5
- - dnd
6
- - simple approach loses context due to stepping out of react tree to run a ReactDOM.render().
7
- - Would need to pass drag parts as props (no context)
8
- - Or do the entire tree render in react - like a simple slate
9
- - HTML5Backend - ? going to be a an issue w/ multiple items using dnd?
10
-
11
- * hey diddle sample
12
- * add feedback
13
- * check perf
14
- * more complex html