@khanacademy/math-input 14.1.1 → 14.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 +10 -0
- package/dist/components/aphrodite-css-transition-group/index.d.ts +51 -0
- package/dist/components/aphrodite-css-transition-group/transition-child.d.ts +11 -0
- package/dist/components/aphrodite-css-transition-group/types.d.ts +18 -0
- package/dist/components/aphrodite-css-transition-group/util.d.ts +7 -0
- package/dist/components/keypad/mobile-keypad.d.ts +10 -12
- package/dist/es/index.js +324 -54
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +326 -55
- package/dist/index.js.map +1 -1
- package/package.json +4 -2
- package/src/components/aphrodite-css-transition-group/index.tsx +78 -0
- package/src/components/aphrodite-css-transition-group/transition-child.tsx +191 -0
- package/src/components/aphrodite-css-transition-group/types.ts +20 -0
- package/src/components/aphrodite-css-transition-group/util.ts +97 -0
- package/src/components/keypad/__tests__/__snapshots__/mobile-keypad.test.tsx.snap +593 -0
- package/src/components/keypad/__tests__/mobile-keypad.test.tsx +115 -0
- package/src/components/keypad/mobile-keypad.tsx +66 -79
- package/tsconfig-build.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# @khanacademy/math-input
|
|
2
2
|
|
|
3
|
+
## 14.2.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- aea0387f: Change mobile-keypad to use AphroditeCSSTransitionGroup to animate mounting/unmounting the keypad when active (prevents DOM elements from being in the DOM unless the keypad is actually open).
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- c4ae088f: Upgrades MathQuill to fix Android keyboard error
|
|
12
|
+
|
|
3
13
|
## 14.1.1
|
|
4
14
|
|
|
5
15
|
### Patch Changes
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Aphrodite doesn't play well with CSSTransition from react-transition-group,
|
|
3
|
+
* which assumes that you have CSS classes and it can combine them arbitrarily.
|
|
4
|
+
*
|
|
5
|
+
* There are also some issue with react-transition-group that make it difficult
|
|
6
|
+
* to work. Even if the CSS classes are defined ahead of time it makes no
|
|
7
|
+
* guarantee that the start style will be applied by the browser before the
|
|
8
|
+
* active style is applied. This can cause the first time a transition runs to
|
|
9
|
+
* fail.
|
|
10
|
+
*
|
|
11
|
+
* AphroditeCSSTransitionGroup provides a wrapper around TransitionGroup to
|
|
12
|
+
* address these issues.
|
|
13
|
+
*
|
|
14
|
+
* There are three types of transitions:
|
|
15
|
+
* - appear: the time the child is added to the render tree
|
|
16
|
+
* - enter: whenever the child is added to the render tree after "appear". If
|
|
17
|
+
* no "appear" transition is specified then the "enter" transition will also
|
|
18
|
+
* be used for the first time the child is added to the render tree.
|
|
19
|
+
* - leave: whenever the child is removed from the render tree
|
|
20
|
+
*
|
|
21
|
+
* Each transition type has two states:
|
|
22
|
+
* - base: e.g. css(enter)
|
|
23
|
+
* - active: e.g. css(enter, enterActive)
|
|
24
|
+
*
|
|
25
|
+
* If "done" styles are not provided, the "active" style will remain on the
|
|
26
|
+
* component after the animation has completed.
|
|
27
|
+
*
|
|
28
|
+
* Usage: TBD
|
|
29
|
+
*
|
|
30
|
+
* Limitations:
|
|
31
|
+
* - This component only supports a single child whereas TransitionGroup supports
|
|
32
|
+
* multiple children.
|
|
33
|
+
* - We ignore inline styles that are provided as part of AnimationStyles.
|
|
34
|
+
*
|
|
35
|
+
* TODOs:
|
|
36
|
+
* - (FEI-3211): Change the API for AphroditeCSSTransitionGroup so that it makes
|
|
37
|
+
* bad states impossible.
|
|
38
|
+
*/
|
|
39
|
+
import * as React from "react";
|
|
40
|
+
import type { AnimationStyles } from "./types";
|
|
41
|
+
type Props = {
|
|
42
|
+
transitionStyle: AnimationStyles | (() => AnimationStyles);
|
|
43
|
+
transitionAppearTimeout?: number;
|
|
44
|
+
transitionEnterTimeout?: number;
|
|
45
|
+
transitionLeaveTimeout?: number;
|
|
46
|
+
children?: React.ReactNode;
|
|
47
|
+
};
|
|
48
|
+
declare class AphroditeCSSTransitionGroup extends React.Component<Props> {
|
|
49
|
+
render(): React.ReactNode;
|
|
50
|
+
}
|
|
51
|
+
export default AphroditeCSSTransitionGroup;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import type { AnimationStyles } from "./types";
|
|
3
|
+
declare const _default: (props: {
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
transitionStyles: AnimationStyles | (() => AnimationStyles);
|
|
6
|
+
appearTimeout?: number | undefined;
|
|
7
|
+
enterTimeout?: number | undefined;
|
|
8
|
+
leaveTimeout?: number | undefined;
|
|
9
|
+
in?: boolean | undefined;
|
|
10
|
+
}) => JSX.Element;
|
|
11
|
+
export default _default;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { StyleType } from "@khanacademy/wonder-blocks-core";
|
|
2
|
+
import type { CSSProperties } from "aphrodite";
|
|
3
|
+
export type AnimationStyles = {
|
|
4
|
+
enter?: StyleType;
|
|
5
|
+
enterActive?: StyleType;
|
|
6
|
+
leave?: StyleType;
|
|
7
|
+
leaveActive?: StyleType;
|
|
8
|
+
appear?: StyleType;
|
|
9
|
+
appearActive?: StyleType;
|
|
10
|
+
};
|
|
11
|
+
export type InAnimationStyles = {
|
|
12
|
+
enter?: CSSProperties;
|
|
13
|
+
enterActive?: CSSProperties;
|
|
14
|
+
leave?: CSSProperties;
|
|
15
|
+
leaveActive?: CSSProperties;
|
|
16
|
+
appear?: CSSProperties;
|
|
17
|
+
appearActive?: CSSProperties;
|
|
18
|
+
};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { InAnimationStyles } from "./types";
|
|
2
|
+
import type { StyleType } from "@khanacademy/wonder-blocks-core";
|
|
3
|
+
export declare function processStyleType(style?: StyleType): {
|
|
4
|
+
className: string;
|
|
5
|
+
style: Record<any, any>;
|
|
6
|
+
};
|
|
7
|
+
export declare const createTransition: (styles: InAnimationStyles) => any;
|
|
@@ -4,16 +4,6 @@ import type Key from "../../data/keys";
|
|
|
4
4
|
import type { Cursor, KeypadConfiguration, KeyHandler, KeypadAPI } from "../../types";
|
|
5
5
|
import type { AnalyticsEventHandlerFn } from "@khanacademy/perseus-core";
|
|
6
6
|
import type { StyleType } from "@khanacademy/wonder-blocks-core";
|
|
7
|
-
/**
|
|
8
|
-
* This is the v2 equivalent of v1's ProvidedKeypad. It follows the same
|
|
9
|
-
* external API so that it can be hot-swapped with the v1 keypad and
|
|
10
|
-
* is responsible for connecting the keypad with MathInput and the Renderer.
|
|
11
|
-
*
|
|
12
|
-
* Ideally this strategy of attaching methods on the class component for
|
|
13
|
-
* other components to call will be replaced props/callbacks since React
|
|
14
|
-
* doesn't support this type of code anymore (functional components
|
|
15
|
-
* can't have methods attached to them).
|
|
16
|
-
*/
|
|
17
7
|
type Props = {
|
|
18
8
|
onElementMounted?: (arg1: any) => void;
|
|
19
9
|
onDismiss?: () => void;
|
|
@@ -24,16 +14,24 @@ type Props = {
|
|
|
24
14
|
};
|
|
25
15
|
type State = {
|
|
26
16
|
containerWidth: number;
|
|
27
|
-
hasBeenActivated: boolean;
|
|
28
17
|
keypadConfig?: KeypadConfiguration;
|
|
29
18
|
keyHandler?: KeyHandler;
|
|
30
19
|
cursor?: Cursor;
|
|
31
20
|
};
|
|
21
|
+
/**
|
|
22
|
+
* This is the v2 equivalent of v1's ProvidedKeypad. It follows the same
|
|
23
|
+
* external API so that it can be hot-swapped with the v1 keypad and
|
|
24
|
+
* is responsible for connecting the keypad with MathInput and the Renderer.
|
|
25
|
+
*
|
|
26
|
+
* Ideally this strategy of attaching methods on the class component for
|
|
27
|
+
* other components to call will be replaced props/callbacks since React
|
|
28
|
+
* doesn't support this type of code anymore (functional components
|
|
29
|
+
* can't have methods attached to them).
|
|
30
|
+
*/
|
|
32
31
|
declare class MobileKeypad extends React.Component<Props, State> implements KeypadAPI {
|
|
33
32
|
_containerRef: React.RefObject<HTMLDivElement>;
|
|
34
33
|
_containerResizeObserver: ResizeObserver | null;
|
|
35
34
|
_throttleResize: boolean;
|
|
36
|
-
hasMounted: boolean;
|
|
37
35
|
state: State;
|
|
38
36
|
componentDidMount(): void;
|
|
39
37
|
componentWillUnmount(): void;
|
package/dist/es/index.js
CHANGED
|
@@ -11,15 +11,16 @@ import $ from 'jquery';
|
|
|
11
11
|
import MathQuill from 'mathquill';
|
|
12
12
|
import { View as View$1 } from '@khanacademy/wonder-blocks-core';
|
|
13
13
|
import Clickable from '@khanacademy/wonder-blocks-clickable';
|
|
14
|
+
import { TransitionGroup, CSSTransition } from 'react-transition-group';
|
|
15
|
+
import { withActionScheduler } from '@khanacademy/wonder-blocks-timing';
|
|
14
16
|
import { connect, Provider } from 'react-redux';
|
|
15
17
|
import katex from 'katex';
|
|
16
18
|
import PropTypes from 'prop-types';
|
|
17
|
-
import { TransitionGroup, CSSTransition } from 'react-transition-group';
|
|
18
19
|
import * as Redux from 'redux';
|
|
19
20
|
|
|
20
21
|
// This file is processed by a Rollup plugin (replace) to inject the production
|
|
21
22
|
const libName = "@khanacademy/math-input";
|
|
22
|
-
const libVersion = "14.
|
|
23
|
+
const libVersion = "14.2.0";
|
|
23
24
|
addLibraryVersionToPerseusDebug(libName, libVersion);
|
|
24
25
|
|
|
25
26
|
function _extends() {
|
|
@@ -5090,16 +5091,302 @@ const styles$d = StyleSheet.create({
|
|
|
5090
5091
|
}
|
|
5091
5092
|
});
|
|
5092
5093
|
|
|
5094
|
+
function flatten(list) {
|
|
5095
|
+
const result = [];
|
|
5096
|
+
if (!list) {
|
|
5097
|
+
return result;
|
|
5098
|
+
}
|
|
5099
|
+
if (Array.isArray(list)) {
|
|
5100
|
+
for (const item of list) {
|
|
5101
|
+
result.push(...flatten(item));
|
|
5102
|
+
}
|
|
5103
|
+
} else {
|
|
5104
|
+
result.push(list);
|
|
5105
|
+
}
|
|
5106
|
+
return result;
|
|
5107
|
+
}
|
|
5108
|
+
function processStyleType(style) {
|
|
5109
|
+
const stylesheetStyles = [];
|
|
5110
|
+
const inlineStyles = [];
|
|
5111
|
+
if (!style) {
|
|
5112
|
+
return {
|
|
5113
|
+
style: {},
|
|
5114
|
+
className: ""
|
|
5115
|
+
};
|
|
5116
|
+
}
|
|
5117
|
+
|
|
5118
|
+
// Check to see if we should inline all the styles for snapshot tests.
|
|
5119
|
+
const shouldInlineStyles = typeof globalThis !== "undefined" && globalThis.SNAPSHOT_INLINE_APHRODITE;
|
|
5120
|
+
flatten(style).forEach(child => {
|
|
5121
|
+
// Check for aphrodite internal property
|
|
5122
|
+
const _definition = child._definition;
|
|
5123
|
+
if (_definition != null) {
|
|
5124
|
+
if (shouldInlineStyles) {
|
|
5125
|
+
const def = {};
|
|
5126
|
+
// React 16 complains about invalid keys in inline styles.
|
|
5127
|
+
// It doesn't accept kebab-case in media queries and instead
|
|
5128
|
+
// prefers camelCase.
|
|
5129
|
+
for (const [key, value] of entries(_definition)) {
|
|
5130
|
+
// This regex converts all instances of -{lowercaseLetter}
|
|
5131
|
+
// to the uppercase version of that letter, without the
|
|
5132
|
+
// leading dash.
|
|
5133
|
+
def[key.replace(/-[a-z]/g, match => match[1].toUpperCase())] = value;
|
|
5134
|
+
}
|
|
5135
|
+
inlineStyles.push(def);
|
|
5136
|
+
} else {
|
|
5137
|
+
stylesheetStyles.push(child);
|
|
5138
|
+
}
|
|
5139
|
+
} else {
|
|
5140
|
+
inlineStyles.push(child);
|
|
5141
|
+
}
|
|
5142
|
+
});
|
|
5143
|
+
const inlineStylesObject = Object.assign({}, ...inlineStyles);
|
|
5144
|
+
|
|
5145
|
+
// TODO(somewhatabstract): When aphrodite no longer puts "!important" on
|
|
5146
|
+
// all the styles, remove this <ADD JIRA ISSUE HERE IF THIS PASSES REVIEW>
|
|
5147
|
+
// If we're not snapshotting styles, let's create a class for the inline
|
|
5148
|
+
// styles so that they can apply to the element even with aphrodite's
|
|
5149
|
+
// use of !important.
|
|
5150
|
+
if (inlineStyles.length > 0 && !shouldInlineStyles) {
|
|
5151
|
+
const inlineStylesStyleSheet = StyleSheet.create({
|
|
5152
|
+
inlineStyles: inlineStylesObject
|
|
5153
|
+
});
|
|
5154
|
+
stylesheetStyles.push(inlineStylesStyleSheet.inlineStyles);
|
|
5155
|
+
}
|
|
5156
|
+
return {
|
|
5157
|
+
style: shouldInlineStyles ? inlineStylesObject : {},
|
|
5158
|
+
className: css(...stylesheetStyles)
|
|
5159
|
+
};
|
|
5160
|
+
}
|
|
5161
|
+
|
|
5162
|
+
class TransitionChild extends React.Component {
|
|
5163
|
+
// Each 2-tuple in the queue represents two classnames: one to remove and
|
|
5164
|
+
// one to add (in that order).
|
|
5165
|
+
|
|
5166
|
+
// We keep track of all of the current applied classes so that we can remove
|
|
5167
|
+
// them before a new transition starts in the case of the current transition
|
|
5168
|
+
// being interrupted.
|
|
5169
|
+
|
|
5170
|
+
// The use of getDerivedStateFromProps here is to avoid an extra call to
|
|
5171
|
+
// setState if the component re-enters. This can happen if TransitionGroup
|
|
5172
|
+
// sets `in` from `false` to `true`.
|
|
5173
|
+
// eslint-disable-next-line no-restricted-syntax
|
|
5174
|
+
static getDerivedStateFromProps({
|
|
5175
|
+
in: nextIn
|
|
5176
|
+
}, prevState) {
|
|
5177
|
+
if (nextIn && prevState.status === "unmounted") {
|
|
5178
|
+
return {
|
|
5179
|
+
status: "mounted"
|
|
5180
|
+
};
|
|
5181
|
+
}
|
|
5182
|
+
return null;
|
|
5183
|
+
}
|
|
5184
|
+
constructor(props) {
|
|
5185
|
+
super(props);
|
|
5186
|
+
this.classNameQueue = void 0;
|
|
5187
|
+
this.appliedClassNames = void 0;
|
|
5188
|
+
this._isMounted = false;
|
|
5189
|
+
this.addClass = (elem, className) => {
|
|
5190
|
+
if (className) {
|
|
5191
|
+
elem.classList.add(className);
|
|
5192
|
+
this.appliedClassNames.add(className);
|
|
5193
|
+
}
|
|
5194
|
+
};
|
|
5195
|
+
this.removeClass = (elem, className) => {
|
|
5196
|
+
if (className) {
|
|
5197
|
+
elem.classList.remove(className);
|
|
5198
|
+
this.appliedClassNames.delete(className);
|
|
5199
|
+
}
|
|
5200
|
+
};
|
|
5201
|
+
this.flushClassNameQueue = () => {
|
|
5202
|
+
if (this._isMounted) {
|
|
5203
|
+
const node = ReactDOM.findDOMNode(this);
|
|
5204
|
+
if (node instanceof Element) {
|
|
5205
|
+
this.classNameQueue.forEach(([removeClassName, addClassName]) => {
|
|
5206
|
+
// Remove the old class before adding a new class just
|
|
5207
|
+
// in case the new class is the same as the old one.
|
|
5208
|
+
this.removeClass(node, removeClassName);
|
|
5209
|
+
this.addClass(node, addClassName);
|
|
5210
|
+
});
|
|
5211
|
+
}
|
|
5212
|
+
}
|
|
5213
|
+
|
|
5214
|
+
// Remove all items in the Array.
|
|
5215
|
+
this.classNameQueue.length = 0;
|
|
5216
|
+
};
|
|
5217
|
+
this._isMounted = false;
|
|
5218
|
+
this.classNameQueue = [];
|
|
5219
|
+
this.appliedClassNames = new Set();
|
|
5220
|
+
this.state = {
|
|
5221
|
+
status: "mounted"
|
|
5222
|
+
};
|
|
5223
|
+
}
|
|
5224
|
+
componentDidMount() {
|
|
5225
|
+
this._isMounted = true;
|
|
5226
|
+
if (typeof this.props.appearTimeout === "number") {
|
|
5227
|
+
this.transition("appear", this.props.appearTimeout);
|
|
5228
|
+
} else {
|
|
5229
|
+
this.transition("enter", this.props.enterTimeout);
|
|
5230
|
+
}
|
|
5231
|
+
}
|
|
5232
|
+
componentDidUpdate(oldProps, oldState) {
|
|
5233
|
+
if (oldProps.in && !this.props.in) {
|
|
5234
|
+
this.transition("leave", this.props.leaveTimeout);
|
|
5235
|
+
} else if (!oldProps.in && this.props.in) {
|
|
5236
|
+
this.transition("enter", this.props.enterTimeout);
|
|
5237
|
+
}
|
|
5238
|
+
if (oldState.status !== "mounted" && this.state.status === "mounted") {
|
|
5239
|
+
// Remove the node from the DOM
|
|
5240
|
+
// eslint-disable-next-line react/no-did-update-set-state
|
|
5241
|
+
this.setState({
|
|
5242
|
+
status: "unmounted"
|
|
5243
|
+
});
|
|
5244
|
+
}
|
|
5245
|
+
}
|
|
5246
|
+
|
|
5247
|
+
// NOTE: This will only get called when the parent TransitionGroup becomes
|
|
5248
|
+
// unmounted. This is because that component clones all of its children and
|
|
5249
|
+
// keeps them around so that they can be animated when leaving and also so
|
|
5250
|
+
// that the can be animated when re-rentering if that occurs.
|
|
5251
|
+
componentWillUnmount() {
|
|
5252
|
+
this._isMounted = false;
|
|
5253
|
+
this.props.schedule.clearAll();
|
|
5254
|
+
}
|
|
5255
|
+
removeAllClasses(node) {
|
|
5256
|
+
for (const className of this.appliedClassNames) {
|
|
5257
|
+
this.removeClass(node, className);
|
|
5258
|
+
}
|
|
5259
|
+
}
|
|
5260
|
+
transition(animationType, duration) {
|
|
5261
|
+
const node = ReactDOM.findDOMNode(this);
|
|
5262
|
+
if (!(node instanceof Element)) {
|
|
5263
|
+
return;
|
|
5264
|
+
}
|
|
5265
|
+
|
|
5266
|
+
// Remove any classes from previous transitions.
|
|
5267
|
+
this.removeAllClasses(node);
|
|
5268
|
+
|
|
5269
|
+
// A previous transition may still be in progress so clear its timers.
|
|
5270
|
+
this.props.schedule.clearAll();
|
|
5271
|
+
const transitionStyles = typeof this.props.transitionStyles === "function" ? this.props.transitionStyles() : this.props.transitionStyles;
|
|
5272
|
+
const {
|
|
5273
|
+
className
|
|
5274
|
+
} = processStyleType(transitionStyles[animationType]);
|
|
5275
|
+
const {
|
|
5276
|
+
className: activeClassName
|
|
5277
|
+
} = processStyleType([transitionStyles[animationType], transitionStyles[animationType + "Active"]]);
|
|
5278
|
+
|
|
5279
|
+
// Put the node in the starting position.
|
|
5280
|
+
this.addClass(node, className);
|
|
5281
|
+
|
|
5282
|
+
// Queue the component to show the "active" style.
|
|
5283
|
+
this.queueClass(className, activeClassName);
|
|
5284
|
+
|
|
5285
|
+
// Unmount the children after the 'leave' transition has completed.
|
|
5286
|
+
if (animationType === "leave") {
|
|
5287
|
+
this.props.schedule.timeout(() => {
|
|
5288
|
+
if (this._isMounted) {
|
|
5289
|
+
this.setState({
|
|
5290
|
+
status: "unmounted"
|
|
5291
|
+
});
|
|
5292
|
+
}
|
|
5293
|
+
}, duration || 0);
|
|
5294
|
+
}
|
|
5295
|
+
}
|
|
5296
|
+
queueClass(removeClassName, addClassName) {
|
|
5297
|
+
this.classNameQueue.push([removeClassName, addClassName]);
|
|
5298
|
+
this.props.schedule.animationFrame(this.flushClassNameQueue);
|
|
5299
|
+
}
|
|
5300
|
+
render() {
|
|
5301
|
+
const {
|
|
5302
|
+
status
|
|
5303
|
+
} = this.state;
|
|
5304
|
+
if (status === "unmounted") {
|
|
5305
|
+
return null;
|
|
5306
|
+
}
|
|
5307
|
+
return this.props.children;
|
|
5308
|
+
}
|
|
5309
|
+
}
|
|
5310
|
+
var TransitionChild$1 = withActionScheduler(TransitionChild);
|
|
5311
|
+
|
|
5312
|
+
/**
|
|
5313
|
+
* Aphrodite doesn't play well with CSSTransition from react-transition-group,
|
|
5314
|
+
* which assumes that you have CSS classes and it can combine them arbitrarily.
|
|
5315
|
+
*
|
|
5316
|
+
* There are also some issue with react-transition-group that make it difficult
|
|
5317
|
+
* to work. Even if the CSS classes are defined ahead of time it makes no
|
|
5318
|
+
* guarantee that the start style will be applied by the browser before the
|
|
5319
|
+
* active style is applied. This can cause the first time a transition runs to
|
|
5320
|
+
* fail.
|
|
5321
|
+
*
|
|
5322
|
+
* AphroditeCSSTransitionGroup provides a wrapper around TransitionGroup to
|
|
5323
|
+
* address these issues.
|
|
5324
|
+
*
|
|
5325
|
+
* There are three types of transitions:
|
|
5326
|
+
* - appear: the time the child is added to the render tree
|
|
5327
|
+
* - enter: whenever the child is added to the render tree after "appear". If
|
|
5328
|
+
* no "appear" transition is specified then the "enter" transition will also
|
|
5329
|
+
* be used for the first time the child is added to the render tree.
|
|
5330
|
+
* - leave: whenever the child is removed from the render tree
|
|
5331
|
+
*
|
|
5332
|
+
* Each transition type has two states:
|
|
5333
|
+
* - base: e.g. css(enter)
|
|
5334
|
+
* - active: e.g. css(enter, enterActive)
|
|
5335
|
+
*
|
|
5336
|
+
* If "done" styles are not provided, the "active" style will remain on the
|
|
5337
|
+
* component after the animation has completed.
|
|
5338
|
+
*
|
|
5339
|
+
* Usage: TBD
|
|
5340
|
+
*
|
|
5341
|
+
* Limitations:
|
|
5342
|
+
* - This component only supports a single child whereas TransitionGroup supports
|
|
5343
|
+
* multiple children.
|
|
5344
|
+
* - We ignore inline styles that are provided as part of AnimationStyles.
|
|
5345
|
+
*
|
|
5346
|
+
* TODOs:
|
|
5347
|
+
* - (FEI-3211): Change the API for AphroditeCSSTransitionGroup so that it makes
|
|
5348
|
+
* bad states impossible.
|
|
5349
|
+
*/
|
|
5350
|
+
class AphroditeCSSTransitionGroup extends React.Component {
|
|
5351
|
+
render() {
|
|
5352
|
+
const {
|
|
5353
|
+
children
|
|
5354
|
+
} = this.props;
|
|
5355
|
+
return (
|
|
5356
|
+
/*#__PURE__*/
|
|
5357
|
+
// `component={null}` prevents wrapping each child with a <div>
|
|
5358
|
+
// which can muck with certain layouts.
|
|
5359
|
+
React.createElement(TransitionGroup, {
|
|
5360
|
+
component: null
|
|
5361
|
+
}, React.Children.map(children, child => /*#__PURE__*/React.createElement(TransitionChild$1, {
|
|
5362
|
+
transitionStyles: this.props.transitionStyle,
|
|
5363
|
+
appearTimeout: this.props.transitionAppearTimeout,
|
|
5364
|
+
enterTimeout: this.props.transitionEnterTimeout,
|
|
5365
|
+
leaveTimeout: this.props.transitionLeaveTimeout
|
|
5366
|
+
}, child)))
|
|
5367
|
+
);
|
|
5368
|
+
}
|
|
5369
|
+
}
|
|
5370
|
+
|
|
5371
|
+
const AnimationDurationInMS = 200;
|
|
5372
|
+
/**
|
|
5373
|
+
* This is the v2 equivalent of v1's ProvidedKeypad. It follows the same
|
|
5374
|
+
* external API so that it can be hot-swapped with the v1 keypad and
|
|
5375
|
+
* is responsible for connecting the keypad with MathInput and the Renderer.
|
|
5376
|
+
*
|
|
5377
|
+
* Ideally this strategy of attaching methods on the class component for
|
|
5378
|
+
* other components to call will be replaced props/callbacks since React
|
|
5379
|
+
* doesn't support this type of code anymore (functional components
|
|
5380
|
+
* can't have methods attached to them).
|
|
5381
|
+
*/
|
|
5093
5382
|
class MobileKeypad extends React.Component {
|
|
5094
5383
|
constructor(...args) {
|
|
5095
5384
|
super(...args);
|
|
5096
5385
|
this._containerRef = /*#__PURE__*/React.createRef();
|
|
5097
5386
|
this._containerResizeObserver = null;
|
|
5098
5387
|
this._throttleResize = false;
|
|
5099
|
-
this.hasMounted = false;
|
|
5100
5388
|
this.state = {
|
|
5101
|
-
containerWidth: 0
|
|
5102
|
-
hasBeenActivated: false
|
|
5389
|
+
containerWidth: 0
|
|
5103
5390
|
};
|
|
5104
5391
|
this._resize = () => {
|
|
5105
5392
|
var _this$_containerRef$c;
|
|
@@ -5120,9 +5407,6 @@ class MobileKeypad extends React.Component {
|
|
|
5120
5407
|
};
|
|
5121
5408
|
this.activate = () => {
|
|
5122
5409
|
this.props.setKeypadActive(true);
|
|
5123
|
-
this.setState({
|
|
5124
|
-
hasBeenActivated: true
|
|
5125
|
-
});
|
|
5126
5410
|
};
|
|
5127
5411
|
this.dismiss = () => {
|
|
5128
5412
|
var _this$props$onDismiss, _this$props;
|
|
@@ -5160,6 +5444,7 @@ class MobileKeypad extends React.Component {
|
|
|
5160
5444
|
};
|
|
5161
5445
|
}
|
|
5162
5446
|
componentDidMount() {
|
|
5447
|
+
var _this$props$onElement, _this$props2;
|
|
5163
5448
|
this._resize();
|
|
5164
5449
|
window.addEventListener("resize", this._throttleResizeHandler);
|
|
5165
5450
|
window.addEventListener("orientationchange", this._throttleResizeHandler);
|
|
@@ -5172,6 +5457,14 @@ class MobileKeypad extends React.Component {
|
|
|
5172
5457
|
this._containerResizeObserver.observe(this._containerRef.current);
|
|
5173
5458
|
}
|
|
5174
5459
|
}
|
|
5460
|
+
(_this$props$onElement = (_this$props2 = this.props).onElementMounted) == null ? void 0 : _this$props$onElement.call(_this$props2, {
|
|
5461
|
+
activate: this.activate,
|
|
5462
|
+
dismiss: this.dismiss,
|
|
5463
|
+
configure: this.configure,
|
|
5464
|
+
setCursor: this.setCursor,
|
|
5465
|
+
setKeyHandler: this.setKeyHandler,
|
|
5466
|
+
getDOMNode: this.getDOMNode
|
|
5467
|
+
});
|
|
5175
5468
|
}
|
|
5176
5469
|
componentWillUnmount() {
|
|
5177
5470
|
var _this$_containerResiz;
|
|
@@ -5196,52 +5489,37 @@ class MobileKeypad extends React.Component {
|
|
|
5196
5489
|
style
|
|
5197
5490
|
} = this.props;
|
|
5198
5491
|
const {
|
|
5199
|
-
hasBeenActivated,
|
|
5200
5492
|
containerWidth,
|
|
5201
5493
|
cursor,
|
|
5202
5494
|
keypadConfig
|
|
5203
5495
|
} = this.state;
|
|
5204
|
-
const containerStyle = [
|
|
5205
|
-
// internal styles
|
|
5206
|
-
styles$c.keypadContainer, keypadActive && styles$c.activeKeypadContainer,
|
|
5496
|
+
const containerStyle = [styles$c.keypadContainer,
|
|
5207
5497
|
// styles passed as props
|
|
5208
5498
|
...(Array.isArray(style) ? style : [style])];
|
|
5209
|
-
|
|
5210
|
-
// If the keypad is yet to have ever been activated, we keep it invisible
|
|
5211
|
-
// so as to avoid, e.g., the keypad flashing at the bottom of the page
|
|
5212
|
-
// during the initial render.
|
|
5213
|
-
// Done inline (dynamicStyle) since stylesheets might not be loaded yet.
|
|
5214
|
-
let dynamicStyle = {};
|
|
5215
|
-
if (!keypadActive && !hasBeenActivated) {
|
|
5216
|
-
dynamicStyle = {
|
|
5217
|
-
visibility: "hidden"
|
|
5218
|
-
};
|
|
5219
|
-
}
|
|
5220
5499
|
const isExpression = (keypadConfig == null ? void 0 : keypadConfig.keypadType) === "EXPRESSION";
|
|
5221
5500
|
const convertDotToTimes = keypadConfig == null ? void 0 : keypadConfig.times;
|
|
5222
|
-
return /*#__PURE__*/React.createElement(
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
5228
|
-
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
getDOMNode: this.getDOMNode
|
|
5240
|
-
});
|
|
5241
|
-
this.hasMounted = true;
|
|
5242
|
-
(_this$props$onElement = (_this$props2 = this.props).onElementMounted) == null ? void 0 : _this$props$onElement.call(_this$props2, elementWithDispatchMethods);
|
|
5501
|
+
return /*#__PURE__*/React.createElement(AphroditeCSSTransitionGroup, {
|
|
5502
|
+
transitionEnterTimeout: AnimationDurationInMS,
|
|
5503
|
+
transitionLeaveTimeout: AnimationDurationInMS,
|
|
5504
|
+
transitionStyle: {
|
|
5505
|
+
enter: {
|
|
5506
|
+
transform: "translate3d(0, 100%, 0)",
|
|
5507
|
+
transition: `${AnimationDurationInMS}ms ease-out`
|
|
5508
|
+
},
|
|
5509
|
+
enterActive: {
|
|
5510
|
+
transform: "translate3d(0, 0, 0)"
|
|
5511
|
+
},
|
|
5512
|
+
leave: {
|
|
5513
|
+
transform: "translate3d(0, 0, 0)",
|
|
5514
|
+
transition: `${AnimationDurationInMS}ms ease-out`
|
|
5515
|
+
},
|
|
5516
|
+
leaveActive: {
|
|
5517
|
+
transform: "translate3d(0, 100%, 0)"
|
|
5243
5518
|
}
|
|
5244
5519
|
}
|
|
5520
|
+
}, keypadActive ? /*#__PURE__*/React.createElement(View, {
|
|
5521
|
+
style: containerStyle,
|
|
5522
|
+
forwardRef: this._containerRef
|
|
5245
5523
|
}, /*#__PURE__*/React.createElement(Keypad$2, {
|
|
5246
5524
|
onAnalyticsEvent: this.props.onAnalyticsEvent,
|
|
5247
5525
|
extraKeys: keypadConfig == null ? void 0 : keypadConfig.extraKeys,
|
|
@@ -5257,7 +5535,7 @@ class MobileKeypad extends React.Component {
|
|
|
5257
5535
|
advancedRelations: isExpression,
|
|
5258
5536
|
expandedView: containerWidth > expandedViewThreshold$1,
|
|
5259
5537
|
showDismiss: true
|
|
5260
|
-
}));
|
|
5538
|
+
})) : null);
|
|
5261
5539
|
}
|
|
5262
5540
|
}
|
|
5263
5541
|
const styles$c = StyleSheet.create({
|
|
@@ -5265,15 +5543,7 @@ const styles$c = StyleSheet.create({
|
|
|
5265
5543
|
bottom: 0,
|
|
5266
5544
|
left: 0,
|
|
5267
5545
|
right: 0,
|
|
5268
|
-
position: "fixed"
|
|
5269
|
-
transitionProperty: "all",
|
|
5270
|
-
transition: `200ms ease-out`,
|
|
5271
|
-
visibility: "hidden",
|
|
5272
|
-
transform: "translate3d(0, 100%, 0)"
|
|
5273
|
-
},
|
|
5274
|
-
activeKeypadContainer: {
|
|
5275
|
-
transform: "translate3d(0, 0, 0)",
|
|
5276
|
-
visibility: "visible"
|
|
5546
|
+
position: "fixed"
|
|
5277
5547
|
}
|
|
5278
5548
|
});
|
|
5279
5549
|
|