@pie-lib/math-toolbar 2.0.0-beta.3 → 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/src/index.jsx CHANGED
@@ -1,13 +1,19 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import cx from 'classnames';
4
3
  import EditorAndPad from './editor-and-pad';
5
4
  import { DoneButton } from './done-button';
6
- import { withStyles } from '@material-ui/core/styles';
5
+ import { styled } from '@mui/material/styles';
7
6
  import MathPreview from './math-preview';
8
7
 
9
8
  export { MathPreview };
10
9
 
10
+ const PureToolbarContainer = styled('div')({
11
+ display: 'flex',
12
+ width: '100%',
13
+ zIndex: 8,
14
+ alignItems: 'center',
15
+ });
16
+
11
17
  export class MathToolbar extends React.Component {
12
18
  static propTypes = {
13
19
  autoFocus: PropTypes.bool,
@@ -28,6 +34,8 @@ export class MathToolbar extends React.Component {
28
34
  onFocus: PropTypes.func,
29
35
  onBlur: PropTypes.func,
30
36
  hideDoneButton: PropTypes.bool,
37
+ keyPadCharacterRef: PropTypes.func,
38
+ setKeypadInteraction: PropTypes.func,
31
39
  };
32
40
 
33
41
  static defaultProps = {
@@ -83,6 +91,8 @@ export class MathToolbar extends React.Component {
83
91
  onBlur,
84
92
  hideDoneButton,
85
93
  error,
94
+ keyPadCharacterRef,
95
+ setKeypadInteraction,
86
96
  maxResponseAreas,
87
97
  } = this.props;
88
98
 
@@ -96,6 +106,8 @@ export class MathToolbar extends React.Component {
96
106
  additionalKeys={additionalKeys}
97
107
  noDecimal={noDecimal}
98
108
  keypadMode={keypadMode}
109
+ keyPadCharacterRef={keyPadCharacterRef}
110
+ setKeypadInteraction={setKeypadInteraction}
99
111
  onChange={this.onChange}
100
112
  onDone={this.done}
101
113
  onFocus={onFocus}
@@ -114,7 +126,7 @@ export class MathToolbar extends React.Component {
114
126
  export class RawPureToolbar extends React.Component {
115
127
  static propTypes = {
116
128
  classNames: PropTypes.object,
117
- latex: PropTypes.string,
129
+ latex: PropTypes.string.isRequired,
118
130
  keypadMode: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
119
131
  hideInput: PropTypes.bool,
120
132
  noLatexHandling: PropTypes.bool,
@@ -125,7 +137,6 @@ export class RawPureToolbar extends React.Component {
125
137
  onAnswerBlockAdd: PropTypes.func,
126
138
  additionalKeys: PropTypes.array,
127
139
  onFocus: PropTypes.func,
128
- classes: PropTypes.object.isRequired,
129
140
  autoFocus: PropTypes.bool,
130
141
  noDecimal: PropTypes.bool,
131
142
  allowAnswerBlock: PropTypes.bool,
@@ -136,6 +147,8 @@ export class RawPureToolbar extends React.Component {
136
147
  hideDoneButtonBackground: PropTypes.bool,
137
148
  error: PropTypes.any,
138
149
  maxResponseAreas: PropTypes.number,
150
+ keyPadCharacterRef: PropTypes.object,
151
+ setKeypadInteraction: PropTypes.func,
139
152
  };
140
153
 
141
154
  static defaultProps = {
@@ -158,6 +171,8 @@ export class RawPureToolbar extends React.Component {
158
171
  hideInput,
159
172
  noLatexHandling,
160
173
  layoutForKeyPad,
174
+ keyPadCharacterRef,
175
+ setKeypadInteraction,
161
176
  latex,
162
177
  onChange,
163
178
  onDone,
@@ -165,13 +180,12 @@ export class RawPureToolbar extends React.Component {
165
180
  onBlur,
166
181
  hideDoneButton,
167
182
  hideDoneButtonBackground,
168
- classes,
169
183
  error,
170
184
  maxResponseAreas,
171
185
  } = this.props;
172
186
 
173
187
  return (
174
- <div className={cx(classes.pureToolbar, (classNames || {}).toolbar)} contentEditable={false}>
188
+ <PureToolbarContainer className={(classNames && classNames.toolbar) || ''} ref={keyPadCharacterRef}>
175
189
  <div />
176
190
  <EditorAndPad
177
191
  autoFocus={autoFocus}
@@ -193,21 +207,14 @@ export class RawPureToolbar extends React.Component {
193
207
  onBlur={onBlur}
194
208
  error={error}
195
209
  maxResponseAreas={maxResponseAreas}
210
+ setKeypadInteraction={setKeypadInteraction}
196
211
  />
197
212
  {(!controlledKeypad || (controlledKeypad && showKeypad)) && !hideDoneButton && (
198
213
  <DoneButton hideBackground={hideDoneButtonBackground} onClick={onDone} />
199
214
  )}
200
- </div>
215
+ </PureToolbarContainer>
201
216
  );
202
217
  }
203
218
  }
204
- const styles = () => ({
205
- pureToolbar: {
206
- display: 'flex',
207
- width: '100%',
208
- zIndex: 8,
209
- alignItems: 'center',
210
- },
211
- });
212
219
 
213
- export const PureToolbar = withStyles(styles)(RawPureToolbar);
220
+ export const PureToolbar = RawPureToolbar;
@@ -1,205 +1,164 @@
1
1
  import React from 'react';
2
- import classNames from 'classnames';
3
- import get from 'lodash/get';
4
2
  import debug from 'debug';
5
- import { makeStyles } from '@material-ui/styles';
3
+ import { styled } from '@mui/material/styles';
6
4
  import PropTypes from 'prop-types';
7
5
  import { mq } from '@pie-lib/math-input';
6
+ import { markFractionBaseSuperscripts } from './utils';
7
+
8
+ const { commonMqFontStyles, longdivStyles, supsubStyles } = mq.CommonMqStyles;
8
9
 
9
10
  const log = debug('@pie-lib:math-toolbar:math-preview');
10
11
 
11
- const useStyles = makeStyles((theme) => ({
12
- root: {
13
- display: 'inline-flex',
14
- alignItems: 'center',
15
- position: 'relative',
12
+ const MathPreviewContainer = styled('div')(({ theme, isSelected }) => ({
13
+ display: 'inline-flex',
14
+ alignItems: 'center',
15
+ position: 'relative',
16
+ '& *': commonMqFontStyles,
17
+ ...supsubStyles,
18
+ ...longdivStyles,
19
+ '& > .mq-math-mode': {
20
+ border: isSelected ? 'solid 0px lightgrey' : 'solid 1px lightgrey',
21
+ },
22
+ '& > .mq-focused': {
23
+ outline: 'none',
24
+ boxShadow: 'none',
25
+ border: 'solid 1px black',
26
+ borderRadius: '0px',
27
+ },
28
+ '& > .mq-math-mode .mq-root-block': {
29
+ paddingTop: '7px !important',
30
+ },
31
+ '& > .mq-math-mode .mq-overarc ': {
32
+ paddingTop: '0.45em !important',
33
+ },
34
+ '& > .mq-math-mode .mq-sqrt-prefix': {
35
+ verticalAlign: 'baseline !important',
36
+ top: '1px !important',
37
+ left: '-0.1em !important',
38
+ },
39
+ '& > .mq-math-mode .mq-denominator': {
40
+ marginTop: '-5px !important',
41
+ padding: '0.5em 0.1em 0.1em !important',
42
+ },
43
+ '& > .mq-math-mode .mq-numerator, .mq-math-mode .mq-over': {
44
+ padding: '0 0.1em !important',
45
+ paddingBottom: '0 !important',
46
+ marginBottom: '-2px',
47
+ },
48
+ '& > .mq-math-mode .mq-longdiv .mq-longdiv-inner .mq-empty': {
49
+ paddingTop: '6px !important',
50
+ paddingLeft: '4px !important',
51
+ },
52
+ '& > .mq-math-mode .mq-longdiv .mq-longdiv-inner': {
53
+ marginLeft: '0 !important',
54
+ },
55
+ '& > .mq-math-mode .mq-overarrow': {
56
+ fontFamily: 'Roboto, Helvetica, Arial, sans-serif !important',
57
+ },
58
+ '& > .mq-math-mode .mq-paren': {
59
+ verticalAlign: 'top !important',
60
+ padding: '1px 0.1em !important',
61
+ },
62
+ '& > .mq-math-mode .mq-sqrt-stem': {
63
+ borderTop: '0.07em solid',
64
+ marginLeft: '-1.5px',
65
+ marginTop: '-2px !important',
66
+ paddingTop: '5px !important',
67
+ },
68
+ '& .mq-overarrow-inner': {
69
+ paddingTop: '0 !important',
70
+ border: 'none !important',
71
+ },
72
+ '& .mq-editable-field .mq-cursor': {
73
+ marginTop: '-15px !important',
74
+ },
75
+ '& .mq-overarrow.mq-arrow-both': {
76
+ top: '7.5px',
77
+ marginTop: '0px',
78
+ minWidth: '1.23em',
16
79
  '& *': {
17
- fontFamily: 'MJXZERO, MJXTEX !important',
18
- '-webkit-font-smoothing': 'antialiased !important',
19
- },
20
- '& > .mq-math-mode > span > var': {
21
- fontFamily: 'MJXZERO, MJXTEX-I !important',
22
- },
23
- '& > .mq-math-mode span var': {
24
- fontFamily: 'MJXZERO, MJXTEX-I !important',
25
- },
26
- '& > .mq-math-mode .mq-nonSymbola': {
27
- fontFamily: 'MJXZERO, MJXTEX-I !important',
28
- },
29
- '& > .mq-math-mode > span > var.mq-operator-name': {
30
- fontFamily: 'MJXZERO, MJXTEX !important',
31
- },
32
- '& > .mq-math-mode': {
33
- border: 'solid 1px lightgrey',
34
- },
35
- '& > .mq-focused': {
36
- outline: 'none',
37
- boxShadow: 'none',
38
- border: 'solid 1px black',
39
- borderRadius: '0px',
40
- },
41
- '& > .mq-math-mode .mq-root-block': {
42
- paddingTop: '7px !important',
43
- },
44
- '& > .mq-math-mode .mq-overarc ': {
45
- paddingTop: '0.45em !important',
46
- },
47
- '& > .mq-math-mode .mq-sqrt-prefix': {
48
- verticalAlign: 'baseline !important',
49
- top: '1px !important',
50
- left: '-0.1em !important',
51
- },
52
- '& > .mq-math-mode .mq-denominator': {
53
- marginTop: '-5px !important',
54
- padding: '0.5em 0.1em 0.1em !important',
55
- },
56
- '& > .mq-math-mode .mq-numerator, .mq-math-mode .mq-over': {
57
- padding: '0 0.1em !important',
58
- paddingBottom: '0 !important',
59
- marginBottom: '-2px',
60
- },
61
- '& > .mq-math-mode sup.mq-nthroot': {
62
- fontSize: '70.7% !important',
63
- verticalAlign: '0.5em !important',
64
- paddingRight: '0.15em',
80
+ lineHeight: '1 !important',
65
81
  },
66
- '& > .mq-longdiv-inner': {
67
- marginTop: '-1px',
68
- marginLeft: '5px !important;',
69
-
70
- '& > .mq-empty': {
71
- padding: '0 !important',
72
- marginLeft: '0px !important',
73
- marginTop: '2px',
74
- },
75
- },
76
- '& > .mq-math-mode .mq-longdiv': {
77
- display: 'inline-flex !important',
78
- },
79
- '& > .mq-math-mode .mq-longdiv .mq-longdiv-inner .mq-empty': {
80
- paddingTop: '6px !important',
81
- paddingLeft: '4px !important',
82
- },
83
- '& > .mq-math-mode .mq-longdiv .mq-longdiv-inner': {
84
- marginLeft: '0 !important',
85
- },
86
- '& > .mq-math-mode .mq-supsub': {
87
- fontSize: '70.7% !important',
88
- },
89
- '& > .mq-math-mode .mq-overarrow': {
90
- fontFamily: 'Roboto, Helvetica, Arial, sans-serif !important',
91
- },
92
- '& > .mq-math-mode .mq-paren': {
93
- verticalAlign: 'top !important',
94
- padding: '1px 0.1em !important',
95
- },
96
-
97
- '& > .mq-math-mode .mq-sqrt-stem': {
98
- borderTop: '0.07em solid',
99
- marginLeft: '-1.5px',
100
- marginTop: '-2px !important',
101
- paddingTop: '5px !important',
102
- },
103
- '& > .mq-supsub ': {
104
- fontSize: '70.7%',
105
- },
106
-
107
- '& > .mq-math-mode .mq-supsub.mq-sup-only': {
108
- verticalAlign: '-0.1em !important',
109
-
110
- '& .mq-sup': {
111
- marginBottom: '0px !important',
112
- },
113
- },
114
- '& .mq-overarrow-inner': {
115
- paddingTop: '0 !important',
116
- border: 'none !important',
82
+ '&:before': {
83
+ top: '-0.4em',
84
+ left: '-1px',
117
85
  },
118
- '& .mq-editable-field .mq-cursor': {
119
- marginTop: '-15px !important',
86
+ '&:after': {
87
+ top: '0px !important',
88
+ position: 'absolute !important',
89
+ right: '-2px',
120
90
  },
121
- '& .mq-overarrow.mq-arrow-both': {
122
- top: '7.5px',
123
- marginTop: '0px',
124
- minWidth: '1.23em',
125
- '& *': {
126
- lineHeight: '1 !important',
127
- },
128
- '&:before': {
129
- top: '-0.4em',
130
- left: '-1px',
131
- },
132
- '&:after': {
133
- top: '0px !important',
134
- position: 'absolute',
135
- right: '-2px',
136
- },
137
- '&.mq-empty:after': {
138
- top: '-0.45em',
139
- },
140
- },
141
- '& .mq-overarrow.mq-arrow-right': {
142
- '&:before': {
143
- top: '-0.4em',
144
- right: '-1px',
145
- },
146
- },
147
- '& .mq-overarrow-inner-right': {
148
- display: 'none !important',
149
- },
150
- '& .mq-overarrow-inner-left': {
151
- display: 'none !important',
152
- },
153
- '& .mq-longdiv-inner': {
154
- borderTop: '1px solid !important',
155
- paddingTop: '1.5px !important',
156
- },
157
- '& .mq-parallelogram': {
158
- lineHeight: 0.85,
91
+ '&.mq-empty:after': {
92
+ top: '-0.45em',
159
93
  },
160
94
  },
161
- selected: {
162
- border: `solid 1px ${get(theme, 'palette.primary.main')}`,
163
- '& > .mq-math-mode': {
164
- border: 'solid 0px lightgrey',
95
+ '& .mq-overarrow.mq-arrow-right': {
96
+ '&:before': {
97
+ top: '-0.4em',
98
+ right: '-1px',
165
99
  },
166
100
  },
167
- insideOverlay: {
168
- position: 'absolute',
169
- bottom: 0,
170
- left: 0,
171
- right: 0,
172
- top: 0,
101
+ '& .mq-overarrow-inner-right': {
102
+ display: 'none !important',
103
+ },
104
+ '& .mq-overarrow-inner-left': {
105
+ display: 'none !important',
106
+ },
107
+ '& .mq-longdiv-inner': {
108
+ borderTop: '1px solid !important',
109
+ paddingTop: '1.5px !important',
173
110
  },
111
+ '& .mq-parallelogram': {
112
+ lineHeight: 0.85,
113
+ },
114
+ '& span[data-prime="true"]': {
115
+ fontFamily: 'Roboto, Helvetica, Arial, sans-serif !important',
116
+ },
117
+ ...(isSelected && {
118
+ border: `solid 1px ${theme.palette.primary.main}`,
119
+ }),
174
120
  }));
175
121
 
176
- export const RawMathPreview = React.forwardRef((props, ref) => {
177
- log('[render] data: ', props.element.data);
178
- const latex = props.element.data.latex;
179
- const { isSelected, onFocus, onBlur, attributes, children } = props;
180
- const classes = useStyles(props);
181
-
182
- return (
183
- <div
184
- className={classNames(classes.root, isSelected && classes.selected)}
185
- {...attributes}
186
- contentEditable={false}
187
- ref={ref}
188
- >
189
- {children} <span className={classes.insideOverlay} />
190
- <mq.Static latex={latex} onFocus={onFocus} onBlur={onBlur} />
191
- </div>
192
- );
122
+ const InsideOverlay = styled('span')({
123
+ position: 'absolute',
124
+ bottom: 0,
125
+ left: 0,
126
+ right: 0,
127
+ top: 0,
193
128
  });
194
129
 
195
- RawMathPreview.propTypes = {
196
- element: PropTypes.object,
197
- latex: PropTypes.string,
198
- node: PropTypes.object,
199
- classes: PropTypes.object,
200
- isSelected: PropTypes.bool,
201
- onFocus: PropTypes.func,
202
- onBlur: PropTypes.func,
203
- };
130
+ export class RawMathPreview extends React.Component {
131
+ static propTypes = {
132
+ latex: PropTypes.string,
133
+ node: PropTypes.object,
134
+ isSelected: PropTypes.bool,
135
+ onFocus: PropTypes.func,
136
+ onBlur: PropTypes.func,
137
+ };
138
+
139
+ componentDidMount() {
140
+ markFractionBaseSuperscripts();
141
+ }
142
+
143
+ componentDidUpdate(prevProps) {
144
+ // Re-run only if LaTeX changed
145
+ if (this.props.node.data.get('latex') !== prevProps.node.data.get('latex')) {
146
+ markFractionBaseSuperscripts();
147
+ }
148
+ }
149
+
150
+ render() {
151
+ log('[render] data: ', this.props.node.data);
152
+ const latex = this.props.node.data.get('latex');
153
+ const { isSelected, onFocus, onBlur } = this.props;
154
+ return (
155
+ <MathPreviewContainer isSelected={isSelected}>
156
+ {' '}
157
+ <InsideOverlay />
158
+ <mq.Static latex={latex} onFocus={onFocus} onBlur={onBlur} />
159
+ </MathPreviewContainer>
160
+ );
161
+ }
162
+ }
204
163
 
205
164
  export default RawMathPreview;
package/src/utils.js ADDED
@@ -0,0 +1,11 @@
1
+ export const markFractionBaseSuperscripts = () => {
2
+ document.querySelectorAll('.mq-supsub.mq-sup-only').forEach((supsub) => {
3
+ const prev = supsub.previousElementSibling;
4
+
5
+ if (prev && prev.classList.contains('mq-non-leaf') && prev.querySelector('.mq-fraction')) {
6
+ supsub.classList.add('mq-after-fraction-group');
7
+ } else {
8
+ supsub.classList.remove('mq-after-fraction-group');
9
+ }
10
+ });
11
+ };