@khanacademy/math-input 16.1.1 → 16.2.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 +19 -0
- package/dist/components/input/math-input.d.ts +4 -6
- package/dist/es/index.js +78 -45
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +73 -38
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/components/__tests__/integration.test.tsx +17 -1
- package/src/components/input/math-input.tsx +84 -51
- package/tsconfig-build.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# @khanacademy/math-input
|
|
2
2
|
|
|
3
|
+
## 16.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#853](https://github.com/Khan/perseus/pull/853) [`cbcc0e68`](https://github.com/Khan/perseus/commit/cbcc0e689b6d4640361c14ae112c476fb061d5f4) Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! - Allowing click events on math-input in order to support third party browsers on ChromeOS.
|
|
8
|
+
|
|
9
|
+
* [#859](https://github.com/Khan/perseus/pull/859) [`e7bec961`](https://github.com/Khan/perseus/commit/e7bec961bc5136bcaeb4ebb4b6744b0809f372ec) Thanks [@SonicScrewdriver](https://github.com/SonicScrewdriver)! - Ensure that we're always getting the current keypadBounds
|
|
10
|
+
|
|
11
|
+
## 16.1.2
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- [#856](https://github.com/Khan/perseus/pull/856) [`6c323dc3`](https://github.com/Khan/perseus/commit/6c323dc37e7cc972fe5a1ab7cbf90a23bf4dd3a0) Thanks [@nedredmond](https://github.com/nedredmond)! - Upgrade WB
|
|
16
|
+
|
|
17
|
+
* [#804](https://github.com/Khan/perseus/pull/804) [`2c295e2c`](https://github.com/Khan/perseus/commit/2c295e2c26ff2bf15e1e8e82bcc34e04e4b9bab0) Thanks [@nixterrimus](https://github.com/nixterrimus)! - Upgrade WonderBlocks Popover
|
|
18
|
+
|
|
19
|
+
* Updated dependencies [[`1f4e17ba`](https://github.com/Khan/perseus/commit/1f4e17ba77e1491523813655af18a70285a25989), [`8857950b`](https://github.com/Khan/perseus/commit/8857950bdeeb6e13bc3766b1c6545289b21cbe2a)]:
|
|
20
|
+
- @khanacademy/perseus-core@1.4.1
|
|
21
|
+
|
|
3
22
|
## 16.1.1
|
|
4
23
|
|
|
5
24
|
### Patch Changes
|
|
@@ -28,6 +28,7 @@ declare class MathInput extends React.Component<Props, State> {
|
|
|
28
28
|
mathField: any;
|
|
29
29
|
recordTouchStartOutside: (arg1: any) => void;
|
|
30
30
|
blurOnTouchEndOutside: (arg1: any) => void;
|
|
31
|
+
blurOnClickOutside: (arg1: any) => void;
|
|
31
32
|
dragListener: any;
|
|
32
33
|
inputRef: HTMLDivElement | null | undefined;
|
|
33
34
|
_isMounted: boolean | null | undefined;
|
|
@@ -35,18 +36,14 @@ declare class MathInput extends React.Component<Props, State> {
|
|
|
35
36
|
_container: HTMLDivElement;
|
|
36
37
|
_root: any;
|
|
37
38
|
_containerBounds: ClientRect;
|
|
38
|
-
_keypadBounds: ClientRect | null | undefined;
|
|
39
39
|
static defaultProps: DefaultProps;
|
|
40
40
|
state: State;
|
|
41
41
|
componentDidMount(): void;
|
|
42
|
-
UNSAFE_componentWillReceiveProps(props: Props): void;
|
|
43
42
|
componentDidUpdate(prevProps: Props, prevState: State): void;
|
|
44
43
|
componentWillUnmount(): void;
|
|
45
|
-
_clearKeypadBoundsCache: () => void;
|
|
46
|
-
_cacheKeypadBounds: (arg1: any) => void;
|
|
47
44
|
_updateInputPadding: () => void;
|
|
48
|
-
/**
|
|
49
|
-
_getKeypadBounds
|
|
45
|
+
/** Returns the current bounds of the keypadElement */
|
|
46
|
+
_getKeypadBounds(): DOMRect | null;
|
|
50
47
|
_updateCursorHandle: (arg1?: boolean) => void;
|
|
51
48
|
_hideCursorHandle: () => void;
|
|
52
49
|
_handleScroll: () => void;
|
|
@@ -86,6 +83,7 @@ declare class MathInput extends React.Component<Props, State> {
|
|
|
86
83
|
*/
|
|
87
84
|
_insertCursorAtClosestNode: (arg1: number, arg2: number) => void;
|
|
88
85
|
handleTouchStart: (arg1: React.TouchEvent<HTMLDivElement>) => void;
|
|
86
|
+
handleClick: (e: React.MouseEvent<HTMLDivElement>) => void;
|
|
89
87
|
handleTouchMove: (arg1: React.TouchEvent<HTMLDivElement>) => void;
|
|
90
88
|
handleTouchEnd: (arg1: React.TouchEvent<HTMLDivElement>) => void;
|
|
91
89
|
/**
|
package/dist/es/index.js
CHANGED
|
@@ -17,7 +17,7 @@ import PropTypes from 'prop-types';
|
|
|
17
17
|
|
|
18
18
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
19
19
|
const libName = "@khanacademy/math-input";
|
|
20
|
-
const libVersion = "16.
|
|
20
|
+
const libVersion = "16.2.0";
|
|
21
21
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
22
22
|
|
|
23
23
|
function _extends() {
|
|
@@ -1369,6 +1369,8 @@ class MathInput extends React.Component {
|
|
|
1369
1369
|
this.recordTouchStartOutside = void 0;
|
|
1370
1370
|
// @ts-expect-error - TS2564 - Property 'blurOnTouchEndOutside' has no initializer and is not definitely assigned in the constructor.
|
|
1371
1371
|
this.blurOnTouchEndOutside = void 0;
|
|
1372
|
+
// @ts-expect-error - TS2564 - Property 'blurOnClickOutside' has no initializer and is not definitely assigned in the constructor.
|
|
1373
|
+
this.blurOnClickOutside = void 0;
|
|
1372
1374
|
this.dragListener = void 0;
|
|
1373
1375
|
this.inputRef = void 0;
|
|
1374
1376
|
this._isMounted = void 0;
|
|
@@ -1378,7 +1380,6 @@ class MathInput extends React.Component {
|
|
|
1378
1380
|
this._root = void 0;
|
|
1379
1381
|
// @ts-expect-error - TS2564 - Property '_containerBounds' has no initializer and is not definitely assigned in the constructor.
|
|
1380
1382
|
this._containerBounds = void 0;
|
|
1381
|
-
this._keypadBounds = void 0;
|
|
1382
1383
|
this.state = {
|
|
1383
1384
|
focused: false,
|
|
1384
1385
|
handle: {
|
|
@@ -1388,12 +1389,6 @@ class MathInput extends React.Component {
|
|
|
1388
1389
|
y: 0
|
|
1389
1390
|
}
|
|
1390
1391
|
};
|
|
1391
|
-
this._clearKeypadBoundsCache = () => {
|
|
1392
|
-
this._keypadBounds = null;
|
|
1393
|
-
};
|
|
1394
|
-
this._cacheKeypadBounds = keypadNode => {
|
|
1395
|
-
this._keypadBounds = keypadNode.getBoundingClientRect();
|
|
1396
|
-
};
|
|
1397
1392
|
this._updateInputPadding = () => {
|
|
1398
1393
|
this._container = ReactDOM.findDOMNode(this);
|
|
1399
1394
|
this._root = this._container.querySelector(".mq-root-block");
|
|
@@ -1402,15 +1397,6 @@ class MathInput extends React.Component {
|
|
|
1402
1397
|
this._root.style.padding = `${padding.paddingTop}px ${padding.paddingRight}px` + ` ${padding.paddingBottom}px ${padding.paddingLeft}px`;
|
|
1403
1398
|
this._root.style.fontSize = `${fontSizePt}pt`;
|
|
1404
1399
|
};
|
|
1405
|
-
/** Gets and cache they bounds of the keypadElement */
|
|
1406
|
-
this._getKeypadBounds = () => {
|
|
1407
|
-
if (!this._keypadBounds) {
|
|
1408
|
-
var _this$props$keypadEle;
|
|
1409
|
-
const node = (_this$props$keypadEle = this.props.keypadElement) == null ? void 0 : _this$props$keypadEle.getDOMNode();
|
|
1410
|
-
this._cacheKeypadBounds(node);
|
|
1411
|
-
}
|
|
1412
|
-
return this._keypadBounds;
|
|
1413
|
-
};
|
|
1414
1400
|
this._updateCursorHandle = animateIntoPosition => {
|
|
1415
1401
|
const containerBounds = this._container.getBoundingClientRect();
|
|
1416
1402
|
const cursor = this._container.querySelector(".mq-cursor");
|
|
@@ -1470,10 +1456,10 @@ class MathInput extends React.Component {
|
|
|
1470
1456
|
});
|
|
1471
1457
|
};
|
|
1472
1458
|
this.focus = () => {
|
|
1473
|
-
var _this$props$
|
|
1459
|
+
var _this$props$keypadEle, _this$props;
|
|
1474
1460
|
// Pass this component's handleKey method to the keypad so it can call
|
|
1475
1461
|
// it whenever it needs to trigger a keypress action.
|
|
1476
|
-
(_this$props$
|
|
1462
|
+
(_this$props$keypadEle = this.props.keypadElement) == null || _this$props$keypadEle.setKeyHandler(key => {
|
|
1477
1463
|
const cursor = this.mathField.pressKey(key);
|
|
1478
1464
|
|
|
1479
1465
|
// Trigger an `onChange` if the value in the input changed, and hide
|
|
@@ -1506,14 +1492,14 @@ class MathInput extends React.Component {
|
|
|
1506
1492
|
// Android Browser 4.3.
|
|
1507
1493
|
setTimeout(() => {
|
|
1508
1494
|
if (this._isMounted) {
|
|
1509
|
-
var _this$props$
|
|
1495
|
+
var _this$props$keypadEle2;
|
|
1510
1496
|
// TODO(benkomalo): the keypad is animating at this point,
|
|
1511
1497
|
// so we can't call _cacheKeypadBounds(), even though
|
|
1512
1498
|
// it'd be nice to do so. It should probably be the case
|
|
1513
1499
|
// that the higher level controller tells us when the
|
|
1514
1500
|
// keypad is settled (then scrollIntoView wouldn't have
|
|
1515
1501
|
// to make assumptions about that either).
|
|
1516
|
-
const maybeKeypadNode = (_this$props$
|
|
1502
|
+
const maybeKeypadNode = (_this$props$keypadEle2 = this.props.keypadElement) == null ? void 0 : _this$props$keypadEle2.getDOMNode();
|
|
1517
1503
|
scrollIntoView(this._container, maybeKeypadNode);
|
|
1518
1504
|
}
|
|
1519
1505
|
});
|
|
@@ -1708,6 +1694,31 @@ class MathInput extends React.Component {
|
|
|
1708
1694
|
this.focus();
|
|
1709
1695
|
}
|
|
1710
1696
|
};
|
|
1697
|
+
// We want to allow the user to be able to focus the input via click
|
|
1698
|
+
// when using ChromeOS third-party browsers that use mobile user agents,
|
|
1699
|
+
// but don't actually simulate touch events.
|
|
1700
|
+
this.handleClick = e => {
|
|
1701
|
+
e.stopPropagation();
|
|
1702
|
+
|
|
1703
|
+
// Hide the cursor handle on click
|
|
1704
|
+
this._hideCursorHandle();
|
|
1705
|
+
|
|
1706
|
+
// Cache the container bounds, so as to avoid re-computing. If we don't
|
|
1707
|
+
// have any content, then it's not necessary, since the cursor can't be
|
|
1708
|
+
// moved anyway.
|
|
1709
|
+
if (this.mathField.getContent() !== "") {
|
|
1710
|
+
this._containerBounds = this._container.getBoundingClientRect();
|
|
1711
|
+
|
|
1712
|
+
// Make the cursor visible and set the handle-less cursor's
|
|
1713
|
+
// location.
|
|
1714
|
+
this._insertCursorAtClosestNode(e.clientX, e.clientY);
|
|
1715
|
+
}
|
|
1716
|
+
|
|
1717
|
+
// Trigger a focus event, if we're not already focused.
|
|
1718
|
+
if (!this.state.focused) {
|
|
1719
|
+
this.focus();
|
|
1720
|
+
}
|
|
1721
|
+
};
|
|
1711
1722
|
this.handleTouchMove = e => {
|
|
1712
1723
|
e.stopPropagation();
|
|
1713
1724
|
|
|
@@ -1927,6 +1938,16 @@ class MathInput extends React.Component {
|
|
|
1927
1938
|
this._container = ReactDOM.findDOMNode(this);
|
|
1928
1939
|
this._root = this._container.querySelector(".mq-root-block");
|
|
1929
1940
|
this._root.addEventListener("scroll", this._handleScroll);
|
|
1941
|
+
const isWithinKeypadBounds = (x, y) => {
|
|
1942
|
+
const bounds = this._getKeypadBounds();
|
|
1943
|
+
|
|
1944
|
+
// If there are no bounds, then the keypad is not mounted, so we
|
|
1945
|
+
// assume that the event is not within the keypad bounds.
|
|
1946
|
+
if (!bounds) {
|
|
1947
|
+
return false;
|
|
1948
|
+
}
|
|
1949
|
+
return bounds.left <= x && bounds.right >= x && bounds.top <= y && bounds.bottom >= y || bounds.bottom < y;
|
|
1950
|
+
};
|
|
1930
1951
|
|
|
1931
1952
|
// Record the initial scroll displacement on touch start. This allows
|
|
1932
1953
|
// us to detect whether a touch event was a scroll and only blur the
|
|
@@ -1944,10 +1965,9 @@ class MathInput extends React.Component {
|
|
|
1944
1965
|
if (!this._container.contains(evt.target)) {
|
|
1945
1966
|
let touchDidStartInOrBelowKeypad = false;
|
|
1946
1967
|
if (this.props.keypadElement && this.props.keypadElement.getDOMNode()) {
|
|
1947
|
-
const bounds = this._getKeypadBounds();
|
|
1948
1968
|
for (let i = 0; i < evt.changedTouches.length; i++) {
|
|
1949
1969
|
const [x, y] = [evt.changedTouches[i].clientX, evt.changedTouches[i].clientY];
|
|
1950
|
-
if (
|
|
1970
|
+
if (isWithinKeypadBounds(x, y)) {
|
|
1951
1971
|
touchDidStartInOrBelowKeypad = true;
|
|
1952
1972
|
break;
|
|
1953
1973
|
}
|
|
@@ -1983,25 +2003,31 @@ class MathInput extends React.Component {
|
|
|
1983
2003
|
this.dragListener.detach();
|
|
1984
2004
|
}
|
|
1985
2005
|
};
|
|
2006
|
+
|
|
2007
|
+
// We want to allow the user to blur the input by clicking outside of it
|
|
2008
|
+
// when using ChromeOS third-party browsers that use mobile user agents,
|
|
2009
|
+
// but don't actually simulate touch events.
|
|
2010
|
+
this.blurOnClickOutside = evt => {
|
|
2011
|
+
if (this.state.focused) {
|
|
2012
|
+
if (!this._container.contains(evt.target)) {
|
|
2013
|
+
if (this.props.keypadElement && this.props.keypadElement.getDOMNode()) {
|
|
2014
|
+
const [x, y] = [evt.clientX, evt.clientY];
|
|
2015
|
+
// We only want to blur if the click is above the keypad,
|
|
2016
|
+
// to the left of the keypad, or to the right of the keypad.
|
|
2017
|
+
// The reasoning for not blurring for any clicks below the keypad is
|
|
2018
|
+
// that the keypad may be anchored above the 'Check answer' bottom bar,
|
|
2019
|
+
// in which case we don't want to dismiss the keypad on check.
|
|
2020
|
+
if (!isWithinKeypadBounds(x, y)) {
|
|
2021
|
+
this.blur();
|
|
2022
|
+
}
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
};
|
|
1986
2027
|
window.addEventListener("touchstart", this.recordTouchStartOutside);
|
|
1987
2028
|
window.addEventListener("touchend", this.blurOnTouchEndOutside);
|
|
1988
2029
|
window.addEventListener("touchcancel", this.blurOnTouchEndOutside);
|
|
1989
|
-
|
|
1990
|
-
// HACK(benkomalo): if the window resizes, the keypad bounds can
|
|
1991
|
-
// change. That's a bit peeking into the internals of the keypad
|
|
1992
|
-
// itself, since we know bounds can change only when the viewport
|
|
1993
|
-
// changes, but seems like a rare enough thing to get wrong that it's
|
|
1994
|
-
// not worth wiring up extra things for the technical "purity" of
|
|
1995
|
-
// having the keypad notify of changes to us.
|
|
1996
|
-
window.addEventListener("resize", this._clearKeypadBoundsCache);
|
|
1997
|
-
window.addEventListener("orientationchange", this._clearKeypadBoundsCache);
|
|
1998
|
-
}
|
|
1999
|
-
|
|
2000
|
-
// eslint-disable-next-line react/no-unsafe
|
|
2001
|
-
UNSAFE_componentWillReceiveProps(props) {
|
|
2002
|
-
if (this.props.keypadElement !== props.keypadElement) {
|
|
2003
|
-
this._clearKeypadBoundsCache();
|
|
2004
|
-
}
|
|
2030
|
+
window.addEventListener("click", this.blurOnClickOutside);
|
|
2005
2031
|
}
|
|
2006
2032
|
componentDidUpdate(prevProps, prevState) {
|
|
2007
2033
|
if (this.mathField.getContent() !== this.props.value) {
|
|
@@ -2016,11 +2042,18 @@ class MathInput extends React.Component {
|
|
|
2016
2042
|
window.removeEventListener("touchstart", this.recordTouchStartOutside);
|
|
2017
2043
|
window.removeEventListener("touchend", this.blurOnTouchEndOutside);
|
|
2018
2044
|
window.removeEventListener("touchcancel", this.blurOnTouchEndOutside);
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2045
|
+
window.removeEventListener("click", this.blurOnClickOutside);
|
|
2046
|
+
}
|
|
2047
|
+
/** Returns the current bounds of the keypadElement */
|
|
2048
|
+
_getKeypadBounds() {
|
|
2049
|
+
var _this$props$keypadEle3;
|
|
2050
|
+
const keypadNode = (_this$props$keypadEle3 = this.props.keypadElement) == null ? void 0 : _this$props$keypadEle3.getDOMNode();
|
|
2051
|
+
|
|
2052
|
+
// If the keypad is mounted, return its bounds. Otherwise, return null.
|
|
2053
|
+
if (keypadNode instanceof Element) {
|
|
2054
|
+
return keypadNode.getBoundingClientRect();
|
|
2055
|
+
}
|
|
2056
|
+
return null;
|
|
2024
2057
|
}
|
|
2025
2058
|
render() {
|
|
2026
2059
|
const {
|
|
@@ -2049,7 +2082,7 @@ class MathInput extends React.Component {
|
|
|
2049
2082
|
onTouchStart: this.handleTouchStart,
|
|
2050
2083
|
onTouchMove: this.handleTouchMove,
|
|
2051
2084
|
onTouchEnd: this.handleTouchEnd,
|
|
2052
|
-
onClick:
|
|
2085
|
+
onClick: this.handleClick,
|
|
2053
2086
|
role: "textbox",
|
|
2054
2087
|
ariaLabel: ariaLabel
|
|
2055
2088
|
}, /*#__PURE__*/React.createElement("div", {
|