@pie-lib/math-input 6.11.4 → 6.11.5-next.1844

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 (48) hide show
  1. package/CHANGELOG.json +6 -1536
  2. package/CHANGELOG.md +178 -117
  3. package/NEXT.CHANGELOG.json +1 -0
  4. package/lib/horizontal-keypad.js +9 -3
  5. package/lib/horizontal-keypad.js.map +1 -1
  6. package/lib/index.js +10 -14
  7. package/lib/index.js.map +1 -1
  8. package/lib/keypad/index.js +95 -24
  9. package/lib/keypad/index.js.map +1 -1
  10. package/lib/keys/geometry.js +4 -2
  11. package/lib/keys/geometry.js.map +1 -1
  12. package/lib/keys/grades.js +12 -0
  13. package/lib/keys/grades.js.map +1 -1
  14. package/lib/keys/log.js +1 -1
  15. package/lib/keys/log.js.map +1 -1
  16. package/lib/mq/common-mq-styles.js +110 -0
  17. package/lib/mq/common-mq-styles.js.map +1 -0
  18. package/lib/mq/index.js +8 -0
  19. package/lib/mq/index.js.map +1 -1
  20. package/lib/mq/input.js +12 -10
  21. package/lib/mq/input.js.map +1 -1
  22. package/lib/mq/static.js +198 -75
  23. package/lib/mq/static.js.map +1 -1
  24. package/lib/shared/constants.js +16 -0
  25. package/lib/updateSpans.js +23 -0
  26. package/lib/updateSpans.js.map +1 -0
  27. package/package.json +4 -2
  28. package/src/__tests__/__snapshots__/math-input-test.jsx.snap +152 -0
  29. package/src/__tests__/math-input-test.jsx +85 -0
  30. package/src/horizontal-keypad.jsx +14 -1
  31. package/src/index.jsx +1 -10
  32. package/src/keypad/__tests__/__snapshots__/index.test.jsx.snap +193 -0
  33. package/src/keypad/__tests__/index.test.jsx +24 -0
  34. package/src/keypad/__tests__/keys-layout.test.js +15 -0
  35. package/src/keypad/index.jsx +99 -15
  36. package/src/keys/__tests__/utils.test.js +57 -0
  37. package/src/keys/geometry.js +6 -2
  38. package/src/keys/grades.js +11 -0
  39. package/src/keys/log.js +1 -1
  40. package/src/mq/__tests__/__snapshots__/input.test.jsx.snap +9 -0
  41. package/src/mq/__tests__/input.test.jsx +92 -0
  42. package/src/mq/__tests__/static.test.jsx +57 -0
  43. package/src/mq/common-mq-styles.js +105 -0
  44. package/src/mq/index.js +2 -1
  45. package/src/mq/input.jsx +22 -9
  46. package/src/mq/static.jsx +142 -13
  47. package/src/updateSpans.js +15 -0
  48. package/README.md +0 -27
package/src/mq/input.jsx CHANGED
@@ -53,14 +53,17 @@ export class Input extends React.Component {
53
53
  if (!this.mathField) {
54
54
  return;
55
55
  }
56
+
56
57
  const { latex } = this.props;
57
- if (latex) {
58
+
59
+ if (latex !== undefined && latex !== null) {
58
60
  this.mathField.latex(latex);
59
61
  }
60
62
  }
61
63
 
62
64
  clear() {
63
65
  this.mathField.latex('');
66
+
64
67
  return '';
65
68
  }
66
69
 
@@ -83,13 +86,16 @@ export class Input extends React.Component {
83
86
  } else {
84
87
  this.mathField.cmd(v);
85
88
  }
89
+
86
90
  this.mathField.focus();
91
+
87
92
  return this.mathField.latex();
88
93
  }
89
94
 
90
95
  keystroke(v) {
91
96
  this.mathField.keystroke(v);
92
97
  this.mathField.focus();
98
+
93
99
  return this.mathField.latex();
94
100
  }
95
101
 
@@ -97,12 +103,14 @@ export class Input extends React.Component {
97
103
  log('write: ', v);
98
104
  this.mathField.write(v);
99
105
  this.mathField.focus();
106
+
100
107
  return this.mathField.latex();
101
108
  }
102
109
 
103
110
  onInputEdit = () => {
104
111
  log('[onInputEdit] ...');
105
112
  const { onChange } = this.props;
113
+
106
114
  if (!this.mathField) {
107
115
  return;
108
116
  }
@@ -128,28 +136,33 @@ export class Input extends React.Component {
128
136
  }
129
137
 
130
138
  if (event.charCode === 13) {
131
- // if enter's pressed, we're going for a custom embedded element that'll
132
- // have a block display (empty div) - for a hacked line break using ccs
133
- // all because mathquill doesn't support a line break
134
- this.write('\\embed{newLine}[]');
135
- this.onInputEdit();
139
+ event.preventDefault();
140
+ return;
136
141
  }
137
142
  };
138
143
 
144
+ onClick = (event) => {
145
+ const { onClick } = this.props;
146
+
147
+ this.refresh();
148
+ onClick && onClick(event);
149
+ };
150
+
139
151
  shouldComponentUpdate(nextProps) {
140
152
  log('next: ', nextProps.latex);
141
153
  log('current: ', this.mathField.latex());
154
+
142
155
  return nextProps.latex !== this.mathField.latex();
143
156
  }
144
157
 
145
158
  render() {
146
- const { onClick, onFocus, onBlur, classes, className } = this.props;
159
+ const { onFocus, onBlur, classes, className } = this.props;
147
160
 
148
161
  return (
149
162
  <span
150
163
  className={classNames(classes.input, className)}
151
- onKeyPress={this.onKeyPress}
152
- onClick={onClick}
164
+ onKeyDown={this.onKeyPress}
165
+ onClick={this.onClick}
153
166
  onFocus={onFocus}
154
167
  onBlur={onBlur}
155
168
  ref={(r) => (this.input = r)}
package/src/mq/static.jsx CHANGED
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
2
2
  import React from 'react';
3
3
  import debug from 'debug';
4
4
  import MathQuill from '@pie-framework/mathquill';
5
- import { updateSpans } from '../index';
5
+ import { updateSpans } from '../updateSpans';
6
6
 
7
7
  let MQ;
8
8
  if (typeof window !== 'undefined') {
@@ -17,6 +17,18 @@ function stripSpaces(string = '') {
17
17
  return string.replace(WHITESPACE_REGEX, '');
18
18
  }
19
19
 
20
+ function countBraces(latex) {
21
+ let count = 0;
22
+
23
+ for (let i = 0; i < (latex || '').length; i++) {
24
+ if (latex[i] === '{') {
25
+ count++;
26
+ }
27
+ }
28
+
29
+ return count;
30
+ }
31
+
20
32
  /**
21
33
  * Wrapper for MathQuill MQ.MathField.
22
34
  */
@@ -36,9 +48,24 @@ export default class Static extends React.Component {
36
48
  getFieldName: () => {},
37
49
  };
38
50
 
51
+ constructor(props) {
52
+ super(props);
53
+ this.state = {
54
+ announcement: '',
55
+ previousLatex: '',
56
+ inputSource: null,
57
+ isDeleteKeyPressed: false,
58
+ };
59
+
60
+ this.inputRef = React.createRef();
61
+ }
62
+
39
63
  componentDidMount() {
40
64
  this.update();
41
65
  updateSpans();
66
+
67
+ this.createLiveRegion();
68
+ this.addEventListeners();
42
69
  }
43
70
 
44
71
  componentDidUpdate() {
@@ -46,7 +73,62 @@ export default class Static extends React.Component {
46
73
  updateSpans();
47
74
  }
48
75
 
49
- onInputEdit(field) {
76
+ componentWillUnmount() {
77
+ this.removeLiveRegion();
78
+ this.removeEventListeners();
79
+ }
80
+
81
+ createLiveRegion = () => {
82
+ this.liveRegion = document.createElement('div');
83
+ this.liveRegion.style.position = 'absolute';
84
+ this.liveRegion.style.width = '1px';
85
+ this.liveRegion.style.height = '1px';
86
+ this.liveRegion.style.marginTop = '-1px';
87
+ this.liveRegion.style.clip = 'rect(1px, 1px, 1px, 1px)';
88
+ this.liveRegion.style.overflow = 'hidden';
89
+ this.liveRegion.setAttribute('aria-live', 'polite');
90
+ this.liveRegion.setAttribute('aria-atomic', 'true');
91
+
92
+ document.body.appendChild(this.liveRegion);
93
+ };
94
+
95
+ addEventListeners = () => {
96
+ const input = this.inputRef.current;
97
+
98
+ if (input) {
99
+ input.addEventListener('keydown', this.handleKeyDown);
100
+ input.addEventListener('click', this.handleMathKeyboardClick);
101
+ }
102
+ };
103
+
104
+ removeEventListeners = () => {
105
+ const input = this.inputRef.current;
106
+
107
+ if (input) {
108
+ input.removeEventListener('keydown', this.handleKeyDown);
109
+ input.removeEventListener('click', this.handleMathKeyboardClick);
110
+ }
111
+ };
112
+
113
+ removeLiveRegion = () => {
114
+ if (this.liveRegion) {
115
+ document.body.removeChild(this.liveRegion);
116
+ this.liveRegion = null;
117
+ }
118
+ };
119
+
120
+ handleKeyDown = (event) => {
121
+ if (event?.key === 'Backspace' || event?.key === 'Delete') {
122
+ this.setState({ isDeleteKeyPressed: true });
123
+ }
124
+ this.setState({ inputSource: 'keyboard' });
125
+ };
126
+
127
+ handleMathKeyboardClick = () => {
128
+ this.setState({ inputSource: 'mathKeyboard' });
129
+ };
130
+
131
+ onInputEdit = (field) => {
50
132
  if (!this.mathField) {
51
133
  return;
52
134
  }
@@ -56,7 +138,7 @@ export default class Static extends React.Component {
56
138
  // eslint-disable-next-line no-useless-escape
57
139
  const regexMatch = field.latex().match(/[0-9]\\ \\frac\{[^\{]*\}\{ \}/);
58
140
 
59
- if (this.input && regexMatch && regexMatch?.length) {
141
+ if (this.inputRef?.current && regexMatch && regexMatch?.length) {
60
142
  try {
61
143
  field.__controller.cursor.insLeftOf(field.__controller.cursor.parent[-1].parent);
62
144
  field.el().dispatchEvent(new KeyboardEvent('keydown', { keyCode: 8 }));
@@ -68,15 +150,62 @@ export default class Static extends React.Component {
68
150
  this.props.onSubFieldChange(name, field.latex());
69
151
  }
70
152
  }
71
- }
72
153
 
73
- update() {
154
+ this.announceLatexConversion(field.latex());
155
+ };
156
+
157
+ announceLatexConversion = (newLatex) => {
158
+ if (!this.state) {
159
+ console.error('State is not initialized');
160
+ return;
161
+ }
162
+
163
+ const { previousLatex, inputSource, isDeleteKeyPressed } = this.state;
164
+ const announcement = 'Converted to math symbol';
165
+
166
+ if (inputSource === 'keyboard' && !isDeleteKeyPressed) {
167
+ const newBraces = countBraces(newLatex);
168
+ const oldBraces = countBraces(previousLatex);
169
+
170
+ if (newBraces > oldBraces) {
171
+ this.announceMessage(announcement);
172
+ } else {
173
+ try {
174
+ this.mathField.parseLatex(previousLatex);
175
+ this.mathField.parseLatex(newLatex);
176
+
177
+ if (newLatex == previousLatex) {
178
+ this.announceMessage(announcement);
179
+ }
180
+ } catch (e) {
181
+ console.warn('Error parsing latex:', e.message);
182
+ console.warn(e);
183
+ }
184
+ }
185
+ }
186
+
187
+ this.setState({ previousLatex: newLatex, isDeleteKeyPressed: false });
188
+ };
189
+
190
+ announceMessage = (message) => {
191
+ this.setState({ previousLatex: '' });
192
+
193
+ if (this.liveRegion) {
194
+ this.liveRegion.textContent = message;
195
+
196
+ // Clear the message after it is announced
197
+ setTimeout(() => {
198
+ this.liveRegion.textContent = '';
199
+ }, 500);
200
+ }
201
+ };
202
+
203
+ update = () => {
74
204
  if (!MQ) {
75
205
  throw new Error('MQ is not defined - but component has mounted?');
76
206
  }
77
- // this.input.innerHTML = this.props.latex;
78
207
  if (!this.mathField) {
79
- this.mathField = MQ.StaticMath(this.input, {
208
+ this.mathField = MQ.StaticMath(this.inputRef?.current, {
80
209
  handlers: {
81
210
  edit: this.onInputEdit.bind(this),
82
211
  },
@@ -90,17 +219,17 @@ export default class Static extends React.Component {
90
219
  // default latex if received has errors
91
220
  this.mathField.latex('\\MathQuillMathField[r1]{}');
92
221
  }
93
- }
222
+ };
94
223
 
95
- blur() {
224
+ blur = () => {
96
225
  log('blur mathfield');
97
226
  this.mathField.blur();
98
- }
227
+ };
99
228
 
100
- focus() {
229
+ focus = () => {
101
230
  log('focus mathfield...');
102
231
  this.mathField.focus();
103
- }
232
+ };
104
233
 
105
234
  shouldComponentUpdate(nextProps) {
106
235
  try {
@@ -151,6 +280,6 @@ export default class Static extends React.Component {
151
280
  render() {
152
281
  const { onBlur, className } = this.props;
153
282
 
154
- return <span className={className} onFocus={this.onFocus} onBlur={onBlur} ref={(r) => (this.input = r)} />;
283
+ return <span className={className} onFocus={this.onFocus} onBlur={onBlur} ref={this.inputRef} />;
155
284
  }
156
285
  }
@@ -0,0 +1,15 @@
1
+ // increase the font of parallel notation
2
+ const updateSpans = () => {
3
+ const spans = Array.from(document.querySelectorAll('span[mathquill-command-id]'));
4
+ (spans || []).forEach((span) => {
5
+ if (span && span.innerText === '∥' && span.className !== 'mq-editable-field') {
6
+ span.style.fontSize = '32px';
7
+ }
8
+
9
+ if ((span.innerText === '′' || span.innerText === '′′') && !span.hasAttribute('data-prime')) {
10
+ span.setAttribute('data-prime', 'true');
11
+ }
12
+ });
13
+ };
14
+
15
+ export { updateSpans };
package/README.md DELETED
@@ -1,27 +0,0 @@
1
- # math-input
2
-
3
- A [React](http://github.com/facebook/react) math input field, with a material design feel. Uses [Mathquill](http://mathquill.com/).
4
-
5
- ## install
6
-
7
- ```bash
8
- npm|yarn install
9
- ```
10
-
11
- ## demo
12
- ```bash
13
-
14
- cd demo
15
- ../node_modules/.bin/webpack-dev-server --hot --inline
16
- ```
17
-
18
- ## test
19
-
20
- ```bash
21
- npm|yarn test
22
- ```
23
-
24
-
25
- ## Using in another app
26
-
27
- We expose the jsx directly, so you'll need to update your build pipeline to build from src.