@khanacademy/math-input 17.0.4 → 17.0.6

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.
Files changed (86) hide show
  1. package/dist/components/input/math-wrapper.d.ts +2 -2
  2. package/dist/components/input/mathquill-types.d.ts +49 -6
  3. package/dist/es/index.js +8 -6
  4. package/dist/es/index.js.map +1 -1
  5. package/dist/index.js +8 -7
  6. package/dist/index.js.map +1 -1
  7. package/package.json +6 -3
  8. package/.eslintrc.js +0 -18
  9. package/CHANGELOG.md +0 -660
  10. package/less/main.less +0 -2
  11. package/less/overrides.less +0 -122
  12. package/src/components/__tests__/integration.test.tsx +0 -300
  13. package/src/components/aphrodite-css-transition-group/index.tsx +0 -78
  14. package/src/components/aphrodite-css-transition-group/transition-child.tsx +0 -192
  15. package/src/components/aphrodite-css-transition-group/types.ts +0 -20
  16. package/src/components/aphrodite-css-transition-group/util.ts +0 -97
  17. package/src/components/input/__tests__/context-tracking.test.ts +0 -176
  18. package/src/components/input/__tests__/mathquill-helpers.test.ts +0 -105
  19. package/src/components/input/__tests__/mathquill.test.ts +0 -747
  20. package/src/components/input/__tests__/test-math-wrapper.ts +0 -29
  21. package/src/components/input/cursor-contexts.ts +0 -37
  22. package/src/components/input/cursor-handle.tsx +0 -137
  23. package/src/components/input/cursor-styles.ts +0 -10
  24. package/src/components/input/drag-listener.ts +0 -79
  25. package/src/components/input/math-input.tsx +0 -1036
  26. package/src/components/input/math-wrapper.ts +0 -189
  27. package/src/components/input/mathquill-helpers.ts +0 -262
  28. package/src/components/input/mathquill-instance.ts +0 -106
  29. package/src/components/input/mathquill-types.ts +0 -32
  30. package/src/components/input/scroll-into-view.ts +0 -65
  31. package/src/components/key-handlers/__tests__/handle-jump-out.test.ts +0 -94
  32. package/src/components/key-handlers/handle-arrow.ts +0 -70
  33. package/src/components/key-handlers/handle-backspace.ts +0 -277
  34. package/src/components/key-handlers/handle-exponent.ts +0 -53
  35. package/src/components/key-handlers/handle-jump-out.ts +0 -107
  36. package/src/components/key-handlers/key-translator.ts +0 -222
  37. package/src/components/keypad/__tests__/__snapshots__/keypad.test.tsx.snap +0 -1913
  38. package/src/components/keypad/__tests__/__snapshots__/mobile-keypad.test.tsx.snap +0 -600
  39. package/src/components/keypad/__tests__/keypad-button.test.tsx +0 -84
  40. package/src/components/keypad/__tests__/keypad-v2-mathquill.test.tsx +0 -304
  41. package/src/components/keypad/__tests__/keypad-v2.cypress.ts +0 -16
  42. package/src/components/keypad/__tests__/keypad.test.tsx +0 -321
  43. package/src/components/keypad/__tests__/mobile-keypad.test.tsx +0 -115
  44. package/src/components/keypad/__tests__/test-data-tabs.ts +0 -21
  45. package/src/components/keypad/button-assets.tsx +0 -1880
  46. package/src/components/keypad/index.tsx +0 -2
  47. package/src/components/keypad/keypad-button.stories.tsx +0 -81
  48. package/src/components/keypad/keypad-button.tsx +0 -124
  49. package/src/components/keypad/keypad-mathquill.stories.tsx +0 -109
  50. package/src/components/keypad/keypad-pages/extras-page.tsx +0 -35
  51. package/src/components/keypad/keypad-pages/fractions-page.tsx +0 -125
  52. package/src/components/keypad/keypad-pages/geometry-page.tsx +0 -34
  53. package/src/components/keypad/keypad-pages/keypad-pages.stories.tsx +0 -37
  54. package/src/components/keypad/keypad-pages/numbers-page.tsx +0 -94
  55. package/src/components/keypad/keypad-pages/operators-page.tsx +0 -117
  56. package/src/components/keypad/keypad.tsx +0 -233
  57. package/src/components/keypad/mobile-keypad-internals.tsx +0 -240
  58. package/src/components/keypad/mobile-keypad.tsx +0 -24
  59. package/src/components/keypad/navigation-button.tsx +0 -127
  60. package/src/components/keypad/navigation-pad.stories.tsx +0 -26
  61. package/src/components/keypad/navigation-pad.tsx +0 -67
  62. package/src/components/keypad/shared-keys.tsx +0 -109
  63. package/src/components/keypad/utils.ts +0 -34
  64. package/src/components/keypad-context.tsx +0 -70
  65. package/src/components/prop-types.ts +0 -16
  66. package/src/components/tabbar/__tests__/tabbar.test.tsx +0 -105
  67. package/src/components/tabbar/icons.tsx +0 -122
  68. package/src/components/tabbar/index.ts +0 -1
  69. package/src/components/tabbar/item.tsx +0 -146
  70. package/src/components/tabbar/tabbar.stories.tsx +0 -83
  71. package/src/components/tabbar/tabbar.tsx +0 -65
  72. package/src/data/key-configs.ts +0 -770
  73. package/src/data/keys.ts +0 -123
  74. package/src/enums.ts +0 -27
  75. package/src/fake-react-native-web/index.ts +0 -11
  76. package/src/fake-react-native-web/text.tsx +0 -55
  77. package/src/fake-react-native-web/view.tsx +0 -91
  78. package/src/full-keypad.stories.tsx +0 -142
  79. package/src/full-mobile-input.stories.tsx +0 -115
  80. package/src/index.ts +0 -52
  81. package/src/types.ts +0 -70
  82. package/src/utils.test.ts +0 -33
  83. package/src/utils.ts +0 -61
  84. package/src/version.ts +0 -10
  85. package/tsconfig-build.json +0 -11
  86. package/tsconfig-build.tsbuildinfo +0 -1
@@ -1,127 +0,0 @@
1
- import Clickable from "@khanacademy/wonder-blocks-clickable";
2
- import Color from "@khanacademy/wonder-blocks-color";
3
- import {View} from "@khanacademy/wonder-blocks-core";
4
- import {StyleSheet} from "aphrodite";
5
- import * as React from "react";
6
-
7
- import ButtonAsset from "./button-assets";
8
-
9
- import type Key from "../../data/keys";
10
- import type {KeyConfig, ClickKeyCallback} from "../../types";
11
-
12
- export type KeypadButtonProps = {
13
- // 0 indexed [x, y] position in keypad CSS grid
14
- coord: readonly [number, number];
15
- keyConfig: KeyConfig;
16
- onClickKey: ClickKeyCallback;
17
- };
18
-
19
- function getStyles(key: Key) {
20
- switch (key) {
21
- case "UP":
22
- return styles.up;
23
- case "RIGHT":
24
- return styles.right;
25
- case "DOWN":
26
- return styles.down;
27
- case "LEFT":
28
- return styles.left;
29
- default:
30
- throw new Error(`Invalid key: ${key}`);
31
- }
32
- }
33
-
34
- export default function NavigationButton({
35
- coord,
36
- keyConfig,
37
- onClickKey,
38
- }: KeypadButtonProps) {
39
- const key = keyConfig.id;
40
- const directionalStyles = getStyles(key);
41
-
42
- return (
43
- <View
44
- style={{
45
- gridColumn: coord[0] + 1,
46
- gridRow: coord[1] + 1,
47
- }}
48
- >
49
- <Clickable
50
- onClick={(e) => onClickKey(keyConfig.id, e)}
51
- style={styles.clickable}
52
- aria-label={keyConfig.ariaLabel}
53
- >
54
- {({hovered, focused, pressed}) => (
55
- <View style={styles.outerBoxBase}>
56
- <View
57
- style={[
58
- styles.base,
59
- directionalStyles,
60
- hovered && styles.hovered,
61
- focused && styles.focused,
62
- pressed && styles.pressed,
63
- ]}
64
- >
65
- <ButtonAsset id={keyConfig.id} />
66
- </View>
67
- </View>
68
- )}
69
- </Clickable>
70
- </View>
71
- );
72
- }
73
-
74
- const borderRadiusPx = 4;
75
-
76
- const styles = StyleSheet.create({
77
- clickable: {
78
- width: "100%",
79
- height: "100%",
80
-
81
- ":focus": {
82
- outline: `none`,
83
- },
84
- },
85
- outerBoxBase: {
86
- height: "100%",
87
- width: "100%",
88
- },
89
- base: {
90
- boxShadow: `0px 1px 0px ${Color.offBlack32}`,
91
- display: "flex",
92
- justifyContent: "center",
93
- alignItems: "center",
94
- background: Color.white,
95
- borderWidth: 2,
96
- borderColor: Color.white,
97
- },
98
- up: {
99
- borderTopLeftRadius: borderRadiusPx,
100
- borderTopRightRadius: borderRadiusPx,
101
- },
102
- right: {
103
- borderTopRightRadius: borderRadiusPx,
104
- borderBottomRightRadius: borderRadiusPx,
105
- },
106
- down: {
107
- borderBottomLeftRadius: borderRadiusPx,
108
- borderBottomRightRadius: borderRadiusPx,
109
- },
110
- left: {
111
- borderTopLeftRadius: borderRadiusPx,
112
- borderBottomLeftRadius: borderRadiusPx,
113
- },
114
- hovered: {
115
- borderColor: Color.blue,
116
- boxShadow: "none",
117
- },
118
- focused: {
119
- borderColor: Color.blue,
120
- boxShadow: "none",
121
- },
122
- pressed: {
123
- border: "2px solid #1B50B3",
124
- background: `linear-gradient(0deg, rgba(24, 101, 242, 0.32), rgba(24, 101, 242, 0.32)), ${Color.white}`,
125
- boxShadow: "none",
126
- },
127
- });
@@ -1,26 +0,0 @@
1
- import {action} from "@storybook/addon-actions";
2
- import * as React from "react";
3
-
4
- import NavigationPad from "./navigation-pad";
5
-
6
- export default {
7
- title: "math-input/components/MathInput v2 Navigation Pad",
8
- parameters: {
9
- backgrounds: {
10
- default: "light background",
11
- values: [
12
- // We want a slightly darker default bg so that we can
13
- // see the top of the keypad when it is open
14
- {name: "light background", value: "lightgrey", default: true},
15
- ],
16
- },
17
- },
18
- };
19
-
20
- export function basic() {
21
- return (
22
- <div style={{padding: 50}}>
23
- <NavigationPad onClickKey={action("onClickKey")} />
24
- </div>
25
- );
26
- }
@@ -1,67 +0,0 @@
1
- import Color from "@khanacademy/wonder-blocks-color";
2
- import {View} from "@khanacademy/wonder-blocks-core";
3
- import {StyleSheet} from "aphrodite";
4
- import * as React from "react";
5
-
6
- import Keys from "../../data/key-configs";
7
-
8
- import NavigationButton from "./navigation-button";
9
-
10
- import type {ClickKeyCallback} from "../../types";
11
-
12
- export type Props = {
13
- onClickKey: ClickKeyCallback;
14
- };
15
-
16
- export default function NavigationPad(props: Props) {
17
- const {onClickKey} = props;
18
-
19
- return (
20
- <View style={styles.container}>
21
- <View style={styles.grid}>
22
- <NavigationButton
23
- keyConfig={Keys.UP}
24
- onClickKey={onClickKey}
25
- coord={[1, 0]}
26
- />
27
- <NavigationButton
28
- keyConfig={Keys.RIGHT}
29
- onClickKey={onClickKey}
30
- coord={[2, 1]}
31
- />
32
- <NavigationButton
33
- keyConfig={Keys.DOWN}
34
- onClickKey={onClickKey}
35
- coord={[1, 2]}
36
- />
37
- <NavigationButton
38
- keyConfig={Keys.LEFT}
39
- onClickKey={onClickKey}
40
- coord={[0, 1]}
41
- />
42
- <View style={styles.spacer} />
43
- </View>
44
- </View>
45
- );
46
- }
47
-
48
- const styles = StyleSheet.create({
49
- container: {
50
- display: "flex",
51
- alignItems: "center",
52
- justifyContent: "center",
53
- padding: "0 1.5rem",
54
- },
55
- grid: {
56
- width: 140,
57
- height: 140,
58
- display: "grid",
59
- gridTemplateColumns: "repeat(3, 1fr)",
60
- gridTemplateRows: "repeat(3, 1fr)",
61
- },
62
- spacer: {
63
- gridColumn: 2,
64
- gridRow: 2,
65
- background: Color.white,
66
- },
67
- });
@@ -1,109 +0,0 @@
1
- import * as React from "react";
2
-
3
- import Keys from "../../data/key-configs";
4
- import {convertDotToTimesByLocale} from "../../utils";
5
-
6
- import {KeypadButton} from "./keypad-button";
7
- import {getCursorContextConfig} from "./utils";
8
-
9
- import type {ClickKeyCallback, KeypadPageType} from "../../types";
10
- import type {CursorContext} from "../input/cursor-contexts";
11
-
12
- type Props = {
13
- onClickKey: ClickKeyCallback;
14
- selectedPage: KeypadPageType;
15
- cursorContext?: typeof CursorContext[keyof typeof CursorContext];
16
- convertDotToTimes?: boolean;
17
- divisionKey?: boolean;
18
- };
19
-
20
- export default function SharedKeys(props: Props) {
21
- const {
22
- onClickKey,
23
- cursorContext,
24
- divisionKey,
25
- convertDotToTimes,
26
- selectedPage,
27
- } = props;
28
-
29
- const cursorKeyConfig = getCursorContextConfig(cursorContext);
30
-
31
- // Fraction position depends on the page
32
- const fractionCoord: readonly [number, number] =
33
- selectedPage === "Numbers" || selectedPage === "Operators"
34
- ? [3, 1]
35
- : [3, 0];
36
-
37
- return (
38
- <>
39
- <KeypadButton
40
- keyConfig={Keys.FRAC}
41
- onClickKey={onClickKey}
42
- coord={fractionCoord}
43
- secondary
44
- />
45
- <KeypadButton
46
- keyConfig={Keys.PLUS}
47
- onClickKey={onClickKey}
48
- coord={[4, 0]}
49
- secondary
50
- />
51
- <KeypadButton
52
- keyConfig={Keys.MINUS}
53
- onClickKey={onClickKey}
54
- coord={[5, 0]}
55
- secondary
56
- />
57
-
58
- {/* Row 2 */}
59
- <KeypadButton
60
- keyConfig={
61
- convertDotToTimesByLocale(!!convertDotToTimes)
62
- ? Keys.TIMES
63
- : Keys.CDOT
64
- }
65
- onClickKey={onClickKey}
66
- coord={[4, 1]}
67
- secondary
68
- />
69
- {divisionKey && (
70
- <KeypadButton
71
- keyConfig={Keys.DIVIDE}
72
- onClickKey={onClickKey}
73
- coord={[5, 1]}
74
- secondary
75
- />
76
- )}
77
-
78
- {/* Row 3 */}
79
- <KeypadButton
80
- keyConfig={Keys.LEFT_PAREN}
81
- onClickKey={onClickKey}
82
- coord={[4, 2]}
83
- secondary
84
- />
85
- <KeypadButton
86
- keyConfig={Keys.RIGHT_PAREN}
87
- onClickKey={onClickKey}
88
- coord={[5, 2]}
89
- secondary
90
- />
91
-
92
- {/* Row 4 */}
93
- {cursorKeyConfig && (
94
- <KeypadButton
95
- keyConfig={cursorKeyConfig}
96
- onClickKey={onClickKey}
97
- coord={[4, 3]}
98
- secondary
99
- />
100
- )}
101
- <KeypadButton
102
- keyConfig={Keys.BACKSPACE}
103
- onClickKey={onClickKey}
104
- coord={[5, 3]}
105
- action
106
- />
107
- </>
108
- );
109
- }
@@ -1,34 +0,0 @@
1
- import Keys from "../../data/key-configs";
2
- import {CursorContext} from "../input/cursor-contexts";
3
-
4
- // This is just a magic number, I just played around with it
5
- // until the transition from expanded -> regular -> expanded felt natural
6
- export const expandedViewThreshold = 500;
7
-
8
- // This is a helper function that returns the correct context for the cursor
9
- // based on the cursorContext prop. It is used in the keypad to determine
10
- // which key to render as the "jump out" key.
11
- export function getCursorContextConfig(
12
- cursorContext?: typeof CursorContext[keyof typeof CursorContext],
13
- ) {
14
- if (!cursorContext) {
15
- return null;
16
- }
17
-
18
- switch (cursorContext) {
19
- case CursorContext.NONE:
20
- return null;
21
- case CursorContext.IN_PARENS:
22
- return Keys.JUMP_OUT_PARENTHESES;
23
- case CursorContext.IN_SUPER_SCRIPT:
24
- return Keys.JUMP_OUT_EXPONENT;
25
- case CursorContext.IN_SUB_SCRIPT:
26
- return Keys.JUMP_OUT_BASE;
27
- case CursorContext.IN_NUMERATOR:
28
- return Keys.JUMP_OUT_NUMERATOR;
29
- case CursorContext.IN_DENOMINATOR:
30
- return Keys.JUMP_OUT_DENOMINATOR;
31
- case CursorContext.BEFORE_FRACTION:
32
- return Keys.JUMP_INTO_NUMERATOR;
33
- }
34
- }
@@ -1,70 +0,0 @@
1
- /**
2
- * KeypadContext provides a way to the Keypad and Perseus Renderers to
3
- * communicate.
4
- *
5
- * The StatefulKeypadContextProvider wraps the application
6
- * while KeypadContext.Consumer wraps things that need this state:
7
- * - mobile keypad usages
8
- * - Perseus Renderers (Server/Item/Article)
9
- */
10
- import * as React from "react";
11
- import {useState, useMemo} from "react";
12
-
13
- import type {KeypadAPI, KeypadContextType} from "../types";
14
- import type {KeypadContextRendererInterface} from "@khanacademy/perseus-core";
15
-
16
- // @ts-expect-error - TS2322 - Type 'Context<{ setKeypadElement: (keypadElement: HTMLElement | null | undefined) => void; keypadElement: null; setRenderer: (renderer: RendererInterface | null | undefined) => void; renderer: null; setScrollableElement: (scrollableElement: HTMLElement | ... 1 more ... | undefined) => void; scrollableElement: null; }>' is not assignable to type 'Context<KeypadContext>'.
17
- export const KeypadContext: React.Context<KeypadContextType> =
18
- React.createContext({
19
- setKeypadActive: (keypadActive) => {},
20
- keypadActive: false,
21
- setKeypadElement: (keypadElement) => {},
22
- keypadElement: null,
23
- setRenderer: (renderer) => {},
24
- renderer: null,
25
- setScrollableElement: (scrollableElement) => {},
26
- scrollableElement: null,
27
- });
28
-
29
- type Props = React.PropsWithChildren<unknown>;
30
-
31
- export function StatefulKeypadContextProvider(props: Props) {
32
- // whether or not to display the keypad
33
- const [keypadActive, setKeypadActive] = useState<boolean>(false);
34
- // used to communicate between the keypad and the Renderer
35
- const [keypadElement, setKeypadElement] = useState<KeypadAPI | null>();
36
- // this is a KeypadContextRendererInterface from Perseus
37
- const [renderer, setRenderer] =
38
- useState<KeypadContextRendererInterface | null>();
39
- const [scrollableElement, setScrollableElement] =
40
- useState<HTMLElement | null>();
41
-
42
- const memoizedValue = useMemo(
43
- () => ({
44
- keypadActive,
45
- setKeypadActive,
46
- keypadElement,
47
- setKeypadElement,
48
- renderer,
49
- setRenderer,
50
- scrollableElement,
51
- setScrollableElement,
52
- }),
53
- [
54
- keypadActive,
55
- setKeypadActive,
56
- keypadElement,
57
- setKeypadElement,
58
- renderer,
59
- setRenderer,
60
- scrollableElement,
61
- setScrollableElement,
62
- ],
63
- );
64
-
65
- return (
66
- <KeypadContext.Provider value={memoizedValue}>
67
- {props.children}
68
- </KeypadContext.Provider>
69
- );
70
- }
@@ -1,16 +0,0 @@
1
- /**
2
- * React PropTypes that may be shared between components.
3
- */
4
-
5
- import PropTypes from "prop-types";
6
-
7
- // NOTE(jared): This is no longer guaranteed to be React element
8
- // @deprecated Use `KeypadAPI` Typescript interface instead.
9
- export const keypadElementPropType = PropTypes.shape({
10
- activate: PropTypes.func.isRequired,
11
- dismiss: PropTypes.func.isRequired,
12
- configure: PropTypes.func.isRequired,
13
- setCursor: PropTypes.func.isRequired,
14
- setKeyHandler: PropTypes.func.isRequired,
15
- getDOMNode: PropTypes.func.isRequired,
16
- });
@@ -1,105 +0,0 @@
1
- import {render, screen} from "@testing-library/react";
2
- import userEvent from "@testing-library/user-event";
3
- import * as React from "react";
4
- import "@testing-library/jest-dom";
5
-
6
- import Tabbar from "../tabbar";
7
-
8
- describe("<Tabbar />", () => {
9
- it("renders one tab", () => {
10
- // Arrange
11
- render(
12
- <Tabbar
13
- items={["Numbers"]}
14
- selectedItem={"Numbers"}
15
- onSelectItem={() => {}}
16
- />,
17
- );
18
-
19
- // Assert
20
- expect(screen.getByRole("tab", {name: "Numbers"})).toBeInTheDocument();
21
- });
22
-
23
- it("renders many tabs", () => {
24
- // Arrange
25
- render(
26
- <Tabbar
27
- items={["Numbers", "Extras", "Geometry", "Operators"]}
28
- selectedItem={"Numbers"}
29
- onSelectItem={() => {}}
30
- />,
31
- );
32
-
33
- // Assert
34
- expect(screen.getByRole("tab", {name: "Numbers"})).toBeInTheDocument();
35
- expect(screen.getByRole("tab", {name: "Extras"})).toBeInTheDocument();
36
- expect(screen.getByRole("tab", {name: "Geometry"})).toBeInTheDocument();
37
- expect(
38
- screen.getByRole("tab", {name: "Operators"}),
39
- ).toBeInTheDocument();
40
- });
41
-
42
- it("handles callback", () => {
43
- // Arrange
44
- const mockSelectCallback = jest.fn();
45
- render(
46
- <Tabbar
47
- items={["Numbers", "Geometry"]}
48
- selectedItem={"Numbers"}
49
- onSelectItem={mockSelectCallback}
50
- />,
51
- );
52
-
53
- // Assert
54
- userEvent.click(screen.getByRole("tab", {name: "Geometry"}));
55
- expect(mockSelectCallback).toHaveBeenCalledWith("Geometry");
56
- });
57
-
58
- it("shows dismiss button with a onClickClose callback", () => {
59
- // Arrange
60
- render(
61
- <Tabbar
62
- items={["Numbers"]}
63
- selectedItem={"Numbers"}
64
- onSelectItem={() => {}}
65
- onClickClose={() => {}}
66
- />,
67
- );
68
-
69
- // Assert
70
- expect(screen.getByRole("tab", {name: "Dismiss"})).toBeInTheDocument();
71
- });
72
-
73
- it("does not show dismiss button without onClickClose callback", () => {
74
- // Arrange
75
- render(
76
- <Tabbar
77
- items={["Numbers"]}
78
- selectedItem={"Numbers"}
79
- onSelectItem={() => {}}
80
- />,
81
- );
82
-
83
- // Assert
84
- expect(
85
- screen.queryByRole("tab", {name: "Dismiss"}),
86
- ).not.toBeInTheDocument();
87
- });
88
-
89
- it("handles onClickClose callback", () => {
90
- // Arrange
91
- const mockClickCloseCallback = jest.fn();
92
- render(
93
- <Tabbar
94
- items={["Numbers", "Geometry"]}
95
- selectedItem={"Numbers"}
96
- onSelectItem={() => {}}
97
- onClickClose={mockClickCloseCallback}
98
- />,
99
- );
100
-
101
- // Assert
102
- userEvent.click(screen.getByRole("tab", {name: "Dismiss"}));
103
- expect(mockClickCloseCallback).toHaveBeenCalled();
104
- });
105
- });