@khanacademy/math-input 3.0.0 → 4.0.0
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 +35 -0
- package/dist/components/input/__tests__/test-math-wrapper.d.ts +1 -1
- package/dist/components/input/__tests__/test-math-wrapper.js.flow +1 -1
- package/dist/components/input/key-handlers/handle-arrow.d.ts +3 -0
- package/dist/components/input/key-handlers/handle-arrow.js.flow +12 -0
- package/dist/components/input/key-handlers/handle-backspace.d.ts +7 -0
- package/dist/components/input/key-handlers/handle-backspace.js.flow +14 -0
- package/dist/components/input/key-handlers/handle-exponent.d.ts +3 -0
- package/dist/components/input/key-handlers/handle-exponent.js.flow +12 -0
- package/dist/components/input/key-handlers/handle-jump-out.d.ts +7 -0
- package/dist/components/input/key-handlers/handle-jump-out.js.flow +14 -0
- package/dist/components/input/math-wrapper.d.ts +7 -78
- package/dist/components/input/math-wrapper.js.flow +16 -78
- package/dist/components/input/mathquill-helpers.d.ts +46 -0
- package/dist/components/input/mathquill-helpers.js.flow +56 -0
- package/dist/components/input/mathquill-instance.d.ts +3 -0
- package/dist/components/input/mathquill-instance.js.flow +9 -0
- package/dist/components/input/mathquill-types.d.ts +25 -0
- package/dist/components/input/mathquill-types.js.flow +34 -0
- package/dist/components/key-translator.d.ts +4 -0
- package/dist/components/key-translator.js.flow +10 -0
- package/dist/components/keypad/button-assets.d.ts +2 -2
- package/dist/components/keypad/button-assets.js.flow +2 -2
- package/dist/components/keypad/keypad-page-items.d.ts +1 -1
- package/dist/components/keypad/keypad-page-items.js.flow +1 -1
- package/dist/components/keypad-legacy/gesture-manager.d.ts +21 -9
- package/dist/components/keypad-legacy/gesture-manager.js.flow +27 -12
- package/dist/components/keypad-legacy/gesture-state-machine.d.ts +9 -9
- package/dist/components/keypad-legacy/gesture-state-machine.js.flow +10 -10
- package/dist/components/keypad-legacy/keypad-button.d.ts +2 -2
- package/dist/components/keypad-legacy/keypad-button.js.flow +3 -3
- package/dist/components/keypad-legacy/store/actions.d.ts +4 -14
- package/dist/components/keypad-legacy/store/actions.js.flow +3 -15
- package/dist/components/keypad-legacy/store/types.d.ts +2 -2
- package/dist/components/keypad-legacy/store/types.js.flow +2 -2
- package/dist/components/keypad-legacy/touchable-keypad-button.d.ts +6 -6
- package/dist/components/keypad-legacy/touchable-keypad-button.js.flow +9 -14
- package/dist/data/key-configs.d.ts +3 -6
- package/dist/data/key-configs.js.flow +3 -8
- package/dist/data/keys.d.ts +2 -54
- package/dist/data/keys.js.flow +116 -55
- package/dist/enums.d.ts +2 -9
- package/dist/enums.js.flow +2 -11
- package/dist/es/index.js +1781 -1196
- package/dist/es/index.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +2069 -1242
- package/dist/index.js.flow +4 -2
- package/dist/index.js.map +1 -1
- package/dist/strings.js +26 -10
- package/dist/types.d.ts +10 -12
- package/dist/types.js.flow +13 -12
- package/package.json +1 -1
- package/src/components/input/__tests__/context-tracking.test.ts +43 -44
- package/src/components/input/__tests__/mathquill.test.ts +133 -135
- package/src/components/input/key-handlers/handle-arrow.ts +70 -0
- package/src/components/input/key-handlers/handle-backspace.ts +275 -0
- package/src/components/input/key-handlers/handle-exponent.ts +52 -0
- package/src/components/input/key-handlers/handle-jump-out.ts +103 -0
- package/src/components/input/math-input.tsx +11 -12
- package/src/components/input/math-wrapper.ts +88 -837
- package/src/components/input/mathquill-helpers.ts +268 -0
- package/src/components/input/mathquill-instance.ts +5 -0
- package/src/components/input/mathquill-types.ts +55 -0
- package/src/components/key-translator.ts +209 -0
- package/src/components/keypad/button-assets.tsx +411 -100
- package/src/components/keypad/geometry-page/index.tsx +1 -1
- package/src/components/keypad/keypad-mathquill.stories.tsx +69 -0
- package/src/components/keypad/keypad-page-items.tsx +2 -1
- package/src/components/keypad/operators-page/index.tsx +1 -1
- package/src/components/keypad-legacy/echo-manager.tsx +4 -4
- package/src/components/keypad-legacy/empty-keypad-button.tsx +6 -4
- package/src/components/keypad-legacy/gesture-manager.ts +32 -9
- package/src/components/keypad-legacy/gesture-state-machine.ts +14 -14
- package/src/components/keypad-legacy/keypad-button.tsx +15 -18
- package/src/components/keypad-legacy/many-keypad-button.tsx +9 -2
- package/src/components/keypad-legacy/store/actions.ts +3 -29
- package/src/components/keypad-legacy/store/echo-reducer.ts +2 -5
- package/src/components/keypad-legacy/store/index.ts +4 -10
- package/src/components/keypad-legacy/store/input-reducer.ts +1 -2
- package/src/components/keypad-legacy/store/keypad-reducer.ts +2 -3
- package/src/components/keypad-legacy/store/types.ts +2 -2
- package/src/components/keypad-legacy/touchable-keypad-button.tsx +8 -13
- package/src/components/tabbar/icons.tsx +0 -2
- package/src/data/key-configs.ts +751 -304
- package/src/data/keys.ts +118 -65
- package/src/enums.ts +10 -9
- package/src/index.ts +3 -2
- package/src/math-input.stories.tsx +1 -1
- package/src/types.ts +10 -12
- package/tsconfig-build.tsbuildinfo +1 -1
package/dist/es/index.js
CHANGED
|
@@ -57,64 +57,6 @@ function _extends() {
|
|
|
57
57
|
return _extends.apply(this, arguments);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
/**
|
|
61
|
-
* This file contains constants for keypad buttons that aren't single
|
|
62
|
-
* alphanumeric characters.
|
|
63
|
-
*/
|
|
64
|
-
// TODO(charlie): There's duplication between this file and key-configs.js.
|
|
65
|
-
// We should clean it up by removing this file and requiring clients to use the
|
|
66
|
-
// `id` field on the key configurations.
|
|
67
|
-
var Keys = /*#__PURE__*/function (Keys) {
|
|
68
|
-
Keys["PLUS"] = "PLUS";
|
|
69
|
-
Keys["MINUS"] = "MINUS";
|
|
70
|
-
Keys["NEGATIVE"] = "NEGATIVE";
|
|
71
|
-
Keys["TIMES"] = "TIMES";
|
|
72
|
-
Keys["DIVIDE"] = "DIVIDE";
|
|
73
|
-
Keys["DECIMAL"] = "DECIMAL";
|
|
74
|
-
Keys["PERIOD"] = "PERIOD";
|
|
75
|
-
Keys["PERCENT"] = "PERCENT";
|
|
76
|
-
Keys["CDOT"] = "CDOT";
|
|
77
|
-
Keys["EQUAL"] = "EQUAL";
|
|
78
|
-
Keys["NEQ"] = "NEQ";
|
|
79
|
-
Keys["GT"] = "GT";
|
|
80
|
-
Keys["LT"] = "LT";
|
|
81
|
-
Keys["GEQ"] = "GEQ";
|
|
82
|
-
Keys["LEQ"] = "LEQ";
|
|
83
|
-
Keys["FRAC_INCLUSIVE"] = "FRAC_INCLUSIVE";
|
|
84
|
-
Keys["FRAC_EXCLUSIVE"] = "FRAC_EXCLUSIVE";
|
|
85
|
-
Keys["FRAC"] = "FRAC";
|
|
86
|
-
Keys["EXP"] = "EXP";
|
|
87
|
-
Keys["EXP_2"] = "EXP_2";
|
|
88
|
-
Keys["EXP_3"] = "EXP_3";
|
|
89
|
-
Keys["SQRT"] = "SQRT";
|
|
90
|
-
Keys["CUBE_ROOT"] = "CUBE_ROOT";
|
|
91
|
-
Keys["RADICAL"] = "RADICAL";
|
|
92
|
-
Keys["LEFT_PAREN"] = "LEFT_PAREN";
|
|
93
|
-
Keys["RIGHT_PAREN"] = "RIGHT_PAREN";
|
|
94
|
-
Keys["LN"] = "LN";
|
|
95
|
-
Keys["LOG"] = "LOG";
|
|
96
|
-
Keys["LOG_N"] = "LOG_N";
|
|
97
|
-
Keys["SIN"] = "SIN";
|
|
98
|
-
Keys["COS"] = "COS";
|
|
99
|
-
Keys["TAN"] = "TAN";
|
|
100
|
-
Keys["PI"] = "PI";
|
|
101
|
-
Keys["THETA"] = "THETA";
|
|
102
|
-
Keys["UP"] = "UP";
|
|
103
|
-
Keys["RIGHT"] = "RIGHT";
|
|
104
|
-
Keys["DOWN"] = "DOWN";
|
|
105
|
-
Keys["LEFT"] = "LEFT";
|
|
106
|
-
Keys["BACKSPACE"] = "BACKSPACE";
|
|
107
|
-
Keys["DISMISS"] = "DISMISS";
|
|
108
|
-
Keys["JUMP_OUT_PARENTHESES"] = "JUMP_OUT_PARENTHESES";
|
|
109
|
-
Keys["JUMP_OUT_EXPONENT"] = "JUMP_OUT_EXPONENT";
|
|
110
|
-
Keys["JUMP_OUT_BASE"] = "JUMP_OUT_BASE";
|
|
111
|
-
Keys["JUMP_INTO_NUMERATOR"] = "JUMP_INTO_NUMERATOR";
|
|
112
|
-
Keys["JUMP_OUT_NUMERATOR"] = "JUMP_OUT_NUMERATOR";
|
|
113
|
-
Keys["JUMP_OUT_DENOMINATOR"] = "JUMP_OUT_DENOMINATOR";
|
|
114
|
-
Keys["NOOP"] = "NOOP";
|
|
115
|
-
return Keys;
|
|
116
|
-
}(Keys || {}); // mobile native only
|
|
117
|
-
|
|
118
60
|
class Text extends React.Component {
|
|
119
61
|
render() {
|
|
120
62
|
const {
|
|
@@ -408,16 +350,23 @@ let KeypadType = /*#__PURE__*/function (KeypadType) {
|
|
|
408
350
|
KeypadType["EXPRESSION"] = "EXPRESSION";
|
|
409
351
|
return KeypadType;
|
|
410
352
|
}({});
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
353
|
+
const KeyTypes = ["EMPTY",
|
|
354
|
+
// For numerals, variables, and any other characters that themselves
|
|
355
|
+
// compose 'values'.
|
|
356
|
+
"VALUE",
|
|
357
|
+
// For buttons that insert or adjust math in an input.
|
|
358
|
+
"OPERATOR",
|
|
359
|
+
// For buttons that move the cursor in an input (including via
|
|
360
|
+
// deletion).
|
|
361
|
+
"INPUT_NAVIGATION",
|
|
362
|
+
// For buttons that modify the broader keypad state (e.g., by changing
|
|
363
|
+
// the visible pane).
|
|
364
|
+
"KEYPAD_NAVIGATION",
|
|
365
|
+
// For buttons that house multiple buttons and have no action
|
|
366
|
+
// themselves.
|
|
367
|
+
"MANY",
|
|
368
|
+
// For the echo animation that appears on press.
|
|
369
|
+
"ECHO"];
|
|
421
370
|
let DeviceOrientation = /*#__PURE__*/function (DeviceOrientation) {
|
|
422
371
|
DeviceOrientation["LANDSCAPE"] = "LANDSCAPE";
|
|
423
372
|
DeviceOrientation["PORTRAIT"] = "PORTRAIT";
|
|
@@ -470,131 +419,208 @@ let EchoAnimationType = /*#__PURE__*/function (EchoAnimationType) {
|
|
|
470
419
|
// listed here. Much of the Arab world uses U+066C.
|
|
471
420
|
const decimalSeparator = getDecimalSeparator() === "," ? DecimalSeparator.COMMA : DecimalSeparator.PERIOD;
|
|
472
421
|
|
|
473
|
-
|
|
474
|
-
* This file contains a wrapper around MathQuill so that we can provide a
|
|
475
|
-
* more regular interface for the functionality we need while insulating us
|
|
476
|
-
* from MathQuill changes.
|
|
477
|
-
*/
|
|
478
|
-
|
|
479
|
-
// Keeping `window` in place for test suite and GitHub Pages.
|
|
480
|
-
// If it does not exist, fall back to CommonJS require. - jsatk
|
|
422
|
+
var MQ = MathQuill.getInterface(2);
|
|
481
423
|
|
|
482
|
-
const decimalSymbol = decimalSeparator === DecimalSeparator.COMMA ? "," : ".";
|
|
483
424
|
var ActionType = /*#__PURE__*/function (ActionType) {
|
|
484
425
|
ActionType["WRITE"] = "write";
|
|
485
426
|
ActionType["CMD"] = "cmd";
|
|
486
427
|
ActionType["KEYSTROKE"] = "keystroke";
|
|
487
428
|
ActionType[ActionType["MQ_END"] = 0] = "MQ_END";
|
|
488
429
|
return ActionType;
|
|
489
|
-
}(ActionType || {});
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
fn: ActionType.CMD
|
|
537
|
-
},
|
|
538
|
-
[Keys.RIGHT_PAREN]: {
|
|
539
|
-
str: ")",
|
|
540
|
-
fn: ActionType.CMD
|
|
541
|
-
},
|
|
542
|
-
[Keys.SQRT]: {
|
|
543
|
-
str: "sqrt",
|
|
544
|
-
fn: ActionType.CMD
|
|
545
|
-
},
|
|
546
|
-
[Keys.PI]: {
|
|
547
|
-
str: "pi",
|
|
548
|
-
fn: ActionType.CMD
|
|
549
|
-
},
|
|
550
|
-
[Keys.THETA]: {
|
|
551
|
-
str: "theta",
|
|
552
|
-
fn: ActionType.CMD
|
|
553
|
-
},
|
|
554
|
-
[Keys.RADICAL]: {
|
|
555
|
-
str: "nthroot",
|
|
556
|
-
fn: ActionType.CMD
|
|
557
|
-
},
|
|
558
|
-
[Keys.LT]: {
|
|
559
|
-
str: "<",
|
|
560
|
-
fn: ActionType.WRITE
|
|
561
|
-
},
|
|
562
|
-
[Keys.LEQ]: {
|
|
563
|
-
str: "\\leq",
|
|
564
|
-
fn: ActionType.WRITE
|
|
565
|
-
},
|
|
566
|
-
[Keys.GT]: {
|
|
567
|
-
str: ">",
|
|
568
|
-
fn: ActionType.WRITE
|
|
569
|
-
},
|
|
570
|
-
[Keys.GEQ]: {
|
|
571
|
-
str: "\\geq",
|
|
572
|
-
fn: ActionType.WRITE
|
|
573
|
-
},
|
|
574
|
-
[Keys.UP]: {
|
|
575
|
-
str: "Up",
|
|
576
|
-
fn: ActionType.KEYSTROKE
|
|
577
|
-
},
|
|
578
|
-
[Keys.DOWN]: {
|
|
579
|
-
str: "Down",
|
|
580
|
-
fn: ActionType.KEYSTROKE
|
|
581
|
-
},
|
|
430
|
+
}(ActionType || {});
|
|
431
|
+
const decimalSymbol = decimalSeparator === DecimalSeparator.COMMA ? "," : ".";
|
|
432
|
+
function buildGenericCallback(str, type = ActionType.WRITE) {
|
|
433
|
+
return function (mathQuill) {
|
|
434
|
+
switch (type) {
|
|
435
|
+
case ActionType.WRITE:
|
|
436
|
+
{
|
|
437
|
+
mathQuill.write(str);
|
|
438
|
+
return;
|
|
439
|
+
}
|
|
440
|
+
case ActionType.CMD:
|
|
441
|
+
{
|
|
442
|
+
mathQuill.cmd(str);
|
|
443
|
+
return;
|
|
444
|
+
}
|
|
445
|
+
case ActionType.KEYSTROKE:
|
|
446
|
+
{
|
|
447
|
+
mathQuill.keystroke(str);
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
};
|
|
452
|
+
}
|
|
453
|
+
const keyToMathquillMap = {
|
|
454
|
+
CDOT: buildGenericCallback("\\cdot"),
|
|
455
|
+
COS: buildGenericCallback("cos"),
|
|
456
|
+
DECIMAL: buildGenericCallback(decimalSymbol),
|
|
457
|
+
DIVIDE: buildGenericCallback("\\div"),
|
|
458
|
+
EQUAL: buildGenericCallback("="),
|
|
459
|
+
EXP: buildGenericCallback("^"),
|
|
460
|
+
EXP_2: buildGenericCallback("^2"),
|
|
461
|
+
EXP_3: buildGenericCallback("^3"),
|
|
462
|
+
GEQ: buildGenericCallback("\\geq"),
|
|
463
|
+
GT: buildGenericCallback(">"),
|
|
464
|
+
LEQ: buildGenericCallback("\\leq"),
|
|
465
|
+
LN: buildGenericCallback("\\ln"),
|
|
466
|
+
LOG: buildGenericCallback("\\log"),
|
|
467
|
+
LT: buildGenericCallback("<"),
|
|
468
|
+
MINUS: buildGenericCallback("-"),
|
|
469
|
+
NEGATIVE: buildGenericCallback("-"),
|
|
470
|
+
NEQ: buildGenericCallback("\\neq"),
|
|
471
|
+
PERCENT: buildGenericCallback("%"),
|
|
472
|
+
PERIOD: buildGenericCallback("."),
|
|
473
|
+
PLUS: buildGenericCallback("+"),
|
|
474
|
+
SIN: buildGenericCallback("sin"),
|
|
475
|
+
TAN: buildGenericCallback("tan"),
|
|
476
|
+
TIMES: buildGenericCallback("\\times"),
|
|
582
477
|
// The `FRAC_EXCLUSIVE` variant is handled manually, since we may need to do
|
|
583
478
|
// some additional navigation depending on the cursor position.
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
479
|
+
FRAC_INCLUSIVE: buildGenericCallback("/", ActionType.CMD),
|
|
480
|
+
LEFT_PAREN: buildGenericCallback("(", ActionType.CMD),
|
|
481
|
+
RIGHT_PAREN: buildGenericCallback(")", ActionType.CMD),
|
|
482
|
+
SQRT: buildGenericCallback("sqrt", ActionType.CMD),
|
|
483
|
+
PHI: buildGenericCallback("\\phi", ActionType.CMD),
|
|
484
|
+
PI: buildGenericCallback("pi", ActionType.CMD),
|
|
485
|
+
THETA: buildGenericCallback("theta", ActionType.CMD),
|
|
486
|
+
RADICAL: buildGenericCallback("nthroot", ActionType.CMD),
|
|
487
|
+
UP: buildGenericCallback("Up", ActionType.KEYSTROKE),
|
|
488
|
+
DOWN: buildGenericCallback("Down", ActionType.KEYSTROKE),
|
|
489
|
+
CUBE_ROOT: mathQuill => {
|
|
490
|
+
mathQuill.write("\\sqrt[3]{}");
|
|
491
|
+
mathQuill.keystroke("Left"); // under the root
|
|
492
|
+
},
|
|
493
|
+
|
|
494
|
+
FRAC_EXCLUSIVE: mathQuill => {
|
|
495
|
+
const cursor = mathQuill.__controller.cursor;
|
|
496
|
+
// If there's nothing to the left of the cursor, then we want to
|
|
497
|
+
// leave the cursor to the left of the fraction after creating it.
|
|
498
|
+
const shouldNavigateLeft = cursor[MQ.L] === ActionType.MQ_END;
|
|
499
|
+
mathQuill.cmd("\\frac");
|
|
500
|
+
if (shouldNavigateLeft) {
|
|
501
|
+
mathQuill.keystroke("Left");
|
|
502
|
+
}
|
|
503
|
+
},
|
|
504
|
+
LOG_B: mathQuill => {
|
|
505
|
+
mathQuill.typedText("log_");
|
|
506
|
+
mathQuill.keystroke("Right");
|
|
507
|
+
mathQuill.typedText("(");
|
|
508
|
+
mathQuill.keystroke("Left");
|
|
509
|
+
mathQuill.keystroke("Left");
|
|
510
|
+
},
|
|
511
|
+
LOG_N: mathQuill => {
|
|
512
|
+
mathQuill.write("log_{ }\\left(\\right)");
|
|
513
|
+
mathQuill.keystroke("Left"); // into parentheses
|
|
514
|
+
mathQuill.keystroke("Left"); // out of parentheses
|
|
515
|
+
mathQuill.keystroke("Left"); // into index
|
|
516
|
+
},
|
|
517
|
+
|
|
518
|
+
NTHROOT3: mathQuill => {
|
|
519
|
+
mathQuill.typedText("nthroot3");
|
|
520
|
+
mathQuill.keystroke("Right");
|
|
521
|
+
},
|
|
522
|
+
POW: mathQuill => {
|
|
523
|
+
const contents = mathQuill.latex();
|
|
524
|
+
mathQuill.typedText("^");
|
|
525
|
+
|
|
526
|
+
// If the input hasn't changed (for example, if we're
|
|
527
|
+
// attempting to add an exponent on an empty input or an empty
|
|
528
|
+
// denominator), insert our own "a^b"
|
|
529
|
+
if (mathQuill.latex() === contents) {
|
|
530
|
+
mathQuill.typedText("a^b");
|
|
531
|
+
}
|
|
532
|
+
},
|
|
533
|
+
// These need to be overwritten by the consumer
|
|
534
|
+
// if they're going to be used
|
|
535
|
+
FRAC: () => {},
|
|
536
|
+
RIGHT: () => {},
|
|
537
|
+
LEFT: () => {},
|
|
538
|
+
BACKSPACE: () => {},
|
|
539
|
+
DISMISS: () => {},
|
|
540
|
+
JUMP_OUT_PARENTHESES: () => {},
|
|
541
|
+
JUMP_OUT_EXPONENT: () => {},
|
|
542
|
+
JUMP_OUT_BASE: () => {},
|
|
543
|
+
JUMP_INTO_NUMERATOR: () => {},
|
|
544
|
+
JUMP_OUT_NUMERATOR: () => {},
|
|
545
|
+
JUMP_OUT_DENOMINATOR: () => {},
|
|
546
|
+
NOOP: () => {},
|
|
547
|
+
MANY: () => {},
|
|
548
|
+
NUM_0: buildGenericCallback("0"),
|
|
549
|
+
NUM_1: buildGenericCallback("1"),
|
|
550
|
+
NUM_2: buildGenericCallback("2"),
|
|
551
|
+
NUM_3: buildGenericCallback("3"),
|
|
552
|
+
NUM_4: buildGenericCallback("4"),
|
|
553
|
+
NUM_5: buildGenericCallback("5"),
|
|
554
|
+
NUM_6: buildGenericCallback("6"),
|
|
555
|
+
NUM_7: buildGenericCallback("7"),
|
|
556
|
+
NUM_8: buildGenericCallback("8"),
|
|
557
|
+
NUM_9: buildGenericCallback("9"),
|
|
558
|
+
a: buildGenericCallback("a"),
|
|
559
|
+
b: buildGenericCallback("b"),
|
|
560
|
+
c: buildGenericCallback("c"),
|
|
561
|
+
d: buildGenericCallback("d"),
|
|
562
|
+
e: buildGenericCallback("e"),
|
|
563
|
+
f: buildGenericCallback("f"),
|
|
564
|
+
g: buildGenericCallback("g"),
|
|
565
|
+
h: buildGenericCallback("h"),
|
|
566
|
+
i: buildGenericCallback("i"),
|
|
567
|
+
j: buildGenericCallback("j"),
|
|
568
|
+
k: buildGenericCallback("k"),
|
|
569
|
+
l: buildGenericCallback("l"),
|
|
570
|
+
m: buildGenericCallback("m"),
|
|
571
|
+
n: buildGenericCallback("n"),
|
|
572
|
+
o: buildGenericCallback("o"),
|
|
573
|
+
p: buildGenericCallback("p"),
|
|
574
|
+
q: buildGenericCallback("q"),
|
|
575
|
+
r: buildGenericCallback("r"),
|
|
576
|
+
s: buildGenericCallback("s"),
|
|
577
|
+
t: buildGenericCallback("t"),
|
|
578
|
+
u: buildGenericCallback("u"),
|
|
579
|
+
v: buildGenericCallback("v"),
|
|
580
|
+
w: buildGenericCallback("w"),
|
|
581
|
+
x: buildGenericCallback("x"),
|
|
582
|
+
y: buildGenericCallback("y"),
|
|
583
|
+
z: buildGenericCallback("z"),
|
|
584
|
+
A: buildGenericCallback("A"),
|
|
585
|
+
B: buildGenericCallback("B"),
|
|
586
|
+
C: buildGenericCallback("C"),
|
|
587
|
+
D: buildGenericCallback("D"),
|
|
588
|
+
E: buildGenericCallback("E"),
|
|
589
|
+
F: buildGenericCallback("F"),
|
|
590
|
+
G: buildGenericCallback("G"),
|
|
591
|
+
H: buildGenericCallback("H"),
|
|
592
|
+
I: buildGenericCallback("I"),
|
|
593
|
+
J: buildGenericCallback("J"),
|
|
594
|
+
K: buildGenericCallback("K"),
|
|
595
|
+
L: buildGenericCallback("L"),
|
|
596
|
+
M: buildGenericCallback("M"),
|
|
597
|
+
N: buildGenericCallback("N"),
|
|
598
|
+
O: buildGenericCallback("O"),
|
|
599
|
+
P: buildGenericCallback("P"),
|
|
600
|
+
Q: buildGenericCallback("Q"),
|
|
601
|
+
R: buildGenericCallback("R"),
|
|
602
|
+
S: buildGenericCallback("S"),
|
|
603
|
+
T: buildGenericCallback("T"),
|
|
604
|
+
U: buildGenericCallback("U"),
|
|
605
|
+
V: buildGenericCallback("V"),
|
|
606
|
+
W: buildGenericCallback("W"),
|
|
607
|
+
X: buildGenericCallback("X"),
|
|
608
|
+
Y: buildGenericCallback("Y"),
|
|
609
|
+
Z: buildGenericCallback("Z")
|
|
595
610
|
};
|
|
596
|
-
|
|
597
|
-
|
|
611
|
+
|
|
612
|
+
let MathFieldActionType = /*#__PURE__*/function (MathFieldActionType) {
|
|
613
|
+
MathFieldActionType["WRITE"] = "write";
|
|
614
|
+
MathFieldActionType["CMD"] = "cmd";
|
|
615
|
+
MathFieldActionType["KEYSTROKE"] = "keystroke";
|
|
616
|
+
MathFieldActionType[MathFieldActionType["MQ_END"] = 0] = "MQ_END";
|
|
617
|
+
return MathFieldActionType;
|
|
618
|
+
}({});
|
|
619
|
+
|
|
620
|
+
// The MathQuill MathField Cursor
|
|
621
|
+
// it's not part of the public API for MathQuill,
|
|
622
|
+
// we reach into the internals to get it
|
|
623
|
+
|
|
598
624
|
const Numerals = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"];
|
|
599
625
|
const GreekLetters = ["\\theta", "\\pi"];
|
|
600
626
|
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"];
|
|
@@ -602,24 +628,623 @@ const Letters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M"
|
|
|
602
628
|
// We only consider numerals, variables, and Greek Letters to be proper
|
|
603
629
|
// leaf nodes.
|
|
604
630
|
const ValidLeaves = [...Numerals, ...GreekLetters, ...Letters.map(letter => letter.toLowerCase()), ...Letters.map(letter => letter.toUpperCase())];
|
|
631
|
+
function getCursor(mathField) {
|
|
632
|
+
return mathField.__controller.cursor;
|
|
633
|
+
}
|
|
634
|
+
function isFraction(node) {
|
|
635
|
+
return node.jQ && node.jQ.hasClass("mq-fraction");
|
|
636
|
+
}
|
|
637
|
+
function isNumerator(node) {
|
|
638
|
+
return node.jQ && node.jQ.hasClass("mq-numerator");
|
|
639
|
+
}
|
|
640
|
+
function isDenominator(node) {
|
|
641
|
+
return node.jQ && node.jQ.hasClass("mq-denominator");
|
|
642
|
+
}
|
|
643
|
+
function isSubScript(node) {
|
|
644
|
+
// NOTE(charlie): MyScript has a structure whereby its superscripts seem
|
|
645
|
+
// to be represented as a parent node with 'mq-sup-only' containing a
|
|
646
|
+
// single child with 'mq-sup'.
|
|
647
|
+
return node.jQ && (node.jQ.hasClass("mq-sub-only") || node.jQ.hasClass("mq-sub"));
|
|
648
|
+
}
|
|
649
|
+
function isSuperScript(node) {
|
|
650
|
+
// NOTE(charlie): MyScript has a structure whereby its superscripts seem
|
|
651
|
+
// to be represented as a parent node with 'mq-sup-only' containing a
|
|
652
|
+
// single child with 'mq-sup'.
|
|
653
|
+
return node.jQ && (node.jQ.hasClass("mq-sup-only") || node.jQ.hasClass("mq-sup"));
|
|
654
|
+
}
|
|
655
|
+
function isParens(node) {
|
|
656
|
+
return node && node.ctrlSeq === "\\left(";
|
|
657
|
+
}
|
|
658
|
+
function isLeaf(node) {
|
|
659
|
+
return node && node.ctrlSeq && ValidLeaves.includes(node.ctrlSeq.trim());
|
|
660
|
+
}
|
|
661
|
+
function isSquareRoot(node) {
|
|
662
|
+
return node.blocks && node.blocks[0].jQ && node.blocks[0].jQ.hasClass("mq-sqrt-stem");
|
|
663
|
+
}
|
|
664
|
+
function isNthRoot(node) {
|
|
665
|
+
return node.blocks && node.blocks[0].jQ && node.blocks[0].jQ.hasClass("mq-nthroot");
|
|
666
|
+
}
|
|
667
|
+
function isNthRootIndex(node) {
|
|
668
|
+
return node.jQ && node.jQ.hasClass("mq-nthroot");
|
|
669
|
+
}
|
|
670
|
+
function isInsideLogIndex(cursor) {
|
|
671
|
+
const grandparent = cursor.parent.parent;
|
|
672
|
+
if (grandparent && grandparent.jQ.hasClass("mq-supsub")) {
|
|
673
|
+
const command = maybeFindCommandBeforeParens(grandparent);
|
|
674
|
+
if (command && command.name === "\\log") {
|
|
675
|
+
return true;
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
return false;
|
|
679
|
+
}
|
|
680
|
+
function isInsideEmptyNode(cursor) {
|
|
681
|
+
return cursor[MQ.L] === MathFieldActionType.MQ_END && cursor[MQ.R] === MathFieldActionType.MQ_END;
|
|
682
|
+
}
|
|
683
|
+
function selectNode(node, cursor) {
|
|
684
|
+
cursor.insLeftOf(node);
|
|
685
|
+
cursor.startSelection();
|
|
686
|
+
cursor.insRightOf(node);
|
|
687
|
+
cursor.select();
|
|
688
|
+
cursor.endSelection();
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
/**
|
|
692
|
+
* Return the start node, end node, and full name of the command of which
|
|
693
|
+
* the initial node is a part, or `null` if the node is not part of a
|
|
694
|
+
* command.
|
|
695
|
+
*
|
|
696
|
+
* @param {node} initialNode - the node to included as part of the command
|
|
697
|
+
* @returns {null|object} - `null` or an object containing the start node
|
|
698
|
+
* (`startNode`), end node (`endNode`), and full
|
|
699
|
+
* name (`name`) of the command
|
|
700
|
+
*/
|
|
701
|
+
function maybeFindCommand(initialNode) {
|
|
702
|
+
if (!initialNode) {
|
|
703
|
+
return null;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// MathQuill stores commands as separate characters so that
|
|
707
|
+
// users can delete commands one character at a time. We iterate over
|
|
708
|
+
// the nodes from right to left until we hit a sequence starting with a
|
|
709
|
+
// '\\', which signifies the start of a command; then we iterate from
|
|
710
|
+
// left to right until we hit a '\\left(', which signifies the end of a
|
|
711
|
+
// command. If we encounter any character that doesn't belong in a
|
|
712
|
+
// command, we return null. We match a single character at a time.
|
|
713
|
+
// Ex) ['\\l', 'o', 'g ', '\\left(', ...]
|
|
714
|
+
const commandCharRegex = /^[a-z]$/;
|
|
715
|
+
const commandStartRegex = /^\\[a-z]$/;
|
|
716
|
+
const commandEndSeq = "\\left(";
|
|
717
|
+
|
|
718
|
+
// Note: We allowlist the set of valid commands, since relying solely on
|
|
719
|
+
// a command being prefixed with a backslash leads to undesired
|
|
720
|
+
// behavior. For example, Greek symbols, left parentheses, and square
|
|
721
|
+
// roots all get treated as commands.
|
|
722
|
+
const validCommands = ["\\log", "\\ln", "\\cos", "\\sin", "\\tan"];
|
|
723
|
+
let name = "";
|
|
724
|
+
let startNode;
|
|
725
|
+
let endNode;
|
|
726
|
+
|
|
727
|
+
// Collect the portion of the command from the current node, leftwards
|
|
728
|
+
// until the start of the command.
|
|
729
|
+
let node = initialNode;
|
|
730
|
+
while (node !== 0) {
|
|
731
|
+
const ctrlSeq = node.ctrlSeq.trim();
|
|
732
|
+
if (commandCharRegex.test(ctrlSeq)) {
|
|
733
|
+
name = ctrlSeq + name;
|
|
734
|
+
} else if (commandStartRegex.test(ctrlSeq)) {
|
|
735
|
+
name = ctrlSeq + name;
|
|
736
|
+
startNode = node;
|
|
737
|
+
break;
|
|
738
|
+
} else {
|
|
739
|
+
break;
|
|
740
|
+
}
|
|
741
|
+
node = node[MQ.L];
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
// If we hit the start of a command, then grab the rest of it by
|
|
745
|
+
// iterating rightwards to compute the full name of the command, along
|
|
746
|
+
// with its terminal node.
|
|
747
|
+
if (startNode) {
|
|
748
|
+
// Next, iterate from the start to the right.
|
|
749
|
+
node = initialNode[MQ.R];
|
|
750
|
+
while (node !== 0) {
|
|
751
|
+
const ctrlSeq = node.ctrlSeq.trim();
|
|
752
|
+
if (commandCharRegex.test(ctrlSeq)) {
|
|
753
|
+
// If we have a single character, add it to the command
|
|
754
|
+
// name.
|
|
755
|
+
name = name + ctrlSeq;
|
|
756
|
+
} else if (ctrlSeq === commandEndSeq) {
|
|
757
|
+
// If we hit the command end delimiter (the left
|
|
758
|
+
// parentheses surrounding its arguments), stop.
|
|
759
|
+
endNode = node;
|
|
760
|
+
break;
|
|
761
|
+
}
|
|
762
|
+
node = node[MQ.R];
|
|
763
|
+
}
|
|
764
|
+
if (validCommands.includes(name)) {
|
|
765
|
+
return {
|
|
766
|
+
name,
|
|
767
|
+
startNode,
|
|
768
|
+
endNode
|
|
769
|
+
};
|
|
770
|
+
} else {
|
|
771
|
+
return null;
|
|
772
|
+
}
|
|
773
|
+
} else {
|
|
774
|
+
return null;
|
|
775
|
+
}
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
/**
|
|
779
|
+
* Return the start node, end node, and full name of the command to the left
|
|
780
|
+
* of `\\left(`, or `null` if there is no command.
|
|
781
|
+
*
|
|
782
|
+
* @param {node} leftParenNode - node where .ctrlSeq == `\\left(`
|
|
783
|
+
* @returns {null|object} - `null` or an object containing the start node
|
|
784
|
+
* (`startNode`), end node (`endNode`), and full
|
|
785
|
+
* name (`name`) of the command
|
|
786
|
+
*/
|
|
787
|
+
function maybeFindCommandBeforeParens(leftParenNode) {
|
|
788
|
+
return maybeFindCommand(leftParenNode[MQ.L]);
|
|
789
|
+
}
|
|
790
|
+
function contextForCursor(cursor) {
|
|
791
|
+
// First, try to find any fraction to the right, unimpeded.
|
|
792
|
+
let visitor = cursor;
|
|
793
|
+
while (visitor[MQ.R] !== MathFieldActionType.MQ_END) {
|
|
794
|
+
if (isFraction(visitor[MQ.R])) {
|
|
795
|
+
return CursorContext.BEFORE_FRACTION;
|
|
796
|
+
} else if (!isLeaf(visitor[MQ.R])) {
|
|
797
|
+
break;
|
|
798
|
+
}
|
|
799
|
+
visitor = visitor[MQ.R];
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// If that didn't work, check if the parent or grandparent is a special
|
|
803
|
+
// context, so that we can jump outwards.
|
|
804
|
+
if (isParens(cursor.parent && cursor.parent.parent)) {
|
|
805
|
+
return CursorContext.IN_PARENS;
|
|
806
|
+
} else if (isNumerator(cursor.parent)) {
|
|
807
|
+
return CursorContext.IN_NUMERATOR;
|
|
808
|
+
} else if (isDenominator(cursor.parent)) {
|
|
809
|
+
return CursorContext.IN_DENOMINATOR;
|
|
810
|
+
} else if (isSubScript(cursor.parent)) {
|
|
811
|
+
return CursorContext.IN_SUB_SCRIPT;
|
|
812
|
+
} else if (isSuperScript(cursor.parent)) {
|
|
813
|
+
return CursorContext.IN_SUPER_SCRIPT;
|
|
814
|
+
} else {
|
|
815
|
+
return CursorContext.NONE;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
function handleLeftArrow(mathField, cursor) {
|
|
820
|
+
// If we're inside a function, and just after the left parentheses, we
|
|
821
|
+
// need to skip the entire function name, rather than move the cursor
|
|
822
|
+
// inside of it. For example, when hitting left from within the
|
|
823
|
+
// parentheses in `cos()`, we want to place the cursor to the left of
|
|
824
|
+
// the entire expression, rather than between the `s` and the left
|
|
825
|
+
// parenthesis.
|
|
826
|
+
// From the cursor's perspective, this requires that our left node is
|
|
827
|
+
// the ActionType.MQ_END node, that our grandparent is the left parenthesis, and
|
|
828
|
+
// the nodes to the left of our grandparent comprise a valid function
|
|
829
|
+
// name.
|
|
830
|
+
if (cursor[MQ.L] === MathFieldActionType.MQ_END) {
|
|
831
|
+
const parent = cursor.parent;
|
|
832
|
+
const grandparent = parent.parent;
|
|
833
|
+
if (grandparent.ctrlSeq === "\\left(") {
|
|
834
|
+
const command = maybeFindCommandBeforeParens(grandparent);
|
|
835
|
+
if (command) {
|
|
836
|
+
cursor.insLeftOf(command.startNode);
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
// Otherwise, we default to the standard MathQull left behavior.
|
|
843
|
+
mathField.keystroke("Left");
|
|
844
|
+
}
|
|
845
|
+
function handleRightArrow(mathField, cursor) {
|
|
846
|
+
const command = maybeFindCommand(cursor[MQ.R]);
|
|
847
|
+
if (command) {
|
|
848
|
+
// Similarly, if a function is to our right, then we need to place
|
|
849
|
+
// the cursor at the start of its parenthetical content, which is
|
|
850
|
+
// done by putting it to the left of ites parentheses and then
|
|
851
|
+
// moving right once.
|
|
852
|
+
cursor.insLeftOf(command.endNode);
|
|
853
|
+
mathField.keystroke("Right");
|
|
854
|
+
} else {
|
|
855
|
+
// Otherwise, we default to the standard MathQull right behavior.
|
|
856
|
+
mathField.keystroke("Right");
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
function handleArrow(mathField, key) {
|
|
860
|
+
const cursor = getCursor(mathField);
|
|
861
|
+
if (key === "LEFT") {
|
|
862
|
+
handleLeftArrow(mathField, cursor);
|
|
863
|
+
} else if (key === "RIGHT") {
|
|
864
|
+
handleRightArrow(mathField, cursor);
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
function handleBackspaceInNthRoot(mathField, cursor) {
|
|
869
|
+
const isAtLeftEnd = cursor[MQ.L] === MathFieldActionType.MQ_END;
|
|
870
|
+
const isRootEmpty = isInsideEmptyNode(cursor.parent.parent.blocks[0].ends);
|
|
871
|
+
if (isAtLeftEnd) {
|
|
872
|
+
selectNode(cursor.parent.parent, cursor);
|
|
873
|
+
if (isRootEmpty) {
|
|
874
|
+
mathField.keystroke("Backspace");
|
|
875
|
+
}
|
|
876
|
+
} else {
|
|
877
|
+
mathField.keystroke("Backspace");
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
function handleBackspaceInRootIndex(mathField, cursor) {
|
|
881
|
+
if (isInsideEmptyNode(cursor)) {
|
|
882
|
+
// When deleting the index in a nthroot, we change from the nthroot
|
|
883
|
+
// to a sqrt, e.g. \sqrt[|]{35x-5} => |\sqrt{35x-5}. If there's no
|
|
884
|
+
// content under the root, then we delete the whole thing.
|
|
885
|
+
|
|
886
|
+
const grandparent = cursor.parent.parent;
|
|
887
|
+
const latex = grandparent.latex();
|
|
888
|
+
const reinsertionPoint = grandparent[MQ.L];
|
|
889
|
+
selectNode(grandparent, cursor);
|
|
890
|
+
const rootIsEmpty = grandparent.blocks[1].jQ.text() === "";
|
|
891
|
+
if (rootIsEmpty) {
|
|
892
|
+
// If there is not content under the root then simply delete
|
|
893
|
+
// the whole thing.
|
|
894
|
+
mathField.keystroke("Backspace");
|
|
895
|
+
} else {
|
|
896
|
+
// Replace the nthroot with a sqrt if there was content under
|
|
897
|
+
// the root.
|
|
898
|
+
|
|
899
|
+
// Start by deleting the selection.
|
|
900
|
+
mathField.keystroke("Backspace");
|
|
901
|
+
|
|
902
|
+
// Replace the nth-root with a sqrt.
|
|
903
|
+
mathField.write(latex.replace(/^\\sqrt\[\]/, "\\sqrt"));
|
|
904
|
+
|
|
905
|
+
// Adjust the cursor to be to the left the sqrt.
|
|
906
|
+
if (reinsertionPoint === MathFieldActionType.MQ_END) {
|
|
907
|
+
mathField.moveToDirEnd(MQ.L);
|
|
908
|
+
} else {
|
|
909
|
+
cursor.insRightOf(reinsertionPoint);
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
} else {
|
|
913
|
+
if (cursor[MQ.L] !== MathFieldActionType.MQ_END) {
|
|
914
|
+
// If the cursor is not at the leftmost position inside the
|
|
915
|
+
// root's index, delete a character.
|
|
916
|
+
mathField.keystroke("Backspace");
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
}
|
|
920
|
+
function handleBackspaceInLogIndex(mathField, cursor) {
|
|
921
|
+
if (isInsideEmptyNode(cursor)) {
|
|
922
|
+
const grandparent = cursor.parent.parent;
|
|
923
|
+
const command = maybeFindCommandBeforeParens(grandparent);
|
|
924
|
+
cursor.insLeftOf(command == null ? void 0 : command.startNode);
|
|
925
|
+
cursor.startSelection();
|
|
926
|
+
if (grandparent[MQ.R] !== MathFieldActionType.MQ_END) {
|
|
927
|
+
cursor.insRightOf(grandparent[MQ.R]);
|
|
928
|
+
} else {
|
|
929
|
+
cursor.insRightOf(grandparent);
|
|
930
|
+
}
|
|
931
|
+
cursor.select();
|
|
932
|
+
cursor.endSelection();
|
|
933
|
+
const isLogBodyEmpty = grandparent[MQ.R].contentjQ.text() === "";
|
|
934
|
+
if (isLogBodyEmpty) {
|
|
935
|
+
// If there's no content inside the log's parens then delete the
|
|
936
|
+
// whole thing.
|
|
937
|
+
mathField.keystroke("Backspace");
|
|
938
|
+
}
|
|
939
|
+
} else {
|
|
940
|
+
mathField.keystroke("Backspace");
|
|
941
|
+
}
|
|
942
|
+
}
|
|
943
|
+
function handleBackspaceOutsideParens(cursor) {
|
|
944
|
+
// In this case the node with '\\left(' for its ctrlSeq
|
|
945
|
+
// is the parent of the expression contained within the
|
|
946
|
+
// parentheses.
|
|
947
|
+
//
|
|
948
|
+
// Handle selecting an expression before deleting:
|
|
949
|
+
// (x+1)| => |(x+1)|
|
|
950
|
+
// \log(x+1)| => |\log(x+1)|
|
|
951
|
+
|
|
952
|
+
const leftNode = cursor[MQ.L];
|
|
953
|
+
const rightNode = cursor[MQ.R];
|
|
954
|
+
const command = maybeFindCommandBeforeParens(leftNode);
|
|
955
|
+
if (command && command.startNode) {
|
|
956
|
+
// There's a command before the parens so we select it as well as
|
|
957
|
+
// the parens.
|
|
958
|
+
cursor.insLeftOf(command.startNode);
|
|
959
|
+
cursor.startSelection();
|
|
960
|
+
if (rightNode === MathFieldActionType.MQ_END) {
|
|
961
|
+
cursor.insAtRightEnd(cursor.parent);
|
|
962
|
+
} else {
|
|
963
|
+
cursor.insLeftOf(rightNode);
|
|
964
|
+
}
|
|
965
|
+
cursor.select();
|
|
966
|
+
cursor.endSelection();
|
|
967
|
+
} else {
|
|
968
|
+
cursor.startSelection();
|
|
969
|
+
cursor.insLeftOf(leftNode); // left of \\left(
|
|
970
|
+
cursor.select();
|
|
971
|
+
cursor.endSelection();
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
function handleBackspaceInsideParens(mathField, cursor) {
|
|
975
|
+
// Handle situations when the cursor is inside parens or a
|
|
976
|
+
// command that uses parens, e.g. \log() or \tan()
|
|
977
|
+
//
|
|
978
|
+
// MathQuill represents log(x+1) in roughly the following way
|
|
979
|
+
// [l, o, g, \\left[parent:[x, +, 1]]]
|
|
980
|
+
//
|
|
981
|
+
// If the cursor is inside the parentheses it's next to one of:
|
|
982
|
+
// x, +, or 1. This makes sub_sub_expr its parent and sub_expr
|
|
983
|
+
// it's parent.
|
|
984
|
+
//
|
|
985
|
+
// Interestingly parent doesn't have any nodes to the left or
|
|
986
|
+
// right of it (even though the corresponding DOM node has
|
|
987
|
+
// ( and ) characters on either side.
|
|
988
|
+
//
|
|
989
|
+
// The grandparent's ctrlSeq is `\\left(`. The `\\right)` isn't
|
|
990
|
+
// stored anywhere. NOTE(kevinb): I believe this is because
|
|
991
|
+
// MathQuill knows what the close paren should be and does the
|
|
992
|
+
// right thing at render time.
|
|
993
|
+
//
|
|
994
|
+
// This conditional branch handles the following cases:
|
|
995
|
+
// - \log(x+1|) => \log(x+|)
|
|
996
|
+
// - \log(|x+1) => |\log(x+1)|
|
|
997
|
+
// - \log(|) => |
|
|
998
|
+
|
|
999
|
+
if (cursor[MQ.L] !== MathFieldActionType.MQ_END) {
|
|
1000
|
+
// This command contains math and there's some math to
|
|
1001
|
+
// the left of the cursor that we should delete normally
|
|
1002
|
+
// before doing anything special.
|
|
1003
|
+
mathField.keystroke("Backspace");
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
1006
|
+
const grandparent = cursor.parent.parent;
|
|
1007
|
+
|
|
1008
|
+
// If the cursors is inside the parens at the start but the command
|
|
1009
|
+
// has a subscript as is the case in log_n then move the cursor into
|
|
1010
|
+
// the subscript, e.g. \log_{5}(|x+1) => \log_{5|}(x+1)
|
|
1011
|
+
|
|
1012
|
+
if (grandparent[MQ.L].sub) {
|
|
1013
|
+
// if there is a subscript
|
|
1014
|
+
if (grandparent[MQ.L].sub.jQ.text()) {
|
|
1015
|
+
// and it contains text
|
|
1016
|
+
// move the cursor to the right end of the subscript
|
|
1017
|
+
cursor.insAtRightEnd(grandparent[MQ.L].sub);
|
|
1018
|
+
return;
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
|
|
1022
|
+
// Determine if the parens are empty before we modify the
|
|
1023
|
+
// cursor's position.
|
|
1024
|
+
const isEmpty = isInsideEmptyNode(cursor);
|
|
1025
|
+
|
|
1026
|
+
// Insert the cursor to the left of the command if there is one
|
|
1027
|
+
// or before the '\\left(` if there isn't
|
|
1028
|
+
const command = maybeFindCommandBeforeParens(grandparent);
|
|
1029
|
+
cursor.insLeftOf(command && command.startNode || grandparent);
|
|
1030
|
+
cursor.startSelection();
|
|
1031
|
+
cursor.insRightOf(grandparent);
|
|
1032
|
+
cursor.select();
|
|
1033
|
+
cursor.endSelection();
|
|
1034
|
+
|
|
1035
|
+
// Delete the selection, but only if the parens were empty to
|
|
1036
|
+
// begin with.
|
|
1037
|
+
if (isEmpty) {
|
|
1038
|
+
mathField.keystroke("Backspace");
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
function handleBackspaceAfterLigaturedSymbol(mathField) {
|
|
1042
|
+
mathField.keystroke("Backspace");
|
|
1043
|
+
mathField.keystroke("Backspace");
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
/**
|
|
1047
|
+
* Selects and deletes part of the expression based on the cursor location.
|
|
1048
|
+
* See inline comments for precise behavior of different cases.
|
|
1049
|
+
*/
|
|
1050
|
+
function handleBackspace(mathField) {
|
|
1051
|
+
const cursor = getCursor(mathField);
|
|
1052
|
+
if (!cursor.selection) {
|
|
1053
|
+
const parent = cursor.parent;
|
|
1054
|
+
const grandparent = parent.parent;
|
|
1055
|
+
const leftNode = cursor[MQ.L];
|
|
1056
|
+
if (isFraction(leftNode)) {
|
|
1057
|
+
selectNode(leftNode, cursor);
|
|
1058
|
+
} else if (isSquareRoot(leftNode)) {
|
|
1059
|
+
selectNode(leftNode, cursor);
|
|
1060
|
+
} else if (isNthRoot(leftNode)) {
|
|
1061
|
+
selectNode(leftNode, cursor);
|
|
1062
|
+
} else if (isNthRootIndex(parent)) {
|
|
1063
|
+
handleBackspaceInRootIndex(mathField, cursor);
|
|
1064
|
+
} else if (leftNode.ctrlSeq === "\\left(") {
|
|
1065
|
+
handleBackspaceOutsideParens(cursor);
|
|
1066
|
+
} else if (grandparent.ctrlSeq === "\\left(") {
|
|
1067
|
+
handleBackspaceInsideParens(mathField, cursor);
|
|
1068
|
+
} else if (isInsideLogIndex(cursor)) {
|
|
1069
|
+
handleBackspaceInLogIndex(mathField, cursor);
|
|
1070
|
+
} else if (leftNode.ctrlSeq === "\\ge " || leftNode.ctrlSeq === "\\le ") {
|
|
1071
|
+
handleBackspaceAfterLigaturedSymbol(mathField);
|
|
1072
|
+
} else if (isNthRoot(grandparent) && leftNode === MathFieldActionType.MQ_END) {
|
|
1073
|
+
handleBackspaceInNthRoot(mathField, cursor);
|
|
1074
|
+
} else {
|
|
1075
|
+
mathField.keystroke("Backspace");
|
|
1076
|
+
}
|
|
1077
|
+
} else {
|
|
1078
|
+
mathField.keystroke("Backspace");
|
|
1079
|
+
}
|
|
1080
|
+
}
|
|
1081
|
+
|
|
1082
|
+
const ArithmeticOperators = ["+", "-", "\\cdot", "\\times", "\\div"];
|
|
1083
|
+
const EqualityOperators = ["=", "\\neq", "<", "\\leq", ">", "\\geq"];
|
|
1084
|
+
function handleExponent(mathField, key) {
|
|
1085
|
+
const cursor = getCursor(mathField);
|
|
1086
|
+
// If there's an invalid operator preceding the cursor (anything that
|
|
1087
|
+
// knowingly cannot be raised to a power), add an empty set of
|
|
1088
|
+
// parentheses and apply the exponent to that.
|
|
1089
|
+
const invalidPrefixes = [...ArithmeticOperators, ...EqualityOperators];
|
|
1090
|
+
const precedingNode = cursor[MQ.L];
|
|
1091
|
+
const shouldPrefixWithParens = precedingNode === MathFieldActionType.MQ_END || invalidPrefixes.includes(precedingNode.ctrlSeq.trim());
|
|
1092
|
+
if (shouldPrefixWithParens) {
|
|
1093
|
+
mathField.write("\\left(\\right)");
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
// Insert the appropriate exponent operator.
|
|
1097
|
+
switch (key) {
|
|
1098
|
+
case "EXP":
|
|
1099
|
+
mathField.cmd("^");
|
|
1100
|
+
break;
|
|
1101
|
+
case "EXP_2":
|
|
1102
|
+
case "EXP_3":
|
|
1103
|
+
mathField.write(`^${key === "EXP_2" ? 2 : 3}`);
|
|
1104
|
+
|
|
1105
|
+
// If we enter a square or a cube, we should leave the cursor
|
|
1106
|
+
// within the newly inserted parens, if they exist. This takes
|
|
1107
|
+
// exactly four left strokes, since the cursor by default would
|
|
1108
|
+
// end up to the right of the exponent.
|
|
1109
|
+
if (shouldPrefixWithParens) {
|
|
1110
|
+
mathField.keystroke("Left");
|
|
1111
|
+
mathField.keystroke("Left");
|
|
1112
|
+
mathField.keystroke("Left");
|
|
1113
|
+
mathField.keystroke("Left");
|
|
1114
|
+
}
|
|
1115
|
+
break;
|
|
1116
|
+
default:
|
|
1117
|
+
throw new Error(`Invalid exponent key: ${key}`);
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
|
|
605
1121
|
const KeysForJumpContext = {
|
|
606
|
-
[CursorContext.IN_PARENS]:
|
|
607
|
-
[CursorContext.IN_SUPER_SCRIPT]:
|
|
608
|
-
[CursorContext.IN_SUB_SCRIPT]:
|
|
609
|
-
[CursorContext.BEFORE_FRACTION]:
|
|
610
|
-
[CursorContext.IN_NUMERATOR]:
|
|
611
|
-
[CursorContext.IN_DENOMINATOR]:
|
|
1122
|
+
[CursorContext.IN_PARENS]: "JUMP_OUT_PARENTHESES",
|
|
1123
|
+
[CursorContext.IN_SUPER_SCRIPT]: "JUMP_OUT_EXPONENT",
|
|
1124
|
+
[CursorContext.IN_SUB_SCRIPT]: "JUMP_OUT_BASE",
|
|
1125
|
+
[CursorContext.BEFORE_FRACTION]: "JUMP_INTO_NUMERATOR",
|
|
1126
|
+
[CursorContext.IN_NUMERATOR]: "JUMP_OUT_NUMERATOR",
|
|
1127
|
+
[CursorContext.IN_DENOMINATOR]: "JUMP_OUT_DENOMINATOR"
|
|
612
1128
|
};
|
|
1129
|
+
|
|
1130
|
+
/**
|
|
1131
|
+
* Advances the cursor to the next logical position.
|
|
1132
|
+
*/
|
|
1133
|
+
function handleJumpOut(mathField, key) {
|
|
1134
|
+
const cursor = getCursor(mathField);
|
|
1135
|
+
const context = contextForCursor(cursor);
|
|
1136
|
+
|
|
1137
|
+
// Validate that the current cursor context matches the key's intent.
|
|
1138
|
+
if (KeysForJumpContext[context] !== key) {
|
|
1139
|
+
// If we don't have a valid cursor context, yet the user was able
|
|
1140
|
+
// to trigger a jump-out key, that's a broken invariant. Rather
|
|
1141
|
+
// than throw an error (which would kick the user out of the
|
|
1142
|
+
// exercise), we do nothing, as a fallback strategy. The user can
|
|
1143
|
+
// still move the cursor manually.
|
|
1144
|
+
return;
|
|
1145
|
+
}
|
|
1146
|
+
switch (context) {
|
|
1147
|
+
case CursorContext.IN_PARENS:
|
|
1148
|
+
// Insert at the end of the parentheses, and then navigate right
|
|
1149
|
+
// once more to get 'beyond' the parentheses.
|
|
1150
|
+
cursor.insRightOf(cursor.parent.parent);
|
|
1151
|
+
break;
|
|
1152
|
+
case CursorContext.BEFORE_FRACTION:
|
|
1153
|
+
// Find the nearest fraction to the right of the cursor.
|
|
1154
|
+
let fractionNode;
|
|
1155
|
+
let visitor = cursor;
|
|
1156
|
+
while (visitor[MQ.R] !== MathFieldActionType.MQ_END) {
|
|
1157
|
+
if (isFraction(visitor[MQ.R])) {
|
|
1158
|
+
fractionNode = visitor[MQ.R];
|
|
1159
|
+
}
|
|
1160
|
+
visitor = visitor[MQ.R];
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
// Jump into it!
|
|
1164
|
+
cursor.insLeftOf(fractionNode);
|
|
1165
|
+
mathField.keystroke("Right");
|
|
1166
|
+
break;
|
|
1167
|
+
case CursorContext.IN_NUMERATOR:
|
|
1168
|
+
// HACK(charlie): I can't find a better way to do this. The goal
|
|
1169
|
+
// is to place the cursor at the start of the matching
|
|
1170
|
+
// denominator. So, we identify the appropriate node, and
|
|
1171
|
+
// continue rightwards until we find ourselves inside of it.
|
|
1172
|
+
// It's possible that there are cases in which we don't reach
|
|
1173
|
+
// the denominator, though I can't think of any.
|
|
1174
|
+
const siblingDenominator = cursor.parent.parent.blocks[1];
|
|
1175
|
+
while (cursor.parent !== siblingDenominator) {
|
|
1176
|
+
mathField.keystroke("Right");
|
|
1177
|
+
}
|
|
1178
|
+
break;
|
|
1179
|
+
case CursorContext.IN_DENOMINATOR:
|
|
1180
|
+
cursor.insRightOf(cursor.parent.parent);
|
|
1181
|
+
break;
|
|
1182
|
+
case CursorContext.IN_SUB_SCRIPT:
|
|
1183
|
+
// Insert just beyond the superscript.
|
|
1184
|
+
cursor.insRightOf(cursor.parent.parent);
|
|
1185
|
+
|
|
1186
|
+
// Navigate right once more, if we're right before parens. This
|
|
1187
|
+
// is to handle the standard case in which the subscript is the
|
|
1188
|
+
// base of a custom log.
|
|
1189
|
+
if (isParens(cursor[MQ.R])) {
|
|
1190
|
+
mathField.keystroke("Right");
|
|
1191
|
+
}
|
|
1192
|
+
break;
|
|
1193
|
+
case CursorContext.IN_SUPER_SCRIPT:
|
|
1194
|
+
// Insert just beyond the superscript.
|
|
1195
|
+
cursor.insRightOf(cursor.parent.parent);
|
|
1196
|
+
break;
|
|
1197
|
+
default:
|
|
1198
|
+
throw new Error(`Attempted to 'Jump Out' from node, but found no ` + `appropriate cursor context: ${context}`);
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
function buildNormalFunctionCallback(command) {
|
|
1203
|
+
return function (mathField) {
|
|
1204
|
+
mathField.write(`\\${command}\\left(\\right)`);
|
|
1205
|
+
mathField.keystroke("Left");
|
|
1206
|
+
};
|
|
1207
|
+
}
|
|
1208
|
+
const customKeyTranslator = _extends({}, keyToMathquillMap, {
|
|
1209
|
+
// note(Matthew): in all likelihood, this should be moved
|
|
1210
|
+
// to the shared key2MathQuill translator. During this refactor
|
|
1211
|
+
// I tried to keep logic the same while deduplicating code.
|
|
1212
|
+
// Perseus' Expression MathInput treats this stuff differently
|
|
1213
|
+
// (or doesn't do anything with them at all), so I kept it that way
|
|
1214
|
+
BACKSPACE: handleBackspace,
|
|
1215
|
+
EXP: handleExponent,
|
|
1216
|
+
EXP_2: handleExponent,
|
|
1217
|
+
EXP_3: handleExponent,
|
|
1218
|
+
FRAC: mathQuill => {
|
|
1219
|
+
mathQuill.cmd("\\frac");
|
|
1220
|
+
},
|
|
1221
|
+
JUMP_OUT_PARENTHESES: handleJumpOut,
|
|
1222
|
+
JUMP_OUT_EXPONENT: handleJumpOut,
|
|
1223
|
+
JUMP_OUT_BASE: handleJumpOut,
|
|
1224
|
+
JUMP_INTO_NUMERATOR: handleJumpOut,
|
|
1225
|
+
JUMP_OUT_NUMERATOR: handleJumpOut,
|
|
1226
|
+
JUMP_OUT_DENOMINATOR: handleJumpOut,
|
|
1227
|
+
LEFT: handleArrow,
|
|
1228
|
+
RIGHT: handleArrow,
|
|
1229
|
+
LOG: buildNormalFunctionCallback("log"),
|
|
1230
|
+
LN: buildNormalFunctionCallback("ln"),
|
|
1231
|
+
SIN: buildNormalFunctionCallback("sin"),
|
|
1232
|
+
COS: buildNormalFunctionCallback("cos"),
|
|
1233
|
+
TAN: buildNormalFunctionCallback("tan")
|
|
1234
|
+
});
|
|
1235
|
+
|
|
1236
|
+
/**
|
|
1237
|
+
* This file contains a wrapper around MathQuill so that we can provide a
|
|
1238
|
+
* more regular interface for the functionality we need while insulating us
|
|
1239
|
+
* from MathQuill changes.
|
|
1240
|
+
*/
|
|
613
1241
|
class MathWrapper {
|
|
614
|
-
// MathQuill interface
|
|
615
1242
|
// MathQuill input
|
|
616
1243
|
|
|
617
1244
|
constructor(element, options = {}, callbacks = {}) {
|
|
618
|
-
this.MQ = void 0;
|
|
619
1245
|
this.mathField = void 0;
|
|
620
1246
|
this.callbacks = void 0;
|
|
621
|
-
this.
|
|
622
|
-
this.mathField = this.MQ.MathField(element, {
|
|
1247
|
+
this.mathField = MQ.MathField(element, {
|
|
623
1248
|
// use a span instead of a textarea so that we don't bring up the
|
|
624
1249
|
// native keyboard on mobile when selecting the input
|
|
625
1250
|
substituteTextarea: function () {
|
|
@@ -645,10 +1270,6 @@ class MathWrapper {
|
|
|
645
1270
|
controller.cursor.hide();
|
|
646
1271
|
controller.blurred = true;
|
|
647
1272
|
}
|
|
648
|
-
_writeNormalFunction(name) {
|
|
649
|
-
this.mathField.write(`\\${name}\\left(\\right)`);
|
|
650
|
-
this.mathField.keystroke("Left");
|
|
651
|
-
}
|
|
652
1273
|
|
|
653
1274
|
/**
|
|
654
1275
|
* Handle a key press and return the resulting cursor state.
|
|
@@ -657,51 +1278,10 @@ class MathWrapper {
|
|
|
657
1278
|
* @returns {object} a cursor object, consisting of a cursor context
|
|
658
1279
|
*/
|
|
659
1280
|
pressKey(key) {
|
|
660
|
-
const cursor = this.
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
fn
|
|
665
|
-
} = KeyActions[key];
|
|
666
|
-
if (str && fn) {
|
|
667
|
-
this.mathField[fn](str);
|
|
668
|
-
}
|
|
669
|
-
} else if (Object.keys(NormalCommands).includes(key)) {
|
|
670
|
-
this._writeNormalFunction(NormalCommands[key]);
|
|
671
|
-
} else if (key === Keys.FRAC_EXCLUSIVE) {
|
|
672
|
-
// If there's nothing to the left of the cursor, then we want to
|
|
673
|
-
// leave the cursor to the left of the fraction after creating it.
|
|
674
|
-
const shouldNavigateLeft = cursor[this.MQ.L] === ActionType.MQ_END;
|
|
675
|
-
this.mathField.cmd("\\frac");
|
|
676
|
-
if (shouldNavigateLeft) {
|
|
677
|
-
this.mathField.keystroke("Left");
|
|
678
|
-
}
|
|
679
|
-
} else if (key === Keys.FRAC) {
|
|
680
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
681
|
-
cursor[this.MQ.L] === ActionType.MQ_END;
|
|
682
|
-
this.mathField.cmd("\\frac");
|
|
683
|
-
} else if (key === Keys.LOG_N) {
|
|
684
|
-
this.mathField.write("log_{ }\\left(\\right)");
|
|
685
|
-
this.mathField.keystroke("Left"); // into parentheses
|
|
686
|
-
this.mathField.keystroke("Left"); // out of parentheses
|
|
687
|
-
this.mathField.keystroke("Left"); // into index
|
|
688
|
-
} else if (key === Keys.CUBE_ROOT) {
|
|
689
|
-
this.mathField.write("\\sqrt[3]{}");
|
|
690
|
-
this.mathField.keystroke("Left"); // under the root
|
|
691
|
-
} else if (key === Keys.EXP || key === Keys.EXP_2 || key === Keys.EXP_3) {
|
|
692
|
-
this._handleExponent(cursor, key);
|
|
693
|
-
} else if (key === Keys.JUMP_OUT_PARENTHESES || key === Keys.JUMP_OUT_EXPONENT || key === Keys.JUMP_OUT_BASE || key === Keys.JUMP_INTO_NUMERATOR || key === Keys.JUMP_OUT_NUMERATOR || key === Keys.JUMP_OUT_DENOMINATOR) {
|
|
694
|
-
this._handleJumpOut(cursor, key);
|
|
695
|
-
} else if (key === Keys.BACKSPACE) {
|
|
696
|
-
this._handleBackspace(cursor);
|
|
697
|
-
} else if (key === Keys.LEFT) {
|
|
698
|
-
this._handleLeftArrow(cursor);
|
|
699
|
-
} else if (key === Keys.RIGHT) {
|
|
700
|
-
this._handleRightArrow(cursor);
|
|
701
|
-
} else if (/^[a-zA-Z]$/.test(key)) {
|
|
702
|
-
this.mathField[ActionType.WRITE](key);
|
|
703
|
-
} else if (/^NUM_\d/.test(key)) {
|
|
704
|
-
this.mathField[ActionType.WRITE](key[4]);
|
|
1281
|
+
const cursor = this.getCursor();
|
|
1282
|
+
const translator = customKeyTranslator[key];
|
|
1283
|
+
if (translator) {
|
|
1284
|
+
translator(this.mathField, key);
|
|
705
1285
|
}
|
|
706
1286
|
if (!cursor.selection) {
|
|
707
1287
|
// don't show the cursor for selections
|
|
@@ -747,7 +1327,7 @@ class MathWrapper {
|
|
|
747
1327
|
// Unless that would leave us mid-command, in which case, we
|
|
748
1328
|
// need to adjust and place the cursor inside the parens
|
|
749
1329
|
// following the command.
|
|
750
|
-
const command =
|
|
1330
|
+
const command = maybeFindCommand(cursor[MQ.L]);
|
|
751
1331
|
if (command && command.endNode) {
|
|
752
1332
|
// NOTE(charlie): endNode should definitely be \left(.
|
|
753
1333
|
cursor.insLeftOf(command.endNode);
|
|
@@ -761,8 +1341,17 @@ class MathWrapper {
|
|
|
761
1341
|
}
|
|
762
1342
|
}
|
|
763
1343
|
}
|
|
1344
|
+
|
|
1345
|
+
// note(Matthew): extracted this logic to share it elsewhere,
|
|
1346
|
+
// but it's part of the public MathWrapper API
|
|
764
1347
|
getCursor() {
|
|
765
|
-
return this.mathField
|
|
1348
|
+
return getCursor(this.mathField);
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
// note(Matthew): extracted this logic to keep this file focused,
|
|
1352
|
+
// but it's part of the public MathWrapper API
|
|
1353
|
+
contextForCursor(cursor) {
|
|
1354
|
+
return contextForCursor(cursor);
|
|
766
1355
|
}
|
|
767
1356
|
getSelection() {
|
|
768
1357
|
return this.getCursor().selection;
|
|
@@ -777,576 +1366,6 @@ class MathWrapper {
|
|
|
777
1366
|
const cursor = this.getCursor();
|
|
778
1367
|
return cursor.parent.id === 1 && cursor[1] === 0 && cursor[-1] === 0;
|
|
779
1368
|
}
|
|
780
|
-
|
|
781
|
-
// Notes about MathQuill
|
|
782
|
-
//
|
|
783
|
-
// MathQuill's stores its layout as nested linked lists. Each node in the
|
|
784
|
-
// list has this.MQ.L '-1' and this.MQ.R '1' properties that define links to
|
|
785
|
-
// the left and right nodes respectively. They also have
|
|
786
|
-
//
|
|
787
|
-
// ctrlSeq: contains the latex code snippet that defines that node.
|
|
788
|
-
// jQ: jQuery object for the DOM node(s) for this MathQuill node.
|
|
789
|
-
// ends: pointers to the nodes at the ends of the container.
|
|
790
|
-
// parent: parent node.
|
|
791
|
-
// blocks: an array containing one or more nodes that make up the node.
|
|
792
|
-
// sub?: subscript node if there is one as is the case in log_n
|
|
793
|
-
//
|
|
794
|
-
// All of the code below is super fragile. Please be especially careful
|
|
795
|
-
// when upgrading MathQuill.
|
|
796
|
-
|
|
797
|
-
_handleBackspaceInNthRoot(cursor) {
|
|
798
|
-
const isAtLeftEnd = cursor[this.MQ.L] === ActionType.MQ_END;
|
|
799
|
-
const isRootEmpty = this._isInsideEmptyNode(cursor.parent.parent.blocks[0].ends);
|
|
800
|
-
if (isAtLeftEnd) {
|
|
801
|
-
this._selectNode(cursor.parent.parent, cursor);
|
|
802
|
-
if (isRootEmpty) {
|
|
803
|
-
this.mathField.keystroke("Backspace");
|
|
804
|
-
}
|
|
805
|
-
} else {
|
|
806
|
-
this.mathField.keystroke("Backspace");
|
|
807
|
-
}
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
/**
|
|
811
|
-
* Advances the cursor to the next logical position.
|
|
812
|
-
*
|
|
813
|
-
* @param {cursor} cursor
|
|
814
|
-
* @private
|
|
815
|
-
*/
|
|
816
|
-
_handleJumpOut(cursor, key) {
|
|
817
|
-
const context = this.contextForCursor(cursor);
|
|
818
|
-
|
|
819
|
-
// Validate that the current cursor context matches the key's intent.
|
|
820
|
-
if (KeysForJumpContext[context] !== key) {
|
|
821
|
-
// If we don't have a valid cursor context, yet the user was able
|
|
822
|
-
// to trigger a jump-out key, that's a broken invariant. Rather
|
|
823
|
-
// than throw an error (which would kick the user out of the
|
|
824
|
-
// exercise), we do nothing, as a fallback strategy. The user can
|
|
825
|
-
// still move the cursor manually.
|
|
826
|
-
return;
|
|
827
|
-
}
|
|
828
|
-
switch (context) {
|
|
829
|
-
case CursorContext.IN_PARENS:
|
|
830
|
-
// Insert at the end of the parentheses, and then navigate right
|
|
831
|
-
// once more to get 'beyond' the parentheses.
|
|
832
|
-
cursor.insRightOf(cursor.parent.parent);
|
|
833
|
-
break;
|
|
834
|
-
case CursorContext.BEFORE_FRACTION:
|
|
835
|
-
// Find the nearest fraction to the right of the cursor.
|
|
836
|
-
let fractionNode;
|
|
837
|
-
let visitor = cursor;
|
|
838
|
-
while (visitor[this.MQ.R] !== ActionType.MQ_END) {
|
|
839
|
-
if (this._isFraction(visitor[this.MQ.R])) {
|
|
840
|
-
fractionNode = visitor[this.MQ.R];
|
|
841
|
-
}
|
|
842
|
-
visitor = visitor[this.MQ.R];
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
// Jump into it!
|
|
846
|
-
cursor.insLeftOf(fractionNode);
|
|
847
|
-
this.mathField.keystroke("Right");
|
|
848
|
-
break;
|
|
849
|
-
case CursorContext.IN_NUMERATOR:
|
|
850
|
-
// HACK(charlie): I can't find a better way to do this. The goal
|
|
851
|
-
// is to place the cursor at the start of the matching
|
|
852
|
-
// denominator. So, we identify the appropriate node, and
|
|
853
|
-
// continue rightwards until we find ourselves inside of it.
|
|
854
|
-
// It's possible that there are cases in which we don't reach
|
|
855
|
-
// the denominator, though I can't think of any.
|
|
856
|
-
const siblingDenominator = cursor.parent.parent.blocks[1];
|
|
857
|
-
while (cursor.parent !== siblingDenominator) {
|
|
858
|
-
this.mathField.keystroke("Right");
|
|
859
|
-
}
|
|
860
|
-
break;
|
|
861
|
-
case CursorContext.IN_DENOMINATOR:
|
|
862
|
-
cursor.insRightOf(cursor.parent.parent);
|
|
863
|
-
break;
|
|
864
|
-
case CursorContext.IN_SUB_SCRIPT:
|
|
865
|
-
// Insert just beyond the superscript.
|
|
866
|
-
cursor.insRightOf(cursor.parent.parent);
|
|
867
|
-
|
|
868
|
-
// Navigate right once more, if we're right before parens. This
|
|
869
|
-
// is to handle the standard case in which the subscript is the
|
|
870
|
-
// base of a custom log.
|
|
871
|
-
if (this._isParens(cursor[this.MQ.R])) {
|
|
872
|
-
this.mathField.keystroke("Right");
|
|
873
|
-
}
|
|
874
|
-
break;
|
|
875
|
-
case CursorContext.IN_SUPER_SCRIPT:
|
|
876
|
-
// Insert just beyond the superscript.
|
|
877
|
-
cursor.insRightOf(cursor.parent.parent);
|
|
878
|
-
break;
|
|
879
|
-
default:
|
|
880
|
-
throw new Error(`Attempted to 'Jump Out' from node, but found no ` + `appropriate cursor context: ${context}`);
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
|
|
884
|
-
/**
|
|
885
|
-
* Selects and deletes part of the expression based on the cursor location.
|
|
886
|
-
* See inline comments for precise behavior of different cases.
|
|
887
|
-
*
|
|
888
|
-
* @param {cursor} cursor
|
|
889
|
-
* @private
|
|
890
|
-
*/
|
|
891
|
-
_handleBackspace(cursor) {
|
|
892
|
-
if (!cursor.selection) {
|
|
893
|
-
const parent = cursor.parent;
|
|
894
|
-
const grandparent = parent.parent;
|
|
895
|
-
const leftNode = cursor[this.MQ.L];
|
|
896
|
-
if (this._isFraction(leftNode)) {
|
|
897
|
-
this._selectNode(leftNode, cursor);
|
|
898
|
-
} else if (this._isSquareRoot(leftNode)) {
|
|
899
|
-
this._selectNode(leftNode, cursor);
|
|
900
|
-
} else if (this._isNthRoot(leftNode)) {
|
|
901
|
-
this._selectNode(leftNode, cursor);
|
|
902
|
-
} else if (this._isNthRootIndex(parent)) {
|
|
903
|
-
this._handleBackspaceInRootIndex(cursor);
|
|
904
|
-
} else if (leftNode.ctrlSeq === "\\left(") {
|
|
905
|
-
this._handleBackspaceOutsideParens(cursor);
|
|
906
|
-
} else if (grandparent.ctrlSeq === "\\left(") {
|
|
907
|
-
this._handleBackspaceInsideParens(cursor);
|
|
908
|
-
} else if (this._isInsideLogIndex(cursor)) {
|
|
909
|
-
this._handleBackspaceInLogIndex(cursor);
|
|
910
|
-
} else if (leftNode.ctrlSeq === "\\ge " || leftNode.ctrlSeq === "\\le ") {
|
|
911
|
-
this._handleBackspaceAfterLigaturedSymbol(cursor);
|
|
912
|
-
} else if (this._isNthRoot(grandparent) && leftNode === ActionType.MQ_END) {
|
|
913
|
-
this._handleBackspaceInNthRoot(cursor);
|
|
914
|
-
} else {
|
|
915
|
-
this.mathField.keystroke("Backspace");
|
|
916
|
-
}
|
|
917
|
-
} else {
|
|
918
|
-
this.mathField.keystroke("Backspace");
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
_handleLeftArrow(cursor) {
|
|
922
|
-
// If we're inside a function, and just after the left parentheses, we
|
|
923
|
-
// need to skip the entire function name, rather than move the cursor
|
|
924
|
-
// inside of it. For example, when hitting left from within the
|
|
925
|
-
// parentheses in `cos()`, we want to place the cursor to the left of
|
|
926
|
-
// the entire expression, rather than between the `s` and the left
|
|
927
|
-
// parenthesis.
|
|
928
|
-
// From the cursor's perspective, this requires that our left node is
|
|
929
|
-
// the ActionType.MQ_END node, that our grandparent is the left parenthesis, and
|
|
930
|
-
// the nodes to the left of our grandparent comprise a valid function
|
|
931
|
-
// name.
|
|
932
|
-
if (cursor[this.MQ.L] === ActionType.MQ_END) {
|
|
933
|
-
const parent = cursor.parent;
|
|
934
|
-
const grandparent = parent.parent;
|
|
935
|
-
if (grandparent.ctrlSeq === "\\left(") {
|
|
936
|
-
const command = this._maybeFindCommandBeforeParens(grandparent);
|
|
937
|
-
if (command) {
|
|
938
|
-
cursor.insLeftOf(command.startNode);
|
|
939
|
-
return;
|
|
940
|
-
}
|
|
941
|
-
}
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
// Otherwise, we default to the standard MathQull left behavior.
|
|
945
|
-
this.mathField.keystroke("Left");
|
|
946
|
-
}
|
|
947
|
-
_handleRightArrow(cursor) {
|
|
948
|
-
const command = this._maybeFindCommand(cursor[this.MQ.R]);
|
|
949
|
-
if (command) {
|
|
950
|
-
// Similarly, if a function is to our right, then we need to place
|
|
951
|
-
// the cursor at the start of its parenthetical content, which is
|
|
952
|
-
// done by putting it to the left of ites parentheses and then
|
|
953
|
-
// moving right once.
|
|
954
|
-
cursor.insLeftOf(command.endNode);
|
|
955
|
-
this.mathField.keystroke("Right");
|
|
956
|
-
} else {
|
|
957
|
-
// Otherwise, we default to the standard MathQull right behavior.
|
|
958
|
-
this.mathField.keystroke("Right");
|
|
959
|
-
}
|
|
960
|
-
}
|
|
961
|
-
_handleExponent(cursor, key) {
|
|
962
|
-
// If there's an invalid operator preceding the cursor (anything that
|
|
963
|
-
// knowingly cannot be raised to a power), add an empty set of
|
|
964
|
-
// parentheses and apply the exponent to that.
|
|
965
|
-
const invalidPrefixes = [...ArithmeticOperators, ...EqualityOperators];
|
|
966
|
-
const precedingNode = cursor[this.MQ.L];
|
|
967
|
-
const shouldPrefixWithParens = precedingNode === ActionType.MQ_END || invalidPrefixes.includes(precedingNode.ctrlSeq.trim());
|
|
968
|
-
if (shouldPrefixWithParens) {
|
|
969
|
-
this.mathField.write("\\left(\\right)");
|
|
970
|
-
}
|
|
971
|
-
|
|
972
|
-
// Insert the appropriate exponent operator.
|
|
973
|
-
switch (key) {
|
|
974
|
-
case Keys.EXP:
|
|
975
|
-
this.mathField.cmd("^");
|
|
976
|
-
break;
|
|
977
|
-
case Keys.EXP_2:
|
|
978
|
-
case Keys.EXP_3:
|
|
979
|
-
this.mathField.write(`^${key === Keys.EXP_2 ? 2 : 3}`);
|
|
980
|
-
|
|
981
|
-
// If we enter a square or a cube, we should leave the cursor
|
|
982
|
-
// within the newly inserted parens, if they exist. This takes
|
|
983
|
-
// exactly four left strokes, since the cursor by default would
|
|
984
|
-
// end up to the right of the exponent.
|
|
985
|
-
if (shouldPrefixWithParens) {
|
|
986
|
-
this.mathField.keystroke("Left");
|
|
987
|
-
this.mathField.keystroke("Left");
|
|
988
|
-
this.mathField.keystroke("Left");
|
|
989
|
-
this.mathField.keystroke("Left");
|
|
990
|
-
}
|
|
991
|
-
break;
|
|
992
|
-
default:
|
|
993
|
-
throw new Error(`Invalid exponent key: ${key}`);
|
|
994
|
-
}
|
|
995
|
-
}
|
|
996
|
-
|
|
997
|
-
/**
|
|
998
|
-
* Return the start node, end node, and full name of the command of which
|
|
999
|
-
* the initial node is a part, or `null` if the node is not part of a
|
|
1000
|
-
* command.
|
|
1001
|
-
*
|
|
1002
|
-
* @param {node} initialNode - the node to included as part of the command
|
|
1003
|
-
* @returns {null|object} - `null` or an object containing the start node
|
|
1004
|
-
* (`startNode`), end node (`endNode`), and full
|
|
1005
|
-
* name (`name`) of the command
|
|
1006
|
-
* @private
|
|
1007
|
-
*/
|
|
1008
|
-
_maybeFindCommand(initialNode) {
|
|
1009
|
-
if (!initialNode) {
|
|
1010
|
-
return null;
|
|
1011
|
-
}
|
|
1012
|
-
|
|
1013
|
-
// MathQuill stores commands as separate characters so that
|
|
1014
|
-
// users can delete commands one character at a time. We iterate over
|
|
1015
|
-
// the nodes from right to left until we hit a sequence starting with a
|
|
1016
|
-
// '\\', which signifies the start of a command; then we iterate from
|
|
1017
|
-
// left to right until we hit a '\\left(', which signifies the end of a
|
|
1018
|
-
// command. If we encounter any character that doesn't belong in a
|
|
1019
|
-
// command, we return null. We match a single character at a time.
|
|
1020
|
-
// Ex) ['\\l', 'o', 'g ', '\\left(', ...]
|
|
1021
|
-
const commandCharRegex = /^[a-z]$/;
|
|
1022
|
-
const commandStartRegex = /^\\[a-z]$/;
|
|
1023
|
-
const commandEndSeq = "\\left(";
|
|
1024
|
-
|
|
1025
|
-
// Note: We allowlist the set of valid commands, since relying solely on
|
|
1026
|
-
// a command being prefixed with a backslash leads to undesired
|
|
1027
|
-
// behavior. For example, Greek symbols, left parentheses, and square
|
|
1028
|
-
// roots all get treated as commands.
|
|
1029
|
-
const validCommands = ["\\log", "\\ln", "\\cos", "\\sin", "\\tan"];
|
|
1030
|
-
let name = "";
|
|
1031
|
-
let startNode;
|
|
1032
|
-
let endNode;
|
|
1033
|
-
|
|
1034
|
-
// Collect the portion of the command from the current node, leftwards
|
|
1035
|
-
// until the start of the command.
|
|
1036
|
-
let node = initialNode;
|
|
1037
|
-
while (node !== 0) {
|
|
1038
|
-
const ctrlSeq = node.ctrlSeq.trim();
|
|
1039
|
-
if (commandCharRegex.test(ctrlSeq)) {
|
|
1040
|
-
name = ctrlSeq + name;
|
|
1041
|
-
} else if (commandStartRegex.test(ctrlSeq)) {
|
|
1042
|
-
name = ctrlSeq + name;
|
|
1043
|
-
startNode = node;
|
|
1044
|
-
break;
|
|
1045
|
-
} else {
|
|
1046
|
-
break;
|
|
1047
|
-
}
|
|
1048
|
-
node = node[this.MQ.L];
|
|
1049
|
-
}
|
|
1050
|
-
|
|
1051
|
-
// If we hit the start of a command, then grab the rest of it by
|
|
1052
|
-
// iterating rightwards to compute the full name of the command, along
|
|
1053
|
-
// with its terminal node.
|
|
1054
|
-
if (startNode) {
|
|
1055
|
-
// Next, iterate from the start to the right.
|
|
1056
|
-
node = initialNode[this.MQ.R];
|
|
1057
|
-
while (node !== 0) {
|
|
1058
|
-
const ctrlSeq = node.ctrlSeq.trim();
|
|
1059
|
-
if (commandCharRegex.test(ctrlSeq)) {
|
|
1060
|
-
// If we have a single character, add it to the command
|
|
1061
|
-
// name.
|
|
1062
|
-
name = name + ctrlSeq;
|
|
1063
|
-
} else if (ctrlSeq === commandEndSeq) {
|
|
1064
|
-
// If we hit the command end delimiter (the left
|
|
1065
|
-
// parentheses surrounding its arguments), stop.
|
|
1066
|
-
endNode = node;
|
|
1067
|
-
break;
|
|
1068
|
-
}
|
|
1069
|
-
node = node[this.MQ.R];
|
|
1070
|
-
}
|
|
1071
|
-
if (validCommands.includes(name)) {
|
|
1072
|
-
return {
|
|
1073
|
-
name,
|
|
1074
|
-
startNode,
|
|
1075
|
-
endNode
|
|
1076
|
-
};
|
|
1077
|
-
} else {
|
|
1078
|
-
return null;
|
|
1079
|
-
}
|
|
1080
|
-
} else {
|
|
1081
|
-
return null;
|
|
1082
|
-
}
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
|
-
/**
|
|
1086
|
-
* Return the start node, end node, and full name of the command to the left
|
|
1087
|
-
* of `\\left(`, or `null` if there is no command.
|
|
1088
|
-
*
|
|
1089
|
-
* @param {node} leftParenNode - node where .ctrlSeq == `\\left(`
|
|
1090
|
-
* @returns {null|object} - `null` or an object containing the start node
|
|
1091
|
-
* (`startNode`), end node (`endNode`), and full
|
|
1092
|
-
* name (`name`) of the command
|
|
1093
|
-
* @private
|
|
1094
|
-
*/
|
|
1095
|
-
_maybeFindCommandBeforeParens(leftParenNode) {
|
|
1096
|
-
return this._maybeFindCommand(leftParenNode[this.MQ.L]);
|
|
1097
|
-
}
|
|
1098
|
-
_selectNode(node, cursor) {
|
|
1099
|
-
cursor.insLeftOf(node);
|
|
1100
|
-
cursor.startSelection();
|
|
1101
|
-
cursor.insRightOf(node);
|
|
1102
|
-
cursor.select();
|
|
1103
|
-
cursor.endSelection();
|
|
1104
|
-
}
|
|
1105
|
-
_isFraction(node) {
|
|
1106
|
-
return node.jQ && node.jQ.hasClass("mq-fraction");
|
|
1107
|
-
}
|
|
1108
|
-
_isNumerator(node) {
|
|
1109
|
-
return node.jQ && node.jQ.hasClass("mq-numerator");
|
|
1110
|
-
}
|
|
1111
|
-
_isDenominator(node) {
|
|
1112
|
-
return node.jQ && node.jQ.hasClass("mq-denominator");
|
|
1113
|
-
}
|
|
1114
|
-
_isSubScript(node) {
|
|
1115
|
-
// NOTE(charlie): MyScript has a structure whereby its superscripts seem
|
|
1116
|
-
// to be represented as a parent node with 'mq-sup-only' containing a
|
|
1117
|
-
// single child with 'mq-sup'.
|
|
1118
|
-
return node.jQ && (node.jQ.hasClass("mq-sub-only") || node.jQ.hasClass("mq-sub"));
|
|
1119
|
-
}
|
|
1120
|
-
_isSuperScript(node) {
|
|
1121
|
-
// NOTE(charlie): MyScript has a structure whereby its superscripts seem
|
|
1122
|
-
// to be represented as a parent node with 'mq-sup-only' containing a
|
|
1123
|
-
// single child with 'mq-sup'.
|
|
1124
|
-
return node.jQ && (node.jQ.hasClass("mq-sup-only") || node.jQ.hasClass("mq-sup"));
|
|
1125
|
-
}
|
|
1126
|
-
_isParens(node) {
|
|
1127
|
-
return node && node.ctrlSeq === "\\left(";
|
|
1128
|
-
}
|
|
1129
|
-
_isLeaf(node) {
|
|
1130
|
-
return node && node.ctrlSeq && ValidLeaves.includes(node.ctrlSeq.trim());
|
|
1131
|
-
}
|
|
1132
|
-
_isSquareRoot(node) {
|
|
1133
|
-
return node.blocks && node.blocks[0].jQ && node.blocks[0].jQ.hasClass("mq-sqrt-stem");
|
|
1134
|
-
}
|
|
1135
|
-
_isNthRoot(node) {
|
|
1136
|
-
return node.blocks && node.blocks[0].jQ && node.blocks[0].jQ.hasClass("mq-nthroot");
|
|
1137
|
-
}
|
|
1138
|
-
_isNthRootIndex(node) {
|
|
1139
|
-
return node.jQ && node.jQ.hasClass("mq-nthroot");
|
|
1140
|
-
}
|
|
1141
|
-
_isInsideLogIndex(cursor) {
|
|
1142
|
-
const grandparent = cursor.parent.parent;
|
|
1143
|
-
if (grandparent && grandparent.jQ.hasClass("mq-supsub")) {
|
|
1144
|
-
const command = this._maybeFindCommandBeforeParens(grandparent);
|
|
1145
|
-
if (command && command.name === "\\log") {
|
|
1146
|
-
return true;
|
|
1147
|
-
}
|
|
1148
|
-
}
|
|
1149
|
-
return false;
|
|
1150
|
-
}
|
|
1151
|
-
_isInsideEmptyNode(cursor) {
|
|
1152
|
-
return cursor[this.MQ.L] === ActionType.MQ_END && cursor[this.MQ.R] === ActionType.MQ_END;
|
|
1153
|
-
}
|
|
1154
|
-
_handleBackspaceInRootIndex(cursor) {
|
|
1155
|
-
if (this._isInsideEmptyNode(cursor)) {
|
|
1156
|
-
// When deleting the index in a nthroot, we change from the nthroot
|
|
1157
|
-
// to a sqrt, e.g. \sqrt[|]{35x-5} => |\sqrt{35x-5}. If there's no
|
|
1158
|
-
// content under the root, then we delete the whole thing.
|
|
1159
|
-
|
|
1160
|
-
const grandparent = cursor.parent.parent;
|
|
1161
|
-
const latex = grandparent.latex();
|
|
1162
|
-
const reinsertionPoint = grandparent[this.MQ.L];
|
|
1163
|
-
this._selectNode(grandparent, cursor);
|
|
1164
|
-
const rootIsEmpty = grandparent.blocks[1].jQ.text() === "";
|
|
1165
|
-
if (rootIsEmpty) {
|
|
1166
|
-
// If there is not content under the root then simply delete
|
|
1167
|
-
// the whole thing.
|
|
1168
|
-
this.mathField.keystroke("Backspace");
|
|
1169
|
-
} else {
|
|
1170
|
-
// Replace the nthroot with a sqrt if there was content under
|
|
1171
|
-
// the root.
|
|
1172
|
-
|
|
1173
|
-
// Start by deleting the selection.
|
|
1174
|
-
this.mathField.keystroke("Backspace");
|
|
1175
|
-
|
|
1176
|
-
// Replace the nth-root with a sqrt.
|
|
1177
|
-
this.mathField.write(latex.replace(/^\\sqrt\[\]/, "\\sqrt"));
|
|
1178
|
-
|
|
1179
|
-
// Adjust the cursor to be to the left the sqrt.
|
|
1180
|
-
if (reinsertionPoint === ActionType.MQ_END) {
|
|
1181
|
-
this.mathField.moveToDirEnd(this.MQ.L);
|
|
1182
|
-
} else {
|
|
1183
|
-
cursor.insRightOf(reinsertionPoint);
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
1186
|
-
} else {
|
|
1187
|
-
if (cursor[this.MQ.L] !== ActionType.MQ_END) {
|
|
1188
|
-
// If the cursor is not at the leftmost position inside the
|
|
1189
|
-
// root's index, delete a character.
|
|
1190
|
-
this.mathField.keystroke("Backspace");
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
}
|
|
1194
|
-
_handleBackspaceInLogIndex(cursor) {
|
|
1195
|
-
if (this._isInsideEmptyNode(cursor)) {
|
|
1196
|
-
const grandparent = cursor.parent.parent;
|
|
1197
|
-
const command = this._maybeFindCommandBeforeParens(grandparent);
|
|
1198
|
-
cursor.insLeftOf(command == null ? void 0 : command.startNode);
|
|
1199
|
-
cursor.startSelection();
|
|
1200
|
-
if (grandparent[this.MQ.R] !== ActionType.MQ_END) {
|
|
1201
|
-
cursor.insRightOf(grandparent[this.MQ.R]);
|
|
1202
|
-
} else {
|
|
1203
|
-
cursor.insRightOf(grandparent);
|
|
1204
|
-
}
|
|
1205
|
-
cursor.select();
|
|
1206
|
-
cursor.endSelection();
|
|
1207
|
-
const isLogBodyEmpty = grandparent[this.MQ.R].contentjQ.text() === "";
|
|
1208
|
-
if (isLogBodyEmpty) {
|
|
1209
|
-
// If there's no content inside the log's parens then delete the
|
|
1210
|
-
// whole thing.
|
|
1211
|
-
this.mathField.keystroke("Backspace");
|
|
1212
|
-
}
|
|
1213
|
-
} else {
|
|
1214
|
-
this.mathField.keystroke("Backspace");
|
|
1215
|
-
}
|
|
1216
|
-
}
|
|
1217
|
-
_handleBackspaceOutsideParens(cursor) {
|
|
1218
|
-
// In this case the node with '\\left(' for its ctrlSeq
|
|
1219
|
-
// is the parent of the expression contained within the
|
|
1220
|
-
// parentheses.
|
|
1221
|
-
//
|
|
1222
|
-
// Handle selecting an expression before deleting:
|
|
1223
|
-
// (x+1)| => |(x+1)|
|
|
1224
|
-
// \log(x+1)| => |\log(x+1)|
|
|
1225
|
-
|
|
1226
|
-
const leftNode = cursor[this.MQ.L];
|
|
1227
|
-
const rightNode = cursor[this.MQ.R];
|
|
1228
|
-
const command = this._maybeFindCommandBeforeParens(leftNode);
|
|
1229
|
-
if (command && command.startNode) {
|
|
1230
|
-
// There's a command before the parens so we select it as well as
|
|
1231
|
-
// the parens.
|
|
1232
|
-
cursor.insLeftOf(command.startNode);
|
|
1233
|
-
cursor.startSelection();
|
|
1234
|
-
if (rightNode === ActionType.MQ_END) {
|
|
1235
|
-
cursor.insAtRightEnd(cursor.parent);
|
|
1236
|
-
} else {
|
|
1237
|
-
cursor.insLeftOf(rightNode);
|
|
1238
|
-
}
|
|
1239
|
-
cursor.select();
|
|
1240
|
-
cursor.endSelection();
|
|
1241
|
-
} else {
|
|
1242
|
-
cursor.startSelection();
|
|
1243
|
-
cursor.insLeftOf(leftNode); // left of \\left(
|
|
1244
|
-
cursor.select();
|
|
1245
|
-
cursor.endSelection();
|
|
1246
|
-
}
|
|
1247
|
-
}
|
|
1248
|
-
_handleBackspaceInsideParens(cursor) {
|
|
1249
|
-
// Handle situations when the cursor is inside parens or a
|
|
1250
|
-
// command that uses parens, e.g. \log() or \tan()
|
|
1251
|
-
//
|
|
1252
|
-
// MathQuill represents log(x+1) in roughly the following way
|
|
1253
|
-
// [l, o, g, \\left[parent:[x, +, 1]]]
|
|
1254
|
-
//
|
|
1255
|
-
// If the cursor is inside the parentheses it's next to one of:
|
|
1256
|
-
// x, +, or 1. This makes sub_sub_expr its parent and sub_expr
|
|
1257
|
-
// it's parent.
|
|
1258
|
-
//
|
|
1259
|
-
// Interestingly parent doesn't have any nodes to the left or
|
|
1260
|
-
// right of it (even though the corresponding DOM node has
|
|
1261
|
-
// ( and ) characters on either side.
|
|
1262
|
-
//
|
|
1263
|
-
// The grandparent's ctrlSeq is `\\left(`. The `\\right)` isn't
|
|
1264
|
-
// stored anywhere. NOTE(kevinb): I believe this is because
|
|
1265
|
-
// MathQuill knows what the close paren should be and does the
|
|
1266
|
-
// right thing at render time.
|
|
1267
|
-
//
|
|
1268
|
-
// This conditional branch handles the following cases:
|
|
1269
|
-
// - \log(x+1|) => \log(x+|)
|
|
1270
|
-
// - \log(|x+1) => |\log(x+1)|
|
|
1271
|
-
// - \log(|) => |
|
|
1272
|
-
|
|
1273
|
-
if (cursor[this.MQ.L] !== ActionType.MQ_END) {
|
|
1274
|
-
// This command contains math and there's some math to
|
|
1275
|
-
// the left of the cursor that we should delete normally
|
|
1276
|
-
// before doing anything special.
|
|
1277
|
-
this.mathField.keystroke("Backspace");
|
|
1278
|
-
return;
|
|
1279
|
-
}
|
|
1280
|
-
const grandparent = cursor.parent.parent;
|
|
1281
|
-
|
|
1282
|
-
// If the cursors is inside the parens at the start but the command
|
|
1283
|
-
// has a subscript as is the case in log_n then move the cursor into
|
|
1284
|
-
// the subscript, e.g. \log_{5}(|x+1) => \log_{5|}(x+1)
|
|
1285
|
-
|
|
1286
|
-
if (grandparent[this.MQ.L].sub) {
|
|
1287
|
-
// if there is a subscript
|
|
1288
|
-
if (grandparent[this.MQ.L].sub.jQ.text()) {
|
|
1289
|
-
// and it contains text
|
|
1290
|
-
// move the cursor to the right end of the subscript
|
|
1291
|
-
cursor.insAtRightEnd(grandparent[this.MQ.L].sub);
|
|
1292
|
-
return;
|
|
1293
|
-
}
|
|
1294
|
-
}
|
|
1295
|
-
|
|
1296
|
-
// Determine if the parens are empty before we modify the
|
|
1297
|
-
// cursor's position.
|
|
1298
|
-
const isEmpty = this._isInsideEmptyNode(cursor);
|
|
1299
|
-
|
|
1300
|
-
// Insert the cursor to the left of the command if there is one
|
|
1301
|
-
// or before the '\\left(` if there isn't
|
|
1302
|
-
const command = this._maybeFindCommandBeforeParens(grandparent);
|
|
1303
|
-
cursor.insLeftOf(command && command.startNode || grandparent);
|
|
1304
|
-
cursor.startSelection();
|
|
1305
|
-
cursor.insRightOf(grandparent);
|
|
1306
|
-
cursor.select();
|
|
1307
|
-
cursor.endSelection();
|
|
1308
|
-
|
|
1309
|
-
// Delete the selection, but only if the parens were empty to
|
|
1310
|
-
// begin with.
|
|
1311
|
-
if (isEmpty) {
|
|
1312
|
-
this.mathField.keystroke("Backspace");
|
|
1313
|
-
}
|
|
1314
|
-
}
|
|
1315
|
-
_handleBackspaceAfterLigaturedSymbol(cursor) {
|
|
1316
|
-
this.mathField.keystroke("Backspace");
|
|
1317
|
-
this.mathField.keystroke("Backspace");
|
|
1318
|
-
}
|
|
1319
|
-
contextForCursor(cursor) {
|
|
1320
|
-
// First, try to find any fraction to the right, unimpeded.
|
|
1321
|
-
let visitor = cursor;
|
|
1322
|
-
while (visitor[this.MQ.R] !== ActionType.MQ_END) {
|
|
1323
|
-
if (this._isFraction(visitor[this.MQ.R])) {
|
|
1324
|
-
return CursorContext.BEFORE_FRACTION;
|
|
1325
|
-
} else if (!this._isLeaf(visitor[this.MQ.R])) {
|
|
1326
|
-
break;
|
|
1327
|
-
}
|
|
1328
|
-
visitor = visitor[this.MQ.R];
|
|
1329
|
-
}
|
|
1330
|
-
|
|
1331
|
-
// If that didn't work, check if the parent or grandparent is a special
|
|
1332
|
-
// context, so that we can jump outwards.
|
|
1333
|
-
if (this._isParens(cursor.parent && cursor.parent.parent)) {
|
|
1334
|
-
return CursorContext.IN_PARENS;
|
|
1335
|
-
} else if (this._isNumerator(cursor.parent)) {
|
|
1336
|
-
return CursorContext.IN_NUMERATOR;
|
|
1337
|
-
} else if (this._isDenominator(cursor.parent)) {
|
|
1338
|
-
return CursorContext.IN_DENOMINATOR;
|
|
1339
|
-
} else if (this._isSubScript(cursor.parent)) {
|
|
1340
|
-
return CursorContext.IN_SUB_SCRIPT;
|
|
1341
|
-
} else if (this._isSuperScript(cursor.parent)) {
|
|
1342
|
-
return CursorContext.IN_SUPER_SCRIPT;
|
|
1343
|
-
} else {
|
|
1344
|
-
return CursorContext.NONE;
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1347
|
-
_isAtTopLevel(cursor) {
|
|
1348
|
-
return !cursor.parent.parent;
|
|
1349
|
-
}
|
|
1350
1369
|
}
|
|
1351
1370
|
|
|
1352
1371
|
/**
|
|
@@ -1805,16 +1824,16 @@ class MathInput extends React.Component {
|
|
|
1805
1824
|
};
|
|
1806
1825
|
this.domKeyToMathQuillKey = key => {
|
|
1807
1826
|
const keyMap = {
|
|
1808
|
-
"+":
|
|
1809
|
-
"-":
|
|
1810
|
-
"*":
|
|
1811
|
-
"/":
|
|
1812
|
-
".":
|
|
1813
|
-
"%":
|
|
1814
|
-
"=":
|
|
1815
|
-
">":
|
|
1816
|
-
"<":
|
|
1817
|
-
"^":
|
|
1827
|
+
"+": "PLUS",
|
|
1828
|
+
"-": "MINUS",
|
|
1829
|
+
"*": "TIMES",
|
|
1830
|
+
"/": "DIVIDE",
|
|
1831
|
+
".": "DECIMAL",
|
|
1832
|
+
"%": "PERCENT",
|
|
1833
|
+
"=": "EQUAL",
|
|
1834
|
+
">": "GT",
|
|
1835
|
+
"<": "LT",
|
|
1836
|
+
"^": "EXP"
|
|
1818
1837
|
};
|
|
1819
1838
|
|
|
1820
1839
|
// Numbers
|
|
@@ -1824,7 +1843,7 @@ class MathInput extends React.Component {
|
|
|
1824
1843
|
|
|
1825
1844
|
// Movement keys
|
|
1826
1845
|
else if (key === "Backspace") {
|
|
1827
|
-
return
|
|
1846
|
+
return "BACKSPACE";
|
|
1828
1847
|
}
|
|
1829
1848
|
|
|
1830
1849
|
// Operators
|
|
@@ -2116,40 +2135,84 @@ const keypadElementPropType = PropTypes.shape({
|
|
|
2116
2135
|
getDOMNode: PropTypes.func.isRequired
|
|
2117
2136
|
});
|
|
2118
2137
|
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2138
|
+
const getDefaultOperatorFields = ({
|
|
2139
|
+
key,
|
|
2140
|
+
keyType: _keyType = "OPERATOR",
|
|
2141
|
+
iconType: _iconType = IconType.SVG,
|
|
2142
|
+
ariaLabel: _ariaLabel = key,
|
|
2143
|
+
data: _data = key
|
|
2144
|
+
}) => ({
|
|
2145
|
+
id: key,
|
|
2146
|
+
type: _keyType,
|
|
2147
|
+
ariaLabel: _ariaLabel,
|
|
2148
|
+
icon: {
|
|
2149
|
+
type: _iconType,
|
|
2150
|
+
data: _data
|
|
2151
|
+
}
|
|
2152
|
+
});
|
|
2153
|
+
const getDefaultValueFields = ({
|
|
2154
|
+
key,
|
|
2155
|
+
keyType: _keyType2 = "VALUE",
|
|
2156
|
+
iconType: _iconType2 = IconType.MATH,
|
|
2157
|
+
ariaLabel: _ariaLabel2 = key,
|
|
2158
|
+
data: _data2 = key
|
|
2159
|
+
}) => ({
|
|
2160
|
+
id: key,
|
|
2161
|
+
type: _keyType2,
|
|
2162
|
+
ariaLabel: _ariaLabel2,
|
|
2163
|
+
icon: {
|
|
2164
|
+
type: _iconType2,
|
|
2165
|
+
data: _data2
|
|
2166
|
+
}
|
|
2167
|
+
});
|
|
2168
|
+
const getDefaultNumberFields = ({
|
|
2169
|
+
key,
|
|
2170
|
+
data: _data3 = key.replace("NUM_", ""),
|
|
2171
|
+
keyType: _keyType3 = "VALUE",
|
|
2172
|
+
iconType: _iconType3 = IconType.TEXT,
|
|
2173
|
+
ariaLabel: _ariaLabel3 = _data3
|
|
2174
|
+
}) => ({
|
|
2175
|
+
id: key,
|
|
2176
|
+
type: _keyType3,
|
|
2177
|
+
ariaLabel: _ariaLabel3,
|
|
2178
|
+
icon: {
|
|
2179
|
+
type: _iconType3,
|
|
2180
|
+
data: _data3
|
|
2181
|
+
}
|
|
2182
|
+
});
|
|
2122
2183
|
const KeyConfigs = {
|
|
2123
|
-
// Basic math
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
// I18N: A label for a plus sign.
|
|
2184
|
+
// Basic math
|
|
2185
|
+
PLUS: _extends({}, getDefaultOperatorFields({
|
|
2186
|
+
key: "PLUS",
|
|
2187
|
+
// I18N: A label for a 'plus' sign.
|
|
2127
2188
|
ariaLabel: i18n._("Plus")
|
|
2128
|
-
},
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
// I18N: A label for a minus sign.
|
|
2189
|
+
})),
|
|
2190
|
+
MINUS: _extends({}, getDefaultOperatorFields({
|
|
2191
|
+
key: "MINUS",
|
|
2192
|
+
// I18N: A label for a 'minus' sign.
|
|
2132
2193
|
ariaLabel: i18n._("Minus")
|
|
2133
|
-
},
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
// I18N: A label for a
|
|
2194
|
+
})),
|
|
2195
|
+
NEGATIVE: _extends({}, getDefaultOperatorFields({
|
|
2196
|
+
key: "NEGATIVE",
|
|
2197
|
+
// I18N: A label for a 'negative' sign.
|
|
2137
2198
|
ariaLabel: i18n._("Negative")
|
|
2138
|
-
},
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
// I18N: A label for a
|
|
2199
|
+
})),
|
|
2200
|
+
TIMES: _extends({}, getDefaultOperatorFields({
|
|
2201
|
+
key: "TIMES",
|
|
2202
|
+
// I18N: A label for a 'multiply' sign.
|
|
2142
2203
|
ariaLabel: i18n._("Multiply")
|
|
2143
|
-
},
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
// I18N: A label for a
|
|
2204
|
+
})),
|
|
2205
|
+
DIVIDE: _extends({}, getDefaultOperatorFields({
|
|
2206
|
+
key: "DIVIDE",
|
|
2207
|
+
// I18N: A label for a 'divide' sign.
|
|
2147
2208
|
ariaLabel: i18n._("Divide")
|
|
2148
|
-
},
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2209
|
+
})),
|
|
2210
|
+
DECIMAL: _extends({}, getDefaultOperatorFields({
|
|
2211
|
+
key: "DECIMAL",
|
|
2212
|
+
keyType: "VALUE",
|
|
2213
|
+
// I18N: A label for a 'decimal' sign (represented as '.' or ',').
|
|
2214
|
+
ariaLabel: i18n._("Decimal")
|
|
2215
|
+
}), {
|
|
2153
2216
|
icon: decimalSeparator === DecimalSeparator.COMMA ? {
|
|
2154
2217
|
// TODO(charlie): Get an SVG icon for the comma, or verify with
|
|
2155
2218
|
// design that the text-rendered version is acceptable.
|
|
@@ -2157,252 +2220,447 @@ const KeyConfigs = {
|
|
|
2157
2220
|
data: ","
|
|
2158
2221
|
} : {
|
|
2159
2222
|
type: IconType.SVG,
|
|
2160
|
-
data:
|
|
2223
|
+
data: "PERIOD"
|
|
2161
2224
|
}
|
|
2162
|
-
},
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2225
|
+
}),
|
|
2226
|
+
PERIOD: _extends({}, getDefaultOperatorFields({
|
|
2227
|
+
key: "PERIOD",
|
|
2228
|
+
keyType: "VALUE",
|
|
2229
|
+
ariaLabel: "."
|
|
2230
|
+
})),
|
|
2231
|
+
PERCENT: _extends({}, getDefaultOperatorFields({
|
|
2232
|
+
key: "PERCENT",
|
|
2233
|
+
// I18N: A label for a 'percent' sign (represented as '%').
|
|
2166
2234
|
ariaLabel: i18n._("Percent")
|
|
2167
|
-
},
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
// I18N: A label for a multiplication sign (represented as
|
|
2235
|
+
})),
|
|
2236
|
+
CDOT: _extends({}, getDefaultOperatorFields({
|
|
2237
|
+
key: "CDOT",
|
|
2238
|
+
// I18N: A label for a 'centered dot' multiplication sign (represented as '⋅').
|
|
2171
2239
|
ariaLabel: i18n._("Multiply")
|
|
2172
|
-
},
|
|
2173
|
-
|
|
2174
|
-
|
|
2240
|
+
})),
|
|
2241
|
+
EQUAL: _extends({}, getDefaultOperatorFields({
|
|
2242
|
+
key: "EQUAL",
|
|
2243
|
+
// I18N: A label for an 'equals' sign (represented as '=').
|
|
2175
2244
|
ariaLabel: i18n._("Equals sign")
|
|
2176
|
-
},
|
|
2177
|
-
|
|
2178
|
-
|
|
2245
|
+
})),
|
|
2246
|
+
NEQ: _extends({}, getDefaultOperatorFields({
|
|
2247
|
+
key: "NEQ",
|
|
2248
|
+
// I18N: A label for a 'not-equals' sign (represented as '≠').
|
|
2179
2249
|
ariaLabel: i18n._("Not-equals sign")
|
|
2180
|
-
},
|
|
2181
|
-
|
|
2182
|
-
|
|
2250
|
+
})),
|
|
2251
|
+
GT: _extends({}, getDefaultOperatorFields({
|
|
2252
|
+
key: "GT",
|
|
2183
2253
|
// I18N: A label for a 'greater than' sign (represented as '>').
|
|
2184
2254
|
ariaLabel: i18n._("Greater than sign")
|
|
2185
|
-
},
|
|
2186
|
-
|
|
2187
|
-
|
|
2255
|
+
})),
|
|
2256
|
+
LT: _extends({}, getDefaultOperatorFields({
|
|
2257
|
+
key: "LT",
|
|
2188
2258
|
// I18N: A label for a 'less than' sign (represented as '<').
|
|
2189
2259
|
ariaLabel: i18n._("Less than sign")
|
|
2190
|
-
},
|
|
2191
|
-
|
|
2192
|
-
|
|
2260
|
+
})),
|
|
2261
|
+
GEQ: _extends({}, getDefaultOperatorFields({
|
|
2262
|
+
key: "GEQ",
|
|
2263
|
+
// I18N: A label for a 'greater than or equal to' sign (represented as '≥').
|
|
2193
2264
|
ariaLabel: i18n._("Greater than or equal to sign")
|
|
2194
|
-
},
|
|
2195
|
-
|
|
2196
|
-
|
|
2265
|
+
})),
|
|
2266
|
+
LEQ: _extends({}, getDefaultOperatorFields({
|
|
2267
|
+
key: "LEQ",
|
|
2268
|
+
// I18N: A label for a 'less than or equal to' sign (represented as '≤').
|
|
2197
2269
|
ariaLabel: i18n._("Less than or equal to sign")
|
|
2198
|
-
},
|
|
2270
|
+
})),
|
|
2199
2271
|
// mobile native
|
|
2200
|
-
|
|
2201
|
-
|
|
2272
|
+
FRAC_INCLUSIVE: _extends({}, getDefaultOperatorFields({
|
|
2273
|
+
key: "FRAC_INCLUSIVE",
|
|
2202
2274
|
// I18N: A label for a button that creates a new fraction and puts the
|
|
2203
2275
|
// current expression in the numerator of that fraction.
|
|
2204
2276
|
ariaLabel: i18n._("Fraction, with current expression in numerator")
|
|
2205
|
-
},
|
|
2277
|
+
})),
|
|
2206
2278
|
// mobile native
|
|
2207
|
-
|
|
2208
|
-
|
|
2279
|
+
FRAC_EXCLUSIVE: _extends({}, getDefaultOperatorFields({
|
|
2280
|
+
key: "FRAC_EXCLUSIVE",
|
|
2209
2281
|
// I18N: A label for a button that creates a new fraction next to the
|
|
2210
2282
|
// cursor.
|
|
2211
2283
|
ariaLabel: i18n._("Fraction, excluding the current expression")
|
|
2212
|
-
},
|
|
2284
|
+
})),
|
|
2213
2285
|
// mobile web
|
|
2214
|
-
|
|
2215
|
-
|
|
2286
|
+
FRAC: _extends({}, getDefaultOperatorFields({
|
|
2287
|
+
key: "FRAC",
|
|
2216
2288
|
// I18N: A label for a button that creates a new fraction next to the
|
|
2217
2289
|
// cursor.
|
|
2218
2290
|
ariaLabel: i18n._("Fraction, excluding the current expression")
|
|
2219
|
-
},
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
// I18N: A label for a button that will allow the user to input a
|
|
2223
|
-
// exponent.
|
|
2291
|
+
})),
|
|
2292
|
+
EXP: _extends({}, getDefaultOperatorFields({
|
|
2293
|
+
key: "EXP",
|
|
2294
|
+
// I18N: A label for a button that will allow the user to input a
|
|
2295
|
+
// custom exponent.
|
|
2224
2296
|
ariaLabel: i18n._("Custom exponent")
|
|
2225
|
-
},
|
|
2226
|
-
|
|
2227
|
-
|
|
2297
|
+
})),
|
|
2298
|
+
EXP_2: _extends({}, getDefaultOperatorFields({
|
|
2299
|
+
key: "EXP_2",
|
|
2228
2300
|
// I18N: A label for a button that will square (take to the second
|
|
2229
2301
|
// power) some math.
|
|
2230
2302
|
ariaLabel: i18n._("Square")
|
|
2231
|
-
},
|
|
2232
|
-
|
|
2233
|
-
|
|
2303
|
+
})),
|
|
2304
|
+
EXP_3: _extends({}, getDefaultOperatorFields({
|
|
2305
|
+
key: "EXP_3",
|
|
2234
2306
|
// I18N: A label for a button that will cube (take to the third power)
|
|
2235
2307
|
// some math.
|
|
2236
2308
|
ariaLabel: i18n._("Cube")
|
|
2237
|
-
},
|
|
2238
|
-
|
|
2239
|
-
|
|
2309
|
+
})),
|
|
2310
|
+
SQRT: _extends({}, getDefaultOperatorFields({
|
|
2311
|
+
key: "SQRT",
|
|
2312
|
+
// I18N: A label for a button that will allow the user to input a
|
|
2313
|
+
// square root.
|
|
2240
2314
|
ariaLabel: i18n._("Square root")
|
|
2241
|
-
},
|
|
2242
|
-
|
|
2243
|
-
|
|
2315
|
+
})),
|
|
2316
|
+
CUBE_ROOT: _extends({}, getDefaultOperatorFields({
|
|
2317
|
+
key: "CUBE_ROOT",
|
|
2318
|
+
// I18N: A label for a button that will allow the user to input a
|
|
2319
|
+
// cube root.
|
|
2244
2320
|
ariaLabel: i18n._("Cube root")
|
|
2245
|
-
},
|
|
2246
|
-
|
|
2247
|
-
|
|
2321
|
+
})),
|
|
2322
|
+
RADICAL: _extends({}, getDefaultOperatorFields({
|
|
2323
|
+
key: "RADICAL",
|
|
2324
|
+
// I18N: A label for a button that will allow the user to input a
|
|
2325
|
+
// radical with a custom root.
|
|
2248
2326
|
ariaLabel: i18n._("Radical with custom root")
|
|
2249
|
-
},
|
|
2250
|
-
|
|
2251
|
-
|
|
2327
|
+
})),
|
|
2328
|
+
LEFT_PAREN: _extends({}, getDefaultOperatorFields({
|
|
2329
|
+
key: "LEFT_PAREN",
|
|
2330
|
+
// I18N: A label for a button that will allow the user to input a
|
|
2331
|
+
// left parenthesis (i.e. '(')
|
|
2252
2332
|
ariaLabel: i18n._("Left parenthesis")
|
|
2253
|
-
},
|
|
2254
|
-
|
|
2255
|
-
|
|
2333
|
+
})),
|
|
2334
|
+
RIGHT_PAREN: _extends({}, getDefaultOperatorFields({
|
|
2335
|
+
key: "RIGHT_PAREN",
|
|
2336
|
+
// I18N: A label for a button that will allow the user to input a
|
|
2337
|
+
// right parenthesis (i.e. ')')
|
|
2256
2338
|
ariaLabel: i18n._("Right parenthesis")
|
|
2257
|
-
},
|
|
2258
|
-
|
|
2259
|
-
|
|
2339
|
+
})),
|
|
2340
|
+
LN: _extends({}, getDefaultOperatorFields({
|
|
2341
|
+
key: "LN",
|
|
2342
|
+
// I18N: A label for a button that will allow the user to input a
|
|
2343
|
+
// natural logarithm.
|
|
2260
2344
|
ariaLabel: i18n._("Natural logarithm")
|
|
2261
|
-
},
|
|
2262
|
-
|
|
2263
|
-
|
|
2345
|
+
})),
|
|
2346
|
+
LOG: _extends({}, getDefaultOperatorFields({
|
|
2347
|
+
key: "LOG",
|
|
2348
|
+
// I18N: A label for a button that will allow the user to input a
|
|
2349
|
+
// logarithm with base 10.
|
|
2264
2350
|
ariaLabel: i18n._("Logarithm with base 10")
|
|
2265
|
-
},
|
|
2266
|
-
|
|
2267
|
-
|
|
2351
|
+
})),
|
|
2352
|
+
LOG_N: _extends({}, getDefaultOperatorFields({
|
|
2353
|
+
key: "LOG_N",
|
|
2354
|
+
// I18N: A label for a button that will allow the user to input a
|
|
2355
|
+
// logarithm with a custom base.
|
|
2268
2356
|
ariaLabel: i18n._("Logarithm with custom base")
|
|
2269
|
-
},
|
|
2270
|
-
|
|
2271
|
-
|
|
2357
|
+
})),
|
|
2358
|
+
SIN: _extends({}, getDefaultOperatorFields({
|
|
2359
|
+
key: "SIN",
|
|
2360
|
+
// I18N: A label for a button that will allow the user to input a
|
|
2361
|
+
// sine function.
|
|
2272
2362
|
ariaLabel: i18n._("Sine")
|
|
2273
|
-
},
|
|
2274
|
-
|
|
2275
|
-
|
|
2363
|
+
})),
|
|
2364
|
+
COS: _extends({}, getDefaultOperatorFields({
|
|
2365
|
+
key: "COS",
|
|
2366
|
+
// I18N: A label for a button that will allow the user to input a
|
|
2367
|
+
// cosine function.
|
|
2276
2368
|
ariaLabel: i18n._("Cosine")
|
|
2277
|
-
},
|
|
2278
|
-
|
|
2279
|
-
|
|
2369
|
+
})),
|
|
2370
|
+
TAN: _extends({}, getDefaultOperatorFields({
|
|
2371
|
+
key: "TAN",
|
|
2372
|
+
// I18N: A label for a button that will allow the user to input a
|
|
2373
|
+
// tangent function.
|
|
2280
2374
|
ariaLabel: i18n._("Tangent")
|
|
2281
|
-
},
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
},
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2375
|
+
})),
|
|
2376
|
+
PI: _extends({}, getDefaultValueFields({
|
|
2377
|
+
key: "PI",
|
|
2378
|
+
data: "\\pi",
|
|
2379
|
+
// I18N: A label for a button that will allow the user to input the
|
|
2380
|
+
// mathematical constant pi (i.e., π)
|
|
2381
|
+
ariaLabel: i18n._("Pi")
|
|
2382
|
+
})),
|
|
2383
|
+
THETA: _extends({}, getDefaultValueFields({
|
|
2384
|
+
key: "THETA",
|
|
2385
|
+
data: "\\theta",
|
|
2386
|
+
// I18N: A label for a button that will allow the user to input the
|
|
2387
|
+
// mathematical constant theta (i.e., θ)
|
|
2388
|
+
ariaLabel: i18n._("Theta")
|
|
2389
|
+
})),
|
|
2390
|
+
NOOP: _extends({}, getDefaultOperatorFields({
|
|
2391
|
+
key: "NOOP",
|
|
2392
|
+
keyType: "EMPTY"
|
|
2393
|
+
})),
|
|
2394
|
+
// Input navigation
|
|
2395
|
+
UP: _extends({}, getDefaultOperatorFields({
|
|
2396
|
+
key: "UP",
|
|
2397
|
+
keyType: "INPUT_NAVIGATION",
|
|
2304
2398
|
ariaLabel: i18n._("Up arrow")
|
|
2305
|
-
},
|
|
2306
|
-
|
|
2307
|
-
|
|
2399
|
+
})),
|
|
2400
|
+
RIGHT: _extends({}, getDefaultOperatorFields({
|
|
2401
|
+
key: "RIGHT",
|
|
2402
|
+
keyType: "INPUT_NAVIGATION",
|
|
2308
2403
|
ariaLabel: i18n._("Right arrow")
|
|
2309
|
-
},
|
|
2310
|
-
|
|
2311
|
-
|
|
2404
|
+
})),
|
|
2405
|
+
DOWN: _extends({}, getDefaultOperatorFields({
|
|
2406
|
+
key: "DOWN",
|
|
2407
|
+
keyType: "INPUT_NAVIGATION",
|
|
2312
2408
|
ariaLabel: i18n._("Down arrow")
|
|
2313
|
-
},
|
|
2314
|
-
|
|
2315
|
-
|
|
2409
|
+
})),
|
|
2410
|
+
LEFT: _extends({}, getDefaultOperatorFields({
|
|
2411
|
+
key: "LEFT",
|
|
2412
|
+
keyType: "INPUT_NAVIGATION",
|
|
2316
2413
|
ariaLabel: i18n._("Left arrow")
|
|
2317
|
-
},
|
|
2318
|
-
|
|
2319
|
-
|
|
2414
|
+
})),
|
|
2415
|
+
JUMP_OUT_PARENTHESES: _extends({}, getDefaultOperatorFields({
|
|
2416
|
+
key: "JUMP_OUT_PARENTHESES",
|
|
2417
|
+
keyType: "INPUT_NAVIGATION",
|
|
2320
2418
|
ariaLabel: i18n._("Navigate right out of a set of parentheses")
|
|
2321
|
-
},
|
|
2322
|
-
|
|
2323
|
-
|
|
2419
|
+
})),
|
|
2420
|
+
JUMP_OUT_EXPONENT: _extends({}, getDefaultOperatorFields({
|
|
2421
|
+
key: "JUMP_OUT_EXPONENT",
|
|
2422
|
+
keyType: "INPUT_NAVIGATION",
|
|
2324
2423
|
ariaLabel: i18n._("Navigate right out of an exponent")
|
|
2325
|
-
},
|
|
2326
|
-
|
|
2327
|
-
|
|
2424
|
+
})),
|
|
2425
|
+
JUMP_OUT_BASE: _extends({}, getDefaultOperatorFields({
|
|
2426
|
+
key: "JUMP_OUT_BASE",
|
|
2427
|
+
keyType: "INPUT_NAVIGATION",
|
|
2328
2428
|
ariaLabel: i18n._("Navigate right out of a base")
|
|
2329
|
-
},
|
|
2330
|
-
|
|
2331
|
-
|
|
2429
|
+
})),
|
|
2430
|
+
JUMP_INTO_NUMERATOR: _extends({}, getDefaultOperatorFields({
|
|
2431
|
+
key: "JUMP_INTO_NUMERATOR",
|
|
2432
|
+
keyType: "INPUT_NAVIGATION",
|
|
2332
2433
|
ariaLabel: i18n._("Navigate right into the numerator of a fraction")
|
|
2333
|
-
},
|
|
2334
|
-
|
|
2335
|
-
|
|
2434
|
+
})),
|
|
2435
|
+
JUMP_OUT_NUMERATOR: _extends({}, getDefaultOperatorFields({
|
|
2436
|
+
key: "JUMP_OUT_NUMERATOR",
|
|
2437
|
+
keyType: "INPUT_NAVIGATION",
|
|
2336
2438
|
ariaLabel: i18n._("Navigate right out of the numerator and into the denominator")
|
|
2337
|
-
},
|
|
2338
|
-
|
|
2339
|
-
|
|
2439
|
+
})),
|
|
2440
|
+
JUMP_OUT_DENOMINATOR: _extends({}, getDefaultOperatorFields({
|
|
2441
|
+
key: "JUMP_OUT_DENOMINATOR",
|
|
2442
|
+
keyType: "INPUT_NAVIGATION",
|
|
2340
2443
|
ariaLabel: i18n._("Navigate right out of the denominator of a fraction")
|
|
2341
|
-
},
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2444
|
+
})),
|
|
2445
|
+
BACKSPACE: _extends({}, getDefaultOperatorFields({
|
|
2446
|
+
key: "BACKSPACE",
|
|
2447
|
+
keyType: "INPUT_NAVIGATION",
|
|
2345
2448
|
ariaLabel: i18n._("Delete")
|
|
2346
|
-
},
|
|
2347
|
-
// Keypad navigation
|
|
2348
|
-
|
|
2349
|
-
|
|
2449
|
+
})),
|
|
2450
|
+
// Keypad navigation
|
|
2451
|
+
DISMISS: _extends({}, getDefaultOperatorFields({
|
|
2452
|
+
key: "DISMISS",
|
|
2453
|
+
keyType: "KEYPAD_NAVIGATION",
|
|
2350
2454
|
// I18N: A label for a button that will dismiss/hide a keypad.
|
|
2351
2455
|
ariaLabel: i18n._("Dismiss")
|
|
2352
|
-
},
|
|
2456
|
+
})),
|
|
2353
2457
|
// TODO(charlie): Use the numeral color for the 'Many' key.
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2458
|
+
MANY: _extends({}, getDefaultOperatorFields({
|
|
2459
|
+
key: "MANY",
|
|
2460
|
+
keyType: "MANY"
|
|
2461
|
+
})),
|
|
2462
|
+
// NUMBERS
|
|
2463
|
+
NUM_0: _extends({}, getDefaultNumberFields({
|
|
2464
|
+
key: "NUM_0"
|
|
2465
|
+
})),
|
|
2466
|
+
NUM_1: _extends({}, getDefaultNumberFields({
|
|
2467
|
+
key: "NUM_1"
|
|
2468
|
+
})),
|
|
2469
|
+
NUM_2: _extends({}, getDefaultNumberFields({
|
|
2470
|
+
key: "NUM_2"
|
|
2471
|
+
})),
|
|
2472
|
+
NUM_3: _extends({}, getDefaultNumberFields({
|
|
2473
|
+
key: "NUM_3"
|
|
2474
|
+
})),
|
|
2475
|
+
NUM_4: _extends({}, getDefaultNumberFields({
|
|
2476
|
+
key: "NUM_4"
|
|
2477
|
+
})),
|
|
2478
|
+
NUM_5: _extends({}, getDefaultNumberFields({
|
|
2479
|
+
key: "NUM_5"
|
|
2480
|
+
})),
|
|
2481
|
+
NUM_6: _extends({}, getDefaultNumberFields({
|
|
2482
|
+
key: "NUM_6"
|
|
2483
|
+
})),
|
|
2484
|
+
NUM_7: _extends({}, getDefaultNumberFields({
|
|
2485
|
+
key: "NUM_7"
|
|
2486
|
+
})),
|
|
2487
|
+
NUM_8: _extends({}, getDefaultNumberFields({
|
|
2488
|
+
key: "NUM_8"
|
|
2489
|
+
})),
|
|
2490
|
+
NUM_9: _extends({}, getDefaultNumberFields({
|
|
2491
|
+
key: "NUM_9"
|
|
2492
|
+
})),
|
|
2493
|
+
// LETTERS
|
|
2494
|
+
A: _extends({}, getDefaultValueFields({
|
|
2495
|
+
key: "A"
|
|
2496
|
+
})),
|
|
2497
|
+
B: _extends({}, getDefaultValueFields({
|
|
2498
|
+
key: "B"
|
|
2499
|
+
})),
|
|
2500
|
+
C: _extends({}, getDefaultValueFields({
|
|
2501
|
+
key: "C"
|
|
2502
|
+
})),
|
|
2503
|
+
D: _extends({}, getDefaultValueFields({
|
|
2504
|
+
key: "D"
|
|
2505
|
+
})),
|
|
2506
|
+
E: _extends({}, getDefaultValueFields({
|
|
2507
|
+
key: "E"
|
|
2508
|
+
})),
|
|
2509
|
+
F: _extends({}, getDefaultValueFields({
|
|
2510
|
+
key: "F"
|
|
2511
|
+
})),
|
|
2512
|
+
G: _extends({}, getDefaultValueFields({
|
|
2513
|
+
key: "G"
|
|
2514
|
+
})),
|
|
2515
|
+
H: _extends({}, getDefaultValueFields({
|
|
2516
|
+
key: "H"
|
|
2517
|
+
})),
|
|
2518
|
+
I: _extends({}, getDefaultValueFields({
|
|
2519
|
+
key: "I"
|
|
2520
|
+
})),
|
|
2521
|
+
J: _extends({}, getDefaultValueFields({
|
|
2522
|
+
key: "J"
|
|
2523
|
+
})),
|
|
2524
|
+
K: _extends({}, getDefaultValueFields({
|
|
2525
|
+
key: "K"
|
|
2526
|
+
})),
|
|
2527
|
+
L: _extends({}, getDefaultValueFields({
|
|
2528
|
+
key: "L"
|
|
2529
|
+
})),
|
|
2530
|
+
M: _extends({}, getDefaultValueFields({
|
|
2531
|
+
key: "M"
|
|
2532
|
+
})),
|
|
2533
|
+
N: _extends({}, getDefaultValueFields({
|
|
2534
|
+
key: "N"
|
|
2535
|
+
})),
|
|
2536
|
+
O: _extends({}, getDefaultValueFields({
|
|
2537
|
+
key: "O"
|
|
2538
|
+
})),
|
|
2539
|
+
P: _extends({}, getDefaultValueFields({
|
|
2540
|
+
key: "P"
|
|
2541
|
+
})),
|
|
2542
|
+
Q: _extends({}, getDefaultValueFields({
|
|
2543
|
+
key: "Q"
|
|
2544
|
+
})),
|
|
2545
|
+
R: _extends({}, getDefaultValueFields({
|
|
2546
|
+
key: "R"
|
|
2547
|
+
})),
|
|
2548
|
+
S: _extends({}, getDefaultValueFields({
|
|
2549
|
+
key: "S"
|
|
2550
|
+
})),
|
|
2551
|
+
T: _extends({}, getDefaultValueFields({
|
|
2552
|
+
key: "T"
|
|
2553
|
+
})),
|
|
2554
|
+
U: _extends({}, getDefaultValueFields({
|
|
2555
|
+
key: "U"
|
|
2556
|
+
})),
|
|
2557
|
+
V: _extends({}, getDefaultValueFields({
|
|
2558
|
+
key: "V"
|
|
2559
|
+
})),
|
|
2560
|
+
W: _extends({}, getDefaultValueFields({
|
|
2561
|
+
key: "W"
|
|
2562
|
+
})),
|
|
2563
|
+
X: _extends({}, getDefaultValueFields({
|
|
2564
|
+
key: "X"
|
|
2565
|
+
})),
|
|
2566
|
+
Y: _extends({}, getDefaultValueFields({
|
|
2567
|
+
key: "Y"
|
|
2568
|
+
})),
|
|
2569
|
+
Z: _extends({}, getDefaultValueFields({
|
|
2570
|
+
key: "Z"
|
|
2571
|
+
})),
|
|
2572
|
+
a: _extends({}, getDefaultValueFields({
|
|
2573
|
+
key: "a"
|
|
2574
|
+
})),
|
|
2575
|
+
b: _extends({}, getDefaultValueFields({
|
|
2576
|
+
key: "b"
|
|
2577
|
+
})),
|
|
2578
|
+
c: _extends({}, getDefaultValueFields({
|
|
2579
|
+
key: "c"
|
|
2580
|
+
})),
|
|
2581
|
+
d: _extends({}, getDefaultValueFields({
|
|
2582
|
+
key: "d"
|
|
2583
|
+
})),
|
|
2584
|
+
e: _extends({}, getDefaultValueFields({
|
|
2585
|
+
key: "e"
|
|
2586
|
+
})),
|
|
2587
|
+
f: _extends({}, getDefaultValueFields({
|
|
2588
|
+
key: "f"
|
|
2589
|
+
})),
|
|
2590
|
+
g: _extends({}, getDefaultValueFields({
|
|
2591
|
+
key: "g"
|
|
2592
|
+
})),
|
|
2593
|
+
h: _extends({}, getDefaultValueFields({
|
|
2594
|
+
key: "h"
|
|
2595
|
+
})),
|
|
2596
|
+
i: _extends({}, getDefaultValueFields({
|
|
2597
|
+
key: "i"
|
|
2598
|
+
})),
|
|
2599
|
+
j: _extends({}, getDefaultValueFields({
|
|
2600
|
+
key: "j"
|
|
2601
|
+
})),
|
|
2602
|
+
k: _extends({}, getDefaultValueFields({
|
|
2603
|
+
key: "k"
|
|
2604
|
+
})),
|
|
2605
|
+
l: _extends({}, getDefaultValueFields({
|
|
2606
|
+
key: "l"
|
|
2607
|
+
})),
|
|
2608
|
+
m: _extends({}, getDefaultValueFields({
|
|
2609
|
+
key: "m"
|
|
2610
|
+
})),
|
|
2611
|
+
n: _extends({}, getDefaultValueFields({
|
|
2612
|
+
key: "n"
|
|
2613
|
+
})),
|
|
2614
|
+
o: _extends({}, getDefaultValueFields({
|
|
2615
|
+
key: "o"
|
|
2616
|
+
})),
|
|
2617
|
+
p: _extends({}, getDefaultValueFields({
|
|
2618
|
+
key: "p"
|
|
2619
|
+
})),
|
|
2620
|
+
q: _extends({}, getDefaultValueFields({
|
|
2621
|
+
key: "q"
|
|
2622
|
+
})),
|
|
2623
|
+
r: _extends({}, getDefaultValueFields({
|
|
2624
|
+
key: "r"
|
|
2625
|
+
})),
|
|
2626
|
+
s: _extends({}, getDefaultValueFields({
|
|
2627
|
+
key: "s"
|
|
2628
|
+
})),
|
|
2629
|
+
t: _extends({}, getDefaultValueFields({
|
|
2630
|
+
key: "t"
|
|
2631
|
+
})),
|
|
2632
|
+
u: _extends({}, getDefaultValueFields({
|
|
2633
|
+
key: "u"
|
|
2634
|
+
})),
|
|
2635
|
+
v: _extends({}, getDefaultValueFields({
|
|
2636
|
+
key: "v"
|
|
2637
|
+
})),
|
|
2638
|
+
w: _extends({}, getDefaultValueFields({
|
|
2639
|
+
key: "w"
|
|
2640
|
+
})),
|
|
2641
|
+
x: _extends({}, getDefaultValueFields({
|
|
2642
|
+
key: "x"
|
|
2643
|
+
})),
|
|
2644
|
+
y: _extends({}, getDefaultValueFields({
|
|
2645
|
+
key: "y"
|
|
2646
|
+
})),
|
|
2647
|
+
z: _extends({}, getDefaultValueFields({
|
|
2648
|
+
key: "z"
|
|
2649
|
+
})),
|
|
2650
|
+
PHI: _extends({}, getDefaultValueFields({
|
|
2651
|
+
key: "PHI"
|
|
2652
|
+
})),
|
|
2653
|
+
NTHROOT3: _extends({}, getDefaultValueFields({
|
|
2654
|
+
key: "NTHROOT3"
|
|
2655
|
+
})),
|
|
2656
|
+
POW: _extends({}, getDefaultValueFields({
|
|
2657
|
+
key: "POW"
|
|
2658
|
+
})),
|
|
2659
|
+
LOG_B: _extends({}, getDefaultValueFields({
|
|
2660
|
+
key: "LOG_B"
|
|
2661
|
+
}))
|
|
2360
2662
|
};
|
|
2361
2663
|
|
|
2362
|
-
// Add in every numeral.
|
|
2363
|
-
const NUMBERS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
2364
|
-
for (const num of NUMBERS) {
|
|
2365
|
-
// TODO(charlie): Consider removing the SVG icons that we have for the
|
|
2366
|
-
// numeral keys. They can be rendered just as easily with text (though that
|
|
2367
|
-
// would mean that we'd be using text beyond the variable key).
|
|
2368
|
-
const textRepresentation = `${num}`;
|
|
2369
|
-
KeyConfigs[`NUM_${num}`] = {
|
|
2370
|
-
type: KeyType.VALUE,
|
|
2371
|
-
ariaLabel: textRepresentation,
|
|
2372
|
-
icon: {
|
|
2373
|
-
type: IconType.TEXT,
|
|
2374
|
-
data: textRepresentation
|
|
2375
|
-
}
|
|
2376
|
-
};
|
|
2377
|
-
}
|
|
2378
|
-
|
|
2379
|
-
// Add in every variable.
|
|
2380
|
-
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"];
|
|
2381
|
-
for (const letter of LETTERS) {
|
|
2382
|
-
const lowerCaseVariable = letter.toLowerCase();
|
|
2383
|
-
const upperCaseVariable = letter.toUpperCase();
|
|
2384
|
-
for (const textRepresentation of [lowerCaseVariable, upperCaseVariable]) {
|
|
2385
|
-
KeyConfigs[textRepresentation] = {
|
|
2386
|
-
type: KeyType.VALUE,
|
|
2387
|
-
ariaLabel: textRepresentation,
|
|
2388
|
-
icon: {
|
|
2389
|
-
type: IconType.MATH,
|
|
2390
|
-
data: textRepresentation
|
|
2391
|
-
}
|
|
2392
|
-
};
|
|
2393
|
-
}
|
|
2394
|
-
}
|
|
2395
|
-
for (const key of Object.keys(KeyConfigs)) {
|
|
2396
|
-
KeyConfigs[key] = _extends({
|
|
2397
|
-
id: key,
|
|
2398
|
-
// Default to an SVG icon indexed by the key name.
|
|
2399
|
-
icon: {
|
|
2400
|
-
type: IconType.SVG,
|
|
2401
|
-
data: key
|
|
2402
|
-
}
|
|
2403
|
-
}, KeyConfigs[key]);
|
|
2404
|
-
}
|
|
2405
|
-
|
|
2406
2664
|
function _objectWithoutPropertiesLoose(source, excluded) {
|
|
2407
2665
|
if (source == null) return {};
|
|
2408
2666
|
var target = {};
|
|
@@ -4049,7 +4307,7 @@ class KeypadButton$1 extends React.PureComponent {
|
|
|
4049
4307
|
// object. This method must be called whenever a property that
|
|
4050
4308
|
// influences the possible outcomes of `this._getFocusStyle` and
|
|
4051
4309
|
// `this._getButtonStyle` changes (such as `this.buttonSizeStyle`).
|
|
4052
|
-
for (const type of
|
|
4310
|
+
for (const type of KeyTypes) {
|
|
4053
4311
|
css(View.styles.initial, ...this._getFocusStyle(type));
|
|
4054
4312
|
for (const borders of Object.values(BorderStyles)) {
|
|
4055
4313
|
css(View.styles.initial, ...this._getButtonStyle(type, borders));
|
|
@@ -4058,7 +4316,7 @@ class KeypadButton$1 extends React.PureComponent {
|
|
|
4058
4316
|
};
|
|
4059
4317
|
this._getFocusStyle = type => {
|
|
4060
4318
|
let focusBackgroundStyle;
|
|
4061
|
-
if (type ===
|
|
4319
|
+
if (type === "INPUT_NAVIGATION" || type === "KEYPAD_NAVIGATION") {
|
|
4062
4320
|
focusBackgroundStyle = styles$9.light;
|
|
4063
4321
|
} else {
|
|
4064
4322
|
focusBackgroundStyle = styles$9.bright;
|
|
@@ -4069,21 +4327,21 @@ class KeypadButton$1 extends React.PureComponent {
|
|
|
4069
4327
|
// Select the appropriate style for the button.
|
|
4070
4328
|
let backgroundStyle;
|
|
4071
4329
|
switch (type) {
|
|
4072
|
-
case
|
|
4330
|
+
case "EMPTY":
|
|
4073
4331
|
backgroundStyle = styles$9.empty;
|
|
4074
4332
|
break;
|
|
4075
|
-
case
|
|
4076
|
-
case
|
|
4333
|
+
case "MANY":
|
|
4334
|
+
case "VALUE":
|
|
4077
4335
|
backgroundStyle = styles$9.value;
|
|
4078
4336
|
break;
|
|
4079
|
-
case
|
|
4337
|
+
case "OPERATOR":
|
|
4080
4338
|
backgroundStyle = styles$9.operator;
|
|
4081
4339
|
break;
|
|
4082
|
-
case
|
|
4083
|
-
case
|
|
4340
|
+
case "INPUT_NAVIGATION":
|
|
4341
|
+
case "KEYPAD_NAVIGATION":
|
|
4084
4342
|
backgroundStyle = styles$9.control;
|
|
4085
4343
|
break;
|
|
4086
|
-
case
|
|
4344
|
+
case "ECHO":
|
|
4087
4345
|
backgroundStyle = null;
|
|
4088
4346
|
break;
|
|
4089
4347
|
}
|
|
@@ -4096,7 +4354,7 @@ class KeypadButton$1 extends React.PureComponent {
|
|
|
4096
4354
|
// @ts-expect-error TS2345
|
|
4097
4355
|
borderStyle.push(styles$9.bottomBorder);
|
|
4098
4356
|
}
|
|
4099
|
-
return [styles$9.buttonBase, backgroundStyle, ...borderStyle, type ===
|
|
4357
|
+
return [styles$9.buttonBase, backgroundStyle, ...borderStyle, type === "ECHO" && styles$9.echo, this.buttonSizeStyle,
|
|
4100
4358
|
// React Native allows you to set the 'style' props on user defined
|
|
4101
4359
|
// components.
|
|
4102
4360
|
// See: https://facebook.github.io/react-native/docs/style.html
|
|
@@ -4138,7 +4396,7 @@ class KeypadButton$1 extends React.PureComponent {
|
|
|
4138
4396
|
|
|
4139
4397
|
// We render in the focus state if the key is focused, or if it's an
|
|
4140
4398
|
// echo.
|
|
4141
|
-
const renderFocused = !disabled && focused || popoverEnabled || type ===
|
|
4399
|
+
const renderFocused = !disabled && focused || popoverEnabled || type === "ECHO";
|
|
4142
4400
|
const buttonStyle = this._getButtonStyle(type, borders, style);
|
|
4143
4401
|
const focusStyle = this._getFocusStyle(type);
|
|
4144
4402
|
const iconWrapperStyle = [styles$9.iconWrapper, disabled ? styles$9.disabled : undefined];
|
|
@@ -4154,11 +4412,11 @@ class KeypadButton$1 extends React.PureComponent {
|
|
|
4154
4412
|
const maybeCornerDecal = !renderFocused && !disabled && childKeys && childKeys.length > 0 && /*#__PURE__*/React.createElement(CornerDecal, {
|
|
4155
4413
|
style: styles$9.decalInset
|
|
4156
4414
|
});
|
|
4157
|
-
if (type ===
|
|
4415
|
+
if (type === "EMPTY") {
|
|
4158
4416
|
return /*#__PURE__*/React.createElement(View, _extends({
|
|
4159
4417
|
style: buttonStyle
|
|
4160
4418
|
}, eventHandlers));
|
|
4161
|
-
} else if (type ===
|
|
4419
|
+
} else if (type === "MANY") {
|
|
4162
4420
|
// TODO(charlie): Make the long-press interaction accessible. See
|
|
4163
4421
|
// the TODO in key-configs.js for more.
|
|
4164
4422
|
const manyButtonA11yMarkup = {
|
|
@@ -4398,7 +4656,7 @@ const mapStateToProps$5 = (state, ownProps) => {
|
|
|
4398
4656
|
|
|
4399
4657
|
// Override with the default child props, if the key is a multi-symbol key
|
|
4400
4658
|
// (but not a many-symbol key, which operates under different rules).
|
|
4401
|
-
const useFirstChildProps = type !==
|
|
4659
|
+
const useFirstChildProps = type !== "MANY" && childKeys && childKeys.length > 0;
|
|
4402
4660
|
return _extends({}, rest, {
|
|
4403
4661
|
childKeyIds: childKeyIds,
|
|
4404
4662
|
gestureManager: gestures.gestureManager,
|
|
@@ -4443,8 +4701,13 @@ class ManyKeypadButton extends React.Component {
|
|
|
4443
4701
|
} else {
|
|
4444
4702
|
const keyConfig = {
|
|
4445
4703
|
id: "MANY",
|
|
4446
|
-
type:
|
|
4447
|
-
childKeyIds: keys
|
|
4704
|
+
type: "MANY",
|
|
4705
|
+
childKeyIds: keys,
|
|
4706
|
+
ariaLabel: keys.map(key => KeyConfigs[key].ariaLabel).join(", "),
|
|
4707
|
+
icon: {
|
|
4708
|
+
type: IconType.SVG,
|
|
4709
|
+
data: "many"
|
|
4710
|
+
}
|
|
4448
4711
|
};
|
|
4449
4712
|
return /*#__PURE__*/React.createElement(TouchableKeypadButton$1, _extends({
|
|
4450
4713
|
keyConfig: keyConfig
|
|
@@ -4475,8 +4738,6 @@ const IconAsset = function IconAsset({
|
|
|
4475
4738
|
}));
|
|
4476
4739
|
} else if (type === "Operators") {
|
|
4477
4740
|
return /*#__PURE__*/React.createElement("svg", {
|
|
4478
|
-
width: "32",
|
|
4479
|
-
height: "32",
|
|
4480
4741
|
viewBox: "0 0 32 32",
|
|
4481
4742
|
fill: "none",
|
|
4482
4743
|
xmlns: "http://www.w3.org/2000/svg"
|
|
@@ -4674,7 +4935,7 @@ class Echo extends React.Component {
|
|
|
4674
4935
|
style: containerStyle
|
|
4675
4936
|
}, /*#__PURE__*/React.createElement(KeypadButton$2, {
|
|
4676
4937
|
icon: icon,
|
|
4677
|
-
type:
|
|
4938
|
+
type: "ECHO"
|
|
4678
4939
|
}));
|
|
4679
4940
|
}
|
|
4680
4941
|
}
|
|
@@ -4888,18 +5149,6 @@ const setCursor = cursor => {
|
|
|
4888
5149
|
|
|
4889
5150
|
// Gesture actions
|
|
4890
5151
|
|
|
4891
|
-
const onSwipeChange = dx => {
|
|
4892
|
-
return {
|
|
4893
|
-
type: "OnSwipeChange",
|
|
4894
|
-
dx
|
|
4895
|
-
};
|
|
4896
|
-
};
|
|
4897
|
-
const onSwipeEnd = dx => {
|
|
4898
|
-
return {
|
|
4899
|
-
type: "OnSwipeEnd",
|
|
4900
|
-
dx
|
|
4901
|
-
};
|
|
4902
|
-
};
|
|
4903
5152
|
const setActiveNodes = activeNodes => {
|
|
4904
5153
|
return {
|
|
4905
5154
|
type: "SetActiveNodes",
|
|
@@ -5991,7 +6240,8 @@ class GestureStateMachine {
|
|
|
5991
6240
|
// Only respect the finger that started a swipe. Any other lingering
|
|
5992
6241
|
// gestures are ignored.
|
|
5993
6242
|
if (this.swipeState.touchId === touchId) {
|
|
5994
|
-
|
|
6243
|
+
var _this$handlers$onSwip, _this$handlers;
|
|
6244
|
+
(_this$handlers$onSwip = (_this$handlers = this.handlers).onSwipeChange) == null ? void 0 : _this$handlers$onSwip.call(_this$handlers, pageX - this.swipeState.startX);
|
|
5995
6245
|
}
|
|
5996
6246
|
} else if (this.touchState[touchId]) {
|
|
5997
6247
|
// It could be touch events started outside the keypad and
|
|
@@ -6004,6 +6254,7 @@ class GestureStateMachine {
|
|
|
6004
6254
|
const dx = pageX - startX;
|
|
6005
6255
|
const shouldBeginSwiping = swipeEnabled && !swipeLocked && Math.abs(dx) > this.options.swipeThresholdPx;
|
|
6006
6256
|
if (shouldBeginSwiping) {
|
|
6257
|
+
var _this$handlers$onSwip2, _this$handlers2;
|
|
6007
6258
|
this._onSwipeStart();
|
|
6008
6259
|
|
|
6009
6260
|
// Trigger the swipe.
|
|
@@ -6011,7 +6262,7 @@ class GestureStateMachine {
|
|
|
6011
6262
|
touchId,
|
|
6012
6263
|
startX
|
|
6013
6264
|
};
|
|
6014
|
-
this.handlers.onSwipeChange(pageX - this.swipeState.startX);
|
|
6265
|
+
(_this$handlers$onSwip2 = (_this$handlers2 = this.handlers).onSwipeChange) == null ? void 0 : _this$handlers$onSwip2.call(_this$handlers2, pageX - this.swipeState.startX);
|
|
6015
6266
|
} else {
|
|
6016
6267
|
const id = getId();
|
|
6017
6268
|
if (id !== activeNodeId) {
|
|
@@ -6034,7 +6285,8 @@ class GestureStateMachine {
|
|
|
6034
6285
|
// Only respect the finger that started a swipe. Any other lingering
|
|
6035
6286
|
// gestures are ignored.
|
|
6036
6287
|
if (this.swipeState.touchId === touchId) {
|
|
6037
|
-
|
|
6288
|
+
var _this$handlers$onSwip3, _this$handlers3;
|
|
6289
|
+
(_this$handlers$onSwip3 = (_this$handlers3 = this.handlers).onSwipeEnd) == null ? void 0 : _this$handlers$onSwip3.call(_this$handlers3, pageX - this.swipeState.startX);
|
|
6038
6290
|
this.swipeState = null;
|
|
6039
6291
|
}
|
|
6040
6292
|
} else if (this.touchState[touchId]) {
|
|
@@ -6068,7 +6320,8 @@ class GestureStateMachine {
|
|
|
6068
6320
|
// displacement.
|
|
6069
6321
|
if (this.swipeState) {
|
|
6070
6322
|
if (this.swipeState.touchId === touchId) {
|
|
6071
|
-
|
|
6323
|
+
var _this$handlers$onSwip4, _this$handlers4;
|
|
6324
|
+
(_this$handlers$onSwip4 = (_this$handlers4 = this.handlers).onSwipeEnd) == null ? void 0 : _this$handlers$onSwip4.call(_this$handlers4, 0);
|
|
6072
6325
|
this.swipeState = null;
|
|
6073
6326
|
}
|
|
6074
6327
|
} else if (this.touchState[touchId]) {
|
|
@@ -6446,7 +6699,7 @@ class GestureManager {
|
|
|
6446
6699
|
* Handle a touch-start event that originated in a node registered with the
|
|
6447
6700
|
* gesture system.
|
|
6448
6701
|
*
|
|
6449
|
-
* @param {TouchEvent} evt - the raw touch event from the browser
|
|
6702
|
+
* @param {React.TouchEvent<HTMLDivElement>} evt - the raw touch event from the browser
|
|
6450
6703
|
* @param {string} id - the identifier of the DOM node in which the touch
|
|
6451
6704
|
* occurred
|
|
6452
6705
|
*/
|
|
@@ -6473,7 +6726,7 @@ class GestureManager {
|
|
|
6473
6726
|
* Handle a touch-move event that originated in a node registered with the
|
|
6474
6727
|
* gesture system.
|
|
6475
6728
|
*
|
|
6476
|
-
* @param {TouchEvent} evt - the raw touch event from the browser
|
|
6729
|
+
* @param {React.TouchEvent<HTMLDivElement>} evt - the raw touch event from the browser
|
|
6477
6730
|
*/
|
|
6478
6731
|
onTouchMove(evt) {
|
|
6479
6732
|
if (!this.trackEvents) {
|
|
@@ -6491,7 +6744,7 @@ class GestureManager {
|
|
|
6491
6744
|
* Handle a touch-end event that originated in a node registered with the
|
|
6492
6745
|
* gesture system.
|
|
6493
6746
|
*
|
|
6494
|
-
* @param {TouchEvent} evt - the raw touch event from the browser
|
|
6747
|
+
* @param {React.TouchEvent<HTMLDivElement>} evt - the raw touch event from the browser
|
|
6495
6748
|
*/
|
|
6496
6749
|
onTouchEnd(evt) {
|
|
6497
6750
|
if (!this.trackEvents) {
|
|
@@ -6507,7 +6760,7 @@ class GestureManager {
|
|
|
6507
6760
|
* Handle a touch-cancel event that originated in a node registered with the
|
|
6508
6761
|
* gesture system.
|
|
6509
6762
|
*
|
|
6510
|
-
* @param {TouchEvent} evt - the raw touch event from the browser
|
|
6763
|
+
* @param {React.TouchEvent<HTMLDivElement>} evt - the raw touch event from the browser
|
|
6511
6764
|
*/
|
|
6512
6765
|
onTouchCancel(evt) {
|
|
6513
6766
|
if (!this.trackEvents) {
|
|
@@ -6573,7 +6826,7 @@ const echoReducer = function echoReducer(state = initialEchoState, action) {
|
|
|
6573
6826
|
|
|
6574
6827
|
// Add in the echo animation if the user performs a math
|
|
6575
6828
|
// operation.
|
|
6576
|
-
if (keyConfig.type ===
|
|
6829
|
+
if (keyConfig.type === "VALUE" || keyConfig.type === "OPERATOR") {
|
|
6577
6830
|
return _extends({}, state, {
|
|
6578
6831
|
echoes: [...state.echoes, {
|
|
6579
6832
|
animationId: "" + _lastAnimationId++,
|
|
@@ -6610,7 +6863,7 @@ const inputReducer = function inputReducer(state = initialInputState, action) {
|
|
|
6610
6863
|
});
|
|
6611
6864
|
case "PressKey":
|
|
6612
6865
|
const keyConfig = KeyConfigs[action.key];
|
|
6613
|
-
if (keyConfig.type !==
|
|
6866
|
+
if (keyConfig.type !== "KEYPAD_NAVIGATION") {
|
|
6614
6867
|
// This is probably an anti-pattern but it works for the
|
|
6615
6868
|
// case where we don't actually control the state but we
|
|
6616
6869
|
// still want to communicate with the other object
|
|
@@ -6637,7 +6890,7 @@ const keypadForType = {
|
|
|
6637
6890
|
};
|
|
6638
6891
|
|
|
6639
6892
|
const initialKeypadState = {
|
|
6640
|
-
extraKeys: ["x", "y",
|
|
6893
|
+
extraKeys: ["x", "y", "THETA", "PI"],
|
|
6641
6894
|
keypadType: defaultKeypadType,
|
|
6642
6895
|
active: false
|
|
6643
6896
|
};
|
|
@@ -6665,7 +6918,7 @@ const keypadReducer = function keypadReducer(state = initialKeypadState, action)
|
|
|
6665
6918
|
// right actions when they occur. Hence, we figure off a
|
|
6666
6919
|
// dismissal here rather than dispatching a dismiss action in
|
|
6667
6920
|
// the first place.
|
|
6668
|
-
if (keyConfig.id ===
|
|
6921
|
+
if (keyConfig.id === "DISMISS") {
|
|
6669
6922
|
return keypadReducer(state, {
|
|
6670
6923
|
type: "DismissKeypad"
|
|
6671
6924
|
});
|
|
@@ -6904,19 +7157,13 @@ const createStore = () => {
|
|
|
6904
7157
|
return new GestureManager({
|
|
6905
7158
|
swipeEnabled
|
|
6906
7159
|
}, {
|
|
6907
|
-
onSwipeChange: dx => {
|
|
6908
|
-
store.dispatch(onSwipeChange(dx));
|
|
6909
|
-
},
|
|
6910
|
-
onSwipeEnd: dx => {
|
|
6911
|
-
store.dispatch(onSwipeEnd(dx));
|
|
6912
|
-
},
|
|
6913
7160
|
onActiveNodesChanged: activeNodes => {
|
|
6914
7161
|
store.dispatch(setActiveNodes(activeNodes));
|
|
6915
7162
|
},
|
|
6916
7163
|
onClick: (key, layoutProps, inPopover) => {
|
|
6917
7164
|
store.dispatch(pressKey(key, layoutProps.initialBounds, inPopover));
|
|
6918
7165
|
}
|
|
6919
|
-
}, [], [
|
|
7166
|
+
}, [], ["BACKSPACE", "UP", "RIGHT", "DOWN", "LEFT"]);
|
|
6920
7167
|
};
|
|
6921
7168
|
const initialGestureState = {
|
|
6922
7169
|
popover: null,
|
|
@@ -7128,9 +7375,6 @@ asset.
|
|
|
7128
7375
|
In the future it would be great if these were included from files so that
|
|
7129
7376
|
no copying and pasting is necessary.
|
|
7130
7377
|
*/
|
|
7131
|
-
|
|
7132
|
-
// TODO: This should be an enumeration of all of the possible legal values
|
|
7133
|
-
|
|
7134
7378
|
function ButtonAsset({
|
|
7135
7379
|
id
|
|
7136
7380
|
}) {
|
|
@@ -7275,84 +7519,94 @@ function ButtonAsset({
|
|
|
7275
7519
|
}));
|
|
7276
7520
|
case "MINUS":
|
|
7277
7521
|
return /*#__PURE__*/React.createElement("svg", {
|
|
7278
|
-
|
|
7279
|
-
|
|
7280
|
-
|
|
7281
|
-
fill: "
|
|
7282
|
-
|
|
7522
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
7523
|
+
width: "20",
|
|
7524
|
+
height: "20",
|
|
7525
|
+
fill: "currentColor",
|
|
7526
|
+
viewBox: "0 0 256 256"
|
|
7283
7527
|
}, /*#__PURE__*/React.createElement("path", {
|
|
7284
|
-
d: "
|
|
7285
|
-
stroke: "#21242C",
|
|
7286
|
-
strokeWidth: "2",
|
|
7287
|
-
strokeLinecap: "round",
|
|
7288
|
-
strokeLinejoin: "round"
|
|
7528
|
+
d: "M224,128a8,8,0,0,1-8,8H40a8,8,0,0,1,0-16H216A8,8,0,0,1,224,128Z"
|
|
7289
7529
|
}));
|
|
7290
7530
|
case "PLUS":
|
|
7531
|
+
return (
|
|
7532
|
+
/*#__PURE__*/
|
|
7533
|
+
// Phosphor Icons - Plus Bold
|
|
7534
|
+
React.createElement("svg", {
|
|
7535
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
7536
|
+
width: "20",
|
|
7537
|
+
height: "20",
|
|
7538
|
+
fill: "currentColor",
|
|
7539
|
+
viewBox: "0 0 256 256"
|
|
7540
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
7541
|
+
d: "M224,128a8,8,0,0,1-8,8H136v80a8,8,0,0,1-16,0V136H40a8,8,0,0,1,0-16h80V40a8,8,0,0,1,16,0v80h80A8,8,0,0,1,224,128Z"
|
|
7542
|
+
}), " ")
|
|
7543
|
+
);
|
|
7544
|
+
case "TIMES":
|
|
7545
|
+
return (
|
|
7546
|
+
/*#__PURE__*/
|
|
7547
|
+
// Phosphor Icons - X Bold
|
|
7548
|
+
React.createElement("svg", {
|
|
7549
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
7550
|
+
width: "20",
|
|
7551
|
+
height: "20",
|
|
7552
|
+
fill: "#000000",
|
|
7553
|
+
viewBox: "0 0 256 256"
|
|
7554
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
7555
|
+
d: "M205.66,194.34a8,8,0,0,1-11.32,11.32L128,139.31,61.66,205.66a8,8,0,0,1-11.32-11.32L116.69,128,50.34,61.66A8,8,0,0,1,61.66,50.34L128,116.69l66.34-66.35a8,8,0,0,1,11.32,11.32L139.31,128Z"
|
|
7556
|
+
}))
|
|
7557
|
+
);
|
|
7558
|
+
case "BACKSPACE":
|
|
7291
7559
|
return /*#__PURE__*/React.createElement("svg", {
|
|
7292
|
-
|
|
7293
|
-
|
|
7294
|
-
|
|
7295
|
-
fill: "
|
|
7296
|
-
|
|
7560
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
7561
|
+
width: "20",
|
|
7562
|
+
height: "20",
|
|
7563
|
+
fill: "currentColor",
|
|
7564
|
+
viewBox: "0 0 256 256"
|
|
7297
7565
|
}, /*#__PURE__*/React.createElement("path", {
|
|
7298
|
-
d: "
|
|
7299
|
-
stroke: "#21242C",
|
|
7300
|
-
strokeWidth: "2",
|
|
7301
|
-
strokeLinecap: "round",
|
|
7302
|
-
strokeLinejoin: "round"
|
|
7303
|
-
}), /*#__PURE__*/React.createElement("path", {
|
|
7304
|
-
d: "M20 13V27",
|
|
7305
|
-
stroke: "#21242C",
|
|
7306
|
-
strokeWidth: "2",
|
|
7307
|
-
strokeLinecap: "round",
|
|
7308
|
-
strokeLinejoin: "round"
|
|
7566
|
+
d: "M216,40H68.53a16.08,16.08,0,0,0-13.72,7.77L9.14,123.88a8,8,0,0,0,0,8.24l45.67,76.11A16.08,16.08,0,0,0,68.53,216H216a16,16,0,0,0,16-16V56A16,16,0,0,0,216,40ZM61.67,204.12,68.53,200h0ZM216,200H68.53l-43.2-72,43.2-72H216ZM106.34,146.34,124.69,128l-18.35-18.34a8,8,0,0,1,11.32-11.32L136,116.69l18.34-18.35a8,8,0,0,1,11.32,11.32L147.31,128l18.35,18.34a8,8,0,0,1-11.32,11.32L136,139.31l-18.34,18.35a8,8,0,0,1-11.32-11.32Z"
|
|
7309
7567
|
}));
|
|
7310
|
-
case "
|
|
7568
|
+
case "DISMISS":
|
|
7311
7569
|
return /*#__PURE__*/React.createElement("svg", {
|
|
7312
|
-
|
|
7313
|
-
|
|
7314
|
-
|
|
7315
|
-
fill: "
|
|
7316
|
-
|
|
7570
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
7571
|
+
width: "20",
|
|
7572
|
+
height: "20",
|
|
7573
|
+
fill: "currentColor",
|
|
7574
|
+
viewBox: "0 0 256 256"
|
|
7317
7575
|
}, /*#__PURE__*/React.createElement("path", {
|
|
7318
|
-
|
|
7319
|
-
|
|
7320
|
-
|
|
7321
|
-
strokeLinecap: "round",
|
|
7322
|
-
strokeLinejoin: "round"
|
|
7323
|
-
}), /*#__PURE__*/React.createElement("path", {
|
|
7324
|
-
d: "M24.9498 15.0507L15.0503 24.9502",
|
|
7325
|
-
stroke: "#21242C",
|
|
7326
|
-
strokeWidth: "2",
|
|
7327
|
-
strokeLinecap: "round",
|
|
7328
|
-
strokeLinejoin: "round"
|
|
7576
|
+
// flip to point down
|
|
7577
|
+
transform: "scale(1,-1) translate(0, -260)",
|
|
7578
|
+
d: "M205.66,125.66a8,8,0,0,1-11.32,0L128,59.31,61.66,125.66a8,8,0,0,1-11.32-11.32l72-72a8,8,0,0,1,11.32,0l72,72A8,8,0,0,1,205.66,125.66Z"
|
|
7329
7579
|
}));
|
|
7330
|
-
case "
|
|
7580
|
+
case "FRAC":
|
|
7331
7581
|
return /*#__PURE__*/React.createElement("svg", {
|
|
7332
|
-
width: "
|
|
7333
|
-
height: "
|
|
7334
|
-
viewBox: "0 0
|
|
7582
|
+
width: "48",
|
|
7583
|
+
height: "48",
|
|
7584
|
+
viewBox: "0 0 48 48"
|
|
7585
|
+
}, /*#__PURE__*/React.createElement("g", {
|
|
7335
7586
|
fill: "none",
|
|
7336
|
-
|
|
7587
|
+
fillRule: "evenodd"
|
|
7337
7588
|
}, /*#__PURE__*/React.createElement("path", {
|
|
7338
|
-
fillRule: "evenodd",
|
|
7339
|
-
clipRule: "evenodd",
|
|
7340
|
-
d: "M10 20L16 14H28.1716V26L16 26L10 20ZM8.58579 18.5858L14.5858 12.5858C14.9609 12.2107 15.4696 12 16 12H28.1716C29.2761 12 30.1716 12.8954 30.1716 14V26C30.1716 27.1046 29.2761 28 28.1716 28H16C15.4696 28 14.9609 27.7893 14.5858 27.4142L8.58579 21.4142C7.80474 20.6332 7.80474 19.3668 8.58579 18.5858ZM22.4645 17.2929L21.1716 18.5858L19.8787 17.2929C19.4882 16.9024 18.855 16.9024 18.4645 17.2929C18.074 17.6834 18.074 18.3166 18.4645 18.7071L19.7574 20L18.4645 21.2929C18.074 21.6834 18.074 22.3166 18.4645 22.7071C18.855 23.0976 19.4882 23.0976 19.8787 22.7071L21.1716 21.4142L22.4645 22.7071C22.855 23.0976 23.4882 23.0976 23.8787 22.7071C24.2693 22.3166 24.2693 21.6834 23.8787 21.2929L22.5858 20L23.8787 18.7071C24.2693 18.3166 24.2693 17.6834 23.8787 17.2929C23.4882 16.9024 22.855 16.9024 22.4645 17.2929Z",
|
|
7341
|
-
fill: "#21242C"
|
|
7342
|
-
}));
|
|
7343
|
-
case "DISMISS":
|
|
7344
|
-
return /*#__PURE__*/React.createElement("svg", {
|
|
7345
|
-
width: "40",
|
|
7346
|
-
height: "40",
|
|
7347
|
-
viewBox: "0 0 40 40",
|
|
7348
7589
|
fill: "none",
|
|
7349
|
-
|
|
7590
|
+
d: "M0 0h48v48H0z"
|
|
7591
|
+
}), /*#__PURE__*/React.createElement("g", {
|
|
7592
|
+
transform: "translate(12 12)"
|
|
7350
7593
|
}, /*#__PURE__*/React.createElement("path", {
|
|
7351
|
-
|
|
7352
|
-
|
|
7353
|
-
|
|
7354
|
-
|
|
7355
|
-
|
|
7594
|
+
fill: "none",
|
|
7595
|
+
d: "M0 0h24v24H0z"
|
|
7596
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
7597
|
+
d: "M8 16.997c0-.55.453-.997.997-.997h6.006c.55 0 .997.453.997.997v6.006c0 .55-.453.997-.997.997H8.997c-.55 0-.997-.453-.997-.997v-6.006zM10 18h4v4h-4v-4z",
|
|
7598
|
+
fill: "currentColor"
|
|
7599
|
+
}), /*#__PURE__*/React.createElement("rect", {
|
|
7600
|
+
fill: "currentColor",
|
|
7601
|
+
x: "2",
|
|
7602
|
+
y: "11",
|
|
7603
|
+
width: "20",
|
|
7604
|
+
height: "2",
|
|
7605
|
+
rx: "1"
|
|
7606
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
7607
|
+
d: "M8 .997C8 .447 8.453 0 8.997 0h6.006c.55 0 .997.453.997.997v6.006c0 .55-.453.997-.997.997H8.997C8.447 8 8 7.547 8 7.003V.997zM10 2h4v4h-4V2z",
|
|
7608
|
+
fill: "currentColor"
|
|
7609
|
+
}))));
|
|
7356
7610
|
case "FRAC_INCLUSIVE":
|
|
7357
7611
|
return /*#__PURE__*/React.createElement("svg", {
|
|
7358
7612
|
width: "40",
|
|
@@ -7379,26 +7633,23 @@ function ButtonAsset({
|
|
|
7379
7633
|
d: "M12.9571 13.2929C13.3476 13.6834 13.3476 14.3166 12.9571 14.7071C11.6871 15.9771 11 17.9485 11 20C11 22.0515 11.6871 24.0229 12.9571 25.2929C13.3476 25.6834 13.3476 26.3166 12.9571 26.7071C12.5666 27.0976 11.9334 27.0976 11.5429 26.7071C9.81292 24.9771 9 22.4485 9 20C9 17.5515 9.81292 15.0229 11.5429 13.2929C11.9334 12.9024 12.5666 12.9024 12.9571 13.2929ZM14 20C14 19.4477 14.4477 19 15 19H25C25.5523 19 26 19.4477 26 20C26 20.5523 25.5523 21 25 21H15C14.4477 21 14 20.5523 14 20ZM28.4571 13.2929C28.0666 12.9024 27.4334 12.9024 27.0429 13.2929C26.6524 13.6834 26.6524 14.3166 27.0429 14.7071C28.3129 15.9771 29 17.9485 29 20C29 22.0515 28.3129 24.0229 27.0429 25.2929C26.6524 25.6834 26.6524 26.3166 27.0429 26.7071C27.4334 27.0976 28.0666 27.0976 28.4571 26.7071C30.1871 24.9771 31 22.4485 31 20C31 17.5515 30.1871 15.0229 28.4571 13.2929Z",
|
|
7380
7634
|
fill: "#21242C"
|
|
7381
7635
|
}));
|
|
7636
|
+
// TODO(ned): Per the notes in `KeyConfigs`, shouldn't this be a comma
|
|
7637
|
+
// that we replace with the period icon for i18n? Duplicating for now.
|
|
7382
7638
|
case "DECIMAL":
|
|
7639
|
+
case "PERIOD":
|
|
7383
7640
|
return /*#__PURE__*/React.createElement("svg", {
|
|
7384
|
-
|
|
7385
|
-
|
|
7386
|
-
|
|
7387
|
-
fill: "
|
|
7388
|
-
|
|
7389
|
-
}, /*#__PURE__*/React.createElement("g", {
|
|
7390
|
-
clipPath: "url(#clip0)"
|
|
7391
|
-
}, /*#__PURE__*/React.createElement("circle", {
|
|
7392
|
-
cx: "20",
|
|
7393
|
-
cy: "20",
|
|
7394
|
-
r: "1.5",
|
|
7395
|
-
fill: "#21242C"
|
|
7396
|
-
})), /*#__PURE__*/React.createElement("defs", null, /*#__PURE__*/React.createElement("clipPath", {
|
|
7397
|
-
id: "clip0"
|
|
7641
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
7642
|
+
width: "20",
|
|
7643
|
+
height: "20",
|
|
7644
|
+
fill: "currentColor",
|
|
7645
|
+
viewBox: "0 0 256 256"
|
|
7398
7646
|
}, /*#__PURE__*/React.createElement("path", {
|
|
7399
|
-
d: "
|
|
7400
|
-
|
|
7401
|
-
|
|
7647
|
+
d: "M140,128a12,12,0,1,1-12-12A12,12,0,0,1,140,128Z"
|
|
7648
|
+
// moves decimal down to baseline of number icons,
|
|
7649
|
+
// otherwise indistinguishable from cdot
|
|
7650
|
+
,
|
|
7651
|
+
transform: "translate(0 80)"
|
|
7652
|
+
}));
|
|
7402
7653
|
case "RADICAL":
|
|
7403
7654
|
return /*#__PURE__*/React.createElement("svg", {
|
|
7404
7655
|
width: "40",
|
|
@@ -7413,6 +7664,38 @@ function ButtonAsset({
|
|
|
7413
7664
|
fill: "#21242C"
|
|
7414
7665
|
}));
|
|
7415
7666
|
case "SQRT":
|
|
7667
|
+
return /*#__PURE__*/React.createElement("svg", {
|
|
7668
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
7669
|
+
width: "20",
|
|
7670
|
+
height: "20",
|
|
7671
|
+
fill: "currentColor",
|
|
7672
|
+
viewBox: "0 0 256 256"
|
|
7673
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
7674
|
+
d: "M240,72V96a8,8,0,0,1-16,0V80H125.55L79.49,202.81a8,8,0,0,1-15,0l-48-128a8,8,0,1,1,15-5.62L72,177.22l40.51-108A8,8,0,0,1,120,64H232A8,8,0,0,1,240,72Z"
|
|
7675
|
+
}));
|
|
7676
|
+
case "CUBE_ROOT":
|
|
7677
|
+
return /*#__PURE__*/React.createElement("svg", {
|
|
7678
|
+
width: "48",
|
|
7679
|
+
height: "48",
|
|
7680
|
+
viewBox: "0 0 48 48"
|
|
7681
|
+
}, /*#__PURE__*/React.createElement("g", {
|
|
7682
|
+
fill: "none",
|
|
7683
|
+
fillRule: "evenodd",
|
|
7684
|
+
transform: "translate(0, -4)"
|
|
7685
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
7686
|
+
fill: "none",
|
|
7687
|
+
d: "M0 0h48v48H0z"
|
|
7688
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
7689
|
+
d: "M17.91 23.12c1.66 0 2.76-.81 2.76-1.98 0-.96-.86-1.51-1.57-1.58.79-.13 1.46-.72 1.46-1.5 0-1.1-.95-1.83-2.65-1.83-1.23 0-2.11.45-2.67 1.08l.83 1.08c.47-.42 1.05-.64 1.66-.64.64 0 1.12.19 1.12.61 0 .35-.39.52-1.08.52-.25 0-.77 0-.9-.01v1.53c.1-.01.61-.01.9-.01.91 0 1.19.18 1.19.56 0 .37-.38.65-1.12.65-.58 0-1.34-.23-1.82-.7l-.87 1.17c.52.6 1.48 1.05 2.76 1.05z",
|
|
7690
|
+
fill: "currentColor"
|
|
7691
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
7692
|
+
stroke: "currentColor",
|
|
7693
|
+
strokeWidth: "2",
|
|
7694
|
+
strokeLinecap: "round",
|
|
7695
|
+
strokeLinejoin: "round",
|
|
7696
|
+
d: "M14 29l4 6 9-14h7"
|
|
7697
|
+
})));
|
|
7698
|
+
case "EXP":
|
|
7416
7699
|
return /*#__PURE__*/React.createElement("svg", {
|
|
7417
7700
|
width: "40",
|
|
7418
7701
|
height: "40",
|
|
@@ -7420,11 +7703,10 @@ function ButtonAsset({
|
|
|
7420
7703
|
fill: "none",
|
|
7421
7704
|
xmlns: "http://www.w3.org/2000/svg"
|
|
7422
7705
|
}, /*#__PURE__*/React.createElement("path", {
|
|
7423
|
-
|
|
7424
|
-
|
|
7425
|
-
|
|
7426
|
-
|
|
7427
|
-
strokeLinejoin: "round"
|
|
7706
|
+
fillRule: "evenodd",
|
|
7707
|
+
clipRule: "evenodd",
|
|
7708
|
+
fill: "#21242C",
|
|
7709
|
+
d: "M28 8C28 7.44772 28.4477 7 29 7H35C35.5523 7 36 7.44772 36 8V14C36 14.5523 35.5523 15 35 15H29C28.4477 15 28 14.5523 28 14V8ZM30 9H34V13H30V9ZM14 13C14 12.4477 14.4477 12 15 12H25C25.5523 12 26 12.4477 26 13V27C26 27.5523 25.5523 28 25 28H15C14.4477 28 14 27.5523 14 27V13ZM16 14H24V26H16V14Z"
|
|
7428
7710
|
}));
|
|
7429
7711
|
case "EXP_2":
|
|
7430
7712
|
return /*#__PURE__*/React.createElement("svg", {
|
|
@@ -7439,25 +7721,20 @@ function ButtonAsset({
|
|
|
7439
7721
|
d: "M33.5791 13.7461C33.4874 13.6545 33.3591 13.6086 33.1941 13.6086H31.4011C31.2397 13.6086 31.0674 13.6251 30.8841 13.6581C30.7007 13.6875 30.5156 13.7296 30.3286 13.7846L32.0226 12.0521C32.2352 11.8358 32.4369 11.6213 32.6276 11.4086C32.8182 11.196 32.9851 10.9778 33.1281 10.7541C33.2747 10.5268 33.3902 10.2885 33.4746 10.0391C33.5589 9.78981 33.6011 9.51847 33.6011 9.22514C33.6011 8.88414 33.5406 8.57247 33.4196 8.29014C33.2986 8.00781 33.1281 7.76764 32.9081 7.56964C32.6881 7.36797 32.4222 7.21214 32.1106 7.10214C31.8026 6.98847 31.4597 6.93164 31.0821 6.93164C30.7227 6.93164 30.3872 6.98114 30.0756 7.08014C29.7639 7.17547 29.4871 7.32031 29.2451 7.51464C29.0031 7.70897 28.8014 7.95281 28.6401 8.24614C28.4787 8.53947 28.3687 8.88047 28.3101 9.26914L29.1131 9.41214C29.3184 9.44514 29.4761 9.43231 29.5861 9.37364C29.6997 9.31131 29.7896 9.18847 29.8556 9.00514C29.8886 8.88781 29.9399 8.77964 30.0096 8.68064C30.0792 8.58164 30.1617 8.49547 30.2571 8.42214C30.3561 8.34881 30.4661 8.29197 30.5871 8.25164C30.7117 8.20764 30.8474 8.18564 30.9941 8.18564C31.3277 8.18564 31.5862 8.27914 31.7696 8.46614C31.9529 8.64947 32.0446 8.91897 32.0446 9.27464C32.0446 9.47631 32.0189 9.66881 31.9676 9.85214C31.9162 10.0355 31.8392 10.217 31.7366 10.3966C31.6339 10.5726 31.5056 10.7541 31.3516 10.9411C31.1976 11.1245 31.0197 11.317 30.8181 11.5186L28.4531 13.8891C28.3577 13.9808 28.2899 14.0835 28.2496 14.1971C28.2092 14.3071 28.1891 14.4098 28.1891 14.5051V15.0001H33.7221V14.1091C33.7221 13.9588 33.6744 13.8378 33.5791 13.7461ZM14 13.0001C14 12.4479 14.4477 12.0001 15 12.0001H25C25.5523 12.0001 26 12.4479 26 13.0001V27.0001C26 27.5524 25.5523 28.0001 25 28.0001H15C14.4477 28.0001 14 27.5524 14 27.0001V13.0001ZM16 14.0001H24V26.0001H16V14.0001Z",
|
|
7440
7722
|
fill: "#21242C"
|
|
7441
7723
|
}));
|
|
7442
|
-
case "
|
|
7724
|
+
case "EXP_3":
|
|
7443
7725
|
return /*#__PURE__*/React.createElement("svg", {
|
|
7444
|
-
width: "
|
|
7445
|
-
height: "
|
|
7726
|
+
width: "42",
|
|
7727
|
+
height: "42",
|
|
7446
7728
|
viewBox: "0 0 40 40",
|
|
7447
7729
|
fill: "none",
|
|
7448
7730
|
xmlns: "http://www.w3.org/2000/svg"
|
|
7449
7731
|
}, /*#__PURE__*/React.createElement("path", {
|
|
7732
|
+
transform: "translate(0, -8)",
|
|
7450
7733
|
fillRule: "evenodd",
|
|
7451
7734
|
clipRule: "evenodd",
|
|
7452
|
-
|
|
7453
|
-
|
|
7735
|
+
fill: "#21242C",
|
|
7736
|
+
d: "M14 21c0-.552.456-1 1.002-1h9.996A1 1 0 0 1 26 21v14c0 .552-.456 1-1.002 1h-9.996A1 1 0 0 1 14 35V21zm2 1h8v12h-8V22zM30.92 23.12c1.66 0 2.76-.81 2.76-1.98 0-.96-.86-1.51-1.57-1.58.79-.13 1.46-.72 1.46-1.5 0-1.1-.95-1.83-2.65-1.83-1.23 0-2.11.45-2.67 1.08l.83 1.08c.47-.42 1.05-.64 1.66-.64.64 0 1.12.19 1.12.61 0 .35-.39.52-1.08.52-.25 0-.77 0-.9-.01v1.53c.1-.01.61-.01.9-.01.91 0 1.19.18 1.19.56 0 .37-.38.65-1.12.65-.58 0-1.34-.23-1.82-.7l-.87 1.17c.52.6 1.48 1.05 2.76 1.05z"
|
|
7454
7737
|
}));
|
|
7455
|
-
case "PI":
|
|
7456
|
-
//TODO(NickR): use correct font, size, and color for this. It's not an SVG asset
|
|
7457
|
-
return /*#__PURE__*/React.createElement("span", null, "pi");
|
|
7458
|
-
case "X":
|
|
7459
|
-
//TODO(NickR): use correct font, size, and color for this. It's not an SVG asset
|
|
7460
|
-
return /*#__PURE__*/React.createElement("span", null, "x");
|
|
7461
7738
|
case "TAN":
|
|
7462
7739
|
return /*#__PURE__*/React.createElement("svg", {
|
|
7463
7740
|
width: "40",
|
|
@@ -7491,7 +7768,310 @@ function ButtonAsset({
|
|
|
7491
7768
|
d: "M16.4215 19.392C16.3682 19.4773 16.3122 19.5387 16.2535 19.576C16.1948 19.608 16.1202 19.624 16.0295 19.624C15.9335 19.624 15.8295 19.5973 15.7175 19.544C15.6108 19.4907 15.4855 19.432 15.3415 19.368C15.1975 19.2987 15.0322 19.2373 14.8455 19.184C14.6642 19.1307 14.4482 19.104 14.1975 19.104C13.8082 19.104 13.5015 19.1867 13.2775 19.352C13.0588 19.5173 12.9495 19.7333 12.9495 20C12.9495 20.176 13.0055 20.3253 13.1175 20.448C13.2348 20.5653 13.3868 20.6693 13.5735 20.76C13.7655 20.8507 13.9815 20.9333 14.2215 21.008C14.4615 21.0773 14.7042 21.1547 14.9495 21.24C15.2002 21.3253 15.4455 21.424 15.6855 21.536C15.9255 21.6427 16.1388 21.7813 16.3255 21.952C16.5175 22.1173 16.6695 22.3173 16.7815 22.552C16.8988 22.7867 16.9575 23.0693 16.9575 23.4C16.9575 23.7947 16.8855 24.16 16.7415 24.496C16.6028 24.8267 16.3948 25.1147 16.1175 25.36C15.8402 25.6 15.4962 25.7893 15.0855 25.928C14.6802 26.0613 14.2108 26.128 13.6775 26.128C13.3948 26.128 13.1175 26.1013 12.8455 26.048C12.5788 26 12.3202 25.9307 12.0695 25.84C11.8242 25.7493 11.5948 25.6427 11.3815 25.52C11.1735 25.3973 10.9895 25.264 10.8295 25.12L11.2855 24.368C11.3442 24.2773 11.4135 24.208 11.4935 24.16C11.5735 24.112 11.6748 24.088 11.7975 24.088C11.9202 24.088 12.0348 24.1227 12.1415 24.192C12.2535 24.2613 12.3815 24.336 12.5255 24.416C12.6695 24.496 12.8375 24.5707 13.0295 24.64C13.2268 24.7093 13.4748 24.744 13.7735 24.744C14.0082 24.744 14.2082 24.7173 14.3735 24.664C14.5442 24.6053 14.6828 24.5307 14.7895 24.44C14.9015 24.3493 14.9815 24.2453 15.0295 24.128C15.0828 24.0053 15.1095 23.88 15.1095 23.752C15.1095 23.56 15.0508 23.4027 14.9335 23.28C14.8215 23.1573 14.6695 23.0507 14.4775 22.96C14.2908 22.8693 14.0748 22.7893 13.8295 22.72C13.5895 22.6453 13.3415 22.5653 13.0855 22.48C12.8348 22.3947 12.5868 22.296 12.3415 22.184C12.1015 22.0667 11.8855 21.92 11.6935 21.744C11.5068 21.568 11.3548 21.352 11.2375 21.096C11.1255 20.84 11.0695 20.5307 11.0695 20.168C11.0695 19.832 11.1362 19.512 11.2695 19.208C11.4028 18.904 11.5975 18.64 11.8535 18.416C12.1148 18.1867 12.4375 18.0053 12.8215 17.872C13.2108 17.7333 13.6588 17.664 14.1655 17.664C14.7308 17.664 15.2455 17.7573 15.7095 17.944C16.1735 18.1307 16.5602 18.376 16.8695 18.68L16.4215 19.392ZM20.4928 17.792V26H18.5088V17.792H20.4928ZM20.7648 15.4C20.7648 15.5707 20.7301 15.7307 20.6608 15.88C20.5914 16.0293 20.4981 16.16 20.3808 16.272C20.2688 16.384 20.1354 16.4747 19.9808 16.544C19.8261 16.608 19.6608 16.64 19.4848 16.64C19.3141 16.64 19.1514 16.608 18.9968 16.544C18.8474 16.4747 18.7168 16.384 18.6048 16.272C18.4928 16.16 18.4021 16.0293 18.3328 15.88C18.2688 15.7307 18.2368 15.5707 18.2368 15.4C18.2368 15.224 18.2688 15.0587 18.3328 14.904C18.4021 14.7493 18.4928 14.616 18.6048 14.504C18.7168 14.392 18.8474 14.304 18.9968 14.24C19.1514 14.1707 19.3141 14.136 19.4848 14.136C19.6608 14.136 19.8261 14.1707 19.9808 14.24C20.1354 14.304 20.2688 14.392 20.3808 14.504C20.4981 14.616 20.5914 14.7493 20.6608 14.904C20.7301 15.0587 20.7648 15.224 20.7648 15.4ZM24.3553 18.8C24.5206 18.6347 24.6939 18.4827 24.8753 18.344C25.0619 18.2 25.2566 18.08 25.4593 17.984C25.6673 17.8827 25.8886 17.8053 26.1233 17.752C26.3579 17.6933 26.6139 17.664 26.8913 17.664C27.3393 17.664 27.7366 17.7413 28.0833 17.896C28.4299 18.0453 28.7179 18.2587 28.9473 18.536C29.1819 18.808 29.3579 19.136 29.4753 19.52C29.5979 19.8987 29.6593 20.3173 29.6593 20.776V26H27.6833V20.776C27.6833 20.2747 27.5686 19.888 27.3393 19.616C27.1099 19.3387 26.7606 19.2 26.2913 19.2C25.9499 19.2 25.6299 19.2773 25.3313 19.432C25.0326 19.5867 24.7499 19.7973 24.4833 20.064V26H22.5073V17.792H23.7153C23.9713 17.792 24.1393 17.912 24.2193 18.152L24.3553 18.8Z",
|
|
7492
7769
|
fill: "#21242C"
|
|
7493
7770
|
}));
|
|
7494
|
-
|
|
7771
|
+
case "DIVIDE":
|
|
7772
|
+
return /*#__PURE__*/React.createElement("svg", {
|
|
7773
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
7774
|
+
width: "20",
|
|
7775
|
+
height: "20",
|
|
7776
|
+
fill: "currentColor",
|
|
7777
|
+
viewBox: "0 0 256 256"
|
|
7778
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
7779
|
+
d: "M224,128a8,8,0,0,1-8,8H40a8,8,0,0,1,0-16H216A8,8,0,0,1,224,128ZM128,80a16,16,0,1,0-16-16A16,16,0,0,0,128,80Zm0,96a16,16,0,1,0,16,16A16,16,0,0,0,128,176Z"
|
|
7780
|
+
}));
|
|
7781
|
+
case "EQUAL":
|
|
7782
|
+
return /*#__PURE__*/React.createElement("svg", {
|
|
7783
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
7784
|
+
width: "20",
|
|
7785
|
+
height: "20",
|
|
7786
|
+
fill: "currentColor",
|
|
7787
|
+
viewBox: "0 0 256 256"
|
|
7788
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
7789
|
+
d: "M224,160a8,8,0,0,1-8,8H40a8,8,0,0,1,0-16H216A8,8,0,0,1,224,160ZM40,104H216a8,8,0,0,0,0-16H40a8,8,0,0,0,0,16Z"
|
|
7790
|
+
}));
|
|
7791
|
+
case "GT":
|
|
7792
|
+
return /*#__PURE__*/React.createElement("svg", {
|
|
7793
|
+
width: "44",
|
|
7794
|
+
height: "44",
|
|
7795
|
+
viewBox: "0 0 48 48"
|
|
7796
|
+
}, /*#__PURE__*/React.createElement("g", {
|
|
7797
|
+
fill: "none",
|
|
7798
|
+
fillRule: "evenodd"
|
|
7799
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
7800
|
+
fill: "none",
|
|
7801
|
+
d: "M0 0h48v48H0z"
|
|
7802
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
7803
|
+
fill: "none",
|
|
7804
|
+
d: "M12 12h24v24H12z"
|
|
7805
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
7806
|
+
stroke: "currentColor",
|
|
7807
|
+
strokeWidth: "2",
|
|
7808
|
+
strokeLinecap: "round",
|
|
7809
|
+
strokeLinejoin: "round",
|
|
7810
|
+
d: "M16 30l16-6-16-6"
|
|
7811
|
+
})));
|
|
7812
|
+
case "LT":
|
|
7813
|
+
return /*#__PURE__*/React.createElement("svg", {
|
|
7814
|
+
width: "44",
|
|
7815
|
+
height: "44",
|
|
7816
|
+
viewBox: "0 0 48 48"
|
|
7817
|
+
}, /*#__PURE__*/React.createElement("g", {
|
|
7818
|
+
fill: "none",
|
|
7819
|
+
fillRule: "evenodd"
|
|
7820
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
7821
|
+
fill: "none",
|
|
7822
|
+
d: "M0 0h48v48H0z"
|
|
7823
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
7824
|
+
fill: "none",
|
|
7825
|
+
d: "M12 12h24v24H12z"
|
|
7826
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
7827
|
+
stroke: "currentColor",
|
|
7828
|
+
strokeWidth: "2",
|
|
7829
|
+
strokeLinecap: "round",
|
|
7830
|
+
strokeLinejoin: "round",
|
|
7831
|
+
d: "M32 30l-16-6 16-6"
|
|
7832
|
+
})));
|
|
7833
|
+
case "GEQ":
|
|
7834
|
+
return /*#__PURE__*/React.createElement("svg", {
|
|
7835
|
+
width: "44",
|
|
7836
|
+
height: "44",
|
|
7837
|
+
viewBox: "0 0 48 48"
|
|
7838
|
+
}, /*#__PURE__*/React.createElement("g", {
|
|
7839
|
+
fill: "none",
|
|
7840
|
+
fillRule: "evenodd"
|
|
7841
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
7842
|
+
fill: "none",
|
|
7843
|
+
d: "M0 0h48v48H0z"
|
|
7844
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
7845
|
+
fill: "none",
|
|
7846
|
+
d: "M12 12h24v24H12z"
|
|
7847
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
7848
|
+
d: "M16 33h16M16 30l16-6-16-6",
|
|
7849
|
+
stroke: "currentColor",
|
|
7850
|
+
strokeWidth: "2",
|
|
7851
|
+
strokeLinecap: "round",
|
|
7852
|
+
strokeLinejoin: "round"
|
|
7853
|
+
})));
|
|
7854
|
+
case "LEQ":
|
|
7855
|
+
return /*#__PURE__*/React.createElement("svg", {
|
|
7856
|
+
width: "44",
|
|
7857
|
+
height: "44",
|
|
7858
|
+
viewBox: "0 0 48 48"
|
|
7859
|
+
}, /*#__PURE__*/React.createElement("g", {
|
|
7860
|
+
fill: "none",
|
|
7861
|
+
fillRule: "evenodd"
|
|
7862
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
7863
|
+
fill: "none",
|
|
7864
|
+
d: "M0 0h48v48H0z"
|
|
7865
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
7866
|
+
fill: "none",
|
|
7867
|
+
d: "M12 12h24v24H12z"
|
|
7868
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
7869
|
+
d: "M16 33h16M32 30l-16-6 16-6",
|
|
7870
|
+
stroke: "currentColor",
|
|
7871
|
+
strokeWidth: "2",
|
|
7872
|
+
strokeLinecap: "round",
|
|
7873
|
+
strokeLinejoin: "round"
|
|
7874
|
+
})));
|
|
7875
|
+
case "NEQ":
|
|
7876
|
+
return /*#__PURE__*/React.createElement("svg", {
|
|
7877
|
+
width: "44",
|
|
7878
|
+
height: "44",
|
|
7879
|
+
viewBox: "0 0 48 48"
|
|
7880
|
+
}, /*#__PURE__*/React.createElement("g", {
|
|
7881
|
+
fill: "none",
|
|
7882
|
+
fillRule: "evenodd"
|
|
7883
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
7884
|
+
fill: "none",
|
|
7885
|
+
d: "M0 0h48v48H0z"
|
|
7886
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
7887
|
+
fill: "none",
|
|
7888
|
+
d: "M12 12h24v24H12z"
|
|
7889
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
7890
|
+
d: "M19 33l10-18M16 21h17M16 27h17",
|
|
7891
|
+
stroke: "currentColor",
|
|
7892
|
+
strokeWidth: "2",
|
|
7893
|
+
strokeLinecap: "round",
|
|
7894
|
+
strokeLinejoin: "round"
|
|
7895
|
+
})));
|
|
7896
|
+
case "LN":
|
|
7897
|
+
return /*#__PURE__*/React.createElement("svg", {
|
|
7898
|
+
width: "48",
|
|
7899
|
+
height: "48",
|
|
7900
|
+
viewBox: "0 0 48 48"
|
|
7901
|
+
}, /*#__PURE__*/React.createElement("g", {
|
|
7902
|
+
fill: "none",
|
|
7903
|
+
fillRule: "evenodd"
|
|
7904
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
7905
|
+
fill: "none",
|
|
7906
|
+
d: "M0 0h48v48H0z"
|
|
7907
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
7908
|
+
d: "M20.836 29v-9.338h-1.778V29h1.778zm8.106 0v-4.774c0-1.316-.714-2.156-2.198-2.156-1.106 0-1.932.532-2.366 1.05v-.882H22.6V29h1.778v-4.55c.294-.406.84-.798 1.54-.798.756 0 1.246.322 1.246 1.26V29h1.778z",
|
|
7909
|
+
fill: "currentColor"
|
|
7910
|
+
})));
|
|
7911
|
+
case "LOG":
|
|
7912
|
+
return /*#__PURE__*/React.createElement("svg", {
|
|
7913
|
+
width: "48",
|
|
7914
|
+
height: "48",
|
|
7915
|
+
viewBox: "0 0 48 48"
|
|
7916
|
+
}, /*#__PURE__*/React.createElement("g", {
|
|
7917
|
+
fill: "none",
|
|
7918
|
+
fillRule: "evenodd"
|
|
7919
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
7920
|
+
fill: "none",
|
|
7921
|
+
d: "M0 0h48v48H0z"
|
|
7922
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
7923
|
+
d: "M16.776 29v-9.338h-1.778V29h1.778zm4.9.168c2.24 0 3.584-1.624 3.584-3.556 0-1.918-1.344-3.542-3.584-3.542-2.226 0-3.57 1.624-3.57 3.542 0 1.932 1.344 3.556 3.57 3.556zm0-1.582c-1.106 0-1.722-.91-1.722-1.974 0-1.05.616-1.96 1.722-1.96 1.106 0 1.736.91 1.736 1.96 0 1.064-.63 1.974-1.736 1.974zm7.672 4.158c1.666 0 3.654-.63 3.654-3.206v-6.3H31.21v.868c-.546-.686-1.274-1.036-2.086-1.036-1.708 0-2.982 1.232-2.982 3.444 0 2.254 1.288 3.444 2.982 3.444.826 0 1.554-.392 2.086-1.064v.686c0 1.33-1.008 1.708-1.862 1.708-.854 0-1.568-.238-2.114-.84l-.798 1.288c.854.742 1.75 1.008 2.912 1.008zm.336-4.368c-1.008 0-1.708-.7-1.708-1.862 0-1.162.7-1.862 1.708-1.862.588 0 1.232.322 1.526.77v2.184c-.294.434-.938.77-1.526.77z",
|
|
7924
|
+
fill: "currentColor"
|
|
7925
|
+
})));
|
|
7926
|
+
case "LOG_N":
|
|
7927
|
+
return /*#__PURE__*/React.createElement("svg", {
|
|
7928
|
+
width: "48",
|
|
7929
|
+
height: "48",
|
|
7930
|
+
viewBox: "0 0 48 48"
|
|
7931
|
+
}, /*#__PURE__*/React.createElement("g", {
|
|
7932
|
+
fill: "none",
|
|
7933
|
+
fillRule: "evenodd"
|
|
7934
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
7935
|
+
fill: "none",
|
|
7936
|
+
d: "M0 0h48v48H0z"
|
|
7937
|
+
}), /*#__PURE__*/React.createElement("path", {
|
|
7938
|
+
d: "M30 28.997c0-.55.453-.997.997-.997h6.006c.55 0 .997.453.997.997v6.006c0 .55-.453.997-.997.997h-6.006c-.55 0-.997-.453-.997-.997v-6.006zM32 30h4v4h-4v-4zM12.776 29v-9.338h-1.778V29h1.778zm4.9.168c2.24 0 3.584-1.624 3.584-3.556 0-1.918-1.344-3.542-3.584-3.542-2.226 0-3.57 1.624-3.57 3.542 0 1.932 1.344 3.556 3.57 3.556zm0-1.582c-1.106 0-1.722-.91-1.722-1.974 0-1.05.616-1.96 1.722-1.96 1.106 0 1.736.91 1.736 1.96 0 1.064-.63 1.974-1.736 1.974zm7.672 4.158c1.666 0 3.654-.63 3.654-3.206v-6.3H27.21v.868c-.546-.686-1.274-1.036-2.086-1.036-1.708 0-2.982 1.232-2.982 3.444 0 2.254 1.288 3.444 2.982 3.444.826 0 1.554-.392 2.086-1.064v.686c0 1.33-1.008 1.708-1.862 1.708-.854 0-1.568-.238-2.114-.84l-.798 1.288c.854.742 1.75 1.008 2.912 1.008zm.336-4.368c-1.008 0-1.708-.7-1.708-1.862 0-1.162.7-1.862 1.708-1.862.588 0 1.232.322 1.526.77v2.184c-.294.434-.938.77-1.526.77z",
|
|
7939
|
+
fill: "currentColor"
|
|
7940
|
+
})));
|
|
7941
|
+
case "PERCENT":
|
|
7942
|
+
return /*#__PURE__*/React.createElement("svg", {
|
|
7943
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
7944
|
+
width: "20",
|
|
7945
|
+
height: "20",
|
|
7946
|
+
fill: "currentColor",
|
|
7947
|
+
viewBox: "0 0 256 256"
|
|
7948
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
7949
|
+
d: "M205.66,61.64l-144,144a8,8,0,0,1-11.32-11.32l144-144a8,8,0,0,1,11.32,11.31ZM50.54,101.44a36,36,0,0,1,50.92-50.91h0a36,36,0,0,1-50.92,50.91ZM56,76A20,20,0,1,0,90.14,61.84h0A20,20,0,0,0,56,76ZM216,180a36,36,0,1,1-10.54-25.46h0A35.76,35.76,0,0,1,216,180Zm-16,0a20,20,0,1,0-5.86,14.14A19.87,19.87,0,0,0,200,180Z"
|
|
7950
|
+
}));
|
|
7951
|
+
case "CDOT":
|
|
7952
|
+
return /*#__PURE__*/React.createElement("svg", {
|
|
7953
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
7954
|
+
width: "20",
|
|
7955
|
+
height: "20",
|
|
7956
|
+
fill: "currentColor",
|
|
7957
|
+
viewBox: "0 0 256 256"
|
|
7958
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
7959
|
+
d: "M140,128a12,12,0,1,1-12-12A12,12,0,0,1,140,128Z"
|
|
7960
|
+
}));
|
|
7961
|
+
case "PI":
|
|
7962
|
+
return /*#__PURE__*/React.createElement("svg", {
|
|
7963
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
7964
|
+
width: "20",
|
|
7965
|
+
height: "20",
|
|
7966
|
+
fill: "currentColor",
|
|
7967
|
+
viewBox: "0 0 256 256"
|
|
7968
|
+
}, /*#__PURE__*/React.createElement("path", {
|
|
7969
|
+
d: "M232,172a36,36,0,0,1-72,0V72H96V200a8,8,0,0,1-16,0V72H72a40,40,0,0,0-40,40,8,8,0,0,1-16,0A56.06,56.06,0,0,1,72,56H224a8,8,0,0,1,0,16H176V172a20,20,0,0,0,40,0,8,8,0,0,1,16,0Z"
|
|
7970
|
+
}));
|
|
7971
|
+
case "x":
|
|
7972
|
+
// MATHEMATICAL ITALIC SMALL CHI
|
|
7973
|
+
// https://en.wikipedia.org/wiki/Chi_(letter)#Mathematical_chi
|
|
7974
|
+
return /*#__PURE__*/React.createElement("svg", {
|
|
7975
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
7976
|
+
width: "20",
|
|
7977
|
+
height: "20",
|
|
7978
|
+
fill: "currentColor",
|
|
7979
|
+
viewBox: "0 0 256 256"
|
|
7980
|
+
}, /*#__PURE__*/React.createElement("text", {
|
|
7981
|
+
fontSize: "200px",
|
|
7982
|
+
x: "50%",
|
|
7983
|
+
y: "50%",
|
|
7984
|
+
dominantBaseline: "middle",
|
|
7985
|
+
textAnchor: "middle"
|
|
7986
|
+
}, "\uD835\uDF12"));
|
|
7987
|
+
case "X":
|
|
7988
|
+
// MATHEMATICAL ITALIC CAPITAL CHI
|
|
7989
|
+
// https://en.wikipedia.org/wiki/Chi_(letter)#Mathematical_chi
|
|
7990
|
+
return /*#__PURE__*/React.createElement("svg", {
|
|
7991
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
7992
|
+
width: "20",
|
|
7993
|
+
height: "20",
|
|
7994
|
+
fill: "currentColor",
|
|
7995
|
+
viewBox: "0 0 256 256"
|
|
7996
|
+
}, /*#__PURE__*/React.createElement("text", {
|
|
7997
|
+
fontSize: "200px",
|
|
7998
|
+
x: "50%",
|
|
7999
|
+
y: "50%",
|
|
8000
|
+
dominantBaseline: "middle",
|
|
8001
|
+
textAnchor: "middle"
|
|
8002
|
+
}, "\uD835\uDEF8"));
|
|
8003
|
+
|
|
8004
|
+
/**
|
|
8005
|
+
* ANYTHING BELOW IS NOT YET HANDLED
|
|
8006
|
+
*/
|
|
8007
|
+
case "MANY":
|
|
8008
|
+
case "FRAC_EXCLUSIVE":
|
|
8009
|
+
case "THETA":
|
|
8010
|
+
case "NOOP":
|
|
8011
|
+
case "UP":
|
|
8012
|
+
case "DOWN":
|
|
8013
|
+
case "LEFT":
|
|
8014
|
+
case "RIGHT":
|
|
8015
|
+
case "JUMP_OUT_PARENTHESES":
|
|
8016
|
+
case "JUMP_OUT_EXPONENT":
|
|
8017
|
+
case "JUMP_OUT_BASE":
|
|
8018
|
+
case "JUMP_INTO_NUMERATOR":
|
|
8019
|
+
case "JUMP_OUT_NUMERATOR":
|
|
8020
|
+
case "JUMP_OUT_DENOMINATOR":
|
|
8021
|
+
case "PHI":
|
|
8022
|
+
case "NTHROOT3":
|
|
8023
|
+
case "POW":
|
|
8024
|
+
case "LOG_B":
|
|
8025
|
+
case "a":
|
|
8026
|
+
case "b":
|
|
8027
|
+
case "c":
|
|
8028
|
+
case "d":
|
|
8029
|
+
case "e":
|
|
8030
|
+
case "f":
|
|
8031
|
+
case "g":
|
|
8032
|
+
case "h":
|
|
8033
|
+
case "i":
|
|
8034
|
+
case "j":
|
|
8035
|
+
case "k":
|
|
8036
|
+
case "l":
|
|
8037
|
+
case "m":
|
|
8038
|
+
case "n":
|
|
8039
|
+
case "o":
|
|
8040
|
+
case "p":
|
|
8041
|
+
case "q":
|
|
8042
|
+
case "r":
|
|
8043
|
+
case "s":
|
|
8044
|
+
case "t":
|
|
8045
|
+
case "u":
|
|
8046
|
+
case "v":
|
|
8047
|
+
case "w":
|
|
8048
|
+
case "y":
|
|
8049
|
+
case "z":
|
|
8050
|
+
case "A":
|
|
8051
|
+
case "B":
|
|
8052
|
+
case "C":
|
|
8053
|
+
case "D":
|
|
8054
|
+
case "E":
|
|
8055
|
+
case "F":
|
|
8056
|
+
case "G":
|
|
8057
|
+
case "H":
|
|
8058
|
+
case "I":
|
|
8059
|
+
case "J":
|
|
8060
|
+
case "K":
|
|
8061
|
+
case "L":
|
|
8062
|
+
case "M":
|
|
8063
|
+
case "N":
|
|
8064
|
+
case "O":
|
|
8065
|
+
case "P":
|
|
8066
|
+
case "Q":
|
|
8067
|
+
case "R":
|
|
8068
|
+
case "S":
|
|
8069
|
+
case "T":
|
|
8070
|
+
case "U":
|
|
8071
|
+
case "V":
|
|
8072
|
+
case "W":
|
|
8073
|
+
case "Y":
|
|
8074
|
+
case "Z":
|
|
7495
8075
|
// placeholder
|
|
7496
8076
|
return /*#__PURE__*/React.createElement("svg", {
|
|
7497
8077
|
width: "40",
|
|
@@ -7509,6 +8089,11 @@ function ButtonAsset({
|
|
|
7509
8089
|
lengthAdjust: "spacingAndGlyphs",
|
|
7510
8090
|
fill: "red"
|
|
7511
8091
|
}, "placeholder"));
|
|
8092
|
+
default:
|
|
8093
|
+
// this line forces an exhaustive check of all keys;
|
|
8094
|
+
// if a key is not handled, the compiler will complain.
|
|
8095
|
+
const unhandledKey = id;
|
|
8096
|
+
throw new Error(`Unhandled key: ${unhandledKey}`);
|
|
7512
8097
|
}
|
|
7513
8098
|
}
|
|
7514
8099
|
|
|
@@ -7611,7 +8196,7 @@ class GeometryPage extends React.Component {
|
|
|
7611
8196
|
gridColumn: 6
|
|
7612
8197
|
}
|
|
7613
8198
|
}), /*#__PURE__*/React.createElement(SecondaryKeypadButton, {
|
|
7614
|
-
keyConfig: KeyConfigs.
|
|
8199
|
+
keyConfig: KeyConfigs.x,
|
|
7615
8200
|
onClickKey: onClickKey,
|
|
7616
8201
|
style: {
|
|
7617
8202
|
gridColumn: 5
|
|
@@ -7832,7 +8417,7 @@ class OperatorsPage extends React.Component {
|
|
|
7832
8417
|
onClickKey: onClickKey,
|
|
7833
8418
|
placeholder: !this.props.logarithms
|
|
7834
8419
|
}), /*#__PURE__*/React.createElement(SecondaryKeypadButton, {
|
|
7835
|
-
keyConfig: KeyConfigs.
|
|
8420
|
+
keyConfig: KeyConfigs.x,
|
|
7836
8421
|
onClickKey: onClickKey,
|
|
7837
8422
|
style: {
|
|
7838
8423
|
gridColumn: 5
|
|
@@ -7909,5 +8494,5 @@ class Keypad extends React.Component {
|
|
|
7909
8494
|
}
|
|
7910
8495
|
}
|
|
7911
8496
|
|
|
7912
|
-
export { CursorContext, KeyConfigs,
|
|
8497
|
+
export { CursorContext, KeyConfigs, Keypad, MathInput as KeypadInput, KeypadType, ProvidedKeypad as LegacyKeypad, keyToMathquillMap as keyTranslator, keypadElementPropType };
|
|
7913
8498
|
//# sourceMappingURL=index.js.map
|