@khanacademy/math-input 0.7.0 → 0.7.2
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.md +13 -0
- package/dist/components/keypad/button.d.ts +1 -2
- package/dist/components/keypad/button.js.flow +1 -2
- package/dist/components/keypad/keypad-page-items.d.ts +1 -2
- package/dist/components/keypad/keypad-page-items.js.flow +1 -2
- package/dist/es/index.js +1046 -955
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/components/gesture-state-machine.js +1 -1
- package/src/components/keypad/button.tsx +1 -3
- package/src/components/keypad/keypad-page-items.tsx +1 -3
- package/src/fake-react-native-web/view.tsx +0 -1
- package/tsconfig.tsbuildinfo +1 -1
- /package/dist/{strings → strings.js} +0 -0
package/dist/es/index.js
CHANGED
|
@@ -16,96 +16,23 @@ import { View as View$1 } from '@khanacademy/wonder-blocks-core';
|
|
|
16
16
|
import Clickable from '@khanacademy/wonder-blocks-clickable';
|
|
17
17
|
import now from 'performance-now';
|
|
18
18
|
|
|
19
|
-
function ownKeys(object, enumerableOnly) {
|
|
20
|
-
var keys = Object.keys(object);
|
|
21
|
-
if (Object.getOwnPropertySymbols) {
|
|
22
|
-
var symbols = Object.getOwnPropertySymbols(object);
|
|
23
|
-
enumerableOnly && (symbols = symbols.filter(function (sym) {
|
|
24
|
-
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
|
25
|
-
})), keys.push.apply(keys, symbols);
|
|
26
|
-
}
|
|
27
|
-
return keys;
|
|
28
|
-
}
|
|
29
|
-
function _objectSpread2(target) {
|
|
30
|
-
for (var i = 1; i < arguments.length; i++) {
|
|
31
|
-
var source = null != arguments[i] ? arguments[i] : {};
|
|
32
|
-
i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
|
|
33
|
-
_defineProperty(target, key, source[key]);
|
|
34
|
-
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
|
|
35
|
-
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
|
36
|
-
});
|
|
37
|
-
}
|
|
38
|
-
return target;
|
|
39
|
-
}
|
|
40
|
-
function _defineProperty(obj, key, value) {
|
|
41
|
-
key = _toPropertyKey(key);
|
|
42
|
-
if (key in obj) {
|
|
43
|
-
Object.defineProperty(obj, key, {
|
|
44
|
-
value: value,
|
|
45
|
-
enumerable: true,
|
|
46
|
-
configurable: true,
|
|
47
|
-
writable: true
|
|
48
|
-
});
|
|
49
|
-
} else {
|
|
50
|
-
obj[key] = value;
|
|
51
|
-
}
|
|
52
|
-
return obj;
|
|
53
|
-
}
|
|
54
19
|
function _extends() {
|
|
55
|
-
_extends = Object.assign
|
|
20
|
+
_extends = Object.assign || function (target) {
|
|
56
21
|
for (var i = 1; i < arguments.length; i++) {
|
|
57
22
|
var source = arguments[i];
|
|
23
|
+
|
|
58
24
|
for (var key in source) {
|
|
59
25
|
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
60
26
|
target[key] = source[key];
|
|
61
27
|
}
|
|
62
28
|
}
|
|
63
29
|
}
|
|
30
|
+
|
|
64
31
|
return target;
|
|
65
32
|
};
|
|
33
|
+
|
|
66
34
|
return _extends.apply(this, arguments);
|
|
67
35
|
}
|
|
68
|
-
function _objectWithoutPropertiesLoose(source, excluded) {
|
|
69
|
-
if (source == null) return {};
|
|
70
|
-
var target = {};
|
|
71
|
-
var sourceKeys = Object.keys(source);
|
|
72
|
-
var key, i;
|
|
73
|
-
for (i = 0; i < sourceKeys.length; i++) {
|
|
74
|
-
key = sourceKeys[i];
|
|
75
|
-
if (excluded.indexOf(key) >= 0) continue;
|
|
76
|
-
target[key] = source[key];
|
|
77
|
-
}
|
|
78
|
-
return target;
|
|
79
|
-
}
|
|
80
|
-
function _objectWithoutProperties(source, excluded) {
|
|
81
|
-
if (source == null) return {};
|
|
82
|
-
var target = _objectWithoutPropertiesLoose(source, excluded);
|
|
83
|
-
var key, i;
|
|
84
|
-
if (Object.getOwnPropertySymbols) {
|
|
85
|
-
var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
|
|
86
|
-
for (i = 0; i < sourceSymbolKeys.length; i++) {
|
|
87
|
-
key = sourceSymbolKeys[i];
|
|
88
|
-
if (excluded.indexOf(key) >= 0) continue;
|
|
89
|
-
if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
|
|
90
|
-
target[key] = source[key];
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
return target;
|
|
94
|
-
}
|
|
95
|
-
function _toPrimitive(input, hint) {
|
|
96
|
-
if (typeof input !== "object" || input === null) return input;
|
|
97
|
-
var prim = input[Symbol.toPrimitive];
|
|
98
|
-
if (prim !== undefined) {
|
|
99
|
-
var res = prim.call(input, hint || "default");
|
|
100
|
-
if (typeof res !== "object") return res;
|
|
101
|
-
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
102
|
-
}
|
|
103
|
-
return (hint === "string" ? String : Number)(input);
|
|
104
|
-
}
|
|
105
|
-
function _toPropertyKey(arg) {
|
|
106
|
-
var key = _toPrimitive(arg, "string");
|
|
107
|
-
return typeof key === "symbol" ? key : String(key);
|
|
108
|
-
}
|
|
109
36
|
|
|
110
37
|
/**
|
|
111
38
|
* This file contains constants for keypad buttons that aren't single
|
|
@@ -115,7 +42,7 @@ function _toPropertyKey(arg) {
|
|
|
115
42
|
// TODO(charlie): There's duplication between this file and key-configs.js.
|
|
116
43
|
// We should clean it up by removing this file and requiring clients to use the
|
|
117
44
|
// `id` field on the key configurations.
|
|
118
|
-
|
|
45
|
+
const Keys = {
|
|
119
46
|
PLUS: "PLUS",
|
|
120
47
|
MINUS: "MINUS",
|
|
121
48
|
NEGATIVE: "NEGATIVE",
|
|
@@ -177,11 +104,11 @@ var Keys = {
|
|
|
177
104
|
|
|
178
105
|
class Text extends React.Component {
|
|
179
106
|
render() {
|
|
180
|
-
|
|
107
|
+
const {
|
|
181
108
|
numberOfLines,
|
|
182
109
|
style
|
|
183
110
|
} = this.props;
|
|
184
|
-
|
|
111
|
+
const className = css(styles$f.initial, ...(Array.isArray(style) ? style : [style]), numberOfLines === 1 && styles$f.singleLineStyle);
|
|
185
112
|
return /*#__PURE__*/React.createElement("span", {
|
|
186
113
|
className: className,
|
|
187
114
|
style: this.props.dynamicStyle
|
|
@@ -190,7 +117,7 @@ class Text extends React.Component {
|
|
|
190
117
|
}
|
|
191
118
|
|
|
192
119
|
// https://github.com/necolas/react-native-web/blob/master/src/components/Text/index.js
|
|
193
|
-
|
|
120
|
+
const styles$f = StyleSheet.create({
|
|
194
121
|
initial: {
|
|
195
122
|
color: "inherit",
|
|
196
123
|
display: "inline",
|
|
@@ -209,10 +136,8 @@ var styles$f = StyleSheet.create({
|
|
|
209
136
|
});
|
|
210
137
|
|
|
211
138
|
class View extends React.Component {
|
|
212
|
-
// $FlowFixMe[signature-verification-failure]
|
|
213
|
-
|
|
214
139
|
render() {
|
|
215
|
-
|
|
140
|
+
const className = css(View.styles.initial, ...(Array.isArray(this.props.style) ? this.props.style : [this.props.style])) + (this.props.extraClassName ? ` ${this.props.extraClassName}` : "");
|
|
216
141
|
return /*#__PURE__*/React.createElement("div", {
|
|
217
142
|
className: className,
|
|
218
143
|
style: this.props.dynamicStyle,
|
|
@@ -226,7 +151,7 @@ class View extends React.Component {
|
|
|
226
151
|
}, this.props.children);
|
|
227
152
|
}
|
|
228
153
|
}
|
|
229
|
-
|
|
154
|
+
View.styles = StyleSheet.create({
|
|
230
155
|
// From: https://github.com/necolas/react-native-web/blob/master/src/components/View/index.js
|
|
231
156
|
// eslint-disable-next-line react-native/no-unused-styles
|
|
232
157
|
initial: {
|
|
@@ -253,71 +178,71 @@ _defineProperty(View, "styles", StyleSheet.create({
|
|
|
253
178
|
minHeight: 0,
|
|
254
179
|
minWidth: 0
|
|
255
180
|
}
|
|
256
|
-
})
|
|
181
|
+
});
|
|
257
182
|
|
|
258
183
|
/**
|
|
259
184
|
* Common parameters used to style components.
|
|
260
185
|
*/
|
|
261
|
-
|
|
262
|
-
|
|
186
|
+
const wonderBlocksBlue = Color.blue;
|
|
187
|
+
const offBlack = Color.offBlack;
|
|
263
188
|
Color.offBlack32;
|
|
264
|
-
|
|
189
|
+
const offBlack16 = Color.offBlack16;
|
|
265
190
|
Color.offBlack8;
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
191
|
+
const iconSizeHeightPx = 48;
|
|
192
|
+
const iconSizeWidthPx = 48;
|
|
193
|
+
const compactKeypadBorderRadiusPx = 4;
|
|
194
|
+
const cursorHandleRadiusPx = 11;
|
|
270
195
|
|
|
271
196
|
// The amount to multiply the radius by to get the distance from the
|
|
272
197
|
// center to the tip of the cursor handle. The cursor is a circle with
|
|
273
198
|
// one quadrant replace with a square. The hypotenuse of the square is
|
|
274
199
|
// 1.045 times the radius of the circle.
|
|
275
|
-
|
|
200
|
+
const cursorHandleDistanceMultiplier = 1.045;
|
|
276
201
|
|
|
277
202
|
// Keypad button colors
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
203
|
+
const valueGrey = "#FFF";
|
|
204
|
+
const operatorGrey = "#FAFAFA";
|
|
205
|
+
const controlGrey = "#F6F7F7";
|
|
206
|
+
const emptyGrey = "#F0F1F2";
|
|
282
207
|
|
|
283
208
|
// Constants defining any borders between elements in the keypad.
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
209
|
+
const innerBorderColor = offBlack16;
|
|
210
|
+
const innerBorderStyle = "solid";
|
|
211
|
+
const innerBorderWidthPx = 1;
|
|
287
212
|
|
|
288
213
|
// The width at which a device is classified as a "tablet" for the purposes
|
|
289
214
|
// of the keypad layout.
|
|
290
|
-
|
|
215
|
+
const tabletCutoffPx = 600;
|
|
291
216
|
|
|
292
217
|
// The dimensions that define various components in the tree, which may be
|
|
293
218
|
// needed outside of those components in order to determine various layout
|
|
294
219
|
// parameters.
|
|
295
|
-
|
|
296
|
-
|
|
220
|
+
const pageIndicatorHeightPx = 16;
|
|
221
|
+
const navigationPadWidthPx = 192;
|
|
297
222
|
// HACK(charlie): This should be injected by webapp somehow.
|
|
298
223
|
// TODO(charlie): Add a link to the webapp location as soon as the footer
|
|
299
224
|
// has settled down.
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
225
|
+
const toolbarHeightPx = 60;
|
|
226
|
+
|
|
227
|
+
const touchTargetRadiusPx = 2 * cursorHandleRadiusPx;
|
|
228
|
+
const touchTargetHeightPx = 2 * touchTargetRadiusPx;
|
|
229
|
+
const touchTargetWidthPx = 2 * touchTargetRadiusPx;
|
|
230
|
+
const cursorRadiusPx = cursorHandleRadiusPx;
|
|
231
|
+
const cursorHeightPx = cursorHandleDistanceMultiplier * (cursorRadiusPx * 4);
|
|
232
|
+
const cursorWidthPx = 4 * cursorRadiusPx;
|
|
308
233
|
class CursorHandle extends React.Component {
|
|
309
234
|
render() {
|
|
310
|
-
|
|
235
|
+
const {
|
|
311
236
|
x,
|
|
312
237
|
y,
|
|
313
238
|
animateIntoPosition
|
|
314
239
|
} = this.props;
|
|
315
|
-
|
|
240
|
+
const animationStyle = animateIntoPosition ? {
|
|
316
241
|
transitionDuration: "100ms",
|
|
317
242
|
transitionProperty: "transform"
|
|
318
243
|
} : {};
|
|
319
|
-
|
|
320
|
-
|
|
244
|
+
const transformString = `translate(${x}px, ${y}px)`;
|
|
245
|
+
const outerStyle = _extends({
|
|
321
246
|
position: "absolute",
|
|
322
247
|
// This is essentially webapp's interactiveComponent + 1.
|
|
323
248
|
// TODO(charlie): Pull in those styles somehow to avoid breakages.
|
|
@@ -341,7 +266,7 @@ class CursorHandle extends React.Component {
|
|
|
341
266
|
fill: "none",
|
|
342
267
|
width: cursorWidthPx,
|
|
343
268
|
height: cursorHeightPx,
|
|
344
|
-
viewBox:
|
|
269
|
+
viewBox: `0 0 ${cursorWidthPx} ${cursorHeightPx}`
|
|
345
270
|
}, /*#__PURE__*/React.createElement("filter", {
|
|
346
271
|
id: "math-input_cursor",
|
|
347
272
|
colorInterpolationFilters: "sRGB",
|
|
@@ -387,12 +312,12 @@ class CursorHandle extends React.Component {
|
|
|
387
312
|
})));
|
|
388
313
|
}
|
|
389
314
|
}
|
|
390
|
-
|
|
315
|
+
CursorHandle.defaultProps = {
|
|
391
316
|
animateIntoPosition: false,
|
|
392
317
|
visible: false,
|
|
393
318
|
x: 0,
|
|
394
319
|
y: 0
|
|
395
|
-
}
|
|
320
|
+
};
|
|
396
321
|
|
|
397
322
|
/**
|
|
398
323
|
* A gesture recognizer that detects 'drags', crudely defined as either scrolls
|
|
@@ -402,7 +327,7 @@ _defineProperty(CursorHandle, "defaultProps", {
|
|
|
402
327
|
// The 'slop' factor, after which we consider the use to be dragging. The value
|
|
403
328
|
// is taken from the Android SDK. It won't be robust to page zoom and the like,
|
|
404
329
|
// but it should be good enough for our purposes.
|
|
405
|
-
|
|
330
|
+
const touchSlopPx = 8;
|
|
406
331
|
class DragListener {
|
|
407
332
|
constructor(onDrag, initialEvent) {
|
|
408
333
|
// We detect drags in two ways. First, by listening for the window
|
|
@@ -414,21 +339,21 @@ class DragListener {
|
|
|
414
339
|
// And second, by listening for touch moves and tracking the each
|
|
415
340
|
// finger's displacement. This allows us to track, e.g., when the user
|
|
416
341
|
// scrolls within an individual view.
|
|
417
|
-
|
|
418
|
-
for (
|
|
419
|
-
|
|
342
|
+
const touchLocationsById = {};
|
|
343
|
+
for (let i = 0; i < initialEvent.changedTouches.length; i++) {
|
|
344
|
+
const touch = initialEvent.changedTouches[i];
|
|
420
345
|
touchLocationsById[touch.identifier] = [touch.clientX, touch.clientY];
|
|
421
346
|
}
|
|
422
347
|
this._moveListener = evt => {
|
|
423
|
-
for (
|
|
424
|
-
|
|
425
|
-
|
|
348
|
+
for (let i = 0; i < evt.changedTouches.length; i++) {
|
|
349
|
+
const touch = evt.changedTouches[i];
|
|
350
|
+
const initialTouchLocation = touchLocationsById[touch.identifier];
|
|
426
351
|
if (initialTouchLocation) {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
352
|
+
const touchLocation = [touch.clientX, touch.clientY];
|
|
353
|
+
const dx = touchLocation[0] - initialTouchLocation[0];
|
|
354
|
+
const dy = touchLocation[1] - initialTouchLocation[1];
|
|
355
|
+
const squaredDist = dx * dx + dy * dy;
|
|
356
|
+
const squaredTouchSlop = touchSlopPx * touchSlopPx;
|
|
432
357
|
if (squaredDist > squaredTouchSlop) {
|
|
433
358
|
onDrag();
|
|
434
359
|
}
|
|
@@ -439,8 +364,8 @@ class DragListener {
|
|
|
439
364
|
// Clean-up any terminated gestures, since some browsers reuse
|
|
440
365
|
// identifiers.
|
|
441
366
|
this._endAndCancelListener = evt => {
|
|
442
|
-
for (
|
|
443
|
-
delete touchLocationsById[evt.changedTouches[
|
|
367
|
+
for (let i = 0; i < evt.changedTouches.length; i++) {
|
|
368
|
+
delete touchLocationsById[evt.changedTouches[i].identifier];
|
|
444
369
|
}
|
|
445
370
|
};
|
|
446
371
|
}
|
|
@@ -463,11 +388,11 @@ class DragListener {
|
|
|
463
388
|
*/
|
|
464
389
|
|
|
465
390
|
// TODO: Retire this in favour of KeypadType (above)
|
|
466
|
-
|
|
391
|
+
const KeypadTypes = {
|
|
467
392
|
FRACTION: "FRACTION",
|
|
468
393
|
EXPRESSION: "EXPRESSION"
|
|
469
394
|
};
|
|
470
|
-
|
|
395
|
+
const KeyTypes = {
|
|
471
396
|
EMPTY: "EMPTY",
|
|
472
397
|
// For numerals, variables, and any other characters that themselves
|
|
473
398
|
// compose 'values'.
|
|
@@ -486,38 +411,38 @@ var KeyTypes = {
|
|
|
486
411
|
// For the echo animation that appears on press.
|
|
487
412
|
ECHO: "ECHO"
|
|
488
413
|
};
|
|
489
|
-
|
|
414
|
+
const DeviceOrientations = {
|
|
490
415
|
LANDSCAPE: "LANDSCAPE",
|
|
491
416
|
PORTRAIT: "PORTRAIT"
|
|
492
417
|
};
|
|
493
|
-
|
|
418
|
+
const DeviceTypes = {
|
|
494
419
|
PHONE: "PHONE",
|
|
495
420
|
TABLET: "TABLET"
|
|
496
421
|
};
|
|
497
|
-
|
|
422
|
+
const LayoutModes = {
|
|
498
423
|
FULLSCREEN: "FULLSCREEN",
|
|
499
424
|
COMPACT: "COMPACT"
|
|
500
425
|
};
|
|
501
|
-
|
|
426
|
+
const BorderDirections = {
|
|
502
427
|
LEFT: "LEFT",
|
|
503
428
|
BOTTOM: "BOTTOM"
|
|
504
429
|
};
|
|
505
|
-
|
|
430
|
+
const BorderStyles = {
|
|
506
431
|
LEFT: ["LEFT"],
|
|
507
432
|
BOTTOM: ["BOTTOM"],
|
|
508
433
|
ALL: ["LEFT", "BOTTOM"],
|
|
509
434
|
NONE: []
|
|
510
435
|
};
|
|
511
|
-
|
|
436
|
+
const IconTypes = {
|
|
512
437
|
MATH: "MATH",
|
|
513
438
|
SVG: "SVG",
|
|
514
439
|
TEXT: "TEXT"
|
|
515
440
|
};
|
|
516
|
-
|
|
441
|
+
const DecimalSeparators = {
|
|
517
442
|
COMMA: "COMMA",
|
|
518
443
|
PERIOD: "PERIOD"
|
|
519
444
|
};
|
|
520
|
-
|
|
445
|
+
const EchoAnimationTypes = {
|
|
521
446
|
SLIDE_AND_FADE: "SLIDE_AND_FADE",
|
|
522
447
|
FADE_ONLY: "FADE_ONLY",
|
|
523
448
|
LONG_FADE_ONLY: "LONG_FADE_ONLY"
|
|
@@ -529,7 +454,7 @@ var EchoAnimationTypes = {
|
|
|
529
454
|
// imported from wonder-blocks-i18n.
|
|
530
455
|
// - Some languages/locales use different decimal separators than the ones
|
|
531
456
|
// listed here. Much of the Arab world uses U+066C.
|
|
532
|
-
|
|
457
|
+
const decimalSeparator = getDecimalSeparator() === "," ? DecimalSeparators.COMMA : DecimalSeparators.PERIOD;
|
|
533
458
|
|
|
534
459
|
/**
|
|
535
460
|
* Constants that define the various contexts in which a cursor can exist. The
|
|
@@ -546,22 +471,22 @@ var decimalSeparator = getDecimalSeparator() === "," ? DecimalSeparators.COMMA :
|
|
|
546
471
|
// TODO: Get rid of these constants in favour of CursorContext type.
|
|
547
472
|
|
|
548
473
|
// The cursor is not in any of the other viable contexts.
|
|
549
|
-
|
|
474
|
+
const NONE = "NONE";
|
|
550
475
|
// The cursor is within a set of parentheses.
|
|
551
|
-
|
|
476
|
+
const IN_PARENS = "IN_PARENS";
|
|
552
477
|
// The cursor is within a superscript (e.g., an exponent).
|
|
553
|
-
|
|
478
|
+
const IN_SUPER_SCRIPT = "IN_SUPER_SCRIPT";
|
|
554
479
|
// The cursor is within a subscript (e.g., the base of a custom logarithm).
|
|
555
|
-
|
|
480
|
+
const IN_SUB_SCRIPT = "IN_SUB_SCRIPT";
|
|
556
481
|
// The cursor is in the numerator of a fraction.
|
|
557
|
-
|
|
482
|
+
const IN_NUMERATOR = "IN_NUMERATOR";
|
|
558
483
|
// The cursor is in the denominator of a fraction.
|
|
559
|
-
|
|
484
|
+
const IN_DENOMINATOR = "IN_DENOMINATOR";
|
|
560
485
|
// The cursor is sitting before a fraction; that is, the cursor is within
|
|
561
486
|
// what looks to be a mixed number preceding a fraction. This will only be
|
|
562
487
|
// the case when the only math between the cursor and the fraction to its
|
|
563
488
|
// write is non-leaf math (numbers and variables).
|
|
564
|
-
|
|
489
|
+
const BEFORE_FRACTION = "BEFORE_FRACTION";
|
|
565
490
|
|
|
566
491
|
var CursorContexts = /*#__PURE__*/Object.freeze({
|
|
567
492
|
__proto__: null,
|
|
@@ -583,17 +508,17 @@ var CursorContexts = /*#__PURE__*/Object.freeze({
|
|
|
583
508
|
// Keeping `window` in place for test suite and GitHub Pages.
|
|
584
509
|
// If it does not exist, fall back to CommonJS require. - jsatk
|
|
585
510
|
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
511
|
+
const decimalSymbol = decimalSeparator === DecimalSeparators.COMMA ? "," : ".";
|
|
512
|
+
const WRITE = "write";
|
|
513
|
+
const CMD = "cmd";
|
|
514
|
+
const KEYSTROKE = "keystroke";
|
|
515
|
+
const MQ_END = 0;
|
|
591
516
|
|
|
592
517
|
// A mapping from keys that can be pressed on a keypad to the way in which
|
|
593
518
|
// MathQuill should modify its input in response to that key-press. Any keys
|
|
594
519
|
// that do not provide explicit actions (like the numeral keys) will merely
|
|
595
520
|
// write their contents to MathQuill.
|
|
596
|
-
|
|
521
|
+
const KeyActions = {
|
|
597
522
|
[Keys.PLUS]: {
|
|
598
523
|
str: "+",
|
|
599
524
|
fn: WRITE
|
|
@@ -689,23 +614,23 @@ var KeyActions = {
|
|
|
689
614
|
fn: CMD
|
|
690
615
|
}
|
|
691
616
|
};
|
|
692
|
-
|
|
617
|
+
const NormalCommands = {
|
|
693
618
|
[Keys.LOG]: "log",
|
|
694
619
|
[Keys.LN]: "ln",
|
|
695
620
|
[Keys.SIN]: "sin",
|
|
696
621
|
[Keys.COS]: "cos",
|
|
697
622
|
[Keys.TAN]: "tan"
|
|
698
623
|
};
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
624
|
+
const ArithmeticOperators = ["+", "-", "\\cdot", "\\times", "\\div"];
|
|
625
|
+
const EqualityOperators = ["=", "\\neq", "<", "\\leq", ">", "\\geq"];
|
|
626
|
+
const Numerals = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
|
|
627
|
+
const GreekLetters = ["\\theta", "\\pi"];
|
|
628
|
+
const Letters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
|
|
704
629
|
|
|
705
630
|
// We only consider numerals, variables, and Greek Letters to be proper
|
|
706
631
|
// leaf nodes.
|
|
707
|
-
|
|
708
|
-
|
|
632
|
+
const ValidLeaves = [...Numerals, ...GreekLetters, ...Letters.map(letter => letter.toLowerCase()), ...Letters.map(letter => letter.toUpperCase())];
|
|
633
|
+
const KeysForJumpContext = {
|
|
709
634
|
[IN_PARENS]: Keys.JUMP_OUT_PARENTHESES,
|
|
710
635
|
[IN_SUPER_SCRIPT]: Keys.JUMP_OUT_EXPONENT,
|
|
711
636
|
[IN_SUB_SCRIPT]: Keys.JUMP_OUT_BASE,
|
|
@@ -714,13 +639,12 @@ var KeysForJumpContext = {
|
|
|
714
639
|
[IN_DENOMINATOR]: Keys.JUMP_OUT_DENOMINATOR
|
|
715
640
|
};
|
|
716
641
|
class MathWrapper {
|
|
717
|
-
constructor(element) {
|
|
718
|
-
var callbacks = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
642
|
+
constructor(element, options = {}, callbacks = {}) {
|
|
719
643
|
this.MQ = MathQuill.getInterface(2);
|
|
720
644
|
this.mathField = this.MQ.MathField(element, {
|
|
721
645
|
// use a span instead of a textarea so that we don't bring up the
|
|
722
646
|
// native keyboard on mobile when selecting the input
|
|
723
|
-
substituteTextarea: function
|
|
647
|
+
substituteTextarea: function () {
|
|
724
648
|
return document.createElement("span");
|
|
725
649
|
}
|
|
726
650
|
});
|
|
@@ -730,7 +654,7 @@ class MathWrapper {
|
|
|
730
654
|
// HACK(charlie): We shouldn't reaching into MathQuill internals like
|
|
731
655
|
// this, but it's the easiest way to allow us to manage the focus state
|
|
732
656
|
// ourselves.
|
|
733
|
-
|
|
657
|
+
const controller = this.mathField.__controller;
|
|
734
658
|
controller.cursor.show();
|
|
735
659
|
|
|
736
660
|
// Set MathQuill's internal state to reflect the focus, otherwise it
|
|
@@ -739,12 +663,12 @@ class MathWrapper {
|
|
|
739
663
|
controller.blurred = false;
|
|
740
664
|
}
|
|
741
665
|
blur() {
|
|
742
|
-
|
|
666
|
+
const controller = this.mathField.__controller;
|
|
743
667
|
controller.cursor.hide();
|
|
744
668
|
controller.blurred = true;
|
|
745
669
|
}
|
|
746
670
|
_writeNormalFunction(name) {
|
|
747
|
-
this.mathField.write(
|
|
671
|
+
this.mathField.write(`\\${name}\\left(\\right)`);
|
|
748
672
|
this.mathField.keystroke("Left");
|
|
749
673
|
}
|
|
750
674
|
|
|
@@ -755,9 +679,9 @@ class MathWrapper {
|
|
|
755
679
|
* @returns {object} a cursor object, consisting of a cursor context
|
|
756
680
|
*/
|
|
757
681
|
pressKey(key) {
|
|
758
|
-
|
|
682
|
+
const cursor = this.mathField.__controller.cursor;
|
|
759
683
|
if (key in KeyActions) {
|
|
760
|
-
|
|
684
|
+
const {
|
|
761
685
|
str,
|
|
762
686
|
fn
|
|
763
687
|
} = KeyActions[key];
|
|
@@ -769,7 +693,7 @@ class MathWrapper {
|
|
|
769
693
|
} else if (key === Keys.FRAC_EXCLUSIVE) {
|
|
770
694
|
// If there's nothing to the left of the cursor, then we want to
|
|
771
695
|
// leave the cursor to the left of the fraction after creating it.
|
|
772
|
-
|
|
696
|
+
const shouldNavigateLeft = cursor[this.MQ.L] === MQ_END;
|
|
773
697
|
this.mathField.cmd("\\frac");
|
|
774
698
|
if (shouldNavigateLeft) {
|
|
775
699
|
this.mathField.keystroke("Left");
|
|
@@ -828,24 +752,24 @@ class MathWrapper {
|
|
|
828
752
|
* should be placed
|
|
829
753
|
*/
|
|
830
754
|
setCursorPosition(x, y, hitNode) {
|
|
831
|
-
|
|
755
|
+
const el = hitNode || document.elementFromPoint(x, y);
|
|
832
756
|
if (el) {
|
|
833
|
-
|
|
757
|
+
const cursor = this.getCursor();
|
|
834
758
|
if (el.hasAttribute("mq-root-block")) {
|
|
835
759
|
// If we're in the empty area place the cursor at the right
|
|
836
760
|
// end of the expression.
|
|
837
761
|
cursor.insAtRightEnd(this.mathField.__controller.root);
|
|
838
762
|
} else {
|
|
839
763
|
// Otherwise place beside the element at x, y.
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
764
|
+
const controller = this.mathField.__controller;
|
|
765
|
+
const pageX = x - document.body.scrollLeft;
|
|
766
|
+
const pageY = y - document.body.scrollTop;
|
|
843
767
|
controller.seek($(el), pageX, pageY).cursor.startSelection();
|
|
844
768
|
|
|
845
769
|
// Unless that would leave us mid-command, in which case, we
|
|
846
770
|
// need to adjust and place the cursor inside the parens
|
|
847
771
|
// following the command.
|
|
848
|
-
|
|
772
|
+
const command = this._maybeFindCommand(cursor[this.MQ.L]);
|
|
849
773
|
if (command && command.endNode) {
|
|
850
774
|
// NOTE(charlie): endNode should definitely be \left(.
|
|
851
775
|
cursor.insLeftOf(command.endNode);
|
|
@@ -872,7 +796,7 @@ class MathWrapper {
|
|
|
872
796
|
this.mathField.latex(latex);
|
|
873
797
|
}
|
|
874
798
|
isEmpty() {
|
|
875
|
-
|
|
799
|
+
const cursor = this.getCursor();
|
|
876
800
|
return cursor.parent.id === 1 && cursor[1] === 0 && cursor[-1] === 0;
|
|
877
801
|
}
|
|
878
802
|
|
|
@@ -893,8 +817,8 @@ class MathWrapper {
|
|
|
893
817
|
// when upgrading MathQuill.
|
|
894
818
|
|
|
895
819
|
_handleBackspaceInNthRoot(cursor) {
|
|
896
|
-
|
|
897
|
-
|
|
820
|
+
const isAtLeftEnd = cursor[this.MQ.L] === MQ_END;
|
|
821
|
+
const isRootEmpty = this._isInsideEmptyNode(cursor.parent.parent.blocks[0].ends);
|
|
898
822
|
if (isAtLeftEnd) {
|
|
899
823
|
this._selectNode(cursor.parent.parent, cursor);
|
|
900
824
|
if (isRootEmpty) {
|
|
@@ -912,7 +836,7 @@ class MathWrapper {
|
|
|
912
836
|
* @private
|
|
913
837
|
*/
|
|
914
838
|
_handleJumpOut(cursor, key) {
|
|
915
|
-
|
|
839
|
+
const context = this.contextForCursor(cursor);
|
|
916
840
|
|
|
917
841
|
// Validate that the current cursor context matches the key's intent.
|
|
918
842
|
if (KeysForJumpContext[context] !== key) {
|
|
@@ -931,8 +855,8 @@ class MathWrapper {
|
|
|
931
855
|
break;
|
|
932
856
|
case BEFORE_FRACTION:
|
|
933
857
|
// Find the nearest fraction to the right of the cursor.
|
|
934
|
-
|
|
935
|
-
|
|
858
|
+
let fractionNode;
|
|
859
|
+
let visitor = cursor;
|
|
936
860
|
while (visitor[this.MQ.R] !== MQ_END) {
|
|
937
861
|
if (this._isFraction(visitor[this.MQ.R])) {
|
|
938
862
|
fractionNode = visitor[this.MQ.R];
|
|
@@ -951,7 +875,7 @@ class MathWrapper {
|
|
|
951
875
|
// continue rightwards until we find ourselves inside of it.
|
|
952
876
|
// It's possible that there are cases in which we don't reach
|
|
953
877
|
// the denominator, though I can't think of any.
|
|
954
|
-
|
|
878
|
+
const siblingDenominator = cursor.parent.parent.blocks[1];
|
|
955
879
|
while (cursor.parent !== siblingDenominator) {
|
|
956
880
|
this.mathField.keystroke("Right");
|
|
957
881
|
}
|
|
@@ -975,7 +899,7 @@ class MathWrapper {
|
|
|
975
899
|
cursor.insRightOf(cursor.parent.parent);
|
|
976
900
|
break;
|
|
977
901
|
default:
|
|
978
|
-
throw new Error(
|
|
902
|
+
throw new Error(`Attempted to 'Jump Out' from node, but found no ` + `appropriate cursor context: ${context}`);
|
|
979
903
|
}
|
|
980
904
|
}
|
|
981
905
|
|
|
@@ -988,9 +912,9 @@ class MathWrapper {
|
|
|
988
912
|
*/
|
|
989
913
|
_handleBackspace(cursor) {
|
|
990
914
|
if (!cursor.selection) {
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
915
|
+
const parent = cursor.parent;
|
|
916
|
+
const grandparent = parent.parent;
|
|
917
|
+
const leftNode = cursor[this.MQ.L];
|
|
994
918
|
if (this._isFraction(leftNode)) {
|
|
995
919
|
this._selectNode(leftNode, cursor);
|
|
996
920
|
} else if (this._isSquareRoot(leftNode)) {
|
|
@@ -1028,10 +952,10 @@ class MathWrapper {
|
|
|
1028
952
|
// the nodes to the left of our grandparent comprise a valid function
|
|
1029
953
|
// name.
|
|
1030
954
|
if (cursor[this.MQ.L] === MQ_END) {
|
|
1031
|
-
|
|
1032
|
-
|
|
955
|
+
const parent = cursor.parent;
|
|
956
|
+
const grandparent = parent.parent;
|
|
1033
957
|
if (grandparent.ctrlSeq === "\\left(") {
|
|
1034
|
-
|
|
958
|
+
const command = this._maybeFindCommandBeforeParens(grandparent);
|
|
1035
959
|
if (command) {
|
|
1036
960
|
cursor.insLeftOf(command.startNode);
|
|
1037
961
|
return;
|
|
@@ -1043,7 +967,7 @@ class MathWrapper {
|
|
|
1043
967
|
this.mathField.keystroke("Left");
|
|
1044
968
|
}
|
|
1045
969
|
_handleRightArrow(cursor) {
|
|
1046
|
-
|
|
970
|
+
const command = this._maybeFindCommand(cursor[this.MQ.R]);
|
|
1047
971
|
if (command) {
|
|
1048
972
|
// Similarly, if a function is to our right, then we need to place
|
|
1049
973
|
// the cursor at the start of its parenthetical content, which is
|
|
@@ -1060,9 +984,9 @@ class MathWrapper {
|
|
|
1060
984
|
// If there's an invalid operator preceding the cursor (anything that
|
|
1061
985
|
// knowingly cannot be raised to a power), add an empty set of
|
|
1062
986
|
// parentheses and apply the exponent to that.
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
987
|
+
const invalidPrefixes = [...ArithmeticOperators, ...EqualityOperators];
|
|
988
|
+
const precedingNode = cursor[this.MQ.L];
|
|
989
|
+
const shouldPrefixWithParens = precedingNode === MQ_END || invalidPrefixes.includes(precedingNode.ctrlSeq.trim());
|
|
1066
990
|
if (shouldPrefixWithParens) {
|
|
1067
991
|
this.mathField.write("\\left(\\right)");
|
|
1068
992
|
}
|
|
@@ -1074,7 +998,7 @@ class MathWrapper {
|
|
|
1074
998
|
break;
|
|
1075
999
|
case Keys.EXP_2:
|
|
1076
1000
|
case Keys.EXP_3:
|
|
1077
|
-
this.mathField.write(
|
|
1001
|
+
this.mathField.write(`^${key === Keys.EXP_2 ? 2 : 3}`);
|
|
1078
1002
|
|
|
1079
1003
|
// If we enter a square or a cube, we should leave the cursor
|
|
1080
1004
|
// within the newly inserted parens, if they exist. This takes
|
|
@@ -1088,7 +1012,7 @@ class MathWrapper {
|
|
|
1088
1012
|
}
|
|
1089
1013
|
break;
|
|
1090
1014
|
default:
|
|
1091
|
-
throw new Error(
|
|
1015
|
+
throw new Error(`Invalid exponent key: ${key}`);
|
|
1092
1016
|
}
|
|
1093
1017
|
}
|
|
1094
1018
|
|
|
@@ -1116,24 +1040,24 @@ class MathWrapper {
|
|
|
1116
1040
|
// command. If we encounter any character that doesn't belong in a
|
|
1117
1041
|
// command, we return null. We match a single character at a time.
|
|
1118
1042
|
// Ex) ['\\l', 'o', 'g ', '\\left(', ...]
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1043
|
+
const commandCharRegex = /^[a-z]$/;
|
|
1044
|
+
const commandStartRegex = /^\\[a-z]$/;
|
|
1045
|
+
const commandEndSeq = "\\left(";
|
|
1122
1046
|
|
|
1123
1047
|
// Note: We allowlist the set of valid commands, since relying solely on
|
|
1124
1048
|
// a command being prefixed with a backslash leads to undesired
|
|
1125
1049
|
// behavior. For example, Greek symbols, left parentheses, and square
|
|
1126
1050
|
// roots all get treated as commands.
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1051
|
+
const validCommands = ["\\log", "\\ln", "\\cos", "\\sin", "\\tan"];
|
|
1052
|
+
let name = "";
|
|
1053
|
+
let startNode;
|
|
1054
|
+
let endNode;
|
|
1131
1055
|
|
|
1132
1056
|
// Collect the portion of the command from the current node, leftwards
|
|
1133
1057
|
// until the start of the command.
|
|
1134
|
-
|
|
1058
|
+
let node = initialNode;
|
|
1135
1059
|
while (node !== 0) {
|
|
1136
|
-
|
|
1060
|
+
const ctrlSeq = node.ctrlSeq.trim();
|
|
1137
1061
|
if (commandCharRegex.test(ctrlSeq)) {
|
|
1138
1062
|
name = ctrlSeq + name;
|
|
1139
1063
|
} else if (commandStartRegex.test(ctrlSeq)) {
|
|
@@ -1153,12 +1077,12 @@ class MathWrapper {
|
|
|
1153
1077
|
// Next, iterate from the start to the right.
|
|
1154
1078
|
node = initialNode[this.MQ.R];
|
|
1155
1079
|
while (node !== 0) {
|
|
1156
|
-
|
|
1157
|
-
if (commandCharRegex.test(
|
|
1080
|
+
const ctrlSeq = node.ctrlSeq.trim();
|
|
1081
|
+
if (commandCharRegex.test(ctrlSeq)) {
|
|
1158
1082
|
// If we have a single character, add it to the command
|
|
1159
1083
|
// name.
|
|
1160
|
-
name = name +
|
|
1161
|
-
} else if (
|
|
1084
|
+
name = name + ctrlSeq;
|
|
1085
|
+
} else if (ctrlSeq === commandEndSeq) {
|
|
1162
1086
|
// If we hit the command end delimiter (the left
|
|
1163
1087
|
// parentheses surrounding its arguments), stop.
|
|
1164
1088
|
endNode = node;
|
|
@@ -1237,9 +1161,9 @@ class MathWrapper {
|
|
|
1237
1161
|
return node.jQ && node.jQ.hasClass("mq-nthroot");
|
|
1238
1162
|
}
|
|
1239
1163
|
_isInsideLogIndex(cursor) {
|
|
1240
|
-
|
|
1164
|
+
const grandparent = cursor.parent.parent;
|
|
1241
1165
|
if (grandparent && grandparent.jQ.hasClass("mq-supsub")) {
|
|
1242
|
-
|
|
1166
|
+
const command = this._maybeFindCommandBeforeParens(grandparent);
|
|
1243
1167
|
if (command && command.name === "\\log") {
|
|
1244
1168
|
return true;
|
|
1245
1169
|
}
|
|
@@ -1255,11 +1179,11 @@ class MathWrapper {
|
|
|
1255
1179
|
// to a sqrt, e.g. \sqrt[|]{35x-5} => |\sqrt{35x-5}. If there's no
|
|
1256
1180
|
// content under the root, then we delete the whole thing.
|
|
1257
1181
|
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1182
|
+
const grandparent = cursor.parent.parent;
|
|
1183
|
+
const latex = grandparent.latex();
|
|
1184
|
+
const reinsertionPoint = grandparent[this.MQ.L];
|
|
1261
1185
|
this._selectNode(grandparent, cursor);
|
|
1262
|
-
|
|
1186
|
+
const rootIsEmpty = grandparent.blocks[1].jQ.text() === "";
|
|
1263
1187
|
if (rootIsEmpty) {
|
|
1264
1188
|
// If there is not content under the root then simply delete
|
|
1265
1189
|
// the whole thing.
|
|
@@ -1291,8 +1215,8 @@ class MathWrapper {
|
|
|
1291
1215
|
}
|
|
1292
1216
|
_handleBackspaceInLogIndex(cursor) {
|
|
1293
1217
|
if (this._isInsideEmptyNode(cursor)) {
|
|
1294
|
-
|
|
1295
|
-
|
|
1218
|
+
const grandparent = cursor.parent.parent;
|
|
1219
|
+
const command = this._maybeFindCommandBeforeParens(grandparent);
|
|
1296
1220
|
cursor.insLeftOf(command.startNode);
|
|
1297
1221
|
cursor.startSelection();
|
|
1298
1222
|
if (grandparent[this.MQ.R] !== MQ_END) {
|
|
@@ -1302,7 +1226,7 @@ class MathWrapper {
|
|
|
1302
1226
|
}
|
|
1303
1227
|
cursor.select();
|
|
1304
1228
|
cursor.endSelection();
|
|
1305
|
-
|
|
1229
|
+
const isLogBodyEmpty = grandparent[this.MQ.R].contentjQ.text() === "";
|
|
1306
1230
|
if (isLogBodyEmpty) {
|
|
1307
1231
|
// If there's no content inside the log's parens then delete the
|
|
1308
1232
|
// whole thing.
|
|
@@ -1321,9 +1245,9 @@ class MathWrapper {
|
|
|
1321
1245
|
// (x+1)| => |(x+1)|
|
|
1322
1246
|
// \log(x+1)| => |\log(x+1)|
|
|
1323
1247
|
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1248
|
+
const leftNode = cursor[this.MQ.L];
|
|
1249
|
+
const rightNode = cursor[this.MQ.R];
|
|
1250
|
+
const command = this._maybeFindCommandBeforeParens(leftNode);
|
|
1327
1251
|
if (command && command.startNode) {
|
|
1328
1252
|
// There's a command before the parens so we select it as well as
|
|
1329
1253
|
// the parens.
|
|
@@ -1375,7 +1299,7 @@ class MathWrapper {
|
|
|
1375
1299
|
this.mathField.keystroke("Backspace");
|
|
1376
1300
|
return;
|
|
1377
1301
|
}
|
|
1378
|
-
|
|
1302
|
+
const grandparent = cursor.parent.parent;
|
|
1379
1303
|
|
|
1380
1304
|
// If the cursors is inside the parens at the start but the command
|
|
1381
1305
|
// has a subscript as is the case in log_n then move the cursor into
|
|
@@ -1393,11 +1317,11 @@ class MathWrapper {
|
|
|
1393
1317
|
|
|
1394
1318
|
// Determine if the parens are empty before we modify the
|
|
1395
1319
|
// cursor's position.
|
|
1396
|
-
|
|
1320
|
+
const isEmpty = this._isInsideEmptyNode(cursor);
|
|
1397
1321
|
|
|
1398
1322
|
// Insert the cursor to the left of the command if there is one
|
|
1399
1323
|
// or before the '\\left(` if there isn't
|
|
1400
|
-
|
|
1324
|
+
const command = this._maybeFindCommandBeforeParens(grandparent);
|
|
1401
1325
|
cursor.insLeftOf(command && command.startNode || grandparent);
|
|
1402
1326
|
cursor.startSelection();
|
|
1403
1327
|
cursor.insRightOf(grandparent);
|
|
@@ -1416,7 +1340,7 @@ class MathWrapper {
|
|
|
1416
1340
|
}
|
|
1417
1341
|
contextForCursor(cursor) {
|
|
1418
1342
|
// First, try to find any fraction to the right, unimpeded.
|
|
1419
|
-
|
|
1343
|
+
let visitor = cursor;
|
|
1420
1344
|
while (visitor[this.MQ.R] !== MQ_END) {
|
|
1421
1345
|
if (this._isFraction(visitor[this.MQ.R])) {
|
|
1422
1346
|
return BEFORE_FRACTION;
|
|
@@ -1469,17 +1393,17 @@ function bodyOrHtml() {
|
|
|
1469
1393
|
}
|
|
1470
1394
|
return document.documentElement;
|
|
1471
1395
|
}
|
|
1472
|
-
|
|
1396
|
+
const scrollIntoView = (containerNode, keypadNode) => {
|
|
1473
1397
|
// TODO(charlie): There's no need for us to be reading the keypad bounds
|
|
1474
1398
|
// here, since they're pre-determined by logic in the store. We should
|
|
1475
1399
|
// instead pass around an object that knows the bounds.
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1400
|
+
const containerBounds = containerNode.getBoundingClientRect();
|
|
1401
|
+
const containerBottomPx = containerBounds.bottom;
|
|
1402
|
+
const containerTopPx = containerBounds.top;
|
|
1479
1403
|
|
|
1480
1404
|
// Get the element that scrolls the document.
|
|
1481
|
-
|
|
1482
|
-
|
|
1405
|
+
const scrollNode = bodyOrHtml();
|
|
1406
|
+
const desiredMarginPx = 16;
|
|
1483
1407
|
if (keypadNode) {
|
|
1484
1408
|
// NOTE(charlie): We can't use the bounding rect of the keypad,
|
|
1485
1409
|
// as it is likely in the process of animating in. Instead, to
|
|
@@ -1489,14 +1413,14 @@ var scrollIntoView = (containerNode, keypadNode) => {
|
|
|
1489
1413
|
// in the native apps (where the toolbar is rendered natively), this
|
|
1490
1414
|
// will result in us leaving excess space between the input and the
|
|
1491
1415
|
// keypad, but that seems okay.
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1416
|
+
const pageHeightPx = window.innerHeight;
|
|
1417
|
+
const keypadHeightPx = keypadNode.clientHeight;
|
|
1418
|
+
const keypadTopPx = pageHeightPx - (keypadHeightPx + toolbarHeightPx);
|
|
1495
1419
|
if (containerBottomPx > keypadTopPx) {
|
|
1496
1420
|
// If the input would be obscured by the keypad, scroll such that
|
|
1497
1421
|
// the bottom of the input is just above the top of the keypad,
|
|
1498
1422
|
// taking care not to scroll the input out of view.
|
|
1499
|
-
|
|
1423
|
+
const scrollOffset = Math.min(containerBottomPx - keypadTopPx + desiredMarginPx, containerTopPx);
|
|
1500
1424
|
scrollNode.scrollTop += scrollOffset;
|
|
1501
1425
|
return;
|
|
1502
1426
|
}
|
|
@@ -1510,25 +1434,25 @@ var scrollIntoView = (containerNode, keypadNode) => {
|
|
|
1510
1434
|
}
|
|
1511
1435
|
};
|
|
1512
1436
|
|
|
1513
|
-
|
|
1437
|
+
const constrainingFrictionFactor = 0.8;
|
|
1514
1438
|
// eslint-disable-next-line react/no-unsafe
|
|
1515
1439
|
class MathInput extends React.Component {
|
|
1516
|
-
constructor() {
|
|
1517
|
-
super(...
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1440
|
+
constructor(...args) {
|
|
1441
|
+
super(...args);
|
|
1442
|
+
this.didTouchOutside = void 0;
|
|
1443
|
+
this.didScroll = void 0;
|
|
1444
|
+
this.mathField = void 0;
|
|
1445
|
+
this.recordTouchStartOutside = void 0;
|
|
1446
|
+
this.blurOnTouchEndOutside = void 0;
|
|
1447
|
+
this.dragListener = void 0;
|
|
1448
|
+
this.inputRef = void 0;
|
|
1449
|
+
this._isMounted = void 0;
|
|
1450
|
+
this._mathContainer = void 0;
|
|
1451
|
+
this._container = void 0;
|
|
1452
|
+
this._root = void 0;
|
|
1453
|
+
this._containerBounds = void 0;
|
|
1454
|
+
this._keypadBounds = void 0;
|
|
1455
|
+
this.state = {
|
|
1532
1456
|
focused: false,
|
|
1533
1457
|
handle: {
|
|
1534
1458
|
animateIntoPosition: false,
|
|
@@ -1536,41 +1460,41 @@ class MathInput extends React.Component {
|
|
|
1536
1460
|
x: 0,
|
|
1537
1461
|
y: 0
|
|
1538
1462
|
}
|
|
1539
|
-
}
|
|
1540
|
-
|
|
1463
|
+
};
|
|
1464
|
+
this._clearKeypadBoundsCache = () => {
|
|
1541
1465
|
this._keypadBounds = null;
|
|
1542
|
-
}
|
|
1543
|
-
|
|
1466
|
+
};
|
|
1467
|
+
this._cacheKeypadBounds = keypadNode => {
|
|
1544
1468
|
this._keypadBounds = keypadNode.getBoundingClientRect();
|
|
1545
|
-
}
|
|
1546
|
-
|
|
1469
|
+
};
|
|
1470
|
+
this._updateInputPadding = () => {
|
|
1547
1471
|
this._container = ReactDOM.findDOMNode(this);
|
|
1548
1472
|
this._root = this._container.querySelector(".mq-root-block");
|
|
1549
|
-
|
|
1473
|
+
const padding = this.getInputInnerPadding();
|
|
1550
1474
|
// NOTE(diedra): This overrides the default 2px padding from Mathquil.
|
|
1551
|
-
this._root.style.padding =
|
|
1552
|
-
this._root.style.fontSize =
|
|
1553
|
-
}
|
|
1554
|
-
|
|
1475
|
+
this._root.style.padding = `${padding.paddingTop}px ${padding.paddingRight}px` + ` ${padding.paddingBottom}px ${padding.paddingLeft}px`;
|
|
1476
|
+
this._root.style.fontSize = `${fontSizePt}pt`;
|
|
1477
|
+
};
|
|
1478
|
+
this._getKeypadBounds = () => {
|
|
1555
1479
|
if (!this._keypadBounds) {
|
|
1556
|
-
|
|
1480
|
+
const node = this.props.keypadElement.getDOMNode();
|
|
1557
1481
|
this._cacheKeypadBounds(node);
|
|
1558
1482
|
}
|
|
1559
1483
|
return this._keypadBounds;
|
|
1560
|
-
}
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1484
|
+
};
|
|
1485
|
+
this._updateCursorHandle = animateIntoPosition => {
|
|
1486
|
+
const containerBounds = this._container.getBoundingClientRect();
|
|
1487
|
+
const cursor = this._container.querySelector(".mq-cursor");
|
|
1488
|
+
const cursorBounds = cursor.getBoundingClientRect();
|
|
1489
|
+
const cursorWidth = cursorBounds.width;
|
|
1490
|
+
const gapBelowCursor = 2;
|
|
1491
|
+
const inputInnerPadding = this.getInputInnerPadding();
|
|
1568
1492
|
|
|
1569
1493
|
// The cursor should never be further right or left than the edge of the
|
|
1570
1494
|
// container's values.
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1495
|
+
const furthestRightCursorBound = containerBounds.right - cursorWidth - inputInnerPadding.paddingRight;
|
|
1496
|
+
const furthestLeftCursorBound = containerBounds.left + cursorWidth + inputInnerPadding.paddingLeft;
|
|
1497
|
+
let cursorBoundsLeft = cursorBounds.left;
|
|
1574
1498
|
if (cursorBounds.left > furthestRightCursorBound) {
|
|
1575
1499
|
cursorBoundsLeft = furthestRightCursorBound;
|
|
1576
1500
|
} else if (cursorBounds.left < furthestLeftCursorBound) {
|
|
@@ -1586,8 +1510,8 @@ class MathInput extends React.Component {
|
|
|
1586
1510
|
y: cursorBounds.bottom + gapBelowCursor - containerBounds.top
|
|
1587
1511
|
}
|
|
1588
1512
|
});
|
|
1589
|
-
}
|
|
1590
|
-
|
|
1513
|
+
};
|
|
1514
|
+
this._hideCursorHandle = () => {
|
|
1591
1515
|
this.setState({
|
|
1592
1516
|
handle: {
|
|
1593
1517
|
visible: false,
|
|
@@ -1595,8 +1519,8 @@ class MathInput extends React.Component {
|
|
|
1595
1519
|
y: 0
|
|
1596
1520
|
}
|
|
1597
1521
|
});
|
|
1598
|
-
}
|
|
1599
|
-
|
|
1522
|
+
};
|
|
1523
|
+
this._handleScroll = () => {
|
|
1600
1524
|
// If animateIntoPosition is false, the user is currently manually positioning
|
|
1601
1525
|
// the cursor. This is important because the user can scroll the input field
|
|
1602
1526
|
// with the curor handle, and we don't want to override that ability.
|
|
@@ -1605,8 +1529,8 @@ class MathInput extends React.Component {
|
|
|
1605
1529
|
if (this.state.handle.animateIntoPosition !== false) {
|
|
1606
1530
|
this._hideCursorHandle();
|
|
1607
1531
|
}
|
|
1608
|
-
}
|
|
1609
|
-
|
|
1532
|
+
};
|
|
1533
|
+
this.blur = () => {
|
|
1610
1534
|
this.mathField.blur();
|
|
1611
1535
|
this.props.onBlur && this.props.onBlur();
|
|
1612
1536
|
this.setState({
|
|
@@ -1615,25 +1539,25 @@ class MathInput extends React.Component {
|
|
|
1615
1539
|
visible: false
|
|
1616
1540
|
}
|
|
1617
1541
|
});
|
|
1618
|
-
}
|
|
1619
|
-
|
|
1542
|
+
};
|
|
1543
|
+
this.focus = () => {
|
|
1620
1544
|
// Pass this component's handleKey method to the keypad so it can call
|
|
1621
1545
|
// it whenever it needs to trigger a keypress action.
|
|
1622
1546
|
this.props.keypadElement.setKeyHandler(key => {
|
|
1623
|
-
|
|
1547
|
+
const cursor = this.mathField.pressKey(key);
|
|
1624
1548
|
|
|
1625
1549
|
// Trigger an `onChange` if the value in the input changed, and hide
|
|
1626
1550
|
// the cursor handle whenever the user types a key. If the value
|
|
1627
1551
|
// changed as a result of a keypress, we need to be careful not to
|
|
1628
1552
|
// call `setState` until after `onChange` has resolved.
|
|
1629
|
-
|
|
1553
|
+
const hideCursor = () => {
|
|
1630
1554
|
this.setState({
|
|
1631
1555
|
handle: {
|
|
1632
1556
|
visible: false
|
|
1633
1557
|
}
|
|
1634
1558
|
});
|
|
1635
1559
|
};
|
|
1636
|
-
|
|
1560
|
+
const value = this.mathField.getContent();
|
|
1637
1561
|
if (this.props.value !== value) {
|
|
1638
1562
|
this.props.onChange(value, hideCursor);
|
|
1639
1563
|
} else {
|
|
@@ -1658,17 +1582,17 @@ class MathInput extends React.Component {
|
|
|
1658
1582
|
// that the higher level controller tells us when the
|
|
1659
1583
|
// keypad is settled (then scrollIntoView wouldn't have
|
|
1660
1584
|
// to make assumptions about that either).
|
|
1661
|
-
|
|
1585
|
+
const maybeKeypadNode = this.props.keypadElement && this.props.keypadElement.getDOMNode();
|
|
1662
1586
|
scrollIntoView(this._container, maybeKeypadNode);
|
|
1663
1587
|
}
|
|
1664
1588
|
});
|
|
1665
1589
|
});
|
|
1666
|
-
}
|
|
1667
|
-
|
|
1590
|
+
};
|
|
1591
|
+
this._findHitNode = (containerBounds, x, y, dx, dy) => {
|
|
1668
1592
|
while (y >= containerBounds.top && y <= containerBounds.bottom) {
|
|
1669
1593
|
y += dy;
|
|
1670
|
-
|
|
1671
|
-
|
|
1594
|
+
const points = [[x - dx, y], [x, y], [x + dx, y]];
|
|
1595
|
+
const elements = points
|
|
1672
1596
|
// @ts-expect-error [FEI-5003] - TS2556 - A spread argument must either have a tuple type or be passed to a rest parameter.
|
|
1673
1597
|
.map(point => document.elementFromPoint(...point))
|
|
1674
1598
|
// We exclude the root container itself and any nodes marked
|
|
@@ -1682,23 +1606,17 @@ class MathInput extends React.Component {
|
|
|
1682
1606
|
// included, neither mq-numerator nor mq-denominator nodes are
|
|
1683
1607
|
// and neither are subscripts or superscripts.
|
|
1684
1608
|
.filter(element => element && this._root.contains(element) && (!element.classList.contains("mq-root-block") && !element.classList.contains("mq-non-leaf") || element.classList.contains("mq-empty") || element.classList.contains("mq-hasCursor")));
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
// Contains only DOMNodes without child elements. These should
|
|
1688
|
-
// contain some amount of text though.
|
|
1689
|
-
var leafElements = [];
|
|
1609
|
+
let hitNode = null;
|
|
1690
1610
|
|
|
1691
1611
|
// Contains only DOMNodes with child elements.
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
for (
|
|
1612
|
+
const nonLeafElements = [];
|
|
1613
|
+
let max = 0;
|
|
1614
|
+
const counts = {};
|
|
1615
|
+
const elementsById = {};
|
|
1616
|
+
for (const element of elements) {
|
|
1697
1617
|
// @ts-expect-error [FEI-5003] - TS2531 - Object is possibly 'null'.
|
|
1698
|
-
|
|
1618
|
+
const id = element.getAttribute("mathquill-command-id");
|
|
1699
1619
|
if (id != null) {
|
|
1700
|
-
// @ts-expect-error [FEI-5003] - TS2345 - Argument of type 'Element | null' is not assignable to parameter of type 'HTMLElement | null'.
|
|
1701
|
-
leafElements.push(element);
|
|
1702
1620
|
counts[id] = (counts[id] || 0) + 1;
|
|
1703
1621
|
elementsById[id] = element;
|
|
1704
1622
|
} else {
|
|
@@ -1718,10 +1636,10 @@ class MathInput extends React.Component {
|
|
|
1718
1636
|
// we hit multiple leaf nodes at the same time. In this case we
|
|
1719
1637
|
// we prefer the DOMNode with the most hits.
|
|
1720
1638
|
// TODO(kevinb) consider preferring nodes hit by [x, y].
|
|
1721
|
-
for (
|
|
1639
|
+
for (const [id, count] of entries(counts)) {
|
|
1722
1640
|
if (count > max) {
|
|
1723
1641
|
max = count;
|
|
1724
|
-
hitNode = elementsById[
|
|
1642
|
+
hitNode = elementsById[id];
|
|
1725
1643
|
}
|
|
1726
1644
|
}
|
|
1727
1645
|
|
|
@@ -1740,9 +1658,9 @@ class MathInput extends React.Component {
|
|
|
1740
1658
|
}
|
|
1741
1659
|
}
|
|
1742
1660
|
return false;
|
|
1743
|
-
}
|
|
1744
|
-
|
|
1745
|
-
|
|
1661
|
+
};
|
|
1662
|
+
this._insertCursorAtClosestNode = (x, y) => {
|
|
1663
|
+
const cursor = this.mathField.getCursor();
|
|
1746
1664
|
|
|
1747
1665
|
// Pre-emptively check if the input has any child nodes; if not, the
|
|
1748
1666
|
// input is empty, so we throw the cursor at the start.
|
|
@@ -1763,7 +1681,7 @@ class MathInput extends React.Component {
|
|
|
1763
1681
|
} else if (x < this._containerBounds.left) {
|
|
1764
1682
|
x = this._containerBounds.left + 15;
|
|
1765
1683
|
}
|
|
1766
|
-
|
|
1684
|
+
let dy;
|
|
1767
1685
|
|
|
1768
1686
|
// Vertical spacing between hit tests
|
|
1769
1687
|
// dy is negative because we're moving upwards.
|
|
@@ -1773,7 +1691,7 @@ class MathInput extends React.Component {
|
|
|
1773
1691
|
// Note: This value depends on the font size. If the gap is too small
|
|
1774
1692
|
// we end up placing the cursor at the end of the expression when we
|
|
1775
1693
|
// shouldn't.
|
|
1776
|
-
|
|
1694
|
+
const dx = 5;
|
|
1777
1695
|
if (this._findHitNode(this._containerBounds, x, y, dx, dy)) {
|
|
1778
1696
|
return;
|
|
1779
1697
|
}
|
|
@@ -1786,10 +1704,10 @@ class MathInput extends React.Component {
|
|
|
1786
1704
|
if (this._findHitNode(this._containerBounds, x, y, dx, dy)) {
|
|
1787
1705
|
return;
|
|
1788
1706
|
}
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1707
|
+
const firstChildBounds = this._root.firstChild.getBoundingClientRect();
|
|
1708
|
+
const lastChildBounds = this._root.lastChild.getBoundingClientRect();
|
|
1709
|
+
const left = firstChildBounds.left;
|
|
1710
|
+
const right = lastChildBounds.right;
|
|
1793
1711
|
|
|
1794
1712
|
// We've exhausted all of the options. We're likely either to the right
|
|
1795
1713
|
// or left of all of the math, so we place the cursor at the end to
|
|
@@ -1803,8 +1721,8 @@ class MathInput extends React.Component {
|
|
|
1803
1721
|
this.props.keypadElement && this.props.keypadElement.setCursor({
|
|
1804
1722
|
context: this.mathField.contextForCursor(cursor)
|
|
1805
1723
|
});
|
|
1806
|
-
}
|
|
1807
|
-
|
|
1724
|
+
};
|
|
1725
|
+
this.handleTouchStart = e => {
|
|
1808
1726
|
e.stopPropagation();
|
|
1809
1727
|
|
|
1810
1728
|
// Hide the cursor handle on touch start, if the handle itself isn't
|
|
@@ -1819,7 +1737,7 @@ class MathInput extends React.Component {
|
|
|
1819
1737
|
|
|
1820
1738
|
// Make the cursor visible and set the handle-less cursor's
|
|
1821
1739
|
// location.
|
|
1822
|
-
|
|
1740
|
+
const touch = e.changedTouches[0];
|
|
1823
1741
|
this._insertCursorAtClosestNode(touch.clientX, touch.clientY);
|
|
1824
1742
|
}
|
|
1825
1743
|
|
|
@@ -1827,8 +1745,8 @@ class MathInput extends React.Component {
|
|
|
1827
1745
|
if (!this.state.focused) {
|
|
1828
1746
|
this.focus();
|
|
1829
1747
|
}
|
|
1830
|
-
}
|
|
1831
|
-
|
|
1748
|
+
};
|
|
1749
|
+
this.handleTouchMove = e => {
|
|
1832
1750
|
e.stopPropagation();
|
|
1833
1751
|
|
|
1834
1752
|
// Update the handle-less cursor's location on move, if there's any
|
|
@@ -1838,11 +1756,11 @@ class MathInput extends React.Component {
|
|
|
1838
1756
|
// the cursor is no longer visible and the input is no longer
|
|
1839
1757
|
// highlighted).
|
|
1840
1758
|
if (this.mathField.getContent() !== "" && this.state.focused) {
|
|
1841
|
-
|
|
1759
|
+
const touch = e.changedTouches[0];
|
|
1842
1760
|
this._insertCursorAtClosestNode(touch.clientX, touch.clientY);
|
|
1843
1761
|
}
|
|
1844
|
-
}
|
|
1845
|
-
|
|
1762
|
+
};
|
|
1763
|
+
this.handleTouchEnd = e => {
|
|
1846
1764
|
e.stopPropagation();
|
|
1847
1765
|
|
|
1848
1766
|
// And on touch-end, reveal the cursor, unless the input is empty. Note
|
|
@@ -1853,8 +1771,8 @@ class MathInput extends React.Component {
|
|
|
1853
1771
|
if (this.mathField.getContent() !== "" && this.state.focused) {
|
|
1854
1772
|
this._updateCursorHandle();
|
|
1855
1773
|
}
|
|
1856
|
-
}
|
|
1857
|
-
|
|
1774
|
+
};
|
|
1775
|
+
this.onCursorHandleTouchStart = e => {
|
|
1858
1776
|
// NOTE(charlie): The cursor handle is a child of this view, so whenever
|
|
1859
1777
|
// it receives a touch event, that event would also typically be bubbled
|
|
1860
1778
|
// up to our own handlers. However, we want the cursor to handle its own
|
|
@@ -1867,8 +1785,8 @@ class MathInput extends React.Component {
|
|
|
1867
1785
|
|
|
1868
1786
|
// Cache the container bounds, so as to avoid re-computing.
|
|
1869
1787
|
this._containerBounds = this._container.getBoundingClientRect();
|
|
1870
|
-
}
|
|
1871
|
-
|
|
1788
|
+
};
|
|
1789
|
+
this._constrainToBound = (value, min, max, friction) => {
|
|
1872
1790
|
if (value < min) {
|
|
1873
1791
|
return min + (value - min) * friction;
|
|
1874
1792
|
} else if (value > max) {
|
|
@@ -1876,13 +1794,13 @@ class MathInput extends React.Component {
|
|
|
1876
1794
|
} else {
|
|
1877
1795
|
return value;
|
|
1878
1796
|
}
|
|
1879
|
-
}
|
|
1880
|
-
|
|
1797
|
+
};
|
|
1798
|
+
this.onCursorHandleTouchMove = e => {
|
|
1881
1799
|
e.stopPropagation();
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1800
|
+
const x = e.changedTouches[0].clientX;
|
|
1801
|
+
const y = e.changedTouches[0].clientY;
|
|
1802
|
+
const relativeX = x - this._containerBounds.left;
|
|
1803
|
+
const relativeY = y - 2 * cursorHandleRadiusPx * cursorHandleDistanceMultiplier - this._containerBounds.top;
|
|
1886
1804
|
|
|
1887
1805
|
// We subtract the containerBounds left/top to correct for the
|
|
1888
1806
|
// MathInput's position on the page. On top of that, we subtract an
|
|
@@ -1905,20 +1823,20 @@ class MathInput extends React.Component {
|
|
|
1905
1823
|
// Use a y-coordinate that's just above where the user is actually
|
|
1906
1824
|
// touching because they're dragging the handle which is a little
|
|
1907
1825
|
// below where the cursor actually is.
|
|
1908
|
-
|
|
1909
|
-
|
|
1826
|
+
const distanceAboveFingerToTrySelecting = 22;
|
|
1827
|
+
const adjustedY = y - distanceAboveFingerToTrySelecting;
|
|
1910
1828
|
this._insertCursorAtClosestNode(x, adjustedY);
|
|
1911
|
-
}
|
|
1912
|
-
|
|
1829
|
+
};
|
|
1830
|
+
this.onCursorHandleTouchEnd = e => {
|
|
1913
1831
|
e.stopPropagation();
|
|
1914
1832
|
this._updateCursorHandle(true);
|
|
1915
|
-
}
|
|
1916
|
-
|
|
1833
|
+
};
|
|
1834
|
+
this.onCursorHandleTouchCancel = e => {
|
|
1917
1835
|
e.stopPropagation();
|
|
1918
1836
|
this._updateCursorHandle(true);
|
|
1919
|
-
}
|
|
1920
|
-
|
|
1921
|
-
|
|
1837
|
+
};
|
|
1838
|
+
this.domKeyToMathQuillKey = key => {
|
|
1839
|
+
const keyMap = {
|
|
1922
1840
|
"+": Keys.PLUS,
|
|
1923
1841
|
"-": Keys.MINUS,
|
|
1924
1842
|
"*": Keys.TIMES,
|
|
@@ -1933,7 +1851,7 @@ class MathInput extends React.Component {
|
|
|
1933
1851
|
|
|
1934
1852
|
// Numbers
|
|
1935
1853
|
if (["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"].includes(key)) {
|
|
1936
|
-
return
|
|
1854
|
+
return `NUM_${key}`;
|
|
1937
1855
|
}
|
|
1938
1856
|
|
|
1939
1857
|
// Movement keys
|
|
@@ -1948,31 +1866,31 @@ class MathInput extends React.Component {
|
|
|
1948
1866
|
|
|
1949
1867
|
// The key pressed doesn't map to any of the math input operators
|
|
1950
1868
|
return null;
|
|
1951
|
-
}
|
|
1952
|
-
|
|
1953
|
-
|
|
1869
|
+
};
|
|
1870
|
+
this.handleKeyUp = event => {
|
|
1871
|
+
const mathQuillKey = this.domKeyToMathQuillKey(event.key);
|
|
1954
1872
|
if (mathQuillKey) {
|
|
1955
1873
|
this.mathField.pressKey(mathQuillKey);
|
|
1956
1874
|
|
|
1957
1875
|
// TODO(diedra): If the new value being added is off-screen to the right
|
|
1958
1876
|
// due to the max-width of the text box, scroll the box to show the newest
|
|
1959
1877
|
// value
|
|
1960
|
-
|
|
1878
|
+
const value = this.mathField.getContent();
|
|
1961
1879
|
if (this.props.value !== value) {
|
|
1962
1880
|
this.mathField.setContent(this.props.value);
|
|
1963
1881
|
this.props.onChange(value, false);
|
|
1964
1882
|
this._hideCursorHandle();
|
|
1965
1883
|
}
|
|
1966
1884
|
}
|
|
1967
|
-
}
|
|
1968
|
-
|
|
1885
|
+
};
|
|
1886
|
+
this.getBorderWidthPx = () => {
|
|
1969
1887
|
// TODO(diedra): Move these to the common style package.
|
|
1970
|
-
|
|
1971
|
-
|
|
1888
|
+
const normalBorderWidthPx = 1;
|
|
1889
|
+
const focusedBorderWidthPx = 2;
|
|
1972
1890
|
return this.state.focused ? focusedBorderWidthPx : normalBorderWidthPx;
|
|
1973
|
-
}
|
|
1974
|
-
|
|
1975
|
-
|
|
1891
|
+
};
|
|
1892
|
+
this.getInputInnerPadding = () => {
|
|
1893
|
+
const paddingInset = totalDesiredPadding - this.getBorderWidthPx();
|
|
1976
1894
|
|
|
1977
1895
|
// Now, translate that to the appropriate padding for each direction.
|
|
1978
1896
|
// The complication here is that we want numerals to be centered within
|
|
@@ -1980,16 +1898,16 @@ class MathInput extends React.Component {
|
|
|
1980
1898
|
// numerals with approximately 3px of padding below and 1px of padding
|
|
1981
1899
|
// above (to make room for ascenders and descenders). So we ignore those
|
|
1982
1900
|
// padding values for the vertical directions.
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1901
|
+
const symbolaPaddingBottom = 3;
|
|
1902
|
+
const symbolaPaddingTop = 1;
|
|
1903
|
+
const padding = {
|
|
1986
1904
|
paddingTop: paddingInset - symbolaPaddingTop,
|
|
1987
1905
|
paddingRight: paddingInset,
|
|
1988
1906
|
paddingBottom: paddingInset - symbolaPaddingBottom,
|
|
1989
1907
|
paddingLeft: paddingInset
|
|
1990
1908
|
};
|
|
1991
1909
|
return padding;
|
|
1992
|
-
}
|
|
1910
|
+
};
|
|
1993
1911
|
}
|
|
1994
1912
|
componentDidMount() {
|
|
1995
1913
|
this._isMounted = true;
|
|
@@ -2036,11 +1954,11 @@ class MathInput extends React.Component {
|
|
|
2036
1954
|
// to dismiss the keypad on check.
|
|
2037
1955
|
// TODO(charlie): Inject this logic.
|
|
2038
1956
|
if (!this._container.contains(evt.target)) {
|
|
2039
|
-
|
|
1957
|
+
let touchDidStartInOrBelowKeypad = false;
|
|
2040
1958
|
if (this.props.keypadElement && this.props.keypadElement.getDOMNode()) {
|
|
2041
|
-
|
|
2042
|
-
for (
|
|
2043
|
-
|
|
1959
|
+
const bounds = this._getKeypadBounds();
|
|
1960
|
+
for (let i = 0; i < evt.changedTouches.length; i++) {
|
|
1961
|
+
const [x, y] = [evt.changedTouches[i].clientX, evt.changedTouches[i].clientY];
|
|
2044
1962
|
if (bounds.left <= x && bounds.right >= x && bounds.top <= y && bounds.bottom >= y || bounds.bottom < y) {
|
|
2045
1963
|
touchDidStartInOrBelowKeypad = true;
|
|
2046
1964
|
break;
|
|
@@ -2115,18 +2033,18 @@ class MathInput extends React.Component {
|
|
|
2115
2033
|
this._clearKeypadBoundsCache());
|
|
2116
2034
|
}
|
|
2117
2035
|
render() {
|
|
2118
|
-
|
|
2036
|
+
const {
|
|
2119
2037
|
focused,
|
|
2120
2038
|
handle
|
|
2121
2039
|
} = this.state;
|
|
2122
|
-
|
|
2040
|
+
const {
|
|
2123
2041
|
style
|
|
2124
2042
|
} = this.props;
|
|
2125
|
-
|
|
2043
|
+
const innerStyle = _extends({}, inlineStyles$1.innerContainer, {
|
|
2126
2044
|
borderWidth: this.getBorderWidthPx()
|
|
2127
2045
|
}, focused ? {
|
|
2128
2046
|
borderColor: wonderBlocksBlue
|
|
2129
|
-
} : {}
|
|
2047
|
+
} : {}, style);
|
|
2130
2048
|
|
|
2131
2049
|
// NOTE(diedra): This label explicitly refers to tapping because this field
|
|
2132
2050
|
// is currently only seen if the user is using a mobile device.
|
|
@@ -2135,7 +2053,7 @@ class MathInput extends React.Component {
|
|
|
2135
2053
|
// keyboard appear. It should only require one finger, which is how iOS works.
|
|
2136
2054
|
// TODO(diedra): Fix the bug that is causing Android to require a two finger tap
|
|
2137
2055
|
// to the open the keyboard, and then remove the second half of this label.
|
|
2138
|
-
|
|
2056
|
+
const ariaLabel = i18n._("Math input box") + " " + i18n._("Tap with one or two fingers to open keyboard");
|
|
2139
2057
|
return /*#__PURE__*/React.createElement(View, {
|
|
2140
2058
|
style: styles$e.input,
|
|
2141
2059
|
onTouchStart: this.handleTouchStart,
|
|
@@ -2166,12 +2084,12 @@ class MathInput extends React.Component {
|
|
|
2166
2084
|
})));
|
|
2167
2085
|
}
|
|
2168
2086
|
}
|
|
2169
|
-
|
|
2087
|
+
MathInput.defaultProps = {
|
|
2170
2088
|
style: {},
|
|
2171
2089
|
value: ""
|
|
2172
|
-
}
|
|
2173
|
-
|
|
2174
|
-
|
|
2090
|
+
};
|
|
2091
|
+
const fontSizePt = 18;
|
|
2092
|
+
const inputMaxWidth = 128;
|
|
2175
2093
|
|
|
2176
2094
|
// The height of numerals in Symbola (rendered at 18pt) is about 20px (though
|
|
2177
2095
|
// they render at 24px due to padding for ascenders and descenders). We want our
|
|
@@ -2179,11 +2097,11 @@ var inputMaxWidth = 128;
|
|
|
2179
2097
|
// edge of the input, so we use this 20px number as our 'base height' and
|
|
2180
2098
|
// account for the ascender and descender padding when computing the additional
|
|
2181
2099
|
// padding in our `render` method.
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2100
|
+
const numeralHeightPx = 20;
|
|
2101
|
+
const totalDesiredPadding = 12;
|
|
2102
|
+
const minHeightPx = numeralHeightPx + totalDesiredPadding * 2;
|
|
2103
|
+
const minWidthPx = 64;
|
|
2104
|
+
const styles$e = StyleSheet.create({
|
|
2187
2105
|
input: {
|
|
2188
2106
|
position: "relative",
|
|
2189
2107
|
display: "inline-block",
|
|
@@ -2191,7 +2109,7 @@ var styles$e = StyleSheet.create({
|
|
|
2191
2109
|
maxWidth: inputMaxWidth
|
|
2192
2110
|
}
|
|
2193
2111
|
});
|
|
2194
|
-
|
|
2112
|
+
const inlineStyles$1 = {
|
|
2195
2113
|
// Styles for the inner, MathQuill-ified input element. It's important that
|
|
2196
2114
|
// these are done with regular inline styles rather than Aphrodite classes
|
|
2197
2115
|
// as MathQuill adds CSS class names to the element outside of the typical
|
|
@@ -2215,7 +2133,7 @@ var inlineStyles$1 = {
|
|
|
2215
2133
|
}
|
|
2216
2134
|
};
|
|
2217
2135
|
|
|
2218
|
-
|
|
2136
|
+
const KeyConfigs = {
|
|
2219
2137
|
// Basic math keys.
|
|
2220
2138
|
[Keys.PLUS]: {
|
|
2221
2139
|
type: KeyTypes.OPERATOR,
|
|
@@ -2465,13 +2383,13 @@ KeyConfigs[Keys.MANY] = {
|
|
|
2465
2383
|
};
|
|
2466
2384
|
|
|
2467
2385
|
// Add in every numeral.
|
|
2468
|
-
|
|
2469
|
-
for (
|
|
2386
|
+
const NUMBERS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
2387
|
+
for (const num of NUMBERS) {
|
|
2470
2388
|
// TODO(charlie): Consider removing the SVG icons that we have for the
|
|
2471
2389
|
// numeral keys. They can be rendered just as easily with text (though that
|
|
2472
2390
|
// would mean that we'd be using text beyond the variable key).
|
|
2473
|
-
|
|
2474
|
-
KeyConfigs[
|
|
2391
|
+
const textRepresentation = `${num}`;
|
|
2392
|
+
KeyConfigs[`NUM_${num}`] = {
|
|
2475
2393
|
type: KeyTypes.VALUE,
|
|
2476
2394
|
ariaLabel: textRepresentation,
|
|
2477
2395
|
icon: {
|
|
@@ -2482,23 +2400,23 @@ for (var num of NUMBERS) {
|
|
|
2482
2400
|
}
|
|
2483
2401
|
|
|
2484
2402
|
// Add in every variable.
|
|
2485
|
-
|
|
2486
|
-
for (
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
for (
|
|
2490
|
-
KeyConfigs[
|
|
2403
|
+
const LETTERS = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
|
|
2404
|
+
for (const letter of LETTERS) {
|
|
2405
|
+
const lowerCaseVariable = letter.toLowerCase();
|
|
2406
|
+
const upperCaseVariable = letter.toUpperCase();
|
|
2407
|
+
for (const textRepresentation of [lowerCaseVariable, upperCaseVariable]) {
|
|
2408
|
+
KeyConfigs[textRepresentation] = {
|
|
2491
2409
|
type: KeyTypes.VALUE,
|
|
2492
|
-
ariaLabel:
|
|
2410
|
+
ariaLabel: textRepresentation,
|
|
2493
2411
|
icon: {
|
|
2494
2412
|
type: IconTypes.MATH,
|
|
2495
|
-
data:
|
|
2413
|
+
data: textRepresentation
|
|
2496
2414
|
}
|
|
2497
2415
|
};
|
|
2498
2416
|
}
|
|
2499
2417
|
}
|
|
2500
|
-
for (
|
|
2501
|
-
KeyConfigs[key] =
|
|
2418
|
+
for (const key of Object.keys(KeyConfigs)) {
|
|
2419
|
+
KeyConfigs[key] = _extends({
|
|
2502
2420
|
id: key,
|
|
2503
2421
|
// Default to an SVG icon indexed by the key name.
|
|
2504
2422
|
icon: {
|
|
@@ -2511,25 +2429,25 @@ for (var key of Object.keys(KeyConfigs)) {
|
|
|
2511
2429
|
/**
|
|
2512
2430
|
* React PropTypes that may be shared between components.
|
|
2513
2431
|
*/
|
|
2514
|
-
|
|
2432
|
+
const iconPropType = PropTypes.shape({
|
|
2515
2433
|
type: PropTypes.oneOf(Object.keys(IconTypes)).isRequired,
|
|
2516
2434
|
data: PropTypes.string.isRequired
|
|
2517
2435
|
});
|
|
2518
|
-
|
|
2519
|
-
|
|
2436
|
+
const keyIdPropType = PropTypes.oneOf(Object.keys(KeyConfigs));
|
|
2437
|
+
const keyConfigPropType = PropTypes.shape({
|
|
2520
2438
|
ariaLabel: PropTypes.string,
|
|
2521
2439
|
id: keyIdPropType.isRequired,
|
|
2522
2440
|
type: PropTypes.oneOf(Object.keys(KeyTypes)).isRequired,
|
|
2523
2441
|
childKeyIds: PropTypes.arrayOf(keyIdPropType),
|
|
2524
2442
|
icon: iconPropType.isRequired
|
|
2525
2443
|
});
|
|
2526
|
-
|
|
2444
|
+
const keypadConfigurationPropType = PropTypes.shape({
|
|
2527
2445
|
keypadType: PropTypes.oneOf(Object.keys(KeypadTypes)).isRequired,
|
|
2528
2446
|
extraKeys: PropTypes.arrayOf(keyIdPropType)
|
|
2529
2447
|
});
|
|
2530
2448
|
|
|
2531
2449
|
// NOTE(jared): This is no longer guaranteed to be React element
|
|
2532
|
-
|
|
2450
|
+
const keypadElementPropType = PropTypes.shape({
|
|
2533
2451
|
activate: PropTypes.func.isRequired,
|
|
2534
2452
|
dismiss: PropTypes.func.isRequired,
|
|
2535
2453
|
configure: PropTypes.func.isRequired,
|
|
@@ -2537,8 +2455,8 @@ var keypadElementPropType = PropTypes.shape({
|
|
|
2537
2455
|
setKeyHandler: PropTypes.func.isRequired,
|
|
2538
2456
|
getDOMNode: PropTypes.func.isRequired
|
|
2539
2457
|
});
|
|
2540
|
-
|
|
2541
|
-
|
|
2458
|
+
const bordersPropType = PropTypes.arrayOf(PropTypes.oneOf(Object.keys(BorderDirections)));
|
|
2459
|
+
const boundingBoxPropType = PropTypes.shape({
|
|
2542
2460
|
height: PropTypes.number,
|
|
2543
2461
|
width: PropTypes.number,
|
|
2544
2462
|
top: PropTypes.number,
|
|
@@ -2546,31 +2464,46 @@ var boundingBoxPropType = PropTypes.shape({
|
|
|
2546
2464
|
bottom: PropTypes.number,
|
|
2547
2465
|
left: PropTypes.number
|
|
2548
2466
|
});
|
|
2549
|
-
|
|
2467
|
+
const echoPropType = PropTypes.shape({
|
|
2550
2468
|
animationId: PropTypes.string.isRequired,
|
|
2551
2469
|
animationType: PropTypes.oneOf(Object.keys(EchoAnimationTypes)).isRequired,
|
|
2552
2470
|
borders: bordersPropType,
|
|
2553
2471
|
id: keyIdPropType.isRequired,
|
|
2554
2472
|
initialBounds: boundingBoxPropType.isRequired
|
|
2555
2473
|
});
|
|
2556
|
-
|
|
2557
|
-
|
|
2474
|
+
const cursorContextPropType = PropTypes.oneOf(Object.keys(CursorContexts));
|
|
2475
|
+
const popoverPropType = PropTypes.shape({
|
|
2558
2476
|
parentId: keyIdPropType.isRequired,
|
|
2559
2477
|
bounds: boundingBoxPropType.isRequired,
|
|
2560
2478
|
childKeyIds: PropTypes.arrayOf(keyIdPropType).isRequired
|
|
2561
2479
|
});
|
|
2562
2480
|
PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]);
|
|
2563
2481
|
|
|
2482
|
+
function _objectWithoutPropertiesLoose(source, excluded) {
|
|
2483
|
+
if (source == null) return {};
|
|
2484
|
+
var target = {};
|
|
2485
|
+
var sourceKeys = Object.keys(source);
|
|
2486
|
+
var key, i;
|
|
2487
|
+
|
|
2488
|
+
for (i = 0; i < sourceKeys.length; i++) {
|
|
2489
|
+
key = sourceKeys[i];
|
|
2490
|
+
if (excluded.indexOf(key) >= 0) continue;
|
|
2491
|
+
target[key] = source[key];
|
|
2492
|
+
}
|
|
2493
|
+
|
|
2494
|
+
return target;
|
|
2495
|
+
}
|
|
2496
|
+
|
|
2564
2497
|
// naming convention: verb + noun
|
|
2565
2498
|
// the noun should be one of the other properties in the object that's
|
|
2566
2499
|
// being dispatched
|
|
2567
2500
|
|
|
2568
|
-
|
|
2501
|
+
const dismissKeypad = () => {
|
|
2569
2502
|
return {
|
|
2570
2503
|
type: "DismissKeypad"
|
|
2571
2504
|
};
|
|
2572
2505
|
};
|
|
2573
|
-
|
|
2506
|
+
const activateKeypad = () => {
|
|
2574
2507
|
return {
|
|
2575
2508
|
type: "ActivateKeypad"
|
|
2576
2509
|
};
|
|
@@ -2581,20 +2514,20 @@ var activateKeypad = () => {
|
|
|
2581
2514
|
*
|
|
2582
2515
|
* See: `prop-types.js#keypadConfigurationPropType`.
|
|
2583
2516
|
*/
|
|
2584
|
-
|
|
2517
|
+
const configureKeypad = configuration => {
|
|
2585
2518
|
return {
|
|
2586
2519
|
type: "ConfigureKeypad",
|
|
2587
2520
|
configuration
|
|
2588
2521
|
};
|
|
2589
2522
|
};
|
|
2590
|
-
|
|
2523
|
+
const setPageSize = (pageWidthPx, pageHeightPx) => {
|
|
2591
2524
|
return {
|
|
2592
2525
|
type: "SetPageSize",
|
|
2593
2526
|
pageWidthPx,
|
|
2594
2527
|
pageHeightPx
|
|
2595
2528
|
};
|
|
2596
2529
|
};
|
|
2597
|
-
|
|
2530
|
+
const removeEcho = animationId => {
|
|
2598
2531
|
return {
|
|
2599
2532
|
type: "RemoveEcho",
|
|
2600
2533
|
animationId
|
|
@@ -2602,13 +2535,13 @@ var removeEcho = animationId => {
|
|
|
2602
2535
|
};
|
|
2603
2536
|
|
|
2604
2537
|
// Input-related actions.
|
|
2605
|
-
|
|
2538
|
+
const setKeyHandler = keyHandler => {
|
|
2606
2539
|
return {
|
|
2607
2540
|
type: "SetKeyHandler",
|
|
2608
2541
|
keyHandler
|
|
2609
2542
|
};
|
|
2610
2543
|
};
|
|
2611
|
-
|
|
2544
|
+
const setCursor = cursor => {
|
|
2612
2545
|
return {
|
|
2613
2546
|
type: "SetCursor",
|
|
2614
2547
|
cursor
|
|
@@ -2635,63 +2568,59 @@ var setCursor = cursor => {
|
|
|
2635
2568
|
* to be conservative in our measurements and make things smaller than they
|
|
2636
2569
|
* might need to be.
|
|
2637
2570
|
*/
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2571
|
+
const minButtonHeight = 48;
|
|
2572
|
+
const maxButtonSize = 64;
|
|
2573
|
+
const minSpaceAboveKeypad = 32;
|
|
2641
2574
|
|
|
2642
2575
|
// These values are taken from an iPhone 5, but should be consistent with the
|
|
2643
2576
|
// iPhone 4 as well. Regardless, these are meant to be representative of the
|
|
2644
2577
|
// possible types of browser chrome that could appear in various context, rather
|
|
2645
2578
|
// than pixel-perfect for every device.
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2579
|
+
const safariNavBarWhenShrunk = 44;
|
|
2580
|
+
const safariNavBarWhenExpanded = 64;
|
|
2581
|
+
const safariToolbar = 44;
|
|
2649
2582
|
|
|
2650
2583
|
// In mobile Safari, the browser chrome is completely hidden in landscape,
|
|
2651
2584
|
// though a shrunken navbar and full-sized toolbar on scroll. In portrait, the
|
|
2652
2585
|
// shrunken navbar is always visible, but expands on scroll (and the toolbar
|
|
2653
2586
|
// appears as well).
|
|
2654
|
-
|
|
2655
|
-
|
|
2587
|
+
const maxLandscapeBrowserChrome = safariNavBarWhenShrunk + safariToolbar;
|
|
2588
|
+
const maxPortraitBrowserChrome = safariToolbar + (safariNavBarWhenExpanded - safariNavBarWhenShrunk);
|
|
2656
2589
|
|
|
2657
2590
|
// This represents the 'worst case' aspect ratio that we care about (for
|
|
2658
2591
|
// portrait layouts). It's taken from the iPhone 4. The height is computed by
|
|
2659
2592
|
// taking the height of the device and removing the persistent, shrunken navbar.
|
|
2660
2593
|
// (We don't need to account for the expanded navbar, since we include the
|
|
2661
2594
|
// difference when reserving space above the keypad.)
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
navigationPadEnabled,
|
|
2679
|
-
paginationEnabled,
|
|
2680
|
-
toolbarEnabled
|
|
2681
|
-
} = _ref4;
|
|
2595
|
+
const worstCaseAspectRatio = 320 / (480 - safariNavBarWhenShrunk);
|
|
2596
|
+
const computeLayoutParameters = ({
|
|
2597
|
+
numColumns,
|
|
2598
|
+
numMaxVisibleRows,
|
|
2599
|
+
numPages
|
|
2600
|
+
}, {
|
|
2601
|
+
pageWidthPx,
|
|
2602
|
+
pageHeightPx
|
|
2603
|
+
}, {
|
|
2604
|
+
deviceOrientation,
|
|
2605
|
+
deviceType
|
|
2606
|
+
}, {
|
|
2607
|
+
navigationPadEnabled,
|
|
2608
|
+
paginationEnabled,
|
|
2609
|
+
toolbarEnabled
|
|
2610
|
+
}) => {
|
|
2682
2611
|
// First, compute some values that will be used in multiple computations.
|
|
2683
|
-
|
|
2612
|
+
const effectiveNumColumns = paginationEnabled ? numColumns : numColumns * numPages;
|
|
2684
2613
|
|
|
2685
2614
|
// Then, compute the button dimensions based on the provided parameters.
|
|
2686
|
-
|
|
2615
|
+
let buttonDimensions;
|
|
2687
2616
|
if (deviceType === DeviceTypes.PHONE) {
|
|
2688
|
-
|
|
2617
|
+
const isLandscape = deviceOrientation === DeviceOrientations.LANDSCAPE;
|
|
2689
2618
|
|
|
2690
2619
|
// In many cases, the browser chrome will already have been factored
|
|
2691
2620
|
// into `pageHeightPx`. But we have no way of knowing if that's
|
|
2692
2621
|
// the case or not. As such, we take a conservative approach and
|
|
2693
2622
|
// assume that the chrome is _never_ included in `pageHeightPx`.
|
|
2694
|
-
|
|
2623
|
+
const browserChromeHeight = isLandscape ? maxLandscapeBrowserChrome : maxPortraitBrowserChrome;
|
|
2695
2624
|
|
|
2696
2625
|
// Count up all the space that we need to reserve on the page.
|
|
2697
2626
|
// Namely, we need to account for:
|
|
@@ -2699,7 +2628,7 @@ var computeLayoutParameters = (_ref, _ref2, _ref3, _ref4) => {
|
|
|
2699
2628
|
// 2. The presence of the exercise toolbar.
|
|
2700
2629
|
// 3. The presence of the view pager indicator.
|
|
2701
2630
|
// 4. Any browser chrome that may appear later.
|
|
2702
|
-
|
|
2631
|
+
const reservedSpace = minSpaceAboveKeypad + browserChromeHeight + (toolbarEnabled ? toolbarHeightPx : 0) + (paginationEnabled ? pageIndicatorHeightPx : 0);
|
|
2703
2632
|
|
|
2704
2633
|
// Next, compute the effective width and height. We can use the page
|
|
2705
2634
|
// width as the effective width. For the height, though, we take
|
|
@@ -2708,18 +2637,18 @@ var computeLayoutParameters = (_ref, _ref2, _ref3, _ref4) => {
|
|
|
2708
2637
|
// we ignore the device height in portrait and assume the worst.
|
|
2709
2638
|
// This prevents the keypad from changing size when browser chrome
|
|
2710
2639
|
// appears and disappears.
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2640
|
+
const effectiveWidth = pageWidthPx;
|
|
2641
|
+
const effectiveHeight = isLandscape ? pageHeightPx : pageWidthPx / worstCaseAspectRatio;
|
|
2642
|
+
const maxKeypadHeight = effectiveHeight - reservedSpace;
|
|
2714
2643
|
|
|
2715
2644
|
// Finally, compute the button height and width. In computing the
|
|
2716
2645
|
// height, accommodate for the maximum number of rows that will ever be
|
|
2717
2646
|
// visible (since the toggling of popovers can increase the number of
|
|
2718
2647
|
// visible rows).
|
|
2719
|
-
|
|
2720
|
-
|
|
2648
|
+
const buttonHeightPx = Math.max(Math.min(maxKeypadHeight / numMaxVisibleRows, maxButtonSize), minButtonHeight);
|
|
2649
|
+
let buttonWidthPx;
|
|
2721
2650
|
if (numPages > 1) {
|
|
2722
|
-
|
|
2651
|
+
const _effectiveNumColumns = paginationEnabled ? numColumns : numColumns * numPages;
|
|
2723
2652
|
buttonWidthPx = effectiveWidth / _effectiveNumColumns;
|
|
2724
2653
|
} else {
|
|
2725
2654
|
buttonWidthPx = isLandscape ? maxButtonSize : effectiveWidth / numColumns;
|
|
@@ -2739,8 +2668,8 @@ var computeLayoutParameters = (_ref, _ref2, _ref3, _ref4) => {
|
|
|
2739
2668
|
|
|
2740
2669
|
// Finally, determine whether the keypad should be rendered in the
|
|
2741
2670
|
// fullscreen layout by determining its resultant width.
|
|
2742
|
-
|
|
2743
|
-
|
|
2671
|
+
const numSeparators = (navigationPadEnabled ? 1 : 0) + (!paginationEnabled ? numPages - 1 : 0);
|
|
2672
|
+
const keypadWidth = effectiveNumColumns * buttonDimensions.widthPx + (navigationPadEnabled ? navigationPadWidthPx : 0) + numSeparators * innerBorderWidthPx;
|
|
2744
2673
|
return {
|
|
2745
2674
|
buttonDimensions,
|
|
2746
2675
|
layoutMode: keypadWidth >= pageWidthPx ? LayoutModes.FULLSCREEN : LayoutModes.COMPACT
|
|
@@ -2755,7 +2684,7 @@ var computeLayoutParameters = (_ref, _ref2, _ref3, _ref4) => {
|
|
|
2755
2684
|
* multi-touch interactions, tracking gesture state on a per-touch basis.
|
|
2756
2685
|
*/
|
|
2757
2686
|
|
|
2758
|
-
|
|
2687
|
+
const defaults = {
|
|
2759
2688
|
longPressWaitTimeMs: 50,
|
|
2760
2689
|
swipeThresholdPx: 20,
|
|
2761
2690
|
holdIntervalMs: 250
|
|
@@ -2763,34 +2692,34 @@ var defaults = {
|
|
|
2763
2692
|
class GestureStateMachine {
|
|
2764
2693
|
constructor(handlers, options, swipeDisabledNodeIds, multiPressableKeys) {
|
|
2765
2694
|
this.handlers = handlers;
|
|
2766
|
-
this.options =
|
|
2695
|
+
this.options = _extends({}, defaults, options);
|
|
2767
2696
|
this.swipeDisabledNodeIds = swipeDisabledNodeIds || [];
|
|
2768
2697
|
this.multiPressableKeys = multiPressableKeys || [];
|
|
2769
2698
|
|
|
2770
|
-
// TODO(charlie):
|
|
2699
|
+
// TODO(charlie): Add types for this file. It's not great that we're now
|
|
2771
2700
|
// passing around these opaque state objects.
|
|
2772
2701
|
this.touchState = {};
|
|
2773
2702
|
this.swipeState = null;
|
|
2774
2703
|
}
|
|
2775
2704
|
_maybeCancelLongPressForTouch(touchId) {
|
|
2776
|
-
|
|
2705
|
+
const {
|
|
2777
2706
|
longPressTimeoutId
|
|
2778
2707
|
} = this.touchState[touchId];
|
|
2779
2708
|
if (longPressTimeoutId) {
|
|
2780
2709
|
clearTimeout(longPressTimeoutId);
|
|
2781
|
-
this.touchState[touchId] =
|
|
2710
|
+
this.touchState[touchId] = _extends({}, this.touchState[touchId], {
|
|
2782
2711
|
longPressTimeoutId: null
|
|
2783
2712
|
});
|
|
2784
2713
|
}
|
|
2785
2714
|
}
|
|
2786
2715
|
_maybeCancelPressAndHoldForTouch(touchId) {
|
|
2787
|
-
|
|
2716
|
+
const {
|
|
2788
2717
|
pressAndHoldIntervalId
|
|
2789
2718
|
} = this.touchState[touchId];
|
|
2790
2719
|
if (pressAndHoldIntervalId) {
|
|
2791
2720
|
// If there was an interval set to detect holds, clear it out.
|
|
2792
2721
|
clearInterval(pressAndHoldIntervalId);
|
|
2793
|
-
this.touchState[touchId] =
|
|
2722
|
+
this.touchState[touchId] = _extends({}, this.touchState[touchId], {
|
|
2794
2723
|
pressAndHoldIntervalId: null
|
|
2795
2724
|
});
|
|
2796
2725
|
}
|
|
@@ -2823,7 +2752,7 @@ class GestureStateMachine {
|
|
|
2823
2752
|
// indicates that a gesture that can focus future nodes is still in
|
|
2824
2753
|
// progress, but that no node is currently focused. The latter
|
|
2825
2754
|
// indicates that the gesture has ended and nothing will be focused.
|
|
2826
|
-
this.touchState[touchId] =
|
|
2755
|
+
this.touchState[touchId] = _extends({}, this.touchState[touchId], {
|
|
2827
2756
|
activeNodeId: id
|
|
2828
2757
|
});
|
|
2829
2758
|
this.handlers.onFocus(id);
|
|
@@ -2834,7 +2763,7 @@ class GestureStateMachine {
|
|
|
2834
2763
|
this.handlers.onTrigger(id);
|
|
2835
2764
|
|
|
2836
2765
|
// Set up a new hold detector for the current button.
|
|
2837
|
-
this.touchState[touchId] =
|
|
2766
|
+
this.touchState[touchId] = _extends({}, this.touchState[touchId], {
|
|
2838
2767
|
pressAndHoldIntervalId: setInterval(() => {
|
|
2839
2768
|
// On every cycle, trigger the click handler.
|
|
2840
2769
|
this.handlers.onTrigger(id);
|
|
@@ -2842,10 +2771,10 @@ class GestureStateMachine {
|
|
|
2842
2771
|
});
|
|
2843
2772
|
} else {
|
|
2844
2773
|
// Set up a new hold detector for the current button.
|
|
2845
|
-
this.touchState[touchId] =
|
|
2774
|
+
this.touchState[touchId] = _extends({}, this.touchState[touchId], {
|
|
2846
2775
|
longPressTimeoutId: setTimeout(() => {
|
|
2847
2776
|
this.handlers.onLongPress(id);
|
|
2848
|
-
this.touchState[touchId] =
|
|
2777
|
+
this.touchState[touchId] = _extends({}, this.touchState[touchId], {
|
|
2849
2778
|
longPressTimeoutId: null
|
|
2850
2779
|
});
|
|
2851
2780
|
}, this.options.longPressWaitTimeMs)
|
|
@@ -2858,7 +2787,7 @@ class GestureStateMachine {
|
|
|
2858
2787
|
* Clear out all active gesture information.
|
|
2859
2788
|
*/
|
|
2860
2789
|
_onSwipeStart() {
|
|
2861
|
-
for (
|
|
2790
|
+
for (const activeTouchId of Object.keys(this.touchState)) {
|
|
2862
2791
|
this._maybeCancelLongPressForTouch(activeTouchId);
|
|
2863
2792
|
this._maybeCancelPressAndHoldForTouch(activeTouchId);
|
|
2864
2793
|
}
|
|
@@ -2901,7 +2830,7 @@ class GestureStateMachine {
|
|
|
2901
2830
|
// here anyways.
|
|
2902
2831
|
return;
|
|
2903
2832
|
}
|
|
2904
|
-
|
|
2833
|
+
const startingNodeId = getId();
|
|
2905
2834
|
this.touchState[touchId] = {
|
|
2906
2835
|
swipeLocked: this.swipeDisabledNodeIds.includes(startingNodeId),
|
|
2907
2836
|
startX: pageX
|
|
@@ -2929,13 +2858,13 @@ class GestureStateMachine {
|
|
|
2929
2858
|
} else if (this.touchState[touchId]) {
|
|
2930
2859
|
// It could be touch events started outside the keypad and
|
|
2931
2860
|
// moved into it; ignore them.
|
|
2932
|
-
|
|
2861
|
+
const {
|
|
2933
2862
|
activeNodeId,
|
|
2934
2863
|
startX,
|
|
2935
2864
|
swipeLocked
|
|
2936
2865
|
} = this.touchState[touchId];
|
|
2937
|
-
|
|
2938
|
-
|
|
2866
|
+
const dx = pageX - startX;
|
|
2867
|
+
const shouldBeginSwiping = swipeEnabled && !swipeLocked && Math.abs(dx) > this.options.swipeThresholdPx;
|
|
2939
2868
|
if (shouldBeginSwiping) {
|
|
2940
2869
|
this._onSwipeStart();
|
|
2941
2870
|
|
|
@@ -2946,7 +2875,7 @@ class GestureStateMachine {
|
|
|
2946
2875
|
};
|
|
2947
2876
|
this.handlers.onSwipeChange(pageX - this.swipeState.startX);
|
|
2948
2877
|
} else {
|
|
2949
|
-
|
|
2878
|
+
const id = getId();
|
|
2950
2879
|
if (id !== activeNodeId) {
|
|
2951
2880
|
this._onFocus(id, touchId);
|
|
2952
2881
|
}
|
|
@@ -2973,12 +2902,12 @@ class GestureStateMachine {
|
|
|
2973
2902
|
} else if (this.touchState[touchId]) {
|
|
2974
2903
|
// It could be touch events started outside the keypad and
|
|
2975
2904
|
// moved into it; ignore them.
|
|
2976
|
-
|
|
2905
|
+
const {
|
|
2977
2906
|
activeNodeId,
|
|
2978
2907
|
pressAndHoldIntervalId
|
|
2979
2908
|
} = this.touchState[touchId];
|
|
2980
2909
|
this._cleanupTouchEvent(touchId);
|
|
2981
|
-
|
|
2910
|
+
const didPressAndHold = !!pressAndHoldIntervalId;
|
|
2982
2911
|
if (didPressAndHold) {
|
|
2983
2912
|
// We don't trigger a touch end if there was a press and hold,
|
|
2984
2913
|
// because the key has been triggered at least once and calling
|
|
@@ -3066,12 +2995,12 @@ class NodeManager {
|
|
|
3066
2995
|
// Make sure that any children appear first.
|
|
3067
2996
|
// TODO(charlie): This is a very simplistic system that wouldn't
|
|
3068
2997
|
// properly handle multiple levels of nesting.
|
|
3069
|
-
|
|
2998
|
+
const allIds = [...(childIds || []), id, ...this._orderedIds];
|
|
3070
2999
|
|
|
3071
3000
|
// De-dupe the list of IDs.
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
for (
|
|
3001
|
+
const orderedIds = [];
|
|
3002
|
+
const seenIds = {};
|
|
3003
|
+
for (const _id of allIds) {
|
|
3075
3004
|
if (!seenIds[_id]) {
|
|
3076
3005
|
orderedIds.push(_id);
|
|
3077
3006
|
seenIds[_id] = true;
|
|
@@ -3099,10 +3028,10 @@ class NodeManager {
|
|
|
3099
3028
|
* the given coordinates
|
|
3100
3029
|
*/
|
|
3101
3030
|
idForCoords(x, y) {
|
|
3102
|
-
for (
|
|
3103
|
-
|
|
3031
|
+
for (const id of this._orderedIds) {
|
|
3032
|
+
const domNode = this._nodesById[id];
|
|
3104
3033
|
if (domNode) {
|
|
3105
|
-
|
|
3034
|
+
const bounds = domNode.getBoundingClientRect();
|
|
3106
3035
|
if (bounds.left <= x && bounds.right > x && bounds.top <= y && bounds.bottom > y) {
|
|
3107
3036
|
this._cachedBoundingBoxesById[id] = bounds;
|
|
3108
3037
|
return id;
|
|
@@ -3122,7 +3051,7 @@ class NodeManager {
|
|
|
3122
3051
|
*/
|
|
3123
3052
|
layoutPropsForId(id) {
|
|
3124
3053
|
if (!this._cachedBoundingBoxesById[id]) {
|
|
3125
|
-
|
|
3054
|
+
const node = this._nodesById[id];
|
|
3126
3055
|
this._cachedBoundingBoxesById[id] = node ? node.getBoundingClientRect() : new DOMRect();
|
|
3127
3056
|
}
|
|
3128
3057
|
return {
|
|
@@ -3261,7 +3190,7 @@ class PopoverStateMachine {
|
|
|
3261
3190
|
* ended
|
|
3262
3191
|
*/
|
|
3263
3192
|
onTouchEnd(id) {
|
|
3264
|
-
|
|
3193
|
+
const inPopover = !!this.activePopover;
|
|
3265
3194
|
if (inPopover) {
|
|
3266
3195
|
// If we have a popover that is currently active, we trigger a
|
|
3267
3196
|
// click on this node if and only if it's in the popover, with the
|
|
@@ -3275,16 +3204,16 @@ class PopoverStateMachine {
|
|
|
3275
3204
|
if (this._isNodeInsidePopover(this.activePopover, id)) {
|
|
3276
3205
|
this.handlers.onClick(id, id, inPopover);
|
|
3277
3206
|
} else if (this.activePopover === id) {
|
|
3278
|
-
|
|
3207
|
+
const keyId = this._defaultNodeForPopover(id);
|
|
3279
3208
|
this.handlers.onClick(keyId, keyId, inPopover);
|
|
3280
3209
|
}
|
|
3281
3210
|
} else if (this.popovers[id]) {
|
|
3282
3211
|
// Otherwise, if the node is itself a popover revealer, trigger the
|
|
3283
3212
|
// clicking of its default node, but pass back the popover node ID
|
|
3284
3213
|
// for layout purposes.
|
|
3285
|
-
|
|
3286
|
-
|
|
3287
|
-
this.handlers.onClick(
|
|
3214
|
+
const keyId = this._defaultNodeForPopover(id);
|
|
3215
|
+
const domNodeId = id;
|
|
3216
|
+
this.handlers.onClick(keyId, domNodeId, inPopover);
|
|
3288
3217
|
} else if (id != null) {
|
|
3289
3218
|
// Finally, if we have no active popover, and we touched up over a
|
|
3290
3219
|
// valid key, trigger a click.
|
|
@@ -3300,13 +3229,13 @@ class PopoverStateMachine {
|
|
|
3300
3229
|
}
|
|
3301
3230
|
}
|
|
3302
3231
|
|
|
3303
|
-
|
|
3304
|
-
|
|
3232
|
+
const _excluded$5 = ["popover"];
|
|
3233
|
+
const coordsForEvent = evt => {
|
|
3305
3234
|
return [evt.changedTouches[0].clientX, evt.changedTouches[0].clientY];
|
|
3306
3235
|
};
|
|
3307
3236
|
class GestureManager {
|
|
3308
3237
|
constructor(options, handlers, disabledSwipeKeys, multiPressableKeys) {
|
|
3309
|
-
|
|
3238
|
+
const {
|
|
3310
3239
|
swipeEnabled
|
|
3311
3240
|
} = options;
|
|
3312
3241
|
this.swipeEnabled = swipeEnabled;
|
|
@@ -3316,11 +3245,11 @@ class GestureManager {
|
|
|
3316
3245
|
this.nodeManager = new NodeManager();
|
|
3317
3246
|
this.popoverStateMachine = new PopoverStateMachine({
|
|
3318
3247
|
onActiveNodesChanged: activeNodes => {
|
|
3319
|
-
|
|
3248
|
+
const {
|
|
3320
3249
|
popover
|
|
3321
3250
|
} = activeNodes,
|
|
3322
|
-
rest =
|
|
3323
|
-
handlers.onActiveNodesChanged(
|
|
3251
|
+
rest = _objectWithoutPropertiesLoose(activeNodes, _excluded$5);
|
|
3252
|
+
handlers.onActiveNodesChanged(_extends({
|
|
3324
3253
|
popover: popover && {
|
|
3325
3254
|
parentId: popover.parentId,
|
|
3326
3255
|
bounds: this.nodeManager.layoutPropsForId(popover.parentId).initialBounds,
|
|
@@ -3381,13 +3310,13 @@ class GestureManager {
|
|
|
3381
3310
|
if (!this.trackEvents) {
|
|
3382
3311
|
return;
|
|
3383
3312
|
}
|
|
3384
|
-
|
|
3313
|
+
const [x] = coordsForEvent(evt);
|
|
3385
3314
|
|
|
3386
3315
|
// TODO(charlie): It doesn't seem to be guaranteed that every touch
|
|
3387
3316
|
// event on `changedTouches` originates from the node through which this
|
|
3388
3317
|
// touch event was sent. In that case, we'd be inappropriately reporting
|
|
3389
3318
|
// the starting node ID.
|
|
3390
|
-
for (
|
|
3319
|
+
for (let i = 0; i < evt.changedTouches.length; i++) {
|
|
3391
3320
|
this.gestureStateMachine.onTouchStart(() => id, evt.changedTouches[i].identifier, x);
|
|
3392
3321
|
}
|
|
3393
3322
|
|
|
@@ -3406,10 +3335,10 @@ class GestureManager {
|
|
|
3406
3335
|
if (!this.trackEvents) {
|
|
3407
3336
|
return;
|
|
3408
3337
|
}
|
|
3409
|
-
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
for (
|
|
3338
|
+
const swipeLocked = this.popoverStateMachine.isPopoverVisible();
|
|
3339
|
+
const swipeEnabled = this.swipeEnabled && !swipeLocked;
|
|
3340
|
+
const [x, y] = coordsForEvent(evt);
|
|
3341
|
+
for (let i = 0; i < evt.changedTouches.length; i++) {
|
|
3413
3342
|
this.gestureStateMachine.onTouchMove(() => this.nodeManager.idForCoords(x, y), evt.changedTouches[i].identifier, x, swipeEnabled);
|
|
3414
3343
|
}
|
|
3415
3344
|
}
|
|
@@ -3424,8 +3353,8 @@ class GestureManager {
|
|
|
3424
3353
|
if (!this.trackEvents) {
|
|
3425
3354
|
return;
|
|
3426
3355
|
}
|
|
3427
|
-
|
|
3428
|
-
for (
|
|
3356
|
+
const [x, y] = coordsForEvent(evt);
|
|
3357
|
+
for (let i = 0; i < evt.changedTouches.length; i++) {
|
|
3429
3358
|
this.gestureStateMachine.onTouchEnd(() => this.nodeManager.idForCoords(x, y), evt.changedTouches[i].identifier, x);
|
|
3430
3359
|
}
|
|
3431
3360
|
}
|
|
@@ -3440,7 +3369,7 @@ class GestureManager {
|
|
|
3440
3369
|
if (!this.trackEvents) {
|
|
3441
3370
|
return;
|
|
3442
3371
|
}
|
|
3443
|
-
for (
|
|
3372
|
+
for (let i = 0; i < evt.changedTouches.length; i++) {
|
|
3444
3373
|
this.gestureStateMachine.onTouchCancel(evt.changedTouches[i].identifier);
|
|
3445
3374
|
}
|
|
3446
3375
|
}
|
|
@@ -3487,12 +3416,15 @@ class GestureManager {
|
|
|
3487
3416
|
}
|
|
3488
3417
|
}
|
|
3489
3418
|
|
|
3419
|
+
/**
|
|
3420
|
+
* A small triangular decal to sit in the corner of a parent component.
|
|
3421
|
+
*/
|
|
3490
3422
|
class CornerDecal extends React.Component {
|
|
3491
3423
|
render() {
|
|
3492
|
-
|
|
3424
|
+
const {
|
|
3493
3425
|
style
|
|
3494
3426
|
} = this.props;
|
|
3495
|
-
|
|
3427
|
+
const containerStyle = [styles$d.container, ...(Array.isArray(style) ? style : [style])];
|
|
3496
3428
|
return /*#__PURE__*/React.createElement(View, {
|
|
3497
3429
|
style: containerStyle
|
|
3498
3430
|
}, /*#__PURE__*/React.createElement("svg", {
|
|
@@ -3506,11 +3438,11 @@ class CornerDecal extends React.Component {
|
|
|
3506
3438
|
})));
|
|
3507
3439
|
}
|
|
3508
3440
|
}
|
|
3509
|
-
|
|
3441
|
+
CornerDecal.propTypes = {
|
|
3510
3442
|
style: PropTypes.any
|
|
3511
|
-
}
|
|
3512
|
-
|
|
3513
|
-
|
|
3443
|
+
};
|
|
3444
|
+
const triangleSizePx = 7;
|
|
3445
|
+
const styles$d = StyleSheet.create({
|
|
3514
3446
|
container: {
|
|
3515
3447
|
position: "absolute",
|
|
3516
3448
|
top: 0,
|
|
@@ -3554,19 +3486,22 @@ var Styles = StyleSheet.create({
|
|
|
3554
3486
|
}
|
|
3555
3487
|
});
|
|
3556
3488
|
|
|
3557
|
-
|
|
3489
|
+
/**
|
|
3490
|
+
* A component that renders an icon with math (via KaTeX).
|
|
3491
|
+
*/
|
|
3492
|
+
const {
|
|
3558
3493
|
row: row$7,
|
|
3559
3494
|
centered: centered$4
|
|
3560
3495
|
} = Styles;
|
|
3561
3496
|
class MathIcon extends React.Component {
|
|
3562
|
-
constructor() {
|
|
3563
|
-
super(...
|
|
3564
|
-
|
|
3565
|
-
|
|
3497
|
+
constructor(...args) {
|
|
3498
|
+
super(...args);
|
|
3499
|
+
this._renderMath = () => {
|
|
3500
|
+
const {
|
|
3566
3501
|
math
|
|
3567
3502
|
} = this.props;
|
|
3568
3503
|
katex.render(math, ReactDOM.findDOMNode(this));
|
|
3569
|
-
}
|
|
3504
|
+
};
|
|
3570
3505
|
}
|
|
3571
3506
|
componentDidMount() {
|
|
3572
3507
|
this._renderMath();
|
|
@@ -3577,20 +3512,20 @@ class MathIcon extends React.Component {
|
|
|
3577
3512
|
}
|
|
3578
3513
|
}
|
|
3579
3514
|
render() {
|
|
3580
|
-
|
|
3515
|
+
const {
|
|
3581
3516
|
style
|
|
3582
3517
|
} = this.props;
|
|
3583
|
-
|
|
3518
|
+
const containerStyle = [row$7, centered$4, styles$c.size, styles$c.base, ...(Array.isArray(style) ? style : [style])];
|
|
3584
3519
|
return /*#__PURE__*/React.createElement(View, {
|
|
3585
3520
|
style: containerStyle
|
|
3586
3521
|
});
|
|
3587
3522
|
}
|
|
3588
3523
|
}
|
|
3589
|
-
|
|
3524
|
+
MathIcon.propTypes = {
|
|
3590
3525
|
math: PropTypes.string.isRequired,
|
|
3591
3526
|
style: PropTypes.any
|
|
3592
|
-
}
|
|
3593
|
-
|
|
3527
|
+
};
|
|
3528
|
+
const styles$c = StyleSheet.create({
|
|
3594
3529
|
size: {
|
|
3595
3530
|
height: iconSizeHeightPx,
|
|
3596
3531
|
width: iconSizeWidthPx
|
|
@@ -3600,6 +3535,11 @@ var styles$c = StyleSheet.create({
|
|
|
3600
3535
|
}
|
|
3601
3536
|
});
|
|
3602
3537
|
|
|
3538
|
+
/**
|
|
3539
|
+
* An autogenerated component that renders the COS iconograpy in SVG.
|
|
3540
|
+
*
|
|
3541
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
3542
|
+
*/
|
|
3603
3543
|
class Cos extends React.Component {
|
|
3604
3544
|
render() {
|
|
3605
3545
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -3621,10 +3561,15 @@ class Cos extends React.Component {
|
|
|
3621
3561
|
})));
|
|
3622
3562
|
}
|
|
3623
3563
|
}
|
|
3624
|
-
|
|
3564
|
+
Cos.propTypes = {
|
|
3625
3565
|
color: PropTypes.string.isRequired
|
|
3626
|
-
}
|
|
3566
|
+
};
|
|
3627
3567
|
|
|
3568
|
+
/**
|
|
3569
|
+
* An autogenerated component that renders the LOG iconograpy in SVG.
|
|
3570
|
+
*
|
|
3571
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
3572
|
+
*/
|
|
3628
3573
|
class Log extends React.Component {
|
|
3629
3574
|
render() {
|
|
3630
3575
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -3643,10 +3588,15 @@ class Log extends React.Component {
|
|
|
3643
3588
|
})));
|
|
3644
3589
|
}
|
|
3645
3590
|
}
|
|
3646
|
-
|
|
3591
|
+
Log.propTypes = {
|
|
3647
3592
|
color: PropTypes.string.isRequired
|
|
3648
|
-
}
|
|
3593
|
+
};
|
|
3649
3594
|
|
|
3595
|
+
/**
|
|
3596
|
+
* An autogenerated component that renders the EQUAL iconograpy in SVG.
|
|
3597
|
+
*
|
|
3598
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
3599
|
+
*/
|
|
3650
3600
|
class Equal extends React.Component {
|
|
3651
3601
|
render() {
|
|
3652
3602
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -3671,16 +3621,16 @@ class Equal extends React.Component {
|
|
|
3671
3621
|
})));
|
|
3672
3622
|
}
|
|
3673
3623
|
}
|
|
3674
|
-
|
|
3624
|
+
Equal.propTypes = {
|
|
3675
3625
|
color: PropTypes.string.isRequired
|
|
3676
|
-
}
|
|
3626
|
+
};
|
|
3677
3627
|
|
|
3678
3628
|
/**
|
|
3679
3629
|
* An autogenerated component that renders the BACKSPACE iconograpy in SVG.
|
|
3680
3630
|
*
|
|
3681
3631
|
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
3682
3632
|
*/
|
|
3683
|
-
|
|
3633
|
+
const Backspace = () => {
|
|
3684
3634
|
return /*#__PURE__*/React.createElement("svg", {
|
|
3685
3635
|
width: "48",
|
|
3686
3636
|
height: "48",
|
|
@@ -3703,6 +3653,11 @@ var Backspace = () => {
|
|
|
3703
3653
|
})));
|
|
3704
3654
|
};
|
|
3705
3655
|
|
|
3656
|
+
/**
|
|
3657
|
+
* An autogenerated component that renders the SQRT iconograpy in SVG.
|
|
3658
|
+
*
|
|
3659
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
3660
|
+
*/
|
|
3706
3661
|
class Sqrt extends React.Component {
|
|
3707
3662
|
render() {
|
|
3708
3663
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -3724,10 +3679,15 @@ class Sqrt extends React.Component {
|
|
|
3724
3679
|
})));
|
|
3725
3680
|
}
|
|
3726
3681
|
}
|
|
3727
|
-
|
|
3682
|
+
Sqrt.propTypes = {
|
|
3728
3683
|
color: PropTypes.string.isRequired
|
|
3729
|
-
}
|
|
3684
|
+
};
|
|
3730
3685
|
|
|
3686
|
+
/**
|
|
3687
|
+
* An autogenerated component that renders the EXP iconograpy in SVG.
|
|
3688
|
+
*
|
|
3689
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
3690
|
+
*/
|
|
3731
3691
|
class Exp extends React.Component {
|
|
3732
3692
|
render() {
|
|
3733
3693
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -3746,10 +3706,15 @@ class Exp extends React.Component {
|
|
|
3746
3706
|
})));
|
|
3747
3707
|
}
|
|
3748
3708
|
}
|
|
3749
|
-
|
|
3709
|
+
Exp.propTypes = {
|
|
3750
3710
|
color: PropTypes.string.isRequired
|
|
3751
|
-
}
|
|
3711
|
+
};
|
|
3752
3712
|
|
|
3713
|
+
/**
|
|
3714
|
+
* An autogenerated component that renders the NEQ iconograpy in SVG.
|
|
3715
|
+
*
|
|
3716
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
3717
|
+
*/
|
|
3753
3718
|
class Neq extends React.Component {
|
|
3754
3719
|
render() {
|
|
3755
3720
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -3774,10 +3739,15 @@ class Neq extends React.Component {
|
|
|
3774
3739
|
})));
|
|
3775
3740
|
}
|
|
3776
3741
|
}
|
|
3777
|
-
|
|
3742
|
+
Neq.propTypes = {
|
|
3778
3743
|
color: PropTypes.string.isRequired
|
|
3779
|
-
}
|
|
3744
|
+
};
|
|
3780
3745
|
|
|
3746
|
+
/**
|
|
3747
|
+
* An autogenerated component that renders the GEQ iconograpy in SVG.
|
|
3748
|
+
*
|
|
3749
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
3750
|
+
*/
|
|
3781
3751
|
class Geq extends React.Component {
|
|
3782
3752
|
render() {
|
|
3783
3753
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -3802,10 +3772,15 @@ class Geq extends React.Component {
|
|
|
3802
3772
|
})));
|
|
3803
3773
|
}
|
|
3804
3774
|
}
|
|
3805
|
-
|
|
3775
|
+
Geq.propTypes = {
|
|
3806
3776
|
color: PropTypes.string.isRequired
|
|
3807
|
-
}
|
|
3777
|
+
};
|
|
3808
3778
|
|
|
3779
|
+
/**
|
|
3780
|
+
* An autogenerated component that renders the LN iconograpy in SVG.
|
|
3781
|
+
*
|
|
3782
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
3783
|
+
*/
|
|
3809
3784
|
class Ln extends React.Component {
|
|
3810
3785
|
render() {
|
|
3811
3786
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -3824,16 +3799,16 @@ class Ln extends React.Component {
|
|
|
3824
3799
|
})));
|
|
3825
3800
|
}
|
|
3826
3801
|
}
|
|
3827
|
-
|
|
3802
|
+
Ln.propTypes = {
|
|
3828
3803
|
color: PropTypes.string.isRequired
|
|
3829
|
-
}
|
|
3804
|
+
};
|
|
3830
3805
|
|
|
3831
3806
|
/**
|
|
3832
3807
|
* An autogenerated component that renders the DISMISS iconograpy in SVG.
|
|
3833
3808
|
*
|
|
3834
3809
|
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
3835
3810
|
*/
|
|
3836
|
-
|
|
3811
|
+
const Dismiss = () => {
|
|
3837
3812
|
return /*#__PURE__*/React.createElement("svg", {
|
|
3838
3813
|
width: "48",
|
|
3839
3814
|
height: "48",
|
|
@@ -3853,6 +3828,11 @@ var Dismiss = () => {
|
|
|
3853
3828
|
})));
|
|
3854
3829
|
};
|
|
3855
3830
|
|
|
3831
|
+
/**
|
|
3832
|
+
* An autogenerated component that renders the SIN iconograpy in SVG.
|
|
3833
|
+
*
|
|
3834
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
3835
|
+
*/
|
|
3856
3836
|
class Sin extends React.Component {
|
|
3857
3837
|
render() {
|
|
3858
3838
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -3874,10 +3854,15 @@ class Sin extends React.Component {
|
|
|
3874
3854
|
})));
|
|
3875
3855
|
}
|
|
3876
3856
|
}
|
|
3877
|
-
|
|
3857
|
+
Sin.propTypes = {
|
|
3878
3858
|
color: PropTypes.string.isRequired
|
|
3879
|
-
}
|
|
3859
|
+
};
|
|
3880
3860
|
|
|
3861
|
+
/**
|
|
3862
|
+
* An autogenerated component that renders the LT iconograpy in SVG.
|
|
3863
|
+
*
|
|
3864
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
3865
|
+
*/
|
|
3881
3866
|
class Lt extends React.Component {
|
|
3882
3867
|
render() {
|
|
3883
3868
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -3902,10 +3887,15 @@ class Lt extends React.Component {
|
|
|
3902
3887
|
})));
|
|
3903
3888
|
}
|
|
3904
3889
|
}
|
|
3905
|
-
|
|
3890
|
+
Lt.propTypes = {
|
|
3906
3891
|
color: PropTypes.string.isRequired
|
|
3907
|
-
}
|
|
3892
|
+
};
|
|
3908
3893
|
|
|
3894
|
+
/**
|
|
3895
|
+
* An autogenerated component that renders the CUBE_ROOT iconograpy in SVG.
|
|
3896
|
+
*
|
|
3897
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
3898
|
+
*/
|
|
3909
3899
|
class CubeRoot extends React.Component {
|
|
3910
3900
|
render() {
|
|
3911
3901
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -3930,10 +3920,15 @@ class CubeRoot extends React.Component {
|
|
|
3930
3920
|
})));
|
|
3931
3921
|
}
|
|
3932
3922
|
}
|
|
3933
|
-
|
|
3923
|
+
CubeRoot.propTypes = {
|
|
3934
3924
|
color: PropTypes.string.isRequired
|
|
3935
|
-
}
|
|
3925
|
+
};
|
|
3936
3926
|
|
|
3927
|
+
/**
|
|
3928
|
+
* An autogenerated component that renders the PLUS iconograpy in SVG.
|
|
3929
|
+
*
|
|
3930
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
3931
|
+
*/
|
|
3937
3932
|
class Plus extends React.Component {
|
|
3938
3933
|
render() {
|
|
3939
3934
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -3955,10 +3950,15 @@ class Plus extends React.Component {
|
|
|
3955
3950
|
})));
|
|
3956
3951
|
}
|
|
3957
3952
|
}
|
|
3958
|
-
|
|
3953
|
+
Plus.propTypes = {
|
|
3959
3954
|
color: PropTypes.string.isRequired
|
|
3960
|
-
}
|
|
3955
|
+
};
|
|
3961
3956
|
|
|
3957
|
+
/**
|
|
3958
|
+
* An autogenerated component that renders the TAN iconograpy in SVG.
|
|
3959
|
+
*
|
|
3960
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
3961
|
+
*/
|
|
3962
3962
|
class Tan extends React.Component {
|
|
3963
3963
|
render() {
|
|
3964
3964
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -3980,11 +3980,11 @@ class Tan extends React.Component {
|
|
|
3980
3980
|
})));
|
|
3981
3981
|
}
|
|
3982
3982
|
}
|
|
3983
|
-
|
|
3983
|
+
Tan.propTypes = {
|
|
3984
3984
|
color: PropTypes.string.isRequired
|
|
3985
|
-
}
|
|
3985
|
+
};
|
|
3986
3986
|
|
|
3987
|
-
|
|
3987
|
+
const Arrow = props => {
|
|
3988
3988
|
return /*#__PURE__*/React.createElement("g", _extends({
|
|
3989
3989
|
fill: "none",
|
|
3990
3990
|
fillRule: "evenodd"
|
|
@@ -4006,7 +4006,7 @@ var Arrow = props => {
|
|
|
4006
4006
|
/**
|
|
4007
4007
|
* An component that renders the LEFT iconograpy in SVG.
|
|
4008
4008
|
*/
|
|
4009
|
-
|
|
4009
|
+
const Left = () => {
|
|
4010
4010
|
return /*#__PURE__*/React.createElement("svg", {
|
|
4011
4011
|
width: "48",
|
|
4012
4012
|
height: "48",
|
|
@@ -4017,7 +4017,7 @@ var Left = () => {
|
|
|
4017
4017
|
/**
|
|
4018
4018
|
* A component that renders the UP iconograpy in SVG.
|
|
4019
4019
|
*/
|
|
4020
|
-
|
|
4020
|
+
const Up = () => {
|
|
4021
4021
|
return /*#__PURE__*/React.createElement("svg", {
|
|
4022
4022
|
width: "48",
|
|
4023
4023
|
height: "48",
|
|
@@ -4030,7 +4030,7 @@ var Up = () => {
|
|
|
4030
4030
|
/**
|
|
4031
4031
|
* A component that renders the DOWN iconograpy in SVG.
|
|
4032
4032
|
*/
|
|
4033
|
-
|
|
4033
|
+
const Down = () => {
|
|
4034
4034
|
return /*#__PURE__*/React.createElement("svg", {
|
|
4035
4035
|
width: "48",
|
|
4036
4036
|
height: "48",
|
|
@@ -4040,6 +4040,11 @@ var Down = () => {
|
|
|
4040
4040
|
}));
|
|
4041
4041
|
};
|
|
4042
4042
|
|
|
4043
|
+
/**
|
|
4044
|
+
* An autogenerated component that renders the LEFT_PAREN iconograpy in SVG.
|
|
4045
|
+
*
|
|
4046
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4047
|
+
*/
|
|
4043
4048
|
class LeftParen extends React.Component {
|
|
4044
4049
|
render() {
|
|
4045
4050
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -4064,10 +4069,15 @@ class LeftParen extends React.Component {
|
|
|
4064
4069
|
})));
|
|
4065
4070
|
}
|
|
4066
4071
|
}
|
|
4067
|
-
|
|
4072
|
+
LeftParen.propTypes = {
|
|
4068
4073
|
color: PropTypes.string.isRequired
|
|
4069
|
-
}
|
|
4074
|
+
};
|
|
4070
4075
|
|
|
4076
|
+
/**
|
|
4077
|
+
* An autogenerated component that renders the RIGHT_PAREN iconograpy in SVG.
|
|
4078
|
+
*
|
|
4079
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4080
|
+
*/
|
|
4071
4081
|
class RightParen extends React.Component {
|
|
4072
4082
|
render() {
|
|
4073
4083
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -4092,10 +4102,15 @@ class RightParen extends React.Component {
|
|
|
4092
4102
|
})));
|
|
4093
4103
|
}
|
|
4094
4104
|
}
|
|
4095
|
-
|
|
4105
|
+
RightParen.propTypes = {
|
|
4096
4106
|
color: PropTypes.string.isRequired
|
|
4097
|
-
}
|
|
4107
|
+
};
|
|
4098
4108
|
|
|
4109
|
+
/**
|
|
4110
|
+
* An autogenerated component that renders the GT iconograpy in SVG.
|
|
4111
|
+
*
|
|
4112
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4113
|
+
*/
|
|
4099
4114
|
class Gt extends React.Component {
|
|
4100
4115
|
render() {
|
|
4101
4116
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -4120,10 +4135,15 @@ class Gt extends React.Component {
|
|
|
4120
4135
|
})));
|
|
4121
4136
|
}
|
|
4122
4137
|
}
|
|
4123
|
-
|
|
4138
|
+
Gt.propTypes = {
|
|
4124
4139
|
color: PropTypes.string.isRequired
|
|
4125
|
-
}
|
|
4140
|
+
};
|
|
4126
4141
|
|
|
4142
|
+
/**
|
|
4143
|
+
* An autogenerated component that renders the DIVIDE iconograpy in SVG.
|
|
4144
|
+
*
|
|
4145
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4146
|
+
*/
|
|
4127
4147
|
class Divide extends React.Component {
|
|
4128
4148
|
render() {
|
|
4129
4149
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -4155,10 +4175,15 @@ class Divide extends React.Component {
|
|
|
4155
4175
|
})));
|
|
4156
4176
|
}
|
|
4157
4177
|
}
|
|
4158
|
-
|
|
4178
|
+
Divide.propTypes = {
|
|
4159
4179
|
color: PropTypes.string.isRequired
|
|
4160
|
-
}
|
|
4180
|
+
};
|
|
4161
4181
|
|
|
4182
|
+
/**
|
|
4183
|
+
* An autogenerated component that renders the PERIOD iconograpy in SVG.
|
|
4184
|
+
*
|
|
4185
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4186
|
+
*/
|
|
4162
4187
|
class Period extends React.Component {
|
|
4163
4188
|
render() {
|
|
4164
4189
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -4179,10 +4204,15 @@ class Period extends React.Component {
|
|
|
4179
4204
|
})));
|
|
4180
4205
|
}
|
|
4181
4206
|
}
|
|
4182
|
-
|
|
4207
|
+
Period.propTypes = {
|
|
4183
4208
|
color: PropTypes.string.isRequired
|
|
4184
|
-
}
|
|
4209
|
+
};
|
|
4185
4210
|
|
|
4211
|
+
/**
|
|
4212
|
+
* An autogenerated component that renders the PERCENT iconograpy in SVG.
|
|
4213
|
+
*
|
|
4214
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4215
|
+
*/
|
|
4186
4216
|
class Percent extends React.Component {
|
|
4187
4217
|
render() {
|
|
4188
4218
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -4221,10 +4251,15 @@ class Percent extends React.Component {
|
|
|
4221
4251
|
}))));
|
|
4222
4252
|
}
|
|
4223
4253
|
}
|
|
4224
|
-
|
|
4254
|
+
Percent.propTypes = {
|
|
4225
4255
|
color: PropTypes.string.isRequired
|
|
4226
|
-
}
|
|
4256
|
+
};
|
|
4227
4257
|
|
|
4258
|
+
/**
|
|
4259
|
+
* An autogenerated component that renders the TIMES iconograpy in SVG.
|
|
4260
|
+
*
|
|
4261
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4262
|
+
*/
|
|
4228
4263
|
class Times extends React.Component {
|
|
4229
4264
|
render() {
|
|
4230
4265
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -4249,10 +4284,15 @@ class Times extends React.Component {
|
|
|
4249
4284
|
})));
|
|
4250
4285
|
}
|
|
4251
4286
|
}
|
|
4252
|
-
|
|
4287
|
+
Times.propTypes = {
|
|
4253
4288
|
color: PropTypes.string.isRequired
|
|
4254
|
-
}
|
|
4289
|
+
};
|
|
4255
4290
|
|
|
4291
|
+
/**
|
|
4292
|
+
* An autogenerated component that renders the EXP_3 iconograpy in SVG.
|
|
4293
|
+
*
|
|
4294
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4295
|
+
*/
|
|
4256
4296
|
class Exp3 extends React.Component {
|
|
4257
4297
|
render() {
|
|
4258
4298
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -4271,10 +4311,15 @@ class Exp3 extends React.Component {
|
|
|
4271
4311
|
})));
|
|
4272
4312
|
}
|
|
4273
4313
|
}
|
|
4274
|
-
|
|
4314
|
+
Exp3.propTypes = {
|
|
4275
4315
|
color: PropTypes.string.isRequired
|
|
4276
|
-
}
|
|
4316
|
+
};
|
|
4277
4317
|
|
|
4318
|
+
/**
|
|
4319
|
+
* An autogenerated component that renders the EXP_2 iconograpy in SVG.
|
|
4320
|
+
*
|
|
4321
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4322
|
+
*/
|
|
4278
4323
|
class Exp2 extends React.Component {
|
|
4279
4324
|
render() {
|
|
4280
4325
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -4293,14 +4338,14 @@ class Exp2 extends React.Component {
|
|
|
4293
4338
|
})));
|
|
4294
4339
|
}
|
|
4295
4340
|
}
|
|
4296
|
-
|
|
4341
|
+
Exp2.propTypes = {
|
|
4297
4342
|
color: PropTypes.string.isRequired
|
|
4298
|
-
}
|
|
4343
|
+
};
|
|
4299
4344
|
|
|
4300
4345
|
/**
|
|
4301
4346
|
* A component that renders the RIGHT iconograpy in SVG.
|
|
4302
4347
|
*/
|
|
4303
|
-
|
|
4348
|
+
const Right = () => {
|
|
4304
4349
|
return /*#__PURE__*/React.createElement("svg", {
|
|
4305
4350
|
width: "48",
|
|
4306
4351
|
height: "48",
|
|
@@ -4310,6 +4355,11 @@ var Right = () => {
|
|
|
4310
4355
|
}));
|
|
4311
4356
|
};
|
|
4312
4357
|
|
|
4358
|
+
/**
|
|
4359
|
+
* An autogenerated component that renders the CDOT iconograpy in SVG.
|
|
4360
|
+
*
|
|
4361
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4362
|
+
*/
|
|
4313
4363
|
class Cdot extends React.Component {
|
|
4314
4364
|
render() {
|
|
4315
4365
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -4335,10 +4385,15 @@ class Cdot extends React.Component {
|
|
|
4335
4385
|
}))));
|
|
4336
4386
|
}
|
|
4337
4387
|
}
|
|
4338
|
-
|
|
4388
|
+
Cdot.propTypes = {
|
|
4339
4389
|
color: PropTypes.string.isRequired
|
|
4340
|
-
}
|
|
4390
|
+
};
|
|
4341
4391
|
|
|
4392
|
+
/**
|
|
4393
|
+
* An autogenerated component that renders the LOG_N iconograpy in SVG.
|
|
4394
|
+
*
|
|
4395
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4396
|
+
*/
|
|
4342
4397
|
class LogN extends React.Component {
|
|
4343
4398
|
render() {
|
|
4344
4399
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -4357,10 +4412,15 @@ class LogN extends React.Component {
|
|
|
4357
4412
|
})));
|
|
4358
4413
|
}
|
|
4359
4414
|
}
|
|
4360
|
-
|
|
4415
|
+
LogN.propTypes = {
|
|
4361
4416
|
color: PropTypes.string.isRequired
|
|
4362
|
-
}
|
|
4417
|
+
};
|
|
4363
4418
|
|
|
4419
|
+
/**
|
|
4420
|
+
* An autogenerated component that renders the LEQ iconograpy in SVG.
|
|
4421
|
+
*
|
|
4422
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4423
|
+
*/
|
|
4364
4424
|
class Leq extends React.Component {
|
|
4365
4425
|
render() {
|
|
4366
4426
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -4385,10 +4445,15 @@ class Leq extends React.Component {
|
|
|
4385
4445
|
})));
|
|
4386
4446
|
}
|
|
4387
4447
|
}
|
|
4388
|
-
|
|
4448
|
+
Leq.propTypes = {
|
|
4389
4449
|
color: PropTypes.string.isRequired
|
|
4390
|
-
}
|
|
4450
|
+
};
|
|
4391
4451
|
|
|
4452
|
+
/**
|
|
4453
|
+
* An autogenerated component that renders the MINUS iconograpy in SVG.
|
|
4454
|
+
*
|
|
4455
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4456
|
+
*/
|
|
4392
4457
|
class Minus extends React.Component {
|
|
4393
4458
|
render() {
|
|
4394
4459
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -4410,10 +4475,15 @@ class Minus extends React.Component {
|
|
|
4410
4475
|
})));
|
|
4411
4476
|
}
|
|
4412
4477
|
}
|
|
4413
|
-
|
|
4478
|
+
Minus.propTypes = {
|
|
4414
4479
|
color: PropTypes.string.isRequired
|
|
4415
|
-
}
|
|
4480
|
+
};
|
|
4416
4481
|
|
|
4482
|
+
/**
|
|
4483
|
+
* An autogenerated component that renders the RADICAL iconograpy in SVG.
|
|
4484
|
+
*
|
|
4485
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4486
|
+
*/
|
|
4417
4487
|
class Radical extends React.Component {
|
|
4418
4488
|
render() {
|
|
4419
4489
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -4438,10 +4508,15 @@ class Radical extends React.Component {
|
|
|
4438
4508
|
})));
|
|
4439
4509
|
}
|
|
4440
4510
|
}
|
|
4441
|
-
|
|
4511
|
+
Radical.propTypes = {
|
|
4442
4512
|
color: PropTypes.string.isRequired
|
|
4443
|
-
}
|
|
4513
|
+
};
|
|
4444
4514
|
|
|
4515
|
+
/**
|
|
4516
|
+
* An autogenerated component that renders the FRAC iconograpy in SVG.
|
|
4517
|
+
*
|
|
4518
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4519
|
+
*/
|
|
4445
4520
|
class FracInclusive extends React.Component {
|
|
4446
4521
|
render() {
|
|
4447
4522
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -4475,16 +4550,16 @@ class FracInclusive extends React.Component {
|
|
|
4475
4550
|
}))));
|
|
4476
4551
|
}
|
|
4477
4552
|
}
|
|
4478
|
-
|
|
4553
|
+
FracInclusive.propTypes = {
|
|
4479
4554
|
color: PropTypes.string.isRequired
|
|
4480
|
-
}
|
|
4555
|
+
};
|
|
4481
4556
|
|
|
4482
4557
|
/**
|
|
4483
4558
|
* An autogenerated component that renders the JUMP_OUT_PARENTHESES iconograpy in SVG.
|
|
4484
4559
|
*
|
|
4485
4560
|
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4486
4561
|
*/
|
|
4487
|
-
|
|
4562
|
+
const JumpOutParentheses = () => {
|
|
4488
4563
|
return /*#__PURE__*/React.createElement("svg", {
|
|
4489
4564
|
width: "48",
|
|
4490
4565
|
height: "48",
|
|
@@ -4518,7 +4593,7 @@ var JumpOutParentheses = () => {
|
|
|
4518
4593
|
*
|
|
4519
4594
|
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4520
4595
|
*/
|
|
4521
|
-
|
|
4596
|
+
const JumpOutExponent = () => {
|
|
4522
4597
|
return /*#__PURE__*/React.createElement("svg", {
|
|
4523
4598
|
width: "48",
|
|
4524
4599
|
height: "48",
|
|
@@ -4549,7 +4624,7 @@ var JumpOutExponent = () => {
|
|
|
4549
4624
|
*
|
|
4550
4625
|
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4551
4626
|
*/
|
|
4552
|
-
|
|
4627
|
+
const JumpOutBase = () => {
|
|
4553
4628
|
return /*#__PURE__*/React.createElement("svg", {
|
|
4554
4629
|
width: "48",
|
|
4555
4630
|
height: "48",
|
|
@@ -4580,7 +4655,7 @@ var JumpOutBase = () => {
|
|
|
4580
4655
|
*
|
|
4581
4656
|
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4582
4657
|
*/
|
|
4583
|
-
|
|
4658
|
+
const JumpIntoNumerator = () => {
|
|
4584
4659
|
return /*#__PURE__*/React.createElement("svg", {
|
|
4585
4660
|
width: "48",
|
|
4586
4661
|
height: "48",
|
|
@@ -4620,7 +4695,7 @@ var JumpIntoNumerator = () => {
|
|
|
4620
4695
|
*
|
|
4621
4696
|
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4622
4697
|
*/
|
|
4623
|
-
|
|
4698
|
+
const JumpOutNumerator = () => {
|
|
4624
4699
|
return /*#__PURE__*/React.createElement("svg", {
|
|
4625
4700
|
width: "48",
|
|
4626
4701
|
height: "48",
|
|
@@ -4660,7 +4735,7 @@ var JumpOutNumerator = () => {
|
|
|
4660
4735
|
*
|
|
4661
4736
|
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
4662
4737
|
*/
|
|
4663
|
-
|
|
4738
|
+
const JumpOutDenominator = () => {
|
|
4664
4739
|
return /*#__PURE__*/React.createElement("svg", {
|
|
4665
4740
|
width: "48",
|
|
4666
4741
|
height: "48",
|
|
@@ -4742,46 +4817,52 @@ var Iconography = /*#__PURE__*/Object.freeze({
|
|
|
4742
4817
|
JUMP_OUT_DENOMINATOR: JumpOutDenominator
|
|
4743
4818
|
});
|
|
4744
4819
|
|
|
4820
|
+
/**
|
|
4821
|
+
* A component that renders a single SVG icon.
|
|
4822
|
+
*/
|
|
4745
4823
|
class SvgIcon extends React.Component {
|
|
4746
4824
|
render() {
|
|
4747
|
-
|
|
4825
|
+
const {
|
|
4748
4826
|
color,
|
|
4749
4827
|
name
|
|
4750
4828
|
} = this.props;
|
|
4751
4829
|
|
|
4752
4830
|
// eslint-disable-next-line import/namespace
|
|
4753
|
-
|
|
4831
|
+
const SvgForName = Iconography[name];
|
|
4754
4832
|
return /*#__PURE__*/React.createElement(SvgForName, {
|
|
4755
4833
|
color: color
|
|
4756
4834
|
});
|
|
4757
4835
|
}
|
|
4758
4836
|
}
|
|
4759
|
-
|
|
4837
|
+
SvgIcon.propTypes = {
|
|
4760
4838
|
color: PropTypes.string.isRequired,
|
|
4761
4839
|
name: PropTypes.string.isRequired
|
|
4762
|
-
}
|
|
4840
|
+
};
|
|
4763
4841
|
|
|
4764
|
-
|
|
4842
|
+
/**
|
|
4843
|
+
* A component that renders a text-based icon.
|
|
4844
|
+
*/
|
|
4845
|
+
const {
|
|
4765
4846
|
row: row$6,
|
|
4766
4847
|
centered: centered$3
|
|
4767
4848
|
} = Styles;
|
|
4768
4849
|
class TextIcon extends React.Component {
|
|
4769
4850
|
render() {
|
|
4770
|
-
|
|
4851
|
+
const {
|
|
4771
4852
|
character,
|
|
4772
4853
|
style
|
|
4773
4854
|
} = this.props;
|
|
4774
|
-
|
|
4855
|
+
const containerStyle = [row$6, centered$3, styles$b.size, styles$b.base, ...(Array.isArray(style) ? style : [style])];
|
|
4775
4856
|
return /*#__PURE__*/React.createElement(View, {
|
|
4776
4857
|
style: containerStyle
|
|
4777
4858
|
}, /*#__PURE__*/React.createElement(Text, null, character));
|
|
4778
4859
|
}
|
|
4779
4860
|
}
|
|
4780
|
-
|
|
4861
|
+
TextIcon.propTypes = {
|
|
4781
4862
|
character: PropTypes.string.isRequired,
|
|
4782
4863
|
style: PropTypes.any
|
|
4783
|
-
}
|
|
4784
|
-
|
|
4864
|
+
};
|
|
4865
|
+
const styles$b = StyleSheet.create({
|
|
4785
4866
|
size: {
|
|
4786
4867
|
height: iconSizeHeightPx,
|
|
4787
4868
|
width: iconSizeWidthPx
|
|
@@ -4792,16 +4873,19 @@ var styles$b = StyleSheet.create({
|
|
|
4792
4873
|
}
|
|
4793
4874
|
});
|
|
4794
4875
|
|
|
4795
|
-
|
|
4796
|
-
|
|
4876
|
+
/**
|
|
4877
|
+
* A component that renders an icon for a symbol with the given name.
|
|
4878
|
+
*/
|
|
4879
|
+
const focusedColor = "#FFF";
|
|
4880
|
+
const unfocusedColor = offBlack;
|
|
4797
4881
|
class Icon extends React.PureComponent {
|
|
4798
4882
|
render() {
|
|
4799
|
-
|
|
4883
|
+
const {
|
|
4800
4884
|
focused,
|
|
4801
4885
|
icon,
|
|
4802
4886
|
style
|
|
4803
4887
|
} = this.props;
|
|
4804
|
-
|
|
4888
|
+
const styleWithFocus = [focused ? styles$a.focused : styles$a.unfocused, ...(Array.isArray(style) ? style : [style])];
|
|
4805
4889
|
switch (icon.type) {
|
|
4806
4890
|
case IconTypes.MATH:
|
|
4807
4891
|
return /*#__PURE__*/React.createElement(MathIcon, {
|
|
@@ -4826,15 +4910,15 @@ class Icon extends React.PureComponent {
|
|
|
4826
4910
|
throw new Error("No icon or symbol provided");
|
|
4827
4911
|
}
|
|
4828
4912
|
}
|
|
4829
|
-
|
|
4913
|
+
Icon.propTypes = {
|
|
4830
4914
|
focused: PropTypes.bool,
|
|
4831
4915
|
icon: iconPropType.isRequired,
|
|
4832
4916
|
// An Aphrodite style object, or an array of Aphrodite style objects.
|
|
4833
4917
|
// Note that custom styles will only be applied to text and math icons
|
|
4834
4918
|
// (and not SVG icons).
|
|
4835
4919
|
style: PropTypes.any
|
|
4836
|
-
}
|
|
4837
|
-
|
|
4920
|
+
};
|
|
4921
|
+
const styles$a = StyleSheet.create({
|
|
4838
4922
|
unfocused: {
|
|
4839
4923
|
color: unfocusedColor
|
|
4840
4924
|
},
|
|
@@ -4843,7 +4927,11 @@ var styles$a = StyleSheet.create({
|
|
|
4843
4927
|
}
|
|
4844
4928
|
});
|
|
4845
4929
|
|
|
4846
|
-
|
|
4930
|
+
/**
|
|
4931
|
+
* A grid of symbols, rendered as text and positioned based on the number of
|
|
4932
|
+
* symbols provided. Up to four symbols will be shown.
|
|
4933
|
+
*/
|
|
4934
|
+
const {
|
|
4847
4935
|
row: row$5,
|
|
4848
4936
|
column: column$3,
|
|
4849
4937
|
centered: centered$2,
|
|
@@ -4851,7 +4939,7 @@ var {
|
|
|
4851
4939
|
} = Styles;
|
|
4852
4940
|
class MultiSymbolGrid extends React.Component {
|
|
4853
4941
|
render() {
|
|
4854
|
-
|
|
4942
|
+
const {
|
|
4855
4943
|
focused,
|
|
4856
4944
|
icons
|
|
4857
4945
|
} = this.props;
|
|
@@ -4863,7 +4951,7 @@ class MultiSymbolGrid extends React.Component {
|
|
|
4863
4951
|
// some styles coercion and doesn't seem worthwhile right now.
|
|
4864
4952
|
icons.forEach(icon => {
|
|
4865
4953
|
if (icon.type !== IconTypes.MATH) {
|
|
4866
|
-
throw new Error(
|
|
4954
|
+
throw new Error(`Received invalid icon: type=${icon.type}, ` + `data=${icon.data}`);
|
|
4867
4955
|
}
|
|
4868
4956
|
});
|
|
4869
4957
|
if (icons.length === 1) {
|
|
@@ -4872,8 +4960,8 @@ class MultiSymbolGrid extends React.Component {
|
|
|
4872
4960
|
focused: focused
|
|
4873
4961
|
});
|
|
4874
4962
|
} else {
|
|
4875
|
-
|
|
4876
|
-
|
|
4963
|
+
const primaryIconStyle = styles$9.base;
|
|
4964
|
+
const secondaryIconStyle = [styles$9.base, styles$9.secondary];
|
|
4877
4965
|
if (icons.length === 2) {
|
|
4878
4966
|
return /*#__PURE__*/React.createElement(View, {
|
|
4879
4967
|
style: [row$5, styles$9.size]
|
|
@@ -4927,13 +5015,13 @@ class MultiSymbolGrid extends React.Component {
|
|
|
4927
5015
|
throw new Error("Invalid number of icons:", icons.length);
|
|
4928
5016
|
}
|
|
4929
5017
|
}
|
|
4930
|
-
|
|
5018
|
+
MultiSymbolGrid.propTypes = {
|
|
4931
5019
|
focused: PropTypes.bool,
|
|
4932
5020
|
icons: PropTypes.arrayOf(iconPropType).isRequired
|
|
4933
|
-
}
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
5021
|
+
};
|
|
5022
|
+
const verticalInsetPx = 2;
|
|
5023
|
+
const horizontalInsetPx = 4;
|
|
5024
|
+
const styles$9 = StyleSheet.create({
|
|
4937
5025
|
size: {
|
|
4938
5026
|
height: iconSizeHeightPx,
|
|
4939
5027
|
width: iconSizeWidthPx
|
|
@@ -4972,9 +5060,9 @@ var styles$9 = StyleSheet.create({
|
|
|
4972
5060
|
|
|
4973
5061
|
// eslint-disable-next-line react/no-unsafe
|
|
4974
5062
|
class KeypadButton extends React.PureComponent {
|
|
4975
|
-
constructor() {
|
|
4976
|
-
super(...
|
|
4977
|
-
|
|
5063
|
+
constructor(...args) {
|
|
5064
|
+
super(...args);
|
|
5065
|
+
this._preInjectStyles = () => {
|
|
4978
5066
|
// HACK(charlie): Pre-inject all of the possible styles for the button.
|
|
4979
5067
|
// This avoids a flickering effect in the echo animation whereby the
|
|
4980
5068
|
// echoes vary in size as they animate. Note that we need to account for
|
|
@@ -4983,25 +5071,25 @@ class KeypadButton extends React.PureComponent {
|
|
|
4983
5071
|
// object. This method must be called whenever a property that
|
|
4984
5072
|
// influences the possible outcomes of `this._getFocusStyle` and
|
|
4985
5073
|
// `this._getButtonStyle` changes (such as `this.buttonSizeStyle`).
|
|
4986
|
-
for (
|
|
5074
|
+
for (const type of Object.keys(KeyTypes)) {
|
|
4987
5075
|
css(View.styles.initial, ...this._getFocusStyle(type));
|
|
4988
|
-
for (
|
|
5076
|
+
for (const borders of Object.values(BorderStyles)) {
|
|
4989
5077
|
css(View.styles.initial, ...this._getButtonStyle(type, borders));
|
|
4990
5078
|
}
|
|
4991
5079
|
}
|
|
4992
|
-
}
|
|
4993
|
-
|
|
4994
|
-
|
|
5080
|
+
};
|
|
5081
|
+
this._getFocusStyle = type => {
|
|
5082
|
+
let focusBackgroundStyle;
|
|
4995
5083
|
if (type === KeyTypes.INPUT_NAVIGATION || type === KeyTypes.KEYPAD_NAVIGATION) {
|
|
4996
5084
|
focusBackgroundStyle = styles$8.light;
|
|
4997
5085
|
} else {
|
|
4998
5086
|
focusBackgroundStyle = styles$8.bright;
|
|
4999
5087
|
}
|
|
5000
5088
|
return [styles$8.focusBox, focusBackgroundStyle];
|
|
5001
|
-
}
|
|
5002
|
-
|
|
5089
|
+
};
|
|
5090
|
+
this._getButtonStyle = (type, borders, style) => {
|
|
5003
5091
|
// Select the appropriate style for the button.
|
|
5004
|
-
|
|
5092
|
+
let backgroundStyle;
|
|
5005
5093
|
switch (type) {
|
|
5006
5094
|
case KeyTypes.EMPTY:
|
|
5007
5095
|
backgroundStyle = styles$8.empty;
|
|
@@ -5021,7 +5109,7 @@ class KeypadButton extends React.PureComponent {
|
|
|
5021
5109
|
backgroundStyle = null;
|
|
5022
5110
|
break;
|
|
5023
5111
|
}
|
|
5024
|
-
|
|
5112
|
+
const borderStyle = [];
|
|
5025
5113
|
if (borders.indexOf(BorderDirections.LEFT) !== -1) {
|
|
5026
5114
|
borderStyle.push(styles$8.leftBorder);
|
|
5027
5115
|
}
|
|
@@ -5033,7 +5121,7 @@ class KeypadButton extends React.PureComponent {
|
|
|
5033
5121
|
// components.
|
|
5034
5122
|
// See: https://facebook.github.io/react-native/docs/style.html
|
|
5035
5123
|
...(Array.isArray(style) ? style : [style])];
|
|
5036
|
-
}
|
|
5124
|
+
};
|
|
5037
5125
|
}
|
|
5038
5126
|
UNSAFE_componentWillMount() {
|
|
5039
5127
|
this.buttonSizeStyle = styleForButtonDimensions(this.props.heightPx, this.props.widthPx);
|
|
@@ -5052,7 +5140,7 @@ class KeypadButton extends React.PureComponent {
|
|
|
5052
5140
|
}
|
|
5053
5141
|
}
|
|
5054
5142
|
render() {
|
|
5055
|
-
|
|
5143
|
+
const {
|
|
5056
5144
|
ariaLabel,
|
|
5057
5145
|
borders,
|
|
5058
5146
|
childKeys,
|
|
@@ -5070,20 +5158,20 @@ class KeypadButton extends React.PureComponent {
|
|
|
5070
5158
|
|
|
5071
5159
|
// We render in the focus state if the key is focused, or if it's an
|
|
5072
5160
|
// echo.
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5161
|
+
const renderFocused = !disabled && focused || popoverEnabled || type === KeyTypes.ECHO;
|
|
5162
|
+
const buttonStyle = this._getButtonStyle(type, borders, style);
|
|
5163
|
+
const focusStyle = this._getFocusStyle(type);
|
|
5164
|
+
const iconWrapperStyle = [styles$8.iconWrapper, disabled && styles$8.disabled];
|
|
5165
|
+
const eventHandlers = {
|
|
5078
5166
|
onTouchCancel,
|
|
5079
5167
|
onTouchEnd,
|
|
5080
5168
|
onTouchMove,
|
|
5081
5169
|
onTouchStart
|
|
5082
5170
|
};
|
|
5083
|
-
|
|
5171
|
+
const maybeFocusBox = renderFocused && /*#__PURE__*/React.createElement(View, {
|
|
5084
5172
|
style: focusStyle
|
|
5085
5173
|
});
|
|
5086
|
-
|
|
5174
|
+
const maybeCornerDecal = !renderFocused && !disabled && childKeys && childKeys.length > 0 && /*#__PURE__*/React.createElement(CornerDecal, {
|
|
5087
5175
|
style: styles$8.decalInset
|
|
5088
5176
|
});
|
|
5089
5177
|
if (type === KeyTypes.EMPTY) {
|
|
@@ -5093,11 +5181,11 @@ class KeypadButton extends React.PureComponent {
|
|
|
5093
5181
|
} else if (type === KeyTypes.MANY) {
|
|
5094
5182
|
// TODO(charlie): Make the long-press interaction accessible. See
|
|
5095
5183
|
// the TODO in key-configs.js for more.
|
|
5096
|
-
|
|
5184
|
+
const manyButtonA11yMarkup = {
|
|
5097
5185
|
role: "button",
|
|
5098
5186
|
ariaLabel: childKeys[0].ariaLabel
|
|
5099
5187
|
};
|
|
5100
|
-
|
|
5188
|
+
const icons = childKeys.map(keyConfig => {
|
|
5101
5189
|
return keyConfig.icon;
|
|
5102
5190
|
});
|
|
5103
5191
|
return /*#__PURE__*/React.createElement(View, _extends({
|
|
@@ -5109,7 +5197,7 @@ class KeypadButton extends React.PureComponent {
|
|
|
5109
5197
|
focused: renderFocused
|
|
5110
5198
|
})), maybeCornerDecal);
|
|
5111
5199
|
} else {
|
|
5112
|
-
|
|
5200
|
+
const a11yMarkup = {
|
|
5113
5201
|
role: "button",
|
|
5114
5202
|
ariaLabel: ariaLabel
|
|
5115
5203
|
};
|
|
@@ -5124,7 +5212,7 @@ class KeypadButton extends React.PureComponent {
|
|
|
5124
5212
|
}
|
|
5125
5213
|
}
|
|
5126
5214
|
}
|
|
5127
|
-
|
|
5215
|
+
KeypadButton.propTypes = {
|
|
5128
5216
|
ariaLabel: PropTypes.string,
|
|
5129
5217
|
// The borders to display on the button. Typically, this should be set
|
|
5130
5218
|
// using one of the preset `BorderStyles` options.
|
|
@@ -5149,17 +5237,17 @@ _defineProperty(KeypadButton, "propTypes", {
|
|
|
5149
5237
|
// (and rely on Flexbox instead), since it might not be pixel perfect
|
|
5150
5238
|
// with borders and such.
|
|
5151
5239
|
widthPx: PropTypes.number.isRequired
|
|
5152
|
-
}
|
|
5153
|
-
|
|
5240
|
+
};
|
|
5241
|
+
KeypadButton.defaultProps = {
|
|
5154
5242
|
borders: BorderStyles.ALL,
|
|
5155
5243
|
childKeys: [],
|
|
5156
5244
|
disabled: false,
|
|
5157
5245
|
focused: false,
|
|
5158
5246
|
popoverEnabled: false
|
|
5159
|
-
}
|
|
5160
|
-
|
|
5161
|
-
|
|
5162
|
-
|
|
5247
|
+
};
|
|
5248
|
+
const focusInsetPx = 4;
|
|
5249
|
+
const focusBoxZIndex = 0;
|
|
5250
|
+
const styles$8 = StyleSheet.create({
|
|
5163
5251
|
buttonBase: {
|
|
5164
5252
|
// HACK(benkomalo): support old style flex box in Android browsers
|
|
5165
5253
|
"-webkit-box-flex": "1",
|
|
@@ -5227,7 +5315,7 @@ var styles$8 = StyleSheet.create({
|
|
|
5227
5315
|
borderBottomWidth: innerBorderWidthPx
|
|
5228
5316
|
}
|
|
5229
5317
|
});
|
|
5230
|
-
|
|
5318
|
+
const styleForButtonDimensions = (heightPx, widthPx) => {
|
|
5231
5319
|
return StyleSheet.create({
|
|
5232
5320
|
// eslint-disable-next-line react-native/no-unused-styles
|
|
5233
5321
|
buttonSize: {
|
|
@@ -5237,21 +5325,21 @@ var styleForButtonDimensions = (heightPx, widthPx) => {
|
|
|
5237
5325
|
}
|
|
5238
5326
|
}).buttonSize;
|
|
5239
5327
|
};
|
|
5240
|
-
|
|
5328
|
+
const mapStateToProps$7 = state => {
|
|
5241
5329
|
return state.layout.buttonDimensions;
|
|
5242
5330
|
};
|
|
5243
5331
|
var KeypadButton$1 = connect(mapStateToProps$7, null, null, {
|
|
5244
5332
|
forwardRef: true
|
|
5245
5333
|
})(KeypadButton);
|
|
5246
5334
|
|
|
5247
|
-
|
|
5335
|
+
const _excluded$4 = ["gestureManager"];
|
|
5248
5336
|
class EmptyKeypadButton extends React.Component {
|
|
5249
5337
|
render() {
|
|
5250
|
-
|
|
5338
|
+
const _this$props = this.props,
|
|
5251
5339
|
{
|
|
5252
5340
|
gestureManager
|
|
5253
5341
|
} = _this$props,
|
|
5254
|
-
rest =
|
|
5342
|
+
rest = _objectWithoutPropertiesLoose(_this$props, _excluded$4);
|
|
5255
5343
|
|
|
5256
5344
|
// Register touch events on the button, but don't register its DOM node
|
|
5257
5345
|
// or compute focus state or anything like that. We want the gesture
|
|
@@ -5266,11 +5354,11 @@ class EmptyKeypadButton extends React.Component {
|
|
|
5266
5354
|
}, KeyConfigs.NOOP, rest));
|
|
5267
5355
|
}
|
|
5268
5356
|
}
|
|
5269
|
-
|
|
5357
|
+
EmptyKeypadButton.propTypes = {
|
|
5270
5358
|
gestureManager: PropTypes.instanceOf(GestureManager)
|
|
5271
|
-
}
|
|
5272
|
-
|
|
5273
|
-
|
|
5359
|
+
};
|
|
5360
|
+
const mapStateToProps$6 = state => {
|
|
5361
|
+
const {
|
|
5274
5362
|
gestures
|
|
5275
5363
|
} = state;
|
|
5276
5364
|
return {
|
|
@@ -5281,7 +5369,7 @@ var EmptyKeypadButton$1 = connect(mapStateToProps$6, null, null, {
|
|
|
5281
5369
|
forwardRef: true
|
|
5282
5370
|
})(EmptyKeypadButton);
|
|
5283
5371
|
|
|
5284
|
-
|
|
5372
|
+
const _excluded$3 = ["borders", "childKeyIds", "disabled", "gestureManager", "id", "style"],
|
|
5285
5373
|
_excluded2 = ["keyConfig"];
|
|
5286
5374
|
class TouchableKeypadButton extends React.Component {
|
|
5287
5375
|
shouldComponentUpdate(newProps) {
|
|
@@ -5292,14 +5380,14 @@ class TouchableKeypadButton extends React.Component {
|
|
|
5292
5380
|
return newProps.id !== this.props.id || newProps.gestureManager !== this.props.gestureManager || newProps.focused !== this.props.focused || newProps.disabled !== this.props.disabled || newProps.popoverEnabled !== this.props.popoverEnabled || newProps.type !== this.props.type || !!newProps.style;
|
|
5293
5381
|
}
|
|
5294
5382
|
componentWillUnmount() {
|
|
5295
|
-
|
|
5383
|
+
const {
|
|
5296
5384
|
gestureManager,
|
|
5297
5385
|
id
|
|
5298
5386
|
} = this.props;
|
|
5299
5387
|
gestureManager.unregisterDOMNode(id);
|
|
5300
5388
|
}
|
|
5301
5389
|
render() {
|
|
5302
|
-
|
|
5390
|
+
const _this$props = this.props,
|
|
5303
5391
|
{
|
|
5304
5392
|
borders,
|
|
5305
5393
|
childKeyIds,
|
|
@@ -5308,10 +5396,10 @@ class TouchableKeypadButton extends React.Component {
|
|
|
5308
5396
|
id,
|
|
5309
5397
|
style
|
|
5310
5398
|
} = _this$props,
|
|
5311
|
-
rest =
|
|
5399
|
+
rest = _objectWithoutPropertiesLoose(_this$props, _excluded$3);
|
|
5312
5400
|
|
|
5313
5401
|
// Only bind the relevant event handlers if the key is enabled.
|
|
5314
|
-
|
|
5402
|
+
const eventHandlers = disabled ? {
|
|
5315
5403
|
onTouchStart: evt => evt.preventDefault()
|
|
5316
5404
|
} : {
|
|
5317
5405
|
onTouchStart: evt => gestureManager.onTouchStart(evt, id),
|
|
@@ -5319,7 +5407,7 @@ class TouchableKeypadButton extends React.Component {
|
|
|
5319
5407
|
onTouchMove: evt => gestureManager.onTouchMove(evt),
|
|
5320
5408
|
onTouchCancel: evt => gestureManager.onTouchCancel(evt)
|
|
5321
5409
|
};
|
|
5322
|
-
|
|
5410
|
+
const styleWithAddons = [...(Array.isArray(style) ? style : [style]), styles$7.preventScrolls];
|
|
5323
5411
|
return /*#__PURE__*/React.createElement(KeypadButton$1, _extends({
|
|
5324
5412
|
ref: node => gestureManager.registerDOMNode(id, ReactDOM.findDOMNode(node), childKeyIds, borders),
|
|
5325
5413
|
borders: borders,
|
|
@@ -5328,7 +5416,7 @@ class TouchableKeypadButton extends React.Component {
|
|
|
5328
5416
|
}, eventHandlers, rest));
|
|
5329
5417
|
}
|
|
5330
5418
|
}
|
|
5331
|
-
|
|
5419
|
+
TouchableKeypadButton.propTypes = {
|
|
5332
5420
|
borders: bordersPropType,
|
|
5333
5421
|
childKeyIds: PropTypes.arrayOf(keyIdPropType),
|
|
5334
5422
|
disabled: PropTypes.bool,
|
|
@@ -5338,9 +5426,9 @@ _defineProperty(TouchableKeypadButton, "propTypes", {
|
|
|
5338
5426
|
popoverEnabled: PropTypes.bool,
|
|
5339
5427
|
style: PropTypes.any,
|
|
5340
5428
|
type: PropTypes.oneOf(Object.keys(KeyTypes)).isRequired
|
|
5341
|
-
}
|
|
5342
|
-
|
|
5343
|
-
|
|
5429
|
+
};
|
|
5430
|
+
const extractProps = keyConfig => {
|
|
5431
|
+
const {
|
|
5344
5432
|
ariaLabel,
|
|
5345
5433
|
icon,
|
|
5346
5434
|
type
|
|
@@ -5351,25 +5439,25 @@ var extractProps = keyConfig => {
|
|
|
5351
5439
|
type
|
|
5352
5440
|
};
|
|
5353
5441
|
};
|
|
5354
|
-
|
|
5355
|
-
|
|
5442
|
+
const mapStateToProps$5 = (state, ownProps) => {
|
|
5443
|
+
const {
|
|
5356
5444
|
gestures
|
|
5357
5445
|
} = state;
|
|
5358
|
-
|
|
5446
|
+
const {
|
|
5359
5447
|
keyConfig
|
|
5360
5448
|
} = ownProps,
|
|
5361
|
-
rest =
|
|
5362
|
-
|
|
5449
|
+
rest = _objectWithoutPropertiesLoose(ownProps, _excluded2);
|
|
5450
|
+
const {
|
|
5363
5451
|
id,
|
|
5364
5452
|
childKeyIds,
|
|
5365
5453
|
type
|
|
5366
5454
|
} = keyConfig;
|
|
5367
|
-
|
|
5455
|
+
const childKeys = childKeyIds && childKeyIds.map(id => KeyConfigs[id]);
|
|
5368
5456
|
|
|
5369
5457
|
// Override with the default child props, if the key is a multi-symbol key
|
|
5370
5458
|
// (but not a many-symbol key, which operates under different rules).
|
|
5371
|
-
|
|
5372
|
-
return
|
|
5459
|
+
const useFirstChildProps = type !== KeyTypes.MANY && childKeys && childKeys.length > 0;
|
|
5460
|
+
return _extends({}, rest, {
|
|
5373
5461
|
childKeyIds: childKeyIds,
|
|
5374
5462
|
gestureManager: gestures.gestureManager,
|
|
5375
5463
|
id: id,
|
|
@@ -5380,7 +5468,7 @@ var mapStateToProps$5 = (state, ownProps) => {
|
|
|
5380
5468
|
childKeys
|
|
5381
5469
|
}, extractProps(useFirstChildProps ? childKeys[0] : keyConfig));
|
|
5382
5470
|
};
|
|
5383
|
-
|
|
5471
|
+
const styles$7 = StyleSheet.create({
|
|
5384
5472
|
preventScrolls: {
|
|
5385
5473
|
// Touch events that start in the touchable buttons shouldn't be
|
|
5386
5474
|
// allowed to produce page scrolls.
|
|
@@ -5391,14 +5479,14 @@ var TouchableKeypadButton$1 = connect(mapStateToProps$5, null, null, {
|
|
|
5391
5479
|
forwardRef: true
|
|
5392
5480
|
})(TouchableKeypadButton);
|
|
5393
5481
|
|
|
5394
|
-
|
|
5482
|
+
const _excluded$2 = ["keys"];
|
|
5395
5483
|
class ManyKeypadButton extends React.Component {
|
|
5396
5484
|
render() {
|
|
5397
|
-
|
|
5485
|
+
const _this$props = this.props,
|
|
5398
5486
|
{
|
|
5399
5487
|
keys
|
|
5400
5488
|
} = _this$props,
|
|
5401
|
-
rest =
|
|
5489
|
+
rest = _objectWithoutPropertiesLoose(_this$props, _excluded$2);
|
|
5402
5490
|
|
|
5403
5491
|
// If we have no extra symbols, render an empty button. If we have just
|
|
5404
5492
|
// one, render a standard button. Otherwise, capture them all in a
|
|
@@ -5406,34 +5494,34 @@ class ManyKeypadButton extends React.Component {
|
|
|
5406
5494
|
if (keys.length === 0) {
|
|
5407
5495
|
return /*#__PURE__*/React.createElement(EmptyKeypadButton$1, rest);
|
|
5408
5496
|
} else if (keys.length === 1) {
|
|
5409
|
-
|
|
5497
|
+
const keyConfig = KeyConfigs[keys[0]];
|
|
5410
5498
|
return /*#__PURE__*/React.createElement(TouchableKeypadButton$1, _extends({
|
|
5411
5499
|
keyConfig: keyConfig
|
|
5412
5500
|
}, rest));
|
|
5413
5501
|
} else {
|
|
5414
|
-
|
|
5502
|
+
const keyConfig = {
|
|
5415
5503
|
id: Keys.MANY,
|
|
5416
5504
|
type: KeyTypes.MANY,
|
|
5417
5505
|
childKeyIds: keys
|
|
5418
5506
|
};
|
|
5419
5507
|
return /*#__PURE__*/React.createElement(TouchableKeypadButton$1, _extends({
|
|
5420
|
-
keyConfig:
|
|
5508
|
+
keyConfig: keyConfig
|
|
5421
5509
|
}, rest));
|
|
5422
5510
|
}
|
|
5423
5511
|
}
|
|
5424
5512
|
}
|
|
5425
|
-
|
|
5513
|
+
ManyKeypadButton.propTypes = {
|
|
5426
5514
|
keys: PropTypes.arrayOf(keyIdPropType).isRequired
|
|
5427
|
-
}
|
|
5515
|
+
};
|
|
5428
5516
|
|
|
5429
5517
|
/**
|
|
5430
5518
|
* This file contains all of the z-index values used throughout the math-input
|
|
5431
5519
|
* component and its children.
|
|
5432
5520
|
*/
|
|
5433
5521
|
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5522
|
+
const popover = 1;
|
|
5523
|
+
const echo = 2;
|
|
5524
|
+
const keypad = 1060;
|
|
5437
5525
|
|
|
5438
5526
|
class Echo extends React.Component {
|
|
5439
5527
|
componentDidMount() {
|
|
@@ -5442,22 +5530,22 @@ class Echo extends React.Component {
|
|
|
5442
5530
|
// ignorant. However, there doesn't seem to be a cleaner way to make
|
|
5443
5531
|
// this happen, and at least here, all the animation context is
|
|
5444
5532
|
// colocated in this file.
|
|
5445
|
-
|
|
5533
|
+
const {
|
|
5446
5534
|
animationDurationMs,
|
|
5447
5535
|
onAnimationFinish
|
|
5448
5536
|
} = this.props;
|
|
5449
5537
|
setTimeout(() => onAnimationFinish(), animationDurationMs);
|
|
5450
5538
|
}
|
|
5451
5539
|
render() {
|
|
5452
|
-
|
|
5540
|
+
const {
|
|
5453
5541
|
borders,
|
|
5454
5542
|
id,
|
|
5455
5543
|
initialBounds
|
|
5456
5544
|
} = this.props;
|
|
5457
|
-
|
|
5545
|
+
const {
|
|
5458
5546
|
icon
|
|
5459
5547
|
} = KeyConfigs[id];
|
|
5460
|
-
|
|
5548
|
+
const containerStyle = _extends({
|
|
5461
5549
|
zIndex: echo,
|
|
5462
5550
|
position: "absolute",
|
|
5463
5551
|
pointerEvents: "none"
|
|
@@ -5478,21 +5566,21 @@ class Echo extends React.Component {
|
|
|
5478
5566
|
}));
|
|
5479
5567
|
}
|
|
5480
5568
|
}
|
|
5481
|
-
|
|
5569
|
+
Echo.propTypes = {
|
|
5482
5570
|
animationDurationMs: PropTypes.number.isRequired,
|
|
5483
5571
|
borders: bordersPropType,
|
|
5484
5572
|
id: keyIdPropType.isRequired,
|
|
5485
5573
|
initialBounds: boundingBoxPropType.isRequired,
|
|
5486
5574
|
onAnimationFinish: PropTypes.func.isRequired
|
|
5487
|
-
}
|
|
5575
|
+
};
|
|
5488
5576
|
class EchoManager extends React.Component {
|
|
5489
|
-
constructor() {
|
|
5490
|
-
super(...
|
|
5491
|
-
|
|
5577
|
+
constructor(...args) {
|
|
5578
|
+
super(...args);
|
|
5579
|
+
this._animationConfigForType = animationType => {
|
|
5492
5580
|
// NOTE(charlie): These must be kept in sync with the transition
|
|
5493
5581
|
// durations and classnames specified in echo.css.
|
|
5494
|
-
|
|
5495
|
-
|
|
5582
|
+
let animationDurationMs;
|
|
5583
|
+
let animationTransitionName;
|
|
5496
5584
|
switch (animationType) {
|
|
5497
5585
|
case EchoAnimationTypes.SLIDE_AND_FADE:
|
|
5498
5586
|
animationDurationMs = 400;
|
|
@@ -5513,21 +5601,21 @@ class EchoManager extends React.Component {
|
|
|
5513
5601
|
animationDurationMs,
|
|
5514
5602
|
animationTransitionName
|
|
5515
5603
|
};
|
|
5516
|
-
}
|
|
5604
|
+
};
|
|
5517
5605
|
}
|
|
5518
5606
|
render() {
|
|
5519
|
-
|
|
5607
|
+
const {
|
|
5520
5608
|
echoes,
|
|
5521
|
-
onAnimationFinish
|
|
5609
|
+
onAnimationFinish
|
|
5522
5610
|
} = this.props;
|
|
5523
5611
|
return /*#__PURE__*/React.createElement("span", null, Object.keys(EchoAnimationTypes).map(animationType => {
|
|
5524
5612
|
// Collect the relevant parameters for the animation type, and
|
|
5525
5613
|
// filter for the appropriate echoes.
|
|
5526
|
-
|
|
5614
|
+
const {
|
|
5527
5615
|
animationDurationMs,
|
|
5528
5616
|
animationTransitionName
|
|
5529
5617
|
} = this._animationConfigForType(animationType);
|
|
5530
|
-
|
|
5618
|
+
const echoesForType = echoes.filter(echo => {
|
|
5531
5619
|
return echo.animationType === animationType;
|
|
5532
5620
|
});
|
|
5533
5621
|
|
|
@@ -5539,7 +5627,7 @@ class EchoManager extends React.Component {
|
|
|
5539
5627
|
return /*#__PURE__*/React.createElement(TransitionGroup, {
|
|
5540
5628
|
key: animationType
|
|
5541
5629
|
}, echoesForType.map(echo => {
|
|
5542
|
-
|
|
5630
|
+
const {
|
|
5543
5631
|
animationId
|
|
5544
5632
|
} = echo;
|
|
5545
5633
|
return /*#__PURE__*/React.createElement(CSSTransition, {
|
|
@@ -5552,20 +5640,23 @@ class EchoManager extends React.Component {
|
|
|
5552
5640
|
key: animationId
|
|
5553
5641
|
}, /*#__PURE__*/React.createElement(Echo, _extends({
|
|
5554
5642
|
animationDurationMs: animationDurationMs,
|
|
5555
|
-
onAnimationFinish: () =>
|
|
5643
|
+
onAnimationFinish: () => onAnimationFinish(animationId)
|
|
5556
5644
|
}, echo)));
|
|
5557
5645
|
}));
|
|
5558
5646
|
}));
|
|
5559
5647
|
}
|
|
5560
5648
|
}
|
|
5561
|
-
|
|
5649
|
+
EchoManager.propTypes = {
|
|
5562
5650
|
echoes: PropTypes.arrayOf(echoPropType),
|
|
5563
5651
|
onAnimationFinish: PropTypes.func.isRequired
|
|
5564
|
-
}
|
|
5652
|
+
};
|
|
5565
5653
|
|
|
5654
|
+
/**
|
|
5655
|
+
* A popover that renders a set of keys floating above the page.
|
|
5656
|
+
*/
|
|
5566
5657
|
class MultiSymbolPopover extends React.Component {
|
|
5567
5658
|
render() {
|
|
5568
|
-
|
|
5659
|
+
const {
|
|
5569
5660
|
keys
|
|
5570
5661
|
} = this.props;
|
|
5571
5662
|
|
|
@@ -5582,10 +5673,10 @@ class MultiSymbolPopover extends React.Component {
|
|
|
5582
5673
|
}));
|
|
5583
5674
|
}
|
|
5584
5675
|
}
|
|
5585
|
-
|
|
5676
|
+
MultiSymbolPopover.propTypes = {
|
|
5586
5677
|
keys: PropTypes.arrayOf(keyConfigPropType)
|
|
5587
|
-
}
|
|
5588
|
-
|
|
5678
|
+
};
|
|
5679
|
+
const styles$6 = StyleSheet.create({
|
|
5589
5680
|
container: {
|
|
5590
5681
|
flexDirection: "column-reverse",
|
|
5591
5682
|
position: "relative",
|
|
@@ -5603,18 +5694,18 @@ var styles$6 = StyleSheet.create({
|
|
|
5603
5694
|
|
|
5604
5695
|
// NOTE(charlie): These must be kept in sync with the transition durations and
|
|
5605
5696
|
// classnames specified in popover.less.
|
|
5606
|
-
|
|
5607
|
-
|
|
5697
|
+
const animationTransitionName = "popover";
|
|
5698
|
+
const animationDurationMs = 200;
|
|
5608
5699
|
|
|
5609
5700
|
// A container component used to position a popover absolutely at a specific
|
|
5610
5701
|
// position.
|
|
5611
5702
|
class PopoverContainer extends React.Component {
|
|
5612
5703
|
render() {
|
|
5613
|
-
|
|
5704
|
+
const {
|
|
5614
5705
|
bounds,
|
|
5615
5706
|
childKeys
|
|
5616
5707
|
} = this.props;
|
|
5617
|
-
|
|
5708
|
+
const containerStyle = _extends({
|
|
5618
5709
|
position: "absolute"
|
|
5619
5710
|
}, bounds);
|
|
5620
5711
|
return /*#__PURE__*/React.createElement("div", {
|
|
@@ -5624,13 +5715,13 @@ class PopoverContainer extends React.Component {
|
|
|
5624
5715
|
}));
|
|
5625
5716
|
}
|
|
5626
5717
|
}
|
|
5627
|
-
|
|
5718
|
+
PopoverContainer.propTypes = {
|
|
5628
5719
|
bounds: boundingBoxPropType.isRequired,
|
|
5629
5720
|
childKeys: PropTypes.arrayOf(keyConfigPropType).isRequired
|
|
5630
|
-
}
|
|
5721
|
+
};
|
|
5631
5722
|
class PopoverManager extends React.Component {
|
|
5632
5723
|
render() {
|
|
5633
|
-
|
|
5724
|
+
const {
|
|
5634
5725
|
popover
|
|
5635
5726
|
} = this.props;
|
|
5636
5727
|
return popover ? /*#__PURE__*/React.createElement(CSSTransition, {
|
|
@@ -5648,21 +5739,21 @@ class PopoverManager extends React.Component {
|
|
|
5648
5739
|
})) : null;
|
|
5649
5740
|
}
|
|
5650
5741
|
}
|
|
5651
|
-
|
|
5742
|
+
PopoverManager.propTypes = {
|
|
5652
5743
|
popover: popoverPropType
|
|
5653
|
-
}
|
|
5744
|
+
};
|
|
5654
5745
|
|
|
5655
|
-
|
|
5746
|
+
const _excluded$1 = ["initialBounds"];
|
|
5656
5747
|
|
|
5657
5748
|
// eslint-disable-next-line react/no-unsafe
|
|
5658
5749
|
class Keypad extends React.Component {
|
|
5659
|
-
constructor() {
|
|
5660
|
-
super(...
|
|
5661
|
-
|
|
5662
|
-
|
|
5750
|
+
constructor(...args) {
|
|
5751
|
+
super(...args);
|
|
5752
|
+
this._computeContainer = () => {
|
|
5753
|
+
const domNode = ReactDOM.findDOMNode(this);
|
|
5663
5754
|
this._container = domNode.getBoundingClientRect();
|
|
5664
|
-
}
|
|
5665
|
-
|
|
5755
|
+
};
|
|
5756
|
+
this._updateSizeAndPosition = () => {
|
|
5666
5757
|
// Mark the container for recalculation next time the keypad is
|
|
5667
5758
|
// opened.
|
|
5668
5759
|
// TODO(charlie): Since we're not recalculating the container
|
|
@@ -5671,8 +5762,8 @@ class Keypad extends React.Component {
|
|
|
5671
5762
|
// difficult to do and, as such, incredibly unlikely, but we may
|
|
5672
5763
|
// want to reconsider the caching here.
|
|
5673
5764
|
this._container = null;
|
|
5674
|
-
}
|
|
5675
|
-
|
|
5765
|
+
};
|
|
5766
|
+
this._onResize = () => {
|
|
5676
5767
|
// Whenever the page resizes, we need to recompute the container's
|
|
5677
5768
|
// bounding box. This is the only time that the bounding box can change.
|
|
5678
5769
|
|
|
@@ -5686,7 +5777,7 @@ class Keypad extends React.Component {
|
|
|
5686
5777
|
}
|
|
5687
5778
|
}, 66);
|
|
5688
5779
|
}
|
|
5689
|
-
}
|
|
5780
|
+
};
|
|
5690
5781
|
}
|
|
5691
5782
|
componentDidMount() {
|
|
5692
5783
|
this._isMounted = true;
|
|
@@ -5703,7 +5794,7 @@ class Keypad extends React.Component {
|
|
|
5703
5794
|
window.removeEventListener("resize", this._onResize);
|
|
5704
5795
|
}
|
|
5705
5796
|
render() {
|
|
5706
|
-
|
|
5797
|
+
const {
|
|
5707
5798
|
children,
|
|
5708
5799
|
echoes,
|
|
5709
5800
|
removeEcho,
|
|
@@ -5713,12 +5804,12 @@ class Keypad extends React.Component {
|
|
|
5713
5804
|
|
|
5714
5805
|
// Translate the echo boxes, as they'll be positioned absolutely to
|
|
5715
5806
|
// this relative container.
|
|
5716
|
-
|
|
5717
|
-
|
|
5807
|
+
const relativeEchoes = echoes.map(echo => {
|
|
5808
|
+
const {
|
|
5718
5809
|
initialBounds
|
|
5719
5810
|
} = echo,
|
|
5720
|
-
rest =
|
|
5721
|
-
return
|
|
5811
|
+
rest = _objectWithoutPropertiesLoose(echo, _excluded$1);
|
|
5812
|
+
return _extends({}, rest, {
|
|
5722
5813
|
initialBounds: {
|
|
5723
5814
|
top: initialBounds.top - this._container.top,
|
|
5724
5815
|
right: initialBounds.right - this._container.left,
|
|
@@ -5733,7 +5824,7 @@ class Keypad extends React.Component {
|
|
|
5733
5824
|
// Translate the popover bounds from page-absolute to keypad-relative.
|
|
5734
5825
|
// Note that we only need three bounds, since popovers are anchored to
|
|
5735
5826
|
// the bottom left corners of the keys over which they appear.
|
|
5736
|
-
|
|
5827
|
+
const relativePopover = popover && _extends({}, popover, {
|
|
5737
5828
|
bounds: {
|
|
5738
5829
|
bottom: this._container.height - (popover.bounds.bottom - this._container.top),
|
|
5739
5830
|
left: popover.bounds.left - this._container.left,
|
|
@@ -5750,7 +5841,7 @@ class Keypad extends React.Component {
|
|
|
5750
5841
|
}));
|
|
5751
5842
|
}
|
|
5752
5843
|
}
|
|
5753
|
-
|
|
5844
|
+
Keypad.propTypes = {
|
|
5754
5845
|
children: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.node), PropTypes.node]),
|
|
5755
5846
|
removeEcho: PropTypes.func.isRequired,
|
|
5756
5847
|
style: PropTypes.any,
|
|
@@ -5761,14 +5852,14 @@ _defineProperty(Keypad, "propTypes", {
|
|
|
5761
5852
|
active: PropTypes.bool,
|
|
5762
5853
|
echoes: PropTypes.arrayOf(echoPropType).isRequired,
|
|
5763
5854
|
popover: popoverPropType
|
|
5764
|
-
}
|
|
5765
|
-
|
|
5766
|
-
return
|
|
5855
|
+
};
|
|
5856
|
+
const mapStateToProps$4 = state => {
|
|
5857
|
+
return _extends({}, state.echoes, {
|
|
5767
5858
|
active: state.keypad.active,
|
|
5768
5859
|
popover: state.gestures.popover
|
|
5769
5860
|
});
|
|
5770
5861
|
};
|
|
5771
|
-
|
|
5862
|
+
const mapDispatchToProps$1 = dispatch => {
|
|
5772
5863
|
return {
|
|
5773
5864
|
removeEcho: animationId => {
|
|
5774
5865
|
dispatch(removeEcho(animationId));
|
|
@@ -5779,11 +5870,10 @@ var Keypad$1 = connect(mapStateToProps$4, mapDispatchToProps$1, null, {
|
|
|
5779
5870
|
forwardRef: true
|
|
5780
5871
|
})(Keypad);
|
|
5781
5872
|
|
|
5782
|
-
|
|
5783
|
-
|
|
5784
|
-
|
|
5785
|
-
|
|
5786
|
-
} = _ref;
|
|
5873
|
+
const IconAsset = function IconAsset({
|
|
5874
|
+
tintColor,
|
|
5875
|
+
type
|
|
5876
|
+
}) {
|
|
5787
5877
|
if (type === "Geometry") {
|
|
5788
5878
|
return /*#__PURE__*/React.createElement("svg", {
|
|
5789
5879
|
width: "32",
|
|
@@ -5827,19 +5917,19 @@ var IconAsset = function IconAsset(_ref) {
|
|
|
5827
5917
|
throw new Error("Invalid icon type");
|
|
5828
5918
|
};
|
|
5829
5919
|
|
|
5830
|
-
|
|
5920
|
+
const styles$5 = StyleSheet.create({
|
|
5831
5921
|
base: {
|
|
5832
5922
|
display: "flex",
|
|
5833
5923
|
width: 44,
|
|
5834
5924
|
height: 38,
|
|
5835
5925
|
boxSizing: "border-box",
|
|
5836
5926
|
borderRadius: 3,
|
|
5837
|
-
border:
|
|
5927
|
+
border: `1px solid transparent`,
|
|
5838
5928
|
marginRight: 1,
|
|
5839
5929
|
marginLeft: 1
|
|
5840
5930
|
},
|
|
5841
5931
|
hovered: {
|
|
5842
|
-
background:
|
|
5932
|
+
background: `linear-gradient(0deg, rgba(24, 101, 242, 0.32), rgba(24, 101, 242, 0.32)), ${Color.white}`,
|
|
5843
5933
|
border: "1px solid #1865F2"
|
|
5844
5934
|
},
|
|
5845
5935
|
pressed: {
|
|
@@ -5847,11 +5937,11 @@ var styles$5 = StyleSheet.create({
|
|
|
5847
5937
|
},
|
|
5848
5938
|
focused: {
|
|
5849
5939
|
outline: "none",
|
|
5850
|
-
border:
|
|
5940
|
+
border: `2px solid ${Color.blue}`
|
|
5851
5941
|
},
|
|
5852
5942
|
innerBox: {
|
|
5853
5943
|
boxSizing: "border-box",
|
|
5854
|
-
border:
|
|
5944
|
+
border: `1px solid transparent`,
|
|
5855
5945
|
borderRadius: 2,
|
|
5856
5946
|
display: "flex",
|
|
5857
5947
|
flex: 1,
|
|
@@ -5859,7 +5949,7 @@ var styles$5 = StyleSheet.create({
|
|
|
5859
5949
|
alignItems: "center"
|
|
5860
5950
|
},
|
|
5861
5951
|
innerBoxPressed: {
|
|
5862
|
-
border:
|
|
5952
|
+
border: `1px solid ${Color.white}`
|
|
5863
5953
|
},
|
|
5864
5954
|
activeIndicator: {
|
|
5865
5955
|
position: "absolute",
|
|
@@ -5884,7 +5974,7 @@ function imageTintColor(itemState, hovered, focused, pressed) {
|
|
|
5884
5974
|
}
|
|
5885
5975
|
class TabbarItem extends React.Component {
|
|
5886
5976
|
render() {
|
|
5887
|
-
|
|
5977
|
+
const {
|
|
5888
5978
|
onClick,
|
|
5889
5979
|
itemType,
|
|
5890
5980
|
itemState
|
|
@@ -5892,13 +5982,12 @@ class TabbarItem extends React.Component {
|
|
|
5892
5982
|
return /*#__PURE__*/React.createElement(Clickable, {
|
|
5893
5983
|
onClick: onClick,
|
|
5894
5984
|
disabled: itemState === "disabled"
|
|
5895
|
-
},
|
|
5896
|
-
|
|
5897
|
-
|
|
5898
|
-
|
|
5899
|
-
|
|
5900
|
-
|
|
5901
|
-
var tintColor = imageTintColor(itemState, hovered, focused, pressed);
|
|
5985
|
+
}, ({
|
|
5986
|
+
hovered,
|
|
5987
|
+
focused,
|
|
5988
|
+
pressed
|
|
5989
|
+
}) => {
|
|
5990
|
+
const tintColor = imageTintColor(itemState, hovered, focused, pressed);
|
|
5902
5991
|
return /*#__PURE__*/React.createElement(View$1, {
|
|
5903
5992
|
style: [styles$5.base, itemState !== "disabled" && hovered && styles$5.hovered, focused && styles$5.focused, pressed && styles$5.pressed]
|
|
5904
5993
|
}, /*#__PURE__*/React.createElement(View$1, {
|
|
@@ -5915,33 +6004,33 @@ class TabbarItem extends React.Component {
|
|
|
5915
6004
|
}
|
|
5916
6005
|
}
|
|
5917
6006
|
|
|
5918
|
-
|
|
6007
|
+
const styles$4 = StyleSheet.create({
|
|
5919
6008
|
tabbar: {
|
|
5920
6009
|
display: "flex",
|
|
5921
6010
|
flexDirection: "row",
|
|
5922
6011
|
background: Color.offWhite,
|
|
5923
6012
|
paddingTop: 2,
|
|
5924
6013
|
paddingBottom: 2,
|
|
5925
|
-
borderTop:
|
|
5926
|
-
borderBottom:
|
|
6014
|
+
borderTop: `1px solid ${Color.offBlack50}`,
|
|
6015
|
+
borderBottom: `1px solid ${Color.offBlack50}`
|
|
5927
6016
|
}
|
|
5928
6017
|
});
|
|
5929
6018
|
class Tabbar extends React.Component {
|
|
5930
|
-
constructor() {
|
|
5931
|
-
super(...
|
|
5932
|
-
|
|
6019
|
+
constructor(...args) {
|
|
6020
|
+
super(...args);
|
|
6021
|
+
this.state = {
|
|
5933
6022
|
selectedItem: 0
|
|
5934
|
-
}
|
|
6023
|
+
};
|
|
5935
6024
|
}
|
|
5936
6025
|
render() {
|
|
5937
|
-
|
|
6026
|
+
const {
|
|
5938
6027
|
items,
|
|
5939
6028
|
onSelect
|
|
5940
6029
|
} = this.props;
|
|
5941
6030
|
return /*#__PURE__*/React.createElement(View$1, {
|
|
5942
6031
|
style: styles$4.tabbar
|
|
5943
6032
|
}, items.map((item, index) => /*#__PURE__*/React.createElement(TabbarItem, {
|
|
5944
|
-
key:
|
|
6033
|
+
key: `tabbar-item-${index}`,
|
|
5945
6034
|
itemState: index === this.state.selectedItem ? "active" : "inactive",
|
|
5946
6035
|
itemType: item,
|
|
5947
6036
|
onClick: () => {
|
|
@@ -5954,25 +6043,28 @@ class Tabbar extends React.Component {
|
|
|
5954
6043
|
}
|
|
5955
6044
|
}
|
|
5956
6045
|
|
|
5957
|
-
|
|
6046
|
+
/**
|
|
6047
|
+
* A keypad with two pages of keys.
|
|
6048
|
+
*/
|
|
6049
|
+
const {
|
|
5958
6050
|
column: column$2,
|
|
5959
6051
|
row: row$4,
|
|
5960
6052
|
fullWidth: fullWidth$2
|
|
5961
6053
|
} = Styles;
|
|
5962
6054
|
class TwoPageKeypad extends React.Component {
|
|
5963
|
-
constructor() {
|
|
5964
|
-
super(...
|
|
5965
|
-
|
|
6055
|
+
constructor(...args) {
|
|
6056
|
+
super(...args);
|
|
6057
|
+
this.state = {
|
|
5966
6058
|
selectedPage: "Numbers"
|
|
5967
|
-
}
|
|
6059
|
+
};
|
|
5968
6060
|
}
|
|
5969
6061
|
render() {
|
|
5970
|
-
|
|
6062
|
+
const {
|
|
5971
6063
|
leftPage,
|
|
5972
6064
|
paginationEnabled,
|
|
5973
6065
|
rightPage
|
|
5974
6066
|
} = this.props;
|
|
5975
|
-
|
|
6067
|
+
const {
|
|
5976
6068
|
selectedPage
|
|
5977
6069
|
} = this.state;
|
|
5978
6070
|
if (paginationEnabled) {
|
|
@@ -6001,27 +6093,27 @@ class TwoPageKeypad extends React.Component {
|
|
|
6001
6093
|
}
|
|
6002
6094
|
}
|
|
6003
6095
|
}
|
|
6004
|
-
|
|
6096
|
+
TwoPageKeypad.propTypes = {
|
|
6005
6097
|
currentPage: PropTypes.oneOf([0, 1]).isRequired,
|
|
6006
6098
|
leftPage: PropTypes.node.isRequired,
|
|
6007
6099
|
paginationEnabled: PropTypes.bool.isRequired,
|
|
6008
6100
|
rightPage: PropTypes.node.isRequired
|
|
6009
|
-
}
|
|
6010
|
-
|
|
6101
|
+
};
|
|
6102
|
+
const styles$3 = StyleSheet.create({
|
|
6011
6103
|
keypad: {
|
|
6012
6104
|
// Set the background to light grey, so that when the user drags the
|
|
6013
6105
|
// keypad pages past the edges, there's a grey backdrop.
|
|
6014
6106
|
backgroundColor: offBlack16
|
|
6015
6107
|
},
|
|
6016
6108
|
borderTop: {
|
|
6017
|
-
borderTop:
|
|
6109
|
+
borderTop: `${innerBorderWidthPx}px ${innerBorderStyle} ` + `${innerBorderColor}`
|
|
6018
6110
|
},
|
|
6019
6111
|
borderLeft: {
|
|
6020
|
-
borderLeft:
|
|
6112
|
+
borderLeft: `${innerBorderWidthPx}px ${innerBorderStyle} ` + `${innerBorderColor}`,
|
|
6021
6113
|
boxSizing: "content-box"
|
|
6022
6114
|
}
|
|
6023
6115
|
});
|
|
6024
|
-
|
|
6116
|
+
const mapStateToProps$3 = state => {
|
|
6025
6117
|
return {
|
|
6026
6118
|
paginationEnabled: state.layout.paginationEnabled
|
|
6027
6119
|
};
|
|
@@ -6030,7 +6122,10 @@ var TwoPageKeypad$1 = connect(mapStateToProps$3, null, null, {
|
|
|
6030
6122
|
forwardRef: true
|
|
6031
6123
|
})(TwoPageKeypad);
|
|
6032
6124
|
|
|
6033
|
-
|
|
6125
|
+
/**
|
|
6126
|
+
* A keypad that includes all of the expression symbols.
|
|
6127
|
+
*/
|
|
6128
|
+
const {
|
|
6034
6129
|
row: row$3,
|
|
6035
6130
|
column: column$1,
|
|
6036
6131
|
oneColumn,
|
|
@@ -6044,7 +6139,7 @@ class ExpressionKeypad extends React.Component {
|
|
|
6044
6139
|
// contains more than four children.
|
|
6045
6140
|
|
|
6046
6141
|
render() {
|
|
6047
|
-
|
|
6142
|
+
const {
|
|
6048
6143
|
currentPage,
|
|
6049
6144
|
cursorContext,
|
|
6050
6145
|
dynamicJumpOut,
|
|
@@ -6052,7 +6147,7 @@ class ExpressionKeypad extends React.Component {
|
|
|
6052
6147
|
roundTopLeft,
|
|
6053
6148
|
roundTopRight
|
|
6054
6149
|
} = this.props;
|
|
6055
|
-
|
|
6150
|
+
let dismissOrJumpOutKey;
|
|
6056
6151
|
if (dynamicJumpOut) {
|
|
6057
6152
|
switch (cursorContext) {
|
|
6058
6153
|
case IN_PARENS:
|
|
@@ -6081,8 +6176,8 @@ class ExpressionKeypad extends React.Component {
|
|
|
6081
6176
|
} else {
|
|
6082
6177
|
dismissOrJumpOutKey = KeyConfigs.DISMISS;
|
|
6083
6178
|
}
|
|
6084
|
-
|
|
6085
|
-
|
|
6179
|
+
const rightPageStyle = [row$3, fullWidth$1, styles$2.rightPage, roundTopRight && roundedTopRight$1];
|
|
6180
|
+
const rightPage = /*#__PURE__*/React.createElement(View, {
|
|
6086
6181
|
style: rightPageStyle
|
|
6087
6182
|
}, /*#__PURE__*/React.createElement(View, {
|
|
6088
6183
|
style: [column$1, oneColumn]
|
|
@@ -6154,8 +6249,8 @@ class ExpressionKeypad extends React.Component {
|
|
|
6154
6249
|
keyConfig: dismissOrJumpOutKey,
|
|
6155
6250
|
borders: BorderStyles.LEFT
|
|
6156
6251
|
})));
|
|
6157
|
-
|
|
6158
|
-
|
|
6252
|
+
const leftPageStyle = [row$3, fullWidth$1, styles$2.leftPage, roundTopLeft && roundedTopLeft$2];
|
|
6253
|
+
const leftPage = /*#__PURE__*/React.createElement(View, {
|
|
6159
6254
|
style: leftPageStyle
|
|
6160
6255
|
}, /*#__PURE__*/React.createElement(View, {
|
|
6161
6256
|
style: [column$1, oneColumn]
|
|
@@ -6235,19 +6330,19 @@ class ExpressionKeypad extends React.Component {
|
|
|
6235
6330
|
});
|
|
6236
6331
|
}
|
|
6237
6332
|
}
|
|
6238
|
-
|
|
6333
|
+
ExpressionKeypad.propTypes = {
|
|
6239
6334
|
currentPage: PropTypes.number.isRequired,
|
|
6240
6335
|
cursorContext: cursorContextPropType.isRequired,
|
|
6241
6336
|
dynamicJumpOut: PropTypes.bool,
|
|
6242
6337
|
extraKeys: PropTypes.arrayOf(keyIdPropType),
|
|
6243
6338
|
roundTopLeft: PropTypes.bool,
|
|
6244
6339
|
roundTopRight: PropTypes.bool
|
|
6245
|
-
}
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
|
|
6340
|
+
};
|
|
6341
|
+
ExpressionKeypad.rows = 4;
|
|
6342
|
+
ExpressionKeypad.columns = 5;
|
|
6343
|
+
ExpressionKeypad.maxVisibleRows = 4;
|
|
6344
|
+
ExpressionKeypad.numPages = 2;
|
|
6345
|
+
const styles$2 = StyleSheet.create({
|
|
6251
6346
|
// NOTE(charlie): These backgrounds are applied to as to fill in some
|
|
6252
6347
|
// unfortunate 'cracks' in the layout. However, not all keys in the first
|
|
6253
6348
|
// page use this background color (namely, the 'command' keys, backspace and
|
|
@@ -6260,7 +6355,7 @@ var styles$2 = StyleSheet.create({
|
|
|
6260
6355
|
backgroundColor: controlGrey
|
|
6261
6356
|
}
|
|
6262
6357
|
});
|
|
6263
|
-
|
|
6358
|
+
const mapStateToProps$2 = state => {
|
|
6264
6359
|
return {
|
|
6265
6360
|
currentPage: state.pager.currentPage,
|
|
6266
6361
|
cursorContext: state.input.cursor.context,
|
|
@@ -6271,7 +6366,11 @@ var ExpressionKeypad$1 = connect(mapStateToProps$2, null, null, {
|
|
|
6271
6366
|
forwardRef: true
|
|
6272
6367
|
})(ExpressionKeypad);
|
|
6273
6368
|
|
|
6274
|
-
|
|
6369
|
+
/**
|
|
6370
|
+
* A keypad that includes the digits, as well as the symbols required to deal
|
|
6371
|
+
* with fractions, decimals, and percents.
|
|
6372
|
+
*/
|
|
6373
|
+
const {
|
|
6275
6374
|
row: row$2,
|
|
6276
6375
|
roundedTopLeft: roundedTopLeft$1,
|
|
6277
6376
|
roundedTopRight
|
|
@@ -6282,13 +6381,13 @@ class FractionKeypad extends React.Component {
|
|
|
6282
6381
|
// rows vertically.
|
|
6283
6382
|
|
|
6284
6383
|
render() {
|
|
6285
|
-
|
|
6384
|
+
const {
|
|
6286
6385
|
cursorContext,
|
|
6287
6386
|
dynamicJumpOut,
|
|
6288
6387
|
roundTopLeft,
|
|
6289
6388
|
roundTopRight
|
|
6290
6389
|
} = this.props;
|
|
6291
|
-
|
|
6390
|
+
let dismissOrJumpOutKey;
|
|
6292
6391
|
if (dynamicJumpOut) {
|
|
6293
6392
|
switch (cursorContext) {
|
|
6294
6393
|
case IN_PARENS:
|
|
@@ -6384,17 +6483,17 @@ class FractionKeypad extends React.Component {
|
|
|
6384
6483
|
})));
|
|
6385
6484
|
}
|
|
6386
6485
|
}
|
|
6387
|
-
|
|
6486
|
+
FractionKeypad.propTypes = {
|
|
6388
6487
|
cursorContext: cursorContextPropType.isRequired,
|
|
6389
6488
|
dynamicJumpOut: PropTypes.bool,
|
|
6390
6489
|
roundTopLeft: PropTypes.bool,
|
|
6391
6490
|
roundTopRight: PropTypes.bool
|
|
6392
|
-
}
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6397
|
-
|
|
6491
|
+
};
|
|
6492
|
+
FractionKeypad.rows = 4;
|
|
6493
|
+
FractionKeypad.columns = 4;
|
|
6494
|
+
FractionKeypad.maxVisibleRows = 5;
|
|
6495
|
+
FractionKeypad.numPages = 1;
|
|
6496
|
+
const mapStateToProps$1 = state => {
|
|
6398
6497
|
return {
|
|
6399
6498
|
cursorContext: state.input.cursor.context,
|
|
6400
6499
|
dynamicJumpOut: !state.layout.navigationPadEnabled
|
|
@@ -6406,7 +6505,7 @@ var FractionKeypad$1 = connect(mapStateToProps$1, null, null, {
|
|
|
6406
6505
|
|
|
6407
6506
|
class VelocityTracker {
|
|
6408
6507
|
constructor(options) {
|
|
6409
|
-
this.options =
|
|
6508
|
+
this.options = _extends({
|
|
6410
6509
|
velocityTimeout: 100
|
|
6411
6510
|
}, options);
|
|
6412
6511
|
this._events = [];
|
|
@@ -6439,13 +6538,13 @@ class VelocityTracker {
|
|
|
6439
6538
|
* @returns {number} the velocity associated with the tracker
|
|
6440
6539
|
*/
|
|
6441
6540
|
getVelocity() {
|
|
6442
|
-
|
|
6541
|
+
const events = this._getEvents();
|
|
6443
6542
|
if (events.length < 2) {
|
|
6444
6543
|
return 0;
|
|
6445
6544
|
} else {
|
|
6446
|
-
|
|
6447
|
-
|
|
6448
|
-
|
|
6545
|
+
const current = events[events.length - 1];
|
|
6546
|
+
const first = events[0];
|
|
6547
|
+
const dt = current.t - first.t;
|
|
6449
6548
|
return (current.x - first.x) / dt;
|
|
6450
6549
|
}
|
|
6451
6550
|
}
|
|
@@ -6459,8 +6558,8 @@ class VelocityTracker {
|
|
|
6459
6558
|
* milliseconds
|
|
6460
6559
|
*/
|
|
6461
6560
|
_getEvents() {
|
|
6462
|
-
|
|
6463
|
-
|
|
6561
|
+
const threshold = now() - this.options.velocityTimeout;
|
|
6562
|
+
const recentEvents = this._events.filter(event => {
|
|
6464
6563
|
return event.t > threshold;
|
|
6465
6564
|
});
|
|
6466
6565
|
this._events = [];
|
|
@@ -6468,32 +6567,30 @@ class VelocityTracker {
|
|
|
6468
6567
|
}
|
|
6469
6568
|
}
|
|
6470
6569
|
|
|
6471
|
-
|
|
6570
|
+
const keypadForType = {
|
|
6472
6571
|
[KeypadTypes.FRACTION]: FractionKeypad$1,
|
|
6473
6572
|
[KeypadTypes.EXPRESSION]: ExpressionKeypad$1
|
|
6474
6573
|
};
|
|
6475
|
-
|
|
6476
|
-
|
|
6574
|
+
const createStore = () => {
|
|
6575
|
+
const initialInputState = {
|
|
6477
6576
|
keyHandler: null,
|
|
6478
6577
|
cursor: {
|
|
6479
6578
|
context: NONE
|
|
6480
6579
|
}
|
|
6481
6580
|
};
|
|
6482
|
-
|
|
6483
|
-
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialInputState;
|
|
6484
|
-
var action = arguments.length > 1 ? arguments[1] : undefined;
|
|
6581
|
+
const inputReducer = function inputReducer(state = initialInputState, action) {
|
|
6485
6582
|
switch (action.type) {
|
|
6486
6583
|
case "SetKeyHandler":
|
|
6487
|
-
return
|
|
6584
|
+
return _extends({}, state, {
|
|
6488
6585
|
keyHandler: action.keyHandler
|
|
6489
6586
|
});
|
|
6490
6587
|
case "PressKey":
|
|
6491
|
-
|
|
6588
|
+
const keyConfig = KeyConfigs[action.key];
|
|
6492
6589
|
if (keyConfig.type !== KeyTypes.KEYPAD_NAVIGATION) {
|
|
6493
6590
|
// This is probably an anti-pattern but it works for the
|
|
6494
6591
|
// case where we don't actually control the state but we
|
|
6495
6592
|
// still want to communicate with the other object
|
|
6496
|
-
return
|
|
6593
|
+
return _extends({}, state, {
|
|
6497
6594
|
cursor: state.keyHandler(keyConfig.id)
|
|
6498
6595
|
});
|
|
6499
6596
|
}
|
|
@@ -6501,39 +6598,37 @@ var createStore = () => {
|
|
|
6501
6598
|
// TODO(kevinb) get state from MathQuill and store it?
|
|
6502
6599
|
return state;
|
|
6503
6600
|
case "SetCursor":
|
|
6504
|
-
return
|
|
6601
|
+
return _extends({}, state, {
|
|
6505
6602
|
cursor: action.cursor
|
|
6506
6603
|
});
|
|
6507
6604
|
default:
|
|
6508
6605
|
return state;
|
|
6509
6606
|
}
|
|
6510
6607
|
};
|
|
6511
|
-
|
|
6512
|
-
|
|
6608
|
+
const defaultKeypadType = KeypadTypes.EXPRESSION;
|
|
6609
|
+
const initialKeypadState = {
|
|
6513
6610
|
extraKeys: ["x", "y", Keys.THETA, Keys.PI],
|
|
6514
6611
|
keypadType: defaultKeypadType,
|
|
6515
6612
|
active: false
|
|
6516
6613
|
};
|
|
6517
|
-
|
|
6518
|
-
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialKeypadState;
|
|
6519
|
-
var action = arguments.length > 1 ? arguments[1] : undefined;
|
|
6614
|
+
const keypadReducer = function keypadReducer(state = initialKeypadState, action) {
|
|
6520
6615
|
switch (action.type) {
|
|
6521
6616
|
case "DismissKeypad":
|
|
6522
|
-
return
|
|
6617
|
+
return _extends({}, state, {
|
|
6523
6618
|
active: false
|
|
6524
6619
|
});
|
|
6525
6620
|
case "ActivateKeypad":
|
|
6526
|
-
return
|
|
6621
|
+
return _extends({}, state, {
|
|
6527
6622
|
active: true
|
|
6528
6623
|
});
|
|
6529
6624
|
case "ConfigureKeypad":
|
|
6530
|
-
return
|
|
6625
|
+
return _extends({}, state, {
|
|
6531
6626
|
// Default `extraKeys` to the empty array.
|
|
6532
6627
|
extraKeys: []
|
|
6533
6628
|
}, action.configuration);
|
|
6534
6629
|
case "PressKey":
|
|
6535
6630
|
// @ts-expect-error [FEI-5003] - TS2339 - Property 'key' does not exist on type '{ type: string; }'.
|
|
6536
|
-
|
|
6631
|
+
const keyConfig = KeyConfigs[action.key];
|
|
6537
6632
|
// NOTE(charlie): Our keypad system operates by triggering key
|
|
6538
6633
|
// presses with key IDs in a dumb manner, such that the keys
|
|
6539
6634
|
// don't know what they can do--instead, the store is
|
|
@@ -6555,8 +6650,8 @@ var createStore = () => {
|
|
|
6555
6650
|
// We default to the right-most page. This is done so-as to enforce a
|
|
6556
6651
|
// consistent orientation between the view pager layout and the flattened
|
|
6557
6652
|
// layout, where our default page appears on the far right.
|
|
6558
|
-
|
|
6559
|
-
|
|
6653
|
+
const getDefaultPage = numPages => numPages - 1;
|
|
6654
|
+
const initialPagerState = {
|
|
6560
6655
|
animateToPosition: false,
|
|
6561
6656
|
currentPage: getDefaultPage(keypadForType[defaultKeypadType].numPages),
|
|
6562
6657
|
// The cumulative differential in the horizontal direction for the
|
|
@@ -6566,32 +6661,30 @@ var createStore = () => {
|
|
|
6566
6661
|
pageWidthPx: 0,
|
|
6567
6662
|
velocityTracker: new VelocityTracker()
|
|
6568
6663
|
};
|
|
6569
|
-
|
|
6570
|
-
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialPagerState;
|
|
6571
|
-
var action = arguments.length > 1 ? arguments[1] : undefined;
|
|
6664
|
+
const pagerReducer = function pagerReducer(state = initialPagerState, action) {
|
|
6572
6665
|
switch (action.type) {
|
|
6573
6666
|
case "ConfigureKeypad":
|
|
6574
6667
|
// @ts-expect-error [FEI-5003] - TS2339 - Property 'configuration' does not exist on type '{ type: string; }'.
|
|
6575
|
-
|
|
6668
|
+
const {
|
|
6576
6669
|
keypadType
|
|
6577
6670
|
} = action.configuration;
|
|
6578
|
-
|
|
6671
|
+
const {
|
|
6579
6672
|
numPages
|
|
6580
6673
|
} = keypadForType[keypadType];
|
|
6581
|
-
return
|
|
6674
|
+
return _extends({}, state, {
|
|
6582
6675
|
numPages,
|
|
6583
6676
|
animateToPosition: false,
|
|
6584
6677
|
currentPage: getDefaultPage(numPages),
|
|
6585
6678
|
dx: 0
|
|
6586
6679
|
});
|
|
6587
6680
|
case "SetPageSize":
|
|
6588
|
-
return
|
|
6681
|
+
return _extends({}, state, {
|
|
6589
6682
|
// @ts-expect-error [FEI-5003] - TS2339 - Property 'pageWidthPx' does not exist on type '{ type: string; }'.
|
|
6590
6683
|
pageWidthPx: action.pageWidthPx
|
|
6591
6684
|
});
|
|
6592
6685
|
case "PressKey":
|
|
6593
6686
|
// @ts-expect-error [FEI-5003] - TS2339 - Property 'key' does not exist on type '{ type: string; }'.
|
|
6594
|
-
|
|
6687
|
+
const keyConfig = KeyConfigs[action.key];
|
|
6595
6688
|
|
|
6596
6689
|
// Reset the keypad page if the user performs a math operation.
|
|
6597
6690
|
if (keyConfig.type === KeyTypes.VALUE || keyConfig.type === KeyTypes.OPERATOR) {
|
|
@@ -6601,22 +6694,22 @@ var createStore = () => {
|
|
|
6601
6694
|
}
|
|
6602
6695
|
return state;
|
|
6603
6696
|
case "ResetKeypadPage":
|
|
6604
|
-
return
|
|
6697
|
+
return _extends({}, state, {
|
|
6605
6698
|
animateToPosition: true,
|
|
6606
6699
|
// We start at the right-most page.
|
|
6607
6700
|
currentPage: getDefaultPage(state.numPages),
|
|
6608
6701
|
dx: 0
|
|
6609
6702
|
});
|
|
6610
6703
|
case "PageKeypadRight":
|
|
6611
|
-
|
|
6612
|
-
return
|
|
6704
|
+
const nextPage = Math.min(state.currentPage + 1, state.numPages - 1);
|
|
6705
|
+
return _extends({}, state, {
|
|
6613
6706
|
animateToPosition: true,
|
|
6614
6707
|
currentPage: nextPage,
|
|
6615
6708
|
dx: 0
|
|
6616
6709
|
});
|
|
6617
6710
|
case "PageKeypadLeft":
|
|
6618
|
-
|
|
6619
|
-
return
|
|
6711
|
+
const prevPage = Math.max(state.currentPage - 1, 0);
|
|
6712
|
+
return _extends({}, state, {
|
|
6620
6713
|
animateToPosition: true,
|
|
6621
6714
|
currentPage: prevPage,
|
|
6622
6715
|
dx: 0
|
|
@@ -6624,28 +6717,28 @@ var createStore = () => {
|
|
|
6624
6717
|
case "OnSwipeChange":
|
|
6625
6718
|
// @ts-expect-error [FEI-5003] - TS2339 - Property 'dx' does not exist on type '{ type: string; }'.
|
|
6626
6719
|
state.velocityTracker.push(action.dx);
|
|
6627
|
-
return
|
|
6720
|
+
return _extends({}, state, {
|
|
6628
6721
|
animateToPosition: false,
|
|
6629
6722
|
// @ts-expect-error [FEI-5003] - TS2339 - Property 'dx' does not exist on type '{ type: string; }'.
|
|
6630
6723
|
dx: action.dx
|
|
6631
6724
|
});
|
|
6632
6725
|
case "OnSwipeEnd":
|
|
6633
|
-
|
|
6726
|
+
const {
|
|
6634
6727
|
pageWidthPx,
|
|
6635
6728
|
velocityTracker
|
|
6636
6729
|
} = state;
|
|
6637
6730
|
// @ts-expect-error [FEI-5003] - TS2339 - Property 'dx' does not exist on type '{ type: string; }'.
|
|
6638
|
-
|
|
6731
|
+
const {
|
|
6639
6732
|
dx
|
|
6640
6733
|
} = action;
|
|
6641
|
-
|
|
6734
|
+
const velocity = velocityTracker.getVelocity();
|
|
6642
6735
|
|
|
6643
6736
|
// NOTE(charlie): These will need refinement. The velocity comes
|
|
6644
6737
|
// from Framer.
|
|
6645
|
-
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6738
|
+
const minFlingVelocity = 0.1;
|
|
6739
|
+
const minFlingDistance = 10;
|
|
6740
|
+
const shouldPageRight = dx < -pageWidthPx / 2 || velocity < -minFlingVelocity && dx < -minFlingDistance;
|
|
6741
|
+
const shouldPageLeft = dx > pageWidthPx / 2 || velocity > minFlingVelocity && dx > minFlingDistance;
|
|
6649
6742
|
if (shouldPageRight) {
|
|
6650
6743
|
return pagerReducer(state, {
|
|
6651
6744
|
type: "PageKeypadRight"
|
|
@@ -6655,7 +6748,7 @@ var createStore = () => {
|
|
|
6655
6748
|
type: "PageKeypadLeft"
|
|
6656
6749
|
});
|
|
6657
6750
|
}
|
|
6658
|
-
return
|
|
6751
|
+
return _extends({}, state, {
|
|
6659
6752
|
animateToPosition: true,
|
|
6660
6753
|
dx: 0
|
|
6661
6754
|
});
|
|
@@ -6663,7 +6756,7 @@ var createStore = () => {
|
|
|
6663
6756
|
return state;
|
|
6664
6757
|
}
|
|
6665
6758
|
};
|
|
6666
|
-
|
|
6759
|
+
const createGestureManager = swipeEnabled => {
|
|
6667
6760
|
return new GestureManager({
|
|
6668
6761
|
swipeEnabled
|
|
6669
6762
|
}, {
|
|
@@ -6686,23 +6779,21 @@ var createStore = () => {
|
|
|
6686
6779
|
});
|
|
6687
6780
|
},
|
|
6688
6781
|
onClick: (key, layoutProps, inPopover) => {
|
|
6689
|
-
store.dispatch(
|
|
6782
|
+
store.dispatch(_extends({
|
|
6690
6783
|
type: "PressKey",
|
|
6691
6784
|
key
|
|
6692
|
-
}, layoutProps
|
|
6785
|
+
}, layoutProps, {
|
|
6693
6786
|
inPopover
|
|
6694
6787
|
}));
|
|
6695
6788
|
}
|
|
6696
6789
|
}, [], [Keys.BACKSPACE, Keys.UP, Keys.RIGHT, Keys.DOWN, Keys.LEFT]);
|
|
6697
6790
|
};
|
|
6698
|
-
|
|
6791
|
+
const initialGestureState = {
|
|
6699
6792
|
popover: null,
|
|
6700
6793
|
focus: null,
|
|
6701
6794
|
gestureManager: createGestureManager(keypadForType[defaultKeypadType].numPages > 1)
|
|
6702
6795
|
};
|
|
6703
|
-
|
|
6704
|
-
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialGestureState;
|
|
6705
|
-
var action = arguments.length > 1 ? arguments[1] : undefined;
|
|
6796
|
+
const gestureReducer = function gestureReducer(state = initialGestureState, action) {
|
|
6706
6797
|
switch (action.type) {
|
|
6707
6798
|
case "DismissKeypad":
|
|
6708
6799
|
// NOTE(charlie): In the past, we enforced the "gesture manager
|
|
@@ -6720,15 +6811,15 @@ var createStore = () => {
|
|
|
6720
6811
|
state.gestureManager.enableEventTracking();
|
|
6721
6812
|
return state;
|
|
6722
6813
|
case "SetActiveNodes":
|
|
6723
|
-
return
|
|
6814
|
+
return _extends({}, state, action.activeNodes);
|
|
6724
6815
|
case "ConfigureKeypad":
|
|
6725
|
-
|
|
6816
|
+
const {
|
|
6726
6817
|
keypadType
|
|
6727
6818
|
} = action.configuration;
|
|
6728
|
-
|
|
6819
|
+
const {
|
|
6729
6820
|
numPages
|
|
6730
6821
|
} = keypadForType[keypadType];
|
|
6731
|
-
|
|
6822
|
+
const swipeEnabled = numPages > 1;
|
|
6732
6823
|
return {
|
|
6733
6824
|
popover: null,
|
|
6734
6825
|
focus: null,
|
|
@@ -6741,21 +6832,19 @@ var createStore = () => {
|
|
|
6741
6832
|
|
|
6742
6833
|
// Used to generate unique animation IDs for the echo animations. The actual
|
|
6743
6834
|
// values are irrelevant as long as they are unique.
|
|
6744
|
-
|
|
6745
|
-
|
|
6835
|
+
let _lastAnimationId = 0;
|
|
6836
|
+
const initialEchoState = {
|
|
6746
6837
|
echoes: []
|
|
6747
6838
|
};
|
|
6748
|
-
|
|
6749
|
-
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialEchoState;
|
|
6750
|
-
var action = arguments.length > 1 ? arguments[1] : undefined;
|
|
6839
|
+
const echoReducer = function echoReducer(state = initialEchoState, action) {
|
|
6751
6840
|
switch (action.type) {
|
|
6752
6841
|
case "PressKey":
|
|
6753
|
-
|
|
6842
|
+
const keyConfig = KeyConfigs[action.key];
|
|
6754
6843
|
|
|
6755
6844
|
// Add in the echo animation if the user performs a math
|
|
6756
6845
|
// operation.
|
|
6757
6846
|
if (keyConfig.type === KeyTypes.VALUE || keyConfig.type === KeyTypes.OPERATOR) {
|
|
6758
|
-
return
|
|
6847
|
+
return _extends({}, state, {
|
|
6759
6848
|
echoes: [...state.echoes, {
|
|
6760
6849
|
animationId: "" + _lastAnimationId++,
|
|
6761
6850
|
animationType: action.inPopover ? EchoAnimationTypes.LONG_FADE_ONLY : EchoAnimationTypes.FADE_ONLY,
|
|
@@ -6767,18 +6856,18 @@ var createStore = () => {
|
|
|
6767
6856
|
}
|
|
6768
6857
|
return state;
|
|
6769
6858
|
case "RemoveEcho":
|
|
6770
|
-
|
|
6859
|
+
const remainingEchoes = state.echoes.filter(echo => {
|
|
6771
6860
|
// @ts-expect-error [FEI-5003] - TS2339 - Property 'animationId' does not exist on type 'never'.
|
|
6772
6861
|
return echo.animationId !== action.animationId;
|
|
6773
6862
|
});
|
|
6774
|
-
return
|
|
6863
|
+
return _extends({}, state, {
|
|
6775
6864
|
echoes: remainingEchoes
|
|
6776
6865
|
});
|
|
6777
6866
|
default:
|
|
6778
6867
|
return state;
|
|
6779
6868
|
}
|
|
6780
6869
|
};
|
|
6781
|
-
|
|
6870
|
+
const initialLayoutState = {
|
|
6782
6871
|
gridDimensions: {
|
|
6783
6872
|
numRows: keypadForType[defaultKeypadType].rows,
|
|
6784
6873
|
numColumns: keypadForType[defaultKeypadType].columns,
|
|
@@ -6802,25 +6891,25 @@ var createStore = () => {
|
|
|
6802
6891
|
* Compute the additional layout state based on the provided page and grid
|
|
6803
6892
|
* dimensions.
|
|
6804
6893
|
*/
|
|
6805
|
-
|
|
6806
|
-
|
|
6894
|
+
const layoutParametersForDimensions = (pageDimensions, gridDimensions) => {
|
|
6895
|
+
const {
|
|
6807
6896
|
pageWidthPx,
|
|
6808
6897
|
pageHeightPx
|
|
6809
6898
|
} = pageDimensions;
|
|
6810
6899
|
|
|
6811
6900
|
// Determine the device type and orientation.
|
|
6812
|
-
|
|
6813
|
-
|
|
6901
|
+
const deviceOrientation = pageWidthPx > pageHeightPx ? DeviceOrientations.LANDSCAPE : DeviceOrientations.PORTRAIT;
|
|
6902
|
+
const deviceType = Math.min(pageWidthPx, pageHeightPx) > tabletCutoffPx ? DeviceTypes.TABLET : DeviceTypes.PHONE;
|
|
6814
6903
|
|
|
6815
6904
|
// Using that information, make some decisions (or assumptions)
|
|
6816
6905
|
// about the resulting layout.
|
|
6817
|
-
|
|
6818
|
-
|
|
6819
|
-
|
|
6906
|
+
const navigationPadEnabled = deviceType === DeviceTypes.TABLET;
|
|
6907
|
+
const paginationEnabled = deviceType === DeviceTypes.PHONE && deviceOrientation === DeviceOrientations.PORTRAIT;
|
|
6908
|
+
const deviceInfo = {
|
|
6820
6909
|
deviceOrientation,
|
|
6821
6910
|
deviceType
|
|
6822
6911
|
};
|
|
6823
|
-
|
|
6912
|
+
const layoutOptions = {
|
|
6824
6913
|
navigationPadEnabled,
|
|
6825
6914
|
paginationEnabled,
|
|
6826
6915
|
// HACK(charlie): It's not great that we're making assumptions about
|
|
@@ -6832,47 +6921,45 @@ var createStore = () => {
|
|
|
6832
6921
|
// of error.
|
|
6833
6922
|
toolbarEnabled: true
|
|
6834
6923
|
};
|
|
6835
|
-
return
|
|
6924
|
+
return _extends({}, computeLayoutParameters(gridDimensions, pageDimensions, deviceInfo, layoutOptions), {
|
|
6836
6925
|
// Pass along some of the layout information, so that other
|
|
6837
6926
|
// components in the heirarchy can adapt appropriately.
|
|
6838
6927
|
navigationPadEnabled,
|
|
6839
6928
|
paginationEnabled
|
|
6840
6929
|
});
|
|
6841
6930
|
};
|
|
6842
|
-
|
|
6843
|
-
var state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialLayoutState;
|
|
6844
|
-
var action = arguments.length > 1 ? arguments[1] : undefined;
|
|
6931
|
+
const layoutReducer = function layoutReducer(state = initialLayoutState, action) {
|
|
6845
6932
|
switch (action.type) {
|
|
6846
6933
|
case "ConfigureKeypad":
|
|
6847
|
-
|
|
6934
|
+
const {
|
|
6848
6935
|
keypadType
|
|
6849
6936
|
} = action.configuration;
|
|
6850
|
-
|
|
6937
|
+
const gridDimensions = {
|
|
6851
6938
|
numRows: keypadForType[keypadType].rows,
|
|
6852
6939
|
numColumns: keypadForType[keypadType].columns,
|
|
6853
6940
|
numMaxVisibleRows: keypadForType[keypadType].maxVisibleRows,
|
|
6854
6941
|
numPages: keypadForType[keypadType].numPages
|
|
6855
6942
|
};
|
|
6856
|
-
return
|
|
6943
|
+
return _extends({}, state, layoutParametersForDimensions(state.pageDimensions, gridDimensions), {
|
|
6857
6944
|
gridDimensions
|
|
6858
6945
|
});
|
|
6859
6946
|
case "SetPageSize":
|
|
6860
|
-
|
|
6947
|
+
const {
|
|
6861
6948
|
pageWidthPx,
|
|
6862
6949
|
pageHeightPx
|
|
6863
6950
|
} = action;
|
|
6864
|
-
|
|
6951
|
+
const pageDimensions = {
|
|
6865
6952
|
pageWidthPx,
|
|
6866
6953
|
pageHeightPx
|
|
6867
6954
|
};
|
|
6868
|
-
return
|
|
6955
|
+
return _extends({}, state, layoutParametersForDimensions(pageDimensions, state.gridDimensions), {
|
|
6869
6956
|
pageDimensions
|
|
6870
6957
|
});
|
|
6871
6958
|
default:
|
|
6872
6959
|
return state;
|
|
6873
6960
|
}
|
|
6874
6961
|
};
|
|
6875
|
-
|
|
6962
|
+
const reducer = Redux.combineReducers({
|
|
6876
6963
|
input: inputReducer,
|
|
6877
6964
|
keypad: keypadReducer,
|
|
6878
6965
|
pager: pagerReducer,
|
|
@@ -6885,11 +6972,15 @@ var createStore = () => {
|
|
|
6885
6972
|
// gesture manager to dispatch actions on the store in its callbacks. We
|
|
6886
6973
|
// should come up with a better pattern to remove the two-way dependency.
|
|
6887
6974
|
// eslint-disable-next-line import/no-deprecated
|
|
6888
|
-
|
|
6975
|
+
const store = Redux.createStore(reducer);
|
|
6889
6976
|
return store;
|
|
6890
6977
|
};
|
|
6891
6978
|
|
|
6892
|
-
|
|
6979
|
+
/**
|
|
6980
|
+
* A component that renders a navigation pad, which consists of an arrow for
|
|
6981
|
+
* each possible direction.
|
|
6982
|
+
*/
|
|
6983
|
+
const {
|
|
6893
6984
|
row: row$1,
|
|
6894
6985
|
column,
|
|
6895
6986
|
centered: centered$1,
|
|
@@ -6900,11 +6991,11 @@ class NavigationPad extends React.Component {
|
|
|
6900
6991
|
render() {
|
|
6901
6992
|
// TODO(charlie): Disable the navigational arrows depending on the
|
|
6902
6993
|
// cursor context.
|
|
6903
|
-
|
|
6994
|
+
const {
|
|
6904
6995
|
roundTopLeft,
|
|
6905
6996
|
style
|
|
6906
6997
|
} = this.props;
|
|
6907
|
-
|
|
6998
|
+
const containerStyle = [column, centered$1, styles$1.container, roundTopLeft && roundedTopLeft, ...(Array.isArray(style) ? style : [style])];
|
|
6908
6999
|
return /*#__PURE__*/React.createElement(View, {
|
|
6909
7000
|
style: containerStyle
|
|
6910
7001
|
}, /*#__PURE__*/React.createElement(View, {
|
|
@@ -6934,14 +7025,14 @@ class NavigationPad extends React.Component {
|
|
|
6934
7025
|
})));
|
|
6935
7026
|
}
|
|
6936
7027
|
}
|
|
6937
|
-
|
|
7028
|
+
NavigationPad.propTypes = {
|
|
6938
7029
|
roundTopLeft: PropTypes.bool,
|
|
6939
7030
|
style: PropTypes.any
|
|
6940
|
-
}
|
|
6941
|
-
|
|
6942
|
-
|
|
6943
|
-
|
|
6944
|
-
|
|
7031
|
+
};
|
|
7032
|
+
const buttonSizePx = 48;
|
|
7033
|
+
const borderRadiusPx = 4;
|
|
7034
|
+
const borderWidthPx$1 = 1;
|
|
7035
|
+
const styles$1 = StyleSheet.create({
|
|
6945
7036
|
container: {
|
|
6946
7037
|
backgroundColor: controlGrey,
|
|
6947
7038
|
width: navigationPadWidthPx
|
|
@@ -6991,7 +7082,7 @@ var styles$1 = StyleSheet.create({
|
|
|
6991
7082
|
}
|
|
6992
7083
|
});
|
|
6993
7084
|
|
|
6994
|
-
|
|
7085
|
+
const {
|
|
6995
7086
|
row,
|
|
6996
7087
|
centered,
|
|
6997
7088
|
fullWidth
|
|
@@ -6999,13 +7090,13 @@ var {
|
|
|
6999
7090
|
|
|
7000
7091
|
// eslint-disable-next-line react/no-unsafe
|
|
7001
7092
|
class KeypadContainer extends React.Component {
|
|
7002
|
-
constructor() {
|
|
7003
|
-
super(...
|
|
7004
|
-
|
|
7093
|
+
constructor(...args) {
|
|
7094
|
+
super(...args);
|
|
7095
|
+
this.state = {
|
|
7005
7096
|
hasBeenActivated: false,
|
|
7006
7097
|
viewportWidth: "100vw"
|
|
7007
|
-
}
|
|
7008
|
-
|
|
7098
|
+
};
|
|
7099
|
+
this._throttleResizeHandler = () => {
|
|
7009
7100
|
// Throttle the resize callbacks.
|
|
7010
7101
|
// https://developer.mozilla.org/en-US/docs/Web/Events/resize
|
|
7011
7102
|
if (this._resizeTimeout == null) {
|
|
@@ -7014,23 +7105,23 @@ class KeypadContainer extends React.Component {
|
|
|
7014
7105
|
this._onResize();
|
|
7015
7106
|
}, 66);
|
|
7016
7107
|
}
|
|
7017
|
-
}
|
|
7018
|
-
|
|
7108
|
+
};
|
|
7109
|
+
this._onResize = () => {
|
|
7019
7110
|
// Whenever the page resizes, we need to force an update, as the button
|
|
7020
7111
|
// heights and keypad width are computed based on horizontal space.
|
|
7021
7112
|
this.setState({
|
|
7022
7113
|
viewportWidth: window.innerWidth
|
|
7023
7114
|
});
|
|
7024
7115
|
this.props.onPageSizeChange(window.innerWidth, window.innerHeight);
|
|
7025
|
-
}
|
|
7026
|
-
|
|
7027
|
-
|
|
7116
|
+
};
|
|
7117
|
+
this.renderKeypad = () => {
|
|
7118
|
+
const {
|
|
7028
7119
|
extraKeys,
|
|
7029
7120
|
keypadType,
|
|
7030
7121
|
layoutMode,
|
|
7031
7122
|
navigationPadEnabled
|
|
7032
7123
|
} = this.props;
|
|
7033
|
-
|
|
7124
|
+
const keypadProps = {
|
|
7034
7125
|
extraKeys,
|
|
7035
7126
|
// HACK(charlie): In order to properly round the corners of the
|
|
7036
7127
|
// compact keypad, we need to instruct some of our child views to
|
|
@@ -7055,7 +7146,7 @@ class KeypadContainer extends React.Component {
|
|
|
7055
7146
|
default:
|
|
7056
7147
|
throw new Error("Invalid keypad type: " + keypadType);
|
|
7057
7148
|
}
|
|
7058
|
-
}
|
|
7149
|
+
};
|
|
7059
7150
|
}
|
|
7060
7151
|
UNSAFE_componentWillMount() {
|
|
7061
7152
|
if (this.props.active) {
|
|
@@ -7089,23 +7180,23 @@ class KeypadContainer extends React.Component {
|
|
|
7089
7180
|
window.removeEventListener("orientationchange", this._throttleResizeHandler);
|
|
7090
7181
|
}
|
|
7091
7182
|
render() {
|
|
7092
|
-
|
|
7183
|
+
const {
|
|
7093
7184
|
active,
|
|
7094
7185
|
layoutMode,
|
|
7095
7186
|
navigationPadEnabled,
|
|
7096
7187
|
onElementMounted,
|
|
7097
7188
|
style
|
|
7098
7189
|
} = this.props;
|
|
7099
|
-
|
|
7190
|
+
const {
|
|
7100
7191
|
hasBeenActivated
|
|
7101
7192
|
} = this.state;
|
|
7102
7193
|
|
|
7103
7194
|
// NOTE(charlie): We render the transforms as pure inline styles to
|
|
7104
7195
|
// avoid an Aphrodite bug in mobile Safari.
|
|
7105
7196
|
// See: https://github.com/Khan/aphrodite/issues/68.
|
|
7106
|
-
|
|
7107
|
-
|
|
7108
|
-
|
|
7197
|
+
const dynamicStyle = _extends({}, active ? inlineStyles.active : inlineStyles.hidden, !active && !hasBeenActivated ? inlineStyles.invisible : {});
|
|
7198
|
+
const keypadContainerStyle = [row, centered, fullWidth, styles.keypadContainer, ...(Array.isArray(style) ? style : [style])];
|
|
7199
|
+
const keypadStyle = [row, styles.keypadBorder, layoutMode === LayoutModes.FULLSCREEN ? styles.fullscreen : styles.compact];
|
|
7109
7200
|
|
|
7110
7201
|
// TODO(charlie): When the keypad is shorter than the width of the
|
|
7111
7202
|
// screen, add a border on its left and right edges, and round out the
|
|
@@ -7130,7 +7221,7 @@ class KeypadContainer extends React.Component {
|
|
|
7130
7221
|
}, this.renderKeypad())));
|
|
7131
7222
|
}
|
|
7132
7223
|
}
|
|
7133
|
-
|
|
7224
|
+
KeypadContainer.propTypes = {
|
|
7134
7225
|
active: PropTypes.bool,
|
|
7135
7226
|
extraKeys: PropTypes.arrayOf(keyIdPropType),
|
|
7136
7227
|
keypadType: PropTypes.oneOf(Object.keys(KeypadTypes)).isRequired,
|
|
@@ -7142,16 +7233,16 @@ _defineProperty(KeypadContainer, "propTypes", {
|
|
|
7142
7233
|
onElementMounted: PropTypes.func,
|
|
7143
7234
|
onPageSizeChange: PropTypes.func.isRequired,
|
|
7144
7235
|
style: PropTypes.any
|
|
7145
|
-
}
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
|
|
7236
|
+
};
|
|
7237
|
+
const keypadAnimationDurationMs = 300;
|
|
7238
|
+
const borderWidthPx = 1;
|
|
7239
|
+
const styles = StyleSheet.create({
|
|
7149
7240
|
keypadContainer: {
|
|
7150
7241
|
bottom: 0,
|
|
7151
7242
|
left: 0,
|
|
7152
7243
|
right: 0,
|
|
7153
7244
|
position: "fixed",
|
|
7154
|
-
transition:
|
|
7245
|
+
transition: `${keypadAnimationDurationMs}ms ease-out`,
|
|
7155
7246
|
transitionProperty: "transform",
|
|
7156
7247
|
zIndex: keypad
|
|
7157
7248
|
},
|
|
@@ -7172,7 +7263,7 @@ var styles = StyleSheet.create({
|
|
|
7172
7263
|
},
|
|
7173
7264
|
navigationPadContainer: {
|
|
7174
7265
|
// Add a separator between the navigation pad and the keypad.
|
|
7175
|
-
borderRight:
|
|
7266
|
+
borderRight: `${innerBorderWidthPx}px ${innerBorderStyle} ` + `${innerBorderColor}`,
|
|
7176
7267
|
boxSizing: "content-box"
|
|
7177
7268
|
},
|
|
7178
7269
|
// Defer to the navigation pad, such that the navigation pad is always
|
|
@@ -7187,7 +7278,7 @@ var styles = StyleSheet.create({
|
|
|
7187
7278
|
});
|
|
7188
7279
|
|
|
7189
7280
|
// Note: these don't go through an autoprefixer/aphrodite.
|
|
7190
|
-
|
|
7281
|
+
const inlineStyles = {
|
|
7191
7282
|
// If the keypad is yet to have ever been activated, we keep it invisible
|
|
7192
7283
|
// so as to avoid, e.g., the keypad flashing at the bottom of the page
|
|
7193
7284
|
// during the initial render.
|
|
@@ -7201,13 +7292,13 @@ var inlineStyles = {
|
|
|
7201
7292
|
transform: "translate3d(0, 0, 0)"
|
|
7202
7293
|
}
|
|
7203
7294
|
};
|
|
7204
|
-
|
|
7205
|
-
return
|
|
7295
|
+
const mapStateToProps = state => {
|
|
7296
|
+
return _extends({}, state.keypad, {
|
|
7206
7297
|
layoutMode: state.layout.layoutMode,
|
|
7207
7298
|
navigationPadEnabled: state.layout.navigationPadEnabled
|
|
7208
7299
|
});
|
|
7209
7300
|
};
|
|
7210
|
-
|
|
7301
|
+
const mapDispatchToProps = dispatch => {
|
|
7211
7302
|
return {
|
|
7212
7303
|
onPageSizeChange: (pageWidthPx, pageHeightPx) => {
|
|
7213
7304
|
dispatch(setPageSize(pageWidthPx, pageHeightPx));
|
|
@@ -7218,19 +7309,19 @@ var KeypadContainer$1 = connect(mapStateToProps, mapDispatchToProps, null, {
|
|
|
7218
7309
|
forwardRef: true
|
|
7219
7310
|
})(KeypadContainer);
|
|
7220
7311
|
|
|
7221
|
-
|
|
7312
|
+
const _excluded = ["onElementMounted"];
|
|
7222
7313
|
class ProvidedKeypad extends React.Component {
|
|
7223
|
-
constructor() {
|
|
7224
|
-
super(...
|
|
7225
|
-
|
|
7226
|
-
|
|
7227
|
-
|
|
7314
|
+
constructor(...args) {
|
|
7315
|
+
super(...args);
|
|
7316
|
+
this.mounted = void 0;
|
|
7317
|
+
this.store = void 0;
|
|
7318
|
+
this.activate = () => {
|
|
7228
7319
|
this.store.dispatch(activateKeypad());
|
|
7229
|
-
}
|
|
7230
|
-
|
|
7320
|
+
};
|
|
7321
|
+
this.dismiss = () => {
|
|
7231
7322
|
this.store.dispatch(dismissKeypad());
|
|
7232
|
-
}
|
|
7233
|
-
|
|
7323
|
+
};
|
|
7324
|
+
this.configure = (configuration, cb) => {
|
|
7234
7325
|
this.store.dispatch(configureKeypad(configuration));
|
|
7235
7326
|
|
|
7236
7327
|
// HACK(charlie): In Perseus, triggering a focus causes the keypad to
|
|
@@ -7241,16 +7332,16 @@ class ProvidedKeypad extends React.Component {
|
|
|
7241
7332
|
// would require middleware, etc., so we just hack it on with
|
|
7242
7333
|
// `setTimeout` for now.
|
|
7243
7334
|
setTimeout(() => cb && cb());
|
|
7244
|
-
}
|
|
7245
|
-
|
|
7335
|
+
};
|
|
7336
|
+
this.setCursor = cursor => {
|
|
7246
7337
|
this.store.dispatch(setCursor(cursor));
|
|
7247
|
-
}
|
|
7248
|
-
|
|
7338
|
+
};
|
|
7339
|
+
this.setKeyHandler = keyHandler => {
|
|
7249
7340
|
this.store.dispatch(setKeyHandler(keyHandler));
|
|
7250
|
-
}
|
|
7251
|
-
|
|
7341
|
+
};
|
|
7342
|
+
this.getDOMNode = () => {
|
|
7252
7343
|
return ReactDOM.findDOMNode(this);
|
|
7253
|
-
}
|
|
7344
|
+
};
|
|
7254
7345
|
}
|
|
7255
7346
|
UNSAFE_componentWillMount() {
|
|
7256
7347
|
this.store = createStore();
|
|
@@ -7262,18 +7353,18 @@ class ProvidedKeypad extends React.Component {
|
|
|
7262
7353
|
this.mounted = false;
|
|
7263
7354
|
}
|
|
7264
7355
|
render() {
|
|
7265
|
-
|
|
7356
|
+
const _this$props = this.props,
|
|
7266
7357
|
{
|
|
7267
|
-
onElementMounted
|
|
7358
|
+
onElementMounted
|
|
7268
7359
|
} = _this$props,
|
|
7269
|
-
rest =
|
|
7360
|
+
rest = _objectWithoutPropertiesLoose(_this$props, _excluded);
|
|
7270
7361
|
return /*#__PURE__*/React.createElement(Provider, {
|
|
7271
7362
|
store: this.store
|
|
7272
7363
|
}, /*#__PURE__*/React.createElement(KeypadContainer$1, _extends({
|
|
7273
7364
|
onElementMounted: element => {
|
|
7274
7365
|
// Append the dispatch methods that we want to expose
|
|
7275
7366
|
// externally to the returned React element.
|
|
7276
|
-
|
|
7367
|
+
const elementWithDispatchMethods = _extends({}, element, {
|
|
7277
7368
|
activate: this.activate,
|
|
7278
7369
|
dismiss: this.dismiss,
|
|
7279
7370
|
configure: this.configure,
|
|
@@ -7281,7 +7372,7 @@ class ProvidedKeypad extends React.Component {
|
|
|
7281
7372
|
setKeyHandler: this.setKeyHandler,
|
|
7282
7373
|
getDOMNode: this.getDOMNode
|
|
7283
7374
|
});
|
|
7284
|
-
|
|
7375
|
+
onElementMounted && onElementMounted(elementWithDispatchMethods);
|
|
7285
7376
|
}
|
|
7286
7377
|
}, rest)));
|
|
7287
7378
|
}
|