@khanacademy/math-input 0.7.2 → 1.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/components/compute-layout-parameters.d.ts +38 -0
- package/dist/components/compute-layout-parameters.js.flow +49 -0
- package/dist/components/corner-decal.d.ts +12 -0
- package/dist/components/corner-decal.js.flow +15 -0
- package/dist/components/echo-manager.d.ts +26 -0
- package/dist/components/echo-manager.js.flow +29 -0
- package/dist/components/empty-keypad-button.d.ts +13 -0
- package/dist/components/empty-keypad-button.js.flow +23 -0
- package/dist/components/expression-keypad.d.ts +22 -0
- package/dist/components/expression-keypad.js.flow +32 -0
- package/dist/components/fraction-keypad.d.ts +21 -0
- package/dist/components/fraction-keypad.js.flow +30 -0
- package/dist/components/gesture-manager.d.ts +74 -0
- package/dist/components/gesture-manager.js.flow +82 -0
- package/dist/components/gesture-state-machine.d.ts +105 -0
- package/dist/components/gesture-state-machine.js.flow +118 -0
- package/dist/components/icon.d.ts +15 -0
- package/dist/components/icon.js.flow +18 -0
- package/dist/components/input/__tests__/test-math-wrapper.d.ts +8 -0
- package/dist/components/input/__tests__/test-math-wrapper.js.flow +14 -0
- package/dist/components/input/cursor-handle.d.ts +1 -1
- package/dist/components/input/cursor-handle.js.flow +1 -1
- package/dist/components/input/drag-listener.d.ts +13 -0
- package/dist/components/input/drag-listener.js.flow +19 -0
- package/dist/components/input/math-input.d.ts +5 -4
- package/dist/components/input/math-input.js.flow +5 -4
- package/dist/components/input/math-wrapper.d.ts +110 -0
- package/dist/components/input/math-wrapper.js.flow +125 -0
- package/dist/components/input/scroll-into-view.d.ts +11 -0
- package/dist/components/input/scroll-into-view.js.flow +20 -0
- package/dist/components/keypad/button-assets.d.ts +4 -3
- package/dist/components/keypad/button-assets.js.flow +3 -3
- package/dist/components/keypad/button.d.ts +1 -2
- package/dist/components/keypad/button.js.flow +1 -2
- package/dist/components/keypad/index.d.ts +1 -1
- package/dist/components/keypad/index.js.flow +1 -3
- package/dist/components/keypad/keypad-page-items.d.ts +15 -10
- package/dist/components/keypad/keypad-page-items.js.flow +20 -10
- package/dist/components/keypad-button.d.ts +52 -0
- package/dist/components/keypad-button.js.flow +79 -0
- package/dist/components/keypad-container.d.ts +40 -0
- package/dist/components/keypad-container.js.flow +58 -0
- package/dist/components/keypad.d.ts +31 -0
- package/dist/components/keypad.js.flow +40 -0
- package/dist/components/many-keypad-button.d.ts +15 -0
- package/dist/components/many-keypad-button.js.flow +17 -0
- package/dist/components/math-icon.d.ts +16 -0
- package/dist/components/math-icon.js.flow +19 -0
- package/dist/components/multi-symbol-grid.d.ts +14 -0
- package/dist/components/multi-symbol-grid.js.flow +16 -0
- package/dist/components/multi-symbol-popover.d.ts +12 -0
- package/dist/components/multi-symbol-popover.js.flow +15 -0
- package/dist/components/navigation-pad.d.ts +14 -0
- package/dist/components/navigation-pad.js.flow +16 -0
- package/dist/components/node-manager.d.ts +50 -0
- package/dist/components/node-manager.js.flow +62 -0
- package/dist/components/popover-manager.d.ts +13 -0
- package/dist/components/popover-manager.js.flow +15 -0
- package/dist/components/popover-state-machine.d.ts +68 -0
- package/dist/components/popover-state-machine.js.flow +77 -0
- package/dist/components/provided-keypad.d.ts +8 -10
- package/dist/components/provided-keypad.js.flow +8 -10
- package/dist/components/styles.d.ts +6 -0
- package/dist/components/styles.js.flow +13 -0
- package/dist/components/svg-icon.d.ts +12 -0
- package/dist/components/svg-icon.js.flow +15 -0
- package/dist/components/tabbar/icons.d.ts +3 -2
- package/dist/components/tabbar/icons.js.flow +3 -2
- package/dist/components/tabbar/item.d.ts +1 -2
- package/dist/components/tabbar/item.js.flow +1 -2
- package/dist/components/tabbar/tabbar.d.ts +3 -3
- package/dist/components/tabbar/tabbar.js.flow +3 -3
- package/dist/components/text-icon.d.ts +13 -0
- package/dist/components/text-icon.js.flow +16 -0
- package/dist/components/touchable-keypad-button.d.ts +30 -0
- package/dist/components/touchable-keypad-button.js.flow +35 -0
- package/dist/components/two-page-keypad.d.ts +20 -0
- package/dist/components/two-page-keypad.js.flow +30 -0
- package/dist/components/velocity-tracker.d.ts +48 -0
- package/dist/components/velocity-tracker.js.flow +54 -0
- package/dist/es/index.css +0 -3
- package/dist/es/index.js +933 -1065
- package/dist/es/index.js.map +1 -1
- package/dist/fake-react-native-web/text.d.ts +2 -1
- package/dist/fake-react-native-web/text.js.flow +2 -1
- package/dist/fake-react-native-web/view.d.ts +3 -2
- package/dist/fake-react-native-web/view.js.flow +3 -2
- package/dist/index.css +0 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.js +977 -1090
- package/dist/index.js.flow +1 -4
- package/dist/index.js.map +1 -1
- package/dist/store/actions.d.ts +64 -0
- package/dist/store/actions.js.flow +100 -0
- package/dist/store/echo-reducer.d.ts +4 -0
- package/dist/store/echo-reducer.js.flow +10 -0
- package/dist/store/index.d.ts +10 -1
- package/dist/store/index.js.flow +17 -1
- package/dist/store/input-reducer.d.ts +4 -0
- package/dist/store/input-reducer.js.flow +13 -0
- package/dist/store/keypad-reducer.d.ts +4 -0
- package/dist/store/keypad-reducer.js.flow +13 -0
- package/dist/store/layout-reducer.d.ts +4 -0
- package/dist/store/layout-reducer.js.flow +13 -0
- package/dist/store/pager-reducer.d.ts +4 -0
- package/dist/store/pager-reducer.js.flow +13 -0
- package/dist/store/shared.d.ts +6 -0
- package/dist/store/shared.js.flow +13 -0
- package/dist/store/types.d.ts +58 -0
- package/dist/store/types.js.flow +64 -0
- package/dist/types.d.ts +63 -0
- package/dist/types.js.flow +73 -0
- package/less/overrides.less +0 -6
- package/package.json +1 -1
- package/src/components/__tests__/{gesture-state-machine_test.js → gesture-state-machine.test.ts} +5 -1
- package/src/components/__tests__/{two-page-keypad_test.js → two-page-keypad.test.tsx} +0 -2
- package/src/components/{corner-decal.js → corner-decal.tsx} +6 -5
- package/src/components/{echo-manager.js → echo-manager.tsx} +29 -24
- package/src/components/{empty-keypad-button.js → empty-keypad-button.tsx} +17 -10
- package/src/components/{expression-keypad.js → expression-keypad.tsx} +27 -25
- package/src/components/{fraction-keypad.js → fraction-keypad.tsx} +21 -16
- package/src/components/{gesture-manager.js → gesture-manager.ts} +10 -4
- package/src/components/{gesture-state-machine.js → gesture-state-machine.ts} +49 -3
- package/src/components/{icon.js → icon.tsx} +12 -14
- package/src/components/input/cursor-handle.tsx +1 -1
- package/src/components/input/{drag-listener.js → drag-listener.ts} +4 -0
- package/src/components/input/math-input.tsx +10 -9
- package/src/components/input/{math-wrapper.js → math-wrapper.ts} +10 -6
- package/src/components/input/{scroll-into-view.js → scroll-into-view.ts} +5 -15
- package/src/components/keypad/button-assets.tsx +4 -5
- package/src/components/keypad/button.tsx +1 -2
- package/src/components/keypad/index.tsx +2 -2
- package/src/components/keypad/keypad-page-items.tsx +33 -10
- package/src/components/{keypad-button.js → keypad-button.tsx} +42 -37
- package/src/components/{keypad-container.js → keypad-container.tsx} +42 -24
- package/src/components/{keypad.js → keypad.tsx} +32 -24
- package/src/components/{many-keypad-button.js → many-keypad-button.tsx} +8 -6
- package/src/components/{math-icon.js → math-icon.tsx} +7 -6
- package/src/components/{multi-symbol-grid.js → multi-symbol-grid.tsx} +8 -8
- package/src/components/{multi-symbol-popover.js → multi-symbol-popover.tsx} +5 -6
- package/src/components/{navigation-pad.js → navigation-pad.tsx} +7 -6
- package/src/components/{node-manager.js → node-manager.ts} +16 -4
- package/src/components/{popover-manager.js → popover-manager.tsx} +13 -16
- package/src/components/{popover-state-machine.js → popover-state-machine.ts} +13 -2
- package/src/components/prop-types.js +1 -67
- package/src/components/provided-keypad.tsx +16 -23
- package/src/components/{svg-icon.js → svg-icon.tsx} +5 -6
- package/src/components/tabbar/icons.tsx +4 -2
- package/src/components/tabbar/item.tsx +1 -3
- package/src/components/tabbar/{tabbar.stories.js → tabbar.stories.tsx} +10 -1
- package/src/components/tabbar/tabbar.tsx +3 -3
- package/src/components/{text-icon.js → text-icon.tsx} +7 -6
- package/src/components/{touchable-keypad-button.js → touchable-keypad-button.tsx} +19 -16
- package/src/components/{two-page-keypad.js → two-page-keypad.tsx} +13 -9
- package/src/components/{velocity-tracker.js → velocity-tracker.ts} +14 -4
- package/src/fake-react-native-web/text.tsx +2 -1
- package/src/fake-react-native-web/view.tsx +3 -2
- package/src/index.ts +1 -4
- package/src/math-input.stories.tsx +67 -0
- package/src/store/actions.ts +178 -0
- package/src/store/echo-reducer.ts +61 -0
- package/src/store/index.ts +39 -449
- package/src/store/input-reducer.ts +56 -0
- package/src/store/keypad-reducer.ts +59 -0
- package/src/store/layout-reducer.ts +134 -0
- package/src/store/pager-reducer.ts +125 -0
- package/src/store/shared.ts +12 -0
- package/src/store/types.ts +82 -0
- package/src/types.ts +81 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/src/actions/index.js +0 -57
- package/src/components/app.js +0 -73
- package/src/demo.js +0 -9
- package/src/native-app.js +0 -85
- /package/src/components/__tests__/{node-manager_test.js → node-manager.test.ts} +0 -0
- /package/src/components/{compute-layout-parameters.js → compute-layout-parameters.ts} +0 -0
- /package/src/components/input/__tests__/{context-tracking_test.js → context-tracking.test.ts} +0 -0
- /package/src/components/input/__tests__/{mathquill_test.js → mathquill.test.ts} +0 -0
- /package/src/components/input/__tests__/{test-math-wrapper.jsx → test-math-wrapper.ts} +0 -0
- /package/src/components/keypad/{button.stories.js → button.stories.tsx} +0 -0
- /package/src/components/{styles.js → styles.ts} +0 -0
- /package/src/components/tabbar/__tests__/{tabbar_test.js → tabbar.test.tsx} +0 -0
package/dist/index.js
CHANGED
|
@@ -391,6 +391,9 @@ _defineProperty(CursorHandle, "defaultProps", {
|
|
|
391
391
|
const touchSlopPx = 8;
|
|
392
392
|
class DragListener {
|
|
393
393
|
constructor(onDrag, initialEvent) {
|
|
394
|
+
_defineProperty(this, "_scrollListener", void 0);
|
|
395
|
+
_defineProperty(this, "_moveListener", void 0);
|
|
396
|
+
_defineProperty(this, "_endAndCancelListener", void 0);
|
|
394
397
|
// We detect drags in two ways. First, by listening for the window
|
|
395
398
|
// scroll event (we consider any legitimate scroll to be a drag).
|
|
396
399
|
this._scrollListener = () => {
|
|
@@ -549,7 +552,7 @@ const IN_DENOMINATOR = "IN_DENOMINATOR";
|
|
|
549
552
|
// write is non-leaf math (numbers and variables).
|
|
550
553
|
const BEFORE_FRACTION = "BEFORE_FRACTION";
|
|
551
554
|
|
|
552
|
-
var
|
|
555
|
+
var cursorContexts = /*#__PURE__*/Object.freeze({
|
|
553
556
|
__proto__: null,
|
|
554
557
|
NONE: NONE,
|
|
555
558
|
IN_PARENS: IN_PARENS,
|
|
@@ -560,12 +563,6 @@ var CursorContexts = /*#__PURE__*/Object.freeze({
|
|
|
560
563
|
BEFORE_FRACTION: BEFORE_FRACTION
|
|
561
564
|
});
|
|
562
565
|
|
|
563
|
-
/**
|
|
564
|
-
* This file contains a wrapper around MathQuill so that we can provide a
|
|
565
|
-
* more regular interface for the functionality we need while insulating us
|
|
566
|
-
* from MathQuill changes.
|
|
567
|
-
*/
|
|
568
|
-
|
|
569
566
|
// Keeping `window` in place for test suite and GitHub Pages.
|
|
570
567
|
// If it does not exist, fall back to CommonJS require. - jsatk
|
|
571
568
|
|
|
@@ -700,8 +697,14 @@ const KeysForJumpContext = {
|
|
|
700
697
|
[IN_DENOMINATOR]: Keys.JUMP_OUT_DENOMINATOR
|
|
701
698
|
};
|
|
702
699
|
class MathWrapper {
|
|
700
|
+
// MathQuill interface
|
|
701
|
+
// MathQuill input
|
|
702
|
+
|
|
703
703
|
constructor(element) {
|
|
704
704
|
let callbacks = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
705
|
+
_defineProperty(this, "MQ", void 0);
|
|
706
|
+
_defineProperty(this, "mathField", void 0);
|
|
707
|
+
_defineProperty(this, "callbacks", void 0);
|
|
705
708
|
this.MQ = MathQuill__default["default"].getInterface(2);
|
|
706
709
|
this.mathField = this.MQ.MathField(element, {
|
|
707
710
|
// use a span instead of a textarea so that we don't bring up the
|
|
@@ -780,7 +783,7 @@ class MathWrapper {
|
|
|
780
783
|
this._handleBackspace(cursor);
|
|
781
784
|
} else if (key === Keys.LEFT) {
|
|
782
785
|
this._handleLeftArrow(cursor);
|
|
783
|
-
} else if (key === Keys.RIGHT
|
|
786
|
+
} else if (key === Keys.RIGHT) {
|
|
784
787
|
this._handleRightArrow(cursor);
|
|
785
788
|
} else if (/^[a-zA-Z]$/.test(key)) {
|
|
786
789
|
this.mathField[WRITE](key);
|
|
@@ -1279,7 +1282,7 @@ class MathWrapper {
|
|
|
1279
1282
|
if (this._isInsideEmptyNode(cursor)) {
|
|
1280
1283
|
const grandparent = cursor.parent.parent;
|
|
1281
1284
|
const command = this._maybeFindCommandBeforeParens(grandparent);
|
|
1282
|
-
cursor.insLeftOf(command.startNode);
|
|
1285
|
+
cursor.insLeftOf(command === null || command === void 0 ? void 0 : command.startNode);
|
|
1283
1286
|
cursor.startSelection();
|
|
1284
1287
|
if (grandparent[this.MQ.R] !== MQ_END) {
|
|
1285
1288
|
cursor.insRightOf(grandparent[this.MQ.R]);
|
|
@@ -1443,18 +1446,6 @@ class MathWrapper {
|
|
|
1443
1446
|
* TODO(charlie): Move this scroll logic out of our components and into a higher
|
|
1444
1447
|
* level in the component tree--perhaps even into webapp, beyond Perseus.
|
|
1445
1448
|
*/
|
|
1446
|
-
|
|
1447
|
-
// Taken from https://dev.opera.com/articles/fixing-the-scrolltop-bug/
|
|
1448
|
-
function bodyOrHtml() {
|
|
1449
|
-
if ("scrollingElement" in document) {
|
|
1450
|
-
return document.scrollingElement;
|
|
1451
|
-
}
|
|
1452
|
-
// Fallback for legacy browsers
|
|
1453
|
-
if (navigator.userAgent.indexOf("WebKit") !== -1) {
|
|
1454
|
-
return document.body;
|
|
1455
|
-
}
|
|
1456
|
-
return document.documentElement;
|
|
1457
|
-
}
|
|
1458
1449
|
const scrollIntoView = (containerNode, keypadNode) => {
|
|
1459
1450
|
// TODO(charlie): There's no need for us to be reading the keypad bounds
|
|
1460
1451
|
// here, since they're pre-determined by logic in the store. We should
|
|
@@ -1464,7 +1455,7 @@ const scrollIntoView = (containerNode, keypadNode) => {
|
|
|
1464
1455
|
const containerTopPx = containerBounds.top;
|
|
1465
1456
|
|
|
1466
1457
|
// Get the element that scrolls the document.
|
|
1467
|
-
const scrollNode =
|
|
1458
|
+
const scrollNode = document.scrollingElement;
|
|
1468
1459
|
const desiredMarginPx = 16;
|
|
1469
1460
|
if (keypadNode) {
|
|
1470
1461
|
// NOTE(charlie): We can't use the bounding rect of the keypad,
|
|
@@ -1483,7 +1474,9 @@ const scrollIntoView = (containerNode, keypadNode) => {
|
|
|
1483
1474
|
// the bottom of the input is just above the top of the keypad,
|
|
1484
1475
|
// taking care not to scroll the input out of view.
|
|
1485
1476
|
const scrollOffset = Math.min(containerBottomPx - keypadTopPx + desiredMarginPx, containerTopPx);
|
|
1486
|
-
scrollNode
|
|
1477
|
+
if (scrollNode) {
|
|
1478
|
+
scrollNode.scrollTop += scrollOffset;
|
|
1479
|
+
}
|
|
1487
1480
|
return;
|
|
1488
1481
|
}
|
|
1489
1482
|
}
|
|
@@ -1491,7 +1484,7 @@ const scrollIntoView = (containerNode, keypadNode) => {
|
|
|
1491
1484
|
// Alternatively, if the input is out of the viewport or nearly out
|
|
1492
1485
|
// of the viewport, scroll it into view. We can do this regardless
|
|
1493
1486
|
// of whether the keypad has been provided.
|
|
1494
|
-
if (containerTopPx < desiredMarginPx) {
|
|
1487
|
+
if (scrollNode && containerTopPx < desiredMarginPx) {
|
|
1495
1488
|
scrollNode.scrollTop -= containerBounds.height + desiredMarginPx;
|
|
1496
1489
|
}
|
|
1497
1490
|
};
|
|
@@ -2199,323 +2192,11 @@ const inlineStyles$1 = {
|
|
|
2199
2192
|
};
|
|
2200
2193
|
|
|
2201
2194
|
/**
|
|
2202
|
-
*
|
|
2195
|
+
* React PropTypes that may be shared between components.
|
|
2203
2196
|
*/
|
|
2204
|
-
const KeyConfigs = {
|
|
2205
|
-
// Basic math keys.
|
|
2206
|
-
[Keys.PLUS]: {
|
|
2207
|
-
type: KeyTypes.OPERATOR,
|
|
2208
|
-
// I18N: A label for a plus sign.
|
|
2209
|
-
ariaLabel: i18n__namespace._("Plus")
|
|
2210
|
-
},
|
|
2211
|
-
[Keys.MINUS]: {
|
|
2212
|
-
type: KeyTypes.OPERATOR,
|
|
2213
|
-
// I18N: A label for a minus sign.
|
|
2214
|
-
ariaLabel: i18n__namespace._("Minus")
|
|
2215
|
-
},
|
|
2216
|
-
[Keys.NEGATIVE]: {
|
|
2217
|
-
type: KeyTypes.VALUE,
|
|
2218
|
-
// I18N: A label for a minus sign.
|
|
2219
|
-
ariaLabel: i18n__namespace._("Negative")
|
|
2220
|
-
},
|
|
2221
|
-
[Keys.TIMES]: {
|
|
2222
|
-
type: KeyTypes.OPERATOR,
|
|
2223
|
-
// I18N: A label for a multiplication sign (represented with an 'x').
|
|
2224
|
-
ariaLabel: i18n__namespace._("Multiply")
|
|
2225
|
-
},
|
|
2226
|
-
[Keys.DIVIDE]: {
|
|
2227
|
-
type: KeyTypes.OPERATOR,
|
|
2228
|
-
// I18N: A label for a division sign.
|
|
2229
|
-
ariaLabel: i18n__namespace._("Divide")
|
|
2230
|
-
},
|
|
2231
|
-
[Keys.DECIMAL]: {
|
|
2232
|
-
type: KeyTypes.VALUE,
|
|
2233
|
-
// I18N: A label for a decimal symbol.
|
|
2234
|
-
ariaLabel: i18n__namespace._("Decimal"),
|
|
2235
|
-
icon: decimalSeparator === DecimalSeparators.COMMA ? {
|
|
2236
|
-
// TODO(charlie): Get an SVG icon for the comma, or verify with
|
|
2237
|
-
// design that the text-rendered version is acceptable.
|
|
2238
|
-
type: IconTypes.TEXT,
|
|
2239
|
-
data: ","
|
|
2240
|
-
} : {
|
|
2241
|
-
type: IconTypes.SVG,
|
|
2242
|
-
data: Keys.PERIOD
|
|
2243
|
-
}
|
|
2244
|
-
},
|
|
2245
|
-
[Keys.PERCENT]: {
|
|
2246
|
-
type: KeyTypes.OPERATOR,
|
|
2247
|
-
// I18N: A label for a percent sign.
|
|
2248
|
-
ariaLabel: i18n__namespace._("Percent")
|
|
2249
|
-
},
|
|
2250
|
-
[Keys.CDOT]: {
|
|
2251
|
-
type: KeyTypes.OPERATOR,
|
|
2252
|
-
// I18N: A label for a multiplication sign (represented as a dot).
|
|
2253
|
-
ariaLabel: i18n__namespace._("Multiply")
|
|
2254
|
-
},
|
|
2255
|
-
[Keys.EQUAL]: {
|
|
2256
|
-
type: KeyTypes.OPERATOR,
|
|
2257
|
-
ariaLabel: i18n__namespace._("Equals sign")
|
|
2258
|
-
},
|
|
2259
|
-
[Keys.NEQ]: {
|
|
2260
|
-
type: KeyTypes.OPERATOR,
|
|
2261
|
-
ariaLabel: i18n__namespace._("Not-equals sign")
|
|
2262
|
-
},
|
|
2263
|
-
[Keys.GT]: {
|
|
2264
|
-
type: KeyTypes.OPERATOR,
|
|
2265
|
-
// I18N: A label for a 'greater than' sign (represented as '>').
|
|
2266
|
-
ariaLabel: i18n__namespace._("Greater than sign")
|
|
2267
|
-
},
|
|
2268
|
-
[Keys.LT]: {
|
|
2269
|
-
type: KeyTypes.OPERATOR,
|
|
2270
|
-
// I18N: A label for a 'less than' sign (represented as '<').
|
|
2271
|
-
ariaLabel: i18n__namespace._("Less than sign")
|
|
2272
|
-
},
|
|
2273
|
-
[Keys.GEQ]: {
|
|
2274
|
-
type: KeyTypes.OPERATOR,
|
|
2275
|
-
ariaLabel: i18n__namespace._("Greater than or equal to sign")
|
|
2276
|
-
},
|
|
2277
|
-
[Keys.LEQ]: {
|
|
2278
|
-
type: KeyTypes.OPERATOR,
|
|
2279
|
-
ariaLabel: i18n__namespace._("Less than or equal to sign")
|
|
2280
|
-
},
|
|
2281
|
-
// mobile native
|
|
2282
|
-
[Keys.FRAC_INCLUSIVE]: {
|
|
2283
|
-
type: KeyTypes.OPERATOR,
|
|
2284
|
-
// I18N: A label for a button that creates a new fraction and puts the
|
|
2285
|
-
// current expression in the numerator of that fraction.
|
|
2286
|
-
ariaLabel: i18n__namespace._("Fraction, with current expression in numerator")
|
|
2287
|
-
},
|
|
2288
|
-
// mobile native
|
|
2289
|
-
[Keys.FRAC_EXCLUSIVE]: {
|
|
2290
|
-
type: KeyTypes.OPERATOR,
|
|
2291
|
-
// I18N: A label for a button that creates a new fraction next to the
|
|
2292
|
-
// cursor.
|
|
2293
|
-
ariaLabel: i18n__namespace._("Fraction, excluding the current expression")
|
|
2294
|
-
},
|
|
2295
|
-
// mobile web
|
|
2296
|
-
[Keys.FRAC]: {
|
|
2297
|
-
type: KeyTypes.OPERATOR,
|
|
2298
|
-
// I18N: A label for a button that creates a new fraction next to the
|
|
2299
|
-
// cursor.
|
|
2300
|
-
ariaLabel: i18n__namespace._("Fraction, excluding the current expression")
|
|
2301
|
-
},
|
|
2302
|
-
[Keys.EXP]: {
|
|
2303
|
-
type: KeyTypes.OPERATOR,
|
|
2304
|
-
// I18N: A label for a button that will allow the user to input a custom
|
|
2305
|
-
// exponent.
|
|
2306
|
-
ariaLabel: i18n__namespace._("Custom exponent")
|
|
2307
|
-
},
|
|
2308
|
-
[Keys.EXP_2]: {
|
|
2309
|
-
type: KeyTypes.OPERATOR,
|
|
2310
|
-
// I18N: A label for a button that will square (take to the second
|
|
2311
|
-
// power) some math.
|
|
2312
|
-
ariaLabel: i18n__namespace._("Square")
|
|
2313
|
-
},
|
|
2314
|
-
[Keys.EXP_3]: {
|
|
2315
|
-
type: KeyTypes.OPERATOR,
|
|
2316
|
-
// I18N: A label for a button that will cube (take to the third power)
|
|
2317
|
-
// some math.
|
|
2318
|
-
ariaLabel: i18n__namespace._("Cube")
|
|
2319
|
-
},
|
|
2320
|
-
[Keys.SQRT]: {
|
|
2321
|
-
type: KeyTypes.OPERATOR,
|
|
2322
|
-
ariaLabel: i18n__namespace._("Square root")
|
|
2323
|
-
},
|
|
2324
|
-
[Keys.CUBE_ROOT]: {
|
|
2325
|
-
type: KeyTypes.OPERATOR,
|
|
2326
|
-
ariaLabel: i18n__namespace._("Cube root")
|
|
2327
|
-
},
|
|
2328
|
-
[Keys.RADICAL]: {
|
|
2329
|
-
type: KeyTypes.OPERATOR,
|
|
2330
|
-
ariaLabel: i18n__namespace._("Radical with custom root")
|
|
2331
|
-
},
|
|
2332
|
-
[Keys.LEFT_PAREN]: {
|
|
2333
|
-
type: KeyTypes.OPERATOR,
|
|
2334
|
-
ariaLabel: i18n__namespace._("Left parenthesis")
|
|
2335
|
-
},
|
|
2336
|
-
[Keys.RIGHT_PAREN]: {
|
|
2337
|
-
type: KeyTypes.OPERATOR,
|
|
2338
|
-
ariaLabel: i18n__namespace._("Right parenthesis")
|
|
2339
|
-
},
|
|
2340
|
-
[Keys.LN]: {
|
|
2341
|
-
type: KeyTypes.OPERATOR,
|
|
2342
|
-
ariaLabel: i18n__namespace._("Natural logarithm")
|
|
2343
|
-
},
|
|
2344
|
-
[Keys.LOG]: {
|
|
2345
|
-
type: KeyTypes.OPERATOR,
|
|
2346
|
-
ariaLabel: i18n__namespace._("Logarithm with base 10")
|
|
2347
|
-
},
|
|
2348
|
-
[Keys.LOG_N]: {
|
|
2349
|
-
type: KeyTypes.OPERATOR,
|
|
2350
|
-
ariaLabel: i18n__namespace._("Logarithm with custom base")
|
|
2351
|
-
},
|
|
2352
|
-
[Keys.SIN]: {
|
|
2353
|
-
type: KeyTypes.OPERATOR,
|
|
2354
|
-
ariaLabel: i18n__namespace._("Sine")
|
|
2355
|
-
},
|
|
2356
|
-
[Keys.COS]: {
|
|
2357
|
-
type: KeyTypes.OPERATOR,
|
|
2358
|
-
ariaLabel: i18n__namespace._("Cosine")
|
|
2359
|
-
},
|
|
2360
|
-
[Keys.TAN]: {
|
|
2361
|
-
type: KeyTypes.OPERATOR,
|
|
2362
|
-
ariaLabel: i18n__namespace._("Tangent")
|
|
2363
|
-
},
|
|
2364
|
-
[Keys.PI]: {
|
|
2365
|
-
type: KeyTypes.VALUE,
|
|
2366
|
-
ariaLabel: i18n__namespace._("Pi"),
|
|
2367
|
-
icon: {
|
|
2368
|
-
type: IconTypes.MATH,
|
|
2369
|
-
data: "\\pi"
|
|
2370
|
-
}
|
|
2371
|
-
},
|
|
2372
|
-
[Keys.THETA]: {
|
|
2373
|
-
type: KeyTypes.VALUE,
|
|
2374
|
-
ariaLabel: i18n__namespace._("Theta"),
|
|
2375
|
-
icon: {
|
|
2376
|
-
type: IconTypes.MATH,
|
|
2377
|
-
data: "\\theta"
|
|
2378
|
-
}
|
|
2379
|
-
},
|
|
2380
|
-
[Keys.NOOP]: {
|
|
2381
|
-
type: KeyTypes.EMPTY
|
|
2382
|
-
},
|
|
2383
|
-
// Input navigation keys.
|
|
2384
|
-
[Keys.UP]: {
|
|
2385
|
-
type: KeyTypes.INPUT_NAVIGATION,
|
|
2386
|
-
ariaLabel: i18n__namespace._("Up arrow")
|
|
2387
|
-
},
|
|
2388
|
-
[Keys.RIGHT]: {
|
|
2389
|
-
type: KeyTypes.INPUT_NAVIGATION,
|
|
2390
|
-
ariaLabel: i18n__namespace._("Right arrow")
|
|
2391
|
-
},
|
|
2392
|
-
[Keys.DOWN]: {
|
|
2393
|
-
type: KeyTypes.INPUT_NAVIGATION,
|
|
2394
|
-
ariaLabel: i18n__namespace._("Down arrow")
|
|
2395
|
-
},
|
|
2396
|
-
[Keys.LEFT]: {
|
|
2397
|
-
type: KeyTypes.INPUT_NAVIGATION,
|
|
2398
|
-
ariaLabel: i18n__namespace._("Left arrow")
|
|
2399
|
-
},
|
|
2400
|
-
[Keys.JUMP_OUT_PARENTHESES]: {
|
|
2401
|
-
type: KeyTypes.INPUT_NAVIGATION,
|
|
2402
|
-
ariaLabel: i18n__namespace._("Navigate right out of a set of parentheses")
|
|
2403
|
-
},
|
|
2404
|
-
[Keys.JUMP_OUT_EXPONENT]: {
|
|
2405
|
-
type: KeyTypes.INPUT_NAVIGATION,
|
|
2406
|
-
ariaLabel: i18n__namespace._("Navigate right out of an exponent")
|
|
2407
|
-
},
|
|
2408
|
-
[Keys.JUMP_OUT_BASE]: {
|
|
2409
|
-
type: KeyTypes.INPUT_NAVIGATION,
|
|
2410
|
-
ariaLabel: i18n__namespace._("Navigate right out of a base")
|
|
2411
|
-
},
|
|
2412
|
-
[Keys.JUMP_INTO_NUMERATOR]: {
|
|
2413
|
-
type: KeyTypes.INPUT_NAVIGATION,
|
|
2414
|
-
ariaLabel: i18n__namespace._("Navigate right into the numerator of a fraction")
|
|
2415
|
-
},
|
|
2416
|
-
[Keys.JUMP_OUT_NUMERATOR]: {
|
|
2417
|
-
type: KeyTypes.INPUT_NAVIGATION,
|
|
2418
|
-
ariaLabel: i18n__namespace._("Navigate right out of the numerator and into the denominator")
|
|
2419
|
-
},
|
|
2420
|
-
[Keys.JUMP_OUT_DENOMINATOR]: {
|
|
2421
|
-
type: KeyTypes.INPUT_NAVIGATION,
|
|
2422
|
-
ariaLabel: i18n__namespace._("Navigate right out of the denominator of a fraction")
|
|
2423
|
-
},
|
|
2424
|
-
[Keys.BACKSPACE]: {
|
|
2425
|
-
type: KeyTypes.INPUT_NAVIGATION,
|
|
2426
|
-
// I18N: A label for a button that will delete some input.
|
|
2427
|
-
ariaLabel: i18n__namespace._("Delete")
|
|
2428
|
-
},
|
|
2429
|
-
// Keypad navigation keys.
|
|
2430
|
-
[Keys.DISMISS]: {
|
|
2431
|
-
type: KeyTypes.KEYPAD_NAVIGATION,
|
|
2432
|
-
// I18N: A label for a button that will dismiss/hide a keypad.
|
|
2433
|
-
ariaLabel: i18n__namespace._("Dismiss")
|
|
2434
|
-
}
|
|
2435
|
-
};
|
|
2436
|
-
|
|
2437
|
-
// Add in any multi-function buttons. By default, these keys will mix in any
|
|
2438
|
-
// configuration settings from their default child key (i.e., the first key in
|
|
2439
|
-
// the `childKeyIds` array).
|
|
2440
|
-
// TODO(charlie): Make the multi-function button's long-press interaction
|
|
2441
|
-
// accessible.
|
|
2442
|
-
// NOTE(kevinb): This is only used in the mobile native app.
|
|
2443
|
-
KeyConfigs[Keys.FRAC_MULTI] = {
|
|
2444
|
-
childKeyIds: [Keys.FRAC_INCLUSIVE, Keys.FRAC_EXCLUSIVE]
|
|
2445
|
-
};
|
|
2446
|
-
|
|
2447
|
-
// TODO(charlie): Use the numeral color for the 'Many' key.
|
|
2448
|
-
KeyConfigs[Keys.MANY] = {
|
|
2449
|
-
type: KeyTypes.MANY
|
|
2450
|
-
// childKeyIds will be configured by the client.
|
|
2451
|
-
};
|
|
2452
|
-
|
|
2453
|
-
// Add in every numeral.
|
|
2454
|
-
const NUMBERS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
2455
|
-
for (const num of NUMBERS) {
|
|
2456
|
-
// TODO(charlie): Consider removing the SVG icons that we have for the
|
|
2457
|
-
// numeral keys. They can be rendered just as easily with text (though that
|
|
2458
|
-
// would mean that we'd be using text beyond the variable key).
|
|
2459
|
-
const textRepresentation = "".concat(num);
|
|
2460
|
-
KeyConfigs["NUM_".concat(num)] = {
|
|
2461
|
-
type: KeyTypes.VALUE,
|
|
2462
|
-
ariaLabel: textRepresentation,
|
|
2463
|
-
icon: {
|
|
2464
|
-
type: IconTypes.TEXT,
|
|
2465
|
-
data: textRepresentation
|
|
2466
|
-
}
|
|
2467
|
-
};
|
|
2468
|
-
}
|
|
2469
|
-
|
|
2470
|
-
// Add in every variable.
|
|
2471
|
-
const LETTERS = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
|
|
2472
|
-
for (const letter of LETTERS) {
|
|
2473
|
-
const lowerCaseVariable = letter.toLowerCase();
|
|
2474
|
-
const upperCaseVariable = letter.toUpperCase();
|
|
2475
|
-
for (const textRepresentation of [lowerCaseVariable, upperCaseVariable]) {
|
|
2476
|
-
KeyConfigs[textRepresentation] = {
|
|
2477
|
-
type: KeyTypes.VALUE,
|
|
2478
|
-
ariaLabel: textRepresentation,
|
|
2479
|
-
icon: {
|
|
2480
|
-
type: IconTypes.MATH,
|
|
2481
|
-
data: textRepresentation
|
|
2482
|
-
}
|
|
2483
|
-
};
|
|
2484
|
-
}
|
|
2485
|
-
}
|
|
2486
|
-
for (const key of Object.keys(KeyConfigs)) {
|
|
2487
|
-
KeyConfigs[key] = {
|
|
2488
|
-
id: key,
|
|
2489
|
-
// Default to an SVG icon indexed by the key name.
|
|
2490
|
-
icon: {
|
|
2491
|
-
type: IconTypes.SVG,
|
|
2492
|
-
data: key
|
|
2493
|
-
},
|
|
2494
|
-
...KeyConfigs[key]
|
|
2495
|
-
};
|
|
2496
|
-
}
|
|
2497
|
-
|
|
2498
|
-
/**
|
|
2499
|
-
* React PropTypes that may be shared between components.
|
|
2500
|
-
*/
|
|
2501
|
-
const iconPropType = PropTypes__default["default"].shape({
|
|
2502
|
-
type: PropTypes__default["default"].oneOf(Object.keys(IconTypes)).isRequired,
|
|
2503
|
-
data: PropTypes__default["default"].string.isRequired
|
|
2504
|
-
});
|
|
2505
|
-
const keyIdPropType = PropTypes__default["default"].oneOf(Object.keys(KeyConfigs));
|
|
2506
|
-
const keyConfigPropType = PropTypes__default["default"].shape({
|
|
2507
|
-
ariaLabel: PropTypes__default["default"].string,
|
|
2508
|
-
id: keyIdPropType.isRequired,
|
|
2509
|
-
type: PropTypes__default["default"].oneOf(Object.keys(KeyTypes)).isRequired,
|
|
2510
|
-
childKeyIds: PropTypes__default["default"].arrayOf(keyIdPropType),
|
|
2511
|
-
icon: iconPropType.isRequired
|
|
2512
|
-
});
|
|
2513
|
-
const keypadConfigurationPropType = PropTypes__default["default"].shape({
|
|
2514
|
-
keypadType: PropTypes__default["default"].oneOf(Object.keys(KeypadTypes)).isRequired,
|
|
2515
|
-
extraKeys: PropTypes__default["default"].arrayOf(keyIdPropType)
|
|
2516
|
-
});
|
|
2517
2197
|
|
|
2518
2198
|
// NOTE(jared): This is no longer guaranteed to be React element
|
|
2199
|
+
// NOTE(matthewc): only seems to be used in Perseus
|
|
2519
2200
|
const keypadElementPropType = PropTypes__default["default"].shape({
|
|
2520
2201
|
activate: PropTypes__default["default"].func.isRequired,
|
|
2521
2202
|
dismiss: PropTypes__default["default"].func.isRequired,
|
|
@@ -2524,29 +2205,6 @@ const keypadElementPropType = PropTypes__default["default"].shape({
|
|
|
2524
2205
|
setKeyHandler: PropTypes__default["default"].func.isRequired,
|
|
2525
2206
|
getDOMNode: PropTypes__default["default"].func.isRequired
|
|
2526
2207
|
});
|
|
2527
|
-
const bordersPropType = PropTypes__default["default"].arrayOf(PropTypes__default["default"].oneOf(Object.keys(BorderDirections)));
|
|
2528
|
-
const boundingBoxPropType = PropTypes__default["default"].shape({
|
|
2529
|
-
height: PropTypes__default["default"].number,
|
|
2530
|
-
width: PropTypes__default["default"].number,
|
|
2531
|
-
top: PropTypes__default["default"].number,
|
|
2532
|
-
right: PropTypes__default["default"].number,
|
|
2533
|
-
bottom: PropTypes__default["default"].number,
|
|
2534
|
-
left: PropTypes__default["default"].number
|
|
2535
|
-
});
|
|
2536
|
-
const echoPropType = PropTypes__default["default"].shape({
|
|
2537
|
-
animationId: PropTypes__default["default"].string.isRequired,
|
|
2538
|
-
animationType: PropTypes__default["default"].oneOf(Object.keys(EchoAnimationTypes)).isRequired,
|
|
2539
|
-
borders: bordersPropType,
|
|
2540
|
-
id: keyIdPropType.isRequired,
|
|
2541
|
-
initialBounds: boundingBoxPropType.isRequired
|
|
2542
|
-
});
|
|
2543
|
-
const cursorContextPropType = PropTypes__default["default"].oneOf(Object.keys(CursorContexts));
|
|
2544
|
-
const popoverPropType = PropTypes__default["default"].shape({
|
|
2545
|
-
parentId: keyIdPropType.isRequired,
|
|
2546
|
-
bounds: boundingBoxPropType.isRequired,
|
|
2547
|
-
childKeyIds: PropTypes__default["default"].arrayOf(keyIdPropType).isRequired
|
|
2548
|
-
});
|
|
2549
|
-
PropTypes__default["default"].oneOfType([PropTypes__default["default"].arrayOf(PropTypes__default["default"].node), PropTypes__default["default"].node]);
|
|
2550
2208
|
|
|
2551
2209
|
// naming convention: verb + noun
|
|
2552
2210
|
// the noun should be one of the other properties in the object that's
|
|
@@ -2565,9 +2223,8 @@ const activateKeypad = () => {
|
|
|
2565
2223
|
|
|
2566
2224
|
/**
|
|
2567
2225
|
* Configure the keypad with the provided configuration parameters.
|
|
2568
|
-
*
|
|
2569
|
-
* See: `prop-types.js#keypadConfigurationPropType`.
|
|
2570
2226
|
*/
|
|
2227
|
+
|
|
2571
2228
|
const configureKeypad = configuration => {
|
|
2572
2229
|
return {
|
|
2573
2230
|
type: "ConfigureKeypad",
|
|
@@ -2589,6 +2246,7 @@ const removeEcho = animationId => {
|
|
|
2589
2246
|
};
|
|
2590
2247
|
|
|
2591
2248
|
// Input-related actions.
|
|
2249
|
+
|
|
2592
2250
|
const setKeyHandler = keyHandler => {
|
|
2593
2251
|
return {
|
|
2594
2252
|
type: "SetKeyHandler",
|
|
@@ -2602,135 +2260,33 @@ const setCursor = cursor => {
|
|
|
2602
2260
|
};
|
|
2603
2261
|
};
|
|
2604
2262
|
|
|
2605
|
-
|
|
2606
|
-
* An algorithm for computing the appropriate layout parameters for the keypad,
|
|
2607
|
-
* including the size of the buttons and whether or not to render fullscreen,
|
|
2608
|
-
* taking into account a number of factors including the size of the screen, the
|
|
2609
|
-
* orientation of the screen, the presence of browser chrome, the presence of
|
|
2610
|
-
* other exercise-related chrome, the size of the input box, the parameters that
|
|
2611
|
-
* define the keypad (i.e., the number of rows, columns, and pages), and so
|
|
2612
|
-
* forth.
|
|
2613
|
-
*
|
|
2614
|
-
* The computations herein make some strong assumptions about the sizes of
|
|
2615
|
-
* various other elements and the situations under which they will be visible
|
|
2616
|
-
* (e.g., browser chrome). However, this is just a heuristic--it's not crucial
|
|
2617
|
-
* that our buttons are sized in a pixel-perfect manner, but rather, that we
|
|
2618
|
-
* make a balanced use of space.
|
|
2619
|
-
*
|
|
2620
|
-
* Note that one goal of the algorithm is to avoid resizing the keypad in the
|
|
2621
|
-
* face of dynamic browser chrome. In order to avoid that awkwardness, we tend
|
|
2622
|
-
* to be conservative in our measurements and make things smaller than they
|
|
2623
|
-
* might need to be.
|
|
2624
|
-
*/
|
|
2625
|
-
const minButtonHeight = 48;
|
|
2626
|
-
const maxButtonSize = 64;
|
|
2627
|
-
const minSpaceAboveKeypad = 32;
|
|
2628
|
-
|
|
2629
|
-
// These values are taken from an iPhone 5, but should be consistent with the
|
|
2630
|
-
// iPhone 4 as well. Regardless, these are meant to be representative of the
|
|
2631
|
-
// possible types of browser chrome that could appear in various context, rather
|
|
2632
|
-
// than pixel-perfect for every device.
|
|
2633
|
-
const safariNavBarWhenShrunk = 44;
|
|
2634
|
-
const safariNavBarWhenExpanded = 64;
|
|
2635
|
-
const safariToolbar = 44;
|
|
2636
|
-
|
|
2637
|
-
// In mobile Safari, the browser chrome is completely hidden in landscape,
|
|
2638
|
-
// though a shrunken navbar and full-sized toolbar on scroll. In portrait, the
|
|
2639
|
-
// shrunken navbar is always visible, but expands on scroll (and the toolbar
|
|
2640
|
-
// appears as well).
|
|
2641
|
-
const maxLandscapeBrowserChrome = safariNavBarWhenShrunk + safariToolbar;
|
|
2642
|
-
const maxPortraitBrowserChrome = safariToolbar + (safariNavBarWhenExpanded - safariNavBarWhenShrunk);
|
|
2643
|
-
|
|
2644
|
-
// This represents the 'worst case' aspect ratio that we care about (for
|
|
2645
|
-
// portrait layouts). It's taken from the iPhone 4. The height is computed by
|
|
2646
|
-
// taking the height of the device and removing the persistent, shrunken navbar.
|
|
2647
|
-
// (We don't need to account for the expanded navbar, since we include the
|
|
2648
|
-
// difference when reserving space above the keypad.)
|
|
2649
|
-
const worstCaseAspectRatio = 320 / (480 - safariNavBarWhenShrunk);
|
|
2650
|
-
const computeLayoutParameters = (_ref, _ref2, _ref3, _ref4) => {
|
|
2651
|
-
let {
|
|
2652
|
-
numColumns,
|
|
2653
|
-
numMaxVisibleRows,
|
|
2654
|
-
numPages
|
|
2655
|
-
} = _ref;
|
|
2656
|
-
let {
|
|
2657
|
-
pageWidthPx,
|
|
2658
|
-
pageHeightPx
|
|
2659
|
-
} = _ref2;
|
|
2660
|
-
let {
|
|
2661
|
-
deviceOrientation,
|
|
2662
|
-
deviceType
|
|
2663
|
-
} = _ref3;
|
|
2664
|
-
let {
|
|
2665
|
-
navigationPadEnabled,
|
|
2666
|
-
paginationEnabled,
|
|
2667
|
-
toolbarEnabled
|
|
2668
|
-
} = _ref4;
|
|
2669
|
-
// First, compute some values that will be used in multiple computations.
|
|
2670
|
-
const effectiveNumColumns = paginationEnabled ? numColumns : numColumns * numPages;
|
|
2671
|
-
|
|
2672
|
-
// Then, compute the button dimensions based on the provided parameters.
|
|
2673
|
-
let buttonDimensions;
|
|
2674
|
-
if (deviceType === DeviceTypes.PHONE) {
|
|
2675
|
-
const isLandscape = deviceOrientation === DeviceOrientations.LANDSCAPE;
|
|
2676
|
-
|
|
2677
|
-
// In many cases, the browser chrome will already have been factored
|
|
2678
|
-
// into `pageHeightPx`. But we have no way of knowing if that's
|
|
2679
|
-
// the case or not. As such, we take a conservative approach and
|
|
2680
|
-
// assume that the chrome is _never_ included in `pageHeightPx`.
|
|
2681
|
-
const browserChromeHeight = isLandscape ? maxLandscapeBrowserChrome : maxPortraitBrowserChrome;
|
|
2682
|
-
|
|
2683
|
-
// Count up all the space that we need to reserve on the page.
|
|
2684
|
-
// Namely, we need to account for:
|
|
2685
|
-
// 1. Space between the keypad and the top of the page.
|
|
2686
|
-
// 2. The presence of the exercise toolbar.
|
|
2687
|
-
// 3. The presence of the view pager indicator.
|
|
2688
|
-
// 4. Any browser chrome that may appear later.
|
|
2689
|
-
const reservedSpace = minSpaceAboveKeypad + browserChromeHeight + (toolbarEnabled ? toolbarHeightPx : 0) + (paginationEnabled ? pageIndicatorHeightPx : 0);
|
|
2690
|
-
|
|
2691
|
-
// Next, compute the effective width and height. We can use the page
|
|
2692
|
-
// width as the effective width. For the height, though, we take
|
|
2693
|
-
// another conservative measure when in portrait by assuming that
|
|
2694
|
-
// the device has the worst possible aspect ratio. In other words,
|
|
2695
|
-
// we ignore the device height in portrait and assume the worst.
|
|
2696
|
-
// This prevents the keypad from changing size when browser chrome
|
|
2697
|
-
// appears and disappears.
|
|
2698
|
-
const effectiveWidth = pageWidthPx;
|
|
2699
|
-
const effectiveHeight = isLandscape ? pageHeightPx : pageWidthPx / worstCaseAspectRatio;
|
|
2700
|
-
const maxKeypadHeight = effectiveHeight - reservedSpace;
|
|
2701
|
-
|
|
2702
|
-
// Finally, compute the button height and width. In computing the
|
|
2703
|
-
// height, accommodate for the maximum number of rows that will ever be
|
|
2704
|
-
// visible (since the toggling of popovers can increase the number of
|
|
2705
|
-
// visible rows).
|
|
2706
|
-
const buttonHeightPx = Math.max(Math.min(maxKeypadHeight / numMaxVisibleRows, maxButtonSize), minButtonHeight);
|
|
2707
|
-
let buttonWidthPx;
|
|
2708
|
-
if (numPages > 1) {
|
|
2709
|
-
const effectiveNumColumns = paginationEnabled ? numColumns : numColumns * numPages;
|
|
2710
|
-
buttonWidthPx = effectiveWidth / effectiveNumColumns;
|
|
2711
|
-
} else {
|
|
2712
|
-
buttonWidthPx = isLandscape ? maxButtonSize : effectiveWidth / numColumns;
|
|
2713
|
-
}
|
|
2714
|
-
buttonDimensions = {
|
|
2715
|
-
widthPx: buttonWidthPx,
|
|
2716
|
-
heightPx: buttonHeightPx
|
|
2717
|
-
};
|
|
2718
|
-
} else if (deviceType === DeviceTypes.TABLET) {
|
|
2719
|
-
buttonDimensions = {
|
|
2720
|
-
widthPx: maxButtonSize,
|
|
2721
|
-
heightPx: maxButtonSize
|
|
2722
|
-
};
|
|
2723
|
-
} else {
|
|
2724
|
-
throw new Error("Invalid device type: " + deviceType);
|
|
2725
|
-
}
|
|
2263
|
+
// Gesture actions
|
|
2726
2264
|
|
|
2727
|
-
|
|
2728
|
-
// fullscreen layout by determining its resultant width.
|
|
2729
|
-
const numSeparators = (navigationPadEnabled ? 1 : 0) + (!paginationEnabled ? numPages - 1 : 0);
|
|
2730
|
-
const keypadWidth = effectiveNumColumns * buttonDimensions.widthPx + (navigationPadEnabled ? navigationPadWidthPx : 0) + numSeparators * innerBorderWidthPx;
|
|
2265
|
+
const onSwipeChange = dx => {
|
|
2731
2266
|
return {
|
|
2732
|
-
|
|
2733
|
-
|
|
2267
|
+
type: "OnSwipeChange",
|
|
2268
|
+
dx
|
|
2269
|
+
};
|
|
2270
|
+
};
|
|
2271
|
+
const onSwipeEnd = dx => {
|
|
2272
|
+
return {
|
|
2273
|
+
type: "OnSwipeEnd",
|
|
2274
|
+
dx
|
|
2275
|
+
};
|
|
2276
|
+
};
|
|
2277
|
+
const setActiveNodes = activeNodes => {
|
|
2278
|
+
return {
|
|
2279
|
+
type: "SetActiveNodes",
|
|
2280
|
+
activeNodes
|
|
2281
|
+
};
|
|
2282
|
+
};
|
|
2283
|
+
const pressKey = (key, borders, initialBounds, inPopover) => {
|
|
2284
|
+
return {
|
|
2285
|
+
type: "PressKey",
|
|
2286
|
+
key,
|
|
2287
|
+
borders,
|
|
2288
|
+
initialBounds,
|
|
2289
|
+
inPopover
|
|
2734
2290
|
};
|
|
2735
2291
|
};
|
|
2736
2292
|
|
|
@@ -2742,16 +2298,24 @@ const computeLayoutParameters = (_ref, _ref2, _ref3, _ref4) => {
|
|
|
2742
2298
|
* multi-touch interactions, tracking gesture state on a per-touch basis.
|
|
2743
2299
|
*/
|
|
2744
2300
|
|
|
2745
|
-
|
|
2301
|
+
// exported for tests
|
|
2302
|
+
|
|
2303
|
+
const defaultOptions = {
|
|
2746
2304
|
longPressWaitTimeMs: 50,
|
|
2747
2305
|
swipeThresholdPx: 20,
|
|
2748
2306
|
holdIntervalMs: 250
|
|
2749
2307
|
};
|
|
2750
2308
|
class GestureStateMachine {
|
|
2751
2309
|
constructor(handlers, options, swipeDisabledNodeIds, multiPressableKeys) {
|
|
2310
|
+
_defineProperty(this, "handlers", void 0);
|
|
2311
|
+
_defineProperty(this, "options", void 0);
|
|
2312
|
+
_defineProperty(this, "swipeDisabledNodeIds", void 0);
|
|
2313
|
+
_defineProperty(this, "multiPressableKeys", void 0);
|
|
2314
|
+
_defineProperty(this, "touchState", void 0);
|
|
2315
|
+
_defineProperty(this, "swipeState", void 0);
|
|
2752
2316
|
this.handlers = handlers;
|
|
2753
2317
|
this.options = {
|
|
2754
|
-
...
|
|
2318
|
+
...defaultOptions,
|
|
2755
2319
|
...options
|
|
2756
2320
|
};
|
|
2757
2321
|
this.swipeDisabledNodeIds = swipeDisabledNodeIds || [];
|
|
@@ -3020,6 +2584,10 @@ class GestureStateMachine {
|
|
|
3020
2584
|
|
|
3021
2585
|
class NodeManager {
|
|
3022
2586
|
constructor() {
|
|
2587
|
+
_defineProperty(this, "_nodesById", void 0);
|
|
2588
|
+
_defineProperty(this, "_bordersById", void 0);
|
|
2589
|
+
_defineProperty(this, "_orderedIds", void 0);
|
|
2590
|
+
_defineProperty(this, "_cachedBoundingBoxesById", void 0);
|
|
3023
2591
|
// A mapping from IDs to DOM nodes.
|
|
3024
2592
|
this._nodesById = {};
|
|
3025
2593
|
|
|
@@ -3069,6 +2637,7 @@ class NodeManager {
|
|
|
3069
2637
|
const seenIds = {};
|
|
3070
2638
|
for (const id of allIds) {
|
|
3071
2639
|
if (!seenIds[id]) {
|
|
2640
|
+
// @ts-expect-error TS2345
|
|
3072
2641
|
orderedIds.push(id);
|
|
3073
2642
|
seenIds[id] = true;
|
|
3074
2643
|
}
|
|
@@ -3137,6 +2706,9 @@ class NodeManager {
|
|
|
3137
2706
|
|
|
3138
2707
|
class PopoverStateMachine {
|
|
3139
2708
|
constructor(handlers) {
|
|
2709
|
+
_defineProperty(this, "handlers", void 0);
|
|
2710
|
+
_defineProperty(this, "popovers", void 0);
|
|
2711
|
+
_defineProperty(this, "activePopover", void 0);
|
|
3140
2712
|
this.handlers = handlers;
|
|
3141
2713
|
this.activePopover = null;
|
|
3142
2714
|
this.popovers = {};
|
|
@@ -3233,8 +2805,8 @@ class PopoverStateMachine {
|
|
|
3233
2805
|
this.activePopover = id;
|
|
3234
2806
|
this.handlers.onActiveNodesChanged({
|
|
3235
2807
|
popover: {
|
|
3236
|
-
parentId:
|
|
3237
|
-
childIds: this.popovers[
|
|
2808
|
+
parentId: id,
|
|
2809
|
+
childIds: this.popovers[id]
|
|
3238
2810
|
},
|
|
3239
2811
|
focus: this._defaultNodeForPopover(this.activePopover)
|
|
3240
2812
|
});
|
|
@@ -3296,16 +2868,16 @@ class PopoverStateMachine {
|
|
|
3296
2868
|
}
|
|
3297
2869
|
}
|
|
3298
2870
|
|
|
3299
|
-
/**
|
|
3300
|
-
* A high-level manager for our gesture system. In particular, this class
|
|
3301
|
-
* connects our various bits of logic for managing gestures and interactions,
|
|
3302
|
-
* and links them together.
|
|
3303
|
-
*/
|
|
3304
2871
|
const coordsForEvent = evt => {
|
|
3305
2872
|
return [evt.changedTouches[0].clientX, evt.changedTouches[0].clientY];
|
|
3306
2873
|
};
|
|
3307
2874
|
class GestureManager {
|
|
3308
2875
|
constructor(options, handlers, disabledSwipeKeys, multiPressableKeys) {
|
|
2876
|
+
_defineProperty(this, "swipeEnabled", void 0);
|
|
2877
|
+
_defineProperty(this, "trackEvents", void 0);
|
|
2878
|
+
_defineProperty(this, "nodeManager", void 0);
|
|
2879
|
+
_defineProperty(this, "popoverStateMachine", void 0);
|
|
2880
|
+
_defineProperty(this, "gestureStateMachine", void 0);
|
|
3309
2881
|
const {
|
|
3310
2882
|
swipeEnabled
|
|
3311
2883
|
} = options;
|
|
@@ -3488,51 +3060,430 @@ class GestureManager {
|
|
|
3488
3060
|
}
|
|
3489
3061
|
}
|
|
3490
3062
|
|
|
3491
|
-
class CornerDecal extends React__namespace.Component {
|
|
3492
|
-
render() {
|
|
3493
|
-
const {
|
|
3494
|
-
style
|
|
3495
|
-
} = this.props;
|
|
3496
|
-
const containerStyle = [styles$d.container, ...(Array.isArray(style) ? style : [style])];
|
|
3497
|
-
return /*#__PURE__*/React__namespace.createElement(View, {
|
|
3498
|
-
style: containerStyle
|
|
3499
|
-
}, /*#__PURE__*/React__namespace.createElement("svg", {
|
|
3500
|
-
width: triangleSizePx,
|
|
3501
|
-
height: triangleSizePx,
|
|
3502
|
-
viewBox: "4 4 8 8"
|
|
3503
|
-
}, /*#__PURE__*/React__namespace.createElement("path", {
|
|
3504
|
-
fill: offBlack,
|
|
3505
|
-
opacity: "0.3",
|
|
3506
|
-
d: "M5.29289322,5.70710678 L10.2928932,10.7071068 C10.9228581,11.3370716 12,10.8909049 12,10 L12,5 C12,4.44771525 11.5522847,4 11,4 L6,4 C5.10909515,4 4.66292836,5.07714192 5.29289322,5.70710678 Z" // @Nolint
|
|
3507
|
-
})));
|
|
3508
|
-
}
|
|
3509
|
-
}
|
|
3510
|
-
_defineProperty(CornerDecal, "propTypes", {
|
|
3511
|
-
style: PropTypes__default["default"].any
|
|
3512
|
-
});
|
|
3513
|
-
const triangleSizePx = 7;
|
|
3514
|
-
const styles$d = aphrodite.StyleSheet.create({
|
|
3515
|
-
container: {
|
|
3516
|
-
position: "absolute",
|
|
3517
|
-
top: 0,
|
|
3518
|
-
right: 0,
|
|
3519
|
-
width: triangleSizePx,
|
|
3520
|
-
height: triangleSizePx
|
|
3521
|
-
}
|
|
3522
|
-
});
|
|
3523
|
-
|
|
3524
3063
|
/**
|
|
3525
|
-
*
|
|
3064
|
+
* This file contains configuration settings for the buttons in the keypad.
|
|
3526
3065
|
*/
|
|
3527
|
-
|
|
3528
|
-
|
|
3529
|
-
|
|
3066
|
+
const KeyConfigs = {
|
|
3067
|
+
// Basic math keys.
|
|
3068
|
+
[Keys.PLUS]: {
|
|
3069
|
+
type: KeyTypes.OPERATOR,
|
|
3070
|
+
// I18N: A label for a plus sign.
|
|
3071
|
+
ariaLabel: i18n__namespace._("Plus")
|
|
3530
3072
|
},
|
|
3531
|
-
|
|
3532
|
-
|
|
3073
|
+
[Keys.MINUS]: {
|
|
3074
|
+
type: KeyTypes.OPERATOR,
|
|
3075
|
+
// I18N: A label for a minus sign.
|
|
3076
|
+
ariaLabel: i18n__namespace._("Minus")
|
|
3533
3077
|
},
|
|
3534
|
-
|
|
3535
|
-
|
|
3078
|
+
[Keys.NEGATIVE]: {
|
|
3079
|
+
type: KeyTypes.VALUE,
|
|
3080
|
+
// I18N: A label for a minus sign.
|
|
3081
|
+
ariaLabel: i18n__namespace._("Negative")
|
|
3082
|
+
},
|
|
3083
|
+
[Keys.TIMES]: {
|
|
3084
|
+
type: KeyTypes.OPERATOR,
|
|
3085
|
+
// I18N: A label for a multiplication sign (represented with an 'x').
|
|
3086
|
+
ariaLabel: i18n__namespace._("Multiply")
|
|
3087
|
+
},
|
|
3088
|
+
[Keys.DIVIDE]: {
|
|
3089
|
+
type: KeyTypes.OPERATOR,
|
|
3090
|
+
// I18N: A label for a division sign.
|
|
3091
|
+
ariaLabel: i18n__namespace._("Divide")
|
|
3092
|
+
},
|
|
3093
|
+
[Keys.DECIMAL]: {
|
|
3094
|
+
type: KeyTypes.VALUE,
|
|
3095
|
+
// I18N: A label for a decimal symbol.
|
|
3096
|
+
ariaLabel: i18n__namespace._("Decimal"),
|
|
3097
|
+
icon: decimalSeparator === DecimalSeparators.COMMA ? {
|
|
3098
|
+
// TODO(charlie): Get an SVG icon for the comma, or verify with
|
|
3099
|
+
// design that the text-rendered version is acceptable.
|
|
3100
|
+
type: IconTypes.TEXT,
|
|
3101
|
+
data: ","
|
|
3102
|
+
} : {
|
|
3103
|
+
type: IconTypes.SVG,
|
|
3104
|
+
data: Keys.PERIOD
|
|
3105
|
+
}
|
|
3106
|
+
},
|
|
3107
|
+
[Keys.PERCENT]: {
|
|
3108
|
+
type: KeyTypes.OPERATOR,
|
|
3109
|
+
// I18N: A label for a percent sign.
|
|
3110
|
+
ariaLabel: i18n__namespace._("Percent")
|
|
3111
|
+
},
|
|
3112
|
+
[Keys.CDOT]: {
|
|
3113
|
+
type: KeyTypes.OPERATOR,
|
|
3114
|
+
// I18N: A label for a multiplication sign (represented as a dot).
|
|
3115
|
+
ariaLabel: i18n__namespace._("Multiply")
|
|
3116
|
+
},
|
|
3117
|
+
[Keys.EQUAL]: {
|
|
3118
|
+
type: KeyTypes.OPERATOR,
|
|
3119
|
+
ariaLabel: i18n__namespace._("Equals sign")
|
|
3120
|
+
},
|
|
3121
|
+
[Keys.NEQ]: {
|
|
3122
|
+
type: KeyTypes.OPERATOR,
|
|
3123
|
+
ariaLabel: i18n__namespace._("Not-equals sign")
|
|
3124
|
+
},
|
|
3125
|
+
[Keys.GT]: {
|
|
3126
|
+
type: KeyTypes.OPERATOR,
|
|
3127
|
+
// I18N: A label for a 'greater than' sign (represented as '>').
|
|
3128
|
+
ariaLabel: i18n__namespace._("Greater than sign")
|
|
3129
|
+
},
|
|
3130
|
+
[Keys.LT]: {
|
|
3131
|
+
type: KeyTypes.OPERATOR,
|
|
3132
|
+
// I18N: A label for a 'less than' sign (represented as '<').
|
|
3133
|
+
ariaLabel: i18n__namespace._("Less than sign")
|
|
3134
|
+
},
|
|
3135
|
+
[Keys.GEQ]: {
|
|
3136
|
+
type: KeyTypes.OPERATOR,
|
|
3137
|
+
ariaLabel: i18n__namespace._("Greater than or equal to sign")
|
|
3138
|
+
},
|
|
3139
|
+
[Keys.LEQ]: {
|
|
3140
|
+
type: KeyTypes.OPERATOR,
|
|
3141
|
+
ariaLabel: i18n__namespace._("Less than or equal to sign")
|
|
3142
|
+
},
|
|
3143
|
+
// mobile native
|
|
3144
|
+
[Keys.FRAC_INCLUSIVE]: {
|
|
3145
|
+
type: KeyTypes.OPERATOR,
|
|
3146
|
+
// I18N: A label for a button that creates a new fraction and puts the
|
|
3147
|
+
// current expression in the numerator of that fraction.
|
|
3148
|
+
ariaLabel: i18n__namespace._("Fraction, with current expression in numerator")
|
|
3149
|
+
},
|
|
3150
|
+
// mobile native
|
|
3151
|
+
[Keys.FRAC_EXCLUSIVE]: {
|
|
3152
|
+
type: KeyTypes.OPERATOR,
|
|
3153
|
+
// I18N: A label for a button that creates a new fraction next to the
|
|
3154
|
+
// cursor.
|
|
3155
|
+
ariaLabel: i18n__namespace._("Fraction, excluding the current expression")
|
|
3156
|
+
},
|
|
3157
|
+
// mobile web
|
|
3158
|
+
[Keys.FRAC]: {
|
|
3159
|
+
type: KeyTypes.OPERATOR,
|
|
3160
|
+
// I18N: A label for a button that creates a new fraction next to the
|
|
3161
|
+
// cursor.
|
|
3162
|
+
ariaLabel: i18n__namespace._("Fraction, excluding the current expression")
|
|
3163
|
+
},
|
|
3164
|
+
[Keys.EXP]: {
|
|
3165
|
+
type: KeyTypes.OPERATOR,
|
|
3166
|
+
// I18N: A label for a button that will allow the user to input a custom
|
|
3167
|
+
// exponent.
|
|
3168
|
+
ariaLabel: i18n__namespace._("Custom exponent")
|
|
3169
|
+
},
|
|
3170
|
+
[Keys.EXP_2]: {
|
|
3171
|
+
type: KeyTypes.OPERATOR,
|
|
3172
|
+
// I18N: A label for a button that will square (take to the second
|
|
3173
|
+
// power) some math.
|
|
3174
|
+
ariaLabel: i18n__namespace._("Square")
|
|
3175
|
+
},
|
|
3176
|
+
[Keys.EXP_3]: {
|
|
3177
|
+
type: KeyTypes.OPERATOR,
|
|
3178
|
+
// I18N: A label for a button that will cube (take to the third power)
|
|
3179
|
+
// some math.
|
|
3180
|
+
ariaLabel: i18n__namespace._("Cube")
|
|
3181
|
+
},
|
|
3182
|
+
[Keys.SQRT]: {
|
|
3183
|
+
type: KeyTypes.OPERATOR,
|
|
3184
|
+
ariaLabel: i18n__namespace._("Square root")
|
|
3185
|
+
},
|
|
3186
|
+
[Keys.CUBE_ROOT]: {
|
|
3187
|
+
type: KeyTypes.OPERATOR,
|
|
3188
|
+
ariaLabel: i18n__namespace._("Cube root")
|
|
3189
|
+
},
|
|
3190
|
+
[Keys.RADICAL]: {
|
|
3191
|
+
type: KeyTypes.OPERATOR,
|
|
3192
|
+
ariaLabel: i18n__namespace._("Radical with custom root")
|
|
3193
|
+
},
|
|
3194
|
+
[Keys.LEFT_PAREN]: {
|
|
3195
|
+
type: KeyTypes.OPERATOR,
|
|
3196
|
+
ariaLabel: i18n__namespace._("Left parenthesis")
|
|
3197
|
+
},
|
|
3198
|
+
[Keys.RIGHT_PAREN]: {
|
|
3199
|
+
type: KeyTypes.OPERATOR,
|
|
3200
|
+
ariaLabel: i18n__namespace._("Right parenthesis")
|
|
3201
|
+
},
|
|
3202
|
+
[Keys.LN]: {
|
|
3203
|
+
type: KeyTypes.OPERATOR,
|
|
3204
|
+
ariaLabel: i18n__namespace._("Natural logarithm")
|
|
3205
|
+
},
|
|
3206
|
+
[Keys.LOG]: {
|
|
3207
|
+
type: KeyTypes.OPERATOR,
|
|
3208
|
+
ariaLabel: i18n__namespace._("Logarithm with base 10")
|
|
3209
|
+
},
|
|
3210
|
+
[Keys.LOG_N]: {
|
|
3211
|
+
type: KeyTypes.OPERATOR,
|
|
3212
|
+
ariaLabel: i18n__namespace._("Logarithm with custom base")
|
|
3213
|
+
},
|
|
3214
|
+
[Keys.SIN]: {
|
|
3215
|
+
type: KeyTypes.OPERATOR,
|
|
3216
|
+
ariaLabel: i18n__namespace._("Sine")
|
|
3217
|
+
},
|
|
3218
|
+
[Keys.COS]: {
|
|
3219
|
+
type: KeyTypes.OPERATOR,
|
|
3220
|
+
ariaLabel: i18n__namespace._("Cosine")
|
|
3221
|
+
},
|
|
3222
|
+
[Keys.TAN]: {
|
|
3223
|
+
type: KeyTypes.OPERATOR,
|
|
3224
|
+
ariaLabel: i18n__namespace._("Tangent")
|
|
3225
|
+
},
|
|
3226
|
+
[Keys.PI]: {
|
|
3227
|
+
type: KeyTypes.VALUE,
|
|
3228
|
+
ariaLabel: i18n__namespace._("Pi"),
|
|
3229
|
+
icon: {
|
|
3230
|
+
type: IconTypes.MATH,
|
|
3231
|
+
data: "\\pi"
|
|
3232
|
+
}
|
|
3233
|
+
},
|
|
3234
|
+
[Keys.THETA]: {
|
|
3235
|
+
type: KeyTypes.VALUE,
|
|
3236
|
+
ariaLabel: i18n__namespace._("Theta"),
|
|
3237
|
+
icon: {
|
|
3238
|
+
type: IconTypes.MATH,
|
|
3239
|
+
data: "\\theta"
|
|
3240
|
+
}
|
|
3241
|
+
},
|
|
3242
|
+
[Keys.NOOP]: {
|
|
3243
|
+
type: KeyTypes.EMPTY
|
|
3244
|
+
},
|
|
3245
|
+
// Input navigation keys.
|
|
3246
|
+
[Keys.UP]: {
|
|
3247
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
3248
|
+
ariaLabel: i18n__namespace._("Up arrow")
|
|
3249
|
+
},
|
|
3250
|
+
[Keys.RIGHT]: {
|
|
3251
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
3252
|
+
ariaLabel: i18n__namespace._("Right arrow")
|
|
3253
|
+
},
|
|
3254
|
+
[Keys.DOWN]: {
|
|
3255
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
3256
|
+
ariaLabel: i18n__namespace._("Down arrow")
|
|
3257
|
+
},
|
|
3258
|
+
[Keys.LEFT]: {
|
|
3259
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
3260
|
+
ariaLabel: i18n__namespace._("Left arrow")
|
|
3261
|
+
},
|
|
3262
|
+
[Keys.JUMP_OUT_PARENTHESES]: {
|
|
3263
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
3264
|
+
ariaLabel: i18n__namespace._("Navigate right out of a set of parentheses")
|
|
3265
|
+
},
|
|
3266
|
+
[Keys.JUMP_OUT_EXPONENT]: {
|
|
3267
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
3268
|
+
ariaLabel: i18n__namespace._("Navigate right out of an exponent")
|
|
3269
|
+
},
|
|
3270
|
+
[Keys.JUMP_OUT_BASE]: {
|
|
3271
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
3272
|
+
ariaLabel: i18n__namespace._("Navigate right out of a base")
|
|
3273
|
+
},
|
|
3274
|
+
[Keys.JUMP_INTO_NUMERATOR]: {
|
|
3275
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
3276
|
+
ariaLabel: i18n__namespace._("Navigate right into the numerator of a fraction")
|
|
3277
|
+
},
|
|
3278
|
+
[Keys.JUMP_OUT_NUMERATOR]: {
|
|
3279
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
3280
|
+
ariaLabel: i18n__namespace._("Navigate right out of the numerator and into the denominator")
|
|
3281
|
+
},
|
|
3282
|
+
[Keys.JUMP_OUT_DENOMINATOR]: {
|
|
3283
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
3284
|
+
ariaLabel: i18n__namespace._("Navigate right out of the denominator of a fraction")
|
|
3285
|
+
},
|
|
3286
|
+
[Keys.BACKSPACE]: {
|
|
3287
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
3288
|
+
// I18N: A label for a button that will delete some input.
|
|
3289
|
+
ariaLabel: i18n__namespace._("Delete")
|
|
3290
|
+
},
|
|
3291
|
+
// Keypad navigation keys.
|
|
3292
|
+
[Keys.DISMISS]: {
|
|
3293
|
+
type: KeyTypes.KEYPAD_NAVIGATION,
|
|
3294
|
+
// I18N: A label for a button that will dismiss/hide a keypad.
|
|
3295
|
+
ariaLabel: i18n__namespace._("Dismiss")
|
|
3296
|
+
}
|
|
3297
|
+
};
|
|
3298
|
+
|
|
3299
|
+
// Add in any multi-function buttons. By default, these keys will mix in any
|
|
3300
|
+
// configuration settings from their default child key (i.e., the first key in
|
|
3301
|
+
// the `childKeyIds` array).
|
|
3302
|
+
// TODO(charlie): Make the multi-function button's long-press interaction
|
|
3303
|
+
// accessible.
|
|
3304
|
+
// NOTE(kevinb): This is only used in the mobile native app.
|
|
3305
|
+
KeyConfigs[Keys.FRAC_MULTI] = {
|
|
3306
|
+
childKeyIds: [Keys.FRAC_INCLUSIVE, Keys.FRAC_EXCLUSIVE]
|
|
3307
|
+
};
|
|
3308
|
+
|
|
3309
|
+
// TODO(charlie): Use the numeral color for the 'Many' key.
|
|
3310
|
+
KeyConfigs[Keys.MANY] = {
|
|
3311
|
+
type: KeyTypes.MANY
|
|
3312
|
+
// childKeyIds will be configured by the client.
|
|
3313
|
+
};
|
|
3314
|
+
|
|
3315
|
+
// Add in every numeral.
|
|
3316
|
+
const NUMBERS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
3317
|
+
for (const num of NUMBERS) {
|
|
3318
|
+
// TODO(charlie): Consider removing the SVG icons that we have for the
|
|
3319
|
+
// numeral keys. They can be rendered just as easily with text (though that
|
|
3320
|
+
// would mean that we'd be using text beyond the variable key).
|
|
3321
|
+
const textRepresentation = "".concat(num);
|
|
3322
|
+
KeyConfigs["NUM_".concat(num)] = {
|
|
3323
|
+
type: KeyTypes.VALUE,
|
|
3324
|
+
ariaLabel: textRepresentation,
|
|
3325
|
+
icon: {
|
|
3326
|
+
type: IconTypes.TEXT,
|
|
3327
|
+
data: textRepresentation
|
|
3328
|
+
}
|
|
3329
|
+
};
|
|
3330
|
+
}
|
|
3331
|
+
|
|
3332
|
+
// Add in every variable.
|
|
3333
|
+
const LETTERS = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"];
|
|
3334
|
+
for (const letter of LETTERS) {
|
|
3335
|
+
const lowerCaseVariable = letter.toLowerCase();
|
|
3336
|
+
const upperCaseVariable = letter.toUpperCase();
|
|
3337
|
+
for (const textRepresentation of [lowerCaseVariable, upperCaseVariable]) {
|
|
3338
|
+
KeyConfigs[textRepresentation] = {
|
|
3339
|
+
type: KeyTypes.VALUE,
|
|
3340
|
+
ariaLabel: textRepresentation,
|
|
3341
|
+
icon: {
|
|
3342
|
+
type: IconTypes.MATH,
|
|
3343
|
+
data: textRepresentation
|
|
3344
|
+
}
|
|
3345
|
+
};
|
|
3346
|
+
}
|
|
3347
|
+
}
|
|
3348
|
+
for (const key of Object.keys(KeyConfigs)) {
|
|
3349
|
+
KeyConfigs[key] = {
|
|
3350
|
+
id: key,
|
|
3351
|
+
// Default to an SVG icon indexed by the key name.
|
|
3352
|
+
icon: {
|
|
3353
|
+
type: IconTypes.SVG,
|
|
3354
|
+
data: key
|
|
3355
|
+
},
|
|
3356
|
+
...KeyConfigs[key]
|
|
3357
|
+
};
|
|
3358
|
+
}
|
|
3359
|
+
|
|
3360
|
+
// Used to generate unique animation IDs for the echo animations. The actual
|
|
3361
|
+
// values are irrelevant as long as they are unique.
|
|
3362
|
+
let _lastAnimationId = 0;
|
|
3363
|
+
const initialEchoState = {
|
|
3364
|
+
echoes: []
|
|
3365
|
+
};
|
|
3366
|
+
const echoReducer = function () {
|
|
3367
|
+
let state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialEchoState;
|
|
3368
|
+
let action = arguments.length > 1 ? arguments[1] : undefined;
|
|
3369
|
+
switch (action.type) {
|
|
3370
|
+
case "PressKey":
|
|
3371
|
+
const keyConfig = KeyConfigs[action.key];
|
|
3372
|
+
|
|
3373
|
+
// Add in the echo animation if the user performs a math
|
|
3374
|
+
// operation.
|
|
3375
|
+
if (keyConfig.type === KeyTypes.VALUE || keyConfig.type === KeyTypes.OPERATOR) {
|
|
3376
|
+
return {
|
|
3377
|
+
...state,
|
|
3378
|
+
echoes: [...state.echoes, {
|
|
3379
|
+
animationId: "" + _lastAnimationId++,
|
|
3380
|
+
animationType: action.inPopover ? EchoAnimationTypes.LONG_FADE_ONLY : EchoAnimationTypes.FADE_ONLY,
|
|
3381
|
+
borders: action.borders,
|
|
3382
|
+
id: keyConfig.id,
|
|
3383
|
+
initialBounds: action.initialBounds
|
|
3384
|
+
}]
|
|
3385
|
+
};
|
|
3386
|
+
}
|
|
3387
|
+
return state;
|
|
3388
|
+
case "RemoveEcho":
|
|
3389
|
+
const remainingEchoes = state.echoes.filter(echo => {
|
|
3390
|
+
return echo.animationId !== action.animationId;
|
|
3391
|
+
});
|
|
3392
|
+
return {
|
|
3393
|
+
...state,
|
|
3394
|
+
echoes: remainingEchoes
|
|
3395
|
+
};
|
|
3396
|
+
default:
|
|
3397
|
+
return state;
|
|
3398
|
+
}
|
|
3399
|
+
};
|
|
3400
|
+
|
|
3401
|
+
const initialInputState = {
|
|
3402
|
+
keyHandler: null,
|
|
3403
|
+
cursor: {
|
|
3404
|
+
context: NONE
|
|
3405
|
+
}
|
|
3406
|
+
};
|
|
3407
|
+
const inputReducer = function () {
|
|
3408
|
+
let state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialInputState;
|
|
3409
|
+
let action = arguments.length > 1 ? arguments[1] : undefined;
|
|
3410
|
+
switch (action.type) {
|
|
3411
|
+
case "SetKeyHandler":
|
|
3412
|
+
return {
|
|
3413
|
+
...state,
|
|
3414
|
+
keyHandler: action.keyHandler
|
|
3415
|
+
};
|
|
3416
|
+
case "PressKey":
|
|
3417
|
+
const keyConfig = KeyConfigs[action.key];
|
|
3418
|
+
if (keyConfig.type !== KeyTypes.KEYPAD_NAVIGATION) {
|
|
3419
|
+
var _state$keyHandler;
|
|
3420
|
+
// This is probably an anti-pattern but it works for the
|
|
3421
|
+
// case where we don't actually control the state but we
|
|
3422
|
+
// still want to communicate with the other object
|
|
3423
|
+
return {
|
|
3424
|
+
...state,
|
|
3425
|
+
cursor: (_state$keyHandler = state.keyHandler) === null || _state$keyHandler === void 0 ? void 0 : _state$keyHandler.call(state, keyConfig.id)
|
|
3426
|
+
};
|
|
3427
|
+
}
|
|
3428
|
+
|
|
3429
|
+
// TODO(kevinb) get state from MathQuill and store it?
|
|
3430
|
+
return state;
|
|
3431
|
+
case "SetCursor":
|
|
3432
|
+
return {
|
|
3433
|
+
...state,
|
|
3434
|
+
cursor: action.cursor
|
|
3435
|
+
};
|
|
3436
|
+
default:
|
|
3437
|
+
return state;
|
|
3438
|
+
}
|
|
3439
|
+
};
|
|
3440
|
+
|
|
3441
|
+
/**
|
|
3442
|
+
* A small triangular decal to sit in the corner of a parent component.
|
|
3443
|
+
*/
|
|
3444
|
+
class CornerDecal extends React__namespace.Component {
|
|
3445
|
+
render() {
|
|
3446
|
+
const {
|
|
3447
|
+
style
|
|
3448
|
+
} = this.props;
|
|
3449
|
+
const containerStyle = [styles$d.container, ...(Array.isArray(style) ? style : [style])];
|
|
3450
|
+
return /*#__PURE__*/React__namespace.createElement(View, {
|
|
3451
|
+
style: containerStyle
|
|
3452
|
+
}, /*#__PURE__*/React__namespace.createElement("svg", {
|
|
3453
|
+
width: triangleSizePx,
|
|
3454
|
+
height: triangleSizePx,
|
|
3455
|
+
viewBox: "4 4 8 8"
|
|
3456
|
+
}, /*#__PURE__*/React__namespace.createElement("path", {
|
|
3457
|
+
fill: offBlack,
|
|
3458
|
+
opacity: "0.3",
|
|
3459
|
+
d: "M5.29289322,5.70710678 L10.2928932,10.7071068 C10.9228581,11.3370716 12,10.8909049 12,10 L12,5 C12,4.44771525 11.5522847,4 11,4 L6,4 C5.10909515,4 4.66292836,5.07714192 5.29289322,5.70710678 Z" // @Nolint
|
|
3460
|
+
})));
|
|
3461
|
+
}
|
|
3462
|
+
}
|
|
3463
|
+
|
|
3464
|
+
const triangleSizePx = 7;
|
|
3465
|
+
const styles$d = aphrodite.StyleSheet.create({
|
|
3466
|
+
container: {
|
|
3467
|
+
position: "absolute",
|
|
3468
|
+
top: 0,
|
|
3469
|
+
right: 0,
|
|
3470
|
+
width: triangleSizePx,
|
|
3471
|
+
height: triangleSizePx
|
|
3472
|
+
}
|
|
3473
|
+
});
|
|
3474
|
+
|
|
3475
|
+
/**
|
|
3476
|
+
* Common styles shared across components.
|
|
3477
|
+
*/
|
|
3478
|
+
var Styles = aphrodite.StyleSheet.create({
|
|
3479
|
+
row: {
|
|
3480
|
+
flexDirection: "row"
|
|
3481
|
+
},
|
|
3482
|
+
column: {
|
|
3483
|
+
flexDirection: "column"
|
|
3484
|
+
},
|
|
3485
|
+
oneColumn: {
|
|
3486
|
+
flexGrow: 1
|
|
3536
3487
|
},
|
|
3537
3488
|
fullWidth: {
|
|
3538
3489
|
width: "100%"
|
|
@@ -3587,10 +3538,6 @@ class MathIcon extends React__namespace.Component {
|
|
|
3587
3538
|
});
|
|
3588
3539
|
}
|
|
3589
3540
|
}
|
|
3590
|
-
_defineProperty(MathIcon, "propTypes", {
|
|
3591
|
-
math: PropTypes__default["default"].string.isRequired,
|
|
3592
|
-
style: PropTypes__default["default"].any
|
|
3593
|
-
});
|
|
3594
3541
|
const styles$c = aphrodite.StyleSheet.create({
|
|
3595
3542
|
size: {
|
|
3596
3543
|
height: iconSizeHeightPx,
|
|
@@ -4743,6 +4690,9 @@ var Iconography = /*#__PURE__*/Object.freeze({
|
|
|
4743
4690
|
JUMP_OUT_DENOMINATOR: JumpOutDenominator
|
|
4744
4691
|
});
|
|
4745
4692
|
|
|
4693
|
+
/**
|
|
4694
|
+
* A component that renders a single SVG icon.
|
|
4695
|
+
*/
|
|
4746
4696
|
class SvgIcon extends React__namespace.Component {
|
|
4747
4697
|
render() {
|
|
4748
4698
|
const {
|
|
@@ -4757,11 +4707,10 @@ class SvgIcon extends React__namespace.Component {
|
|
|
4757
4707
|
});
|
|
4758
4708
|
}
|
|
4759
4709
|
}
|
|
4760
|
-
_defineProperty(SvgIcon, "propTypes", {
|
|
4761
|
-
color: PropTypes__default["default"].string.isRequired,
|
|
4762
|
-
name: PropTypes__default["default"].string.isRequired
|
|
4763
|
-
});
|
|
4764
4710
|
|
|
4711
|
+
/**
|
|
4712
|
+
* A component that renders a text-based icon.
|
|
4713
|
+
*/
|
|
4765
4714
|
const {
|
|
4766
4715
|
row: row$6,
|
|
4767
4716
|
centered: centered$3
|
|
@@ -4778,10 +4727,6 @@ class TextIcon extends React__namespace.Component {
|
|
|
4778
4727
|
}, /*#__PURE__*/React__namespace.createElement(Text, null, character));
|
|
4779
4728
|
}
|
|
4780
4729
|
}
|
|
4781
|
-
_defineProperty(TextIcon, "propTypes", {
|
|
4782
|
-
character: PropTypes__default["default"].string.isRequired,
|
|
4783
|
-
style: PropTypes__default["default"].any
|
|
4784
|
-
});
|
|
4785
4730
|
const styles$b = aphrodite.StyleSheet.create({
|
|
4786
4731
|
size: {
|
|
4787
4732
|
height: iconSizeHeightPx,
|
|
@@ -4793,6 +4738,9 @@ const styles$b = aphrodite.StyleSheet.create({
|
|
|
4793
4738
|
}
|
|
4794
4739
|
});
|
|
4795
4740
|
|
|
4741
|
+
/**
|
|
4742
|
+
* A component that renders an icon for a symbol with the given name.
|
|
4743
|
+
*/
|
|
4796
4744
|
const focusedColor = "#FFF";
|
|
4797
4745
|
const unfocusedColor = offBlack;
|
|
4798
4746
|
class Icon extends React__namespace.PureComponent {
|
|
@@ -4823,18 +4771,11 @@ class Icon extends React__namespace.PureComponent {
|
|
|
4823
4771
|
character: icon.data,
|
|
4824
4772
|
style: styleWithFocus
|
|
4825
4773
|
});
|
|
4774
|
+
default:
|
|
4775
|
+
throw new Error("No icon or symbol provided");
|
|
4826
4776
|
}
|
|
4827
|
-
throw new Error("No icon or symbol provided");
|
|
4828
4777
|
}
|
|
4829
4778
|
}
|
|
4830
|
-
_defineProperty(Icon, "propTypes", {
|
|
4831
|
-
focused: PropTypes__default["default"].bool,
|
|
4832
|
-
icon: iconPropType.isRequired,
|
|
4833
|
-
// An Aphrodite style object, or an array of Aphrodite style objects.
|
|
4834
|
-
// Note that custom styles will only be applied to text and math icons
|
|
4835
|
-
// (and not SVG icons).
|
|
4836
|
-
style: PropTypes__default["default"].any
|
|
4837
|
-
});
|
|
4838
4779
|
const styles$a = aphrodite.StyleSheet.create({
|
|
4839
4780
|
unfocused: {
|
|
4840
4781
|
color: unfocusedColor
|
|
@@ -4844,6 +4785,10 @@ const styles$a = aphrodite.StyleSheet.create({
|
|
|
4844
4785
|
}
|
|
4845
4786
|
});
|
|
4846
4787
|
|
|
4788
|
+
/**
|
|
4789
|
+
* A grid of symbols, rendered as text and positioned based on the number of
|
|
4790
|
+
* symbols provided. Up to four symbols will be shown.
|
|
4791
|
+
*/
|
|
4847
4792
|
const {
|
|
4848
4793
|
row: row$5,
|
|
4849
4794
|
column: column$3,
|
|
@@ -4925,13 +4870,9 @@ class MultiSymbolGrid extends React__namespace.Component {
|
|
|
4925
4870
|
}))));
|
|
4926
4871
|
}
|
|
4927
4872
|
}
|
|
4928
|
-
throw new Error("Invalid number of icons:"
|
|
4873
|
+
throw new Error("Invalid number of icons: ".concat(icons.length));
|
|
4929
4874
|
}
|
|
4930
4875
|
}
|
|
4931
|
-
_defineProperty(MultiSymbolGrid, "propTypes", {
|
|
4932
|
-
focused: PropTypes__default["default"].bool,
|
|
4933
|
-
icons: PropTypes__default["default"].arrayOf(iconPropType).isRequired
|
|
4934
|
-
});
|
|
4935
4876
|
const verticalInsetPx = 2;
|
|
4936
4877
|
const horizontalInsetPx = 4;
|
|
4937
4878
|
const styles$9 = aphrodite.StyleSheet.create({
|
|
@@ -4975,6 +4916,7 @@ const styles$9 = aphrodite.StyleSheet.create({
|
|
|
4975
4916
|
class KeypadButton extends React__namespace.PureComponent {
|
|
4976
4917
|
constructor() {
|
|
4977
4918
|
super(...arguments);
|
|
4919
|
+
_defineProperty(this, "buttonSizeStyle", void 0);
|
|
4978
4920
|
_defineProperty(this, "_preInjectStyles", () => {
|
|
4979
4921
|
// HACK(charlie): Pre-inject all of the possible styles for the button.
|
|
4980
4922
|
// This avoids a flickering effect in the echo animation whereby the
|
|
@@ -5023,10 +4965,12 @@ class KeypadButton extends React__namespace.PureComponent {
|
|
|
5023
4965
|
break;
|
|
5024
4966
|
}
|
|
5025
4967
|
const borderStyle = [];
|
|
5026
|
-
if (borders.
|
|
4968
|
+
if (borders.includes(BorderDirections.LEFT)) {
|
|
4969
|
+
// @ts-expect-error TS2345
|
|
5027
4970
|
borderStyle.push(styles$8.leftBorder);
|
|
5028
4971
|
}
|
|
5029
|
-
if (borders.
|
|
4972
|
+
if (borders.includes(BorderDirections.BOTTOM)) {
|
|
4973
|
+
// @ts-expect-error TS2345
|
|
5030
4974
|
borderStyle.push(styles$8.bottomBorder);
|
|
5031
4975
|
}
|
|
5032
4976
|
return [styles$8.buttonBase, backgroundStyle, ...borderStyle, type === KeyTypes.ECHO && styles$8.echo, this.buttonSizeStyle,
|
|
@@ -5074,7 +5018,7 @@ class KeypadButton extends React__namespace.PureComponent {
|
|
|
5074
5018
|
const renderFocused = !disabled && focused || popoverEnabled || type === KeyTypes.ECHO;
|
|
5075
5019
|
const buttonStyle = this._getButtonStyle(type, borders, style);
|
|
5076
5020
|
const focusStyle = this._getFocusStyle(type);
|
|
5077
|
-
const iconWrapperStyle = [styles$8.iconWrapper, disabled
|
|
5021
|
+
const iconWrapperStyle = [styles$8.iconWrapper, disabled ? styles$8.disabled : undefined];
|
|
5078
5022
|
const eventHandlers = {
|
|
5079
5023
|
onTouchCancel,
|
|
5080
5024
|
onTouchEnd,
|
|
@@ -5125,32 +5069,6 @@ class KeypadButton extends React__namespace.PureComponent {
|
|
|
5125
5069
|
}
|
|
5126
5070
|
}
|
|
5127
5071
|
}
|
|
5128
|
-
_defineProperty(KeypadButton, "propTypes", {
|
|
5129
|
-
ariaLabel: PropTypes__default["default"].string,
|
|
5130
|
-
// The borders to display on the button. Typically, this should be set
|
|
5131
|
-
// using one of the preset `BorderStyles` options.
|
|
5132
|
-
borders: bordersPropType,
|
|
5133
|
-
// Any additional keys that can be accessed by long-pressing on the
|
|
5134
|
-
// button.
|
|
5135
|
-
childKeys: PropTypes__default["default"].arrayOf(keyConfigPropType),
|
|
5136
|
-
// Whether the button should be rendered in a 'disabled' state, i.e.,
|
|
5137
|
-
// without any touch feedback.
|
|
5138
|
-
disabled: PropTypes__default["default"].bool,
|
|
5139
|
-
focused: PropTypes__default["default"].bool,
|
|
5140
|
-
heightPx: PropTypes__default["default"].number.isRequired,
|
|
5141
|
-
icon: iconPropType,
|
|
5142
|
-
onTouchCancel: PropTypes__default["default"].func,
|
|
5143
|
-
onTouchEnd: PropTypes__default["default"].func,
|
|
5144
|
-
onTouchMove: PropTypes__default["default"].func,
|
|
5145
|
-
onTouchStart: PropTypes__default["default"].func,
|
|
5146
|
-
popoverEnabled: PropTypes__default["default"].bool,
|
|
5147
|
-
style: PropTypes__default["default"].any,
|
|
5148
|
-
type: PropTypes__default["default"].oneOf(Object.keys(KeyTypes)).isRequired,
|
|
5149
|
-
// NOTE(charlie): We may want to make this optional for phone layouts
|
|
5150
|
-
// (and rely on Flexbox instead), since it might not be pixel perfect
|
|
5151
|
-
// with borders and such.
|
|
5152
|
-
widthPx: PropTypes__default["default"].number.isRequired
|
|
5153
|
-
});
|
|
5154
5072
|
_defineProperty(KeypadButton, "defaultProps", {
|
|
5155
5073
|
borders: BorderStyles.ALL,
|
|
5156
5074
|
childKeys: [],
|
|
@@ -5162,8 +5080,6 @@ const focusInsetPx = 4;
|
|
|
5162
5080
|
const focusBoxZIndex = 0;
|
|
5163
5081
|
const styles$8 = aphrodite.StyleSheet.create({
|
|
5164
5082
|
buttonBase: {
|
|
5165
|
-
// HACK(benkomalo): support old style flex box in Android browsers
|
|
5166
|
-
"-webkit-box-flex": "1",
|
|
5167
5083
|
flex: 1,
|
|
5168
5084
|
cursor: "pointer",
|
|
5169
5085
|
// Make the text unselectable
|
|
@@ -5239,7 +5155,10 @@ const styleForButtonDimensions = (heightPx, widthPx) => {
|
|
|
5239
5155
|
}).buttonSize;
|
|
5240
5156
|
};
|
|
5241
5157
|
const mapStateToProps$7 = state => {
|
|
5242
|
-
return
|
|
5158
|
+
return {
|
|
5159
|
+
heightPx: state.layout.buttonDimensions.heightPx,
|
|
5160
|
+
widthPx: state.layout.buttonDimensions.widthPx
|
|
5161
|
+
};
|
|
5243
5162
|
};
|
|
5244
5163
|
var KeypadButton$1 = reactRedux.connect(mapStateToProps$7, null, null, {
|
|
5245
5164
|
forwardRef: true
|
|
@@ -5265,9 +5184,6 @@ class EmptyKeypadButton extends React__namespace.Component {
|
|
|
5265
5184
|
}, KeyConfigs.NOOP, rest));
|
|
5266
5185
|
}
|
|
5267
5186
|
}
|
|
5268
|
-
_defineProperty(EmptyKeypadButton, "propTypes", {
|
|
5269
|
-
gestureManager: PropTypes__default["default"].instanceOf(GestureManager)
|
|
5270
|
-
});
|
|
5271
5187
|
const mapStateToProps$6 = state => {
|
|
5272
5188
|
const {
|
|
5273
5189
|
gestures
|
|
@@ -5324,17 +5240,6 @@ class TouchableKeypadButton extends React__namespace.Component {
|
|
|
5324
5240
|
}, eventHandlers, rest));
|
|
5325
5241
|
}
|
|
5326
5242
|
}
|
|
5327
|
-
_defineProperty(TouchableKeypadButton, "propTypes", {
|
|
5328
|
-
borders: bordersPropType,
|
|
5329
|
-
childKeyIds: PropTypes__default["default"].arrayOf(keyIdPropType),
|
|
5330
|
-
disabled: PropTypes__default["default"].bool,
|
|
5331
|
-
focused: PropTypes__default["default"].bool,
|
|
5332
|
-
gestureManager: PropTypes__default["default"].instanceOf(GestureManager),
|
|
5333
|
-
id: keyIdPropType.isRequired,
|
|
5334
|
-
popoverEnabled: PropTypes__default["default"].bool,
|
|
5335
|
-
style: PropTypes__default["default"].any,
|
|
5336
|
-
type: PropTypes__default["default"].oneOf(Object.keys(KeyTypes)).isRequired
|
|
5337
|
-
});
|
|
5338
5243
|
const extractProps = keyConfig => {
|
|
5339
5244
|
const {
|
|
5340
5245
|
ariaLabel,
|
|
@@ -5400,7 +5305,7 @@ class ManyKeypadButton extends React__namespace.Component {
|
|
|
5400
5305
|
// one, render a standard button. Otherwise, capture them all in a
|
|
5401
5306
|
// single button.
|
|
5402
5307
|
if (keys.length === 0) {
|
|
5403
|
-
return /*#__PURE__*/React__namespace.createElement(EmptyKeypadButton$1,
|
|
5308
|
+
return /*#__PURE__*/React__namespace.createElement(EmptyKeypadButton$1, null);
|
|
5404
5309
|
} else if (keys.length === 1) {
|
|
5405
5310
|
const keyConfig = KeyConfigs[keys[0]];
|
|
5406
5311
|
return /*#__PURE__*/React__namespace.createElement(TouchableKeypadButton$1, _extends({
|
|
@@ -5418,8 +5323,8 @@ class ManyKeypadButton extends React__namespace.Component {
|
|
|
5418
5323
|
}
|
|
5419
5324
|
}
|
|
5420
5325
|
}
|
|
5421
|
-
_defineProperty(ManyKeypadButton, "
|
|
5422
|
-
keys:
|
|
5326
|
+
_defineProperty(ManyKeypadButton, "defaultProps", {
|
|
5327
|
+
keys: []
|
|
5423
5328
|
});
|
|
5424
5329
|
|
|
5425
5330
|
/**
|
|
@@ -5468,20 +5373,12 @@ class Echo extends React__namespace.Component {
|
|
|
5468
5373
|
return /*#__PURE__*/React__namespace.createElement("div", {
|
|
5469
5374
|
style: containerStyle
|
|
5470
5375
|
}, /*#__PURE__*/React__namespace.createElement(KeypadButton$1, {
|
|
5471
|
-
name: id,
|
|
5472
5376
|
icon: icon,
|
|
5473
5377
|
type: KeyTypes.ECHO,
|
|
5474
5378
|
borders: borders
|
|
5475
5379
|
}));
|
|
5476
5380
|
}
|
|
5477
5381
|
}
|
|
5478
|
-
_defineProperty(Echo, "propTypes", {
|
|
5479
|
-
animationDurationMs: PropTypes__default["default"].number.isRequired,
|
|
5480
|
-
borders: bordersPropType,
|
|
5481
|
-
id: keyIdPropType.isRequired,
|
|
5482
|
-
initialBounds: boundingBoxPropType.isRequired,
|
|
5483
|
-
onAnimationFinish: PropTypes__default["default"].func.isRequired
|
|
5484
|
-
});
|
|
5485
5382
|
class EchoManager extends React__namespace.Component {
|
|
5486
5383
|
constructor() {
|
|
5487
5384
|
super(...arguments);
|
|
@@ -5504,7 +5401,7 @@ class EchoManager extends React__namespace.Component {
|
|
|
5504
5401
|
animationTransitionName = "echo-long-fade-only";
|
|
5505
5402
|
break;
|
|
5506
5403
|
default:
|
|
5507
|
-
throw new Error("Invalid echo animation type:"
|
|
5404
|
+
throw new Error("Invalid echo animation type: ".concat(animationType));
|
|
5508
5405
|
}
|
|
5509
5406
|
return {
|
|
5510
5407
|
animationDurationMs,
|
|
@@ -5549,17 +5446,16 @@ class EchoManager extends React__namespace.Component {
|
|
|
5549
5446
|
key: animationId
|
|
5550
5447
|
}, /*#__PURE__*/React__namespace.createElement(Echo, _extends({
|
|
5551
5448
|
animationDurationMs: animationDurationMs,
|
|
5552
|
-
onAnimationFinish: () => onAnimationFinish(animationId)
|
|
5449
|
+
onAnimationFinish: () => onAnimationFinish === null || onAnimationFinish === void 0 ? void 0 : onAnimationFinish(animationId)
|
|
5553
5450
|
}, echo)));
|
|
5554
5451
|
}));
|
|
5555
5452
|
}));
|
|
5556
5453
|
}
|
|
5557
5454
|
}
|
|
5558
|
-
_defineProperty(EchoManager, "propTypes", {
|
|
5559
|
-
echoes: PropTypes__default["default"].arrayOf(echoPropType),
|
|
5560
|
-
onAnimationFinish: PropTypes__default["default"].func.isRequired
|
|
5561
|
-
});
|
|
5562
5455
|
|
|
5456
|
+
/**
|
|
5457
|
+
* A popover that renders a set of keys floating above the page.
|
|
5458
|
+
*/
|
|
5563
5459
|
class MultiSymbolPopover extends React__namespace.Component {
|
|
5564
5460
|
render() {
|
|
5565
5461
|
const {
|
|
@@ -5579,9 +5475,6 @@ class MultiSymbolPopover extends React__namespace.Component {
|
|
|
5579
5475
|
}));
|
|
5580
5476
|
}
|
|
5581
5477
|
}
|
|
5582
|
-
_defineProperty(MultiSymbolPopover, "propTypes", {
|
|
5583
|
-
keys: PropTypes__default["default"].arrayOf(keyConfigPropType)
|
|
5584
|
-
});
|
|
5585
5478
|
const styles$6 = aphrodite.StyleSheet.create({
|
|
5586
5479
|
container: {
|
|
5587
5480
|
flexDirection: "column-reverse",
|
|
@@ -5598,11 +5491,14 @@ const styles$6 = aphrodite.StyleSheet.create({
|
|
|
5598
5491
|
}
|
|
5599
5492
|
});
|
|
5600
5493
|
|
|
5494
|
+
/**
|
|
5495
|
+
* A component that renders and animates the popovers that appear over the
|
|
5496
|
+
* multi-functional keys.
|
|
5497
|
+
*/
|
|
5601
5498
|
// NOTE(charlie): These must be kept in sync with the transition durations and
|
|
5602
5499
|
// classnames specified in popover.less.
|
|
5603
5500
|
const animationTransitionName = "popover";
|
|
5604
5501
|
const animationDurationMs = 200;
|
|
5605
|
-
|
|
5606
5502
|
// A container component used to position a popover absolutely at a specific
|
|
5607
5503
|
// position.
|
|
5608
5504
|
class PopoverContainer extends React__namespace.Component {
|
|
@@ -5622,10 +5518,6 @@ class PopoverContainer extends React__namespace.Component {
|
|
|
5622
5518
|
}));
|
|
5623
5519
|
}
|
|
5624
5520
|
}
|
|
5625
|
-
_defineProperty(PopoverContainer, "propTypes", {
|
|
5626
|
-
bounds: boundingBoxPropType.isRequired,
|
|
5627
|
-
childKeys: PropTypes__default["default"].arrayOf(keyConfigPropType).isRequired
|
|
5628
|
-
});
|
|
5629
5521
|
class PopoverManager extends React__namespace.Component {
|
|
5630
5522
|
render() {
|
|
5631
5523
|
const {
|
|
@@ -5646,14 +5538,14 @@ class PopoverManager extends React__namespace.Component {
|
|
|
5646
5538
|
})) : null;
|
|
5647
5539
|
}
|
|
5648
5540
|
}
|
|
5649
|
-
_defineProperty(PopoverManager, "propTypes", {
|
|
5650
|
-
popover: popoverPropType
|
|
5651
|
-
});
|
|
5652
5541
|
|
|
5653
5542
|
// eslint-disable-next-line react/no-unsafe
|
|
5654
5543
|
class Keypad extends React__namespace.Component {
|
|
5655
5544
|
constructor() {
|
|
5656
5545
|
super(...arguments);
|
|
5546
|
+
_defineProperty(this, "_isMounted", void 0);
|
|
5547
|
+
_defineProperty(this, "_resizeTimeout", void 0);
|
|
5548
|
+
_defineProperty(this, "_container", void 0);
|
|
5657
5549
|
_defineProperty(this, "_computeContainer", () => {
|
|
5658
5550
|
const domNode = ReactDOM__default["default"].findDOMNode(this);
|
|
5659
5551
|
this._container = domNode.getBoundingClientRect();
|
|
@@ -5675,7 +5567,7 @@ class Keypad extends React__namespace.Component {
|
|
|
5675
5567
|
// Throttle resize events -- taken from:
|
|
5676
5568
|
// https://developer.mozilla.org/en-US/docs/Web/Events/resize
|
|
5677
5569
|
if (this._resizeTimeout == null) {
|
|
5678
|
-
this._resizeTimeout = setTimeout(() => {
|
|
5570
|
+
this._resizeTimeout = window.setTimeout(() => {
|
|
5679
5571
|
this._resizeTimeout = null;
|
|
5680
5572
|
if (this._isMounted) {
|
|
5681
5573
|
this._updateSizeAndPosition();
|
|
@@ -5717,9 +5609,13 @@ class Keypad extends React__namespace.Component {
|
|
|
5717
5609
|
return {
|
|
5718
5610
|
...rest,
|
|
5719
5611
|
initialBounds: {
|
|
5612
|
+
// @ts-expect-error TS2533
|
|
5720
5613
|
top: initialBounds.top - this._container.top,
|
|
5614
|
+
// @ts-expect-error TS2533
|
|
5721
5615
|
right: initialBounds.right - this._container.left,
|
|
5616
|
+
// @ts-expect-error TS2533
|
|
5722
5617
|
bottom: initialBounds.bottom - this._container.top,
|
|
5618
|
+
// @ts-expect-error TS2533
|
|
5723
5619
|
left: initialBounds.left - this._container.left,
|
|
5724
5620
|
width: initialBounds.width,
|
|
5725
5621
|
height: initialBounds.height
|
|
@@ -5733,7 +5629,12 @@ class Keypad extends React__namespace.Component {
|
|
|
5733
5629
|
const relativePopover = popover && {
|
|
5734
5630
|
...popover,
|
|
5735
5631
|
bounds: {
|
|
5736
|
-
bottom:
|
|
5632
|
+
bottom:
|
|
5633
|
+
// @ts-expect-error TS2533
|
|
5634
|
+
this._container.height - (
|
|
5635
|
+
// @ts-expect-error TS2533
|
|
5636
|
+
popover.bounds.bottom - this._container.top),
|
|
5637
|
+
// @ts-expect-error TS2533
|
|
5737
5638
|
left: popover.bounds.left - this._container.left,
|
|
5738
5639
|
width: popover.bounds.width
|
|
5739
5640
|
}
|
|
@@ -5748,21 +5649,9 @@ class Keypad extends React__namespace.Component {
|
|
|
5748
5649
|
}));
|
|
5749
5650
|
}
|
|
5750
5651
|
}
|
|
5751
|
-
_defineProperty(Keypad, "propTypes", {
|
|
5752
|
-
children: PropTypes__default["default"].oneOfType([PropTypes__default["default"].arrayOf(PropTypes__default["default"].node), PropTypes__default["default"].node]),
|
|
5753
|
-
removeEcho: PropTypes__default["default"].func.isRequired,
|
|
5754
|
-
style: PropTypes__default["default"].any,
|
|
5755
|
-
// The props below are injected by redux
|
|
5756
|
-
|
|
5757
|
-
// Whether the keypad is active, i.e., whether it should be rendered as
|
|
5758
|
-
// visible or invisible.
|
|
5759
|
-
active: PropTypes__default["default"].bool,
|
|
5760
|
-
echoes: PropTypes__default["default"].arrayOf(echoPropType).isRequired,
|
|
5761
|
-
popover: popoverPropType
|
|
5762
|
-
});
|
|
5763
5652
|
const mapStateToProps$4 = state => {
|
|
5764
5653
|
return {
|
|
5765
|
-
|
|
5654
|
+
echoes: state.echoes.echoes,
|
|
5766
5655
|
active: state.keypad.active,
|
|
5767
5656
|
popover: state.gestures.popover
|
|
5768
5657
|
};
|
|
@@ -6000,12 +5889,6 @@ class TwoPageKeypad extends React__namespace.Component {
|
|
|
6000
5889
|
}
|
|
6001
5890
|
}
|
|
6002
5891
|
}
|
|
6003
|
-
_defineProperty(TwoPageKeypad, "propTypes", {
|
|
6004
|
-
currentPage: PropTypes__default["default"].oneOf([0, 1]).isRequired,
|
|
6005
|
-
leftPage: PropTypes__default["default"].node.isRequired,
|
|
6006
|
-
paginationEnabled: PropTypes__default["default"].bool.isRequired,
|
|
6007
|
-
rightPage: PropTypes__default["default"].node.isRequired
|
|
6008
|
-
});
|
|
6009
5892
|
const styles$3 = aphrodite.StyleSheet.create({
|
|
6010
5893
|
keypad: {
|
|
6011
5894
|
// Set the background to light grey, so that when the user drags the
|
|
@@ -6029,6 +5912,9 @@ var TwoPageKeypad$1 = reactRedux.connect(mapStateToProps$3, null, null, {
|
|
|
6029
5912
|
forwardRef: true
|
|
6030
5913
|
})(TwoPageKeypad);
|
|
6031
5914
|
|
|
5915
|
+
/**
|
|
5916
|
+
* A keypad that includes all of the expression symbols.
|
|
5917
|
+
*/
|
|
6032
5918
|
const {
|
|
6033
5919
|
row: row$3,
|
|
6034
5920
|
column: column$1,
|
|
@@ -6037,11 +5923,16 @@ const {
|
|
|
6037
5923
|
roundedTopLeft: roundedTopLeft$2,
|
|
6038
5924
|
roundedTopRight: roundedTopRight$1
|
|
6039
5925
|
} = Styles;
|
|
5926
|
+
const expressionKeypadLayout = {
|
|
5927
|
+
rows: 4,
|
|
5928
|
+
columns: 5,
|
|
5929
|
+
numPages: 2,
|
|
5930
|
+
// Since we include a two-key popover in the top-right, when the popover
|
|
5931
|
+
// is visible, the keypad will expand to fill the equivalent of five
|
|
5932
|
+
// rows vertically.
|
|
5933
|
+
maxVisibleRows: 4
|
|
5934
|
+
};
|
|
6040
5935
|
class ExpressionKeypad extends React__namespace.Component {
|
|
6041
|
-
// Though we include an infinite-key popover in the bottom-left, it's
|
|
6042
|
-
// assumed that we don't need to accommodate cases in which that key
|
|
6043
|
-
// contains more than four children.
|
|
6044
|
-
|
|
6045
5936
|
render() {
|
|
6046
5937
|
const {
|
|
6047
5938
|
currentPage,
|
|
@@ -6095,8 +5986,7 @@ class ExpressionKeypad extends React__namespace.Component {
|
|
|
6095
5986
|
keyConfig: KeyConfigs.NUM_1,
|
|
6096
5987
|
borders: BorderStyles.BOTTOM
|
|
6097
5988
|
}), /*#__PURE__*/React__namespace.createElement(ManyKeypadButton, {
|
|
6098
|
-
keys: extraKeys
|
|
6099
|
-
borders: BorderStyles.NONE
|
|
5989
|
+
keys: extraKeys
|
|
6100
5990
|
})), /*#__PURE__*/React__namespace.createElement(View, {
|
|
6101
5991
|
style: [column$1, oneColumn]
|
|
6102
5992
|
}, /*#__PURE__*/React__namespace.createElement(TouchableKeypadButton$1, {
|
|
@@ -6234,18 +6124,6 @@ class ExpressionKeypad extends React__namespace.Component {
|
|
|
6234
6124
|
});
|
|
6235
6125
|
}
|
|
6236
6126
|
}
|
|
6237
|
-
_defineProperty(ExpressionKeypad, "propTypes", {
|
|
6238
|
-
currentPage: PropTypes__default["default"].number.isRequired,
|
|
6239
|
-
cursorContext: cursorContextPropType.isRequired,
|
|
6240
|
-
dynamicJumpOut: PropTypes__default["default"].bool,
|
|
6241
|
-
extraKeys: PropTypes__default["default"].arrayOf(keyIdPropType),
|
|
6242
|
-
roundTopLeft: PropTypes__default["default"].bool,
|
|
6243
|
-
roundTopRight: PropTypes__default["default"].bool
|
|
6244
|
-
});
|
|
6245
|
-
_defineProperty(ExpressionKeypad, "rows", 4);
|
|
6246
|
-
_defineProperty(ExpressionKeypad, "columns", 5);
|
|
6247
|
-
_defineProperty(ExpressionKeypad, "maxVisibleRows", 4);
|
|
6248
|
-
_defineProperty(ExpressionKeypad, "numPages", 2);
|
|
6249
6127
|
const styles$2 = aphrodite.StyleSheet.create({
|
|
6250
6128
|
// NOTE(charlie): These backgrounds are applied to as to fill in some
|
|
6251
6129
|
// unfortunate 'cracks' in the layout. However, not all keys in the first
|
|
@@ -6260,9 +6138,10 @@ const styles$2 = aphrodite.StyleSheet.create({
|
|
|
6260
6138
|
}
|
|
6261
6139
|
});
|
|
6262
6140
|
const mapStateToProps$2 = state => {
|
|
6141
|
+
var _state$input$cursor;
|
|
6263
6142
|
return {
|
|
6264
6143
|
currentPage: state.pager.currentPage,
|
|
6265
|
-
cursorContext: state.input.cursor.context,
|
|
6144
|
+
cursorContext: (_state$input$cursor = state.input.cursor) === null || _state$input$cursor === void 0 ? void 0 : _state$input$cursor.context,
|
|
6266
6145
|
dynamicJumpOut: !state.layout.navigationPadEnabled
|
|
6267
6146
|
};
|
|
6268
6147
|
};
|
|
@@ -6270,16 +6149,25 @@ var ExpressionKeypad$1 = reactRedux.connect(mapStateToProps$2, null, null, {
|
|
|
6270
6149
|
forwardRef: true
|
|
6271
6150
|
})(ExpressionKeypad);
|
|
6272
6151
|
|
|
6152
|
+
/**
|
|
6153
|
+
* A keypad that includes the digits, as well as the symbols required to deal
|
|
6154
|
+
* with fractions, decimals, and percents.
|
|
6155
|
+
*/
|
|
6273
6156
|
const {
|
|
6274
6157
|
row: row$2,
|
|
6275
6158
|
roundedTopLeft: roundedTopLeft$1,
|
|
6276
6159
|
roundedTopRight
|
|
6277
6160
|
} = Styles;
|
|
6278
|
-
|
|
6161
|
+
const fractionKeypadLayout = {
|
|
6162
|
+
rows: 4,
|
|
6163
|
+
columns: 4,
|
|
6164
|
+
numPages: 1,
|
|
6279
6165
|
// Since we include a two-key popover in the top-right, when the popover
|
|
6280
6166
|
// is visible, the keypad will expand to fill the equivalent of five
|
|
6281
6167
|
// rows vertically.
|
|
6282
|
-
|
|
6168
|
+
maxVisibleRows: 5
|
|
6169
|
+
};
|
|
6170
|
+
class FractionKeypad extends React__namespace.Component {
|
|
6283
6171
|
render() {
|
|
6284
6172
|
const {
|
|
6285
6173
|
cursorContext,
|
|
@@ -6382,35 +6270,306 @@ class FractionKeypad extends React__namespace.Component {
|
|
|
6382
6270
|
borders: BorderStyles.LEFT
|
|
6383
6271
|
})));
|
|
6384
6272
|
}
|
|
6385
|
-
}
|
|
6386
|
-
|
|
6387
|
-
|
|
6388
|
-
|
|
6389
|
-
|
|
6390
|
-
|
|
6391
|
-
}
|
|
6392
|
-
|
|
6393
|
-
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6273
|
+
}
|
|
6274
|
+
const mapStateToProps$1 = state => {
|
|
6275
|
+
var _state$input$cursor;
|
|
6276
|
+
return {
|
|
6277
|
+
cursorContext: (_state$input$cursor = state.input.cursor) === null || _state$input$cursor === void 0 ? void 0 : _state$input$cursor.context,
|
|
6278
|
+
dynamicJumpOut: !state.layout.navigationPadEnabled
|
|
6279
|
+
};
|
|
6280
|
+
};
|
|
6281
|
+
var FractionKeypad$1 = reactRedux.connect(mapStateToProps$1, null, null, {
|
|
6282
|
+
forwardRef: true
|
|
6283
|
+
})(FractionKeypad);
|
|
6284
|
+
|
|
6285
|
+
const defaultKeypadType = KeypadTypes.EXPRESSION;
|
|
6286
|
+
const keypadForType = {
|
|
6287
|
+
[KeypadTypes.FRACTION]: fractionKeypadLayout,
|
|
6288
|
+
[KeypadTypes.EXPRESSION]: expressionKeypadLayout
|
|
6289
|
+
};
|
|
6290
|
+
|
|
6291
|
+
const initialKeypadState = {
|
|
6292
|
+
extraKeys: ["x", "y", Keys.THETA, Keys.PI],
|
|
6293
|
+
keypadType: defaultKeypadType,
|
|
6294
|
+
active: false
|
|
6295
|
+
};
|
|
6296
|
+
const keypadReducer = function () {
|
|
6297
|
+
let state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialKeypadState;
|
|
6298
|
+
let action = arguments.length > 1 ? arguments[1] : undefined;
|
|
6299
|
+
switch (action.type) {
|
|
6300
|
+
case "DismissKeypad":
|
|
6301
|
+
return {
|
|
6302
|
+
...state,
|
|
6303
|
+
active: false
|
|
6304
|
+
};
|
|
6305
|
+
case "ActivateKeypad":
|
|
6306
|
+
return {
|
|
6307
|
+
...state,
|
|
6308
|
+
active: true
|
|
6309
|
+
};
|
|
6310
|
+
case "ConfigureKeypad":
|
|
6311
|
+
return {
|
|
6312
|
+
...state,
|
|
6313
|
+
// Default `extraKeys` to the empty array.
|
|
6314
|
+
extraKeys: [],
|
|
6315
|
+
...action.configuration
|
|
6316
|
+
};
|
|
6317
|
+
case "PressKey":
|
|
6318
|
+
const keyConfig = KeyConfigs[action.key];
|
|
6319
|
+
// NOTE(charlie): Our keypad system operates by triggering key
|
|
6320
|
+
// presses with key IDs in a dumb manner, such that the keys
|
|
6321
|
+
// don't know what they can do--instead, the store is
|
|
6322
|
+
// responsible for interpreting key presses and triggering the
|
|
6323
|
+
// right actions when they occur. Hence, we figure off a
|
|
6324
|
+
// dismissal here rather than dispatching a dismiss action in
|
|
6325
|
+
// the first place.
|
|
6326
|
+
if (keyConfig.id === Keys.DISMISS) {
|
|
6327
|
+
return keypadReducer(state, {
|
|
6328
|
+
type: "DismissKeypad"
|
|
6329
|
+
});
|
|
6330
|
+
}
|
|
6331
|
+
return state;
|
|
6332
|
+
default:
|
|
6333
|
+
return state;
|
|
6334
|
+
}
|
|
6335
|
+
};
|
|
6336
|
+
|
|
6337
|
+
/**
|
|
6338
|
+
* An algorithm for computing the appropriate layout parameters for the keypad,
|
|
6339
|
+
* including the size of the buttons and whether or not to render fullscreen,
|
|
6340
|
+
* taking into account a number of factors including the size of the screen, the
|
|
6341
|
+
* orientation of the screen, the presence of browser chrome, the presence of
|
|
6342
|
+
* other exercise-related chrome, the size of the input box, the parameters that
|
|
6343
|
+
* define the keypad (i.e., the number of rows, columns, and pages), and so
|
|
6344
|
+
* forth.
|
|
6345
|
+
*
|
|
6346
|
+
* The computations herein make some strong assumptions about the sizes of
|
|
6347
|
+
* various other elements and the situations under which they will be visible
|
|
6348
|
+
* (e.g., browser chrome). However, this is just a heuristic--it's not crucial
|
|
6349
|
+
* that our buttons are sized in a pixel-perfect manner, but rather, that we
|
|
6350
|
+
* make a balanced use of space.
|
|
6351
|
+
*
|
|
6352
|
+
* Note that one goal of the algorithm is to avoid resizing the keypad in the
|
|
6353
|
+
* face of dynamic browser chrome. In order to avoid that awkwardness, we tend
|
|
6354
|
+
* to be conservative in our measurements and make things smaller than they
|
|
6355
|
+
* might need to be.
|
|
6356
|
+
*/
|
|
6357
|
+
const minButtonHeight = 48;
|
|
6358
|
+
const maxButtonSize = 64;
|
|
6359
|
+
const minSpaceAboveKeypad = 32;
|
|
6360
|
+
|
|
6361
|
+
// These values are taken from an iPhone 5, but should be consistent with the
|
|
6362
|
+
// iPhone 4 as well. Regardless, these are meant to be representative of the
|
|
6363
|
+
// possible types of browser chrome that could appear in various context, rather
|
|
6364
|
+
// than pixel-perfect for every device.
|
|
6365
|
+
const safariNavBarWhenShrunk = 44;
|
|
6366
|
+
const safariNavBarWhenExpanded = 64;
|
|
6367
|
+
const safariToolbar = 44;
|
|
6368
|
+
|
|
6369
|
+
// In mobile Safari, the browser chrome is completely hidden in landscape,
|
|
6370
|
+
// though a shrunken navbar and full-sized toolbar on scroll. In portrait, the
|
|
6371
|
+
// shrunken navbar is always visible, but expands on scroll (and the toolbar
|
|
6372
|
+
// appears as well).
|
|
6373
|
+
const maxLandscapeBrowserChrome = safariNavBarWhenShrunk + safariToolbar;
|
|
6374
|
+
const maxPortraitBrowserChrome = safariToolbar + (safariNavBarWhenExpanded - safariNavBarWhenShrunk);
|
|
6375
|
+
|
|
6376
|
+
// This represents the 'worst case' aspect ratio that we care about (for
|
|
6377
|
+
// portrait layouts). It's taken from the iPhone 4. The height is computed by
|
|
6378
|
+
// taking the height of the device and removing the persistent, shrunken navbar.
|
|
6379
|
+
// (We don't need to account for the expanded navbar, since we include the
|
|
6380
|
+
// difference when reserving space above the keypad.)
|
|
6381
|
+
const worstCaseAspectRatio = 320 / (480 - safariNavBarWhenShrunk);
|
|
6382
|
+
const computeLayoutParameters = (_ref, _ref2, _ref3, _ref4) => {
|
|
6383
|
+
let {
|
|
6384
|
+
numColumns,
|
|
6385
|
+
numMaxVisibleRows,
|
|
6386
|
+
numPages
|
|
6387
|
+
} = _ref;
|
|
6388
|
+
let {
|
|
6389
|
+
pageWidthPx,
|
|
6390
|
+
pageHeightPx
|
|
6391
|
+
} = _ref2;
|
|
6392
|
+
let {
|
|
6393
|
+
deviceOrientation,
|
|
6394
|
+
deviceType
|
|
6395
|
+
} = _ref3;
|
|
6396
|
+
let {
|
|
6397
|
+
navigationPadEnabled,
|
|
6398
|
+
paginationEnabled,
|
|
6399
|
+
toolbarEnabled
|
|
6400
|
+
} = _ref4;
|
|
6401
|
+
// First, compute some values that will be used in multiple computations.
|
|
6402
|
+
const effectiveNumColumns = paginationEnabled ? numColumns : numColumns * numPages;
|
|
6403
|
+
|
|
6404
|
+
// Then, compute the button dimensions based on the provided parameters.
|
|
6405
|
+
let buttonDimensions;
|
|
6406
|
+
if (deviceType === DeviceTypes.PHONE) {
|
|
6407
|
+
const isLandscape = deviceOrientation === DeviceOrientations.LANDSCAPE;
|
|
6408
|
+
|
|
6409
|
+
// In many cases, the browser chrome will already have been factored
|
|
6410
|
+
// into `pageHeightPx`. But we have no way of knowing if that's
|
|
6411
|
+
// the case or not. As such, we take a conservative approach and
|
|
6412
|
+
// assume that the chrome is _never_ included in `pageHeightPx`.
|
|
6413
|
+
const browserChromeHeight = isLandscape ? maxLandscapeBrowserChrome : maxPortraitBrowserChrome;
|
|
6414
|
+
|
|
6415
|
+
// Count up all the space that we need to reserve on the page.
|
|
6416
|
+
// Namely, we need to account for:
|
|
6417
|
+
// 1. Space between the keypad and the top of the page.
|
|
6418
|
+
// 2. The presence of the exercise toolbar.
|
|
6419
|
+
// 3. The presence of the view pager indicator.
|
|
6420
|
+
// 4. Any browser chrome that may appear later.
|
|
6421
|
+
const reservedSpace = minSpaceAboveKeypad + browserChromeHeight + (toolbarEnabled ? toolbarHeightPx : 0) + (paginationEnabled ? pageIndicatorHeightPx : 0);
|
|
6422
|
+
|
|
6423
|
+
// Next, compute the effective width and height. We can use the page
|
|
6424
|
+
// width as the effective width. For the height, though, we take
|
|
6425
|
+
// another conservative measure when in portrait by assuming that
|
|
6426
|
+
// the device has the worst possible aspect ratio. In other words,
|
|
6427
|
+
// we ignore the device height in portrait and assume the worst.
|
|
6428
|
+
// This prevents the keypad from changing size when browser chrome
|
|
6429
|
+
// appears and disappears.
|
|
6430
|
+
const effectiveWidth = pageWidthPx;
|
|
6431
|
+
const effectiveHeight = isLandscape ? pageHeightPx : pageWidthPx / worstCaseAspectRatio;
|
|
6432
|
+
const maxKeypadHeight = effectiveHeight - reservedSpace;
|
|
6433
|
+
|
|
6434
|
+
// Finally, compute the button height and width. In computing the
|
|
6435
|
+
// height, accommodate for the maximum number of rows that will ever be
|
|
6436
|
+
// visible (since the toggling of popovers can increase the number of
|
|
6437
|
+
// visible rows).
|
|
6438
|
+
const buttonHeightPx = Math.max(Math.min(maxKeypadHeight / numMaxVisibleRows, maxButtonSize), minButtonHeight);
|
|
6439
|
+
let buttonWidthPx;
|
|
6440
|
+
if (numPages > 1) {
|
|
6441
|
+
const effectiveNumColumns = paginationEnabled ? numColumns : numColumns * numPages;
|
|
6442
|
+
buttonWidthPx = effectiveWidth / effectiveNumColumns;
|
|
6443
|
+
} else {
|
|
6444
|
+
buttonWidthPx = isLandscape ? maxButtonSize : effectiveWidth / numColumns;
|
|
6445
|
+
}
|
|
6446
|
+
buttonDimensions = {
|
|
6447
|
+
widthPx: buttonWidthPx,
|
|
6448
|
+
heightPx: buttonHeightPx
|
|
6449
|
+
};
|
|
6450
|
+
} else if (deviceType === DeviceTypes.TABLET) {
|
|
6451
|
+
buttonDimensions = {
|
|
6452
|
+
widthPx: maxButtonSize,
|
|
6453
|
+
heightPx: maxButtonSize
|
|
6454
|
+
};
|
|
6455
|
+
} else {
|
|
6456
|
+
throw new Error("Invalid device type: " + deviceType);
|
|
6457
|
+
}
|
|
6458
|
+
|
|
6459
|
+
// Finally, determine whether the keypad should be rendered in the
|
|
6460
|
+
// fullscreen layout by determining its resultant width.
|
|
6461
|
+
const numSeparators = (navigationPadEnabled ? 1 : 0) + (!paginationEnabled ? numPages - 1 : 0);
|
|
6462
|
+
const keypadWidth = effectiveNumColumns * buttonDimensions.widthPx + (navigationPadEnabled ? navigationPadWidthPx : 0) + numSeparators * innerBorderWidthPx;
|
|
6397
6463
|
return {
|
|
6398
|
-
|
|
6399
|
-
|
|
6464
|
+
buttonDimensions,
|
|
6465
|
+
layoutMode: keypadWidth >= pageWidthPx ? LayoutModes.FULLSCREEN : LayoutModes.COMPACT
|
|
6400
6466
|
};
|
|
6401
6467
|
};
|
|
6402
|
-
|
|
6403
|
-
|
|
6404
|
-
|
|
6468
|
+
|
|
6469
|
+
const initialLayoutState = {
|
|
6470
|
+
gridDimensions: {
|
|
6471
|
+
numRows: keypadForType[defaultKeypadType].rows,
|
|
6472
|
+
numColumns: keypadForType[defaultKeypadType].columns,
|
|
6473
|
+
numMaxVisibleRows: keypadForType[defaultKeypadType].maxVisibleRows,
|
|
6474
|
+
numPages: keypadForType[defaultKeypadType].numPages
|
|
6475
|
+
},
|
|
6476
|
+
buttonDimensions: {
|
|
6477
|
+
widthPx: 48,
|
|
6478
|
+
heightPx: 48
|
|
6479
|
+
},
|
|
6480
|
+
pageDimensions: {
|
|
6481
|
+
pageWidthPx: 0,
|
|
6482
|
+
pageHeightPx: 0
|
|
6483
|
+
},
|
|
6484
|
+
layoutMode: LayoutModes.FULLSCREEN,
|
|
6485
|
+
paginationEnabled: false,
|
|
6486
|
+
navigationPadEnabled: false
|
|
6487
|
+
};
|
|
6405
6488
|
|
|
6406
6489
|
/**
|
|
6407
|
-
*
|
|
6408
|
-
*
|
|
6409
|
-
* Velocity is computed by smoothing linearly over the gestures that have
|
|
6410
|
-
* occurred in the last 100 milliseconds.
|
|
6490
|
+
* Compute the additional layout state based on the provided page and grid
|
|
6491
|
+
* dimensions.
|
|
6411
6492
|
*/
|
|
6493
|
+
const layoutParametersForDimensions = (pageDimensions, gridDimensions) => {
|
|
6494
|
+
const {
|
|
6495
|
+
pageWidthPx,
|
|
6496
|
+
pageHeightPx
|
|
6497
|
+
} = pageDimensions;
|
|
6498
|
+
|
|
6499
|
+
// Determine the device type and orientation.
|
|
6500
|
+
const deviceOrientation = pageWidthPx > pageHeightPx ? DeviceOrientations.LANDSCAPE : DeviceOrientations.PORTRAIT;
|
|
6501
|
+
const deviceType = Math.min(pageWidthPx, pageHeightPx) > tabletCutoffPx ? DeviceTypes.TABLET : DeviceTypes.PHONE;
|
|
6502
|
+
|
|
6503
|
+
// Using that information, make some decisions (or assumptions)
|
|
6504
|
+
// about the resulting layout.
|
|
6505
|
+
const navigationPadEnabled = deviceType === DeviceTypes.TABLET;
|
|
6506
|
+
const paginationEnabled = deviceType === DeviceTypes.PHONE && deviceOrientation === DeviceOrientations.PORTRAIT;
|
|
6507
|
+
const deviceInfo = {
|
|
6508
|
+
deviceOrientation,
|
|
6509
|
+
deviceType
|
|
6510
|
+
};
|
|
6511
|
+
const layoutOptions = {
|
|
6512
|
+
navigationPadEnabled,
|
|
6513
|
+
paginationEnabled,
|
|
6514
|
+
// HACK(charlie): It's not great that we're making assumptions about
|
|
6515
|
+
// the toolbar (which is rendered by webapp, and should always be
|
|
6516
|
+
// visible and anchored to the bottom of the page for phone and
|
|
6517
|
+
// tablet exercises). But this is primarily a heuristic (the goal is
|
|
6518
|
+
// to preserve a 'good' amount of space between the top of the
|
|
6519
|
+
// keypad and the top of the page) so we afford to have some margin
|
|
6520
|
+
// of error.
|
|
6521
|
+
toolbarEnabled: true
|
|
6522
|
+
};
|
|
6523
|
+
return {
|
|
6524
|
+
...computeLayoutParameters(gridDimensions, pageDimensions, deviceInfo, layoutOptions),
|
|
6525
|
+
// Pass along some of the layout information, so that other
|
|
6526
|
+
// components in the heirarchy can adapt appropriately.
|
|
6527
|
+
navigationPadEnabled,
|
|
6528
|
+
paginationEnabled
|
|
6529
|
+
};
|
|
6530
|
+
};
|
|
6531
|
+
const layoutReducer = function () {
|
|
6532
|
+
let state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialLayoutState;
|
|
6533
|
+
let action = arguments.length > 1 ? arguments[1] : undefined;
|
|
6534
|
+
switch (action.type) {
|
|
6535
|
+
case "ConfigureKeypad":
|
|
6536
|
+
const {
|
|
6537
|
+
keypadType
|
|
6538
|
+
} = action.configuration;
|
|
6539
|
+
const gridDimensions = {
|
|
6540
|
+
numRows: keypadForType[keypadType].rows,
|
|
6541
|
+
numColumns: keypadForType[keypadType].columns,
|
|
6542
|
+
numMaxVisibleRows: keypadForType[keypadType].maxVisibleRows,
|
|
6543
|
+
numPages: keypadForType[keypadType].numPages
|
|
6544
|
+
};
|
|
6545
|
+
return {
|
|
6546
|
+
...state,
|
|
6547
|
+
...layoutParametersForDimensions(state.pageDimensions, gridDimensions),
|
|
6548
|
+
gridDimensions
|
|
6549
|
+
};
|
|
6550
|
+
case "SetPageSize":
|
|
6551
|
+
const {
|
|
6552
|
+
pageWidthPx,
|
|
6553
|
+
pageHeightPx
|
|
6554
|
+
} = action;
|
|
6555
|
+
const pageDimensions = {
|
|
6556
|
+
pageWidthPx,
|
|
6557
|
+
pageHeightPx
|
|
6558
|
+
};
|
|
6559
|
+
return {
|
|
6560
|
+
...state,
|
|
6561
|
+
...layoutParametersForDimensions(pageDimensions, state.gridDimensions),
|
|
6562
|
+
pageDimensions
|
|
6563
|
+
};
|
|
6564
|
+
default:
|
|
6565
|
+
return state;
|
|
6566
|
+
}
|
|
6567
|
+
};
|
|
6568
|
+
|
|
6412
6569
|
class VelocityTracker {
|
|
6413
6570
|
constructor(options) {
|
|
6571
|
+
_defineProperty(this, "options", void 0);
|
|
6572
|
+
_defineProperty(this, "_events", void 0);
|
|
6414
6573
|
this.options = {
|
|
6415
6574
|
velocityTimeout: 100,
|
|
6416
6575
|
...options
|
|
@@ -6474,149 +6633,48 @@ class VelocityTracker {
|
|
|
6474
6633
|
}
|
|
6475
6634
|
}
|
|
6476
6635
|
|
|
6477
|
-
|
|
6478
|
-
|
|
6479
|
-
|
|
6636
|
+
// We default to the right-most page. This is done so-as to enforce a
|
|
6637
|
+
// consistent orientation between the view pager layout and the flattened
|
|
6638
|
+
// layout, where our default page appears on the far right.
|
|
6639
|
+
const getDefaultPage = numPages => numPages - 1;
|
|
6640
|
+
const initialPagerState = {
|
|
6641
|
+
animateToPosition: false,
|
|
6642
|
+
currentPage: getDefaultPage(keypadForType[defaultKeypadType].numPages),
|
|
6643
|
+
// The cumulative differential in the horizontal direction for the
|
|
6644
|
+
// current swipe.
|
|
6645
|
+
dx: 0,
|
|
6646
|
+
numPages: keypadForType[defaultKeypadType].numPages,
|
|
6647
|
+
pageWidthPx: 0,
|
|
6648
|
+
velocityTracker: new VelocityTracker()
|
|
6480
6649
|
};
|
|
6481
|
-
const
|
|
6482
|
-
|
|
6483
|
-
|
|
6484
|
-
|
|
6485
|
-
|
|
6486
|
-
|
|
6487
|
-
|
|
6488
|
-
|
|
6489
|
-
|
|
6490
|
-
|
|
6491
|
-
|
|
6492
|
-
|
|
6493
|
-
|
|
6494
|
-
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
};
|
|
6507
|
-
}
|
|
6508
|
-
|
|
6509
|
-
// TODO(kevinb) get state from MathQuill and store it?
|
|
6510
|
-
return state;
|
|
6511
|
-
case "SetCursor":
|
|
6512
|
-
return {
|
|
6513
|
-
...state,
|
|
6514
|
-
cursor: action.cursor
|
|
6515
|
-
};
|
|
6516
|
-
default:
|
|
6517
|
-
return state;
|
|
6518
|
-
}
|
|
6519
|
-
};
|
|
6520
|
-
const defaultKeypadType = KeypadTypes.EXPRESSION;
|
|
6521
|
-
const initialKeypadState = {
|
|
6522
|
-
extraKeys: ["x", "y", Keys.THETA, Keys.PI],
|
|
6523
|
-
keypadType: defaultKeypadType,
|
|
6524
|
-
active: false
|
|
6525
|
-
};
|
|
6526
|
-
const keypadReducer = function () {
|
|
6527
|
-
let state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialKeypadState;
|
|
6528
|
-
let action = arguments.length > 1 ? arguments[1] : undefined;
|
|
6529
|
-
switch (action.type) {
|
|
6530
|
-
case "DismissKeypad":
|
|
6531
|
-
return {
|
|
6532
|
-
...state,
|
|
6533
|
-
active: false
|
|
6534
|
-
};
|
|
6535
|
-
case "ActivateKeypad":
|
|
6536
|
-
return {
|
|
6537
|
-
...state,
|
|
6538
|
-
active: true
|
|
6539
|
-
};
|
|
6540
|
-
case "ConfigureKeypad":
|
|
6541
|
-
return {
|
|
6542
|
-
...state,
|
|
6543
|
-
// Default `extraKeys` to the empty array.
|
|
6544
|
-
extraKeys: [],
|
|
6545
|
-
// @ts-expect-error [FEI-5003] - TS2339 - Property 'configuration' does not exist on type '{ type: string; }'.
|
|
6546
|
-
...action.configuration
|
|
6547
|
-
};
|
|
6548
|
-
case "PressKey":
|
|
6549
|
-
// @ts-expect-error [FEI-5003] - TS2339 - Property 'key' does not exist on type '{ type: string; }'.
|
|
6550
|
-
const keyConfig = KeyConfigs[action.key];
|
|
6551
|
-
// NOTE(charlie): Our keypad system operates by triggering key
|
|
6552
|
-
// presses with key IDs in a dumb manner, such that the keys
|
|
6553
|
-
// don't know what they can do--instead, the store is
|
|
6554
|
-
// responsible for interpreting key presses and triggering the
|
|
6555
|
-
// right actions when they occur. Hence, we figure off a
|
|
6556
|
-
// dismissal here rather than dispatching a dismiss action in
|
|
6557
|
-
// the first place.
|
|
6558
|
-
if (keyConfig.id === Keys.DISMISS) {
|
|
6559
|
-
return keypadReducer(state, {
|
|
6560
|
-
type: "DismissKeypad"
|
|
6561
|
-
});
|
|
6562
|
-
}
|
|
6563
|
-
return state;
|
|
6564
|
-
default:
|
|
6565
|
-
return state;
|
|
6566
|
-
}
|
|
6567
|
-
};
|
|
6650
|
+
const pagerReducer = function () {
|
|
6651
|
+
let state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialPagerState;
|
|
6652
|
+
let action = arguments.length > 1 ? arguments[1] : undefined;
|
|
6653
|
+
switch (action.type) {
|
|
6654
|
+
case "ConfigureKeypad":
|
|
6655
|
+
const {
|
|
6656
|
+
keypadType
|
|
6657
|
+
} = action.configuration;
|
|
6658
|
+
const {
|
|
6659
|
+
numPages
|
|
6660
|
+
} = keypadForType[keypadType];
|
|
6661
|
+
return {
|
|
6662
|
+
...state,
|
|
6663
|
+
numPages,
|
|
6664
|
+
animateToPosition: false,
|
|
6665
|
+
currentPage: getDefaultPage(numPages),
|
|
6666
|
+
dx: 0
|
|
6667
|
+
};
|
|
6668
|
+
case "SetPageSize":
|
|
6669
|
+
return {
|
|
6670
|
+
...state,
|
|
6671
|
+
pageWidthPx: action.pageWidthPx
|
|
6672
|
+
};
|
|
6673
|
+
case "PressKey":
|
|
6674
|
+
const keyConfig = KeyConfigs[action.key];
|
|
6568
6675
|
|
|
6569
|
-
|
|
6570
|
-
|
|
6571
|
-
// layout, where our default page appears on the far right.
|
|
6572
|
-
const getDefaultPage = numPages => numPages - 1;
|
|
6573
|
-
const initialPagerState = {
|
|
6574
|
-
animateToPosition: false,
|
|
6575
|
-
currentPage: getDefaultPage(keypadForType[defaultKeypadType].numPages),
|
|
6576
|
-
// The cumulative differential in the horizontal direction for the
|
|
6577
|
-
// current swipe.
|
|
6578
|
-
dx: 0,
|
|
6579
|
-
numPages: keypadForType[defaultKeypadType].numPages,
|
|
6580
|
-
pageWidthPx: 0,
|
|
6581
|
-
velocityTracker: new VelocityTracker()
|
|
6582
|
-
};
|
|
6583
|
-
const pagerReducer = function () {
|
|
6584
|
-
let state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialPagerState;
|
|
6585
|
-
let action = arguments.length > 1 ? arguments[1] : undefined;
|
|
6586
|
-
switch (action.type) {
|
|
6587
|
-
case "ConfigureKeypad":
|
|
6588
|
-
// @ts-expect-error [FEI-5003] - TS2339 - Property 'configuration' does not exist on type '{ type: string; }'.
|
|
6589
|
-
const {
|
|
6590
|
-
keypadType
|
|
6591
|
-
} = action.configuration;
|
|
6592
|
-
const {
|
|
6593
|
-
numPages
|
|
6594
|
-
} = keypadForType[keypadType];
|
|
6595
|
-
return {
|
|
6596
|
-
...state,
|
|
6597
|
-
numPages,
|
|
6598
|
-
animateToPosition: false,
|
|
6599
|
-
currentPage: getDefaultPage(numPages),
|
|
6600
|
-
dx: 0
|
|
6601
|
-
};
|
|
6602
|
-
case "SetPageSize":
|
|
6603
|
-
return {
|
|
6604
|
-
...state,
|
|
6605
|
-
// @ts-expect-error [FEI-5003] - TS2339 - Property 'pageWidthPx' does not exist on type '{ type: string; }'.
|
|
6606
|
-
pageWidthPx: action.pageWidthPx
|
|
6607
|
-
};
|
|
6608
|
-
case "PressKey":
|
|
6609
|
-
// @ts-expect-error [FEI-5003] - TS2339 - Property 'key' does not exist on type '{ type: string; }'.
|
|
6610
|
-
const keyConfig = KeyConfigs[action.key];
|
|
6611
|
-
|
|
6612
|
-
// Reset the keypad page if the user performs a math operation.
|
|
6613
|
-
if (keyConfig.type === KeyTypes.VALUE || keyConfig.type === KeyTypes.OPERATOR) {
|
|
6614
|
-
return pagerReducer(state, {
|
|
6615
|
-
type: "ResetKeypadPage"
|
|
6616
|
-
});
|
|
6617
|
-
}
|
|
6618
|
-
return state;
|
|
6619
|
-
case "ResetKeypadPage":
|
|
6676
|
+
// Reset the keypad page if the user performs a math operation.
|
|
6677
|
+
if (keyConfig.type === KeyTypes.VALUE || keyConfig.type === KeyTypes.OPERATOR) {
|
|
6620
6678
|
return {
|
|
6621
6679
|
...state,
|
|
6622
6680
|
animateToPosition: true,
|
|
@@ -6624,7 +6682,32 @@ const createStore = () => {
|
|
|
6624
6682
|
currentPage: getDefaultPage(state.numPages),
|
|
6625
6683
|
dx: 0
|
|
6626
6684
|
};
|
|
6627
|
-
|
|
6685
|
+
}
|
|
6686
|
+
return state;
|
|
6687
|
+
case "OnSwipeChange":
|
|
6688
|
+
state.velocityTracker.push(action.dx);
|
|
6689
|
+
return {
|
|
6690
|
+
...state,
|
|
6691
|
+
animateToPosition: false,
|
|
6692
|
+
dx: action.dx
|
|
6693
|
+
};
|
|
6694
|
+
case "OnSwipeEnd":
|
|
6695
|
+
const {
|
|
6696
|
+
pageWidthPx,
|
|
6697
|
+
velocityTracker
|
|
6698
|
+
} = state;
|
|
6699
|
+
const {
|
|
6700
|
+
dx
|
|
6701
|
+
} = action;
|
|
6702
|
+
const velocity = velocityTracker.getVelocity();
|
|
6703
|
+
|
|
6704
|
+
// NOTE(charlie): These will need refinement. The velocity comes
|
|
6705
|
+
// from Framer.
|
|
6706
|
+
const minFlingVelocity = 0.1;
|
|
6707
|
+
const minFlingDistance = 10;
|
|
6708
|
+
const shouldPageRight = dx < -pageWidthPx / 2 || velocity < -minFlingVelocity && dx < -minFlingDistance;
|
|
6709
|
+
const shouldPageLeft = dx > pageWidthPx / 2 || velocity > minFlingVelocity && dx > minFlingDistance;
|
|
6710
|
+
if (shouldPageRight) {
|
|
6628
6711
|
const nextPage = Math.min(state.currentPage + 1, state.numPages - 1);
|
|
6629
6712
|
return {
|
|
6630
6713
|
...state,
|
|
@@ -6632,7 +6715,7 @@ const createStore = () => {
|
|
|
6632
6715
|
currentPage: nextPage,
|
|
6633
6716
|
dx: 0
|
|
6634
6717
|
};
|
|
6635
|
-
|
|
6718
|
+
} else if (shouldPageLeft) {
|
|
6636
6719
|
const prevPage = Math.max(state.currentPage - 1, 0);
|
|
6637
6720
|
return {
|
|
6638
6721
|
...state,
|
|
@@ -6640,79 +6723,35 @@ const createStore = () => {
|
|
|
6640
6723
|
currentPage: prevPage,
|
|
6641
6724
|
dx: 0
|
|
6642
6725
|
};
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
state
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
|
|
6650
|
-
|
|
6651
|
-
|
|
6652
|
-
|
|
6653
|
-
|
|
6654
|
-
|
|
6655
|
-
|
|
6656
|
-
|
|
6657
|
-
// @ts-expect-error [FEI-5003] - TS2339 - Property 'dx' does not exist on type '{ type: string; }'.
|
|
6658
|
-
const {
|
|
6659
|
-
dx
|
|
6660
|
-
} = action;
|
|
6661
|
-
const velocity = velocityTracker.getVelocity();
|
|
6662
|
-
|
|
6663
|
-
// NOTE(charlie): These will need refinement. The velocity comes
|
|
6664
|
-
// from Framer.
|
|
6665
|
-
const minFlingVelocity = 0.1;
|
|
6666
|
-
const minFlingDistance = 10;
|
|
6667
|
-
const shouldPageRight = dx < -pageWidthPx / 2 || velocity < -minFlingVelocity && dx < -minFlingDistance;
|
|
6668
|
-
const shouldPageLeft = dx > pageWidthPx / 2 || velocity > minFlingVelocity && dx > minFlingDistance;
|
|
6669
|
-
if (shouldPageRight) {
|
|
6670
|
-
return pagerReducer(state, {
|
|
6671
|
-
type: "PageKeypadRight"
|
|
6672
|
-
});
|
|
6673
|
-
} else if (shouldPageLeft) {
|
|
6674
|
-
return pagerReducer(state, {
|
|
6675
|
-
type: "PageKeypadLeft"
|
|
6676
|
-
});
|
|
6677
|
-
}
|
|
6678
|
-
return {
|
|
6679
|
-
...state,
|
|
6680
|
-
animateToPosition: true,
|
|
6681
|
-
dx: 0
|
|
6682
|
-
};
|
|
6683
|
-
default:
|
|
6684
|
-
return state;
|
|
6685
|
-
}
|
|
6686
|
-
};
|
|
6726
|
+
}
|
|
6727
|
+
return {
|
|
6728
|
+
...state,
|
|
6729
|
+
animateToPosition: true,
|
|
6730
|
+
dx: 0
|
|
6731
|
+
};
|
|
6732
|
+
default:
|
|
6733
|
+
return state;
|
|
6734
|
+
}
|
|
6735
|
+
};
|
|
6736
|
+
|
|
6737
|
+
const createStore = () => {
|
|
6738
|
+
// TODO(matthewc)[LC-752]: gestureReducer can't be moved from this file
|
|
6739
|
+
// because it depends on `store` being in scope (see note below)
|
|
6687
6740
|
const createGestureManager = swipeEnabled => {
|
|
6688
6741
|
return new GestureManager({
|
|
6689
6742
|
swipeEnabled
|
|
6690
6743
|
}, {
|
|
6691
6744
|
onSwipeChange: dx => {
|
|
6692
|
-
store.dispatch(
|
|
6693
|
-
type: "OnSwipeChange",
|
|
6694
|
-
dx
|
|
6695
|
-
});
|
|
6745
|
+
store.dispatch(onSwipeChange(dx));
|
|
6696
6746
|
},
|
|
6697
6747
|
onSwipeEnd: dx => {
|
|
6698
|
-
store.dispatch(
|
|
6699
|
-
type: "OnSwipeEnd",
|
|
6700
|
-
dx
|
|
6701
|
-
});
|
|
6748
|
+
store.dispatch(onSwipeEnd(dx));
|
|
6702
6749
|
},
|
|
6703
6750
|
onActiveNodesChanged: activeNodes => {
|
|
6704
|
-
store.dispatch(
|
|
6705
|
-
type: "SetActiveNodes",
|
|
6706
|
-
activeNodes
|
|
6707
|
-
});
|
|
6751
|
+
store.dispatch(setActiveNodes(activeNodes));
|
|
6708
6752
|
},
|
|
6709
6753
|
onClick: (key, layoutProps, inPopover) => {
|
|
6710
|
-
store.dispatch(
|
|
6711
|
-
type: "PressKey",
|
|
6712
|
-
key,
|
|
6713
|
-
...layoutProps,
|
|
6714
|
-
inPopover
|
|
6715
|
-
});
|
|
6754
|
+
store.dispatch(pressKey(key, layoutProps.borders, layoutProps.initialBounds, inPopover));
|
|
6716
6755
|
}
|
|
6717
6756
|
}, [], [Keys.BACKSPACE, Keys.UP, Keys.RIGHT, Keys.DOWN, Keys.LEFT]);
|
|
6718
6757
|
};
|
|
@@ -6762,147 +6801,6 @@ const createStore = () => {
|
|
|
6762
6801
|
return state;
|
|
6763
6802
|
}
|
|
6764
6803
|
};
|
|
6765
|
-
|
|
6766
|
-
// Used to generate unique animation IDs for the echo animations. The actual
|
|
6767
|
-
// values are irrelevant as long as they are unique.
|
|
6768
|
-
let _lastAnimationId = 0;
|
|
6769
|
-
const initialEchoState = {
|
|
6770
|
-
echoes: []
|
|
6771
|
-
};
|
|
6772
|
-
const echoReducer = function () {
|
|
6773
|
-
let state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialEchoState;
|
|
6774
|
-
let action = arguments.length > 1 ? arguments[1] : undefined;
|
|
6775
|
-
switch (action.type) {
|
|
6776
|
-
case "PressKey":
|
|
6777
|
-
const keyConfig = KeyConfigs[action.key];
|
|
6778
|
-
|
|
6779
|
-
// Add in the echo animation if the user performs a math
|
|
6780
|
-
// operation.
|
|
6781
|
-
if (keyConfig.type === KeyTypes.VALUE || keyConfig.type === KeyTypes.OPERATOR) {
|
|
6782
|
-
return {
|
|
6783
|
-
...state,
|
|
6784
|
-
echoes: [...state.echoes, {
|
|
6785
|
-
animationId: "" + _lastAnimationId++,
|
|
6786
|
-
animationType: action.inPopover ? EchoAnimationTypes.LONG_FADE_ONLY : EchoAnimationTypes.FADE_ONLY,
|
|
6787
|
-
borders: action.borders,
|
|
6788
|
-
id: keyConfig.id,
|
|
6789
|
-
initialBounds: action.initialBounds
|
|
6790
|
-
}]
|
|
6791
|
-
};
|
|
6792
|
-
}
|
|
6793
|
-
return state;
|
|
6794
|
-
case "RemoveEcho":
|
|
6795
|
-
const remainingEchoes = state.echoes.filter(echo => {
|
|
6796
|
-
// @ts-expect-error [FEI-5003] - TS2339 - Property 'animationId' does not exist on type 'never'.
|
|
6797
|
-
return echo.animationId !== action.animationId;
|
|
6798
|
-
});
|
|
6799
|
-
return {
|
|
6800
|
-
...state,
|
|
6801
|
-
echoes: remainingEchoes
|
|
6802
|
-
};
|
|
6803
|
-
default:
|
|
6804
|
-
return state;
|
|
6805
|
-
}
|
|
6806
|
-
};
|
|
6807
|
-
const initialLayoutState = {
|
|
6808
|
-
gridDimensions: {
|
|
6809
|
-
numRows: keypadForType[defaultKeypadType].rows,
|
|
6810
|
-
numColumns: keypadForType[defaultKeypadType].columns,
|
|
6811
|
-
numMaxVisibleRows: keypadForType[defaultKeypadType].maxVisibleRows,
|
|
6812
|
-
numPages: keypadForType[defaultKeypadType].numPages
|
|
6813
|
-
},
|
|
6814
|
-
buttonDimensions: {
|
|
6815
|
-
widthPx: 48,
|
|
6816
|
-
heightPx: 48
|
|
6817
|
-
},
|
|
6818
|
-
pageDimensions: {
|
|
6819
|
-
pageWidthPx: 0,
|
|
6820
|
-
pageHeightPx: 0
|
|
6821
|
-
},
|
|
6822
|
-
layoutMode: LayoutModes.FULLSCREEN,
|
|
6823
|
-
paginationEnabled: false,
|
|
6824
|
-
navigationPadEnabled: false
|
|
6825
|
-
};
|
|
6826
|
-
|
|
6827
|
-
/**
|
|
6828
|
-
* Compute the additional layout state based on the provided page and grid
|
|
6829
|
-
* dimensions.
|
|
6830
|
-
*/
|
|
6831
|
-
const layoutParametersForDimensions = (pageDimensions, gridDimensions) => {
|
|
6832
|
-
const {
|
|
6833
|
-
pageWidthPx,
|
|
6834
|
-
pageHeightPx
|
|
6835
|
-
} = pageDimensions;
|
|
6836
|
-
|
|
6837
|
-
// Determine the device type and orientation.
|
|
6838
|
-
const deviceOrientation = pageWidthPx > pageHeightPx ? DeviceOrientations.LANDSCAPE : DeviceOrientations.PORTRAIT;
|
|
6839
|
-
const deviceType = Math.min(pageWidthPx, pageHeightPx) > tabletCutoffPx ? DeviceTypes.TABLET : DeviceTypes.PHONE;
|
|
6840
|
-
|
|
6841
|
-
// Using that information, make some decisions (or assumptions)
|
|
6842
|
-
// about the resulting layout.
|
|
6843
|
-
const navigationPadEnabled = deviceType === DeviceTypes.TABLET;
|
|
6844
|
-
const paginationEnabled = deviceType === DeviceTypes.PHONE && deviceOrientation === DeviceOrientations.PORTRAIT;
|
|
6845
|
-
const deviceInfo = {
|
|
6846
|
-
deviceOrientation,
|
|
6847
|
-
deviceType
|
|
6848
|
-
};
|
|
6849
|
-
const layoutOptions = {
|
|
6850
|
-
navigationPadEnabled,
|
|
6851
|
-
paginationEnabled,
|
|
6852
|
-
// HACK(charlie): It's not great that we're making assumptions about
|
|
6853
|
-
// the toolbar (which is rendered by webapp, and should always be
|
|
6854
|
-
// visible and anchored to the bottom of the page for phone and
|
|
6855
|
-
// tablet exercises). But this is primarily a heuristic (the goal is
|
|
6856
|
-
// to preserve a 'good' amount of space between the top of the
|
|
6857
|
-
// keypad and the top of the page) so we afford to have some margin
|
|
6858
|
-
// of error.
|
|
6859
|
-
toolbarEnabled: true
|
|
6860
|
-
};
|
|
6861
|
-
return {
|
|
6862
|
-
...computeLayoutParameters(gridDimensions, pageDimensions, deviceInfo, layoutOptions),
|
|
6863
|
-
// Pass along some of the layout information, so that other
|
|
6864
|
-
// components in the heirarchy can adapt appropriately.
|
|
6865
|
-
navigationPadEnabled,
|
|
6866
|
-
paginationEnabled
|
|
6867
|
-
};
|
|
6868
|
-
};
|
|
6869
|
-
const layoutReducer = function () {
|
|
6870
|
-
let state = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : initialLayoutState;
|
|
6871
|
-
let action = arguments.length > 1 ? arguments[1] : undefined;
|
|
6872
|
-
switch (action.type) {
|
|
6873
|
-
case "ConfigureKeypad":
|
|
6874
|
-
const {
|
|
6875
|
-
keypadType
|
|
6876
|
-
} = action.configuration;
|
|
6877
|
-
const gridDimensions = {
|
|
6878
|
-
numRows: keypadForType[keypadType].rows,
|
|
6879
|
-
numColumns: keypadForType[keypadType].columns,
|
|
6880
|
-
numMaxVisibleRows: keypadForType[keypadType].maxVisibleRows,
|
|
6881
|
-
numPages: keypadForType[keypadType].numPages
|
|
6882
|
-
};
|
|
6883
|
-
return {
|
|
6884
|
-
...state,
|
|
6885
|
-
...layoutParametersForDimensions(state.pageDimensions, gridDimensions),
|
|
6886
|
-
gridDimensions
|
|
6887
|
-
};
|
|
6888
|
-
case "SetPageSize":
|
|
6889
|
-
const {
|
|
6890
|
-
pageWidthPx,
|
|
6891
|
-
pageHeightPx
|
|
6892
|
-
} = action;
|
|
6893
|
-
const pageDimensions = {
|
|
6894
|
-
pageWidthPx,
|
|
6895
|
-
pageHeightPx
|
|
6896
|
-
};
|
|
6897
|
-
return {
|
|
6898
|
-
...state,
|
|
6899
|
-
...layoutParametersForDimensions(pageDimensions, state.gridDimensions),
|
|
6900
|
-
pageDimensions
|
|
6901
|
-
};
|
|
6902
|
-
default:
|
|
6903
|
-
return state;
|
|
6904
|
-
}
|
|
6905
|
-
};
|
|
6906
6804
|
const reducer = Redux__namespace.combineReducers({
|
|
6907
6805
|
input: inputReducer,
|
|
6908
6806
|
keypad: keypadReducer,
|
|
@@ -6920,6 +6818,10 @@ const createStore = () => {
|
|
|
6920
6818
|
return store;
|
|
6921
6819
|
};
|
|
6922
6820
|
|
|
6821
|
+
/**
|
|
6822
|
+
* A component that renders a navigation pad, which consists of an arrow for
|
|
6823
|
+
* each possible direction.
|
|
6824
|
+
*/
|
|
6923
6825
|
const {
|
|
6924
6826
|
row: row$1,
|
|
6925
6827
|
column,
|
|
@@ -6965,10 +6867,6 @@ class NavigationPad extends React__namespace.Component {
|
|
|
6965
6867
|
})));
|
|
6966
6868
|
}
|
|
6967
6869
|
}
|
|
6968
|
-
_defineProperty(NavigationPad, "propTypes", {
|
|
6969
|
-
roundTopLeft: PropTypes__default["default"].bool,
|
|
6970
|
-
style: PropTypes__default["default"].any
|
|
6971
|
-
});
|
|
6972
6870
|
const buttonSizePx = 48;
|
|
6973
6871
|
const borderRadiusPx = 4;
|
|
6974
6872
|
const borderWidthPx$1 = 1;
|
|
@@ -7027,11 +6925,12 @@ const {
|
|
|
7027
6925
|
centered,
|
|
7028
6926
|
fullWidth
|
|
7029
6927
|
} = Styles;
|
|
7030
|
-
|
|
7031
6928
|
// eslint-disable-next-line react/no-unsafe
|
|
7032
6929
|
class KeypadContainer extends React__namespace.Component {
|
|
7033
6930
|
constructor() {
|
|
7034
6931
|
super(...arguments);
|
|
6932
|
+
_defineProperty(this, "_resizeTimeout", void 0);
|
|
6933
|
+
_defineProperty(this, "hasMounted", void 0);
|
|
7035
6934
|
_defineProperty(this, "state", {
|
|
7036
6935
|
hasBeenActivated: false,
|
|
7037
6936
|
viewportWidth: "100vw"
|
|
@@ -7040,19 +6939,20 @@ class KeypadContainer extends React__namespace.Component {
|
|
|
7040
6939
|
// Throttle the resize callbacks.
|
|
7041
6940
|
// https://developer.mozilla.org/en-US/docs/Web/Events/resize
|
|
7042
6941
|
if (this._resizeTimeout == null) {
|
|
7043
|
-
this._resizeTimeout = setTimeout(() => {
|
|
6942
|
+
this._resizeTimeout = window.setTimeout(() => {
|
|
7044
6943
|
this._resizeTimeout = null;
|
|
7045
6944
|
this._onResize();
|
|
7046
6945
|
}, 66);
|
|
7047
6946
|
}
|
|
7048
6947
|
});
|
|
7049
6948
|
_defineProperty(this, "_onResize", () => {
|
|
6949
|
+
var _this$props$onPageSiz, _this$props;
|
|
7050
6950
|
// Whenever the page resizes, we need to force an update, as the button
|
|
7051
6951
|
// heights and keypad width are computed based on horizontal space.
|
|
7052
6952
|
this.setState({
|
|
7053
6953
|
viewportWidth: window.innerWidth
|
|
7054
6954
|
});
|
|
7055
|
-
this.props.onPageSizeChange(window.innerWidth, window.innerHeight);
|
|
6955
|
+
(_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);
|
|
7056
6956
|
});
|
|
7057
6957
|
_defineProperty(this, "renderKeypad", () => {
|
|
7058
6958
|
const {
|
|
@@ -7134,10 +7034,15 @@ class KeypadContainer extends React__namespace.Component {
|
|
|
7134
7034
|
// NOTE(charlie): We render the transforms as pure inline styles to
|
|
7135
7035
|
// avoid an Aphrodite bug in mobile Safari.
|
|
7136
7036
|
// See: https://github.com/Khan/aphrodite/issues/68.
|
|
7137
|
-
|
|
7138
|
-
...(active ? inlineStyles.active : inlineStyles.hidden)
|
|
7139
|
-
...(!active && !hasBeenActivated ? inlineStyles.invisible : {})
|
|
7037
|
+
let dynamicStyle = {
|
|
7038
|
+
...(active ? inlineStyles.active : inlineStyles.hidden)
|
|
7140
7039
|
};
|
|
7040
|
+
if (!active && !hasBeenActivated) {
|
|
7041
|
+
dynamicStyle = {
|
|
7042
|
+
...dynamicStyle,
|
|
7043
|
+
...inlineStyles.invisible
|
|
7044
|
+
};
|
|
7045
|
+
}
|
|
7141
7046
|
const keypadContainerStyle = [row, centered, fullWidth, styles.keypadContainer, ...(Array.isArray(style) ? style : [style])];
|
|
7142
7047
|
const keypadStyle = [row, styles.keypadBorder, layoutMode === LayoutModes.FULLSCREEN ? styles.fullscreen : styles.compact];
|
|
7143
7048
|
|
|
@@ -7164,19 +7069,6 @@ class KeypadContainer extends React__namespace.Component {
|
|
|
7164
7069
|
}, this.renderKeypad())));
|
|
7165
7070
|
}
|
|
7166
7071
|
}
|
|
7167
|
-
_defineProperty(KeypadContainer, "propTypes", {
|
|
7168
|
-
active: PropTypes__default["default"].bool,
|
|
7169
|
-
extraKeys: PropTypes__default["default"].arrayOf(keyIdPropType),
|
|
7170
|
-
keypadType: PropTypes__default["default"].oneOf(Object.keys(KeypadTypes)).isRequired,
|
|
7171
|
-
layoutMode: PropTypes__default["default"].oneOf(Object.keys(LayoutModes)).isRequired,
|
|
7172
|
-
navigationPadEnabled: PropTypes__default["default"].bool.isRequired,
|
|
7173
|
-
onDismiss: PropTypes__default["default"].func,
|
|
7174
|
-
// A callback that should be triggered with the root React element on
|
|
7175
|
-
// mount.
|
|
7176
|
-
onElementMounted: PropTypes__default["default"].func,
|
|
7177
|
-
onPageSizeChange: PropTypes__default["default"].func.isRequired,
|
|
7178
|
-
style: PropTypes__default["default"].any
|
|
7179
|
-
});
|
|
7180
7072
|
const keypadAnimationDurationMs = 300;
|
|
7181
7073
|
const borderWidthPx = 1;
|
|
7182
7074
|
const styles = aphrodite.StyleSheet.create({
|
|
@@ -7237,7 +7129,9 @@ const inlineStyles = {
|
|
|
7237
7129
|
};
|
|
7238
7130
|
const mapStateToProps = state => {
|
|
7239
7131
|
return {
|
|
7240
|
-
|
|
7132
|
+
extraKeys: state.keypad.extraKeys,
|
|
7133
|
+
keypadType: state.keypad.keypadType,
|
|
7134
|
+
active: state.keypad.active,
|
|
7241
7135
|
layoutMode: state.layout.layoutMode,
|
|
7242
7136
|
navigationPadEnabled: state.layout.navigationPadEnabled
|
|
7243
7137
|
};
|
|
@@ -7254,9 +7148,8 @@ var KeypadContainer$1 = reactRedux.connect(mapStateToProps, mapDispatchToProps,
|
|
|
7254
7148
|
})(KeypadContainer);
|
|
7255
7149
|
|
|
7256
7150
|
class ProvidedKeypad extends React__namespace.Component {
|
|
7257
|
-
constructor() {
|
|
7258
|
-
super(
|
|
7259
|
-
_defineProperty(this, "mounted", void 0);
|
|
7151
|
+
constructor(props) {
|
|
7152
|
+
super(props);
|
|
7260
7153
|
_defineProperty(this, "store", void 0);
|
|
7261
7154
|
_defineProperty(this, "activate", () => {
|
|
7262
7155
|
this.store.dispatch(activateKeypad());
|
|
@@ -7285,24 +7178,17 @@ class ProvidedKeypad extends React__namespace.Component {
|
|
|
7285
7178
|
_defineProperty(this, "getDOMNode", () => {
|
|
7286
7179
|
return ReactDOM__default["default"].findDOMNode(this);
|
|
7287
7180
|
});
|
|
7288
|
-
}
|
|
7289
|
-
UNSAFE_componentWillMount() {
|
|
7290
7181
|
this.store = createStore();
|
|
7291
7182
|
}
|
|
7292
|
-
componentDidMount() {
|
|
7293
|
-
this.mounted = true;
|
|
7294
|
-
}
|
|
7295
|
-
componentWillUnmount() {
|
|
7296
|
-
this.mounted = false;
|
|
7297
|
-
}
|
|
7298
7183
|
render() {
|
|
7299
7184
|
const {
|
|
7300
7185
|
onElementMounted,
|
|
7301
|
-
|
|
7186
|
+
onDismiss,
|
|
7187
|
+
style
|
|
7302
7188
|
} = this.props;
|
|
7303
7189
|
return /*#__PURE__*/React__namespace.createElement(reactRedux.Provider, {
|
|
7304
7190
|
store: this.store
|
|
7305
|
-
}, /*#__PURE__*/React__namespace.createElement(KeypadContainer$1,
|
|
7191
|
+
}, /*#__PURE__*/React__namespace.createElement(KeypadContainer$1, {
|
|
7306
7192
|
onElementMounted: element => {
|
|
7307
7193
|
// Append the dispatch methods that we want to expose
|
|
7308
7194
|
// externally to the returned React element.
|
|
@@ -7316,16 +7202,17 @@ class ProvidedKeypad extends React__namespace.Component {
|
|
|
7316
7202
|
getDOMNode: this.getDOMNode
|
|
7317
7203
|
};
|
|
7318
7204
|
onElementMounted && onElementMounted(elementWithDispatchMethods);
|
|
7319
|
-
}
|
|
7320
|
-
|
|
7205
|
+
},
|
|
7206
|
+
onDismiss: onDismiss,
|
|
7207
|
+
style: style
|
|
7208
|
+
}));
|
|
7321
7209
|
}
|
|
7322
7210
|
}
|
|
7323
7211
|
|
|
7324
|
-
exports.CursorContexts =
|
|
7212
|
+
exports.CursorContexts = cursorContexts;
|
|
7325
7213
|
exports.KeyConfigs = KeyConfigs;
|
|
7326
7214
|
exports.Keypad = ProvidedKeypad;
|
|
7327
7215
|
exports.KeypadInput = MathInput;
|
|
7328
7216
|
exports.KeypadTypes = KeypadTypes;
|
|
7329
|
-
exports.keypadConfigurationPropType = keypadConfigurationPropType;
|
|
7330
7217
|
exports.keypadElementPropType = keypadElementPropType;
|
|
7331
7218
|
//# sourceMappingURL=index.js.map
|