@khanacademy/math-input 4.3.1 → 5.0.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.
Files changed (42) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/components/input/math-wrapper.d.ts +2 -2
  3. package/dist/components/input/math-wrapper.js.flow +2 -4
  4. package/dist/components/input/mathquill-helpers.d.ts +1 -1
  5. package/dist/components/input/mathquill-helpers.js.flow +2 -2
  6. package/dist/components/input/mathquill-types.d.ts +270 -10
  7. package/dist/components/input/mathquill-types.js.flow +312 -10
  8. package/dist/components/keypad/index.d.ts +11 -1
  9. package/dist/components/keypad/index.js.flow +14 -1
  10. package/dist/components/keypad/shared-keys.d.ts +4 -0
  11. package/dist/components/keypad/shared-keys.js.flow +4 -0
  12. package/dist/components/tabbar/tabbar.d.ts +1 -0
  13. package/dist/components/tabbar/tabbar.js.flow +1 -0
  14. package/dist/components/tabbar/types.d.ts +1 -1
  15. package/dist/components/tabbar/types.js.flow +6 -1
  16. package/dist/es/index.js +173 -48
  17. package/dist/es/index.js.map +1 -1
  18. package/dist/index.js +173 -48
  19. package/dist/index.js.map +1 -1
  20. package/package.json +2 -1
  21. package/src/components/input/__tests__/mathquill-helpers.test.ts +105 -0
  22. package/src/components/input/math-input.tsx +1 -1
  23. package/src/components/input/math-wrapper.ts +6 -10
  24. package/src/components/input/mathquill-helpers.ts +8 -1
  25. package/src/components/input/mathquill-types.ts +308 -40
  26. package/src/components/key-handlers/__tests__/handle-jump-out.test.ts +94 -0
  27. package/src/components/key-handlers/handle-jump-out.ts +3 -2
  28. package/src/components/keypad/__tests__/keypad-v2-mathquill.test.tsx +42 -39
  29. package/src/components/keypad/__tests__/keypad.test.tsx +42 -0
  30. package/src/components/keypad/button-assets.tsx +34 -6
  31. package/src/components/keypad/index.tsx +25 -2
  32. package/src/components/keypad/keypad-mathquill.stories.tsx +19 -0
  33. package/src/components/keypad/keypad-pages/extras-page.tsx +1 -1
  34. package/src/components/keypad/keypad-pages/numbers-page.tsx +25 -16
  35. package/src/components/keypad/shared-keys.tsx +56 -8
  36. package/src/components/tabbar/__tests__/tabbar.test.tsx +54 -14
  37. package/src/components/tabbar/icons.tsx +34 -12
  38. package/src/components/tabbar/item.tsx +2 -0
  39. package/src/components/tabbar/tabbar.tsx +32 -12
  40. package/src/components/tabbar/types.ts +6 -1
  41. package/tsconfig-build.json +3 -1
  42. package/tsconfig-build.tsbuildinfo +1 -1
@@ -17,9 +17,7 @@ describe("<Tabbar />", () => {
17
17
  );
18
18
 
19
19
  // Assert
20
- expect(
21
- screen.getByRole("button", {name: "Numbers"}),
22
- ).toBeInTheDocument();
20
+ expect(screen.getByRole("tab", {name: "Numbers"})).toBeInTheDocument();
23
21
  });
24
22
 
25
23
  it("renders many tabs", () => {
@@ -33,17 +31,11 @@ describe("<Tabbar />", () => {
33
31
  );
34
32
 
35
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();
36
37
  expect(
37
- screen.getByRole("button", {name: "Numbers"}),
38
- ).toBeInTheDocument();
39
- expect(
40
- screen.getByRole("button", {name: "Extras"}),
41
- ).toBeInTheDocument();
42
- expect(
43
- screen.getByRole("button", {name: "Geometry"}),
44
- ).toBeInTheDocument();
45
- expect(
46
- screen.getByRole("button", {name: "Operators"}),
38
+ screen.getByRole("tab", {name: "Operators"}),
47
39
  ).toBeInTheDocument();
48
40
  });
49
41
 
@@ -59,7 +51,55 @@ describe("<Tabbar />", () => {
59
51
  );
60
52
 
61
53
  // Assert
62
- userEvent.click(screen.getByRole("button", {name: "Geometry"}));
54
+ userEvent.click(screen.getByRole("tab", {name: "Geometry"}));
63
55
  expect(mockSelectCallback).toHaveBeenCalledWith("Geometry");
64
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
+ });
65
105
  });
@@ -64,32 +64,54 @@ const IconAsset = function ({tintColor, type}: Props): React.ReactElement {
64
64
  case "Extras": {
65
65
  return (
66
66
  <svg
67
+ xmlns="http://www.w3.org/2000/svg"
67
68
  width="32"
68
69
  height="32"
69
- viewBox="0 0 32 32"
70
70
  fill="none"
71
- xmlns="http://www.w3.org/2000/svg"
71
+ viewBox="0 0 32 32"
72
72
  >
73
- <g
74
- clipPath="url(#clip0_4011_87172)"
75
- fillRule="evenodd"
76
- clipRule="evenodd"
77
- fill={tintColor}
78
- >
79
- <path d="M6.96605 10.5663c.21528-.0308.38682-.0477.50829-.0477.56911 0 1.09298.1467 1.56707.4407.38228.2296.68532.5084.90301.838.09208-.1207.15248-.2002.18138-.2387l.0047-.0063.0052-.0059c.5949-.6753 1.2944-1.0278 2.093-1.0278.6647 0 1.2196.1954 1.6441.6014.4361.3871.6588.8746.6588 1.45 0 .513-.1499.9563-.4578 1.3166-.3.3693-.7089.552-1.2051.552-.3307 0-.6179-.097-.8437-.304-.2288-.2097-.3392-.4865-.3392-.8103 0-.3888.1066-.7297.3291-1.0101.1474-.1857.3402-.3379.5729-.4597-.1089-.0413-.2631-.0674-.4734-.0674-.1874 0-.3034.0147-.3645.0334-.5098.2175-.9018.667-1.1616 1.3887l-.0009.0025c-.0181.0482-.0814.2776-.1937.7113-.1103.4259-.2644 1.0348-.46245 1.827-.398 1.5767-.60776 2.4474-.63636 2.6333l-.00136.0089c-.04319.2159-.06489.4313-.06489.6465 0 .3246.09331.559.26143.7271.16975.1698.39759.2614.70433.2614.5767 0 1.1059-.2376 1.5927-.7383.4978-.5273.8301-1.1009 1.0032-1.7212l.0011-.0037c.0246-.0819.0521-.156.0846-.2154.0241-.0443.0711-.1194.1545-.1578.0615-.0338.1345-.0465.1905-.0535.0726-.0091.1619-.013.2648-.013.1528 0 .2937.0152.4034.0614.0569.024.1156.0605.1606.1174.0474.0598.0703.1308.0703.2041 0 .022-.0038.0459-.0052.0547-.0023.015-.0055.0337-.0094.0554-.008.0436-.0197.104-.035.1806l-.0027.0138c-.2705.9863-.8277 1.8422-1.6623 2.5666l-.0072.0063c-.746.5872-1.5429.8884-2.3868.8884-1.03863 0-1.85432-.4315-2.43176-1.277-.43549.5807-.97515.9834-1.61932 1.1981l-.00979.0033-.01007.0022c-.15865.0353-.37406.0505-.63768.0505-.93641 0-1.63679-.3356-2.04681-1.0359C3.08287 19.9196 3 19.5787 3 19.1987c0-.5006.1515-.9365.45958-1.2959.31283-.365.71906-.5499 1.2033-.5499.35729 0 .6622.0872.87689.2969.21557.2106.30597.5111.30597.8631 0 .3146-.07482.5975-.23217.8402-.15675.2419-.38726.4314-.67931.5735-.00496.0025-.01055.0055-.01678.0089.15188.0606.31779.0917.49969.0917.44797 0 .86602-.2744 1.24399-.9286l.00246-.0043c.06785-.111.17746-.4008.32772-.9017.14728-.4909.32737-1.1618.5404-2.0139l.0005-.002c.09122-.3497.19011-.7376.29665-1.1637.10644-.4258.18171-.7498.22648-.9736l.00249-.0124c.05541-.2078.09408-.3468.11359-.4088.07445-.404.10861-.6812.10861-.8425 0-.3287-.08814-.5649-.2437-.7325-.15265-.1644-.36917-.2561-.67631-.2561-.62654 0-1.16936.2409-1.63736.7372l-.00199.0022c-.47891.4934-.81198 1.0647-1.00116 1.7162-.0166.0733-.03697.141-.06317.1987-.02519.0554-.06558.1237-.13399.1693l-.01036.0069-.01113.0056c-.03837.0192-.07945.0259-.09978.0289-.02704.0041-.05815.0069-.09148.009-.06706.0042-.15565.0061-.26391.0061h-.40284l-.05858-.0586c-.10441-.1044-.19572-.2369-.19572-.3929v-.0147l.00216-.0146c.06726-.454.32204-1.0087.73818-1.656l.00145-.0022c.74101-1.1194 1.68544-1.7837 2.83334-1.9616l.00234-.0003zM20.9726 10.5186h10.0353c.2631 0 .5155.1045.7016.2906.1861.1861.2906.4384.2906.7016s-.1045.5156-.2906.7016c-.1861.1861-.4385.2907-.7016.2907h-2.705v6.138c0 .2272.0902.445.2508.6056.1606.1606.3784.2508.6056.2508.2271 0 .4449-.0902.6055-.2508.1606-.1606.2508-.3784.2508-.6056 0-.2631.1045-.5155.2906-.7016.1861-.1861.4385-.2906.7017-.2906.2631 0 .5155.1045.7016.2906.1861.1861.2906.4385.2906.7016 0 .7535-.2993 1.4761-.8321 2.0088-.5327.5328-1.2553.8321-2.0087.8321-.7535 0-1.4761-.2993-2.0088-.8321-.5328-.5327-.8321-1.2553-.8321-2.0088v-6.138h-3.2972v7.9867c0 .2631-.1046.5155-.2906.7016-.1861.1861-.4385.2906-.7017.2906-.2631 0-.5155-.1045-.7016-.2906-.1861-.1861-.2906-.4385-.2906-.7016v-7.9867h-.0641c-.5773 0-1.131.2293-1.5392.6375-.4083.4083-.6376.9619-.6376 1.5393 0 .2631-.1045.5155-.2906.7016-.1861.1861-.4385.2906-.7017.2906-.2631 0-.5155-.1045-.7016-.2906-.1861-.1861-.2906-.4385-.2906-.7016.0013-1.1032.4401-2.1611 1.2201-2.9412.7801-.7801 1.838-1.2189 2.9412-1.2201z" />
73
+ <g clipPath="url(#a)">
74
+ <path
75
+ fill={tintColor}
76
+ fillRule="evenodd"
77
+ d="M6.127 10.454c.224-.032.403-.05.53-.05.591 0 1.137.153 1.63.459.398.239.713.529.94.872l.188-.248.005-.007.006-.006c.619-.703 1.347-1.07 2.178-1.07.691 0 1.269.204 1.71.626.454.403.686.91.686 1.51 0 .533-.156.994-.476 1.37-.312.383-.738.574-1.254.574-.345 0-.643-.101-.878-.317a1.1 1.1 0 0 1-.353-.843c0-.405.11-.76.342-1.051.153-.193.354-.352.596-.479a1.416 1.416 0 0 0-.492-.07c-.195 0-.316.016-.38.035-.53.226-.938.694-1.208 1.445l-.001.003c-.02.05-.085.289-.202.74-.115.443-.275 1.077-.481 1.901-.414 1.641-.633 2.547-.662 2.74l-.002.01a3.423 3.423 0 0 0-.067.673c0 .337.097.581.272.756.176.177.413.272.733.272.6 0 1.15-.247 1.657-.768.518-.549.864-1.146 1.044-1.791l.001-.004a1.2 1.2 0 0 1 .088-.224.368.368 0 0 1 .161-.164.564.564 0 0 1 .198-.056 2.19 2.19 0 0 1 .276-.014c.159 0 .305.016.42.064.059.025.12.063.167.122.05.063.073.137.073.213 0 .023-.004.048-.005.057a12.52 12.52 0 0 1-.046.245l-.004.015c-.281 1.026-.86 1.917-1.73 2.67l-.007.007c-.776.611-1.605.925-2.484.925-1.08 0-1.93-.45-2.53-1.33-.453.605-1.015 1.024-1.685 1.248l-.01.003-.011.002a3.23 3.23 0 0 1-.664.053c-.974 0-1.703-.35-2.13-1.078A2.05 2.05 0 0 1 2 19.437c0-.52.158-.975.478-1.349.326-.38.749-.572 1.252-.572.372 0 .69.091.913.31.224.218.318.531.318.898 0 .327-.078.621-.241.874a1.706 1.706 0 0 1-.707.597l-.018.009c.158.063.331.095.52.095.467 0 .902-.285 1.295-.966l.002-.005c.071-.115.185-.417.341-.938.154-.51.341-1.209.563-2.096v-.002c.095-.364.198-.767.31-1.21.11-.444.188-.78.235-1.014l.002-.013c.058-.216.098-.36.119-.425.077-.42.113-.709.113-.877 0-.342-.092-.588-.254-.762-.159-.171-.384-.267-.704-.267-.652 0-1.217.251-1.704.768l-.002.002A4.215 4.215 0 0 0 3.79 14.28a1.084 1.084 0 0 1-.065.207.41.41 0 0 1-.14.176l-.01.007-.012.006a.35.35 0 0 1-.104.03 1.16 1.16 0 0 1-.095.01 5.04 5.04 0 0 1-.275.006H2.67l-.061-.061c-.109-.11-.204-.247-.204-.41v-.015l.003-.015c.07-.472.335-1.05.768-1.723l.001-.002c.771-1.165 1.754-1.857 2.949-2.042h.002Z"
78
+ clipRule="evenodd"
79
+ />
80
+ <path
81
+ fill={tintColor}
82
+ d="M21.084 10.284c.932-.008 2.301-.013 4.107-.013 1.325 0 2.327.003 3.007.007a75.812 75.812 0 0 1 .99.013c.025 0 .047.002.065.003h.002c.01 0 .04.003.067.01l.01.002.011.004c.201.07.37.183.488.347a.966.966 0 0 1 .169.574c0 .3-.078.568-.248.79-.168.221-.411.377-.708.479h-.002a1.01 1.01 0 0 1-.221.034 8.213 8.213 0 0 1-.35.016c-.29.008-.696.012-1.219.012h-1.39l-.038.223v.001c-.198 1.185-.295 2.156-.295 2.916 0 1.446.251 2.746.75 3.905l.004.007c.059.153.105.284.137.393.03.103.053.205.053.29 0 .359-.16.68-.44.961-.278.296-.63.445-1.041.445-.255 0-.492-.03-.654-.139l-.009-.006-.008-.006c-.126-.101-.236-.274-.338-.477l-.006-.012c-.331-.768-.49-1.722-.49-2.852 0-.595.007-1.002.025-1.212v-.005c.118-1.157.377-2.551.776-4.18v-.002c.024-.096.045-.18.061-.25h-1.948c-.008.038-.02.086-.034.143l-.002.007a35.14 35.14 0 0 0-.146.537c-.05.232-.1.448-.15.648v.001a230.673 230.673 0 0 1-1.312 4.936 41.285 41.285 0 0 1-.411 1.384c-.104.322-.19.557-.256.681-.115.262-.28.473-.5.617-.225.146-.49.212-.783.212-.449 0-.807-.173-1.006-.549l-.006-.011-.005-.012a1.37 1.37 0 0 1-.067-.486v-.326l.346-.745c1.24-2.61 2.136-4.858 2.695-6.747l.002-.008.094-.281h-.463c-.662 0-1.105.025-1.346.07-.198.04-.47.173-.824.43l-.007.005-.007.005c-.366.228-.69.542-.97.947-.044.069-.085.13-.125.18a.651.651 0 0 1-.141.136l-.027.017-.03.01a.8.8 0 0 1-.19.03c-.07.005-.156.008-.258.008-.17 0-.335-.021-.465-.09a.437.437 0 0 1-.216-.546c.014-.042.034-.086.057-.132.047-.093.113-.208.198-.343l.003-.005c1.147-1.745 2.311-2.774 3.508-2.96a2.345 2.345 0 0 1 .158-.015 60.295 60.295 0 0 1 1.369-.026Z"
83
+ />
80
84
  </g>
81
85
  <defs>
82
- <clipPath id="clip0_4011_87172">
86
+ <clipPath id="a">
83
87
  <path
84
88
  fill="#fff"
85
- transform="translate(3 10.5186)"
86
- d="M0 0h29v10.9635H0z"
89
+ d="M0 0h28v11.457H0z"
90
+ transform="translate(2 10.271)"
87
91
  />
88
92
  </clipPath>
89
93
  </defs>
90
94
  </svg>
91
95
  );
92
96
  }
97
+ case "Dismiss": {
98
+ return (
99
+ <svg
100
+ width="44"
101
+ height="44"
102
+ viewBox="0 0 44 44"
103
+ fill="none"
104
+ xmlns="http://www.w3.org/2000/svg"
105
+ >
106
+ <path
107
+ fillRule="evenodd"
108
+ clipRule="evenodd"
109
+ d="M28.7071 15.2929C28.3166 14.9024 27.6834 14.9024 27.2929 15.2929L22 20.5858L16.7071 15.2929C16.3166 14.9024 15.6834 14.9024 15.2929 15.2929C14.9024 15.6834 14.9024 16.3166 15.2929 16.7071L20.5858 22L15.2929 27.2929C14.9024 27.6834 14.9024 28.3166 15.2929 28.7071C15.6834 29.0976 16.3166 29.0976 16.7071 28.7071L22 23.4142L27.2929 28.7071C27.6834 29.0976 28.3166 29.0976 28.7071 28.7071C29.0976 28.3166 29.0976 27.6834 28.7071 27.2929L23.4142 22L28.7071 16.7071C29.0976 16.3166 29.0976 15.6834 28.7071 15.2929Z"
110
+ fill={tintColor}
111
+ />
112
+ </svg>
113
+ );
114
+ }
93
115
  default: {
94
116
  // type as never;
95
117
  throw new Error("Invalid icon type");
@@ -84,6 +84,8 @@ class TabbarItem extends React.Component<Props> {
84
84
  onClick={onClick}
85
85
  disabled={itemState === "disabled"}
86
86
  aria-label={itemType}
87
+ aria-selected={itemState === "active"}
88
+ role="tab"
87
89
  >
88
90
  {({hovered, focused, pressed}) => {
89
91
  const tintColor = imageTintColor(
@@ -9,33 +9,53 @@ const styles = StyleSheet.create({
9
9
  tabbar: {
10
10
  display: "flex",
11
11
  flexDirection: "row",
12
+ justifyContent: "space-between",
12
13
  paddingTop: 2,
13
14
  paddingBottom: 2,
14
15
  },
16
+ pages: {
17
+ display: "flex",
18
+ flexDirection: "row",
19
+ },
15
20
  });
16
21
 
17
22
  type Props = {
18
23
  items: ReadonlyArray<TabbarItemType>;
19
24
  selectedItem: TabbarItemType;
25
+ onClickClose?: () => void;
20
26
  onSelectItem: (item: TabbarItemType) => void;
21
27
  style?: StyleType;
22
28
  };
23
29
 
24
30
  function Tabbar(props: Props): React.ReactElement {
25
- const {items, selectedItem, onSelectItem, style} = props;
31
+ const {items, onClickClose, selectedItem, onSelectItem, style} = props;
26
32
 
27
33
  return (
28
- <View style={[styles.tabbar, style]}>
29
- {items.map((item) => (
30
- <TabbarItem
31
- key={`tabbar-item-${item}`}
32
- itemState={item === selectedItem ? "active" : "inactive"}
33
- itemType={item}
34
- onClick={() => {
35
- onSelectItem(item);
36
- }}
37
- />
38
- ))}
34
+ <View style={[styles.tabbar, style]} role="tablist">
35
+ <View style={[styles.pages]}>
36
+ {items.map((item) => (
37
+ <TabbarItem
38
+ key={`tabbar-item-${item}`}
39
+ itemState={
40
+ item === selectedItem ? "active" : "inactive"
41
+ }
42
+ itemType={item}
43
+ onClick={() => {
44
+ onSelectItem(item);
45
+ }}
46
+ />
47
+ ))}
48
+ </View>
49
+
50
+ <View>
51
+ {onClickClose && (
52
+ <TabbarItem
53
+ itemState="inactive"
54
+ itemType="Dismiss"
55
+ onClick={onClickClose}
56
+ />
57
+ )}
58
+ </View>
39
59
  </View>
40
60
  );
41
61
  }
@@ -1 +1,6 @@
1
- export type TabbarItemType = "Geometry" | "Operators" | "Numbers" | "Extras";
1
+ export type TabbarItemType =
2
+ | "Geometry"
3
+ | "Operators"
4
+ | "Numbers"
5
+ | "Extras"
6
+ | "Dismiss";
@@ -4,5 +4,7 @@
4
4
  "outDir": "./dist",
5
5
  "rootDir": "src",
6
6
  },
7
- "references": []
7
+ "references": [
8
+ {"path": "../perseus-core/tsconfig-build.json"},
9
+ ]
8
10
  }