@khanacademy/math-input 14.2.2 → 15.0.1
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 +16 -0
- package/dist/enums.d.ts +0 -4
- package/dist/es/index.js +173 -113
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +1309 -1191
- package/dist/index.js.map +1 -1
- package/dist/utils.d.ts +4 -0
- package/package.json +3 -1
- package/src/components/key-handlers/key-translator.ts +1 -4
- package/src/components/keypad/__tests__/__snapshots__/keypad.test.tsx.snap +2 -0
- package/src/components/keypad/__tests__/__snapshots__/mobile-keypad.test.tsx.snap +10 -3
- package/src/components/keypad/__tests__/keypad.test.tsx +35 -0
- package/src/components/keypad/button-assets.tsx +27 -3
- package/src/components/keypad/mobile-keypad.tsx +25 -28
- package/src/data/key-configs.ts +1 -14
- package/src/enums.ts +0 -5
- package/src/utils.ts +4 -1
- package/tsconfig-build.tsbuildinfo +1 -1
package/dist/index.js
CHANGED
|
@@ -53,23 +53,9 @@ var Redux__namespace = /*#__PURE__*/_interopNamespace(Redux);
|
|
|
53
53
|
|
|
54
54
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
55
55
|
const libName = "@khanacademy/math-input";
|
|
56
|
-
const libVersion = "
|
|
56
|
+
const libVersion = "15.0.1";
|
|
57
57
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
58
58
|
|
|
59
|
-
function _defineProperty(obj, key, value) {
|
|
60
|
-
key = _toPropertyKey(key);
|
|
61
|
-
if (key in obj) {
|
|
62
|
-
Object.defineProperty(obj, key, {
|
|
63
|
-
value: value,
|
|
64
|
-
enumerable: true,
|
|
65
|
-
configurable: true,
|
|
66
|
-
writable: true
|
|
67
|
-
});
|
|
68
|
-
} else {
|
|
69
|
-
obj[key] = value;
|
|
70
|
-
}
|
|
71
|
-
return obj;
|
|
72
|
-
}
|
|
73
59
|
function _extends() {
|
|
74
60
|
_extends = Object.assign ? Object.assign.bind() : function (target) {
|
|
75
61
|
for (var i = 1; i < arguments.length; i++) {
|
|
@@ -84,20 +70,6 @@ function _extends() {
|
|
|
84
70
|
};
|
|
85
71
|
return _extends.apply(this, arguments);
|
|
86
72
|
}
|
|
87
|
-
function _toPrimitive(input, hint) {
|
|
88
|
-
if (typeof input !== "object" || input === null) return input;
|
|
89
|
-
var prim = input[Symbol.toPrimitive];
|
|
90
|
-
if (prim !== undefined) {
|
|
91
|
-
var res = prim.call(input, hint || "default");
|
|
92
|
-
if (typeof res !== "object") return res;
|
|
93
|
-
throw new TypeError("@@toPrimitive must return a primitive value.");
|
|
94
|
-
}
|
|
95
|
-
return (hint === "string" ? String : Number)(input);
|
|
96
|
-
}
|
|
97
|
-
function _toPropertyKey(arg) {
|
|
98
|
-
var key = _toPrimitive(arg, "string");
|
|
99
|
-
return typeof key === "symbol" ? key : String(key);
|
|
100
|
-
}
|
|
101
73
|
|
|
102
74
|
class Text extends React__namespace.Component {
|
|
103
75
|
render() {
|
|
@@ -133,8 +105,36 @@ const styles$k = aphrodite.StyleSheet.create({
|
|
|
133
105
|
});
|
|
134
106
|
|
|
135
107
|
class View extends React__namespace.Component {
|
|
108
|
+
static styles = aphrodite.StyleSheet.create({
|
|
109
|
+
// From: https://github.com/necolas/react-native-web/blob/master/src/components/View/index.js
|
|
110
|
+
// eslint-disable-next-line react-native/no-unused-styles
|
|
111
|
+
initial: {
|
|
112
|
+
alignItems: "stretch",
|
|
113
|
+
borderWidth: 0,
|
|
114
|
+
borderStyle: "solid",
|
|
115
|
+
boxSizing: "border-box",
|
|
116
|
+
display: "flex",
|
|
117
|
+
flexBasis: "auto",
|
|
118
|
+
flexDirection: "column",
|
|
119
|
+
margin: 0,
|
|
120
|
+
padding: 0,
|
|
121
|
+
position: "relative",
|
|
122
|
+
// button and anchor reset
|
|
123
|
+
backgroundColor: "transparent",
|
|
124
|
+
color: "inherit",
|
|
125
|
+
font: "inherit",
|
|
126
|
+
textAlign: "inherit",
|
|
127
|
+
textDecorationLine: "none",
|
|
128
|
+
// list reset
|
|
129
|
+
listStyle: "none",
|
|
130
|
+
// fix flexbox bugs
|
|
131
|
+
maxWidth: "100%",
|
|
132
|
+
minHeight: 0,
|
|
133
|
+
minWidth: 0
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
136
|
render() {
|
|
137
|
-
const className = aphrodite.css(View.styles.initial, ...(Array.isArray(this.props.style) ? this.props.style : [this.props.style])) + (this.props.extraClassName ?
|
|
137
|
+
const className = aphrodite.css(View.styles.initial, ...(Array.isArray(this.props.style) ? this.props.style : [this.props.style])) + (this.props.extraClassName ? ` ${this.props.extraClassName}` : "");
|
|
138
138
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
139
139
|
className: className,
|
|
140
140
|
style: this.props.dynamicStyle,
|
|
@@ -149,34 +149,6 @@ class View extends React__namespace.Component {
|
|
|
149
149
|
}, this.props.children);
|
|
150
150
|
}
|
|
151
151
|
}
|
|
152
|
-
_defineProperty(View, "styles", aphrodite.StyleSheet.create({
|
|
153
|
-
// From: https://github.com/necolas/react-native-web/blob/master/src/components/View/index.js
|
|
154
|
-
// eslint-disable-next-line react-native/no-unused-styles
|
|
155
|
-
initial: {
|
|
156
|
-
alignItems: "stretch",
|
|
157
|
-
borderWidth: 0,
|
|
158
|
-
borderStyle: "solid",
|
|
159
|
-
boxSizing: "border-box",
|
|
160
|
-
display: "flex",
|
|
161
|
-
flexBasis: "auto",
|
|
162
|
-
flexDirection: "column",
|
|
163
|
-
margin: 0,
|
|
164
|
-
padding: 0,
|
|
165
|
-
position: "relative",
|
|
166
|
-
// button and anchor reset
|
|
167
|
-
backgroundColor: "transparent",
|
|
168
|
-
color: "inherit",
|
|
169
|
-
font: "inherit",
|
|
170
|
-
textAlign: "inherit",
|
|
171
|
-
textDecorationLine: "none",
|
|
172
|
-
// list reset
|
|
173
|
-
listStyle: "none",
|
|
174
|
-
// fix flexbox bugs
|
|
175
|
-
maxWidth: "100%",
|
|
176
|
-
minHeight: 0,
|
|
177
|
-
minWidth: 0
|
|
178
|
-
}
|
|
179
|
-
}));
|
|
180
152
|
|
|
181
153
|
/**
|
|
182
154
|
* Common parameters used to style components.
|
|
@@ -218,6 +190,9 @@ const navigationPadWidthPx = 192;
|
|
|
218
190
|
// has settled down.
|
|
219
191
|
const toolbarHeightPx = 60;
|
|
220
192
|
|
|
193
|
+
/**
|
|
194
|
+
* Renders the green tear-shaped handle under the cursor.
|
|
195
|
+
*/
|
|
221
196
|
const touchTargetRadiusPx = 2 * cursorHandleRadiusPx;
|
|
222
197
|
const touchTargetHeightPx = 2 * touchTargetRadiusPx;
|
|
223
198
|
const touchTargetWidthPx = 2 * touchTargetRadiusPx;
|
|
@@ -225,6 +200,12 @@ const cursorRadiusPx = cursorHandleRadiusPx;
|
|
|
225
200
|
const cursorHeightPx = cursorHandleDistanceMultiplier * (cursorRadiusPx * 4);
|
|
226
201
|
const cursorWidthPx = 4 * cursorRadiusPx;
|
|
227
202
|
class CursorHandle extends React__namespace.Component {
|
|
203
|
+
static defaultProps = {
|
|
204
|
+
animateIntoPosition: false,
|
|
205
|
+
visible: false,
|
|
206
|
+
x: 0,
|
|
207
|
+
y: 0
|
|
208
|
+
};
|
|
228
209
|
render() {
|
|
229
210
|
const {
|
|
230
211
|
x,
|
|
@@ -235,7 +216,7 @@ class CursorHandle extends React__namespace.Component {
|
|
|
235
216
|
transitionDuration: "100ms",
|
|
236
217
|
transitionProperty: "transform"
|
|
237
218
|
} : {};
|
|
238
|
-
const transformString =
|
|
219
|
+
const transformString = `translate(${x}px, ${y}px)`;
|
|
239
220
|
const outerStyle = {
|
|
240
221
|
position: "absolute",
|
|
241
222
|
// This is essentially webapp's interactiveComponent + 1.
|
|
@@ -261,7 +242,7 @@ class CursorHandle extends React__namespace.Component {
|
|
|
261
242
|
fill: "none",
|
|
262
243
|
width: cursorWidthPx,
|
|
263
244
|
height: cursorHeightPx,
|
|
264
|
-
viewBox:
|
|
245
|
+
viewBox: `0 0 ${cursorWidthPx} ${cursorHeightPx}`
|
|
265
246
|
}, /*#__PURE__*/React__namespace.createElement("filter", {
|
|
266
247
|
id: "math-input_cursor",
|
|
267
248
|
colorInterpolationFilters: "sRGB",
|
|
@@ -307,12 +288,6 @@ class CursorHandle extends React__namespace.Component {
|
|
|
307
288
|
})));
|
|
308
289
|
}
|
|
309
290
|
}
|
|
310
|
-
_defineProperty(CursorHandle, "defaultProps", {
|
|
311
|
-
animateIntoPosition: false,
|
|
312
|
-
visible: false,
|
|
313
|
-
x: 0,
|
|
314
|
-
y: 0
|
|
315
|
-
});
|
|
316
291
|
|
|
317
292
|
/**
|
|
318
293
|
* A gesture recognizer that detects 'drags', crudely defined as either scrolls
|
|
@@ -325,9 +300,6 @@ _defineProperty(CursorHandle, "defaultProps", {
|
|
|
325
300
|
const touchSlopPx = 8;
|
|
326
301
|
class DragListener {
|
|
327
302
|
constructor(onDrag, initialEvent) {
|
|
328
|
-
_defineProperty(this, "_scrollListener", void 0);
|
|
329
|
-
_defineProperty(this, "_moveListener", void 0);
|
|
330
|
-
_defineProperty(this, "_endAndCancelListener", void 0);
|
|
331
303
|
// We detect drags in two ways. First, by listening for the window
|
|
332
304
|
// scroll event (we consider any legitimate scroll to be a drag).
|
|
333
305
|
this._scrollListener = () => {
|
|
@@ -727,7 +699,7 @@ function handleBackspaceInLogIndex(mathField, cursor) {
|
|
|
727
699
|
if (isInsideEmptyNode(cursor)) {
|
|
728
700
|
const grandparent = cursor.parent.parent;
|
|
729
701
|
const command = maybeFindCommandBeforeParens(grandparent);
|
|
730
|
-
cursor.insLeftOf(command
|
|
702
|
+
cursor.insLeftOf(command?.startNode);
|
|
731
703
|
cursor.startSelection();
|
|
732
704
|
if (grandparent[mathQuillInstance.R] !== MathFieldActionType.MQ_END) {
|
|
733
705
|
cursor.insRightOf(grandparent[mathQuillInstance.R]);
|
|
@@ -885,70 +857,10 @@ function handleBackspace(mathField) {
|
|
|
885
857
|
}
|
|
886
858
|
}
|
|
887
859
|
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
let KeypadType = /*#__PURE__*/function (KeypadType) {
|
|
893
|
-
KeypadType["FRACTION"] = "FRACTION";
|
|
894
|
-
KeypadType["EXPRESSION"] = "EXPRESSION";
|
|
895
|
-
return KeypadType;
|
|
896
|
-
}({});
|
|
897
|
-
const KeyTypes = ["EMPTY",
|
|
898
|
-
// For numerals, variables, and any other characters that themselves
|
|
899
|
-
// compose 'values'.
|
|
900
|
-
"VALUE",
|
|
901
|
-
// For buttons that insert or adjust math in an input.
|
|
902
|
-
"OPERATOR",
|
|
903
|
-
// For buttons that move the cursor in an input (including via
|
|
904
|
-
// deletion).
|
|
905
|
-
"INPUT_NAVIGATION",
|
|
906
|
-
// For buttons that modify the broader keypad state (e.g., by changing
|
|
907
|
-
// the visible pane).
|
|
908
|
-
"KEYPAD_NAVIGATION",
|
|
909
|
-
// For buttons that house multiple buttons and have no action
|
|
910
|
-
// themselves.
|
|
911
|
-
"MANY",
|
|
912
|
-
// For the echo animation that appears on press.
|
|
913
|
-
"ECHO"];
|
|
914
|
-
let DeviceOrientation = /*#__PURE__*/function (DeviceOrientation) {
|
|
915
|
-
DeviceOrientation["LANDSCAPE"] = "LANDSCAPE";
|
|
916
|
-
DeviceOrientation["PORTRAIT"] = "PORTRAIT";
|
|
917
|
-
return DeviceOrientation;
|
|
918
|
-
}({});
|
|
919
|
-
let LayoutMode = /*#__PURE__*/function (LayoutMode) {
|
|
920
|
-
LayoutMode["FULLSCREEN"] = "FULLSCREEN";
|
|
921
|
-
LayoutMode["COMPACT"] = "COMPACT";
|
|
922
|
-
return LayoutMode;
|
|
923
|
-
}({});
|
|
924
|
-
let BorderDirection = /*#__PURE__*/function (BorderDirection) {
|
|
925
|
-
BorderDirection["LEFT"] = "LEFT";
|
|
926
|
-
BorderDirection["BOTTOM"] = "BOTTOM";
|
|
927
|
-
return BorderDirection;
|
|
928
|
-
}({});
|
|
929
|
-
const BorderStyles = {
|
|
930
|
-
LEFT: [BorderDirection.LEFT],
|
|
931
|
-
BOTTOM: [BorderDirection.BOTTOM],
|
|
932
|
-
ALL: [BorderDirection.LEFT, BorderDirection.BOTTOM],
|
|
933
|
-
NONE: []
|
|
860
|
+
const DecimalSeparator = {
|
|
861
|
+
COMMA: ",",
|
|
862
|
+
PERIOD: "."
|
|
934
863
|
};
|
|
935
|
-
let IconType = /*#__PURE__*/function (IconType) {
|
|
936
|
-
IconType["MATH"] = "MATH";
|
|
937
|
-
IconType["SVG"] = "SVG";
|
|
938
|
-
IconType["TEXT"] = "TEXT";
|
|
939
|
-
return IconType;
|
|
940
|
-
}({});
|
|
941
|
-
let DecimalSeparator = /*#__PURE__*/function (DecimalSeparator) {
|
|
942
|
-
DecimalSeparator["COMMA"] = "COMMA";
|
|
943
|
-
DecimalSeparator["PERIOD"] = "PERIOD";
|
|
944
|
-
return DecimalSeparator;
|
|
945
|
-
}({});
|
|
946
|
-
let EchoAnimationType = /*#__PURE__*/function (EchoAnimationType) {
|
|
947
|
-
EchoAnimationType["SLIDE_AND_FADE"] = "SLIDE_AND_FADE";
|
|
948
|
-
EchoAnimationType["FADE_ONLY"] = "FADE_ONLY";
|
|
949
|
-
EchoAnimationType["LONG_FADE_ONLY"] = "LONG_FADE_ONLY";
|
|
950
|
-
return EchoAnimationType;
|
|
951
|
-
}({});
|
|
952
864
|
|
|
953
865
|
// NOTES(kevinb):
|
|
954
866
|
// - In order to get the correct decimal separator for the current locale,
|
|
@@ -1028,7 +940,7 @@ function handleExponent(mathField, key) {
|
|
|
1028
940
|
break;
|
|
1029
941
|
case "EXP_2":
|
|
1030
942
|
case "EXP_3":
|
|
1031
|
-
mathField.write(
|
|
943
|
+
mathField.write(`^${key === "EXP_2" ? 2 : 3}`);
|
|
1032
944
|
|
|
1033
945
|
// If we enter a square or a cube, we should leave the cursor
|
|
1034
946
|
// within the newly inserted parens, if they exist. This takes
|
|
@@ -1042,7 +954,7 @@ function handleExponent(mathField, key) {
|
|
|
1042
954
|
}
|
|
1043
955
|
break;
|
|
1044
956
|
default:
|
|
1045
|
-
throw new Error(
|
|
957
|
+
throw new Error(`Invalid exponent key: ${key}`);
|
|
1046
958
|
}
|
|
1047
959
|
}
|
|
1048
960
|
|
|
@@ -1124,7 +1036,7 @@ function handleJumpOut(mathField, key) {
|
|
|
1124
1036
|
cursor.insRightOf(cursor.parent.parent);
|
|
1125
1037
|
break;
|
|
1126
1038
|
default:
|
|
1127
|
-
throw new Error(
|
|
1039
|
+
throw new Error(`Attempted to 'Jump Out' from node, but found no ` + `appropriate cursor context: ${context}`);
|
|
1128
1040
|
}
|
|
1129
1041
|
}
|
|
1130
1042
|
|
|
@@ -1135,7 +1047,6 @@ var ActionType = /*#__PURE__*/function (ActionType) {
|
|
|
1135
1047
|
ActionType[ActionType["MQ_END"] = 0] = "MQ_END";
|
|
1136
1048
|
return ActionType;
|
|
1137
1049
|
}(ActionType || {});
|
|
1138
|
-
const decimalSymbol = decimalSeparator === DecimalSeparator.COMMA ? "," : ".";
|
|
1139
1050
|
function buildGenericCallback(str) {
|
|
1140
1051
|
let type = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : ActionType.WRITE;
|
|
1141
1052
|
return function (mathQuill) {
|
|
@@ -1160,7 +1071,7 @@ function buildGenericCallback(str) {
|
|
|
1160
1071
|
}
|
|
1161
1072
|
function buildNormalFunctionCallback(command) {
|
|
1162
1073
|
return function (mathField) {
|
|
1163
|
-
mathField.write(
|
|
1074
|
+
mathField.write(`\\${command}\\left(\\right)`);
|
|
1164
1075
|
mathField.keystroke("Left");
|
|
1165
1076
|
};
|
|
1166
1077
|
}
|
|
@@ -1182,7 +1093,7 @@ const keyToMathquillMap = {
|
|
|
1182
1093
|
COS: buildNormalFunctionCallback("cos"),
|
|
1183
1094
|
TAN: buildNormalFunctionCallback("tan"),
|
|
1184
1095
|
CDOT: buildGenericCallback("\\cdot"),
|
|
1185
|
-
DECIMAL: buildGenericCallback(
|
|
1096
|
+
DECIMAL: buildGenericCallback(decimalSeparator),
|
|
1186
1097
|
DIVIDE: buildGenericCallback("\\div"),
|
|
1187
1098
|
EQUAL: buildGenericCallback("="),
|
|
1188
1099
|
GEQ: buildGenericCallback("\\geq"),
|
|
@@ -1323,6 +1234,7 @@ const keyToMathquillMap = {
|
|
|
1323
1234
|
Z: buildGenericCallback("Z")
|
|
1324
1235
|
};
|
|
1325
1236
|
|
|
1237
|
+
// Notes about MathQuill
|
|
1326
1238
|
const mobileKeyTranslator = {
|
|
1327
1239
|
...keyToMathquillMap,
|
|
1328
1240
|
// note(Matthew): our mobile backspace logic is really complicated
|
|
@@ -1344,8 +1256,6 @@ class MathWrapper {
|
|
|
1344
1256
|
|
|
1345
1257
|
constructor(element) {
|
|
1346
1258
|
let callbacks = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
|
1347
|
-
_defineProperty(this, "mathField", void 0);
|
|
1348
|
-
_defineProperty(this, "callbacks", void 0);
|
|
1349
1259
|
this.mathField = createMathField(element, () => {
|
|
1350
1260
|
return {
|
|
1351
1261
|
// use a span instead of a textarea so that we don't bring up the
|
|
@@ -1528,481 +1438,27 @@ const scrollIntoView = (containerNode, keypadNode) => {
|
|
|
1528
1438
|
const constrainingFrictionFactor = 0.8;
|
|
1529
1439
|
// eslint-disable-next-line react/no-unsafe
|
|
1530
1440
|
class MathInput extends React__namespace.Component {
|
|
1531
|
-
constructor
|
|
1532
|
-
super(...arguments);
|
|
1533
|
-
_defineProperty(this, "didTouchOutside", void 0);
|
|
1534
|
-
_defineProperty(this, "didScroll", void 0);
|
|
1535
|
-
_defineProperty(this, "mathField", void 0);
|
|
1536
|
-
_defineProperty(this, "recordTouchStartOutside", void 0);
|
|
1537
|
-
_defineProperty(this, "blurOnTouchEndOutside", void 0);
|
|
1538
|
-
_defineProperty(this, "dragListener", void 0);
|
|
1539
|
-
_defineProperty(this, "inputRef", void 0);
|
|
1540
|
-
_defineProperty(this, "_isMounted", void 0);
|
|
1541
|
-
_defineProperty(this, "_mathContainer", void 0);
|
|
1542
|
-
_defineProperty(this, "_container", void 0);
|
|
1543
|
-
_defineProperty(this, "_root", void 0);
|
|
1544
|
-
_defineProperty(this, "_containerBounds", void 0);
|
|
1545
|
-
_defineProperty(this, "_keypadBounds", void 0);
|
|
1546
|
-
_defineProperty(this, "state", {
|
|
1547
|
-
focused: false,
|
|
1548
|
-
handle: {
|
|
1549
|
-
animateIntoPosition: false,
|
|
1550
|
-
visible: false,
|
|
1551
|
-
x: 0,
|
|
1552
|
-
y: 0
|
|
1553
|
-
}
|
|
1554
|
-
});
|
|
1555
|
-
_defineProperty(this, "_clearKeypadBoundsCache", () => {
|
|
1556
|
-
this._keypadBounds = null;
|
|
1557
|
-
});
|
|
1558
|
-
_defineProperty(this, "_cacheKeypadBounds", keypadNode => {
|
|
1559
|
-
this._keypadBounds = keypadNode.getBoundingClientRect();
|
|
1560
|
-
});
|
|
1561
|
-
_defineProperty(this, "_updateInputPadding", () => {
|
|
1562
|
-
this._container = ReactDOM__default["default"].findDOMNode(this);
|
|
1563
|
-
this._root = this._container.querySelector(".mq-root-block");
|
|
1564
|
-
const padding = this.getInputInnerPadding();
|
|
1565
|
-
// NOTE(diedra): This overrides the default 2px padding from Mathquil.
|
|
1566
|
-
this._root.style.padding = "".concat(padding.paddingTop, "px ").concat(padding.paddingRight, "px") + " ".concat(padding.paddingBottom, "px ").concat(padding.paddingLeft, "px");
|
|
1567
|
-
this._root.style.fontSize = "".concat(fontSizePt, "pt");
|
|
1568
|
-
});
|
|
1569
|
-
_defineProperty(this, "_getKeypadBounds", () => {
|
|
1570
|
-
if (!this._keypadBounds) {
|
|
1571
|
-
var _this$props$keypadEle;
|
|
1572
|
-
const node = (_this$props$keypadEle = this.props.keypadElement) === null || _this$props$keypadEle === void 0 ? void 0 : _this$props$keypadEle.getDOMNode();
|
|
1573
|
-
this._cacheKeypadBounds(node);
|
|
1574
|
-
}
|
|
1575
|
-
return this._keypadBounds;
|
|
1576
|
-
});
|
|
1577
|
-
_defineProperty(this, "_updateCursorHandle", animateIntoPosition => {
|
|
1578
|
-
const containerBounds = this._container.getBoundingClientRect();
|
|
1579
|
-
const cursor = this._container.querySelector(".mq-cursor");
|
|
1580
|
-
const cursorBounds = cursor.getBoundingClientRect();
|
|
1581
|
-
const cursorWidth = cursorBounds.width;
|
|
1582
|
-
const gapBelowCursor = 2;
|
|
1583
|
-
const inputInnerPadding = this.getInputInnerPadding();
|
|
1584
|
-
|
|
1585
|
-
// The cursor should never be further right or left than the edge of the
|
|
1586
|
-
// container's values.
|
|
1587
|
-
const furthestRightCursorBound = containerBounds.right - cursorWidth - inputInnerPadding.paddingRight;
|
|
1588
|
-
const furthestLeftCursorBound = containerBounds.left + cursorWidth + inputInnerPadding.paddingLeft;
|
|
1589
|
-
let cursorBoundsLeft = cursorBounds.left;
|
|
1590
|
-
if (cursorBounds.left > furthestRightCursorBound) {
|
|
1591
|
-
cursorBoundsLeft = furthestRightCursorBound;
|
|
1592
|
-
} else if (cursorBounds.left < furthestLeftCursorBound) {
|
|
1593
|
-
cursorBoundsLeft = furthestLeftCursorBound;
|
|
1594
|
-
}
|
|
1595
|
-
this.setState({
|
|
1596
|
-
handle: {
|
|
1597
|
-
visible: true,
|
|
1598
|
-
animateIntoPosition,
|
|
1599
|
-
// We subtract containerBounds' left/top to correct for the
|
|
1600
|
-
// position of the container within the page.
|
|
1601
|
-
x: cursorBoundsLeft + cursorWidth / 2 - containerBounds.left,
|
|
1602
|
-
y: cursorBounds.bottom + gapBelowCursor - containerBounds.top
|
|
1603
|
-
}
|
|
1604
|
-
});
|
|
1605
|
-
});
|
|
1606
|
-
_defineProperty(this, "_hideCursorHandle", () => {
|
|
1607
|
-
this.setState({
|
|
1608
|
-
handle: {
|
|
1609
|
-
visible: false,
|
|
1610
|
-
x: 0,
|
|
1611
|
-
y: 0
|
|
1612
|
-
}
|
|
1613
|
-
});
|
|
1614
|
-
});
|
|
1615
|
-
_defineProperty(this, "_handleScroll", () => {
|
|
1616
|
-
// If animateIntoPosition is false, the user is currently manually positioning
|
|
1617
|
-
// the cursor. This is important because the user can scroll the input field
|
|
1618
|
-
// with the curor handle, and we don't want to override that ability.
|
|
1619
|
-
// But we do want to hide the handle is the user is just scrolling the input field
|
|
1620
|
-
// normally, because the handle will not move with the scroll.
|
|
1621
|
-
if (this.state.handle.animateIntoPosition !== false) {
|
|
1622
|
-
this._hideCursorHandle();
|
|
1623
|
-
}
|
|
1624
|
-
});
|
|
1625
|
-
_defineProperty(this, "blur", () => {
|
|
1626
|
-
this.mathField.blur();
|
|
1627
|
-
this.props.onBlur && this.props.onBlur();
|
|
1628
|
-
this.setState({
|
|
1629
|
-
focused: false,
|
|
1630
|
-
handle: {
|
|
1631
|
-
visible: false
|
|
1632
|
-
}
|
|
1633
|
-
});
|
|
1634
|
-
});
|
|
1635
|
-
_defineProperty(this, "focus", () => {
|
|
1636
|
-
var _this$props$keypadEle2, _this$props;
|
|
1637
|
-
// Pass this component's handleKey method to the keypad so it can call
|
|
1638
|
-
// it whenever it needs to trigger a keypress action.
|
|
1639
|
-
(_this$props$keypadEle2 = this.props.keypadElement) === null || _this$props$keypadEle2 === void 0 ? void 0 : _this$props$keypadEle2.setKeyHandler(key => {
|
|
1640
|
-
const cursor = this.mathField.pressKey(key);
|
|
1641
|
-
|
|
1642
|
-
// Trigger an `onChange` if the value in the input changed, and hide
|
|
1643
|
-
// the cursor handle whenever the user types a key. If the value
|
|
1644
|
-
// changed as a result of a keypress, we need to be careful not to
|
|
1645
|
-
// call `setState` until after `onChange` has resolved.
|
|
1646
|
-
const hideCursor = () => {
|
|
1647
|
-
this.setState({
|
|
1648
|
-
handle: {
|
|
1649
|
-
visible: false
|
|
1650
|
-
}
|
|
1651
|
-
});
|
|
1652
|
-
};
|
|
1653
|
-
const value = this.mathField.getContent();
|
|
1654
|
-
if (this.props.value !== value) {
|
|
1655
|
-
this.props.onChange(value, hideCursor);
|
|
1656
|
-
} else {
|
|
1657
|
-
hideCursor();
|
|
1658
|
-
}
|
|
1659
|
-
return cursor;
|
|
1660
|
-
});
|
|
1661
|
-
this.mathField.focus();
|
|
1662
|
-
(_this$props = this.props) === null || _this$props === void 0 ? void 0 : _this$props.onFocus();
|
|
1663
|
-
this.setState({
|
|
1664
|
-
focused: true
|
|
1665
|
-
}, () => {
|
|
1666
|
-
// NOTE(charlie): We use `setTimeout` to allow for a layout pass to
|
|
1667
|
-
// occur. Otherwise, the keypad is measured incorrectly. Ideally,
|
|
1668
|
-
// we'd use requestAnimationFrame here, but it's unsupported on
|
|
1669
|
-
// Android Browser 4.3.
|
|
1670
|
-
setTimeout(() => {
|
|
1671
|
-
if (this._isMounted) {
|
|
1672
|
-
var _this$props$keypadEle3;
|
|
1673
|
-
// TODO(benkomalo): the keypad is animating at this point,
|
|
1674
|
-
// so we can't call _cacheKeypadBounds(), even though
|
|
1675
|
-
// it'd be nice to do so. It should probably be the case
|
|
1676
|
-
// that the higher level controller tells us when the
|
|
1677
|
-
// keypad is settled (then scrollIntoView wouldn't have
|
|
1678
|
-
// to make assumptions about that either).
|
|
1679
|
-
const maybeKeypadNode = (_this$props$keypadEle3 = this.props.keypadElement) === null || _this$props$keypadEle3 === void 0 ? void 0 : _this$props$keypadEle3.getDOMNode();
|
|
1680
|
-
scrollIntoView(this._container, maybeKeypadNode);
|
|
1681
|
-
}
|
|
1682
|
-
});
|
|
1683
|
-
});
|
|
1684
|
-
});
|
|
1685
|
-
_defineProperty(this, "_findHitNode", (containerBounds, x, y, dx, dy) => {
|
|
1686
|
-
while (y >= containerBounds.top && y <= containerBounds.bottom) {
|
|
1687
|
-
y += dy;
|
|
1688
|
-
const points = [[x - dx, y], [x, y], [x + dx, y]];
|
|
1689
|
-
const elements = points
|
|
1690
|
-
// @ts-expect-error - TS2556 - A spread argument must either have a tuple type or be passed to a rest parameter.
|
|
1691
|
-
.map(point => document.elementFromPoint(...point))
|
|
1692
|
-
// We exclude the root container itself and any nodes marked
|
|
1693
|
-
// as non-leaf which are fractions, parens, and roots. The
|
|
1694
|
-
// children of those nodes are included in the list because
|
|
1695
|
-
// those are the items we care about placing the cursor next
|
|
1696
|
-
// to.
|
|
1697
|
-
//
|
|
1698
|
-
// MathQuill's mq-non-leaf is not applied to all non-leaf nodes
|
|
1699
|
-
// so the naming is a bit confusing. Although fractions are
|
|
1700
|
-
// included, neither mq-numerator nor mq-denominator nodes are
|
|
1701
|
-
// and neither are subscripts or superscripts.
|
|
1702
|
-
.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")));
|
|
1703
|
-
let hitNode = null;
|
|
1704
|
-
|
|
1705
|
-
// Contains only DOMNodes with child elements.
|
|
1706
|
-
const nonLeafElements = [];
|
|
1707
|
-
let max = 0;
|
|
1708
|
-
const counts = {};
|
|
1709
|
-
const elementsById = {};
|
|
1710
|
-
for (const element of elements) {
|
|
1711
|
-
// @ts-expect-error - TS2531 - Object is possibly 'null'.
|
|
1712
|
-
const id = element.getAttribute("mathquill-command-id");
|
|
1713
|
-
if (id != null) {
|
|
1714
|
-
counts[id] = (counts[id] || 0) + 1;
|
|
1715
|
-
elementsById[id] = element;
|
|
1716
|
-
} else {
|
|
1717
|
-
// @ts-expect-error - TS2345 - Argument of type 'Element | null' is not assignable to parameter of type 'HTMLElement | null'.
|
|
1718
|
-
nonLeafElements.push(element);
|
|
1719
|
-
}
|
|
1720
|
-
}
|
|
1721
|
-
|
|
1722
|
-
// When determining which DOMNode to place the cursor beside, we
|
|
1723
|
-
// prefer leaf nodes. Hitting a leaf node is a good sign that the
|
|
1724
|
-
// cursor is really close to some piece of math that has been
|
|
1725
|
-
// rendered because leaf nodes contain text. Non-leaf nodes may
|
|
1726
|
-
// contain a lot of whitespace so the cursor may be further away
|
|
1727
|
-
// from actual text within the expression.
|
|
1728
|
-
//
|
|
1729
|
-
// Since we're doing three hit tests per loop it's possible that
|
|
1730
|
-
// we hit multiple leaf nodes at the same time. In this case we
|
|
1731
|
-
// we prefer the DOMNode with the most hits.
|
|
1732
|
-
// TODO(kevinb) consider preferring nodes hit by [x, y].
|
|
1733
|
-
for (const [id, count] of wonderStuffCore.entries(counts)) {
|
|
1734
|
-
if (count > max) {
|
|
1735
|
-
max = count;
|
|
1736
|
-
hitNode = elementsById[id];
|
|
1737
|
-
}
|
|
1738
|
-
}
|
|
1739
|
-
|
|
1740
|
-
// It's possible that two non-leaf nodes are right beside each
|
|
1741
|
-
// other. We don't bother counting the number of hits for each,
|
|
1742
|
-
// b/c this seems like an unlikely situation. Also, ignoring the
|
|
1743
|
-
// hit count in the situation should not have serious effects on
|
|
1744
|
-
// the overall accuracy of the algorithm.
|
|
1745
|
-
if (hitNode == null && nonLeafElements.length > 0) {
|
|
1746
|
-
// @ts-expect-error - TS2322 - Type 'HTMLElement | null' is not assignable to type 'null'.
|
|
1747
|
-
hitNode = nonLeafElements[0];
|
|
1748
|
-
}
|
|
1749
|
-
if (hitNode !== null) {
|
|
1750
|
-
this.mathField.setCursorPosition(x, y, hitNode);
|
|
1751
|
-
return true;
|
|
1752
|
-
}
|
|
1753
|
-
}
|
|
1754
|
-
return false;
|
|
1755
|
-
});
|
|
1756
|
-
_defineProperty(this, "_insertCursorAtClosestNode", (x, y) => {
|
|
1757
|
-
const cursor = this.mathField.getCursor();
|
|
1758
|
-
|
|
1759
|
-
// Pre-emptively check if the input has any child nodes; if not, the
|
|
1760
|
-
// input is empty, so we throw the cursor at the start.
|
|
1761
|
-
if (!this._root.hasChildNodes()) {
|
|
1762
|
-
cursor.insAtLeftEnd(this.mathField.mathField.__controller.root);
|
|
1763
|
-
return;
|
|
1764
|
-
}
|
|
1765
|
-
|
|
1766
|
-
// NOTE(diedra): The adding and subtracting of 10 or 15 pixels here accounts
|
|
1767
|
-
// for the padding that surrounds the input values.
|
|
1768
|
-
if (y > this._containerBounds.bottom) {
|
|
1769
|
-
y = this._containerBounds.bottom - 10;
|
|
1770
|
-
} else if (y < this._containerBounds.top) {
|
|
1771
|
-
y = this._containerBounds.top + 10;
|
|
1772
|
-
}
|
|
1773
|
-
if (x > this._containerBounds.right) {
|
|
1774
|
-
x = this._containerBounds.right - 15;
|
|
1775
|
-
} else if (x < this._containerBounds.left) {
|
|
1776
|
-
x = this._containerBounds.left + 15;
|
|
1777
|
-
}
|
|
1778
|
-
let dy;
|
|
1779
|
-
|
|
1780
|
-
// Vertical spacing between hit tests
|
|
1781
|
-
// dy is negative because we're moving upwards.
|
|
1782
|
-
dy = -8;
|
|
1783
|
-
|
|
1784
|
-
// Horizontal spacing between hit tests
|
|
1785
|
-
// Note: This value depends on the font size. If the gap is too small
|
|
1786
|
-
// we end up placing the cursor at the end of the expression when we
|
|
1787
|
-
// shouldn't.
|
|
1788
|
-
const dx = 5;
|
|
1789
|
-
if (this._findHitNode(this._containerBounds, x, y, dx, dy)) {
|
|
1790
|
-
return;
|
|
1791
|
-
}
|
|
1792
|
-
|
|
1793
|
-
// If we haven't found anything start from the top.
|
|
1794
|
-
y = this._containerBounds.top;
|
|
1795
|
-
|
|
1796
|
-
// dy is positive b/c we're going downwards.
|
|
1797
|
-
dy = 8;
|
|
1798
|
-
if (this._findHitNode(this._containerBounds, x, y, dx, dy)) {
|
|
1799
|
-
return;
|
|
1800
|
-
}
|
|
1801
|
-
const firstChildBounds = this._root.firstChild.getBoundingClientRect();
|
|
1802
|
-
const lastChildBounds = this._root.lastChild.getBoundingClientRect();
|
|
1803
|
-
const left = firstChildBounds.left;
|
|
1804
|
-
const right = lastChildBounds.right;
|
|
1805
|
-
|
|
1806
|
-
// We've exhausted all of the options. We're likely either to the right
|
|
1807
|
-
// or left of all of the math, so we place the cursor at the end to
|
|
1808
|
-
// which it's closest.
|
|
1809
|
-
if (Math.abs(x - right) < Math.abs(x - left)) {
|
|
1810
|
-
cursor.insAtRightEnd(this.mathField.mathField.__controller.root);
|
|
1811
|
-
} else {
|
|
1812
|
-
cursor.insAtLeftEnd(this.mathField.mathField.__controller.root);
|
|
1813
|
-
}
|
|
1814
|
-
// In that event, we need to update the cursor context ourselves.
|
|
1815
|
-
this.props.keypadElement && this.props.keypadElement.setCursor({
|
|
1816
|
-
context: this.mathField.contextForCursor()
|
|
1817
|
-
});
|
|
1818
|
-
});
|
|
1819
|
-
_defineProperty(this, "handleTouchStart", e => {
|
|
1820
|
-
e.stopPropagation();
|
|
1821
|
-
|
|
1822
|
-
// Hide the cursor handle on touch start, if the handle itself isn't
|
|
1823
|
-
// handling the touch event.
|
|
1824
|
-
this._hideCursorHandle();
|
|
1825
|
-
|
|
1826
|
-
// Cache the container bounds, so as to avoid re-computing. If we don't
|
|
1827
|
-
// have any content, then it's not necessary, since the cursor can't be
|
|
1828
|
-
// moved anyway.
|
|
1829
|
-
if (this.mathField.getContent() !== "") {
|
|
1830
|
-
this._containerBounds = this._container.getBoundingClientRect();
|
|
1831
|
-
|
|
1832
|
-
// Make the cursor visible and set the handle-less cursor's
|
|
1833
|
-
// location.
|
|
1834
|
-
const touch = e.changedTouches[0];
|
|
1835
|
-
this._insertCursorAtClosestNode(touch.clientX, touch.clientY);
|
|
1836
|
-
}
|
|
1837
|
-
|
|
1838
|
-
// Trigger a focus event, if we're not already focused.
|
|
1839
|
-
if (!this.state.focused) {
|
|
1840
|
-
this.focus();
|
|
1841
|
-
}
|
|
1842
|
-
});
|
|
1843
|
-
_defineProperty(this, "handleTouchMove", e => {
|
|
1844
|
-
e.stopPropagation();
|
|
1845
|
-
|
|
1846
|
-
// Update the handle-less cursor's location on move, if there's any
|
|
1847
|
-
// content in the box. Note that if the user touched outside the keypad
|
|
1848
|
-
// (e.g., with a different finger) during this touch interaction, we
|
|
1849
|
-
// may have blurred, in which case we should ignore the touch (since
|
|
1850
|
-
// the cursor is no longer visible and the input is no longer
|
|
1851
|
-
// highlighted).
|
|
1852
|
-
if (this.mathField.getContent() !== "" && this.state.focused) {
|
|
1853
|
-
const touch = e.changedTouches[0];
|
|
1854
|
-
this._insertCursorAtClosestNode(touch.clientX, touch.clientY);
|
|
1855
|
-
}
|
|
1856
|
-
});
|
|
1857
|
-
_defineProperty(this, "handleTouchEnd", e => {
|
|
1858
|
-
e.stopPropagation();
|
|
1859
|
-
|
|
1860
|
-
// And on touch-end, reveal the cursor, unless the input is empty. Note
|
|
1861
|
-
// that if the user touched outside the keypad (e.g., with a different
|
|
1862
|
-
// finger) during this touch interaction, we may have blurred, in which
|
|
1863
|
-
// case we should ignore the touch (since the cursor is no longer
|
|
1864
|
-
// visible and the input is no longer highlighted).
|
|
1865
|
-
if (this.mathField.getContent() !== "" && this.state.focused) {
|
|
1866
|
-
this._updateCursorHandle();
|
|
1867
|
-
}
|
|
1868
|
-
});
|
|
1869
|
-
_defineProperty(this, "onCursorHandleTouchStart", e => {
|
|
1870
|
-
// NOTE(charlie): The cursor handle is a child of this view, so whenever
|
|
1871
|
-
// it receives a touch event, that event would also typically be bubbled
|
|
1872
|
-
// up to our own handlers. However, we want the cursor to handle its own
|
|
1873
|
-
// touch events, and for this view to only handle touch events that
|
|
1874
|
-
// don't affect the cursor. As such, we `stopPropagation` on any touch
|
|
1875
|
-
// events that are being handled by the cursor, so as to avoid handling
|
|
1876
|
-
// them in our own touch handlers.
|
|
1877
|
-
e.stopPropagation();
|
|
1878
|
-
e.preventDefault();
|
|
1879
|
-
|
|
1880
|
-
// Cache the container bounds, so as to avoid re-computing.
|
|
1881
|
-
this._containerBounds = this._container.getBoundingClientRect();
|
|
1882
|
-
});
|
|
1883
|
-
_defineProperty(this, "_constrainToBound", (value, min, max, friction) => {
|
|
1884
|
-
if (value < min) {
|
|
1885
|
-
return min + (value - min) * friction;
|
|
1886
|
-
} else if (value > max) {
|
|
1887
|
-
return max + (value - max) * friction;
|
|
1888
|
-
} else {
|
|
1889
|
-
return value;
|
|
1890
|
-
}
|
|
1891
|
-
});
|
|
1892
|
-
_defineProperty(this, "onCursorHandleTouchMove", e => {
|
|
1893
|
-
e.stopPropagation();
|
|
1894
|
-
const x = e.changedTouches[0].clientX;
|
|
1895
|
-
const y = e.changedTouches[0].clientY;
|
|
1896
|
-
const relativeX = x - this._containerBounds.left;
|
|
1897
|
-
const relativeY = y - 2 * cursorHandleRadiusPx * cursorHandleDistanceMultiplier - this._containerBounds.top;
|
|
1898
|
-
|
|
1899
|
-
// We subtract the containerBounds left/top to correct for the
|
|
1900
|
-
// MathInput's position on the page. On top of that, we subtract an
|
|
1901
|
-
// additional 2 x {height of the cursor} so that the bottom of the
|
|
1902
|
-
// cursor tracks the user's finger, to make it visible under their
|
|
1903
|
-
// touch.
|
|
1904
|
-
this.setState({
|
|
1905
|
-
handle: {
|
|
1906
|
-
animateIntoPosition: false,
|
|
1907
|
-
visible: true,
|
|
1908
|
-
// TODO(charlie): Use clientX and clientY to avoid the need for
|
|
1909
|
-
// scroll offsets. This likely also means that the cursor
|
|
1910
|
-
// detection doesn't work when scrolled, since we're not
|
|
1911
|
-
// offsetting those values.
|
|
1912
|
-
x: this._constrainToBound(relativeX, 0, this._containerBounds.width, constrainingFrictionFactor),
|
|
1913
|
-
y: this._constrainToBound(relativeY, 0, this._containerBounds.height, constrainingFrictionFactor)
|
|
1914
|
-
}
|
|
1915
|
-
});
|
|
1441
|
+
// @ts-expect-error - TS2564 - Property 'recordTouchStartOutside' has no initializer and is not definitely assigned in the constructor.
|
|
1916
1442
|
|
|
1917
|
-
|
|
1918
|
-
// touching because they're dragging the handle which is a little
|
|
1919
|
-
// below where the cursor actually is.
|
|
1920
|
-
const distanceAboveFingerToTrySelecting = 22;
|
|
1921
|
-
const adjustedY = y - distanceAboveFingerToTrySelecting;
|
|
1922
|
-
this._insertCursorAtClosestNode(x, adjustedY);
|
|
1923
|
-
});
|
|
1924
|
-
_defineProperty(this, "onCursorHandleTouchEnd", e => {
|
|
1925
|
-
e.stopPropagation();
|
|
1926
|
-
this._updateCursorHandle(true);
|
|
1927
|
-
});
|
|
1928
|
-
_defineProperty(this, "onCursorHandleTouchCancel", e => {
|
|
1929
|
-
e.stopPropagation();
|
|
1930
|
-
this._updateCursorHandle(true);
|
|
1931
|
-
});
|
|
1932
|
-
_defineProperty(this, "domKeyToMathQuillKey", key => {
|
|
1933
|
-
const keyMap = {
|
|
1934
|
-
"+": "PLUS",
|
|
1935
|
-
"-": "MINUS",
|
|
1936
|
-
"*": "TIMES",
|
|
1937
|
-
"/": "DIVIDE",
|
|
1938
|
-
".": "DECIMAL",
|
|
1939
|
-
"%": "PERCENT",
|
|
1940
|
-
"=": "EQUAL",
|
|
1941
|
-
">": "GT",
|
|
1942
|
-
"<": "LT",
|
|
1943
|
-
"^": "EXP"
|
|
1944
|
-
};
|
|
1443
|
+
// @ts-expect-error - TS2564 - Property 'blurOnTouchEndOutside' has no initializer and is not definitely assigned in the constructor.
|
|
1945
1444
|
|
|
1946
|
-
|
|
1947
|
-
if (["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"].includes(key)) {
|
|
1948
|
-
return "NUM_".concat(key);
|
|
1949
|
-
}
|
|
1445
|
+
// @ts-expect-error - TS2564 - Property '_container' has no initializer and is not definitely assigned in the constructor.
|
|
1950
1446
|
|
|
1951
|
-
|
|
1952
|
-
else if (key === "Backspace") {
|
|
1953
|
-
return "BACKSPACE";
|
|
1954
|
-
}
|
|
1955
|
-
|
|
1956
|
-
// Operators
|
|
1957
|
-
else if (key in keyMap) {
|
|
1958
|
-
return keyMap[key];
|
|
1959
|
-
}
|
|
1447
|
+
// @ts-expect-error - TS2564 - Property '_containerBounds' has no initializer and is not definitely assigned in the constructor.
|
|
1960
1448
|
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
this.mathField.setContent(this.props.value);
|
|
1975
|
-
this.props.onChange(value, false);
|
|
1976
|
-
this._hideCursorHandle();
|
|
1977
|
-
}
|
|
1978
|
-
}
|
|
1979
|
-
});
|
|
1980
|
-
_defineProperty(this, "getBorderWidthPx", () => {
|
|
1981
|
-
// TODO(diedra): Move these to the common style package.
|
|
1982
|
-
const normalBorderWidthPx = 1;
|
|
1983
|
-
const focusedBorderWidthPx = 2;
|
|
1984
|
-
return this.state.focused ? focusedBorderWidthPx : normalBorderWidthPx;
|
|
1985
|
-
});
|
|
1986
|
-
_defineProperty(this, "getInputInnerPadding", () => {
|
|
1987
|
-
const paddingInset = totalDesiredPadding - this.getBorderWidthPx();
|
|
1988
|
-
|
|
1989
|
-
// Now, translate that to the appropriate padding for each direction.
|
|
1990
|
-
// The complication here is that we want numerals to be centered within
|
|
1991
|
-
// the input. However, Symbola (MathQuill's font of choice) renders
|
|
1992
|
-
// numerals with approximately 3px of padding below and 1px of padding
|
|
1993
|
-
// above (to make room for ascenders and descenders). So we ignore those
|
|
1994
|
-
// padding values for the vertical directions.
|
|
1995
|
-
const symbolaPaddingBottom = 3;
|
|
1996
|
-
const symbolaPaddingTop = 1;
|
|
1997
|
-
const padding = {
|
|
1998
|
-
paddingTop: paddingInset - symbolaPaddingTop,
|
|
1999
|
-
paddingRight: paddingInset,
|
|
2000
|
-
paddingBottom: paddingInset - symbolaPaddingBottom,
|
|
2001
|
-
paddingLeft: paddingInset
|
|
2002
|
-
};
|
|
2003
|
-
return padding;
|
|
2004
|
-
});
|
|
2005
|
-
}
|
|
1449
|
+
static defaultProps = {
|
|
1450
|
+
style: {},
|
|
1451
|
+
value: ""
|
|
1452
|
+
};
|
|
1453
|
+
state = {
|
|
1454
|
+
focused: false,
|
|
1455
|
+
handle: {
|
|
1456
|
+
animateIntoPosition: false,
|
|
1457
|
+
visible: false,
|
|
1458
|
+
x: 0,
|
|
1459
|
+
y: 0
|
|
1460
|
+
}
|
|
1461
|
+
};
|
|
2006
1462
|
componentDidMount() {
|
|
2007
1463
|
this._isMounted = true;
|
|
2008
1464
|
this.mathField = new MathWrapper(this._mathContainer, {
|
|
@@ -2106,26 +1562,539 @@ class MathInput extends React__namespace.Component {
|
|
|
2106
1562
|
if (this.props.keypadElement !== props.keypadElement) {
|
|
2107
1563
|
this._clearKeypadBoundsCache();
|
|
2108
1564
|
}
|
|
2109
|
-
}
|
|
2110
|
-
componentDidUpdate(prevProps, prevState) {
|
|
2111
|
-
if (this.mathField.getContent() !== this.props.value) {
|
|
2112
|
-
this.mathField.setContent(this.props.value);
|
|
1565
|
+
}
|
|
1566
|
+
componentDidUpdate(prevProps, prevState) {
|
|
1567
|
+
if (this.mathField.getContent() !== this.props.value) {
|
|
1568
|
+
this.mathField.setContent(this.props.value);
|
|
1569
|
+
}
|
|
1570
|
+
if (prevState.focused !== this.state.focused) {
|
|
1571
|
+
this._updateInputPadding();
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
componentWillUnmount() {
|
|
1575
|
+
this._isMounted = false;
|
|
1576
|
+
window.removeEventListener("touchstart", this.recordTouchStartOutside);
|
|
1577
|
+
window.removeEventListener("touchend", this.blurOnTouchEndOutside);
|
|
1578
|
+
window.removeEventListener("touchcancel", this.blurOnTouchEndOutside);
|
|
1579
|
+
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
1580
|
+
window.removeEventListener("resize", this._clearKeypadBoundsCache());
|
|
1581
|
+
window.removeEventListener("orientationchange",
|
|
1582
|
+
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
1583
|
+
this._clearKeypadBoundsCache());
|
|
1584
|
+
}
|
|
1585
|
+
_clearKeypadBoundsCache = () => {
|
|
1586
|
+
this._keypadBounds = null;
|
|
1587
|
+
};
|
|
1588
|
+
_cacheKeypadBounds = keypadNode => {
|
|
1589
|
+
this._keypadBounds = keypadNode.getBoundingClientRect();
|
|
1590
|
+
};
|
|
1591
|
+
_updateInputPadding = () => {
|
|
1592
|
+
this._container = ReactDOM__default["default"].findDOMNode(this);
|
|
1593
|
+
this._root = this._container.querySelector(".mq-root-block");
|
|
1594
|
+
const padding = this.getInputInnerPadding();
|
|
1595
|
+
// NOTE(diedra): This overrides the default 2px padding from Mathquil.
|
|
1596
|
+
this._root.style.padding = `${padding.paddingTop}px ${padding.paddingRight}px` + ` ${padding.paddingBottom}px ${padding.paddingLeft}px`;
|
|
1597
|
+
this._root.style.fontSize = `${fontSizePt}pt`;
|
|
1598
|
+
};
|
|
1599
|
+
|
|
1600
|
+
/** Gets and cache they bounds of the keypadElement */
|
|
1601
|
+
_getKeypadBounds = () => {
|
|
1602
|
+
if (!this._keypadBounds) {
|
|
1603
|
+
const node = this.props.keypadElement?.getDOMNode();
|
|
1604
|
+
this._cacheKeypadBounds(node);
|
|
1605
|
+
}
|
|
1606
|
+
return this._keypadBounds;
|
|
1607
|
+
};
|
|
1608
|
+
_updateCursorHandle = animateIntoPosition => {
|
|
1609
|
+
const containerBounds = this._container.getBoundingClientRect();
|
|
1610
|
+
const cursor = this._container.querySelector(".mq-cursor");
|
|
1611
|
+
const cursorBounds = cursor.getBoundingClientRect();
|
|
1612
|
+
const cursorWidth = cursorBounds.width;
|
|
1613
|
+
const gapBelowCursor = 2;
|
|
1614
|
+
const inputInnerPadding = this.getInputInnerPadding();
|
|
1615
|
+
|
|
1616
|
+
// The cursor should never be further right or left than the edge of the
|
|
1617
|
+
// container's values.
|
|
1618
|
+
const furthestRightCursorBound = containerBounds.right - cursorWidth - inputInnerPadding.paddingRight;
|
|
1619
|
+
const furthestLeftCursorBound = containerBounds.left + cursorWidth + inputInnerPadding.paddingLeft;
|
|
1620
|
+
let cursorBoundsLeft = cursorBounds.left;
|
|
1621
|
+
if (cursorBounds.left > furthestRightCursorBound) {
|
|
1622
|
+
cursorBoundsLeft = furthestRightCursorBound;
|
|
1623
|
+
} else if (cursorBounds.left < furthestLeftCursorBound) {
|
|
1624
|
+
cursorBoundsLeft = furthestLeftCursorBound;
|
|
1625
|
+
}
|
|
1626
|
+
this.setState({
|
|
1627
|
+
handle: {
|
|
1628
|
+
visible: true,
|
|
1629
|
+
animateIntoPosition,
|
|
1630
|
+
// We subtract containerBounds' left/top to correct for the
|
|
1631
|
+
// position of the container within the page.
|
|
1632
|
+
x: cursorBoundsLeft + cursorWidth / 2 - containerBounds.left,
|
|
1633
|
+
y: cursorBounds.bottom + gapBelowCursor - containerBounds.top
|
|
1634
|
+
}
|
|
1635
|
+
});
|
|
1636
|
+
};
|
|
1637
|
+
_hideCursorHandle = () => {
|
|
1638
|
+
this.setState({
|
|
1639
|
+
handle: {
|
|
1640
|
+
visible: false,
|
|
1641
|
+
x: 0,
|
|
1642
|
+
y: 0
|
|
1643
|
+
}
|
|
1644
|
+
});
|
|
1645
|
+
};
|
|
1646
|
+
_handleScroll = () => {
|
|
1647
|
+
// If animateIntoPosition is false, the user is currently manually positioning
|
|
1648
|
+
// the cursor. This is important because the user can scroll the input field
|
|
1649
|
+
// with the curor handle, and we don't want to override that ability.
|
|
1650
|
+
// But we do want to hide the handle is the user is just scrolling the input field
|
|
1651
|
+
// normally, because the handle will not move with the scroll.
|
|
1652
|
+
if (this.state.handle.animateIntoPosition !== false) {
|
|
1653
|
+
this._hideCursorHandle();
|
|
1654
|
+
}
|
|
1655
|
+
};
|
|
1656
|
+
blur = () => {
|
|
1657
|
+
this.mathField.blur();
|
|
1658
|
+
this.props.onBlur && this.props.onBlur();
|
|
1659
|
+
this.setState({
|
|
1660
|
+
focused: false,
|
|
1661
|
+
handle: {
|
|
1662
|
+
visible: false
|
|
1663
|
+
}
|
|
1664
|
+
});
|
|
1665
|
+
};
|
|
1666
|
+
focus = () => {
|
|
1667
|
+
// Pass this component's handleKey method to the keypad so it can call
|
|
1668
|
+
// it whenever it needs to trigger a keypress action.
|
|
1669
|
+
this.props.keypadElement?.setKeyHandler(key => {
|
|
1670
|
+
const cursor = this.mathField.pressKey(key);
|
|
1671
|
+
|
|
1672
|
+
// Trigger an `onChange` if the value in the input changed, and hide
|
|
1673
|
+
// the cursor handle whenever the user types a key. If the value
|
|
1674
|
+
// changed as a result of a keypress, we need to be careful not to
|
|
1675
|
+
// call `setState` until after `onChange` has resolved.
|
|
1676
|
+
const hideCursor = () => {
|
|
1677
|
+
this.setState({
|
|
1678
|
+
handle: {
|
|
1679
|
+
visible: false
|
|
1680
|
+
}
|
|
1681
|
+
});
|
|
1682
|
+
};
|
|
1683
|
+
const value = this.mathField.getContent();
|
|
1684
|
+
if (this.props.value !== value) {
|
|
1685
|
+
this.props.onChange(value, hideCursor);
|
|
1686
|
+
} else {
|
|
1687
|
+
hideCursor();
|
|
1688
|
+
}
|
|
1689
|
+
return cursor;
|
|
1690
|
+
});
|
|
1691
|
+
this.mathField.focus();
|
|
1692
|
+
this.props?.onFocus();
|
|
1693
|
+
this.setState({
|
|
1694
|
+
focused: true
|
|
1695
|
+
}, () => {
|
|
1696
|
+
// NOTE(charlie): We use `setTimeout` to allow for a layout pass to
|
|
1697
|
+
// occur. Otherwise, the keypad is measured incorrectly. Ideally,
|
|
1698
|
+
// we'd use requestAnimationFrame here, but it's unsupported on
|
|
1699
|
+
// Android Browser 4.3.
|
|
1700
|
+
setTimeout(() => {
|
|
1701
|
+
if (this._isMounted) {
|
|
1702
|
+
// TODO(benkomalo): the keypad is animating at this point,
|
|
1703
|
+
// so we can't call _cacheKeypadBounds(), even though
|
|
1704
|
+
// it'd be nice to do so. It should probably be the case
|
|
1705
|
+
// that the higher level controller tells us when the
|
|
1706
|
+
// keypad is settled (then scrollIntoView wouldn't have
|
|
1707
|
+
// to make assumptions about that either).
|
|
1708
|
+
const maybeKeypadNode = this.props.keypadElement?.getDOMNode();
|
|
1709
|
+
scrollIntoView(this._container, maybeKeypadNode);
|
|
1710
|
+
}
|
|
1711
|
+
});
|
|
1712
|
+
});
|
|
1713
|
+
};
|
|
1714
|
+
|
|
1715
|
+
/**
|
|
1716
|
+
* Tries to determine which DOM node to place the cursor next to based on
|
|
1717
|
+
* where the user drags the cursor handle. If it finds a node it will
|
|
1718
|
+
* place the cursor next to it, update the handle to be under the cursor,
|
|
1719
|
+
* and return true. If it doesn't find a node, it returns false.
|
|
1720
|
+
*
|
|
1721
|
+
* It searches for nodes by doing it tests at the following points:
|
|
1722
|
+
*
|
|
1723
|
+
* (x - dx, y), (x, y), (x + dx, y)
|
|
1724
|
+
*
|
|
1725
|
+
* If it doesn't find any nodes from the rendered math it will update y
|
|
1726
|
+
* by adding dy.
|
|
1727
|
+
*
|
|
1728
|
+
* The algorithm ends its search when y goes outside the bounds of
|
|
1729
|
+
* containerBounds.
|
|
1730
|
+
*
|
|
1731
|
+
* @param {DOMRect} containerBounds - bounds of the container node
|
|
1732
|
+
* @param {number} x - the initial x coordinate in the viewport
|
|
1733
|
+
* @param {number} y - the initial y coordinate in the viewport
|
|
1734
|
+
* @param {number} dx - horizontal spacing between elementFromPoint calls
|
|
1735
|
+
* @param {number} dy - vertical spacing between elementFromPoint calls,
|
|
1736
|
+
* sign determines direction.
|
|
1737
|
+
* @returns {boolean} - true if a node was hit, false otherwise.
|
|
1738
|
+
*/
|
|
1739
|
+
_findHitNode = (containerBounds, x, y, dx, dy) => {
|
|
1740
|
+
while (y >= containerBounds.top && y <= containerBounds.bottom) {
|
|
1741
|
+
y += dy;
|
|
1742
|
+
const points = [[x - dx, y], [x, y], [x + dx, y]];
|
|
1743
|
+
const elements = points
|
|
1744
|
+
// @ts-expect-error - TS2556 - A spread argument must either have a tuple type or be passed to a rest parameter.
|
|
1745
|
+
.map(point => document.elementFromPoint(...point))
|
|
1746
|
+
// We exclude the root container itself and any nodes marked
|
|
1747
|
+
// as non-leaf which are fractions, parens, and roots. The
|
|
1748
|
+
// children of those nodes are included in the list because
|
|
1749
|
+
// those are the items we care about placing the cursor next
|
|
1750
|
+
// to.
|
|
1751
|
+
//
|
|
1752
|
+
// MathQuill's mq-non-leaf is not applied to all non-leaf nodes
|
|
1753
|
+
// so the naming is a bit confusing. Although fractions are
|
|
1754
|
+
// included, neither mq-numerator nor mq-denominator nodes are
|
|
1755
|
+
// and neither are subscripts or superscripts.
|
|
1756
|
+
.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")));
|
|
1757
|
+
let hitNode = null;
|
|
1758
|
+
|
|
1759
|
+
// Contains only DOMNodes with child elements.
|
|
1760
|
+
const nonLeafElements = [];
|
|
1761
|
+
let max = 0;
|
|
1762
|
+
const counts = {};
|
|
1763
|
+
const elementsById = {};
|
|
1764
|
+
for (const element of elements) {
|
|
1765
|
+
// @ts-expect-error - TS2531 - Object is possibly 'null'.
|
|
1766
|
+
const id = element.getAttribute("mathquill-command-id");
|
|
1767
|
+
if (id != null) {
|
|
1768
|
+
counts[id] = (counts[id] || 0) + 1;
|
|
1769
|
+
elementsById[id] = element;
|
|
1770
|
+
} else {
|
|
1771
|
+
// @ts-expect-error - TS2345 - Argument of type 'Element | null' is not assignable to parameter of type 'HTMLElement | null'.
|
|
1772
|
+
nonLeafElements.push(element);
|
|
1773
|
+
}
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
// When determining which DOMNode to place the cursor beside, we
|
|
1777
|
+
// prefer leaf nodes. Hitting a leaf node is a good sign that the
|
|
1778
|
+
// cursor is really close to some piece of math that has been
|
|
1779
|
+
// rendered because leaf nodes contain text. Non-leaf nodes may
|
|
1780
|
+
// contain a lot of whitespace so the cursor may be further away
|
|
1781
|
+
// from actual text within the expression.
|
|
1782
|
+
//
|
|
1783
|
+
// Since we're doing three hit tests per loop it's possible that
|
|
1784
|
+
// we hit multiple leaf nodes at the same time. In this case we
|
|
1785
|
+
// we prefer the DOMNode with the most hits.
|
|
1786
|
+
// TODO(kevinb) consider preferring nodes hit by [x, y].
|
|
1787
|
+
for (const [id, count] of wonderStuffCore.entries(counts)) {
|
|
1788
|
+
if (count > max) {
|
|
1789
|
+
max = count;
|
|
1790
|
+
hitNode = elementsById[id];
|
|
1791
|
+
}
|
|
1792
|
+
}
|
|
1793
|
+
|
|
1794
|
+
// It's possible that two non-leaf nodes are right beside each
|
|
1795
|
+
// other. We don't bother counting the number of hits for each,
|
|
1796
|
+
// b/c this seems like an unlikely situation. Also, ignoring the
|
|
1797
|
+
// hit count in the situation should not have serious effects on
|
|
1798
|
+
// the overall accuracy of the algorithm.
|
|
1799
|
+
if (hitNode == null && nonLeafElements.length > 0) {
|
|
1800
|
+
// @ts-expect-error - TS2322 - Type 'HTMLElement | null' is not assignable to type 'null'.
|
|
1801
|
+
hitNode = nonLeafElements[0];
|
|
1802
|
+
}
|
|
1803
|
+
if (hitNode !== null) {
|
|
1804
|
+
this.mathField.setCursorPosition(x, y, hitNode);
|
|
1805
|
+
return true;
|
|
1806
|
+
}
|
|
1807
|
+
}
|
|
1808
|
+
return false;
|
|
1809
|
+
};
|
|
1810
|
+
|
|
1811
|
+
/**
|
|
1812
|
+
* Inserts the cursor at the DOM node closest to the given coordinates,
|
|
1813
|
+
* based on hit-tests conducted using #_findHitNode.
|
|
1814
|
+
*
|
|
1815
|
+
* @param {number} x - the x coordinate in the viewport
|
|
1816
|
+
* @param {number} y - the y coordinate in the viewport
|
|
1817
|
+
*/
|
|
1818
|
+
_insertCursorAtClosestNode = (x, y) => {
|
|
1819
|
+
const cursor = this.mathField.getCursor();
|
|
1820
|
+
|
|
1821
|
+
// Pre-emptively check if the input has any child nodes; if not, the
|
|
1822
|
+
// input is empty, so we throw the cursor at the start.
|
|
1823
|
+
if (!this._root.hasChildNodes()) {
|
|
1824
|
+
cursor.insAtLeftEnd(this.mathField.mathField.__controller.root);
|
|
1825
|
+
return;
|
|
1826
|
+
}
|
|
1827
|
+
|
|
1828
|
+
// NOTE(diedra): The adding and subtracting of 10 or 15 pixels here accounts
|
|
1829
|
+
// for the padding that surrounds the input values.
|
|
1830
|
+
if (y > this._containerBounds.bottom) {
|
|
1831
|
+
y = this._containerBounds.bottom - 10;
|
|
1832
|
+
} else if (y < this._containerBounds.top) {
|
|
1833
|
+
y = this._containerBounds.top + 10;
|
|
1834
|
+
}
|
|
1835
|
+
if (x > this._containerBounds.right) {
|
|
1836
|
+
x = this._containerBounds.right - 15;
|
|
1837
|
+
} else if (x < this._containerBounds.left) {
|
|
1838
|
+
x = this._containerBounds.left + 15;
|
|
1839
|
+
}
|
|
1840
|
+
let dy;
|
|
1841
|
+
|
|
1842
|
+
// Vertical spacing between hit tests
|
|
1843
|
+
// dy is negative because we're moving upwards.
|
|
1844
|
+
dy = -8;
|
|
1845
|
+
|
|
1846
|
+
// Horizontal spacing between hit tests
|
|
1847
|
+
// Note: This value depends on the font size. If the gap is too small
|
|
1848
|
+
// we end up placing the cursor at the end of the expression when we
|
|
1849
|
+
// shouldn't.
|
|
1850
|
+
const dx = 5;
|
|
1851
|
+
if (this._findHitNode(this._containerBounds, x, y, dx, dy)) {
|
|
1852
|
+
return;
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
// If we haven't found anything start from the top.
|
|
1856
|
+
y = this._containerBounds.top;
|
|
1857
|
+
|
|
1858
|
+
// dy is positive b/c we're going downwards.
|
|
1859
|
+
dy = 8;
|
|
1860
|
+
if (this._findHitNode(this._containerBounds, x, y, dx, dy)) {
|
|
1861
|
+
return;
|
|
1862
|
+
}
|
|
1863
|
+
const firstChildBounds = this._root.firstChild.getBoundingClientRect();
|
|
1864
|
+
const lastChildBounds = this._root.lastChild.getBoundingClientRect();
|
|
1865
|
+
const left = firstChildBounds.left;
|
|
1866
|
+
const right = lastChildBounds.right;
|
|
1867
|
+
|
|
1868
|
+
// We've exhausted all of the options. We're likely either to the right
|
|
1869
|
+
// or left of all of the math, so we place the cursor at the end to
|
|
1870
|
+
// which it's closest.
|
|
1871
|
+
if (Math.abs(x - right) < Math.abs(x - left)) {
|
|
1872
|
+
cursor.insAtRightEnd(this.mathField.mathField.__controller.root);
|
|
1873
|
+
} else {
|
|
1874
|
+
cursor.insAtLeftEnd(this.mathField.mathField.__controller.root);
|
|
1875
|
+
}
|
|
1876
|
+
// In that event, we need to update the cursor context ourselves.
|
|
1877
|
+
this.props.keypadElement && this.props.keypadElement.setCursor({
|
|
1878
|
+
context: this.mathField.contextForCursor()
|
|
1879
|
+
});
|
|
1880
|
+
};
|
|
1881
|
+
handleTouchStart = e => {
|
|
1882
|
+
e.stopPropagation();
|
|
1883
|
+
|
|
1884
|
+
// Hide the cursor handle on touch start, if the handle itself isn't
|
|
1885
|
+
// handling the touch event.
|
|
1886
|
+
this._hideCursorHandle();
|
|
1887
|
+
|
|
1888
|
+
// Cache the container bounds, so as to avoid re-computing. If we don't
|
|
1889
|
+
// have any content, then it's not necessary, since the cursor can't be
|
|
1890
|
+
// moved anyway.
|
|
1891
|
+
if (this.mathField.getContent() !== "") {
|
|
1892
|
+
this._containerBounds = this._container.getBoundingClientRect();
|
|
1893
|
+
|
|
1894
|
+
// Make the cursor visible and set the handle-less cursor's
|
|
1895
|
+
// location.
|
|
1896
|
+
const touch = e.changedTouches[0];
|
|
1897
|
+
this._insertCursorAtClosestNode(touch.clientX, touch.clientY);
|
|
1898
|
+
}
|
|
1899
|
+
|
|
1900
|
+
// Trigger a focus event, if we're not already focused.
|
|
1901
|
+
if (!this.state.focused) {
|
|
1902
|
+
this.focus();
|
|
1903
|
+
}
|
|
1904
|
+
};
|
|
1905
|
+
handleTouchMove = e => {
|
|
1906
|
+
e.stopPropagation();
|
|
1907
|
+
|
|
1908
|
+
// Update the handle-less cursor's location on move, if there's any
|
|
1909
|
+
// content in the box. Note that if the user touched outside the keypad
|
|
1910
|
+
// (e.g., with a different finger) during this touch interaction, we
|
|
1911
|
+
// may have blurred, in which case we should ignore the touch (since
|
|
1912
|
+
// the cursor is no longer visible and the input is no longer
|
|
1913
|
+
// highlighted).
|
|
1914
|
+
if (this.mathField.getContent() !== "" && this.state.focused) {
|
|
1915
|
+
const touch = e.changedTouches[0];
|
|
1916
|
+
this._insertCursorAtClosestNode(touch.clientX, touch.clientY);
|
|
1917
|
+
}
|
|
1918
|
+
};
|
|
1919
|
+
handleTouchEnd = e => {
|
|
1920
|
+
e.stopPropagation();
|
|
1921
|
+
|
|
1922
|
+
// And on touch-end, reveal the cursor, unless the input is empty. Note
|
|
1923
|
+
// that if the user touched outside the keypad (e.g., with a different
|
|
1924
|
+
// finger) during this touch interaction, we may have blurred, in which
|
|
1925
|
+
// case we should ignore the touch (since the cursor is no longer
|
|
1926
|
+
// visible and the input is no longer highlighted).
|
|
1927
|
+
if (this.mathField.getContent() !== "" && this.state.focused) {
|
|
1928
|
+
this._updateCursorHandle();
|
|
1929
|
+
}
|
|
1930
|
+
};
|
|
1931
|
+
|
|
1932
|
+
/**
|
|
1933
|
+
* When a touch starts in the cursor handle, we track it so as to avoid
|
|
1934
|
+
* handling any touch events ourself.
|
|
1935
|
+
*
|
|
1936
|
+
* @param {TouchEvent} e - the raw touch event from the browser
|
|
1937
|
+
*/
|
|
1938
|
+
onCursorHandleTouchStart = e => {
|
|
1939
|
+
// NOTE(charlie): The cursor handle is a child of this view, so whenever
|
|
1940
|
+
// it receives a touch event, that event would also typically be bubbled
|
|
1941
|
+
// up to our own handlers. However, we want the cursor to handle its own
|
|
1942
|
+
// touch events, and for this view to only handle touch events that
|
|
1943
|
+
// don't affect the cursor. As such, we `stopPropagation` on any touch
|
|
1944
|
+
// events that are being handled by the cursor, so as to avoid handling
|
|
1945
|
+
// them in our own touch handlers.
|
|
1946
|
+
e.stopPropagation();
|
|
1947
|
+
e.preventDefault();
|
|
1948
|
+
|
|
1949
|
+
// Cache the container bounds, so as to avoid re-computing.
|
|
1950
|
+
this._containerBounds = this._container.getBoundingClientRect();
|
|
1951
|
+
};
|
|
1952
|
+
_constrainToBound = (value, min, max, friction) => {
|
|
1953
|
+
if (value < min) {
|
|
1954
|
+
return min + (value - min) * friction;
|
|
1955
|
+
} else if (value > max) {
|
|
1956
|
+
return max + (value - max) * friction;
|
|
1957
|
+
} else {
|
|
1958
|
+
return value;
|
|
1959
|
+
}
|
|
1960
|
+
};
|
|
1961
|
+
|
|
1962
|
+
/**
|
|
1963
|
+
* When the user moves the cursor handle update the position of the cursor
|
|
1964
|
+
* and the handle.
|
|
1965
|
+
*
|
|
1966
|
+
* @param {TouchEvent} e - the raw touch event from the browser
|
|
1967
|
+
*/
|
|
1968
|
+
onCursorHandleTouchMove = e => {
|
|
1969
|
+
e.stopPropagation();
|
|
1970
|
+
const x = e.changedTouches[0].clientX;
|
|
1971
|
+
const y = e.changedTouches[0].clientY;
|
|
1972
|
+
const relativeX = x - this._containerBounds.left;
|
|
1973
|
+
const relativeY = y - 2 * cursorHandleRadiusPx * cursorHandleDistanceMultiplier - this._containerBounds.top;
|
|
1974
|
+
|
|
1975
|
+
// We subtract the containerBounds left/top to correct for the
|
|
1976
|
+
// MathInput's position on the page. On top of that, we subtract an
|
|
1977
|
+
// additional 2 x {height of the cursor} so that the bottom of the
|
|
1978
|
+
// cursor tracks the user's finger, to make it visible under their
|
|
1979
|
+
// touch.
|
|
1980
|
+
this.setState({
|
|
1981
|
+
handle: {
|
|
1982
|
+
animateIntoPosition: false,
|
|
1983
|
+
visible: true,
|
|
1984
|
+
// TODO(charlie): Use clientX and clientY to avoid the need for
|
|
1985
|
+
// scroll offsets. This likely also means that the cursor
|
|
1986
|
+
// detection doesn't work when scrolled, since we're not
|
|
1987
|
+
// offsetting those values.
|
|
1988
|
+
x: this._constrainToBound(relativeX, 0, this._containerBounds.width, constrainingFrictionFactor),
|
|
1989
|
+
y: this._constrainToBound(relativeY, 0, this._containerBounds.height, constrainingFrictionFactor)
|
|
1990
|
+
}
|
|
1991
|
+
});
|
|
1992
|
+
|
|
1993
|
+
// Use a y-coordinate that's just above where the user is actually
|
|
1994
|
+
// touching because they're dragging the handle which is a little
|
|
1995
|
+
// below where the cursor actually is.
|
|
1996
|
+
const distanceAboveFingerToTrySelecting = 22;
|
|
1997
|
+
const adjustedY = y - distanceAboveFingerToTrySelecting;
|
|
1998
|
+
this._insertCursorAtClosestNode(x, adjustedY);
|
|
1999
|
+
};
|
|
2000
|
+
|
|
2001
|
+
/**
|
|
2002
|
+
* When the user releases the cursor handle, animate it back into place.
|
|
2003
|
+
*
|
|
2004
|
+
* @param {TouchEvent} e - the raw touch event from the browser
|
|
2005
|
+
*/
|
|
2006
|
+
onCursorHandleTouchEnd = e => {
|
|
2007
|
+
e.stopPropagation();
|
|
2008
|
+
this._updateCursorHandle(true);
|
|
2009
|
+
};
|
|
2010
|
+
|
|
2011
|
+
/**
|
|
2012
|
+
* If the gesture is cancelled mid-drag, simply hide it.
|
|
2013
|
+
*
|
|
2014
|
+
* @param {TouchEvent} e - the raw touch event from the browser
|
|
2015
|
+
*/
|
|
2016
|
+
onCursorHandleTouchCancel = e => {
|
|
2017
|
+
e.stopPropagation();
|
|
2018
|
+
this._updateCursorHandle(true);
|
|
2019
|
+
};
|
|
2020
|
+
domKeyToMathQuillKey = key => {
|
|
2021
|
+
const keyMap = {
|
|
2022
|
+
"+": "PLUS",
|
|
2023
|
+
"-": "MINUS",
|
|
2024
|
+
"*": "TIMES",
|
|
2025
|
+
"/": "DIVIDE",
|
|
2026
|
+
".": "DECIMAL",
|
|
2027
|
+
"%": "PERCENT",
|
|
2028
|
+
"=": "EQUAL",
|
|
2029
|
+
">": "GT",
|
|
2030
|
+
"<": "LT",
|
|
2031
|
+
"^": "EXP"
|
|
2032
|
+
};
|
|
2033
|
+
|
|
2034
|
+
// Numbers
|
|
2035
|
+
if (["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"].includes(key)) {
|
|
2036
|
+
return `NUM_${key}`;
|
|
2037
|
+
}
|
|
2038
|
+
|
|
2039
|
+
// Movement keys
|
|
2040
|
+
else if (key === "Backspace") {
|
|
2041
|
+
return "BACKSPACE";
|
|
2113
2042
|
}
|
|
2114
|
-
|
|
2115
|
-
|
|
2043
|
+
|
|
2044
|
+
// Operators
|
|
2045
|
+
else if (key in keyMap) {
|
|
2046
|
+
return keyMap[key];
|
|
2116
2047
|
}
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2048
|
+
|
|
2049
|
+
// The key pressed doesn't map to any of the math input operators
|
|
2050
|
+
return null;
|
|
2051
|
+
};
|
|
2052
|
+
handleKeyUp = event => {
|
|
2053
|
+
const mathQuillKey = this.domKeyToMathQuillKey(event.key);
|
|
2054
|
+
if (mathQuillKey) {
|
|
2055
|
+
this.mathField.pressKey(mathQuillKey);
|
|
2056
|
+
|
|
2057
|
+
// TODO(diedra): If the new value being added is off-screen to the right
|
|
2058
|
+
// due to the max-width of the text box, scroll the box to show the newest
|
|
2059
|
+
// value
|
|
2060
|
+
const value = this.mathField.getContent();
|
|
2061
|
+
if (this.props.value !== value) {
|
|
2062
|
+
this.mathField.setContent(this.props.value);
|
|
2063
|
+
this.props.onChange(value, false);
|
|
2064
|
+
this._hideCursorHandle();
|
|
2065
|
+
}
|
|
2066
|
+
}
|
|
2067
|
+
};
|
|
2068
|
+
getBorderWidthPx = () => {
|
|
2069
|
+
// TODO(diedra): Move these to the common style package.
|
|
2070
|
+
const normalBorderWidthPx = 1;
|
|
2071
|
+
const focusedBorderWidthPx = 2;
|
|
2072
|
+
return this.state.focused ? focusedBorderWidthPx : normalBorderWidthPx;
|
|
2073
|
+
};
|
|
2074
|
+
|
|
2075
|
+
// Calculate the appropriate padding based on the border width (which is
|
|
2076
|
+
// considered 'padding', since we're using 'border-box') and the fact
|
|
2077
|
+
// that MathQuill automatically applies 2px of padding to the inner
|
|
2078
|
+
// input.
|
|
2079
|
+
getInputInnerPadding = () => {
|
|
2080
|
+
const paddingInset = totalDesiredPadding - this.getBorderWidthPx();
|
|
2081
|
+
|
|
2082
|
+
// Now, translate that to the appropriate padding for each direction.
|
|
2083
|
+
// The complication here is that we want numerals to be centered within
|
|
2084
|
+
// the input. However, Symbola (MathQuill's font of choice) renders
|
|
2085
|
+
// numerals with approximately 3px of padding below and 1px of padding
|
|
2086
|
+
// above (to make room for ascenders and descenders). So we ignore those
|
|
2087
|
+
// padding values for the vertical directions.
|
|
2088
|
+
const symbolaPaddingBottom = 3;
|
|
2089
|
+
const symbolaPaddingTop = 1;
|
|
2090
|
+
const padding = {
|
|
2091
|
+
paddingTop: paddingInset - symbolaPaddingTop,
|
|
2092
|
+
paddingRight: paddingInset,
|
|
2093
|
+
paddingBottom: paddingInset - symbolaPaddingBottom,
|
|
2094
|
+
paddingLeft: paddingInset
|
|
2095
|
+
};
|
|
2096
|
+
return padding;
|
|
2097
|
+
};
|
|
2129
2098
|
render() {
|
|
2130
2099
|
const {
|
|
2131
2100
|
focused,
|
|
@@ -2181,10 +2150,6 @@ class MathInput extends React__namespace.Component {
|
|
|
2181
2150
|
})));
|
|
2182
2151
|
}
|
|
2183
2152
|
}
|
|
2184
|
-
_defineProperty(MathInput, "defaultProps", {
|
|
2185
|
-
style: {},
|
|
2186
|
-
value: ""
|
|
2187
|
-
});
|
|
2188
2153
|
const fontSizePt = 18;
|
|
2189
2154
|
const inputMaxWidth = 128;
|
|
2190
2155
|
|
|
@@ -2335,12 +2300,12 @@ const styles$i = aphrodite.StyleSheet.create({
|
|
|
2335
2300
|
height: 38,
|
|
2336
2301
|
boxSizing: "border-box",
|
|
2337
2302
|
borderRadius: 3,
|
|
2338
|
-
border:
|
|
2303
|
+
border: `1px solid transparent`,
|
|
2339
2304
|
marginRight: 1,
|
|
2340
2305
|
marginLeft: 1
|
|
2341
2306
|
},
|
|
2342
2307
|
hovered: {
|
|
2343
|
-
background:
|
|
2308
|
+
background: `linear-gradient(0deg, rgba(24, 101, 242, 0.32), rgba(24, 101, 242, 0.32)), ${Color__default["default"].white}`,
|
|
2344
2309
|
border: "1px solid #1865F2"
|
|
2345
2310
|
},
|
|
2346
2311
|
pressed: {
|
|
@@ -2348,11 +2313,11 @@ const styles$i = aphrodite.StyleSheet.create({
|
|
|
2348
2313
|
},
|
|
2349
2314
|
focused: {
|
|
2350
2315
|
outline: "none",
|
|
2351
|
-
border:
|
|
2316
|
+
border: `2px solid ${Color__default["default"].blue}`
|
|
2352
2317
|
},
|
|
2353
2318
|
innerBox: {
|
|
2354
2319
|
boxSizing: "border-box",
|
|
2355
|
-
border:
|
|
2320
|
+
border: `1px solid transparent`,
|
|
2356
2321
|
borderRadius: 2,
|
|
2357
2322
|
display: "flex",
|
|
2358
2323
|
flex: 1,
|
|
@@ -2360,7 +2325,7 @@ const styles$i = aphrodite.StyleSheet.create({
|
|
|
2360
2325
|
alignItems: "center"
|
|
2361
2326
|
},
|
|
2362
2327
|
innerBoxPressed: {
|
|
2363
|
-
border:
|
|
2328
|
+
border: `1px solid ${Color__default["default"].white}`
|
|
2364
2329
|
},
|
|
2365
2330
|
activeIndicator: {
|
|
2366
2331
|
position: "absolute",
|
|
@@ -2372,7 +2337,7 @@ const styles$i = aphrodite.StyleSheet.create({
|
|
|
2372
2337
|
},
|
|
2373
2338
|
clickable: {
|
|
2374
2339
|
":focus": {
|
|
2375
|
-
outline:
|
|
2340
|
+
outline: `none`
|
|
2376
2341
|
}
|
|
2377
2342
|
}
|
|
2378
2343
|
});
|
|
@@ -2452,7 +2417,7 @@ function Tabbar(props) {
|
|
|
2452
2417
|
}, /*#__PURE__*/React__namespace.createElement(wonderBlocksCore.View, {
|
|
2453
2418
|
style: [styles$h.pages]
|
|
2454
2419
|
}, items.map(item => /*#__PURE__*/React__namespace.createElement(TabbarItem, {
|
|
2455
|
-
key:
|
|
2420
|
+
key: `tabbar-item-${item}`,
|
|
2456
2421
|
itemState: item === selectedItem ? "active" : "inactive",
|
|
2457
2422
|
itemType: item,
|
|
2458
2423
|
onClick: () => {
|
|
@@ -2465,6 +2430,66 @@ function Tabbar(props) {
|
|
|
2465
2430
|
})));
|
|
2466
2431
|
}
|
|
2467
2432
|
|
|
2433
|
+
/**
|
|
2434
|
+
* Constants that are shared between multiple files.
|
|
2435
|
+
*/
|
|
2436
|
+
|
|
2437
|
+
let KeypadType = /*#__PURE__*/function (KeypadType) {
|
|
2438
|
+
KeypadType["FRACTION"] = "FRACTION";
|
|
2439
|
+
KeypadType["EXPRESSION"] = "EXPRESSION";
|
|
2440
|
+
return KeypadType;
|
|
2441
|
+
}({});
|
|
2442
|
+
const KeyTypes = ["EMPTY",
|
|
2443
|
+
// For numerals, variables, and any other characters that themselves
|
|
2444
|
+
// compose 'values'.
|
|
2445
|
+
"VALUE",
|
|
2446
|
+
// For buttons that insert or adjust math in an input.
|
|
2447
|
+
"OPERATOR",
|
|
2448
|
+
// For buttons that move the cursor in an input (including via
|
|
2449
|
+
// deletion).
|
|
2450
|
+
"INPUT_NAVIGATION",
|
|
2451
|
+
// For buttons that modify the broader keypad state (e.g., by changing
|
|
2452
|
+
// the visible pane).
|
|
2453
|
+
"KEYPAD_NAVIGATION",
|
|
2454
|
+
// For buttons that house multiple buttons and have no action
|
|
2455
|
+
// themselves.
|
|
2456
|
+
"MANY",
|
|
2457
|
+
// For the echo animation that appears on press.
|
|
2458
|
+
"ECHO"];
|
|
2459
|
+
let DeviceOrientation = /*#__PURE__*/function (DeviceOrientation) {
|
|
2460
|
+
DeviceOrientation["LANDSCAPE"] = "LANDSCAPE";
|
|
2461
|
+
DeviceOrientation["PORTRAIT"] = "PORTRAIT";
|
|
2462
|
+
return DeviceOrientation;
|
|
2463
|
+
}({});
|
|
2464
|
+
let LayoutMode = /*#__PURE__*/function (LayoutMode) {
|
|
2465
|
+
LayoutMode["FULLSCREEN"] = "FULLSCREEN";
|
|
2466
|
+
LayoutMode["COMPACT"] = "COMPACT";
|
|
2467
|
+
return LayoutMode;
|
|
2468
|
+
}({});
|
|
2469
|
+
let BorderDirection = /*#__PURE__*/function (BorderDirection) {
|
|
2470
|
+
BorderDirection["LEFT"] = "LEFT";
|
|
2471
|
+
BorderDirection["BOTTOM"] = "BOTTOM";
|
|
2472
|
+
return BorderDirection;
|
|
2473
|
+
}({});
|
|
2474
|
+
const BorderStyles = {
|
|
2475
|
+
LEFT: [BorderDirection.LEFT],
|
|
2476
|
+
BOTTOM: [BorderDirection.BOTTOM],
|
|
2477
|
+
ALL: [BorderDirection.LEFT, BorderDirection.BOTTOM],
|
|
2478
|
+
NONE: []
|
|
2479
|
+
};
|
|
2480
|
+
let IconType = /*#__PURE__*/function (IconType) {
|
|
2481
|
+
IconType["MATH"] = "MATH";
|
|
2482
|
+
IconType["SVG"] = "SVG";
|
|
2483
|
+
IconType["TEXT"] = "TEXT";
|
|
2484
|
+
return IconType;
|
|
2485
|
+
}({});
|
|
2486
|
+
let EchoAnimationType = /*#__PURE__*/function (EchoAnimationType) {
|
|
2487
|
+
EchoAnimationType["SLIDE_AND_FADE"] = "SLIDE_AND_FADE";
|
|
2488
|
+
EchoAnimationType["FADE_ONLY"] = "FADE_ONLY";
|
|
2489
|
+
EchoAnimationType["LONG_FADE_ONLY"] = "LONG_FADE_ONLY";
|
|
2490
|
+
return EchoAnimationType;
|
|
2491
|
+
}({});
|
|
2492
|
+
|
|
2468
2493
|
/**
|
|
2469
2494
|
* This file contains configuration settings for the buttons in the keypad.
|
|
2470
2495
|
*/
|
|
@@ -2565,16 +2590,7 @@ const KeyConfigs = {
|
|
|
2565
2590
|
keyType: "VALUE",
|
|
2566
2591
|
// I18N: A label for a 'decimal' sign (represented as '.' or ',').
|
|
2567
2592
|
ariaLabel: i18n__namespace._("Decimal")
|
|
2568
|
-
})
|
|
2569
|
-
icon: decimalSeparator === DecimalSeparator.COMMA ? {
|
|
2570
|
-
// TODO(charlie): Get an SVG icon for the comma, or verify with
|
|
2571
|
-
// design that the text-rendered version is acceptable.
|
|
2572
|
-
type: IconType.TEXT,
|
|
2573
|
-
data: ","
|
|
2574
|
-
} : {
|
|
2575
|
-
type: IconType.SVG,
|
|
2576
|
-
data: "PERIOD"
|
|
2577
|
-
}
|
|
2593
|
+
})
|
|
2578
2594
|
},
|
|
2579
2595
|
PERIOD: {
|
|
2580
2596
|
...getDefaultOperatorFields({
|
|
@@ -3357,16 +3373,32 @@ function ButtonAsset(_ref) {
|
|
|
3357
3373
|
d: "M16.735 16.8558c0 1.024.272 1.812.816 2.364.552.544 1.32.816 2.304.816.528 0 .992-.084 1.392-.252.408-.168.752-.392 1.032-.672.28-.288.492-.62.636-.996.144-.384.216-.792.216-1.224 0-.504-.08-.952-.24-1.344-.152-.4-.372-.74-.66-1.02-.28-.28-.616-.492-1.008-.636-.392-.152-.82-.228-1.284-.228-.488 0-.928.08-1.32.24-.392.16-.728.384-1.008.672-.28.28-.496.616-.648 1.008-.152.384-.228.808-.228 1.272zm4.428 5.364c.16-.2.308-.388.444-.564.136-.184.264-.368.384-.552-.416.296-.88.524-1.392.684-.512.152-1.056.228-1.632.228-.624 0-1.224-.104-1.8-.312-.576-.216-1.088-.532-1.536-.948-.448-.424-.808-.944-1.08-1.56-.264-.624-.396-1.34-.396-2.148 0-.76.14-1.476.42-2.148.288-.672.688-1.256 1.2-1.752.512-.504 1.124-.9 1.836-1.188.712-.288 1.5-.432 2.364-.432.856 0 1.632.14 2.328.42.696.272 1.288.66 1.776 1.164.488.496.864 1.092 1.128 1.788.264.688.396 1.448.396 2.28 0 .52-.048 1.012-.144 1.476-.088.464-.22.916-.396 1.356-.168.432-.376.86-.624 1.284-.24.416-.512.84-.816 1.272l-4.068 5.832c-.12.176-.3.32-.54.432-.232.112-.496.168-.792.168h-2.364l5.304-6.78z",
|
|
3358
3374
|
fill: "#21242C"
|
|
3359
3375
|
}));
|
|
3360
|
-
// TODO(ned): Per the notes in `KeyConfigs`, shouldn't this be a comma
|
|
3361
|
-
// that we replace with the period icon for i18n? Duplicating for now.
|
|
3362
3376
|
case "DECIMAL":
|
|
3363
3377
|
case "PERIOD":
|
|
3378
|
+
// Different locales use different symbols for the decimal separator
|
|
3379
|
+
// (, vs .)
|
|
3380
|
+
if (id === "DECIMAL" && decimalSeparator === DecimalSeparator.COMMA) {
|
|
3381
|
+
// comma decimal separator
|
|
3382
|
+
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
3383
|
+
width: "40",
|
|
3384
|
+
height: "40",
|
|
3385
|
+
viewBox: "0 0 32 32",
|
|
3386
|
+
fill: "none",
|
|
3387
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
3388
|
+
"data-test-id": "comma-decimal"
|
|
3389
|
+
}, /*#__PURE__*/React__namespace.createElement("path", {
|
|
3390
|
+
d: "M11.5559 25.3544C11.8679 24.661 12.1799 23.933 12.4919 23.1704C12.8039 22.425 13.0986 21.6884 13.3759 20.9604C13.6706 20.2324 13.9219 19.5737 14.1299 18.9844H16.6259L16.7299 19.2704C16.4526 19.877 16.1232 20.5357 15.7419 21.2464C15.3606 21.9397 14.9619 22.633 14.5459 23.3264C14.1299 24.037 13.7139 24.713 13.2979 25.3544H11.5559Z",
|
|
3391
|
+
fill: "#21242C"
|
|
3392
|
+
}));
|
|
3393
|
+
}
|
|
3394
|
+
// period / US decimal separator
|
|
3364
3395
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
3365
3396
|
width: "40",
|
|
3366
3397
|
height: "40",
|
|
3367
3398
|
viewBox: "0 0 40 40",
|
|
3368
3399
|
fill: "none",
|
|
3369
|
-
xmlns: "http://www.w3.org/2000/svg"
|
|
3400
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
3401
|
+
"data-test-id": "period-decimal"
|
|
3370
3402
|
}, /*#__PURE__*/React__namespace.createElement("path", {
|
|
3371
3403
|
d: "M18.3401 27.512c0-.232.04-.448.12-.648.088-.208.204-.388.348-.54.152-.152.328-.272.528-.36.208-.088.428-.132.66-.132.232 0 .448.044.648.132.208.088.388.208.54.36.152.152.272.332.36.54.088.2.132.416.132.648 0 .24-.044.46-.132.66-.088.2-.208.376-.36.528-.152.152-.332.268-.54.348-.2.088-.416.132-.648.132-.232 0-.452-.044-.66-.132-.2-.08-.376-.196-.528-.348-.144-.152-.26-.328-.348-.528-.08-.2-.12-.42-.12-.66z",
|
|
3372
3404
|
fill: "#21242C"
|
|
@@ -4652,7 +4684,7 @@ function ButtonAsset(_ref) {
|
|
|
4652
4684
|
// this line forces an exhaustive check of all keys;
|
|
4653
4685
|
// if a key is not handled, the compiler will complain.
|
|
4654
4686
|
const unhandledKey = id;
|
|
4655
|
-
throw new Error(
|
|
4687
|
+
throw new Error(`Unhandled key: ${unhandledKey}`);
|
|
4656
4688
|
}
|
|
4657
4689
|
}
|
|
4658
4690
|
|
|
@@ -4702,7 +4734,7 @@ const styles$g = aphrodite.StyleSheet.create({
|
|
|
4702
4734
|
display: "flex",
|
|
4703
4735
|
justifyContent: "center",
|
|
4704
4736
|
alignItems: "center",
|
|
4705
|
-
boxShadow:
|
|
4737
|
+
boxShadow: `0px 1px 0px ${Color__default["default"].offBlack32}`,
|
|
4706
4738
|
boxSizing: "border-box",
|
|
4707
4739
|
background: Color__default["default"].white,
|
|
4708
4740
|
borderRadius: 4,
|
|
@@ -4727,7 +4759,7 @@ const styles$g = aphrodite.StyleSheet.create({
|
|
|
4727
4759
|
pressed: {
|
|
4728
4760
|
border: "2px solid #1B50B3",
|
|
4729
4761
|
padding: 0,
|
|
4730
|
-
background:
|
|
4762
|
+
background: `linear-gradient(0deg, rgba(24, 101, 242, 0.32), rgba(24, 101, 242, 0.32)), ${Color__default["default"].white}`,
|
|
4731
4763
|
boxShadow: "none"
|
|
4732
4764
|
},
|
|
4733
4765
|
outerBoxBase: {
|
|
@@ -4743,7 +4775,7 @@ const styles$g = aphrodite.StyleSheet.create({
|
|
|
4743
4775
|
height: "100%",
|
|
4744
4776
|
boxSizing: "border-box",
|
|
4745
4777
|
":focus": {
|
|
4746
|
-
outline:
|
|
4778
|
+
outline: `none`
|
|
4747
4779
|
}
|
|
4748
4780
|
}
|
|
4749
4781
|
});
|
|
@@ -5037,7 +5069,7 @@ function getStyles(key) {
|
|
|
5037
5069
|
case "LEFT":
|
|
5038
5070
|
return styles$f.left;
|
|
5039
5071
|
default:
|
|
5040
|
-
throw new Error(
|
|
5072
|
+
throw new Error(`Invalid key: ${key}`);
|
|
5041
5073
|
}
|
|
5042
5074
|
}
|
|
5043
5075
|
function NavigationButton(_ref) {
|
|
@@ -5078,7 +5110,7 @@ const styles$f = aphrodite.StyleSheet.create({
|
|
|
5078
5110
|
width: "100%",
|
|
5079
5111
|
height: "100%",
|
|
5080
5112
|
":focus": {
|
|
5081
|
-
outline:
|
|
5113
|
+
outline: `none`
|
|
5082
5114
|
}
|
|
5083
5115
|
},
|
|
5084
5116
|
outerBoxBase: {
|
|
@@ -5086,7 +5118,7 @@ const styles$f = aphrodite.StyleSheet.create({
|
|
|
5086
5118
|
width: "100%"
|
|
5087
5119
|
},
|
|
5088
5120
|
base: {
|
|
5089
|
-
boxShadow:
|
|
5121
|
+
boxShadow: `0px 1px 0px ${Color__default["default"].offBlack32}`,
|
|
5090
5122
|
display: "flex",
|
|
5091
5123
|
justifyContent: "center",
|
|
5092
5124
|
alignItems: "center",
|
|
@@ -5120,7 +5152,7 @@ const styles$f = aphrodite.StyleSheet.create({
|
|
|
5120
5152
|
},
|
|
5121
5153
|
pressed: {
|
|
5122
5154
|
border: "2px solid #1B50B3",
|
|
5123
|
-
background:
|
|
5155
|
+
background: `linear-gradient(0deg, rgba(24, 101, 242, 0.32), rgba(24, 101, 242, 0.32)), ${Color__default["default"].white}`,
|
|
5124
5156
|
boxShadow: "none"
|
|
5125
5157
|
}
|
|
5126
5158
|
});
|
|
@@ -5238,7 +5270,6 @@ const defaultProps = {
|
|
|
5238
5270
|
extraKeys: []
|
|
5239
5271
|
};
|
|
5240
5272
|
function getAvailableTabs(props) {
|
|
5241
|
-
var _props$extraKeys;
|
|
5242
5273
|
// We don't want to show any available tabs on the fractions keypad
|
|
5243
5274
|
if (props.fractionsOnly) {
|
|
5244
5275
|
return [];
|
|
@@ -5252,7 +5283,7 @@ function getAvailableTabs(props) {
|
|
|
5252
5283
|
if (props.trigonometry) {
|
|
5253
5284
|
tabs.push("Geometry");
|
|
5254
5285
|
}
|
|
5255
|
-
if (
|
|
5286
|
+
if (props.extraKeys?.length) {
|
|
5256
5287
|
tabs.push("Extras");
|
|
5257
5288
|
}
|
|
5258
5289
|
return tabs;
|
|
@@ -5465,6 +5496,7 @@ class TransitionChild extends React__namespace.Component {
|
|
|
5465
5496
|
// We keep track of all of the current applied classes so that we can remove
|
|
5466
5497
|
// them before a new transition starts in the case of the current transition
|
|
5467
5498
|
// being interrupted.
|
|
5499
|
+
_isMounted = false;
|
|
5468
5500
|
|
|
5469
5501
|
// The use of getDerivedStateFromProps here is to avoid an extra call to
|
|
5470
5502
|
// setState if the component re-enters. This can happen if TransitionGroup
|
|
@@ -5483,38 +5515,6 @@ class TransitionChild extends React__namespace.Component {
|
|
|
5483
5515
|
}
|
|
5484
5516
|
constructor(props) {
|
|
5485
5517
|
super(props);
|
|
5486
|
-
_defineProperty(this, "classNameQueue", void 0);
|
|
5487
|
-
_defineProperty(this, "appliedClassNames", void 0);
|
|
5488
|
-
_defineProperty(this, "_isMounted", false);
|
|
5489
|
-
_defineProperty(this, "addClass", (elem, className) => {
|
|
5490
|
-
if (className) {
|
|
5491
|
-
elem.classList.add(className);
|
|
5492
|
-
this.appliedClassNames.add(className);
|
|
5493
|
-
}
|
|
5494
|
-
});
|
|
5495
|
-
_defineProperty(this, "removeClass", (elem, className) => {
|
|
5496
|
-
if (className) {
|
|
5497
|
-
elem.classList.remove(className);
|
|
5498
|
-
this.appliedClassNames.delete(className);
|
|
5499
|
-
}
|
|
5500
|
-
});
|
|
5501
|
-
_defineProperty(this, "flushClassNameQueue", () => {
|
|
5502
|
-
if (this._isMounted) {
|
|
5503
|
-
const node = ReactDOM__default["default"].findDOMNode(this);
|
|
5504
|
-
if (node instanceof Element) {
|
|
5505
|
-
this.classNameQueue.forEach(_ref2 => {
|
|
5506
|
-
let [removeClassName, addClassName] = _ref2;
|
|
5507
|
-
// Remove the old class before adding a new class just
|
|
5508
|
-
// in case the new class is the same as the old one.
|
|
5509
|
-
this.removeClass(node, removeClassName);
|
|
5510
|
-
this.addClass(node, addClassName);
|
|
5511
|
-
});
|
|
5512
|
-
}
|
|
5513
|
-
}
|
|
5514
|
-
|
|
5515
|
-
// Remove all items in the Array.
|
|
5516
|
-
this.classNameQueue.length = 0;
|
|
5517
|
-
});
|
|
5518
5518
|
this._isMounted = false;
|
|
5519
5519
|
this.classNameQueue = [];
|
|
5520
5520
|
this.appliedClassNames = new Set();
|
|
@@ -5558,6 +5558,18 @@ class TransitionChild extends React__namespace.Component {
|
|
|
5558
5558
|
this.removeClass(node, className);
|
|
5559
5559
|
}
|
|
5560
5560
|
}
|
|
5561
|
+
addClass = (elem, className) => {
|
|
5562
|
+
if (className) {
|
|
5563
|
+
elem.classList.add(className);
|
|
5564
|
+
this.appliedClassNames.add(className);
|
|
5565
|
+
}
|
|
5566
|
+
};
|
|
5567
|
+
removeClass = (elem, className) => {
|
|
5568
|
+
if (className) {
|
|
5569
|
+
elem.classList.remove(className);
|
|
5570
|
+
this.appliedClassNames.delete(className);
|
|
5571
|
+
}
|
|
5572
|
+
};
|
|
5561
5573
|
transition(animationType, duration) {
|
|
5562
5574
|
const node = ReactDOM__default["default"].findDOMNode(this);
|
|
5563
5575
|
if (!(node instanceof Element)) {
|
|
@@ -5599,6 +5611,23 @@ class TransitionChild extends React__namespace.Component {
|
|
|
5599
5611
|
// Queue operation for after the next paint.
|
|
5600
5612
|
this.props.schedule.timeout(this.flushClassNameQueue, 0);
|
|
5601
5613
|
}
|
|
5614
|
+
flushClassNameQueue = () => {
|
|
5615
|
+
if (this._isMounted) {
|
|
5616
|
+
const node = ReactDOM__default["default"].findDOMNode(this);
|
|
5617
|
+
if (node instanceof Element) {
|
|
5618
|
+
this.classNameQueue.forEach(_ref2 => {
|
|
5619
|
+
let [removeClassName, addClassName] = _ref2;
|
|
5620
|
+
// Remove the old class before adding a new class just
|
|
5621
|
+
// in case the new class is the same as the old one.
|
|
5622
|
+
this.removeClass(node, removeClassName);
|
|
5623
|
+
this.addClass(node, addClassName);
|
|
5624
|
+
});
|
|
5625
|
+
}
|
|
5626
|
+
}
|
|
5627
|
+
|
|
5628
|
+
// Remove all items in the Array.
|
|
5629
|
+
this.classNameQueue.length = 0;
|
|
5630
|
+
};
|
|
5602
5631
|
render() {
|
|
5603
5632
|
const {
|
|
5604
5633
|
status
|
|
@@ -5682,71 +5711,13 @@ const AnimationDurationInMS = 200;
|
|
|
5682
5711
|
* can't have methods attached to them).
|
|
5683
5712
|
*/
|
|
5684
5713
|
class MobileKeypad extends React__namespace.Component {
|
|
5685
|
-
|
|
5686
|
-
|
|
5687
|
-
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
containerWidth: 0
|
|
5692
|
-
});
|
|
5693
|
-
_defineProperty(this, "_resize", () => {
|
|
5694
|
-
var _this$_containerRef$c;
|
|
5695
|
-
const containerWidth = ((_this$_containerRef$c = this._containerRef.current) === null || _this$_containerRef$c === void 0 ? void 0 : _this$_containerRef$c.clientWidth) || 0;
|
|
5696
|
-
this.setState({
|
|
5697
|
-
containerWidth
|
|
5698
|
-
});
|
|
5699
|
-
});
|
|
5700
|
-
_defineProperty(this, "_throttleResizeHandler", () => {
|
|
5701
|
-
if (this._throttleResize) {
|
|
5702
|
-
return;
|
|
5703
|
-
}
|
|
5704
|
-
this._throttleResize = true;
|
|
5705
|
-
setTimeout(() => {
|
|
5706
|
-
this._resize();
|
|
5707
|
-
this._throttleResize = false;
|
|
5708
|
-
}, 100);
|
|
5709
|
-
});
|
|
5710
|
-
_defineProperty(this, "activate", () => {
|
|
5711
|
-
this.props.setKeypadActive(true);
|
|
5712
|
-
});
|
|
5713
|
-
_defineProperty(this, "dismiss", () => {
|
|
5714
|
-
var _this$props$onDismiss, _this$props;
|
|
5715
|
-
this.props.setKeypadActive(false);
|
|
5716
|
-
(_this$props$onDismiss = (_this$props = this.props).onDismiss) === null || _this$props$onDismiss === void 0 ? void 0 : _this$props$onDismiss.call(_this$props);
|
|
5717
|
-
});
|
|
5718
|
-
_defineProperty(this, "configure", (configuration, cb) => {
|
|
5719
|
-
this.setState({
|
|
5720
|
-
keypadConfig: configuration
|
|
5721
|
-
});
|
|
5722
|
-
|
|
5723
|
-
// TODO(matthewc)[LC-1080]: this was brought in from v1's ProvidedKeypad.
|
|
5724
|
-
// We need to investigate whether we still need this.
|
|
5725
|
-
// HACK(charlie): In Perseus, triggering a focus causes the keypad to
|
|
5726
|
-
// animate into view and re-configure. We'd like to provide the option
|
|
5727
|
-
// to re-render the re-configured keypad before animating it into view,
|
|
5728
|
-
// to avoid jank in the animation. As such, we support passing a
|
|
5729
|
-
// callback into `configureKeypad`. However, implementing this properly
|
|
5730
|
-
// would require middleware, etc., so we just hack it on with
|
|
5731
|
-
// `setTimeout` for now.
|
|
5732
|
-
setTimeout(() => cb && cb());
|
|
5733
|
-
});
|
|
5734
|
-
_defineProperty(this, "setCursor", cursor => {
|
|
5735
|
-
this.setState({
|
|
5736
|
-
cursor
|
|
5737
|
-
});
|
|
5738
|
-
});
|
|
5739
|
-
_defineProperty(this, "setKeyHandler", keyHandler => {
|
|
5740
|
-
this.setState({
|
|
5741
|
-
keyHandler
|
|
5742
|
-
});
|
|
5743
|
-
});
|
|
5744
|
-
_defineProperty(this, "getDOMNode", () => {
|
|
5745
|
-
return ReactDOM__default["default"].findDOMNode(this);
|
|
5746
|
-
});
|
|
5747
|
-
}
|
|
5714
|
+
_containerRef = /*#__PURE__*/React__namespace.createRef();
|
|
5715
|
+
_containerResizeObserver = null;
|
|
5716
|
+
_throttleResize = false;
|
|
5717
|
+
state = {
|
|
5718
|
+
containerWidth: 0
|
|
5719
|
+
};
|
|
5748
5720
|
componentDidMount() {
|
|
5749
|
-
var _this$props$onElement, _this$props2;
|
|
5750
5721
|
this._resize();
|
|
5751
5722
|
window.addEventListener("resize", this._throttleResizeHandler);
|
|
5752
5723
|
window.addEventListener("orientationchange", this._throttleResizeHandler);
|
|
@@ -5759,7 +5730,7 @@ class MobileKeypad extends React__namespace.Component {
|
|
|
5759
5730
|
this._containerResizeObserver.observe(this._containerRef.current);
|
|
5760
5731
|
}
|
|
5761
5732
|
}
|
|
5762
|
-
|
|
5733
|
+
this.props.onElementMounted?.({
|
|
5763
5734
|
activate: this.activate,
|
|
5764
5735
|
dismiss: this.dismiss,
|
|
5765
5736
|
configure: this.configure,
|
|
@@ -5769,18 +5740,68 @@ class MobileKeypad extends React__namespace.Component {
|
|
|
5769
5740
|
});
|
|
5770
5741
|
}
|
|
5771
5742
|
componentWillUnmount() {
|
|
5772
|
-
var _this$_containerResiz;
|
|
5773
5743
|
window.removeEventListener("resize", this._throttleResizeHandler);
|
|
5774
5744
|
window.removeEventListener("orientationchange", this._throttleResizeHandler);
|
|
5775
|
-
|
|
5745
|
+
this._containerResizeObserver?.disconnect();
|
|
5776
5746
|
}
|
|
5747
|
+
_resize = () => {
|
|
5748
|
+
const containerWidth = this._containerRef.current?.clientWidth || 0;
|
|
5749
|
+
this.setState({
|
|
5750
|
+
containerWidth
|
|
5751
|
+
});
|
|
5752
|
+
};
|
|
5753
|
+
_throttleResizeHandler = () => {
|
|
5754
|
+
if (this._throttleResize) {
|
|
5755
|
+
return;
|
|
5756
|
+
}
|
|
5757
|
+
this._throttleResize = true;
|
|
5758
|
+
setTimeout(() => {
|
|
5759
|
+
this._resize();
|
|
5760
|
+
this._throttleResize = false;
|
|
5761
|
+
}, 100);
|
|
5762
|
+
};
|
|
5763
|
+
activate = () => {
|
|
5764
|
+
this.props.setKeypadActive(true);
|
|
5765
|
+
};
|
|
5766
|
+
dismiss = () => {
|
|
5767
|
+
this.props.setKeypadActive(false);
|
|
5768
|
+
this.props.onDismiss?.();
|
|
5769
|
+
};
|
|
5770
|
+
configure = (configuration, cb) => {
|
|
5771
|
+
this.setState({
|
|
5772
|
+
keypadConfig: configuration
|
|
5773
|
+
});
|
|
5774
|
+
|
|
5775
|
+
// TODO(matthewc)[LC-1080]: this was brought in from v1's ProvidedKeypad.
|
|
5776
|
+
// We need to investigate whether we still need this.
|
|
5777
|
+
// HACK(charlie): In Perseus, triggering a focus causes the keypad to
|
|
5778
|
+
// animate into view and re-configure. We'd like to provide the option
|
|
5779
|
+
// to re-render the re-configured keypad before animating it into view,
|
|
5780
|
+
// to avoid jank in the animation. As such, we support passing a
|
|
5781
|
+
// callback into `configureKeypad`. However, implementing this properly
|
|
5782
|
+
// would require middleware, etc., so we just hack it on with
|
|
5783
|
+
// `setTimeout` for now.
|
|
5784
|
+
setTimeout(() => cb && cb());
|
|
5785
|
+
};
|
|
5786
|
+
setCursor = cursor => {
|
|
5787
|
+
this.setState({
|
|
5788
|
+
cursor
|
|
5789
|
+
});
|
|
5790
|
+
};
|
|
5791
|
+
setKeyHandler = keyHandler => {
|
|
5792
|
+
this.setState({
|
|
5793
|
+
keyHandler
|
|
5794
|
+
});
|
|
5795
|
+
};
|
|
5796
|
+
getDOMNode = () => {
|
|
5797
|
+
return ReactDOM__default["default"].findDOMNode(this);
|
|
5798
|
+
};
|
|
5777
5799
|
_handleClickKey(key) {
|
|
5778
|
-
var _this$state$keyHandle, _this$state;
|
|
5779
5800
|
if (key === "DISMISS") {
|
|
5780
5801
|
this.dismiss();
|
|
5781
5802
|
return;
|
|
5782
5803
|
}
|
|
5783
|
-
const cursor =
|
|
5804
|
+
const cursor = this.state.keyHandler?.(key);
|
|
5784
5805
|
this.setState({
|
|
5785
5806
|
cursor
|
|
5786
5807
|
});
|
|
@@ -5798,35 +5819,35 @@ class MobileKeypad extends React__namespace.Component {
|
|
|
5798
5819
|
const containerStyle = [styles$c.keypadContainer,
|
|
5799
5820
|
// styles passed as props
|
|
5800
5821
|
...(Array.isArray(style) ? style : [style])];
|
|
5801
|
-
const isExpression =
|
|
5802
|
-
const convertDotToTimes = keypadConfig
|
|
5803
|
-
return /*#__PURE__*/React__namespace.createElement(
|
|
5822
|
+
const isExpression = keypadConfig?.keypadType === "EXPRESSION";
|
|
5823
|
+
const convertDotToTimes = keypadConfig?.times;
|
|
5824
|
+
return /*#__PURE__*/React__namespace.createElement(View, {
|
|
5825
|
+
style: containerStyle,
|
|
5826
|
+
forwardRef: this._containerRef
|
|
5827
|
+
}, /*#__PURE__*/React__namespace.createElement(AphroditeCSSTransitionGroup, {
|
|
5804
5828
|
transitionEnterTimeout: AnimationDurationInMS,
|
|
5805
5829
|
transitionLeaveTimeout: AnimationDurationInMS,
|
|
5806
5830
|
transitionStyle: {
|
|
5807
5831
|
enter: {
|
|
5808
5832
|
transform: "translate3d(0, 100%, 0)",
|
|
5809
|
-
transition:
|
|
5833
|
+
transition: `${AnimationDurationInMS}ms ease-out`
|
|
5810
5834
|
},
|
|
5811
5835
|
enterActive: {
|
|
5812
5836
|
transform: "translate3d(0, 0, 0)"
|
|
5813
5837
|
},
|
|
5814
5838
|
leave: {
|
|
5815
5839
|
transform: "translate3d(0, 0, 0)",
|
|
5816
|
-
transition:
|
|
5840
|
+
transition: `${AnimationDurationInMS}ms ease-out`
|
|
5817
5841
|
},
|
|
5818
5842
|
leaveActive: {
|
|
5819
5843
|
transform: "translate3d(0, 100%, 0)"
|
|
5820
5844
|
}
|
|
5821
5845
|
}
|
|
5822
|
-
}, keypadActive ? /*#__PURE__*/React__namespace.createElement(
|
|
5823
|
-
style: containerStyle,
|
|
5824
|
-
forwardRef: this._containerRef
|
|
5825
|
-
}, /*#__PURE__*/React__namespace.createElement(Keypad$2, {
|
|
5846
|
+
}, keypadActive ? /*#__PURE__*/React__namespace.createElement(Keypad$2, {
|
|
5826
5847
|
onAnalyticsEvent: this.props.onAnalyticsEvent,
|
|
5827
|
-
extraKeys: keypadConfig
|
|
5848
|
+
extraKeys: keypadConfig?.extraKeys,
|
|
5828
5849
|
onClickKey: key => this._handleClickKey(key),
|
|
5829
|
-
cursorContext: cursor
|
|
5850
|
+
cursorContext: cursor?.context,
|
|
5830
5851
|
fractionsOnly: !isExpression,
|
|
5831
5852
|
convertDotToTimes: convertDotToTimes,
|
|
5832
5853
|
divisionKey: isExpression,
|
|
@@ -5837,7 +5858,7 @@ class MobileKeypad extends React__namespace.Component {
|
|
|
5837
5858
|
advancedRelations: isExpression,
|
|
5838
5859
|
expandedView: containerWidth > expandedViewThreshold$1,
|
|
5839
5860
|
showDismiss: true
|
|
5840
|
-
})
|
|
5861
|
+
}) : null));
|
|
5841
5862
|
}
|
|
5842
5863
|
}
|
|
5843
5864
|
const styles$c = aphrodite.StyleSheet.create({
|
|
@@ -5960,20 +5981,14 @@ var Styles = aphrodite.StyleSheet.create({
|
|
|
5960
5981
|
}
|
|
5961
5982
|
});
|
|
5962
5983
|
|
|
5984
|
+
/**
|
|
5985
|
+
* A component that renders an icon with math (via KaTeX).
|
|
5986
|
+
*/
|
|
5963
5987
|
const {
|
|
5964
5988
|
row: row$7,
|
|
5965
5989
|
centered: centered$4
|
|
5966
5990
|
} = Styles;
|
|
5967
5991
|
class MathIcon extends React__namespace.Component {
|
|
5968
|
-
constructor() {
|
|
5969
|
-
super(...arguments);
|
|
5970
|
-
_defineProperty(this, "_renderMath", () => {
|
|
5971
|
-
const {
|
|
5972
|
-
math
|
|
5973
|
-
} = this.props;
|
|
5974
|
-
katex__default["default"].render(math, ReactDOM__default["default"].findDOMNode(this));
|
|
5975
|
-
});
|
|
5976
|
-
}
|
|
5977
5992
|
componentDidMount() {
|
|
5978
5993
|
this._renderMath();
|
|
5979
5994
|
}
|
|
@@ -5982,6 +5997,12 @@ class MathIcon extends React__namespace.Component {
|
|
|
5982
5997
|
this._renderMath();
|
|
5983
5998
|
}
|
|
5984
5999
|
}
|
|
6000
|
+
_renderMath = () => {
|
|
6001
|
+
const {
|
|
6002
|
+
math
|
|
6003
|
+
} = this.props;
|
|
6004
|
+
katex__default["default"].render(math, ReactDOM__default["default"].findDOMNode(this));
|
|
6005
|
+
};
|
|
5985
6006
|
render() {
|
|
5986
6007
|
const {
|
|
5987
6008
|
style
|
|
@@ -6002,7 +6023,15 @@ const styles$a = aphrodite.StyleSheet.create({
|
|
|
6002
6023
|
}
|
|
6003
6024
|
});
|
|
6004
6025
|
|
|
6026
|
+
/**
|
|
6027
|
+
* An autogenerated component that renders the COS iconograpy in SVG.
|
|
6028
|
+
*
|
|
6029
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6030
|
+
*/
|
|
6005
6031
|
class Cos extends React__namespace.Component {
|
|
6032
|
+
static propTypes = {
|
|
6033
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6034
|
+
};
|
|
6006
6035
|
render() {
|
|
6007
6036
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6008
6037
|
width: "48",
|
|
@@ -6023,11 +6052,16 @@ class Cos extends React__namespace.Component {
|
|
|
6023
6052
|
})));
|
|
6024
6053
|
}
|
|
6025
6054
|
}
|
|
6026
|
-
_defineProperty(Cos, "propTypes", {
|
|
6027
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6028
|
-
});
|
|
6029
6055
|
|
|
6056
|
+
/**
|
|
6057
|
+
* An autogenerated component that renders the LOG iconograpy in SVG.
|
|
6058
|
+
*
|
|
6059
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6060
|
+
*/
|
|
6030
6061
|
class Log extends React__namespace.Component {
|
|
6062
|
+
static propTypes = {
|
|
6063
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6064
|
+
};
|
|
6031
6065
|
render() {
|
|
6032
6066
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6033
6067
|
width: "48",
|
|
@@ -6045,11 +6079,16 @@ class Log extends React__namespace.Component {
|
|
|
6045
6079
|
})));
|
|
6046
6080
|
}
|
|
6047
6081
|
}
|
|
6048
|
-
_defineProperty(Log, "propTypes", {
|
|
6049
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6050
|
-
});
|
|
6051
6082
|
|
|
6083
|
+
/**
|
|
6084
|
+
* An autogenerated component that renders the EQUAL iconograpy in SVG.
|
|
6085
|
+
*
|
|
6086
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6087
|
+
*/
|
|
6052
6088
|
class Equal extends React__namespace.Component {
|
|
6089
|
+
static propTypes = {
|
|
6090
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6091
|
+
};
|
|
6053
6092
|
render() {
|
|
6054
6093
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6055
6094
|
width: "48",
|
|
@@ -6073,9 +6112,6 @@ class Equal extends React__namespace.Component {
|
|
|
6073
6112
|
})));
|
|
6074
6113
|
}
|
|
6075
6114
|
}
|
|
6076
|
-
_defineProperty(Equal, "propTypes", {
|
|
6077
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6078
|
-
});
|
|
6079
6115
|
|
|
6080
6116
|
/**
|
|
6081
6117
|
* An autogenerated component that renders the BACKSPACE iconograpy in SVG.
|
|
@@ -6105,7 +6141,15 @@ const Backspace = () => {
|
|
|
6105
6141
|
})));
|
|
6106
6142
|
};
|
|
6107
6143
|
|
|
6144
|
+
/**
|
|
6145
|
+
* An autogenerated component that renders the SQRT iconograpy in SVG.
|
|
6146
|
+
*
|
|
6147
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6148
|
+
*/
|
|
6108
6149
|
class Sqrt extends React__namespace.Component {
|
|
6150
|
+
static propTypes = {
|
|
6151
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6152
|
+
};
|
|
6109
6153
|
render() {
|
|
6110
6154
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6111
6155
|
width: "48",
|
|
@@ -6126,11 +6170,16 @@ class Sqrt extends React__namespace.Component {
|
|
|
6126
6170
|
})));
|
|
6127
6171
|
}
|
|
6128
6172
|
}
|
|
6129
|
-
_defineProperty(Sqrt, "propTypes", {
|
|
6130
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6131
|
-
});
|
|
6132
6173
|
|
|
6174
|
+
/**
|
|
6175
|
+
* An autogenerated component that renders the EXP iconograpy in SVG.
|
|
6176
|
+
*
|
|
6177
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6178
|
+
*/
|
|
6133
6179
|
class Exp extends React__namespace.Component {
|
|
6180
|
+
static propTypes = {
|
|
6181
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6182
|
+
};
|
|
6134
6183
|
render() {
|
|
6135
6184
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6136
6185
|
width: "48",
|
|
@@ -6148,11 +6197,16 @@ class Exp extends React__namespace.Component {
|
|
|
6148
6197
|
})));
|
|
6149
6198
|
}
|
|
6150
6199
|
}
|
|
6151
|
-
_defineProperty(Exp, "propTypes", {
|
|
6152
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6153
|
-
});
|
|
6154
6200
|
|
|
6201
|
+
/**
|
|
6202
|
+
* An autogenerated component that renders the NEQ iconograpy in SVG.
|
|
6203
|
+
*
|
|
6204
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6205
|
+
*/
|
|
6155
6206
|
class Neq extends React__namespace.Component {
|
|
6207
|
+
static propTypes = {
|
|
6208
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6209
|
+
};
|
|
6156
6210
|
render() {
|
|
6157
6211
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6158
6212
|
width: "48",
|
|
@@ -6176,11 +6230,16 @@ class Neq extends React__namespace.Component {
|
|
|
6176
6230
|
})));
|
|
6177
6231
|
}
|
|
6178
6232
|
}
|
|
6179
|
-
_defineProperty(Neq, "propTypes", {
|
|
6180
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6181
|
-
});
|
|
6182
6233
|
|
|
6234
|
+
/**
|
|
6235
|
+
* An autogenerated component that renders the GEQ iconograpy in SVG.
|
|
6236
|
+
*
|
|
6237
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6238
|
+
*/
|
|
6183
6239
|
class Geq extends React__namespace.Component {
|
|
6240
|
+
static propTypes = {
|
|
6241
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6242
|
+
};
|
|
6184
6243
|
render() {
|
|
6185
6244
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6186
6245
|
width: "48",
|
|
@@ -6204,11 +6263,16 @@ class Geq extends React__namespace.Component {
|
|
|
6204
6263
|
})));
|
|
6205
6264
|
}
|
|
6206
6265
|
}
|
|
6207
|
-
_defineProperty(Geq, "propTypes", {
|
|
6208
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6209
|
-
});
|
|
6210
6266
|
|
|
6267
|
+
/**
|
|
6268
|
+
* An autogenerated component that renders the LN iconograpy in SVG.
|
|
6269
|
+
*
|
|
6270
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6271
|
+
*/
|
|
6211
6272
|
class Ln extends React__namespace.Component {
|
|
6273
|
+
static propTypes = {
|
|
6274
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6275
|
+
};
|
|
6212
6276
|
render() {
|
|
6213
6277
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6214
6278
|
width: "48",
|
|
@@ -6226,9 +6290,6 @@ class Ln extends React__namespace.Component {
|
|
|
6226
6290
|
})));
|
|
6227
6291
|
}
|
|
6228
6292
|
}
|
|
6229
|
-
_defineProperty(Ln, "propTypes", {
|
|
6230
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6231
|
-
});
|
|
6232
6293
|
|
|
6233
6294
|
/**
|
|
6234
6295
|
* An autogenerated component that renders the DISMISS iconograpy in SVG.
|
|
@@ -6255,7 +6316,15 @@ const Dismiss = () => {
|
|
|
6255
6316
|
})));
|
|
6256
6317
|
};
|
|
6257
6318
|
|
|
6319
|
+
/**
|
|
6320
|
+
* An autogenerated component that renders the SIN iconograpy in SVG.
|
|
6321
|
+
*
|
|
6322
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6323
|
+
*/
|
|
6258
6324
|
class Sin extends React__namespace.Component {
|
|
6325
|
+
static propTypes = {
|
|
6326
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6327
|
+
};
|
|
6259
6328
|
render() {
|
|
6260
6329
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6261
6330
|
width: "48",
|
|
@@ -6276,11 +6345,16 @@ class Sin extends React__namespace.Component {
|
|
|
6276
6345
|
})));
|
|
6277
6346
|
}
|
|
6278
6347
|
}
|
|
6279
|
-
_defineProperty(Sin, "propTypes", {
|
|
6280
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6281
|
-
});
|
|
6282
6348
|
|
|
6349
|
+
/**
|
|
6350
|
+
* An autogenerated component that renders the LT iconograpy in SVG.
|
|
6351
|
+
*
|
|
6352
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6353
|
+
*/
|
|
6283
6354
|
class Lt extends React__namespace.Component {
|
|
6355
|
+
static propTypes = {
|
|
6356
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6357
|
+
};
|
|
6284
6358
|
render() {
|
|
6285
6359
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6286
6360
|
width: "48",
|
|
@@ -6304,11 +6378,16 @@ class Lt extends React__namespace.Component {
|
|
|
6304
6378
|
})));
|
|
6305
6379
|
}
|
|
6306
6380
|
}
|
|
6307
|
-
_defineProperty(Lt, "propTypes", {
|
|
6308
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6309
|
-
});
|
|
6310
6381
|
|
|
6382
|
+
/**
|
|
6383
|
+
* An autogenerated component that renders the CUBE_ROOT iconograpy in SVG.
|
|
6384
|
+
*
|
|
6385
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6386
|
+
*/
|
|
6311
6387
|
class CubeRoot extends React__namespace.Component {
|
|
6388
|
+
static propTypes = {
|
|
6389
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6390
|
+
};
|
|
6312
6391
|
render() {
|
|
6313
6392
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6314
6393
|
width: "48",
|
|
@@ -6332,11 +6411,16 @@ class CubeRoot extends React__namespace.Component {
|
|
|
6332
6411
|
})));
|
|
6333
6412
|
}
|
|
6334
6413
|
}
|
|
6335
|
-
_defineProperty(CubeRoot, "propTypes", {
|
|
6336
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6337
|
-
});
|
|
6338
6414
|
|
|
6415
|
+
/**
|
|
6416
|
+
* An autogenerated component that renders the PLUS iconograpy in SVG.
|
|
6417
|
+
*
|
|
6418
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6419
|
+
*/
|
|
6339
6420
|
class Plus extends React__namespace.Component {
|
|
6421
|
+
static propTypes = {
|
|
6422
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6423
|
+
};
|
|
6340
6424
|
render() {
|
|
6341
6425
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6342
6426
|
width: "48",
|
|
@@ -6357,11 +6441,16 @@ class Plus extends React__namespace.Component {
|
|
|
6357
6441
|
})));
|
|
6358
6442
|
}
|
|
6359
6443
|
}
|
|
6360
|
-
_defineProperty(Plus, "propTypes", {
|
|
6361
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6362
|
-
});
|
|
6363
6444
|
|
|
6445
|
+
/**
|
|
6446
|
+
* An autogenerated component that renders the TAN iconograpy in SVG.
|
|
6447
|
+
*
|
|
6448
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6449
|
+
*/
|
|
6364
6450
|
class Tan extends React__namespace.Component {
|
|
6451
|
+
static propTypes = {
|
|
6452
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6453
|
+
};
|
|
6365
6454
|
render() {
|
|
6366
6455
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6367
6456
|
width: "48",
|
|
@@ -6382,9 +6471,6 @@ class Tan extends React__namespace.Component {
|
|
|
6382
6471
|
})));
|
|
6383
6472
|
}
|
|
6384
6473
|
}
|
|
6385
|
-
_defineProperty(Tan, "propTypes", {
|
|
6386
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6387
|
-
});
|
|
6388
6474
|
|
|
6389
6475
|
const Arrow = props => {
|
|
6390
6476
|
return /*#__PURE__*/React__namespace.createElement("g", _extends({
|
|
@@ -6442,7 +6528,15 @@ const Down = () => {
|
|
|
6442
6528
|
}));
|
|
6443
6529
|
};
|
|
6444
6530
|
|
|
6531
|
+
/**
|
|
6532
|
+
* An autogenerated component that renders the LEFT_PAREN iconograpy in SVG.
|
|
6533
|
+
*
|
|
6534
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6535
|
+
*/
|
|
6445
6536
|
class LeftParen extends React__namespace.Component {
|
|
6537
|
+
static propTypes = {
|
|
6538
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6539
|
+
};
|
|
6446
6540
|
render() {
|
|
6447
6541
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6448
6542
|
width: "48",
|
|
@@ -6466,11 +6560,16 @@ class LeftParen extends React__namespace.Component {
|
|
|
6466
6560
|
})));
|
|
6467
6561
|
}
|
|
6468
6562
|
}
|
|
6469
|
-
_defineProperty(LeftParen, "propTypes", {
|
|
6470
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6471
|
-
});
|
|
6472
6563
|
|
|
6564
|
+
/**
|
|
6565
|
+
* An autogenerated component that renders the RIGHT_PAREN iconograpy in SVG.
|
|
6566
|
+
*
|
|
6567
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6568
|
+
*/
|
|
6473
6569
|
class RightParen extends React__namespace.Component {
|
|
6570
|
+
static propTypes = {
|
|
6571
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6572
|
+
};
|
|
6474
6573
|
render() {
|
|
6475
6574
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6476
6575
|
width: "48",
|
|
@@ -6494,11 +6593,16 @@ class RightParen extends React__namespace.Component {
|
|
|
6494
6593
|
})));
|
|
6495
6594
|
}
|
|
6496
6595
|
}
|
|
6497
|
-
_defineProperty(RightParen, "propTypes", {
|
|
6498
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6499
|
-
});
|
|
6500
6596
|
|
|
6597
|
+
/**
|
|
6598
|
+
* An autogenerated component that renders the GT iconograpy in SVG.
|
|
6599
|
+
*
|
|
6600
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6601
|
+
*/
|
|
6501
6602
|
class Gt extends React__namespace.Component {
|
|
6603
|
+
static propTypes = {
|
|
6604
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6605
|
+
};
|
|
6502
6606
|
render() {
|
|
6503
6607
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6504
6608
|
width: "48",
|
|
@@ -6522,11 +6626,16 @@ class Gt extends React__namespace.Component {
|
|
|
6522
6626
|
})));
|
|
6523
6627
|
}
|
|
6524
6628
|
}
|
|
6525
|
-
_defineProperty(Gt, "propTypes", {
|
|
6526
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6527
|
-
});
|
|
6528
6629
|
|
|
6630
|
+
/**
|
|
6631
|
+
* An autogenerated component that renders the DIVIDE iconograpy in SVG.
|
|
6632
|
+
*
|
|
6633
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6634
|
+
*/
|
|
6529
6635
|
class Divide extends React__namespace.Component {
|
|
6636
|
+
static propTypes = {
|
|
6637
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6638
|
+
};
|
|
6530
6639
|
render() {
|
|
6531
6640
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6532
6641
|
width: "48",
|
|
@@ -6557,11 +6666,16 @@ class Divide extends React__namespace.Component {
|
|
|
6557
6666
|
})));
|
|
6558
6667
|
}
|
|
6559
6668
|
}
|
|
6560
|
-
_defineProperty(Divide, "propTypes", {
|
|
6561
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6562
|
-
});
|
|
6563
6669
|
|
|
6670
|
+
/**
|
|
6671
|
+
* An autogenerated component that renders the PERIOD iconograpy in SVG.
|
|
6672
|
+
*
|
|
6673
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6674
|
+
*/
|
|
6564
6675
|
class Period extends React__namespace.Component {
|
|
6676
|
+
static propTypes = {
|
|
6677
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6678
|
+
};
|
|
6565
6679
|
render() {
|
|
6566
6680
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6567
6681
|
width: "48",
|
|
@@ -6581,11 +6695,16 @@ class Period extends React__namespace.Component {
|
|
|
6581
6695
|
})));
|
|
6582
6696
|
}
|
|
6583
6697
|
}
|
|
6584
|
-
_defineProperty(Period, "propTypes", {
|
|
6585
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6586
|
-
});
|
|
6587
6698
|
|
|
6699
|
+
/**
|
|
6700
|
+
* An autogenerated component that renders the PERCENT iconograpy in SVG.
|
|
6701
|
+
*
|
|
6702
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6703
|
+
*/
|
|
6588
6704
|
class Percent extends React__namespace.Component {
|
|
6705
|
+
static propTypes = {
|
|
6706
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6707
|
+
};
|
|
6589
6708
|
render() {
|
|
6590
6709
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6591
6710
|
width: "48",
|
|
@@ -6623,11 +6742,16 @@ class Percent extends React__namespace.Component {
|
|
|
6623
6742
|
}))));
|
|
6624
6743
|
}
|
|
6625
6744
|
}
|
|
6626
|
-
_defineProperty(Percent, "propTypes", {
|
|
6627
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6628
|
-
});
|
|
6629
6745
|
|
|
6746
|
+
/**
|
|
6747
|
+
* An autogenerated component that renders the TIMES iconograpy in SVG.
|
|
6748
|
+
*
|
|
6749
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6750
|
+
*/
|
|
6630
6751
|
class Times extends React__namespace.Component {
|
|
6752
|
+
static propTypes = {
|
|
6753
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6754
|
+
};
|
|
6631
6755
|
render() {
|
|
6632
6756
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6633
6757
|
width: "48",
|
|
@@ -6651,11 +6775,16 @@ class Times extends React__namespace.Component {
|
|
|
6651
6775
|
})));
|
|
6652
6776
|
}
|
|
6653
6777
|
}
|
|
6654
|
-
_defineProperty(Times, "propTypes", {
|
|
6655
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6656
|
-
});
|
|
6657
6778
|
|
|
6779
|
+
/**
|
|
6780
|
+
* An autogenerated component that renders the EXP_3 iconograpy in SVG.
|
|
6781
|
+
*
|
|
6782
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6783
|
+
*/
|
|
6658
6784
|
class Exp3 extends React__namespace.Component {
|
|
6785
|
+
static propTypes = {
|
|
6786
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6787
|
+
};
|
|
6659
6788
|
render() {
|
|
6660
6789
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6661
6790
|
width: "48",
|
|
@@ -6673,11 +6802,16 @@ class Exp3 extends React__namespace.Component {
|
|
|
6673
6802
|
})));
|
|
6674
6803
|
}
|
|
6675
6804
|
}
|
|
6676
|
-
_defineProperty(Exp3, "propTypes", {
|
|
6677
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6678
|
-
});
|
|
6679
6805
|
|
|
6806
|
+
/**
|
|
6807
|
+
* An autogenerated component that renders the EXP_2 iconograpy in SVG.
|
|
6808
|
+
*
|
|
6809
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6810
|
+
*/
|
|
6680
6811
|
class Exp2 extends React__namespace.Component {
|
|
6812
|
+
static propTypes = {
|
|
6813
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6814
|
+
};
|
|
6681
6815
|
render() {
|
|
6682
6816
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6683
6817
|
width: "48",
|
|
@@ -6695,9 +6829,6 @@ class Exp2 extends React__namespace.Component {
|
|
|
6695
6829
|
})));
|
|
6696
6830
|
}
|
|
6697
6831
|
}
|
|
6698
|
-
_defineProperty(Exp2, "propTypes", {
|
|
6699
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6700
|
-
});
|
|
6701
6832
|
|
|
6702
6833
|
/**
|
|
6703
6834
|
* A component that renders the RIGHT iconograpy in SVG.
|
|
@@ -6712,7 +6843,15 @@ const Right = () => {
|
|
|
6712
6843
|
}));
|
|
6713
6844
|
};
|
|
6714
6845
|
|
|
6846
|
+
/**
|
|
6847
|
+
* An autogenerated component that renders the CDOT iconograpy in SVG.
|
|
6848
|
+
*
|
|
6849
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6850
|
+
*/
|
|
6715
6851
|
class Cdot extends React__namespace.Component {
|
|
6852
|
+
static propTypes = {
|
|
6853
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6854
|
+
};
|
|
6716
6855
|
render() {
|
|
6717
6856
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6718
6857
|
width: "48",
|
|
@@ -6737,11 +6876,16 @@ class Cdot extends React__namespace.Component {
|
|
|
6737
6876
|
}))));
|
|
6738
6877
|
}
|
|
6739
6878
|
}
|
|
6740
|
-
_defineProperty(Cdot, "propTypes", {
|
|
6741
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6742
|
-
});
|
|
6743
6879
|
|
|
6880
|
+
/**
|
|
6881
|
+
* An autogenerated component that renders the LOG_N iconograpy in SVG.
|
|
6882
|
+
*
|
|
6883
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6884
|
+
*/
|
|
6744
6885
|
class LogN extends React__namespace.Component {
|
|
6886
|
+
static propTypes = {
|
|
6887
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6888
|
+
};
|
|
6745
6889
|
render() {
|
|
6746
6890
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6747
6891
|
width: "48",
|
|
@@ -6759,11 +6903,16 @@ class LogN extends React__namespace.Component {
|
|
|
6759
6903
|
})));
|
|
6760
6904
|
}
|
|
6761
6905
|
}
|
|
6762
|
-
_defineProperty(LogN, "propTypes", {
|
|
6763
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6764
|
-
});
|
|
6765
6906
|
|
|
6907
|
+
/**
|
|
6908
|
+
* An autogenerated component that renders the LEQ iconograpy in SVG.
|
|
6909
|
+
*
|
|
6910
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6911
|
+
*/
|
|
6766
6912
|
class Leq extends React__namespace.Component {
|
|
6913
|
+
static propTypes = {
|
|
6914
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6915
|
+
};
|
|
6767
6916
|
render() {
|
|
6768
6917
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6769
6918
|
width: "48",
|
|
@@ -6787,11 +6936,16 @@ class Leq extends React__namespace.Component {
|
|
|
6787
6936
|
})));
|
|
6788
6937
|
}
|
|
6789
6938
|
}
|
|
6790
|
-
_defineProperty(Leq, "propTypes", {
|
|
6791
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6792
|
-
});
|
|
6793
6939
|
|
|
6940
|
+
/**
|
|
6941
|
+
* An autogenerated component that renders the MINUS iconograpy in SVG.
|
|
6942
|
+
*
|
|
6943
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6944
|
+
*/
|
|
6794
6945
|
class Minus extends React__namespace.Component {
|
|
6946
|
+
static propTypes = {
|
|
6947
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6948
|
+
};
|
|
6795
6949
|
render() {
|
|
6796
6950
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6797
6951
|
width: "48",
|
|
@@ -6812,11 +6966,16 @@ class Minus extends React__namespace.Component {
|
|
|
6812
6966
|
})));
|
|
6813
6967
|
}
|
|
6814
6968
|
}
|
|
6815
|
-
_defineProperty(Minus, "propTypes", {
|
|
6816
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6817
|
-
});
|
|
6818
6969
|
|
|
6970
|
+
/**
|
|
6971
|
+
* An autogenerated component that renders the RADICAL iconograpy in SVG.
|
|
6972
|
+
*
|
|
6973
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
6974
|
+
*/
|
|
6819
6975
|
class Radical extends React__namespace.Component {
|
|
6976
|
+
static propTypes = {
|
|
6977
|
+
color: PropTypes__default["default"].string.isRequired
|
|
6978
|
+
};
|
|
6820
6979
|
render() {
|
|
6821
6980
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6822
6981
|
width: "48",
|
|
@@ -6840,11 +6999,16 @@ class Radical extends React__namespace.Component {
|
|
|
6840
6999
|
})));
|
|
6841
7000
|
}
|
|
6842
7001
|
}
|
|
6843
|
-
_defineProperty(Radical, "propTypes", {
|
|
6844
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6845
|
-
});
|
|
6846
7002
|
|
|
7003
|
+
/**
|
|
7004
|
+
* An autogenerated component that renders the FRAC iconograpy in SVG.
|
|
7005
|
+
*
|
|
7006
|
+
* Generated with: https://gist.github.com/crm416/3c7abc88e520eaed72347af240b32590.
|
|
7007
|
+
*/
|
|
6847
7008
|
class FracInclusive extends React__namespace.Component {
|
|
7009
|
+
static propTypes = {
|
|
7010
|
+
color: PropTypes__default["default"].string.isRequired
|
|
7011
|
+
};
|
|
6848
7012
|
render() {
|
|
6849
7013
|
return /*#__PURE__*/React__namespace.createElement("svg", {
|
|
6850
7014
|
width: "48",
|
|
@@ -6877,9 +7041,6 @@ class FracInclusive extends React__namespace.Component {
|
|
|
6877
7041
|
}))));
|
|
6878
7042
|
}
|
|
6879
7043
|
}
|
|
6880
|
-
_defineProperty(FracInclusive, "propTypes", {
|
|
6881
|
-
color: PropTypes__default["default"].string.isRequired
|
|
6882
|
-
});
|
|
6883
7044
|
|
|
6884
7045
|
/**
|
|
6885
7046
|
* An autogenerated component that renders the JUMP_OUT_PARENTHESES iconograpy in SVG.
|
|
@@ -7263,7 +7424,7 @@ class MultiSymbolGrid extends React__namespace.Component {
|
|
|
7263
7424
|
// some styles coercion and doesn't seem worthwhile right now.
|
|
7264
7425
|
icons.forEach(icon => {
|
|
7265
7426
|
if (icon.type !== IconType.MATH) {
|
|
7266
|
-
throw new Error(
|
|
7427
|
+
throw new Error(`Received invalid icon: type=${icon.type}, ` + `data=${icon.data}`);
|
|
7267
7428
|
}
|
|
7268
7429
|
});
|
|
7269
7430
|
if (icons.length === 1) {
|
|
@@ -7324,7 +7485,7 @@ class MultiSymbolGrid extends React__namespace.Component {
|
|
|
7324
7485
|
}))));
|
|
7325
7486
|
}
|
|
7326
7487
|
}
|
|
7327
|
-
throw new Error(
|
|
7488
|
+
throw new Error(`Invalid number of icons: ${icons.length}`);
|
|
7328
7489
|
}
|
|
7329
7490
|
}
|
|
7330
7491
|
const verticalInsetPx = 2;
|
|
@@ -7368,72 +7529,13 @@ const styles$7 = aphrodite.StyleSheet.create({
|
|
|
7368
7529
|
|
|
7369
7530
|
// eslint-disable-next-line react/no-unsafe
|
|
7370
7531
|
class KeypadButton extends React__namespace.PureComponent {
|
|
7371
|
-
|
|
7372
|
-
|
|
7373
|
-
|
|
7374
|
-
|
|
7375
|
-
|
|
7376
|
-
|
|
7377
|
-
|
|
7378
|
-
// the "initial" styles that `View` will include, as these styles are
|
|
7379
|
-
// applied to `View` components and Aphrodite will consolidate the style
|
|
7380
|
-
// object. This method must be called whenever a property that
|
|
7381
|
-
// influences the possible outcomes of `this._getFocusStyle` and
|
|
7382
|
-
// `this._getButtonStyle` changes (such as `this.buttonSizeStyle`).
|
|
7383
|
-
for (const type of KeyTypes) {
|
|
7384
|
-
aphrodite.css(View.styles.initial, ...this._getFocusStyle(type));
|
|
7385
|
-
for (const borders of Object.values(BorderStyles)) {
|
|
7386
|
-
aphrodite.css(View.styles.initial, ...this._getButtonStyle(type, borders));
|
|
7387
|
-
}
|
|
7388
|
-
}
|
|
7389
|
-
});
|
|
7390
|
-
_defineProperty(this, "_getFocusStyle", type => {
|
|
7391
|
-
let focusBackgroundStyle;
|
|
7392
|
-
if (type === "INPUT_NAVIGATION" || type === "KEYPAD_NAVIGATION") {
|
|
7393
|
-
focusBackgroundStyle = styles$6.light;
|
|
7394
|
-
} else {
|
|
7395
|
-
focusBackgroundStyle = styles$6.bright;
|
|
7396
|
-
}
|
|
7397
|
-
return [styles$6.focusBox, focusBackgroundStyle];
|
|
7398
|
-
});
|
|
7399
|
-
_defineProperty(this, "_getButtonStyle", (type, borders, style) => {
|
|
7400
|
-
// Select the appropriate style for the button.
|
|
7401
|
-
let backgroundStyle;
|
|
7402
|
-
switch (type) {
|
|
7403
|
-
case "EMPTY":
|
|
7404
|
-
backgroundStyle = styles$6.empty;
|
|
7405
|
-
break;
|
|
7406
|
-
case "MANY":
|
|
7407
|
-
case "VALUE":
|
|
7408
|
-
backgroundStyle = styles$6.value;
|
|
7409
|
-
break;
|
|
7410
|
-
case "OPERATOR":
|
|
7411
|
-
backgroundStyle = styles$6.operator;
|
|
7412
|
-
break;
|
|
7413
|
-
case "INPUT_NAVIGATION":
|
|
7414
|
-
case "KEYPAD_NAVIGATION":
|
|
7415
|
-
backgroundStyle = styles$6.control;
|
|
7416
|
-
break;
|
|
7417
|
-
case "ECHO":
|
|
7418
|
-
backgroundStyle = null;
|
|
7419
|
-
break;
|
|
7420
|
-
}
|
|
7421
|
-
const borderStyle = [];
|
|
7422
|
-
if (borders.includes(BorderDirection.LEFT)) {
|
|
7423
|
-
// @ts-expect-error TS2345
|
|
7424
|
-
borderStyle.push(styles$6.leftBorder);
|
|
7425
|
-
}
|
|
7426
|
-
if (borders.includes(BorderDirection.BOTTOM)) {
|
|
7427
|
-
// @ts-expect-error TS2345
|
|
7428
|
-
borderStyle.push(styles$6.bottomBorder);
|
|
7429
|
-
}
|
|
7430
|
-
return [styles$6.buttonBase, backgroundStyle, ...borderStyle, type === "ECHO" && styles$6.echo, this.buttonSizeStyle,
|
|
7431
|
-
// React Native allows you to set the 'style' props on user defined
|
|
7432
|
-
// components.
|
|
7433
|
-
// See: https://facebook.github.io/react-native/docs/style.html
|
|
7434
|
-
...(Array.isArray(style) ? style : [style])];
|
|
7435
|
-
});
|
|
7436
|
-
}
|
|
7532
|
+
static defaultProps = {
|
|
7533
|
+
borders: BorderStyles.ALL,
|
|
7534
|
+
childKeys: [],
|
|
7535
|
+
disabled: false,
|
|
7536
|
+
focused: false,
|
|
7537
|
+
popoverEnabled: false
|
|
7538
|
+
};
|
|
7437
7539
|
UNSAFE_componentWillMount() {
|
|
7438
7540
|
this.buttonSizeStyle = styleForButtonDimensions(this.props.heightPx, this.props.widthPx);
|
|
7439
7541
|
}
|
|
@@ -7450,6 +7552,68 @@ class KeypadButton extends React__namespace.PureComponent {
|
|
|
7450
7552
|
this._preInjectStyles();
|
|
7451
7553
|
}
|
|
7452
7554
|
}
|
|
7555
|
+
_preInjectStyles = () => {
|
|
7556
|
+
// HACK(charlie): Pre-inject all of the possible styles for the button.
|
|
7557
|
+
// This avoids a flickering effect in the echo animation whereby the
|
|
7558
|
+
// echoes vary in size as they animate. Note that we need to account for
|
|
7559
|
+
// the "initial" styles that `View` will include, as these styles are
|
|
7560
|
+
// applied to `View` components and Aphrodite will consolidate the style
|
|
7561
|
+
// object. This method must be called whenever a property that
|
|
7562
|
+
// influences the possible outcomes of `this._getFocusStyle` and
|
|
7563
|
+
// `this._getButtonStyle` changes (such as `this.buttonSizeStyle`).
|
|
7564
|
+
for (const type of KeyTypes) {
|
|
7565
|
+
aphrodite.css(View.styles.initial, ...this._getFocusStyle(type));
|
|
7566
|
+
for (const borders of Object.values(BorderStyles)) {
|
|
7567
|
+
aphrodite.css(View.styles.initial, ...this._getButtonStyle(type, borders));
|
|
7568
|
+
}
|
|
7569
|
+
}
|
|
7570
|
+
};
|
|
7571
|
+
_getFocusStyle = type => {
|
|
7572
|
+
let focusBackgroundStyle;
|
|
7573
|
+
if (type === "INPUT_NAVIGATION" || type === "KEYPAD_NAVIGATION") {
|
|
7574
|
+
focusBackgroundStyle = styles$6.light;
|
|
7575
|
+
} else {
|
|
7576
|
+
focusBackgroundStyle = styles$6.bright;
|
|
7577
|
+
}
|
|
7578
|
+
return [styles$6.focusBox, focusBackgroundStyle];
|
|
7579
|
+
};
|
|
7580
|
+
_getButtonStyle = (type, borders, style) => {
|
|
7581
|
+
// Select the appropriate style for the button.
|
|
7582
|
+
let backgroundStyle;
|
|
7583
|
+
switch (type) {
|
|
7584
|
+
case "EMPTY":
|
|
7585
|
+
backgroundStyle = styles$6.empty;
|
|
7586
|
+
break;
|
|
7587
|
+
case "MANY":
|
|
7588
|
+
case "VALUE":
|
|
7589
|
+
backgroundStyle = styles$6.value;
|
|
7590
|
+
break;
|
|
7591
|
+
case "OPERATOR":
|
|
7592
|
+
backgroundStyle = styles$6.operator;
|
|
7593
|
+
break;
|
|
7594
|
+
case "INPUT_NAVIGATION":
|
|
7595
|
+
case "KEYPAD_NAVIGATION":
|
|
7596
|
+
backgroundStyle = styles$6.control;
|
|
7597
|
+
break;
|
|
7598
|
+
case "ECHO":
|
|
7599
|
+
backgroundStyle = null;
|
|
7600
|
+
break;
|
|
7601
|
+
}
|
|
7602
|
+
const borderStyle = [];
|
|
7603
|
+
if (borders.includes(BorderDirection.LEFT)) {
|
|
7604
|
+
// @ts-expect-error TS2345
|
|
7605
|
+
borderStyle.push(styles$6.leftBorder);
|
|
7606
|
+
}
|
|
7607
|
+
if (borders.includes(BorderDirection.BOTTOM)) {
|
|
7608
|
+
// @ts-expect-error TS2345
|
|
7609
|
+
borderStyle.push(styles$6.bottomBorder);
|
|
7610
|
+
}
|
|
7611
|
+
return [styles$6.buttonBase, backgroundStyle, ...borderStyle, type === "ECHO" && styles$6.echo, this.buttonSizeStyle,
|
|
7612
|
+
// React Native allows you to set the 'style' props on user defined
|
|
7613
|
+
// components.
|
|
7614
|
+
// See: https://facebook.github.io/react-native/docs/style.html
|
|
7615
|
+
...(Array.isArray(style) ? style : [style])];
|
|
7616
|
+
};
|
|
7453
7617
|
render() {
|
|
7454
7618
|
const {
|
|
7455
7619
|
ariaLabel,
|
|
@@ -7523,13 +7687,6 @@ class KeypadButton extends React__namespace.PureComponent {
|
|
|
7523
7687
|
}
|
|
7524
7688
|
}
|
|
7525
7689
|
}
|
|
7526
|
-
_defineProperty(KeypadButton, "defaultProps", {
|
|
7527
|
-
borders: BorderStyles.ALL,
|
|
7528
|
-
childKeys: [],
|
|
7529
|
-
disabled: false,
|
|
7530
|
-
focused: false,
|
|
7531
|
-
popoverEnabled: false
|
|
7532
|
-
});
|
|
7533
7690
|
const focusInsetPx = 4;
|
|
7534
7691
|
const focusBoxZIndex = 0;
|
|
7535
7692
|
const styles$6 = aphrodite.StyleSheet.create({
|
|
@@ -7707,7 +7864,6 @@ const extractProps = keyConfig => {
|
|
|
7707
7864
|
};
|
|
7708
7865
|
};
|
|
7709
7866
|
const mapStateToProps$5 = (state, ownProps) => {
|
|
7710
|
-
var _gestures$popover;
|
|
7711
7867
|
const {
|
|
7712
7868
|
gestures
|
|
7713
7869
|
} = state;
|
|
@@ -7732,7 +7888,7 @@ const mapStateToProps$5 = (state, ownProps) => {
|
|
|
7732
7888
|
id: id,
|
|
7733
7889
|
// Add in some gesture state.
|
|
7734
7890
|
focused: gestures.focus === id,
|
|
7735
|
-
popoverEnabled:
|
|
7891
|
+
popoverEnabled: gestures.popover?.parentId === id,
|
|
7736
7892
|
// Pass down the child keys and any extracted props.
|
|
7737
7893
|
childKeys,
|
|
7738
7894
|
...extractProps(useFirstChildProps ? childKeys[0] : keyConfig)
|
|
@@ -7750,6 +7906,9 @@ var TouchableKeypadButton$1 = reactRedux.connect(mapStateToProps$5, null, null,
|
|
|
7750
7906
|
})(TouchableKeypadButton);
|
|
7751
7907
|
|
|
7752
7908
|
class ManyKeypadButton extends React__namespace.Component {
|
|
7909
|
+
static defaultProps = {
|
|
7910
|
+
keys: []
|
|
7911
|
+
};
|
|
7753
7912
|
render() {
|
|
7754
7913
|
const {
|
|
7755
7914
|
keys,
|
|
@@ -7783,9 +7942,6 @@ class ManyKeypadButton extends React__namespace.Component {
|
|
|
7783
7942
|
}
|
|
7784
7943
|
}
|
|
7785
7944
|
}
|
|
7786
|
-
_defineProperty(ManyKeypadButton, "defaultProps", {
|
|
7787
|
-
keys: []
|
|
7788
|
-
});
|
|
7789
7945
|
|
|
7790
7946
|
/**
|
|
7791
7947
|
* This file contains all of the z-index values used throughout the math-input
|
|
@@ -7838,35 +7994,32 @@ class Echo extends React__namespace.Component {
|
|
|
7838
7994
|
}
|
|
7839
7995
|
}
|
|
7840
7996
|
class EchoManager extends React__namespace.Component {
|
|
7841
|
-
|
|
7842
|
-
|
|
7843
|
-
|
|
7844
|
-
|
|
7845
|
-
|
|
7846
|
-
|
|
7847
|
-
|
|
7848
|
-
|
|
7849
|
-
|
|
7850
|
-
|
|
7851
|
-
|
|
7852
|
-
|
|
7853
|
-
|
|
7854
|
-
|
|
7855
|
-
|
|
7856
|
-
|
|
7857
|
-
|
|
7858
|
-
|
|
7859
|
-
|
|
7860
|
-
|
|
7861
|
-
|
|
7862
|
-
|
|
7863
|
-
|
|
7864
|
-
|
|
7865
|
-
|
|
7866
|
-
|
|
7867
|
-
};
|
|
7868
|
-
});
|
|
7869
|
-
}
|
|
7997
|
+
_animationConfigForType = animationType => {
|
|
7998
|
+
// NOTE(charlie): These must be kept in sync with the transition
|
|
7999
|
+
// durations and classnames specified in echo.css.
|
|
8000
|
+
let animationDurationMs;
|
|
8001
|
+
let animationTransitionName;
|
|
8002
|
+
switch (animationType) {
|
|
8003
|
+
case EchoAnimationType.SLIDE_AND_FADE:
|
|
8004
|
+
animationDurationMs = 400;
|
|
8005
|
+
animationTransitionName = "echo-slide-and-fade";
|
|
8006
|
+
break;
|
|
8007
|
+
case EchoAnimationType.FADE_ONLY:
|
|
8008
|
+
animationDurationMs = 300;
|
|
8009
|
+
animationTransitionName = "echo-fade-only";
|
|
8010
|
+
break;
|
|
8011
|
+
case EchoAnimationType.LONG_FADE_ONLY:
|
|
8012
|
+
animationDurationMs = 400;
|
|
8013
|
+
animationTransitionName = "echo-long-fade-only";
|
|
8014
|
+
break;
|
|
8015
|
+
default:
|
|
8016
|
+
throw new Error(`Invalid echo animation type: ${animationType}`);
|
|
8017
|
+
}
|
|
8018
|
+
return {
|
|
8019
|
+
animationDurationMs,
|
|
8020
|
+
animationTransitionName
|
|
8021
|
+
};
|
|
8022
|
+
};
|
|
7870
8023
|
render() {
|
|
7871
8024
|
const {
|
|
7872
8025
|
echoes,
|
|
@@ -7904,7 +8057,7 @@ class EchoManager extends React__namespace.Component {
|
|
|
7904
8057
|
key: animationId
|
|
7905
8058
|
}, /*#__PURE__*/React__namespace.createElement(Echo, _extends({
|
|
7906
8059
|
animationDurationMs: animationDurationMs,
|
|
7907
|
-
onAnimationFinish: () => onAnimationFinish
|
|
8060
|
+
onAnimationFinish: () => onAnimationFinish?.(animationId)
|
|
7908
8061
|
}, echo)));
|
|
7909
8062
|
}));
|
|
7910
8063
|
}));
|
|
@@ -7999,7 +8152,6 @@ class PopoverManager extends React__namespace.Component {
|
|
|
7999
8152
|
// naming convention: verb + noun
|
|
8000
8153
|
// the noun should be one of the other properties in the object that's
|
|
8001
8154
|
// being dispatched
|
|
8002
|
-
|
|
8003
8155
|
const dismissKeypad = () => {
|
|
8004
8156
|
return {
|
|
8005
8157
|
type: "DismissKeypad"
|
|
@@ -8069,43 +8221,12 @@ const pressKey = (key, initialBounds, inPopover) => {
|
|
|
8069
8221
|
};
|
|
8070
8222
|
};
|
|
8071
8223
|
|
|
8224
|
+
/**
|
|
8225
|
+
* A keypad component that acts as a container for rows or columns of buttons,
|
|
8226
|
+
* and manages the rendering of echo animations on top of those buttons.
|
|
8227
|
+
*/
|
|
8072
8228
|
// eslint-disable-next-line react/no-unsafe
|
|
8073
8229
|
class Keypad extends React__namespace.Component {
|
|
8074
|
-
constructor() {
|
|
8075
|
-
super(...arguments);
|
|
8076
|
-
_defineProperty(this, "_isMounted", void 0);
|
|
8077
|
-
_defineProperty(this, "_resizeTimeout", void 0);
|
|
8078
|
-
_defineProperty(this, "_container", void 0);
|
|
8079
|
-
_defineProperty(this, "_computeContainer", () => {
|
|
8080
|
-
const domNode = ReactDOM__default["default"].findDOMNode(this);
|
|
8081
|
-
this._container = domNode.getBoundingClientRect();
|
|
8082
|
-
});
|
|
8083
|
-
_defineProperty(this, "_updateSizeAndPosition", () => {
|
|
8084
|
-
// Mark the container for recalculation next time the keypad is
|
|
8085
|
-
// opened.
|
|
8086
|
-
// TODO(charlie): Since we're not recalculating the container
|
|
8087
|
-
// immediately, if you were to resize the page while a popover were
|
|
8088
|
-
// active, you'd likely get unexpected behavior. This seems very
|
|
8089
|
-
// difficult to do and, as such, incredibly unlikely, but we may
|
|
8090
|
-
// want to reconsider the caching here.
|
|
8091
|
-
this._container = null;
|
|
8092
|
-
});
|
|
8093
|
-
_defineProperty(this, "_onResize", () => {
|
|
8094
|
-
// Whenever the page resizes, we need to recompute the container's
|
|
8095
|
-
// bounding box. This is the only time that the bounding box can change.
|
|
8096
|
-
|
|
8097
|
-
// Throttle resize events -- taken from:
|
|
8098
|
-
// https://developer.mozilla.org/en-US/docs/Web/Events/resize
|
|
8099
|
-
if (this._resizeTimeout == null) {
|
|
8100
|
-
this._resizeTimeout = window.setTimeout(() => {
|
|
8101
|
-
this._resizeTimeout = null;
|
|
8102
|
-
if (this._isMounted) {
|
|
8103
|
-
this._updateSizeAndPosition();
|
|
8104
|
-
}
|
|
8105
|
-
}, 66);
|
|
8106
|
-
}
|
|
8107
|
-
});
|
|
8108
|
-
}
|
|
8109
8230
|
componentDidMount() {
|
|
8110
8231
|
this._isMounted = true;
|
|
8111
8232
|
window.addEventListener("resize", this._onResize);
|
|
@@ -8120,6 +8241,35 @@ class Keypad extends React__namespace.Component {
|
|
|
8120
8241
|
this._isMounted = false;
|
|
8121
8242
|
window.removeEventListener("resize", this._onResize);
|
|
8122
8243
|
}
|
|
8244
|
+
_computeContainer = () => {
|
|
8245
|
+
const domNode = ReactDOM__default["default"].findDOMNode(this);
|
|
8246
|
+
this._container = domNode.getBoundingClientRect();
|
|
8247
|
+
};
|
|
8248
|
+
_updateSizeAndPosition = () => {
|
|
8249
|
+
// Mark the container for recalculation next time the keypad is
|
|
8250
|
+
// opened.
|
|
8251
|
+
// TODO(charlie): Since we're not recalculating the container
|
|
8252
|
+
// immediately, if you were to resize the page while a popover were
|
|
8253
|
+
// active, you'd likely get unexpected behavior. This seems very
|
|
8254
|
+
// difficult to do and, as such, incredibly unlikely, but we may
|
|
8255
|
+
// want to reconsider the caching here.
|
|
8256
|
+
this._container = null;
|
|
8257
|
+
};
|
|
8258
|
+
_onResize = () => {
|
|
8259
|
+
// Whenever the page resizes, we need to recompute the container's
|
|
8260
|
+
// bounding box. This is the only time that the bounding box can change.
|
|
8261
|
+
|
|
8262
|
+
// Throttle resize events -- taken from:
|
|
8263
|
+
// https://developer.mozilla.org/en-US/docs/Web/Events/resize
|
|
8264
|
+
if (this._resizeTimeout == null) {
|
|
8265
|
+
this._resizeTimeout = window.setTimeout(() => {
|
|
8266
|
+
this._resizeTimeout = null;
|
|
8267
|
+
if (this._isMounted) {
|
|
8268
|
+
this._updateSizeAndPosition();
|
|
8269
|
+
}
|
|
8270
|
+
}, 66);
|
|
8271
|
+
}
|
|
8272
|
+
};
|
|
8123
8273
|
render() {
|
|
8124
8274
|
const {
|
|
8125
8275
|
children,
|
|
@@ -8197,18 +8347,18 @@ var Keypad$1 = reactRedux.connect(mapStateToProps$4, mapDispatchToProps$1, null,
|
|
|
8197
8347
|
forwardRef: true
|
|
8198
8348
|
})(Keypad);
|
|
8199
8349
|
|
|
8350
|
+
/**
|
|
8351
|
+
* A keypad with two pages of keys.
|
|
8352
|
+
*/
|
|
8200
8353
|
const {
|
|
8201
8354
|
column: column$2,
|
|
8202
8355
|
row: row$4,
|
|
8203
8356
|
fullWidth: fullWidth$2
|
|
8204
8357
|
} = Styles;
|
|
8205
8358
|
class TwoPageKeypad extends React__namespace.Component {
|
|
8206
|
-
|
|
8207
|
-
|
|
8208
|
-
|
|
8209
|
-
selectedPage: "Numbers"
|
|
8210
|
-
});
|
|
8211
|
-
}
|
|
8359
|
+
state = {
|
|
8360
|
+
selectedPage: "Numbers"
|
|
8361
|
+
};
|
|
8212
8362
|
render() {
|
|
8213
8363
|
const {
|
|
8214
8364
|
leftPage,
|
|
@@ -8253,16 +8403,16 @@ const styles$3 = aphrodite.StyleSheet.create({
|
|
|
8253
8403
|
backgroundColor: offBlack16
|
|
8254
8404
|
},
|
|
8255
8405
|
borderTop: {
|
|
8256
|
-
borderTop:
|
|
8406
|
+
borderTop: `${innerBorderWidthPx}px ${innerBorderStyle} ` + `${innerBorderColor}`
|
|
8257
8407
|
},
|
|
8258
8408
|
borderLeft: {
|
|
8259
|
-
borderLeft:
|
|
8409
|
+
borderLeft: `${innerBorderWidthPx}px ${innerBorderStyle} ` + `${innerBorderColor}`,
|
|
8260
8410
|
boxSizing: "content-box"
|
|
8261
8411
|
},
|
|
8262
8412
|
tabbar: {
|
|
8263
8413
|
background: Color__default["default"].offWhite,
|
|
8264
|
-
borderTop:
|
|
8265
|
-
borderBottom:
|
|
8414
|
+
borderTop: `1px solid ${Color__default["default"].offBlack50}`,
|
|
8415
|
+
borderBottom: `1px solid ${Color__default["default"].offBlack50}`
|
|
8266
8416
|
}
|
|
8267
8417
|
});
|
|
8268
8418
|
const mapStateToProps$3 = state => {
|
|
@@ -8498,9 +8648,8 @@ const styles$2 = aphrodite.StyleSheet.create({
|
|
|
8498
8648
|
}
|
|
8499
8649
|
});
|
|
8500
8650
|
const mapStateToProps$2 = state => {
|
|
8501
|
-
var _state$input$cursor;
|
|
8502
8651
|
return {
|
|
8503
|
-
cursorContext:
|
|
8652
|
+
cursorContext: state.input.cursor?.context,
|
|
8504
8653
|
dynamicJumpOut: !state.layout.navigationPadEnabled
|
|
8505
8654
|
};
|
|
8506
8655
|
};
|
|
@@ -8631,9 +8780,8 @@ class FractionKeypad extends React__namespace.Component {
|
|
|
8631
8780
|
}
|
|
8632
8781
|
}
|
|
8633
8782
|
const mapStateToProps$1 = state => {
|
|
8634
|
-
var _state$input$cursor;
|
|
8635
8783
|
return {
|
|
8636
|
-
cursorContext:
|
|
8784
|
+
cursorContext: state.input.cursor?.context,
|
|
8637
8785
|
dynamicJumpOut: !state.layout.navigationPadEnabled
|
|
8638
8786
|
};
|
|
8639
8787
|
};
|
|
@@ -8750,71 +8898,12 @@ const {
|
|
|
8750
8898
|
} = Styles;
|
|
8751
8899
|
// eslint-disable-next-line react/no-unsafe
|
|
8752
8900
|
class KeypadContainer extends React__namespace.Component {
|
|
8753
|
-
|
|
8754
|
-
|
|
8755
|
-
|
|
8756
|
-
|
|
8757
|
-
|
|
8758
|
-
|
|
8759
|
-
_defineProperty(this, "state", {
|
|
8760
|
-
hasBeenActivated: false,
|
|
8761
|
-
viewportWidth: "100vw"
|
|
8762
|
-
});
|
|
8763
|
-
_defineProperty(this, "_throttleResizeHandler", () => {
|
|
8764
|
-
// Throttle the resize callbacks.
|
|
8765
|
-
// https://developer.mozilla.org/en-US/docs/Web/Events/resize
|
|
8766
|
-
if (this._resizeTimeout == null) {
|
|
8767
|
-
this._resizeTimeout = window.setTimeout(() => {
|
|
8768
|
-
this._resizeTimeout = null;
|
|
8769
|
-
this._onResize();
|
|
8770
|
-
}, 66);
|
|
8771
|
-
}
|
|
8772
|
-
});
|
|
8773
|
-
_defineProperty(this, "_onResize", () => {
|
|
8774
|
-
var _this$_containerRef$c, _this$_containerRef$c2, _this$props$onPageSiz, _this$props;
|
|
8775
|
-
// Whenever the page resizes, we need to force an update, as the button
|
|
8776
|
-
// heights and keypad width are computed based on horizontal space.
|
|
8777
|
-
this.setState({
|
|
8778
|
-
viewportWidth: window.innerWidth
|
|
8779
|
-
});
|
|
8780
|
-
const containerWidth = ((_this$_containerRef$c = this._containerRef.current) === null || _this$_containerRef$c === void 0 ? void 0 : _this$_containerRef$c.clientWidth) || 0;
|
|
8781
|
-
const containerHeight = ((_this$_containerRef$c2 = this._containerRef.current) === null || _this$_containerRef$c2 === void 0 ? void 0 : _this$_containerRef$c2.clientHeight) || 0;
|
|
8782
|
-
(_this$props$onPageSiz = (_this$props = this.props).onPageSizeChange) === null || _this$props$onPageSiz === void 0 ? void 0 : _this$props$onPageSiz.call(_this$props, window.innerWidth, window.innerHeight, containerWidth, containerHeight);
|
|
8783
|
-
});
|
|
8784
|
-
_defineProperty(this, "renderKeypad", () => {
|
|
8785
|
-
const {
|
|
8786
|
-
extraKeys,
|
|
8787
|
-
keypadType,
|
|
8788
|
-
layoutMode,
|
|
8789
|
-
navigationPadEnabled
|
|
8790
|
-
} = this.props;
|
|
8791
|
-
const keypadProps = {
|
|
8792
|
-
extraKeys,
|
|
8793
|
-
// HACK(charlie): In order to properly round the corners of the
|
|
8794
|
-
// compact keypad, we need to instruct some of our child views to
|
|
8795
|
-
// crop themselves. At least we're colocating all the layout
|
|
8796
|
-
// information in this component, though.
|
|
8797
|
-
roundTopLeft: layoutMode === LayoutMode.COMPACT && !navigationPadEnabled,
|
|
8798
|
-
roundTopRight: layoutMode === LayoutMode.COMPACT
|
|
8799
|
-
};
|
|
8800
|
-
|
|
8801
|
-
// Select the appropriate keyboard given the type.
|
|
8802
|
-
// TODO(charlie): In the future, we might want to move towards a
|
|
8803
|
-
// data-driven approach to defining keyboard layouts, and have a
|
|
8804
|
-
// generic keyboard that takes some "keyboard data" and renders it.
|
|
8805
|
-
// However, the keyboards differ pretty heavily right now and it's not
|
|
8806
|
-
// clear what that format would look like exactly. Plus, there aren't
|
|
8807
|
-
// very many of them. So to keep us moving, we'll just hardcode.
|
|
8808
|
-
switch (keypadType) {
|
|
8809
|
-
case KeypadType.FRACTION:
|
|
8810
|
-
return /*#__PURE__*/React__namespace.createElement(FractionKeypad$1, keypadProps);
|
|
8811
|
-
case KeypadType.EXPRESSION:
|
|
8812
|
-
return /*#__PURE__*/React__namespace.createElement(ExpressionKeypad$1, keypadProps);
|
|
8813
|
-
default:
|
|
8814
|
-
throw new Error("Invalid keypad type: " + keypadType);
|
|
8815
|
-
}
|
|
8816
|
-
});
|
|
8817
|
-
}
|
|
8901
|
+
_containerRef = /*#__PURE__*/React__namespace.createRef();
|
|
8902
|
+
_containerResizeObserver = null;
|
|
8903
|
+
state = {
|
|
8904
|
+
hasBeenActivated: false,
|
|
8905
|
+
viewportWidth: "100vw"
|
|
8906
|
+
};
|
|
8818
8907
|
UNSAFE_componentWillMount() {
|
|
8819
8908
|
if (this.props.active) {
|
|
8820
8909
|
this.setState({
|
|
@@ -8852,11 +8941,63 @@ class KeypadContainer extends React__namespace.Component {
|
|
|
8852
8941
|
}
|
|
8853
8942
|
}
|
|
8854
8943
|
componentWillUnmount() {
|
|
8855
|
-
var _this$_containerResiz;
|
|
8856
8944
|
window.removeEventListener("resize", this._throttleResizeHandler);
|
|
8857
8945
|
window.removeEventListener("orientationchange", this._throttleResizeHandler);
|
|
8858
|
-
|
|
8859
|
-
}
|
|
8946
|
+
this._containerResizeObserver?.disconnect();
|
|
8947
|
+
}
|
|
8948
|
+
_throttleResizeHandler = () => {
|
|
8949
|
+
// Throttle the resize callbacks.
|
|
8950
|
+
// https://developer.mozilla.org/en-US/docs/Web/Events/resize
|
|
8951
|
+
if (this._resizeTimeout == null) {
|
|
8952
|
+
this._resizeTimeout = window.setTimeout(() => {
|
|
8953
|
+
this._resizeTimeout = null;
|
|
8954
|
+
this._onResize();
|
|
8955
|
+
}, 66);
|
|
8956
|
+
}
|
|
8957
|
+
};
|
|
8958
|
+
_onResize = () => {
|
|
8959
|
+
// Whenever the page resizes, we need to force an update, as the button
|
|
8960
|
+
// heights and keypad width are computed based on horizontal space.
|
|
8961
|
+
this.setState({
|
|
8962
|
+
viewportWidth: window.innerWidth
|
|
8963
|
+
});
|
|
8964
|
+
const containerWidth = this._containerRef.current?.clientWidth || 0;
|
|
8965
|
+
const containerHeight = this._containerRef.current?.clientHeight || 0;
|
|
8966
|
+
this.props.onPageSizeChange?.(window.innerWidth, window.innerHeight, containerWidth, containerHeight);
|
|
8967
|
+
};
|
|
8968
|
+
renderKeypad = () => {
|
|
8969
|
+
const {
|
|
8970
|
+
extraKeys,
|
|
8971
|
+
keypadType,
|
|
8972
|
+
layoutMode,
|
|
8973
|
+
navigationPadEnabled
|
|
8974
|
+
} = this.props;
|
|
8975
|
+
const keypadProps = {
|
|
8976
|
+
extraKeys,
|
|
8977
|
+
// HACK(charlie): In order to properly round the corners of the
|
|
8978
|
+
// compact keypad, we need to instruct some of our child views to
|
|
8979
|
+
// crop themselves. At least we're colocating all the layout
|
|
8980
|
+
// information in this component, though.
|
|
8981
|
+
roundTopLeft: layoutMode === LayoutMode.COMPACT && !navigationPadEnabled,
|
|
8982
|
+
roundTopRight: layoutMode === LayoutMode.COMPACT
|
|
8983
|
+
};
|
|
8984
|
+
|
|
8985
|
+
// Select the appropriate keyboard given the type.
|
|
8986
|
+
// TODO(charlie): In the future, we might want to move towards a
|
|
8987
|
+
// data-driven approach to defining keyboard layouts, and have a
|
|
8988
|
+
// generic keyboard that takes some "keyboard data" and renders it.
|
|
8989
|
+
// However, the keyboards differ pretty heavily right now and it's not
|
|
8990
|
+
// clear what that format would look like exactly. Plus, there aren't
|
|
8991
|
+
// very many of them. So to keep us moving, we'll just hardcode.
|
|
8992
|
+
switch (keypadType) {
|
|
8993
|
+
case KeypadType.FRACTION:
|
|
8994
|
+
return /*#__PURE__*/React__namespace.createElement(FractionKeypad$1, keypadProps);
|
|
8995
|
+
case KeypadType.EXPRESSION:
|
|
8996
|
+
return /*#__PURE__*/React__namespace.createElement(ExpressionKeypad$1, keypadProps);
|
|
8997
|
+
default:
|
|
8998
|
+
throw new Error("Invalid keypad type: " + keypadType);
|
|
8999
|
+
}
|
|
9000
|
+
};
|
|
8860
9001
|
render() {
|
|
8861
9002
|
const {
|
|
8862
9003
|
active,
|
|
@@ -8916,7 +9057,7 @@ const styles = aphrodite.StyleSheet.create({
|
|
|
8916
9057
|
left: 0,
|
|
8917
9058
|
right: 0,
|
|
8918
9059
|
position: "fixed",
|
|
8919
|
-
transition:
|
|
9060
|
+
transition: `${keypadAnimationDurationMs}ms ease-out`,
|
|
8920
9061
|
transitionProperty: "transform",
|
|
8921
9062
|
zIndex: keypad
|
|
8922
9063
|
},
|
|
@@ -8937,7 +9078,7 @@ const styles = aphrodite.StyleSheet.create({
|
|
|
8937
9078
|
},
|
|
8938
9079
|
navigationPadContainer: {
|
|
8939
9080
|
// Add a separator between the navigation pad and the keypad.
|
|
8940
|
-
borderRight:
|
|
9081
|
+
borderRight: `${innerBorderWidthPx}px ${innerBorderStyle} ` + `${innerBorderColor}`,
|
|
8941
9082
|
boxSizing: "content-box"
|
|
8942
9083
|
},
|
|
8943
9084
|
// Defer to the navigation pad, such that the navigation pad is always
|
|
@@ -8992,10 +9133,7 @@ var KeypadContainer$1 = reactRedux.connect(mapStateToProps, mapDispatchToProps,
|
|
|
8992
9133
|
* It is entirely ignorant of the existence of popovers and the positions of
|
|
8993
9134
|
* DOM nodes, operating solely on IDs. The state machine does accommodate for
|
|
8994
9135
|
* multi-touch interactions, tracking gesture state on a per-touch basis.
|
|
8995
|
-
*/
|
|
8996
|
-
|
|
8997
|
-
// exported for tests
|
|
8998
|
-
|
|
9136
|
+
*/ // exported for tests
|
|
8999
9137
|
const defaultOptions = {
|
|
9000
9138
|
longPressWaitTimeMs: 50,
|
|
9001
9139
|
swipeThresholdPx: 20,
|
|
@@ -9003,12 +9141,6 @@ const defaultOptions = {
|
|
|
9003
9141
|
};
|
|
9004
9142
|
class GestureStateMachine {
|
|
9005
9143
|
constructor(handlers, options, swipeDisabledNodeIds, multiPressableKeys) {
|
|
9006
|
-
_defineProperty(this, "handlers", void 0);
|
|
9007
|
-
_defineProperty(this, "options", void 0);
|
|
9008
|
-
_defineProperty(this, "swipeDisabledNodeIds", void 0);
|
|
9009
|
-
_defineProperty(this, "multiPressableKeys", void 0);
|
|
9010
|
-
_defineProperty(this, "touchState", void 0);
|
|
9011
|
-
_defineProperty(this, "swipeState", void 0);
|
|
9012
9144
|
this.handlers = handlers;
|
|
9013
9145
|
this.options = {
|
|
9014
9146
|
...defaultOptions,
|
|
@@ -9180,8 +9312,7 @@ class GestureStateMachine {
|
|
|
9180
9312
|
// Only respect the finger that started a swipe. Any other lingering
|
|
9181
9313
|
// gestures are ignored.
|
|
9182
9314
|
if (this.swipeState.touchId === touchId) {
|
|
9183
|
-
|
|
9184
|
-
(_this$handlers$onSwip = (_this$handlers = this.handlers).onSwipeChange) === null || _this$handlers$onSwip === void 0 ? void 0 : _this$handlers$onSwip.call(_this$handlers, pageX - this.swipeState.startX);
|
|
9315
|
+
this.handlers.onSwipeChange?.(pageX - this.swipeState.startX);
|
|
9185
9316
|
}
|
|
9186
9317
|
} else if (this.touchState[touchId]) {
|
|
9187
9318
|
// It could be touch events started outside the keypad and
|
|
@@ -9194,7 +9325,6 @@ class GestureStateMachine {
|
|
|
9194
9325
|
const dx = pageX - startX;
|
|
9195
9326
|
const shouldBeginSwiping = swipeEnabled && !swipeLocked && Math.abs(dx) > this.options.swipeThresholdPx;
|
|
9196
9327
|
if (shouldBeginSwiping) {
|
|
9197
|
-
var _this$handlers$onSwip2, _this$handlers2;
|
|
9198
9328
|
this._onSwipeStart();
|
|
9199
9329
|
|
|
9200
9330
|
// Trigger the swipe.
|
|
@@ -9202,7 +9332,7 @@ class GestureStateMachine {
|
|
|
9202
9332
|
touchId,
|
|
9203
9333
|
startX
|
|
9204
9334
|
};
|
|
9205
|
-
|
|
9335
|
+
this.handlers.onSwipeChange?.(pageX - this.swipeState.startX);
|
|
9206
9336
|
} else {
|
|
9207
9337
|
const id = getId();
|
|
9208
9338
|
if (id !== activeNodeId) {
|
|
@@ -9225,8 +9355,7 @@ class GestureStateMachine {
|
|
|
9225
9355
|
// Only respect the finger that started a swipe. Any other lingering
|
|
9226
9356
|
// gestures are ignored.
|
|
9227
9357
|
if (this.swipeState.touchId === touchId) {
|
|
9228
|
-
|
|
9229
|
-
(_this$handlers$onSwip3 = (_this$handlers3 = this.handlers).onSwipeEnd) === null || _this$handlers$onSwip3 === void 0 ? void 0 : _this$handlers$onSwip3.call(_this$handlers3, pageX - this.swipeState.startX);
|
|
9358
|
+
this.handlers.onSwipeEnd?.(pageX - this.swipeState.startX);
|
|
9230
9359
|
this.swipeState = null;
|
|
9231
9360
|
}
|
|
9232
9361
|
} else if (this.touchState[touchId]) {
|
|
@@ -9260,8 +9389,7 @@ class GestureStateMachine {
|
|
|
9260
9389
|
// displacement.
|
|
9261
9390
|
if (this.swipeState) {
|
|
9262
9391
|
if (this.swipeState.touchId === touchId) {
|
|
9263
|
-
|
|
9264
|
-
(_this$handlers$onSwip4 = (_this$handlers4 = this.handlers).onSwipeEnd) === null || _this$handlers$onSwip4 === void 0 ? void 0 : _this$handlers$onSwip4.call(_this$handlers4, 0);
|
|
9392
|
+
this.handlers.onSwipeEnd?.(0);
|
|
9265
9393
|
this.swipeState = null;
|
|
9266
9394
|
}
|
|
9267
9395
|
} else if (this.touchState[touchId]) {
|
|
@@ -9284,9 +9412,6 @@ class GestureStateMachine {
|
|
|
9284
9412
|
|
|
9285
9413
|
class NodeManager {
|
|
9286
9414
|
constructor() {
|
|
9287
|
-
_defineProperty(this, "_nodesById", void 0);
|
|
9288
|
-
_defineProperty(this, "_orderedIds", void 0);
|
|
9289
|
-
_defineProperty(this, "_cachedBoundingBoxesById", void 0);
|
|
9290
9415
|
// A mapping from IDs to DOM nodes.
|
|
9291
9416
|
this._nodesById = {};
|
|
9292
9417
|
|
|
@@ -9399,9 +9524,6 @@ class NodeManager {
|
|
|
9399
9524
|
|
|
9400
9525
|
class PopoverStateMachine {
|
|
9401
9526
|
constructor(handlers) {
|
|
9402
|
-
_defineProperty(this, "handlers", void 0);
|
|
9403
|
-
_defineProperty(this, "popovers", void 0);
|
|
9404
|
-
_defineProperty(this, "activePopover", void 0);
|
|
9405
9527
|
this.handlers = handlers;
|
|
9406
9528
|
this.activePopover = null;
|
|
9407
9529
|
this.popovers = {};
|
|
@@ -9561,16 +9683,16 @@ class PopoverStateMachine {
|
|
|
9561
9683
|
}
|
|
9562
9684
|
}
|
|
9563
9685
|
|
|
9686
|
+
/**
|
|
9687
|
+
* A high-level manager for our gesture system. In particular, this class
|
|
9688
|
+
* connects our various bits of logic for managing gestures and interactions,
|
|
9689
|
+
* and links them together.
|
|
9690
|
+
*/
|
|
9564
9691
|
const coordsForEvent = evt => {
|
|
9565
9692
|
return [evt.changedTouches[0].clientX, evt.changedTouches[0].clientY];
|
|
9566
9693
|
};
|
|
9567
9694
|
class GestureManager {
|
|
9568
9695
|
constructor(options, handlers, disabledSwipeKeys, multiPressableKeys) {
|
|
9569
|
-
_defineProperty(this, "swipeEnabled", void 0);
|
|
9570
|
-
_defineProperty(this, "trackEvents", void 0);
|
|
9571
|
-
_defineProperty(this, "nodeManager", void 0);
|
|
9572
|
-
_defineProperty(this, "popoverStateMachine", void 0);
|
|
9573
|
-
_defineProperty(this, "gestureStateMachine", void 0);
|
|
9574
9696
|
const {
|
|
9575
9697
|
swipeEnabled
|
|
9576
9698
|
} = options;
|
|
@@ -9811,13 +9933,12 @@ const inputReducer = function () {
|
|
|
9811
9933
|
case "PressKey":
|
|
9812
9934
|
const keyConfig = KeyConfigs[action.key];
|
|
9813
9935
|
if (keyConfig.type !== "KEYPAD_NAVIGATION") {
|
|
9814
|
-
var _state$keyHandler;
|
|
9815
9936
|
// This is probably an anti-pattern but it works for the
|
|
9816
9937
|
// case where we don't actually control the state but we
|
|
9817
9938
|
// still want to communicate with the other object
|
|
9818
9939
|
return {
|
|
9819
9940
|
...state,
|
|
9820
|
-
cursor:
|
|
9941
|
+
cursor: state.keyHandler?.(keyConfig.id)
|
|
9821
9942
|
};
|
|
9822
9943
|
}
|
|
9823
9944
|
|
|
@@ -10186,66 +10307,6 @@ const createStore = () => {
|
|
|
10186
10307
|
class ProvidedKeypad extends React__namespace.Component {
|
|
10187
10308
|
constructor(props) {
|
|
10188
10309
|
super(props);
|
|
10189
|
-
_defineProperty(this, "store", void 0);
|
|
10190
|
-
_defineProperty(this, "activate", () => {
|
|
10191
|
-
this.props.setKeypadActive(true);
|
|
10192
|
-
});
|
|
10193
|
-
_defineProperty(this, "dismiss", () => {
|
|
10194
|
-
this.props.setKeypadActive(false);
|
|
10195
|
-
});
|
|
10196
|
-
_defineProperty(this, "configure", (configuration, cb) => {
|
|
10197
|
-
this.store.dispatch(configureKeypad(configuration));
|
|
10198
|
-
|
|
10199
|
-
// HACK(charlie): In Perseus, triggering a focus causes the keypad to
|
|
10200
|
-
// animate into view and re-configure. We'd like to provide the option
|
|
10201
|
-
// to re-render the re-configured keypad before animating it into view,
|
|
10202
|
-
// to avoid jank in the animation. As such, we support passing a
|
|
10203
|
-
// callback into `configureKeypad`. However, implementing this properly
|
|
10204
|
-
// would require middleware, etc., so we just hack it on with
|
|
10205
|
-
// `setTimeout` for now.
|
|
10206
|
-
setTimeout(() => cb && cb());
|
|
10207
|
-
});
|
|
10208
|
-
_defineProperty(this, "setCursor", cursor => {
|
|
10209
|
-
this.store.dispatch(setCursor(cursor));
|
|
10210
|
-
});
|
|
10211
|
-
_defineProperty(this, "setKeyHandler", keyHandler => {
|
|
10212
|
-
this.store.dispatch(setKeyHandler(keyHandler));
|
|
10213
|
-
});
|
|
10214
|
-
_defineProperty(this, "getDOMNode", () => {
|
|
10215
|
-
return ReactDOM__default["default"].findDOMNode(this);
|
|
10216
|
-
});
|
|
10217
|
-
_defineProperty(this, "onElementMounted", element => {
|
|
10218
|
-
var _this$props$onElement, _this$props;
|
|
10219
|
-
this.props.onAnalyticsEvent({
|
|
10220
|
-
type: "math-input:keypad-opened",
|
|
10221
|
-
payload: {
|
|
10222
|
-
virtualKeypadVersion: "MATH_INPUT_KEYPAD_V1"
|
|
10223
|
-
}
|
|
10224
|
-
});
|
|
10225
|
-
|
|
10226
|
-
// Append the dispatch methods that we want to expose
|
|
10227
|
-
// externally to the returned React element.
|
|
10228
|
-
const elementWithDispatchMethods = {
|
|
10229
|
-
...element,
|
|
10230
|
-
activate: this.activate,
|
|
10231
|
-
dismiss: this.dismiss,
|
|
10232
|
-
configure: this.configure,
|
|
10233
|
-
setCursor: this.setCursor,
|
|
10234
|
-
setKeyHandler: this.setKeyHandler,
|
|
10235
|
-
getDOMNode: this.getDOMNode
|
|
10236
|
-
};
|
|
10237
|
-
(_this$props$onElement = (_this$props = this.props).onElementMounted) === null || _this$props$onElement === void 0 ? void 0 : _this$props$onElement.call(_this$props, elementWithDispatchMethods);
|
|
10238
|
-
});
|
|
10239
|
-
_defineProperty(this, "onDismiss", () => {
|
|
10240
|
-
var _this$props$onDismiss, _this$props2;
|
|
10241
|
-
this.props.onAnalyticsEvent({
|
|
10242
|
-
type: "math-input:keypad-closed",
|
|
10243
|
-
payload: {
|
|
10244
|
-
virtualKeypadVersion: "MATH_INPUT_KEYPAD_V1"
|
|
10245
|
-
}
|
|
10246
|
-
});
|
|
10247
|
-
(_this$props$onDismiss = (_this$props2 = this.props).onDismiss) === null || _this$props$onDismiss === void 0 ? void 0 : _this$props$onDismiss.call(_this$props2);
|
|
10248
|
-
});
|
|
10249
10310
|
this.store = createStore();
|
|
10250
10311
|
}
|
|
10251
10312
|
componentDidUpdate(prevProps) {
|
|
@@ -10256,6 +10317,63 @@ class ProvidedKeypad extends React__namespace.Component {
|
|
|
10256
10317
|
this.store.dispatch(dismissKeypad());
|
|
10257
10318
|
}
|
|
10258
10319
|
}
|
|
10320
|
+
activate = () => {
|
|
10321
|
+
this.props.setKeypadActive(true);
|
|
10322
|
+
};
|
|
10323
|
+
dismiss = () => {
|
|
10324
|
+
this.props.setKeypadActive(false);
|
|
10325
|
+
};
|
|
10326
|
+
configure = (configuration, cb) => {
|
|
10327
|
+
this.store.dispatch(configureKeypad(configuration));
|
|
10328
|
+
|
|
10329
|
+
// HACK(charlie): In Perseus, triggering a focus causes the keypad to
|
|
10330
|
+
// animate into view and re-configure. We'd like to provide the option
|
|
10331
|
+
// to re-render the re-configured keypad before animating it into view,
|
|
10332
|
+
// to avoid jank in the animation. As such, we support passing a
|
|
10333
|
+
// callback into `configureKeypad`. However, implementing this properly
|
|
10334
|
+
// would require middleware, etc., so we just hack it on with
|
|
10335
|
+
// `setTimeout` for now.
|
|
10336
|
+
setTimeout(() => cb && cb());
|
|
10337
|
+
};
|
|
10338
|
+
setCursor = cursor => {
|
|
10339
|
+
this.store.dispatch(setCursor(cursor));
|
|
10340
|
+
};
|
|
10341
|
+
setKeyHandler = keyHandler => {
|
|
10342
|
+
this.store.dispatch(setKeyHandler(keyHandler));
|
|
10343
|
+
};
|
|
10344
|
+
getDOMNode = () => {
|
|
10345
|
+
return ReactDOM__default["default"].findDOMNode(this);
|
|
10346
|
+
};
|
|
10347
|
+
onElementMounted = element => {
|
|
10348
|
+
this.props.onAnalyticsEvent({
|
|
10349
|
+
type: "math-input:keypad-opened",
|
|
10350
|
+
payload: {
|
|
10351
|
+
virtualKeypadVersion: "MATH_INPUT_KEYPAD_V1"
|
|
10352
|
+
}
|
|
10353
|
+
});
|
|
10354
|
+
|
|
10355
|
+
// Append the dispatch methods that we want to expose
|
|
10356
|
+
// externally to the returned React element.
|
|
10357
|
+
const elementWithDispatchMethods = {
|
|
10358
|
+
...element,
|
|
10359
|
+
activate: this.activate,
|
|
10360
|
+
dismiss: this.dismiss,
|
|
10361
|
+
configure: this.configure,
|
|
10362
|
+
setCursor: this.setCursor,
|
|
10363
|
+
setKeyHandler: this.setKeyHandler,
|
|
10364
|
+
getDOMNode: this.getDOMNode
|
|
10365
|
+
};
|
|
10366
|
+
this.props.onElementMounted?.(elementWithDispatchMethods);
|
|
10367
|
+
};
|
|
10368
|
+
onDismiss = () => {
|
|
10369
|
+
this.props.onAnalyticsEvent({
|
|
10370
|
+
type: "math-input:keypad-closed",
|
|
10371
|
+
payload: {
|
|
10372
|
+
virtualKeypadVersion: "MATH_INPUT_KEYPAD_V1"
|
|
10373
|
+
}
|
|
10374
|
+
});
|
|
10375
|
+
this.props.onDismiss?.();
|
|
10376
|
+
};
|
|
10259
10377
|
render() {
|
|
10260
10378
|
const {
|
|
10261
10379
|
style
|