@khanacademy/math-input 0.3.2 → 0.5.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 +8 -0
- package/README.md +1 -1
- package/{build/math-input.css → dist/es/index.css} +0 -150
- package/dist/es/index.js +2 -0
- package/dist/es/index.js.map +1 -0
- package/dist/index.css +586 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.flow +2 -0
- package/dist/index.js.map +1 -0
- package/dist/strings.js +71 -0
- package/index.html +20 -0
- package/less/echo.less +56 -0
- package/less/main.less +5 -0
- package/less/overrides.less +129 -0
- package/less/popover.less +22 -0
- package/less/tabbar.less +6 -0
- package/package.json +38 -70
- package/src/actions/index.js +57 -0
- package/src/components/__tests__/gesture-state-machine_test.js +437 -0
- package/src/components/__tests__/node-manager_test.js +89 -0
- package/src/components/__tests__/two-page-keypad_test.js +42 -0
- package/src/components/app.js +73 -0
- package/src/components/common-style.js +47 -0
- package/src/components/compute-layout-parameters.js +157 -0
- package/src/components/corner-decal.js +56 -0
- package/src/components/echo-manager.js +160 -0
- package/src/components/empty-keypad-button.js +49 -0
- package/src/components/expression-keypad.js +323 -0
- package/src/components/fraction-keypad.js +176 -0
- package/src/components/gesture-manager.js +226 -0
- package/src/components/gesture-state-machine.js +283 -0
- package/src/components/icon.js +74 -0
- package/src/components/iconography/arrow.js +22 -0
- package/src/components/iconography/backspace.js +29 -0
- package/src/components/iconography/cdot.js +29 -0
- package/src/components/iconography/cos.js +30 -0
- package/src/components/iconography/cube-root.js +36 -0
- package/src/components/iconography/dismiss.js +25 -0
- package/src/components/iconography/divide.js +34 -0
- package/src/components/iconography/down.js +16 -0
- package/src/components/iconography/equal.js +33 -0
- package/src/components/iconography/exp-2.js +29 -0
- package/src/components/iconography/exp-3.js +29 -0
- package/src/components/iconography/exp.js +29 -0
- package/src/components/iconography/frac.js +44 -0
- package/src/components/iconography/geq.js +33 -0
- package/src/components/iconography/gt.js +33 -0
- package/src/components/iconography/index.js +45 -0
- package/src/components/iconography/jump-into-numerator.js +41 -0
- package/src/components/iconography/jump-out-base.js +30 -0
- package/src/components/iconography/jump-out-denominator.js +41 -0
- package/src/components/iconography/jump-out-exponent.js +30 -0
- package/src/components/iconography/jump-out-numerator.js +41 -0
- package/src/components/iconography/jump-out-parentheses.js +33 -0
- package/src/components/iconography/left-paren.js +33 -0
- package/src/components/iconography/left.js +16 -0
- package/src/components/iconography/leq.js +33 -0
- package/src/components/iconography/ln.js +29 -0
- package/src/components/iconography/log-n.js +29 -0
- package/src/components/iconography/log.js +29 -0
- package/src/components/iconography/lt.js +33 -0
- package/src/components/iconography/minus.js +32 -0
- package/src/components/iconography/neq.js +33 -0
- package/src/components/iconography/parens.js +33 -0
- package/src/components/iconography/percent.js +49 -0
- package/src/components/iconography/period.js +26 -0
- package/src/components/iconography/plus.js +32 -0
- package/src/components/iconography/radical.js +36 -0
- package/src/components/iconography/right-paren.js +33 -0
- package/src/components/iconography/right.js +16 -0
- package/src/components/iconography/sin.js +30 -0
- package/src/components/iconography/sqrt.js +32 -0
- package/src/components/iconography/tan.js +30 -0
- package/src/components/iconography/times.js +33 -0
- package/src/components/iconography/up.js +16 -0
- package/src/components/input/__tests__/context-tracking_test.js +177 -0
- package/src/components/input/__tests__/math-wrapper.jsx +33 -0
- package/src/components/input/__tests__/mathquill_test.js +747 -0
- package/src/components/input/cursor-contexts.js +29 -0
- package/src/components/input/cursor-handle.js +137 -0
- package/src/components/input/drag-listener.js +75 -0
- package/src/components/input/math-input.js +924 -0
- package/src/components/input/math-wrapper.js +959 -0
- package/src/components/input/scroll-into-view.js +72 -0
- package/src/components/keypad/button-assets.js +492 -0
- package/src/components/keypad/button.js +106 -0
- package/src/components/keypad/button.stories.js +27 -0
- package/src/components/keypad/index.js +64 -0
- package/src/components/keypad/keypad-page-items.js +106 -0
- package/src/components/keypad/keypad-pages.stories.js +32 -0
- package/src/components/keypad/keypad.stories.js +35 -0
- package/src/components/keypad/numeric-input-page.js +100 -0
- package/src/components/keypad/pre-algebra-page.js +98 -0
- package/src/components/keypad/trigonometry-page.js +90 -0
- package/src/components/keypad-button.js +366 -0
- package/src/components/keypad-container.js +303 -0
- package/src/components/keypad.js +154 -0
- package/src/components/many-keypad-button.js +44 -0
- package/src/components/math-icon.js +65 -0
- package/src/components/multi-symbol-grid.js +182 -0
- package/src/components/multi-symbol-popover.js +59 -0
- package/src/components/navigation-pad.js +139 -0
- package/src/components/node-manager.js +129 -0
- package/src/components/popover-manager.js +76 -0
- package/src/components/popover-state-machine.js +173 -0
- package/src/components/prop-types.js +82 -0
- package/src/components/provided-keypad.js +99 -0
- package/src/components/styles.js +38 -0
- package/src/components/svg-icon.js +25 -0
- package/src/components/tabbar/__tests__/tabbar_test.js +65 -0
- package/src/components/tabbar/icons.js +69 -0
- package/src/components/tabbar/item.js +138 -0
- package/src/components/tabbar/tabbar.js +61 -0
- package/src/components/tabbar/tabbar.stories.js +60 -0
- package/src/components/tabbar/types.js +3 -0
- package/src/components/text-icon.js +52 -0
- package/src/components/touchable-keypad-button.js +146 -0
- package/src/components/two-page-keypad.js +99 -0
- package/src/components/velocity-tracker.js +76 -0
- package/src/components/z-indexes.js +9 -0
- package/src/consts.js +74 -0
- package/src/data/key-configs.js +349 -0
- package/src/data/keys.js +72 -0
- package/src/demo.js +8 -0
- package/src/fake-react-native-web/index.js +12 -0
- package/src/fake-react-native-web/text.js +56 -0
- package/src/fake-react-native-web/view.js +91 -0
- package/src/index.js +13 -0
- package/src/native-app.js +84 -0
- package/src/store/index.js +505 -0
- package/src/utils.js +18 -0
- package/tools/svg-to-react/convert.py +111 -0
- package/tools/svg-to-react/icons/math-keypad-icon-0.svg +32 -0
- package/tools/svg-to-react/icons/math-keypad-icon-1.svg +32 -0
- package/tools/svg-to-react/icons/math-keypad-icon-2.svg +32 -0
- package/tools/svg-to-react/icons/math-keypad-icon-3.svg +32 -0
- package/tools/svg-to-react/icons/math-keypad-icon-4.svg +32 -0
- package/tools/svg-to-react/icons/math-keypad-icon-5.svg +32 -0
- package/tools/svg-to-react/icons/math-keypad-icon-6.svg +32 -0
- package/tools/svg-to-react/icons/math-keypad-icon-7.svg +32 -0
- package/tools/svg-to-react/icons/math-keypad-icon-8.svg +32 -0
- package/tools/svg-to-react/icons/math-keypad-icon-9.svg +32 -0
- package/tools/svg-to-react/icons/math-keypad-icon-addition.svg +34 -0
- package/tools/svg-to-react/icons/math-keypad-icon-cos.svg +38 -0
- package/tools/svg-to-react/icons/math-keypad-icon-delete.svg +36 -0
- package/tools/svg-to-react/icons/math-keypad-icon-dismiss.svg +36 -0
- package/tools/svg-to-react/icons/math-keypad-icon-division.svg +36 -0
- package/tools/svg-to-react/icons/math-keypad-icon-equals-not.svg +50 -0
- package/tools/svg-to-react/icons/math-keypad-icon-equals.svg +48 -0
- package/tools/svg-to-react/icons/math-keypad-icon-exponent-2.svg +38 -0
- package/tools/svg-to-react/icons/math-keypad-icon-exponent-3.svg +38 -0
- package/tools/svg-to-react/icons/math-keypad-icon-exponent.svg +38 -0
- package/tools/svg-to-react/icons/math-keypad-icon-fraction.svg +42 -0
- package/tools/svg-to-react/icons/math-keypad-icon-greater-than.svg +46 -0
- package/tools/svg-to-react/icons/math-keypad-icon-jump-out-base.svg +44 -0
- package/tools/svg-to-react/icons/math-keypad-icon-jump-out-denominator.svg +48 -0
- package/tools/svg-to-react/icons/math-keypad-icon-jump-out-exponent.svg +44 -0
- package/tools/svg-to-react/icons/math-keypad-icon-jump-out-parentheses.svg +44 -0
- package/tools/svg-to-react/icons/math-keypad-icon-less-than.svg +46 -0
- package/tools/svg-to-react/icons/math-keypad-icon-log-10.svg +36 -0
- package/tools/svg-to-react/icons/math-keypad-icon-log-e.svg +36 -0
- package/tools/svg-to-react/icons/math-keypad-icon-log.svg +38 -0
- package/tools/svg-to-react/icons/math-keypad-icon-multiplication-cross.svg +40 -0
- package/tools/svg-to-react/icons/math-keypad-icon-multiplication-dot.svg +38 -0
- package/tools/svg-to-react/icons/math-keypad-icon-percent.svg +42 -0
- package/tools/svg-to-react/icons/math-keypad-icon-radical-2.svg +36 -0
- package/tools/svg-to-react/icons/math-keypad-icon-radical-3.svg +38 -0
- package/tools/svg-to-react/icons/math-keypad-icon-radical.svg +38 -0
- package/tools/svg-to-react/icons/math-keypad-icon-radix-character.svg +32 -0
- package/tools/svg-to-react/icons/math-keypad-icon-sin.svg +38 -0
- package/tools/svg-to-react/icons/math-keypad-icon-subtraction.svg +32 -0
- package/tools/svg-to-react/icons/math-keypad-icon-tan.svg +38 -0
- package/tools/svg-to-react/symbol_map.py +41 -0
- package/LICENSE.txt +0 -21
- package/build/math-input.js +0 -1
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A system for tracking gesture velocity in a single dimension.
|
|
3
|
+
*
|
|
4
|
+
* Velocity is computed by smoothing linearly over the gestures that have
|
|
5
|
+
* occurred in the last 100 milliseconds.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import now from "performance-now";
|
|
9
|
+
|
|
10
|
+
class VelocityTracker {
|
|
11
|
+
constructor(options) {
|
|
12
|
+
this.options = {
|
|
13
|
+
velocityTimeout: 100,
|
|
14
|
+
...options,
|
|
15
|
+
};
|
|
16
|
+
this._events = [];
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Pushes an event with the given displacement onto the event buffer,
|
|
21
|
+
* associating it with a timestamp. Note that, as this method computes the
|
|
22
|
+
* timestamp for the event at calltime, it should be called immediately
|
|
23
|
+
* after the event occurs.
|
|
24
|
+
*
|
|
25
|
+
* @param {number} x - the cumulative displacement of the event
|
|
26
|
+
*/
|
|
27
|
+
push(x) {
|
|
28
|
+
this._events.push({
|
|
29
|
+
x,
|
|
30
|
+
t: now(),
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Compute the velocity with respect to the events that have been tracked
|
|
36
|
+
* by the system. Velocity is computed by smoothing linearly over recent
|
|
37
|
+
* displacement values.
|
|
38
|
+
*
|
|
39
|
+
* Note that, for performance reasons, a call to `getVelocity` will clear
|
|
40
|
+
* out the event buffer. As such, repeated calls will not return the same
|
|
41
|
+
* value (in particular, a second call in quick succession will return 0).
|
|
42
|
+
*
|
|
43
|
+
* @returns {number} the velocity associated with the tracker
|
|
44
|
+
*/
|
|
45
|
+
getVelocity() {
|
|
46
|
+
const events = this._getEvents();
|
|
47
|
+
|
|
48
|
+
if (events.length < 2) {
|
|
49
|
+
return 0;
|
|
50
|
+
} else {
|
|
51
|
+
const current = events[events.length - 1];
|
|
52
|
+
const first = events[0];
|
|
53
|
+
const dt = current.t - first.t;
|
|
54
|
+
return (current.x - first.x) / dt;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Filter the tracked events to exclude any events that occurred too far in
|
|
60
|
+
* the past, and reset the event buffer.
|
|
61
|
+
*
|
|
62
|
+
* @returns {number[]} an array of displacements corresponding to events
|
|
63
|
+
* that occurred in the past `velocityTimeout`
|
|
64
|
+
* milliseconds
|
|
65
|
+
*/
|
|
66
|
+
_getEvents() {
|
|
67
|
+
const threshold = now() - this.options.velocityTimeout;
|
|
68
|
+
const recentEvents = this._events.filter((event) => {
|
|
69
|
+
return event.t > threshold;
|
|
70
|
+
});
|
|
71
|
+
this._events = [];
|
|
72
|
+
return recentEvents;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export default VelocityTracker;
|
package/src/consts.js
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
/**
|
|
3
|
+
* Constants that are shared between multiple files.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export const KeypadTypes = {
|
|
7
|
+
FRACTION: "FRACTION",
|
|
8
|
+
EXPRESSION: "EXPRESSION",
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export const KeyTypes = {
|
|
12
|
+
EMPTY: "EMPTY",
|
|
13
|
+
// For numerals, variables, and any other characters that themselves
|
|
14
|
+
// compose 'values'.
|
|
15
|
+
VALUE: "VALUE",
|
|
16
|
+
// For buttons that insert or adjust math in an input.
|
|
17
|
+
OPERATOR: "OPERATOR",
|
|
18
|
+
// For buttons that move the cursor in an input (including via
|
|
19
|
+
// deletion).
|
|
20
|
+
INPUT_NAVIGATION: "INPUT_NAVIGATION",
|
|
21
|
+
// For buttons that modify the broader keypad state (e.g., by changing
|
|
22
|
+
// the visible pane).
|
|
23
|
+
KEYPAD_NAVIGATION: "KEYPAD_NAVIGATION",
|
|
24
|
+
// For buttons that house multiple buttons and have no action
|
|
25
|
+
// themselves.
|
|
26
|
+
MANY: "MANY",
|
|
27
|
+
// For the echo animation that appears on press.
|
|
28
|
+
ECHO: "ECHO",
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export const DeviceOrientations = {
|
|
32
|
+
LANDSCAPE: "LANDSCAPE",
|
|
33
|
+
PORTRAIT: "PORTRAIT",
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const DeviceTypes = {
|
|
37
|
+
PHONE: "PHONE",
|
|
38
|
+
TABLET: "TABLET",
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const LayoutModes = {
|
|
42
|
+
FULLSCREEN: "FULLSCREEN",
|
|
43
|
+
COMPACT: "COMPACT",
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export const BorderDirections = {
|
|
47
|
+
LEFT: ("LEFT": "LEFT"),
|
|
48
|
+
BOTTOM: ("BOTTOM": "BOTTOM"),
|
|
49
|
+
};
|
|
50
|
+
export const BorderStyles: {|
|
|
51
|
+
[style: string]: $ReadOnlyArray<$Values<typeof BorderDirections>>,
|
|
52
|
+
|} = {
|
|
53
|
+
LEFT: ["LEFT"],
|
|
54
|
+
BOTTOM: ["BOTTOM"],
|
|
55
|
+
ALL: ["LEFT", "BOTTOM"],
|
|
56
|
+
NONE: [],
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export const IconTypes = {
|
|
60
|
+
MATH: "MATH",
|
|
61
|
+
SVG: "SVG",
|
|
62
|
+
TEXT: "TEXT",
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
export const DecimalSeparators = {
|
|
66
|
+
COMMA: "COMMA",
|
|
67
|
+
PERIOD: "PERIOD",
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export const EchoAnimationTypes = {
|
|
71
|
+
SLIDE_AND_FADE: "SLIDE_AND_FADE",
|
|
72
|
+
FADE_ONLY: "FADE_ONLY",
|
|
73
|
+
LONG_FADE_ONLY: "LONG_FADE_ONLY",
|
|
74
|
+
};
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
/**
|
|
3
|
+
* This file contains configuration settings for the buttons in the keypad.
|
|
4
|
+
*/
|
|
5
|
+
import * as i18n from "@khanacademy/wonder-blocks-i18n";
|
|
6
|
+
|
|
7
|
+
import {DecimalSeparators, IconTypes, KeyTypes} from "../consts.js";
|
|
8
|
+
import {decimalSeparator} from "../utils.js";
|
|
9
|
+
|
|
10
|
+
import Keys from "./keys.js";
|
|
11
|
+
|
|
12
|
+
export type KeyConfig = {
|
|
13
|
+
id: string,
|
|
14
|
+
type: string,
|
|
15
|
+
ariaLabel: string,
|
|
16
|
+
};
|
|
17
|
+
const KeyConfigs: Object = {
|
|
18
|
+
// Basic math keys.
|
|
19
|
+
[Keys.PLUS]: {
|
|
20
|
+
type: KeyTypes.OPERATOR,
|
|
21
|
+
// I18N: A label for a plus sign.
|
|
22
|
+
ariaLabel: i18n._("Plus"),
|
|
23
|
+
},
|
|
24
|
+
[Keys.MINUS]: {
|
|
25
|
+
type: KeyTypes.OPERATOR,
|
|
26
|
+
// I18N: A label for a minus sign.
|
|
27
|
+
ariaLabel: i18n._("Minus"),
|
|
28
|
+
},
|
|
29
|
+
[Keys.NEGATIVE]: {
|
|
30
|
+
type: KeyTypes.VALUE,
|
|
31
|
+
// I18N: A label for a minus sign.
|
|
32
|
+
ariaLabel: i18n._("Negative"),
|
|
33
|
+
},
|
|
34
|
+
[Keys.TIMES]: {
|
|
35
|
+
type: KeyTypes.OPERATOR,
|
|
36
|
+
// I18N: A label for a multiplication sign (represented with an 'x').
|
|
37
|
+
ariaLabel: i18n._("Multiply"),
|
|
38
|
+
},
|
|
39
|
+
[Keys.DIVIDE]: {
|
|
40
|
+
type: KeyTypes.OPERATOR,
|
|
41
|
+
// I18N: A label for a division sign.
|
|
42
|
+
ariaLabel: i18n._("Divide"),
|
|
43
|
+
},
|
|
44
|
+
[Keys.DECIMAL]: {
|
|
45
|
+
type: KeyTypes.VALUE,
|
|
46
|
+
// I18N: A label for a decimal symbol.
|
|
47
|
+
ariaLabel: i18n._("Decimal"),
|
|
48
|
+
icon:
|
|
49
|
+
decimalSeparator === DecimalSeparators.COMMA
|
|
50
|
+
? {
|
|
51
|
+
// TODO(charlie): Get an SVG icon for the comma, or verify with
|
|
52
|
+
// design that the text-rendered version is acceptable.
|
|
53
|
+
type: IconTypes.TEXT,
|
|
54
|
+
data: ",",
|
|
55
|
+
}
|
|
56
|
+
: {
|
|
57
|
+
type: IconTypes.SVG,
|
|
58
|
+
data: Keys.PERIOD,
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
[Keys.PERCENT]: {
|
|
62
|
+
type: KeyTypes.OPERATOR,
|
|
63
|
+
// I18N: A label for a percent sign.
|
|
64
|
+
ariaLabel: i18n._("Percent"),
|
|
65
|
+
},
|
|
66
|
+
[Keys.CDOT]: {
|
|
67
|
+
type: KeyTypes.OPERATOR,
|
|
68
|
+
// I18N: A label for a multiplication sign (represented as a dot).
|
|
69
|
+
ariaLabel: i18n._("Multiply"),
|
|
70
|
+
},
|
|
71
|
+
[Keys.EQUAL]: {
|
|
72
|
+
type: KeyTypes.OPERATOR,
|
|
73
|
+
ariaLabel: i18n._("Equals sign"),
|
|
74
|
+
},
|
|
75
|
+
[Keys.NEQ]: {
|
|
76
|
+
type: KeyTypes.OPERATOR,
|
|
77
|
+
ariaLabel: i18n._("Not-equals sign"),
|
|
78
|
+
},
|
|
79
|
+
[Keys.GT]: {
|
|
80
|
+
type: KeyTypes.OPERATOR,
|
|
81
|
+
// I18N: A label for a 'greater than' sign (represented as '>').
|
|
82
|
+
ariaLabel: i18n._("Greater than sign"),
|
|
83
|
+
},
|
|
84
|
+
[Keys.LT]: {
|
|
85
|
+
type: KeyTypes.OPERATOR,
|
|
86
|
+
// I18N: A label for a 'less than' sign (represented as '<').
|
|
87
|
+
ariaLabel: i18n._("Less than sign"),
|
|
88
|
+
},
|
|
89
|
+
[Keys.GEQ]: {
|
|
90
|
+
type: KeyTypes.OPERATOR,
|
|
91
|
+
ariaLabel: i18n._("Greater than or equal to sign"),
|
|
92
|
+
},
|
|
93
|
+
[Keys.LEQ]: {
|
|
94
|
+
type: KeyTypes.OPERATOR,
|
|
95
|
+
ariaLabel: i18n._("Less than or equal to sign"),
|
|
96
|
+
},
|
|
97
|
+
// mobile native
|
|
98
|
+
[Keys.FRAC_INCLUSIVE]: {
|
|
99
|
+
type: KeyTypes.OPERATOR,
|
|
100
|
+
// I18N: A label for a button that creates a new fraction and puts the
|
|
101
|
+
// current expression in the numerator of that fraction.
|
|
102
|
+
ariaLabel: i18n._("Fraction, with current expression in numerator"),
|
|
103
|
+
},
|
|
104
|
+
// mobile native
|
|
105
|
+
[Keys.FRAC_EXCLUSIVE]: {
|
|
106
|
+
type: KeyTypes.OPERATOR,
|
|
107
|
+
// I18N: A label for a button that creates a new fraction next to the
|
|
108
|
+
// cursor.
|
|
109
|
+
ariaLabel: i18n._("Fraction, excluding the current expression"),
|
|
110
|
+
},
|
|
111
|
+
// mobile web
|
|
112
|
+
[Keys.FRAC]: {
|
|
113
|
+
type: KeyTypes.OPERATOR,
|
|
114
|
+
// I18N: A label for a button that creates a new fraction next to the
|
|
115
|
+
// cursor.
|
|
116
|
+
ariaLabel: i18n._("Fraction, excluding the current expression"),
|
|
117
|
+
},
|
|
118
|
+
[Keys.EXP]: {
|
|
119
|
+
type: KeyTypes.OPERATOR,
|
|
120
|
+
// I18N: A label for a button that will allow the user to input a custom
|
|
121
|
+
// exponent.
|
|
122
|
+
ariaLabel: i18n._("Custom exponent"),
|
|
123
|
+
},
|
|
124
|
+
[Keys.EXP_2]: {
|
|
125
|
+
type: KeyTypes.OPERATOR,
|
|
126
|
+
// I18N: A label for a button that will square (take to the second
|
|
127
|
+
// power) some math.
|
|
128
|
+
ariaLabel: i18n._("Square"),
|
|
129
|
+
},
|
|
130
|
+
[Keys.EXP_3]: {
|
|
131
|
+
type: KeyTypes.OPERATOR,
|
|
132
|
+
// I18N: A label for a button that will cube (take to the third power)
|
|
133
|
+
// some math.
|
|
134
|
+
ariaLabel: i18n._("Cube"),
|
|
135
|
+
},
|
|
136
|
+
[Keys.SQRT]: {
|
|
137
|
+
type: KeyTypes.OPERATOR,
|
|
138
|
+
ariaLabel: i18n._("Square root"),
|
|
139
|
+
},
|
|
140
|
+
[Keys.CUBE_ROOT]: {
|
|
141
|
+
type: KeyTypes.OPERATOR,
|
|
142
|
+
ariaLabel: i18n._("Cube root"),
|
|
143
|
+
},
|
|
144
|
+
[Keys.RADICAL]: {
|
|
145
|
+
type: KeyTypes.OPERATOR,
|
|
146
|
+
ariaLabel: i18n._("Radical with custom root"),
|
|
147
|
+
},
|
|
148
|
+
[Keys.LEFT_PAREN]: {
|
|
149
|
+
type: KeyTypes.OPERATOR,
|
|
150
|
+
ariaLabel: i18n._("Left parenthesis"),
|
|
151
|
+
},
|
|
152
|
+
[Keys.RIGHT_PAREN]: {
|
|
153
|
+
type: KeyTypes.OPERATOR,
|
|
154
|
+
ariaLabel: i18n._("Right parenthesis"),
|
|
155
|
+
},
|
|
156
|
+
[Keys.LN]: {
|
|
157
|
+
type: KeyTypes.OPERATOR,
|
|
158
|
+
ariaLabel: i18n._("Natural logarithm"),
|
|
159
|
+
},
|
|
160
|
+
[Keys.LOG]: {
|
|
161
|
+
type: KeyTypes.OPERATOR,
|
|
162
|
+
ariaLabel: i18n._("Logarithm with base 10"),
|
|
163
|
+
},
|
|
164
|
+
[Keys.LOG_N]: {
|
|
165
|
+
type: KeyTypes.OPERATOR,
|
|
166
|
+
ariaLabel: i18n._("Logarithm with custom base"),
|
|
167
|
+
},
|
|
168
|
+
[Keys.SIN]: {
|
|
169
|
+
type: KeyTypes.OPERATOR,
|
|
170
|
+
ariaLabel: i18n._("Sine"),
|
|
171
|
+
},
|
|
172
|
+
[Keys.COS]: {
|
|
173
|
+
type: KeyTypes.OPERATOR,
|
|
174
|
+
ariaLabel: i18n._("Cosine"),
|
|
175
|
+
},
|
|
176
|
+
[Keys.TAN]: {
|
|
177
|
+
type: KeyTypes.OPERATOR,
|
|
178
|
+
ariaLabel: i18n._("Tangent"),
|
|
179
|
+
},
|
|
180
|
+
[Keys.PI]: {
|
|
181
|
+
type: KeyTypes.VALUE,
|
|
182
|
+
ariaLabel: i18n._("Pi"),
|
|
183
|
+
icon: {
|
|
184
|
+
type: IconTypes.MATH,
|
|
185
|
+
data: "\\pi",
|
|
186
|
+
},
|
|
187
|
+
},
|
|
188
|
+
[Keys.THETA]: {
|
|
189
|
+
type: KeyTypes.VALUE,
|
|
190
|
+
ariaLabel: i18n._("Theta"),
|
|
191
|
+
icon: {
|
|
192
|
+
type: IconTypes.MATH,
|
|
193
|
+
data: "\\theta",
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
[Keys.NOOP]: {
|
|
197
|
+
type: KeyTypes.EMPTY,
|
|
198
|
+
},
|
|
199
|
+
|
|
200
|
+
// Input navigation keys.
|
|
201
|
+
[Keys.UP]: {
|
|
202
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
203
|
+
ariaLabel: i18n._("Up arrow"),
|
|
204
|
+
},
|
|
205
|
+
[Keys.RIGHT]: {
|
|
206
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
207
|
+
ariaLabel: i18n._("Right arrow"),
|
|
208
|
+
},
|
|
209
|
+
[Keys.DOWN]: {
|
|
210
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
211
|
+
ariaLabel: i18n._("Down arrow"),
|
|
212
|
+
},
|
|
213
|
+
[Keys.LEFT]: {
|
|
214
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
215
|
+
ariaLabel: i18n._("Left arrow"),
|
|
216
|
+
},
|
|
217
|
+
[Keys.JUMP_OUT_PARENTHESES]: {
|
|
218
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
219
|
+
ariaLabel: i18n._("Navigate right out of a set of parentheses"),
|
|
220
|
+
},
|
|
221
|
+
[Keys.JUMP_OUT_EXPONENT]: {
|
|
222
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
223
|
+
ariaLabel: i18n._("Navigate right out of an exponent"),
|
|
224
|
+
},
|
|
225
|
+
[Keys.JUMP_OUT_BASE]: {
|
|
226
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
227
|
+
ariaLabel: i18n._("Navigate right out of a base"),
|
|
228
|
+
},
|
|
229
|
+
[Keys.JUMP_INTO_NUMERATOR]: {
|
|
230
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
231
|
+
ariaLabel: i18n._("Navigate right into the numerator of a fraction"),
|
|
232
|
+
},
|
|
233
|
+
[Keys.JUMP_OUT_NUMERATOR]: {
|
|
234
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
235
|
+
ariaLabel: i18n._(
|
|
236
|
+
"Navigate right out of the numerator and into the denominator",
|
|
237
|
+
),
|
|
238
|
+
},
|
|
239
|
+
[Keys.JUMP_OUT_DENOMINATOR]: {
|
|
240
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
241
|
+
ariaLabel: i18n._(
|
|
242
|
+
"Navigate right out of the denominator of a fraction",
|
|
243
|
+
),
|
|
244
|
+
},
|
|
245
|
+
[Keys.BACKSPACE]: {
|
|
246
|
+
type: KeyTypes.INPUT_NAVIGATION,
|
|
247
|
+
// I18N: A label for a button that will delete some input.
|
|
248
|
+
ariaLabel: i18n._("Delete"),
|
|
249
|
+
},
|
|
250
|
+
|
|
251
|
+
// Keypad navigation keys.
|
|
252
|
+
[Keys.DISMISS]: {
|
|
253
|
+
type: KeyTypes.KEYPAD_NAVIGATION,
|
|
254
|
+
// I18N: A label for a button that will dismiss/hide a keypad.
|
|
255
|
+
ariaLabel: i18n._("Dismiss"),
|
|
256
|
+
},
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
// Add in any multi-function buttons. By default, these keys will mix in any
|
|
260
|
+
// configuration settings from their default child key (i.e., the first key in
|
|
261
|
+
// the `childKeyIds` array).
|
|
262
|
+
// TODO(charlie): Make the multi-function button's long-press interaction
|
|
263
|
+
// accessible.
|
|
264
|
+
// NOTE(kevinb): This is only used in the mobile native app.
|
|
265
|
+
KeyConfigs[Keys.FRAC_MULTI] = {
|
|
266
|
+
childKeyIds: [Keys.FRAC_INCLUSIVE, Keys.FRAC_EXCLUSIVE],
|
|
267
|
+
};
|
|
268
|
+
|
|
269
|
+
// TODO(charlie): Use the numeral color for the 'Many' key.
|
|
270
|
+
KeyConfigs[Keys.MANY] = {
|
|
271
|
+
type: KeyTypes.MANY,
|
|
272
|
+
// childKeyIds will be configured by the client.
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
// Add in every numeral.
|
|
276
|
+
const NUMBERS = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
|
|
277
|
+
for (const num of NUMBERS) {
|
|
278
|
+
// TODO(charlie): Consider removing the SVG icons that we have for the
|
|
279
|
+
// numeral keys. They can be rendered just as easily with text (though that
|
|
280
|
+
// would mean that we'd be using text beyond the variable key).
|
|
281
|
+
const textRepresentation = `${num}`;
|
|
282
|
+
KeyConfigs[`NUM_${num}`] = {
|
|
283
|
+
type: KeyTypes.VALUE,
|
|
284
|
+
ariaLabel: textRepresentation,
|
|
285
|
+
icon: {
|
|
286
|
+
type: IconTypes.TEXT,
|
|
287
|
+
data: textRepresentation,
|
|
288
|
+
},
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
// Add in every variable.
|
|
293
|
+
const LETTERS = [
|
|
294
|
+
"A",
|
|
295
|
+
"B",
|
|
296
|
+
"C",
|
|
297
|
+
"D",
|
|
298
|
+
"E",
|
|
299
|
+
"F",
|
|
300
|
+
"G",
|
|
301
|
+
"H",
|
|
302
|
+
"I",
|
|
303
|
+
"J",
|
|
304
|
+
"K",
|
|
305
|
+
"L",
|
|
306
|
+
"M",
|
|
307
|
+
"N",
|
|
308
|
+
"O",
|
|
309
|
+
"P",
|
|
310
|
+
"Q",
|
|
311
|
+
"R",
|
|
312
|
+
"S",
|
|
313
|
+
"T",
|
|
314
|
+
"U",
|
|
315
|
+
"V",
|
|
316
|
+
"W",
|
|
317
|
+
"X",
|
|
318
|
+
"Y",
|
|
319
|
+
"Z",
|
|
320
|
+
];
|
|
321
|
+
for (const letter of LETTERS) {
|
|
322
|
+
const lowerCaseVariable = letter.toLowerCase();
|
|
323
|
+
const upperCaseVariable = letter.toUpperCase();
|
|
324
|
+
|
|
325
|
+
for (const textRepresentation of [lowerCaseVariable, upperCaseVariable]) {
|
|
326
|
+
KeyConfigs[textRepresentation] = {
|
|
327
|
+
type: KeyTypes.VALUE,
|
|
328
|
+
ariaLabel: textRepresentation,
|
|
329
|
+
icon: {
|
|
330
|
+
type: IconTypes.MATH,
|
|
331
|
+
data: textRepresentation,
|
|
332
|
+
},
|
|
333
|
+
};
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
for (const key of Object.keys(KeyConfigs)) {
|
|
338
|
+
KeyConfigs[key] = {
|
|
339
|
+
id: key,
|
|
340
|
+
// Default to an SVG icon indexed by the key name.
|
|
341
|
+
icon: {
|
|
342
|
+
type: IconTypes.SVG,
|
|
343
|
+
data: key,
|
|
344
|
+
},
|
|
345
|
+
...KeyConfigs[key],
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export default KeyConfigs;
|
package/src/data/keys.js
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
/**
|
|
3
|
+
* This file contains constants for keypad buttons that aren't single
|
|
4
|
+
* alphanumeric characters.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
// TODO(charlie): There's duplication between this file and key-configs.js.
|
|
8
|
+
// We should clean it up by removing this file and requiring clients to use the
|
|
9
|
+
// `id` field on the key configurations.
|
|
10
|
+
const Keys = {
|
|
11
|
+
PLUS: "PLUS",
|
|
12
|
+
MINUS: "MINUS",
|
|
13
|
+
NEGATIVE: "NEGATIVE",
|
|
14
|
+
TIMES: "TIMES",
|
|
15
|
+
DIVIDE: "DIVIDE",
|
|
16
|
+
DECIMAL: "DECIMAL",
|
|
17
|
+
PERIOD: "PERIOD",
|
|
18
|
+
PERCENT: "PERCENT",
|
|
19
|
+
CDOT: "CDOT",
|
|
20
|
+
EQUAL: "EQUAL",
|
|
21
|
+
NEQ: "NEQ",
|
|
22
|
+
GT: "GT",
|
|
23
|
+
LT: "LT",
|
|
24
|
+
GEQ: "GEQ",
|
|
25
|
+
LEQ: "LEQ",
|
|
26
|
+
FRAC_INCLUSIVE: "FRAC_INCLUSIVE", // mobile native only
|
|
27
|
+
FRAC_EXCLUSIVE: "FRAC_EXCLUSIVE", // mobile native only
|
|
28
|
+
FRAC: "FRAC",
|
|
29
|
+
EXP: "EXP",
|
|
30
|
+
EXP_2: "EXP_2",
|
|
31
|
+
EXP_3: "EXP_3",
|
|
32
|
+
SQRT: "SQRT",
|
|
33
|
+
CUBE_ROOT: "CUBE_ROOT",
|
|
34
|
+
RADICAL: "RADICAL",
|
|
35
|
+
LEFT_PAREN: "LEFT_PAREN",
|
|
36
|
+
RIGHT_PAREN: "RIGHT_PAREN",
|
|
37
|
+
LN: "LN",
|
|
38
|
+
LOG: "LOG",
|
|
39
|
+
LOG_N: "LOG_N",
|
|
40
|
+
SIN: "SIN",
|
|
41
|
+
COS: "COS",
|
|
42
|
+
TAN: "TAN",
|
|
43
|
+
|
|
44
|
+
// TODO(charlie): Add in additional Greek letters.
|
|
45
|
+
PI: "PI",
|
|
46
|
+
THETA: "THETA",
|
|
47
|
+
|
|
48
|
+
UP: "UP",
|
|
49
|
+
RIGHT: "RIGHT",
|
|
50
|
+
DOWN: "DOWN",
|
|
51
|
+
LEFT: "LEFT",
|
|
52
|
+
BACKSPACE: "BACKSPACE",
|
|
53
|
+
DISMISS: "DISMISS",
|
|
54
|
+
|
|
55
|
+
JUMP_OUT_PARENTHESES: "JUMP_OUT_PARENTHESES",
|
|
56
|
+
JUMP_OUT_EXPONENT: "JUMP_OUT_EXPONENT",
|
|
57
|
+
JUMP_OUT_BASE: "JUMP_OUT_BASE",
|
|
58
|
+
JUMP_INTO_NUMERATOR: "JUMP_INTO_NUMERATOR",
|
|
59
|
+
JUMP_OUT_NUMERATOR: "JUMP_OUT_NUMERATOR",
|
|
60
|
+
JUMP_OUT_DENOMINATOR: "JUMP_OUT_DENOMINATOR",
|
|
61
|
+
|
|
62
|
+
NOOP: "NOOP",
|
|
63
|
+
|
|
64
|
+
// Multi-functional keys.
|
|
65
|
+
FRAC_MULTI: "FRAC_MULTI", // mobile native only
|
|
66
|
+
|
|
67
|
+
// A custom key that captures an arbitrary number of symbols but has no
|
|
68
|
+
// 'default' symbol or action.
|
|
69
|
+
MANY: "MANY",
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
export default Keys;
|
package/src/demo.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
/**
|
|
3
|
+
* This file exports components View and Text which wrap <div> and <span>.
|
|
4
|
+
* We do this so that someday in the future we can use these components with
|
|
5
|
+
* React Native.
|
|
6
|
+
*
|
|
7
|
+
* Inspired by https://github.com/necolas/react-native-web. We use aphrodite
|
|
8
|
+
* StyleSheets instead.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export {default as Text} from "./text.js";
|
|
12
|
+
export {default as View} from "./view.js";
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// @flow
|
|
2
|
+
|
|
3
|
+
import {StyleSheet, css} from "aphrodite";
|
|
4
|
+
import * as React from "react";
|
|
5
|
+
|
|
6
|
+
import type {CSSProperties} from "aphrodite";
|
|
7
|
+
|
|
8
|
+
type Props = {|
|
|
9
|
+
children: React.Node,
|
|
10
|
+
// The `dynamicStyle` prop is provided for animating dynamic
|
|
11
|
+
// properties, as creating Aphrodite StyleSheets in animation loops is
|
|
12
|
+
// expensive. `dynamicStyle` should be a raw style object, rather than
|
|
13
|
+
// a StyleSheet.
|
|
14
|
+
dynamicStyle?: CSSProperties,
|
|
15
|
+
numberOfLines?: number,
|
|
16
|
+
style?: CSSProperties,
|
|
17
|
+
|};
|
|
18
|
+
|
|
19
|
+
class Text extends React.Component<Props> {
|
|
20
|
+
render(): React.Element<"span"> {
|
|
21
|
+
const {numberOfLines, style} = this.props;
|
|
22
|
+
|
|
23
|
+
const className = css(
|
|
24
|
+
styles.initial,
|
|
25
|
+
...(Array.isArray(style) ? style : [style]),
|
|
26
|
+
numberOfLines === 1 && styles.singleLineStyle,
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<span className={className} style={this.props.dynamicStyle}>
|
|
31
|
+
{this.props.children}
|
|
32
|
+
</span>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// https://github.com/necolas/react-native-web/blob/master/src/components/Text/index.js
|
|
38
|
+
const styles = StyleSheet.create({
|
|
39
|
+
initial: {
|
|
40
|
+
color: "inherit",
|
|
41
|
+
display: "inline",
|
|
42
|
+
font: "inherit",
|
|
43
|
+
margin: 0,
|
|
44
|
+
padding: 0,
|
|
45
|
+
textDecorationLine: "none",
|
|
46
|
+
wordWrap: "break-word",
|
|
47
|
+
},
|
|
48
|
+
singleLineStyle: {
|
|
49
|
+
maxWidth: "100%",
|
|
50
|
+
overflow: "hidden",
|
|
51
|
+
textOverflow: "ellipsis",
|
|
52
|
+
whiteSpace: "nowrap",
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
export default Text;
|