@pie-lib/math-input 8.1.1-next.2 → 8.1.1-next.57
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 +17 -0
- package/CHANGELOG.md +1172 -0
- package/LICENSE.md +5 -0
- package/lib/horizontal-keypad.js +96 -0
- package/lib/horizontal-keypad.js.map +1 -0
- package/lib/index.js +69 -0
- package/lib/index.js.map +1 -0
- package/lib/keypad/index.js +413 -0
- package/lib/keypad/index.js.map +1 -0
- package/lib/keypad/keys-layout.js +22 -0
- package/lib/keypad/keys-layout.js.map +1 -0
- package/lib/keys/basic-operators.js +33 -0
- package/lib/keys/basic-operators.js.map +1 -0
- package/lib/keys/chars.js +12 -0
- package/lib/keys/chars.js.map +1 -0
- package/lib/keys/comparison.js +39 -0
- package/lib/keys/comparison.js.map +1 -0
- package/lib/keys/constants.js +37 -0
- package/lib/keys/constants.js.map +1 -0
- package/lib/keys/digits.js +46 -0
- package/lib/keys/digits.js.map +1 -0
- package/lib/keys/edit.js +14 -0
- package/lib/keys/edit.js.map +1 -0
- package/lib/keys/exponent.js +30 -0
- package/lib/keys/exponent.js.map +1 -0
- package/lib/keys/fractions.js +29 -0
- package/lib/keys/fractions.js.map +1 -0
- package/lib/keys/geometry.js +140 -0
- package/lib/keys/geometry.js.map +1 -0
- package/lib/keys/grades.js +259 -0
- package/lib/keys/grades.js.map +1 -0
- package/lib/keys/index.js +35 -0
- package/lib/keys/index.js.map +1 -0
- package/lib/keys/log.js +27 -0
- package/lib/keys/log.js.map +1 -0
- package/lib/keys/logic.js +19 -0
- package/lib/keys/logic.js.map +1 -0
- package/lib/keys/matrices.js +19 -0
- package/lib/keys/matrices.js.map +1 -0
- package/lib/keys/misc.js +62 -0
- package/lib/keys/misc.js.map +1 -0
- package/lib/keys/navigation.js +20 -0
- package/lib/keys/navigation.js.map +1 -0
- package/lib/keys/operators.js +15 -0
- package/lib/keys/operators.js.map +1 -0
- package/lib/keys/statistics.js +40 -0
- package/lib/keys/statistics.js.map +1 -0
- package/lib/keys/sub-sup.js +19 -0
- package/lib/keys/sub-sup.js.map +1 -0
- package/lib/keys/trigonometry.js +45 -0
- package/lib/keys/trigonometry.js.map +1 -0
- package/lib/keys/utils.js +87 -0
- package/lib/keys/utils.js.map +1 -0
- package/lib/keys/vars.js +24 -0
- package/lib/keys/vars.js.map +1 -0
- package/lib/math-input.js +141 -0
- package/lib/math-input.js.map +1 -0
- package/lib/mq/common-mq-styles.js +102 -0
- package/lib/mq/common-mq-styles.js.map +1 -0
- package/lib/mq/custom-elements.js +20 -0
- package/lib/mq/custom-elements.js.map +1 -0
- package/lib/mq/index.js +28 -0
- package/lib/mq/index.js.map +1 -0
- package/lib/mq/input.js +186 -0
- package/lib/mq/input.js.map +1 -0
- package/lib/mq/mathquill-instance.js +52 -0
- package/lib/mq/mathquill-instance.js.map +1 -0
- package/lib/mq/static.js +301 -0
- package/lib/mq/static.js.map +1 -0
- package/lib/updateSpans.js +19 -0
- package/lib/updateSpans.js.map +1 -0
- package/package.json +18 -33
- package/src/__tests__/horizontal-keypad.test.jsx +463 -0
- package/src/__tests__/index.test.js +247 -0
- package/src/__tests__/math-input-test.jsx +45 -0
- package/src/__tests__/updateSpans.test.js +297 -0
- package/src/horizontal-keypad.jsx +69 -0
- package/src/index.jsx +28 -0
- package/src/keypad/__tests__/index.test.jsx +25 -0
- package/src/keypad/__tests__/keys-layout.test.js +14 -0
- package/src/keypad/index.jsx +439 -0
- package/src/keypad/keys-layout.js +16 -0
- package/src/keys/__tests__/utils.test.js +57 -0
- package/src/keys/basic-operators.js +32 -0
- package/src/keys/chars.js +5 -0
- package/src/keys/comparison.js +28 -0
- package/src/keys/constants.js +35 -0
- package/src/keys/digits.js +40 -0
- package/src/keys/edit.js +3 -0
- package/src/keys/exponent.js +28 -0
- package/src/keys/fractions.js +26 -0
- package/src/keys/geometry.js +144 -0
- package/src/keys/grades.js +367 -0
- package/src/keys/index.js +20 -0
- package/src/keys/log.js +22 -0
- package/src/keys/logic.js +15 -0
- package/src/keys/matrices.js +15 -0
- package/src/keys/misc.js +65 -0
- package/src/keys/navigation.js +8 -0
- package/src/keys/operators.js +10 -0
- package/src/keys/statistics.js +38 -0
- package/src/keys/sub-sup.js +15 -0
- package/src/keys/trigonometry.js +15 -0
- package/src/keys/utils.js +66 -0
- package/src/keys/vars.js +19 -0
- package/src/math-input.jsx +119 -0
- package/src/mq/__tests__/custom-elements.test.js +342 -0
- package/src/mq/__tests__/input.test.jsx +40 -0
- package/src/mq/__tests__/mathquill-instance.test.js +67 -0
- package/src/mq/__tests__/static.test.jsx +33 -0
- package/src/mq/common-mq-styles.js +109 -0
- package/src/mq/custom-elements.js +11 -0
- package/src/mq/index.js +5 -0
- package/src/mq/input.jsx +166 -0
- package/src/mq/mathquill-instance.js +45 -0
- package/src/mq/static.jsx +290 -0
- package/src/updateSpans.js +15 -0
- package/dist/_virtual/_rolldown/runtime.js +0 -11
- package/dist/horizontal-keypad.d.ts +0 -31
- package/dist/horizontal-keypad.js +0 -57
- package/dist/index.d.ts +0 -18
- package/dist/index.js +0 -19
- package/dist/keypad/accessible-keypad.d.ts +0 -37
- package/dist/keypad/accessible-keypad.js +0 -614
- package/dist/keypad/index.d.ts +0 -2
- package/dist/keypad/keys-layout.d.ts +0 -15
- package/dist/keypad/keys-layout.js +0 -5
- package/dist/keypad/model.d.ts +0 -28
- package/dist/keypad/model.js +0 -4
- package/dist/keys/basic-operators.d.ts +0 -13
- package/dist/keys/basic-operators.js +0 -30
- package/dist/keys/chars.d.ts +0 -13
- package/dist/keys/comparison.d.ts +0 -12
- package/dist/keys/comparison.js +0 -32
- package/dist/keys/constants.d.ts +0 -12
- package/dist/keys/constants.js +0 -35
- package/dist/keys/digits.d.ts +0 -23
- package/dist/keys/digits.js +0 -34
- package/dist/keys/edit.d.ts +0 -14
- package/dist/keys/edit.js +0 -9
- package/dist/keys/exponent.d.ts +0 -12
- package/dist/keys/exponent.js +0 -28
- package/dist/keys/fractions.d.ts +0 -11
- package/dist/keys/fractions.js +0 -27
- package/dist/keys/geometry.d.ts +0 -31
- package/dist/keys/geometry.js +0 -127
- package/dist/keys/grades.d.ts +0 -17
- package/dist/keys/grades.js +0 -414
- package/dist/keys/index.d.ts +0 -14
- package/dist/keys/index.js +0 -50
- package/dist/keys/log.d.ts +0 -11
- package/dist/keys/log.js +0 -25
- package/dist/keys/logic.d.ts +0 -10
- package/dist/keys/logic.js +0 -13
- package/dist/keys/matrices.d.ts +0 -10
- package/dist/keys/matrices.js +0 -17
- package/dist/keys/misc.d.ts +0 -18
- package/dist/keys/misc.js +0 -60
- package/dist/keys/navigation.d.ts +0 -10
- package/dist/keys/navigation.js +0 -13
- package/dist/keys/operators.d.ts +0 -9
- package/dist/keys/operators.js +0 -11
- package/dist/keys/statistics.d.ts +0 -13
- package/dist/keys/statistics.js +0 -38
- package/dist/keys/sub-sup.d.ts +0 -10
- package/dist/keys/sub-sup.js +0 -17
- package/dist/keys/trigonometry.d.ts +0 -14
- package/dist/keys/trigonometry.js +0 -43
- package/dist/keys/utils.d.ts +0 -13
- package/dist/keys/utils.js +0 -24
- package/dist/keys/vars.d.ts +0 -11
- package/dist/keys/vars.js +0 -22
- package/dist/math-input.d.ts +0 -30
- package/dist/mq/common-mq-styles.d.ts +0 -225
- package/dist/mq/common-mq-styles.js +0 -54
- package/dist/mq/custom-elements.d.ts +0 -10
- package/dist/mq/custom-elements.js +0 -10
- package/dist/mq/index.d.ts +0 -12
- package/dist/mq/index.js +0 -12
- package/dist/mq/input.d.ts +0 -35
- package/dist/mq/input.js +0 -83
- package/dist/mq/static.d.ts +0 -43
- package/dist/mq/static.js +0 -142
- package/dist/updateSpans.d.ts +0 -10
- package/dist/updateSpans.js +0 -9
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { addBrackets, removeBrackets, registerEmbed, applyStaticMath } from '../index';
|
|
2
|
+
|
|
3
|
+
describe('math-input index', () => {
|
|
4
|
+
it('exports registerEmbed and applyStaticMath', () => {
|
|
5
|
+
expect(typeof registerEmbed).toBe('function');
|
|
6
|
+
expect(typeof applyStaticMath).toBe('function');
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
describe('addBrackets', () => {
|
|
10
|
+
it('should add both brackets to a plain string', () => {
|
|
11
|
+
expect(addBrackets('x^2')).toBe('\\(x^2\\)');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should not add left bracket if already present', () => {
|
|
15
|
+
expect(addBrackets('\\(x^2')).toBe('\\(x^2\\)');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should not add right bracket if already present', () => {
|
|
19
|
+
expect(addBrackets('x^2\\)')).toBe('\\(x^2\\)');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should not add brackets if both are already present', () => {
|
|
23
|
+
expect(addBrackets('\\(x^2\\)')).toBe('\\(x^2\\)');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should handle empty string', () => {
|
|
27
|
+
expect(addBrackets('')).toBe('\\(\\)');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should handle complex latex expressions', () => {
|
|
31
|
+
expect(addBrackets('\\frac{1}{2}')).toBe('\\(\\frac{1}{2}\\)');
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('should handle expressions with parentheses', () => {
|
|
35
|
+
expect(addBrackets('(x+y)')).toBe('\\((x+y)\\)');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should not confuse regular parentheses with latex brackets', () => {
|
|
39
|
+
expect(addBrackets('(x)')).toBe('\\((x)\\)');
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should handle expressions with backslashes', () => {
|
|
43
|
+
expect(addBrackets('\\sin(x)')).toBe('\\(\\sin(x)\\)');
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe('removeBrackets', () => {
|
|
48
|
+
it('should remove both brackets from a bracketed string', () => {
|
|
49
|
+
expect(removeBrackets('\\(x^2\\)')).toBe('x^2');
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should not remove left bracket if not present', () => {
|
|
53
|
+
expect(removeBrackets('x^2\\)')).toBe('x^2');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should not remove right bracket if not present', () => {
|
|
57
|
+
expect(removeBrackets('\\(x^2')).toBe('x^2');
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should not remove brackets if none are present', () => {
|
|
61
|
+
expect(removeBrackets('x^2')).toBe('x^2');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should handle empty bracketed string', () => {
|
|
65
|
+
expect(removeBrackets('\\(\\)')).toBe('');
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should handle complex latex expressions', () => {
|
|
69
|
+
expect(removeBrackets('\\(\\frac{1}{2}\\)')).toBe('\\frac{1}{2}');
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it('should handle expressions with parentheses', () => {
|
|
73
|
+
expect(removeBrackets('\\((x+y)\\)')).toBe('(x+y)');
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
it('should only remove latex brackets, not regular parentheses', () => {
|
|
77
|
+
expect(removeBrackets('\\((x)\\)')).toBe('(x)');
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should handle nested latex commands', () => {
|
|
81
|
+
expect(removeBrackets('\\(\\sqrt{x^2+y^2}\\)')).toBe('\\sqrt{x^2+y^2}');
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
it('should handle multiple backslashes', () => {
|
|
85
|
+
expect(removeBrackets('\\(\\\\text{hello}\\)')).toBe('\\\\text{hello}');
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
describe('addBrackets and removeBrackets symmetry', () => {
|
|
90
|
+
it('should be inverse operations for plain strings', () => {
|
|
91
|
+
const original = 'x^2+y^2';
|
|
92
|
+
expect(removeBrackets(addBrackets(original))).toBe(original);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('should be inverse operations for latex expressions', () => {
|
|
96
|
+
const original = '\\frac{a}{b}';
|
|
97
|
+
expect(removeBrackets(addBrackets(original))).toBe(original);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('should be inverse operations for complex expressions', () => {
|
|
101
|
+
const original = '\\sqrt{\\frac{x^2+y^2}{z}}';
|
|
102
|
+
expect(removeBrackets(addBrackets(original))).toBe(original);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should handle idempotency - adding brackets twice', () => {
|
|
106
|
+
const original = 'x+y';
|
|
107
|
+
const once = addBrackets(original);
|
|
108
|
+
const twice = addBrackets(once);
|
|
109
|
+
expect(once).toBe(twice);
|
|
110
|
+
expect(once).toBe('\\(x+y\\)');
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('should handle idempotency - removing brackets twice', () => {
|
|
114
|
+
const original = '\\(x+y\\)';
|
|
115
|
+
const once = removeBrackets(original);
|
|
116
|
+
const twice = removeBrackets(once);
|
|
117
|
+
expect(once).toBe(twice);
|
|
118
|
+
expect(once).toBe('x+y');
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe('edge cases', () => {
|
|
123
|
+
describe('addBrackets edge cases', () => {
|
|
124
|
+
it('should handle string with only left bracket', () => {
|
|
125
|
+
expect(addBrackets('\\(')).toBe('\\(\\)');
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should handle string with only right bracket', () => {
|
|
129
|
+
expect(addBrackets('\\)')).toBe('\\(\\)');
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('should handle string that starts with \\( in the middle', () => {
|
|
133
|
+
expect(addBrackets('x\\(y')).toBe('\\(x\\(y\\)');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should handle string that ends with \\) in the middle', () => {
|
|
137
|
+
expect(addBrackets('x\\)y')).toBe('\\(x\\)y\\)');
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('should handle very long latex expressions', () => {
|
|
141
|
+
const long = '\\frac{1}{2}+\\frac{3}{4}+\\frac{5}{6}+\\frac{7}{8}';
|
|
142
|
+
expect(addBrackets(long)).toBe(`\\(${long}\\)`);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
describe('removeBrackets edge cases', () => {
|
|
147
|
+
it('should handle string with only left bracket', () => {
|
|
148
|
+
expect(removeBrackets('\\(')).toBe('');
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it('should handle string with only right bracket', () => {
|
|
152
|
+
expect(removeBrackets('\\)')).toBe('');
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should not remove brackets in the middle of string', () => {
|
|
156
|
+
expect(removeBrackets('x\\(middle\\)y')).toBe('x\\(middle\\)y');
|
|
157
|
+
});
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe('special characters and unicode', () => {
|
|
162
|
+
it('should handle expressions with special math symbols', () => {
|
|
163
|
+
expect(addBrackets('π')).toBe('\\(π\\)');
|
|
164
|
+
expect(removeBrackets('\\(π\\)')).toBe('π');
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('should handle expressions with greek letters', () => {
|
|
168
|
+
expect(addBrackets('\\alpha+\\beta')).toBe('\\(\\alpha+\\beta\\)');
|
|
169
|
+
expect(removeBrackets('\\(\\alpha+\\beta\\)')).toBe('\\alpha+\\beta');
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should handle expressions with subscripts and superscripts', () => {
|
|
173
|
+
expect(addBrackets('x_1^2')).toBe('\\(x_1^2\\)');
|
|
174
|
+
expect(removeBrackets('\\(x_1^2\\)')).toBe('x_1^2');
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
describe('whitespace handling', () => {
|
|
179
|
+
it('should preserve whitespace in addBrackets', () => {
|
|
180
|
+
expect(addBrackets(' x + y ')).toBe('\\( x + y \\)');
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('should preserve whitespace in removeBrackets', () => {
|
|
184
|
+
expect(removeBrackets('\\( x + y \\)')).toBe(' x + y ');
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('should handle strings with only whitespace', () => {
|
|
188
|
+
expect(addBrackets(' ')).toBe('\\( \\)');
|
|
189
|
+
expect(removeBrackets('\\( \\)')).toBe(' ');
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('should handle newlines', () => {
|
|
193
|
+
expect(addBrackets('x\ny')).toBe('\\(x\ny\\)');
|
|
194
|
+
expect(removeBrackets('\\(x\ny\\)')).toBe('x\ny');
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('should handle tabs', () => {
|
|
198
|
+
expect(addBrackets('x\ty')).toBe('\\(x\ty\\)');
|
|
199
|
+
expect(removeBrackets('\\(x\ty\\)')).toBe('x\ty');
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
describe('real-world latex examples', () => {
|
|
204
|
+
const examples = [
|
|
205
|
+
'\\frac{-b\\pm\\sqrt{b^2-4ac}}{2a}',
|
|
206
|
+
'\\int_{0}^{\\infty} e^{-x^2} dx',
|
|
207
|
+
'\\sum_{n=1}^{\\infty} \\frac{1}{n^2}',
|
|
208
|
+
'\\lim_{x\\to\\infty} \\frac{1}{x}',
|
|
209
|
+
'\\begin{matrix}a&b\\\\c&d\\end{matrix}',
|
|
210
|
+
'\\sqrt[3]{x^3+y^3}',
|
|
211
|
+
'f(x)=\\begin{cases}x^2&x\\geq0\\\\-x^2&x<0\\end{cases}',
|
|
212
|
+
];
|
|
213
|
+
|
|
214
|
+
examples.forEach((latex, index) => {
|
|
215
|
+
it(`should handle complex latex example ${index + 1}`, () => {
|
|
216
|
+
const withBrackets = addBrackets(latex);
|
|
217
|
+
expect(withBrackets).toBe(`\\(${latex}\\)`);
|
|
218
|
+
expect(removeBrackets(withBrackets)).toBe(latex);
|
|
219
|
+
});
|
|
220
|
+
});
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
describe('boundary conditions', () => {
|
|
224
|
+
it('should handle very short strings', () => {
|
|
225
|
+
expect(addBrackets('x')).toBe('\\(x\\)');
|
|
226
|
+
expect(removeBrackets('\\(x\\)')).toBe('x');
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
it('should handle single character', () => {
|
|
230
|
+
expect(addBrackets('a')).toBe('\\(a\\)');
|
|
231
|
+
expect(removeBrackets('\\(a\\)')).toBe('a');
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('should handle string that is exactly "\\(\\)"', () => {
|
|
235
|
+
expect(addBrackets('\\(\\)')).toBe('\\(\\)');
|
|
236
|
+
expect(removeBrackets('\\(\\)')).toBe('');
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it('should handle string with length exactly 2', () => {
|
|
240
|
+
expect(addBrackets('xy')).toBe('\\(xy\\)');
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it('should handle string with length exactly 3', () => {
|
|
244
|
+
expect(addBrackets('xyz')).toBe('\\(xyz\\)');
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
});
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
import { render } from '@testing-library/react';
|
|
3
|
+
import { MathInput } from '../math-input';
|
|
4
|
+
|
|
5
|
+
describe('MathInput', () => {
|
|
6
|
+
const onChange = jest.fn();
|
|
7
|
+
const defaultProps = {
|
|
8
|
+
classes: {},
|
|
9
|
+
className: 'className',
|
|
10
|
+
onChange,
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
onChange.mockClear();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('rendering', () => {
|
|
18
|
+
it('renders with default props', () => {
|
|
19
|
+
const { container } = render(<MathInput {...defaultProps} />);
|
|
20
|
+
expect(container.firstChild).toBeInTheDocument();
|
|
21
|
+
expect(container.firstChild).toHaveClass('className');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('renders with latex prop', () => {
|
|
25
|
+
const { container } = render(<MathInput {...defaultProps} latex="x^2" />);
|
|
26
|
+
expect(container.firstChild).toBeInTheDocument();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('renders with keypadMode', () => {
|
|
30
|
+
const { container } = render(<MathInput {...defaultProps} keypadMode="scientific" />);
|
|
31
|
+
expect(container.firstChild).toBeInTheDocument();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('renders with disabled prop', () => {
|
|
35
|
+
const { container } = render(<MathInput {...defaultProps} disabled={true} />);
|
|
36
|
+
expect(container.firstChild).toBeInTheDocument();
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Note: Tests for internal methods (keypadPress, changeLatex, inputFocus, inputBlur)
|
|
41
|
+
// are implementation details and cannot be directly tested with RTL.
|
|
42
|
+
// These components are wrappers around MathQuill library and the original tests
|
|
43
|
+
// focused on testing internal implementation via instance methods rather than user-facing behavior.
|
|
44
|
+
// The actual MathQuill integration and user interactions are tested through integration/e2e tests.
|
|
45
|
+
});
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import { updateSpans } from '../updateSpans';
|
|
2
|
+
|
|
3
|
+
describe('updateSpans', () => {
|
|
4
|
+
beforeEach(() => {
|
|
5
|
+
document.body.innerHTML = '';
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
afterEach(() => {
|
|
9
|
+
document.body.innerHTML = '';
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
describe('prime notation (′ and ′′)', () => {
|
|
13
|
+
it('should add data-prime attribute to single prime', () => {
|
|
14
|
+
const span = document.createElement('span');
|
|
15
|
+
span.setAttribute('mathquill-command-id', '1');
|
|
16
|
+
span.innerText = '′';
|
|
17
|
+
document.body.appendChild(span);
|
|
18
|
+
|
|
19
|
+
updateSpans();
|
|
20
|
+
|
|
21
|
+
expect(span.getAttribute('data-prime')).toBe('true');
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should add data-prime attribute to double prime', () => {
|
|
25
|
+
const span = document.createElement('span');
|
|
26
|
+
span.setAttribute('mathquill-command-id', '1');
|
|
27
|
+
span.innerText = '′′';
|
|
28
|
+
document.body.appendChild(span);
|
|
29
|
+
|
|
30
|
+
updateSpans();
|
|
31
|
+
|
|
32
|
+
expect(span.getAttribute('data-prime')).toBe('true');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('should not add data-prime if already present', () => {
|
|
36
|
+
const span = document.createElement('span');
|
|
37
|
+
span.setAttribute('mathquill-command-id', '1');
|
|
38
|
+
span.innerText = '′';
|
|
39
|
+
span.setAttribute('data-prime', 'true');
|
|
40
|
+
document.body.appendChild(span);
|
|
41
|
+
|
|
42
|
+
updateSpans();
|
|
43
|
+
|
|
44
|
+
expect(span.getAttribute('data-prime')).toBe('true');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('should handle multiple prime notation spans', () => {
|
|
48
|
+
const span1 = document.createElement('span');
|
|
49
|
+
span1.setAttribute('mathquill-command-id', '1');
|
|
50
|
+
span1.innerText = '′';
|
|
51
|
+
document.body.appendChild(span1);
|
|
52
|
+
|
|
53
|
+
const span2 = document.createElement('span');
|
|
54
|
+
span2.setAttribute('mathquill-command-id', '2');
|
|
55
|
+
span2.innerText = '′′';
|
|
56
|
+
document.body.appendChild(span2);
|
|
57
|
+
|
|
58
|
+
updateSpans();
|
|
59
|
+
|
|
60
|
+
expect(span1.getAttribute('data-prime')).toBe('true');
|
|
61
|
+
expect(span2.getAttribute('data-prime')).toBe('true');
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
describe('combined scenarios', () => {
|
|
66
|
+
it('should handle both parallel and prime notation in same document', () => {
|
|
67
|
+
const parallelSpan = document.createElement('span');
|
|
68
|
+
parallelSpan.setAttribute('mathquill-command-id', '1');
|
|
69
|
+
parallelSpan.innerText = '∥';
|
|
70
|
+
document.body.appendChild(parallelSpan);
|
|
71
|
+
|
|
72
|
+
const primeSpan = document.createElement('span');
|
|
73
|
+
primeSpan.setAttribute('mathquill-command-id', '2');
|
|
74
|
+
primeSpan.innerText = '′';
|
|
75
|
+
document.body.appendChild(primeSpan);
|
|
76
|
+
|
|
77
|
+
updateSpans();
|
|
78
|
+
|
|
79
|
+
expect(parallelSpan.style.fontSize).toBe('32px');
|
|
80
|
+
expect(primeSpan.getAttribute('data-prime')).toBe('true');
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should handle complex document with multiple span types', () => {
|
|
84
|
+
const parallelSpan = document.createElement('span');
|
|
85
|
+
parallelSpan.setAttribute('mathquill-command-id', '1');
|
|
86
|
+
parallelSpan.innerText = '∥';
|
|
87
|
+
document.body.appendChild(parallelSpan);
|
|
88
|
+
|
|
89
|
+
const primeSpan = document.createElement('span');
|
|
90
|
+
primeSpan.setAttribute('mathquill-command-id', '2');
|
|
91
|
+
primeSpan.innerText = '′';
|
|
92
|
+
document.body.appendChild(primeSpan);
|
|
93
|
+
|
|
94
|
+
const normalSpan = document.createElement('span');
|
|
95
|
+
normalSpan.setAttribute('mathquill-command-id', '3');
|
|
96
|
+
normalSpan.innerText = 'x';
|
|
97
|
+
document.body.appendChild(normalSpan);
|
|
98
|
+
|
|
99
|
+
const editableParallel = document.createElement('span');
|
|
100
|
+
editableParallel.setAttribute('mathquill-command-id', '4');
|
|
101
|
+
editableParallel.innerText = '∥';
|
|
102
|
+
editableParallel.className = 'mq-editable-field';
|
|
103
|
+
document.body.appendChild(editableParallel);
|
|
104
|
+
|
|
105
|
+
updateSpans();
|
|
106
|
+
|
|
107
|
+
expect(parallelSpan.style.fontSize).toBe('32px');
|
|
108
|
+
expect(primeSpan.getAttribute('data-prime')).toBe('true');
|
|
109
|
+
expect(normalSpan.style.fontSize).toBe('');
|
|
110
|
+
expect(normalSpan.getAttribute('data-prime')).toBeNull();
|
|
111
|
+
expect(editableParallel.style.fontSize).toBe('');
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
describe('edge cases', () => {
|
|
116
|
+
it('should handle empty document', () => {
|
|
117
|
+
expect(() => updateSpans()).not.toThrow();
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('should handle document with no mathquill spans', () => {
|
|
121
|
+
const span = document.createElement('span');
|
|
122
|
+
span.innerText = '∥';
|
|
123
|
+
document.body.appendChild(span);
|
|
124
|
+
|
|
125
|
+
expect(() => updateSpans()).not.toThrow();
|
|
126
|
+
expect(span.style.fontSize).toBe('');
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it('should handle spans with empty innerText', () => {
|
|
130
|
+
const span = document.createElement('span');
|
|
131
|
+
span.setAttribute('mathquill-command-id', '1');
|
|
132
|
+
span.innerText = '';
|
|
133
|
+
document.body.appendChild(span);
|
|
134
|
+
|
|
135
|
+
expect(() => updateSpans()).not.toThrow();
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
it('should handle spans with whitespace', () => {
|
|
139
|
+
const span = document.createElement('span');
|
|
140
|
+
span.setAttribute('mathquill-command-id', '1');
|
|
141
|
+
span.innerText = ' ';
|
|
142
|
+
document.body.appendChild(span);
|
|
143
|
+
|
|
144
|
+
expect(() => updateSpans()).not.toThrow();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('should handle null or undefined spans gracefully', () => {
|
|
148
|
+
const span = document.createElement('span');
|
|
149
|
+
span.setAttribute('mathquill-command-id', '1');
|
|
150
|
+
span.innerText = '∥';
|
|
151
|
+
document.body.appendChild(span);
|
|
152
|
+
|
|
153
|
+
expect(() => updateSpans()).not.toThrow();
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
describe('idempotency', () => {
|
|
158
|
+
it('should be safe to call multiple times on parallel notation', () => {
|
|
159
|
+
const span = document.createElement('span');
|
|
160
|
+
span.setAttribute('mathquill-command-id', '1');
|
|
161
|
+
span.innerText = '∥';
|
|
162
|
+
document.body.appendChild(span);
|
|
163
|
+
|
|
164
|
+
updateSpans();
|
|
165
|
+
const fontSize1 = span.style.fontSize;
|
|
166
|
+
|
|
167
|
+
updateSpans();
|
|
168
|
+
const fontSize2 = span.style.fontSize;
|
|
169
|
+
|
|
170
|
+
updateSpans();
|
|
171
|
+
const fontSize3 = span.style.fontSize;
|
|
172
|
+
|
|
173
|
+
expect(fontSize1).toBe('32px');
|
|
174
|
+
expect(fontSize2).toBe('32px');
|
|
175
|
+
expect(fontSize3).toBe('32px');
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('should be safe to call multiple times on prime notation', () => {
|
|
179
|
+
const span = document.createElement('span');
|
|
180
|
+
span.setAttribute('mathquill-command-id', '1');
|
|
181
|
+
span.innerText = '′';
|
|
182
|
+
document.body.appendChild(span);
|
|
183
|
+
|
|
184
|
+
updateSpans();
|
|
185
|
+
expect(span.getAttribute('data-prime')).toBe('true');
|
|
186
|
+
|
|
187
|
+
updateSpans();
|
|
188
|
+
expect(span.getAttribute('data-prime')).toBe('true');
|
|
189
|
+
|
|
190
|
+
updateSpans();
|
|
191
|
+
expect(span.getAttribute('data-prime')).toBe('true');
|
|
192
|
+
});
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
describe('className variations', () => {
|
|
196
|
+
it('should modify parallel notation with classes other than mq-editable-field', () => {
|
|
197
|
+
const span = document.createElement('span');
|
|
198
|
+
span.setAttribute('mathquill-command-id', '1');
|
|
199
|
+
span.innerText = '∥';
|
|
200
|
+
span.className = 'some-other-class';
|
|
201
|
+
document.body.appendChild(span);
|
|
202
|
+
|
|
203
|
+
updateSpans();
|
|
204
|
+
|
|
205
|
+
expect(span.style.fontSize).toBe('32px');
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it('should modify parallel notation with no className', () => {
|
|
209
|
+
const span = document.createElement('span');
|
|
210
|
+
span.setAttribute('mathquill-command-id', '1');
|
|
211
|
+
span.innerText = '∥';
|
|
212
|
+
document.body.appendChild(span);
|
|
213
|
+
|
|
214
|
+
updateSpans();
|
|
215
|
+
|
|
216
|
+
expect(span.style.fontSize).toBe('32px');
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
describe('nested structures', () => {
|
|
221
|
+
it('should handle spans nested in other elements', () => {
|
|
222
|
+
const container = document.createElement('div');
|
|
223
|
+
const span = document.createElement('span');
|
|
224
|
+
span.setAttribute('mathquill-command-id', '1');
|
|
225
|
+
span.innerText = '∥';
|
|
226
|
+
container.appendChild(span);
|
|
227
|
+
document.body.appendChild(container);
|
|
228
|
+
|
|
229
|
+
updateSpans();
|
|
230
|
+
|
|
231
|
+
expect(span.style.fontSize).toBe('32px');
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('should handle deeply nested spans', () => {
|
|
235
|
+
const level1 = document.createElement('div');
|
|
236
|
+
const level2 = document.createElement('div');
|
|
237
|
+
const level3 = document.createElement('div');
|
|
238
|
+
const span = document.createElement('span');
|
|
239
|
+
span.setAttribute('mathquill-command-id', '1');
|
|
240
|
+
span.innerText = '′';
|
|
241
|
+
|
|
242
|
+
level3.appendChild(span);
|
|
243
|
+
level2.appendChild(level3);
|
|
244
|
+
level1.appendChild(level2);
|
|
245
|
+
document.body.appendChild(level1);
|
|
246
|
+
|
|
247
|
+
updateSpans();
|
|
248
|
+
|
|
249
|
+
expect(span.getAttribute('data-prime')).toBe('true');
|
|
250
|
+
});
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
describe('special characters', () => {
|
|
254
|
+
it('should only match exact parallel symbol', () => {
|
|
255
|
+
const symbols = ['||', '|', '‖', '∥∥', 'parallel'];
|
|
256
|
+
|
|
257
|
+
symbols.forEach((symbol, index) => {
|
|
258
|
+
const span = document.createElement('span');
|
|
259
|
+
span.setAttribute('mathquill-command-id', String(index));
|
|
260
|
+
span.innerText = symbol;
|
|
261
|
+
document.body.appendChild(span);
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
const parallelSpan = document.createElement('span');
|
|
265
|
+
parallelSpan.setAttribute('mathquill-command-id', 'correct');
|
|
266
|
+
parallelSpan.innerText = '∥';
|
|
267
|
+
document.body.appendChild(parallelSpan);
|
|
268
|
+
|
|
269
|
+
updateSpans();
|
|
270
|
+
|
|
271
|
+
expect(parallelSpan.style.fontSize).toBe('32px');
|
|
272
|
+
|
|
273
|
+
symbols.forEach((_, index) => {
|
|
274
|
+
const span = document.querySelector(`span[mathquill-command-id="${index}"]`);
|
|
275
|
+
expect(span.style.fontSize).toBe('');
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it('should only match exact prime symbols', () => {
|
|
280
|
+
const symbols = ["'", '"', '`', '´', 'prime'];
|
|
281
|
+
|
|
282
|
+
symbols.forEach((symbol, index) => {
|
|
283
|
+
const span = document.createElement('span');
|
|
284
|
+
span.setAttribute('mathquill-command-id', String(index));
|
|
285
|
+
span.innerText = symbol;
|
|
286
|
+
document.body.appendChild(span);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
updateSpans();
|
|
290
|
+
|
|
291
|
+
symbols.forEach((_, index) => {
|
|
292
|
+
const span = document.querySelector(`span[mathquill-command-id="${index}"]`);
|
|
293
|
+
expect(span.getAttribute('data-prime')).toBeNull();
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
});
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { keysForGrade, normalizeAdditionalKeys } from './keys/grades';
|
|
4
|
+
import { extendKeySet } from './keys/utils';
|
|
5
|
+
import Keypad from './keypad';
|
|
6
|
+
|
|
7
|
+
const toOldModel = (d) => {
|
|
8
|
+
if (d.command) {
|
|
9
|
+
return { value: d.command, type: 'command' };
|
|
10
|
+
} else if (d.write) {
|
|
11
|
+
return { value: d.write };
|
|
12
|
+
} else if (d.keystroke) {
|
|
13
|
+
return { type: 'cursor', value: d.keystroke };
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export default class HorizontalKeypad extends React.Component {
|
|
18
|
+
static propTypes = {
|
|
19
|
+
className: PropTypes.string,
|
|
20
|
+
controlledKeypadMode: PropTypes.bool,
|
|
21
|
+
mode: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
|
|
22
|
+
layoutForKeyPad: PropTypes.object,
|
|
23
|
+
onClick: PropTypes.func.isRequired,
|
|
24
|
+
onFocus: PropTypes.func,
|
|
25
|
+
noDecimal: PropTypes.bool,
|
|
26
|
+
additionalKeys: PropTypes.array,
|
|
27
|
+
setKeypadInteraction: PropTypes.func,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
static defaultProps = {
|
|
31
|
+
mode: 'scientific',
|
|
32
|
+
noDecimal: false,
|
|
33
|
+
additionalKeys: [],
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
keypadPress = (data) => {
|
|
37
|
+
const { onClick } = this.props;
|
|
38
|
+
|
|
39
|
+
onClick(toOldModel(data));
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
render() {
|
|
43
|
+
const {
|
|
44
|
+
mode,
|
|
45
|
+
onFocus,
|
|
46
|
+
controlledKeypadMode,
|
|
47
|
+
noDecimal,
|
|
48
|
+
className,
|
|
49
|
+
additionalKeys,
|
|
50
|
+
layoutForKeyPad,
|
|
51
|
+
setKeypadInteraction,
|
|
52
|
+
} = this.props;
|
|
53
|
+
const normalizedKeys = normalizeAdditionalKeys(additionalKeys);
|
|
54
|
+
|
|
55
|
+
return (
|
|
56
|
+
<Keypad
|
|
57
|
+
className={className}
|
|
58
|
+
controlledKeypadMode={controlledKeypadMode}
|
|
59
|
+
onFocus={onFocus}
|
|
60
|
+
noDecimal={noDecimal}
|
|
61
|
+
layoutForKeyPad={layoutForKeyPad}
|
|
62
|
+
additionalKeys={extendKeySet(keysForGrade(mode), normalizedKeys)}
|
|
63
|
+
onPress={this.keypadPress}
|
|
64
|
+
mode={mode}
|
|
65
|
+
setKeypadInteraction={setKeypadInteraction}
|
|
66
|
+
/>
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
}
|
package/src/index.jsx
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { keysForGrade } from './keys/grades';
|
|
2
|
+
import { updateSpans } from './updateSpans';
|
|
3
|
+
import * as keys from './keys';
|
|
4
|
+
|
|
5
|
+
import HorizontalKeypad from './horizontal-keypad';
|
|
6
|
+
|
|
7
|
+
import * as mq from './mq';
|
|
8
|
+
import { registerEmbed, applyStaticMath } from './mq/mathquill-instance';
|
|
9
|
+
|
|
10
|
+
const addLeftBracket = (s) => (s.indexOf('\\(') === 0 ? s : `\\(${s}`);
|
|
11
|
+
const addRightBracket = (s) => (s.indexOf('\\)') === s.length - 2 ? s : `${s}\\)`);
|
|
12
|
+
const rmLeftBracket = (s) => (s.indexOf('\\(') === 0 ? s.substring(2) : s);
|
|
13
|
+
const rmRightBracket = (s) => (s.indexOf('\\)') === s.length - 2 ? s.substring(0, s.length - 2) : s);
|
|
14
|
+
|
|
15
|
+
const addBrackets = (s) => addRightBracket(addLeftBracket(s));
|
|
16
|
+
const removeBrackets = (s) => rmRightBracket(rmLeftBracket(s));
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
keysForGrade,
|
|
20
|
+
addBrackets,
|
|
21
|
+
removeBrackets,
|
|
22
|
+
keys,
|
|
23
|
+
HorizontalKeypad,
|
|
24
|
+
mq,
|
|
25
|
+
updateSpans,
|
|
26
|
+
registerEmbed,
|
|
27
|
+
applyStaticMath,
|
|
28
|
+
};
|