@khanacademy/math-input 16.1.2 → 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 +8 -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 +1 -1
- 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/dist/index.js
CHANGED
|
@@ -48,7 +48,7 @@ var PropTypes__default = /*#__PURE__*/_interopDefaultLegacy(PropTypes);
|
|
|
48
48
|
|
|
49
49
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
50
50
|
const libName = "@khanacademy/math-input";
|
|
51
|
-
const libVersion = "16.
|
|
51
|
+
const libVersion = "16.2.0";
|
|
52
52
|
perseusCore.addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
53
53
|
|
|
54
54
|
function _extends() {
|
|
@@ -1399,6 +1399,8 @@ class MathInput extends React__namespace.Component {
|
|
|
1399
1399
|
|
|
1400
1400
|
// @ts-expect-error - TS2564 - Property 'blurOnTouchEndOutside' has no initializer and is not definitely assigned in the constructor.
|
|
1401
1401
|
|
|
1402
|
+
// @ts-expect-error - TS2564 - Property 'blurOnClickOutside' has no initializer and is not definitely assigned in the constructor.
|
|
1403
|
+
|
|
1402
1404
|
// @ts-expect-error - TS2564 - Property '_container' has no initializer and is not definitely assigned in the constructor.
|
|
1403
1405
|
|
|
1404
1406
|
// @ts-expect-error - TS2564 - Property '_containerBounds' has no initializer and is not definitely assigned in the constructor.
|
|
@@ -1446,6 +1448,16 @@ class MathInput extends React__namespace.Component {
|
|
|
1446
1448
|
this._container = ReactDOM__default["default"].findDOMNode(this);
|
|
1447
1449
|
this._root = this._container.querySelector(".mq-root-block");
|
|
1448
1450
|
this._root.addEventListener("scroll", this._handleScroll);
|
|
1451
|
+
const isWithinKeypadBounds = (x, y) => {
|
|
1452
|
+
const bounds = this._getKeypadBounds();
|
|
1453
|
+
|
|
1454
|
+
// If there are no bounds, then the keypad is not mounted, so we
|
|
1455
|
+
// assume that the event is not within the keypad bounds.
|
|
1456
|
+
if (!bounds) {
|
|
1457
|
+
return false;
|
|
1458
|
+
}
|
|
1459
|
+
return bounds.left <= x && bounds.right >= x && bounds.top <= y && bounds.bottom >= y || bounds.bottom < y;
|
|
1460
|
+
};
|
|
1449
1461
|
|
|
1450
1462
|
// Record the initial scroll displacement on touch start. This allows
|
|
1451
1463
|
// us to detect whether a touch event was a scroll and only blur the
|
|
@@ -1463,10 +1475,9 @@ class MathInput extends React__namespace.Component {
|
|
|
1463
1475
|
if (!this._container.contains(evt.target)) {
|
|
1464
1476
|
let touchDidStartInOrBelowKeypad = false;
|
|
1465
1477
|
if (this.props.keypadElement && this.props.keypadElement.getDOMNode()) {
|
|
1466
|
-
const bounds = this._getKeypadBounds();
|
|
1467
1478
|
for (let i = 0; i < evt.changedTouches.length; i++) {
|
|
1468
1479
|
const [x, y] = [evt.changedTouches[i].clientX, evt.changedTouches[i].clientY];
|
|
1469
|
-
if (
|
|
1480
|
+
if (isWithinKeypadBounds(x, y)) {
|
|
1470
1481
|
touchDidStartInOrBelowKeypad = true;
|
|
1471
1482
|
break;
|
|
1472
1483
|
}
|
|
@@ -1502,25 +1513,31 @@ class MathInput extends React__namespace.Component {
|
|
|
1502
1513
|
this.dragListener.detach();
|
|
1503
1514
|
}
|
|
1504
1515
|
};
|
|
1516
|
+
|
|
1517
|
+
// We want to allow the user to blur the input by clicking outside of it
|
|
1518
|
+
// when using ChromeOS third-party browsers that use mobile user agents,
|
|
1519
|
+
// but don't actually simulate touch events.
|
|
1520
|
+
this.blurOnClickOutside = evt => {
|
|
1521
|
+
if (this.state.focused) {
|
|
1522
|
+
if (!this._container.contains(evt.target)) {
|
|
1523
|
+
if (this.props.keypadElement && this.props.keypadElement.getDOMNode()) {
|
|
1524
|
+
const [x, y] = [evt.clientX, evt.clientY];
|
|
1525
|
+
// We only want to blur if the click is above the keypad,
|
|
1526
|
+
// to the left of the keypad, or to the right of the keypad.
|
|
1527
|
+
// The reasoning for not blurring for any clicks below the keypad is
|
|
1528
|
+
// that the keypad may be anchored above the 'Check answer' bottom bar,
|
|
1529
|
+
// in which case we don't want to dismiss the keypad on check.
|
|
1530
|
+
if (!isWithinKeypadBounds(x, y)) {
|
|
1531
|
+
this.blur();
|
|
1532
|
+
}
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
};
|
|
1505
1537
|
window.addEventListener("touchstart", this.recordTouchStartOutside);
|
|
1506
1538
|
window.addEventListener("touchend", this.blurOnTouchEndOutside);
|
|
1507
1539
|
window.addEventListener("touchcancel", this.blurOnTouchEndOutside);
|
|
1508
|
-
|
|
1509
|
-
// HACK(benkomalo): if the window resizes, the keypad bounds can
|
|
1510
|
-
// change. That's a bit peeking into the internals of the keypad
|
|
1511
|
-
// itself, since we know bounds can change only when the viewport
|
|
1512
|
-
// changes, but seems like a rare enough thing to get wrong that it's
|
|
1513
|
-
// not worth wiring up extra things for the technical "purity" of
|
|
1514
|
-
// having the keypad notify of changes to us.
|
|
1515
|
-
window.addEventListener("resize", this._clearKeypadBoundsCache);
|
|
1516
|
-
window.addEventListener("orientationchange", this._clearKeypadBoundsCache);
|
|
1517
|
-
}
|
|
1518
|
-
|
|
1519
|
-
// eslint-disable-next-line react/no-unsafe
|
|
1520
|
-
UNSAFE_componentWillReceiveProps(props) {
|
|
1521
|
-
if (this.props.keypadElement !== props.keypadElement) {
|
|
1522
|
-
this._clearKeypadBoundsCache();
|
|
1523
|
-
}
|
|
1540
|
+
window.addEventListener("click", this.blurOnClickOutside);
|
|
1524
1541
|
}
|
|
1525
1542
|
componentDidUpdate(prevProps, prevState) {
|
|
1526
1543
|
if (this.mathField.getContent() !== this.props.value) {
|
|
@@ -1535,18 +1552,8 @@ class MathInput extends React__namespace.Component {
|
|
|
1535
1552
|
window.removeEventListener("touchstart", this.recordTouchStartOutside);
|
|
1536
1553
|
window.removeEventListener("touchend", this.blurOnTouchEndOutside);
|
|
1537
1554
|
window.removeEventListener("touchcancel", this.blurOnTouchEndOutside);
|
|
1538
|
-
|
|
1539
|
-
window.removeEventListener("resize", this._clearKeypadBoundsCache());
|
|
1540
|
-
window.removeEventListener("orientationchange",
|
|
1541
|
-
// @ts-expect-error - TS2769 - No overload matches this call.
|
|
1542
|
-
this._clearKeypadBoundsCache());
|
|
1555
|
+
window.removeEventListener("click", this.blurOnClickOutside);
|
|
1543
1556
|
}
|
|
1544
|
-
_clearKeypadBoundsCache = () => {
|
|
1545
|
-
this._keypadBounds = null;
|
|
1546
|
-
};
|
|
1547
|
-
_cacheKeypadBounds = keypadNode => {
|
|
1548
|
-
this._keypadBounds = keypadNode.getBoundingClientRect();
|
|
1549
|
-
};
|
|
1550
1557
|
_updateInputPadding = () => {
|
|
1551
1558
|
this._container = ReactDOM__default["default"].findDOMNode(this);
|
|
1552
1559
|
this._root = this._container.querySelector(".mq-root-block");
|
|
@@ -1556,14 +1563,16 @@ class MathInput extends React__namespace.Component {
|
|
|
1556
1563
|
this._root.style.fontSize = `${fontSizePt}pt`;
|
|
1557
1564
|
};
|
|
1558
1565
|
|
|
1559
|
-
/**
|
|
1560
|
-
_getKeypadBounds
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1566
|
+
/** Returns the current bounds of the keypadElement */
|
|
1567
|
+
_getKeypadBounds() {
|
|
1568
|
+
const keypadNode = this.props.keypadElement?.getDOMNode();
|
|
1569
|
+
|
|
1570
|
+
// If the keypad is mounted, return its bounds. Otherwise, return null.
|
|
1571
|
+
if (keypadNode instanceof Element) {
|
|
1572
|
+
return keypadNode.getBoundingClientRect();
|
|
1564
1573
|
}
|
|
1565
|
-
return
|
|
1566
|
-
}
|
|
1574
|
+
return null;
|
|
1575
|
+
}
|
|
1567
1576
|
_updateCursorHandle = animateIntoPosition => {
|
|
1568
1577
|
const containerBounds = this._container.getBoundingClientRect();
|
|
1569
1578
|
const cursor = this._container.querySelector(".mq-cursor");
|
|
@@ -1861,6 +1870,32 @@ class MathInput extends React__namespace.Component {
|
|
|
1861
1870
|
this.focus();
|
|
1862
1871
|
}
|
|
1863
1872
|
};
|
|
1873
|
+
|
|
1874
|
+
// We want to allow the user to be able to focus the input via click
|
|
1875
|
+
// when using ChromeOS third-party browsers that use mobile user agents,
|
|
1876
|
+
// but don't actually simulate touch events.
|
|
1877
|
+
handleClick = e => {
|
|
1878
|
+
e.stopPropagation();
|
|
1879
|
+
|
|
1880
|
+
// Hide the cursor handle on click
|
|
1881
|
+
this._hideCursorHandle();
|
|
1882
|
+
|
|
1883
|
+
// Cache the container bounds, so as to avoid re-computing. If we don't
|
|
1884
|
+
// have any content, then it's not necessary, since the cursor can't be
|
|
1885
|
+
// moved anyway.
|
|
1886
|
+
if (this.mathField.getContent() !== "") {
|
|
1887
|
+
this._containerBounds = this._container.getBoundingClientRect();
|
|
1888
|
+
|
|
1889
|
+
// Make the cursor visible and set the handle-less cursor's
|
|
1890
|
+
// location.
|
|
1891
|
+
this._insertCursorAtClosestNode(e.clientX, e.clientY);
|
|
1892
|
+
}
|
|
1893
|
+
|
|
1894
|
+
// Trigger a focus event, if we're not already focused.
|
|
1895
|
+
if (!this.state.focused) {
|
|
1896
|
+
this.focus();
|
|
1897
|
+
}
|
|
1898
|
+
};
|
|
1864
1899
|
handleTouchMove = e => {
|
|
1865
1900
|
e.stopPropagation();
|
|
1866
1901
|
|
|
@@ -2084,7 +2119,7 @@ class MathInput extends React__namespace.Component {
|
|
|
2084
2119
|
onTouchStart: this.handleTouchStart,
|
|
2085
2120
|
onTouchMove: this.handleTouchMove,
|
|
2086
2121
|
onTouchEnd: this.handleTouchEnd,
|
|
2087
|
-
onClick:
|
|
2122
|
+
onClick: this.handleClick,
|
|
2088
2123
|
role: "textbox",
|
|
2089
2124
|
ariaLabel: ariaLabel
|
|
2090
2125
|
}, /*#__PURE__*/React__namespace.createElement("div", {
|