@khanacademy/math-input 8.1.1 → 8.1.3

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 (45) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/components/input/mathquill-types.d.ts +1 -1
  3. package/dist/components/input/mathquill-types.js.flow +4 -1
  4. package/dist/components/keypad/mobile-keypad.d.ts +2 -2
  5. package/dist/components/keypad/mobile-keypad.js.flow +1 -1
  6. package/dist/components/keypad-legacy/compute-layout-parameters.d.ts +6 -17
  7. package/dist/components/keypad-legacy/compute-layout-parameters.js.flow +13 -22
  8. package/dist/components/keypad-legacy/keypad-container.d.ts +2 -1
  9. package/dist/components/keypad-legacy/keypad-container.js.flow +7 -1
  10. package/dist/components/keypad-legacy/store/actions.d.ts +5 -3
  11. package/dist/components/keypad-legacy/store/actions.js.flow +8 -4
  12. package/dist/components/keypad-legacy/store/types.d.ts +14 -14
  13. package/dist/components/keypad-legacy/store/types.js.flow +14 -14
  14. package/dist/components/prop-types.d.ts +12 -0
  15. package/dist/components/prop-types.js.flow +17 -0
  16. package/dist/es/index.css +1 -1
  17. package/dist/es/index.js +133 -132
  18. package/dist/es/index.js.map +1 -1
  19. package/dist/fake-react-native-web/view.d.ts +1 -0
  20. package/dist/fake-react-native-web/view.js.flow +1 -0
  21. package/dist/index.css +1 -1
  22. package/dist/index.d.ts +1 -0
  23. package/dist/index.js +131 -134
  24. package/dist/index.js.flow +1 -0
  25. package/dist/index.js.map +1 -1
  26. package/index.html +17 -16
  27. package/less/echo.less +1 -1
  28. package/less/overrides.less +1 -1
  29. package/package.json +1 -1
  30. package/src/components/input/math-input.tsx +1 -0
  31. package/src/components/input/mathquill-types.ts +4 -1
  32. package/src/components/keypad/keypad-button.tsx +5 -3
  33. package/src/components/keypad/mobile-keypad.tsx +12 -2
  34. package/src/components/keypad-legacy/compute-layout-parameters.ts +127 -78
  35. package/src/components/keypad-legacy/keypad-button.tsx +2 -2
  36. package/src/components/keypad-legacy/keypad-container.tsx +30 -4
  37. package/src/components/keypad-legacy/store/actions.ts +12 -6
  38. package/src/components/keypad-legacy/store/layout-reducer.test.ts +171 -0
  39. package/src/components/keypad-legacy/store/layout-reducer.ts +46 -51
  40. package/src/components/keypad-legacy/store/types.ts +16 -14
  41. package/src/components/{prop-types.js → prop-types.ts} +1 -0
  42. package/src/fake-react-native-web/view.tsx +2 -0
  43. package/src/full-math-input.stories.tsx +2 -2
  44. package/src/index.ts +1 -0
  45. package/tsconfig-build.tsbuildinfo +1 -1
package/index.html CHANGED
@@ -1,20 +1,21 @@
1
1
  <!DOCTYPE html>
2
2
  <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
6
+ <title>Math Input</title>
7
+ <link
8
+ rel="stylesheet"
9
+ href="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css"
10
+ />
11
+ <style>
12
+ body {
13
+ margin: 0;
14
+ }
15
+ </style>
16
+ </head>
3
17
 
4
- <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1">
7
- <title>Math Input</title>
8
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.11.1/dist/katex.min.css">
9
- <style>
10
- body {
11
- margin: 0;
12
- }
13
- </style>
14
- </head>
15
-
16
- <body>
17
- <div id="root"></div>
18
- </body>
19
-
18
+ <body>
19
+ <div id="root"></div>
20
+ </body>
20
21
  </html>
package/less/echo.less CHANGED
@@ -29,7 +29,7 @@
29
29
  * displacement.
30
30
  */
31
31
  transition: transform 800ms cubic-bezier(0, 1, 0.25, 1),
32
- opacity 400ms cubic-bezier(1, 0, 0.9, 1) !important;
32
+ opacity 400ms cubic-bezier(1, 0, 0.9, 1) !important;
33
33
  }
34
34
  }
35
35
 
@@ -96,7 +96,7 @@
96
96
  .mq-hasCursor:empty:not(.mq-root-block):after {
97
97
  // Place a 'c' inside for sizing the cursor (for the case explained
98
98
  // above); normally, MathQuill already does this for .mq-cursor.
99
- content: 'c';
99
+ content: "c";
100
100
  }
101
101
 
102
102
  .mq-math-mode .mq-selection,
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Khan Academy's new expression editor for the mobile web.",
4
4
  "author": "Khan Academy",
5
5
  "license": "MIT",
6
- "version": "8.1.1",
6
+ "version": "8.1.3",
7
7
  "publishConfig": {
8
8
  "access": "public"
9
9
  },
@@ -1,3 +1,4 @@
1
+ /* eslint-disable @khanacademy/ts-no-error-suppressions */
1
2
  import Color from "@khanacademy/wonder-blocks-color";
2
3
  import * as i18n from "@khanacademy/wonder-blocks-i18n";
3
4
  import {entries} from "@khanacademy/wonder-stuff-core";
@@ -167,7 +167,10 @@ export type MathFieldConfig = {
167
167
  edit?: (mathField: MathFieldInterface) => void;
168
168
  enter?: (mathField: MathFieldInterface) => void;
169
169
 
170
- moveOutOf?: (mathField: MathFieldInterface) => void;
170
+ moveOutOf?: (
171
+ direction: MathQuillDirection,
172
+ mathField: MathFieldInterface,
173
+ ) => void;
171
174
  upOutOf?: (mathField: MathFieldInterface) => void;
172
175
  downOutOf?: (mathField: MathFieldInterface) => void;
173
176
 
@@ -78,19 +78,21 @@ const styles = StyleSheet.create({
78
78
  boxSizing: "border-box",
79
79
  background: Color.white,
80
80
  borderRadius: 4,
81
- border: `1px solid transparent`,
81
+ borderWidth: 2,
82
+ borderStyle: "solid",
83
+ borderColor: "transparent",
82
84
  flex: 1,
83
85
  minHeight: 42,
84
86
  minWidth: 42,
85
87
  padding: 1,
86
88
  },
87
89
  hovered: {
88
- border: `2px solid ${Color.blue}`,
90
+ borderColor: Color.blue,
89
91
  padding: 1,
90
92
  boxShadow: "none",
91
93
  },
92
94
  focused: {
93
- border: `2px solid ${Color.blue}`,
95
+ borderColor: Color.blue,
94
96
  padding: 0,
95
97
  boxShadow: "none",
96
98
  },
@@ -3,9 +3,15 @@ import {StyleSheet} from "aphrodite";
3
3
  import * as React from "react";
4
4
  import ReactDOM from "react-dom";
5
5
 
6
- import Key from "../../data/keys";
7
6
  import {View} from "../../fake-react-native-web/index";
8
- import {Cursor, KeypadConfiguration, KeyHandler, KeypadAPI} from "../../types";
7
+
8
+ import type Key from "../../data/keys";
9
+ import type {
10
+ Cursor,
11
+ KeypadConfiguration,
12
+ KeyHandler,
13
+ KeypadAPI,
14
+ } from "../../types";
9
15
 
10
16
  import Keypad from "./index";
11
17
 
@@ -91,11 +97,15 @@ class MobileKeypad extends React.Component<Props, State> implements KeypadAPI {
91
97
  }
92
98
 
93
99
  render(): React.ReactNode {
100
+ const {style} = this.props;
94
101
  const {active, cursor, keypadConfig} = this.state;
95
102
 
96
103
  const containerStyle = [
104
+ // internal styles
97
105
  styles.keypadContainer,
98
106
  active ? styles.activeKeypadContainer : null,
107
+ // styles passed as props
108
+ ...(Array.isArray(style) ? style : [style]),
99
109
  ];
100
110
 
101
111
  const isExpression = keypadConfig?.keypadType === "EXPRESSION";
@@ -19,7 +19,7 @@
19
19
  * might need to be.
20
20
  */
21
21
 
22
- import {DeviceType, DeviceOrientation, LayoutMode} from "../../enums";
22
+ import {DeviceOrientation, LayoutMode} from "../../enums";
23
23
  import {
24
24
  pageIndicatorHeightPx,
25
25
  toolbarHeightPx,
@@ -27,6 +27,8 @@ import {
27
27
  innerBorderWidthPx,
28
28
  } from "../common-style";
29
29
 
30
+ import {GridDimensions, WidthHeight} from "./store/types";
31
+
30
32
  const minButtonHeight = 48;
31
33
  const maxButtonSize = 64;
32
34
  const minSpaceAboveKeypad = 32;
@@ -54,88 +56,135 @@ const maxPortraitBrowserChrome =
54
56
  // difference when reserving space above the keypad.)
55
57
  const worstCaseAspectRatio = 320 / (480 - safariNavBarWhenShrunk);
56
58
 
59
+ type ComputedLayoutProperty = {
60
+ buttonDimensions: WidthHeight;
61
+ layoutMode: LayoutMode;
62
+ };
63
+
64
+ function getButtonWidth(
65
+ gridDimensions: GridDimensions,
66
+ containerDimensions: WidthHeight,
67
+ navigationPadEnabled: boolean,
68
+ paginationEnabled: boolean,
69
+ isLandscape: boolean,
70
+ ): number {
71
+ const {numColumns, numPages} = gridDimensions;
72
+
73
+ // We can use the container width as the effective width.
74
+ let effectiveWidth = containerDimensions.width;
75
+ if (navigationPadEnabled) {
76
+ effectiveWidth -= navigationPadWidthPx;
77
+ }
78
+
79
+ let buttonWidthPx;
80
+ if (numPages > 1) {
81
+ const effectiveNumColumns = paginationEnabled
82
+ ? numColumns
83
+ : numColumns * numPages;
84
+ buttonWidthPx = effectiveWidth / effectiveNumColumns;
85
+ } else {
86
+ buttonWidthPx = isLandscape
87
+ ? maxButtonSize
88
+ : effectiveWidth / numColumns;
89
+ }
90
+
91
+ return buttonWidthPx;
92
+ }
93
+
94
+ function getButtonHeight(
95
+ gridDimensions: GridDimensions,
96
+ pageDimensions: WidthHeight,
97
+ containerDimensions: WidthHeight,
98
+ paginationEnabled: boolean,
99
+ toolbarEnabled: boolean,
100
+ isLandscape: boolean,
101
+ ) {
102
+ const {numMaxVisibleRows} = gridDimensions;
103
+
104
+ // In many cases, the browser chrome will already have been factored
105
+ // into `pageHeight`. But we have no way of knowing if that's
106
+ // the case or not. As such, we take a conservative approach and
107
+ // assume that the chrome is _never_ included in `pageHeight`.
108
+ const browserChromeHeight = isLandscape
109
+ ? maxLandscapeBrowserChrome
110
+ : maxPortraitBrowserChrome;
111
+
112
+ // Count up all the space that we need to reserve on the page.
113
+ // Namely, we need to account for:
114
+ // 1. Space between the keypad and the top of the page.
115
+ // 2. The presence of the exercise toolbar.
116
+ // 3. The presence of the view pager indicator.
117
+ // 4. Any browser chrome that may appear later.
118
+ const reservedSpace =
119
+ minSpaceAboveKeypad +
120
+ browserChromeHeight +
121
+ (toolbarEnabled ? toolbarHeightPx : 0) +
122
+ (paginationEnabled ? pageIndicatorHeightPx : 0);
123
+
124
+ // For the height, we take
125
+ // another conservative measure when in portrait by assuming that
126
+ // the device has the worst possible aspect ratio. In other words,
127
+ // we ignore the device height in portrait and assume the worst.
128
+ // This prevents the keypad from changing size when browser chrome
129
+ // appears and disappears.
130
+ const effectiveHeight = isLandscape
131
+ ? pageDimensions.height
132
+ : containerDimensions.width / worstCaseAspectRatio;
133
+
134
+ // In computing the
135
+ // height, accommodate for the maximum number of rows that will ever be
136
+ // visible (since the toggling of popovers can increase the number of
137
+ // visible rows).
138
+ const maxKeypadHeight = effectiveHeight - reservedSpace;
139
+
140
+ const buttonHeightPx = Math.max(
141
+ Math.min(maxKeypadHeight / numMaxVisibleRows, maxButtonSize),
142
+ minButtonHeight,
143
+ );
144
+
145
+ return buttonHeightPx;
146
+ }
147
+
57
148
  export const computeLayoutParameters = (
58
- {numColumns, numMaxVisibleRows, numPages},
59
- {pageWidthPx, pageHeightPx},
60
- {deviceOrientation, deviceType},
61
- {navigationPadEnabled, paginationEnabled, toolbarEnabled},
62
- ) => {
149
+ gridDimensions: GridDimensions,
150
+ pageDimensions: WidthHeight,
151
+ containerDimensions: WidthHeight,
152
+ deviceOrientation: DeviceOrientation,
153
+ navigationPadEnabled: boolean,
154
+ paginationEnabled: boolean,
155
+ toolbarEnabled: boolean,
156
+ ): ComputedLayoutProperty => {
157
+ const {numColumns, numPages} = gridDimensions;
158
+
63
159
  // First, compute some values that will be used in multiple computations.
64
160
  const effectiveNumColumns = paginationEnabled
65
161
  ? numColumns
66
162
  : numColumns * numPages;
67
163
 
68
164
  // Then, compute the button dimensions based on the provided parameters.
69
- let buttonDimensions;
70
- if (deviceType === DeviceType.PHONE) {
71
- const isLandscape = deviceOrientation === DeviceOrientation.LANDSCAPE;
72
-
73
- // In many cases, the browser chrome will already have been factored
74
- // into `pageHeightPx`. But we have no way of knowing if that's
75
- // the case or not. As such, we take a conservative approach and
76
- // assume that the chrome is _never_ included in `pageHeightPx`.
77
- const browserChromeHeight = isLandscape
78
- ? maxLandscapeBrowserChrome
79
- : maxPortraitBrowserChrome;
80
-
81
- // Count up all the space that we need to reserve on the page.
82
- // Namely, we need to account for:
83
- // 1. Space between the keypad and the top of the page.
84
- // 2. The presence of the exercise toolbar.
85
- // 3. The presence of the view pager indicator.
86
- // 4. Any browser chrome that may appear later.
87
- const reservedSpace =
88
- minSpaceAboveKeypad +
89
- browserChromeHeight +
90
- (toolbarEnabled ? toolbarHeightPx : 0) +
91
- (paginationEnabled ? pageIndicatorHeightPx : 0);
92
-
93
- // Next, compute the effective width and height. We can use the page
94
- // width as the effective width. For the height, though, we take
95
- // another conservative measure when in portrait by assuming that
96
- // the device has the worst possible aspect ratio. In other words,
97
- // we ignore the device height in portrait and assume the worst.
98
- // This prevents the keypad from changing size when browser chrome
99
- // appears and disappears.
100
- const effectiveWidth = pageWidthPx;
101
- const effectiveHeight = isLandscape
102
- ? pageHeightPx
103
- : pageWidthPx / worstCaseAspectRatio;
104
- const maxKeypadHeight = effectiveHeight - reservedSpace;
105
-
106
- // Finally, compute the button height and width. In computing the
107
- // height, accommodate for the maximum number of rows that will ever be
108
- // visible (since the toggling of popovers can increase the number of
109
- // visible rows).
110
- const buttonHeightPx = Math.max(
111
- Math.min(maxKeypadHeight / numMaxVisibleRows, maxButtonSize),
112
- minButtonHeight,
113
- );
114
-
115
- let buttonWidthPx;
116
- if (numPages > 1) {
117
- const effectiveNumColumns = paginationEnabled
118
- ? numColumns
119
- : numColumns * numPages;
120
- buttonWidthPx = effectiveWidth / effectiveNumColumns;
121
- } else {
122
- buttonWidthPx = isLandscape
123
- ? maxButtonSize
124
- : effectiveWidth / numColumns;
125
- }
126
-
127
- buttonDimensions = {
128
- widthPx: buttonWidthPx,
129
- heightPx: buttonHeightPx,
130
- };
131
- } else if (deviceType === DeviceType.TABLET) {
132
- buttonDimensions = {
133
- widthPx: maxButtonSize,
134
- heightPx: maxButtonSize,
135
- };
136
- } else {
137
- throw new Error("Invalid device type: " + deviceType);
138
- }
165
+ const isLandscape = deviceOrientation === DeviceOrientation.LANDSCAPE;
166
+
167
+ const buttonWidth = getButtonWidth(
168
+ gridDimensions,
169
+ containerDimensions,
170
+ navigationPadEnabled,
171
+ paginationEnabled,
172
+ isLandscape,
173
+ );
174
+
175
+ const buttonHeight = getButtonHeight(
176
+ gridDimensions,
177
+ pageDimensions,
178
+ containerDimensions,
179
+ paginationEnabled,
180
+ toolbarEnabled,
181
+ isLandscape,
182
+ );
183
+
184
+ const buttonDimensions = {
185
+ width: buttonWidth,
186
+ height: buttonHeight,
187
+ };
139
188
 
140
189
  // Finally, determine whether the keypad should be rendered in the
141
190
  // fullscreen layout by determining its resultant width.
@@ -143,13 +192,13 @@ export const computeLayoutParameters = (
143
192
  (navigationPadEnabled ? 1 : 0) +
144
193
  (!paginationEnabled ? numPages - 1 : 0);
145
194
  const keypadWidth =
146
- effectiveNumColumns * buttonDimensions.widthPx +
195
+ effectiveNumColumns * buttonDimensions.width +
147
196
  (navigationPadEnabled ? navigationPadWidthPx : 0) +
148
197
  numSeparators * innerBorderWidthPx;
149
198
  return {
150
199
  buttonDimensions,
151
200
  layoutMode:
152
- keypadWidth >= pageWidthPx
201
+ keypadWidth >= containerDimensions.width
153
202
  ? LayoutMode.FULLSCREEN
154
203
  : LayoutMode.COMPACT,
155
204
  };
@@ -356,8 +356,8 @@ const styleForButtonDimensions = (heightPx, widthPx) => {
356
356
 
357
357
  const mapStateToProps = (state: State): ReduxProps => {
358
358
  return {
359
- heightPx: state.layout.buttonDimensions.heightPx,
360
- widthPx: state.layout.buttonDimensions.widthPx,
359
+ heightPx: state.layout.buttonDimensions.height,
360
+ widthPx: state.layout.buttonDimensions.width,
361
361
  };
362
362
  };
363
363
 
@@ -34,7 +34,12 @@ interface ReduxProps {
34
34
  interface Props extends ReduxProps {
35
35
  onDismiss?: () => void;
36
36
  onElementMounted: (element: any) => void;
37
- onPageSizeChange?: (width: number, height: number) => void;
37
+ onPageSizeChange?: (
38
+ pageWidth: number,
39
+ pageHeight: number,
40
+ containerWidth: number,
41
+ containerHeight: number,
42
+ ) => void;
38
43
  style?: StyleType;
39
44
  }
40
45
 
@@ -45,6 +50,7 @@ type State = {
45
50
 
46
51
  // eslint-disable-next-line react/no-unsafe
47
52
  class KeypadContainer extends React.Component<Props, State> {
53
+ _containerRef = React.createRef<HTMLDivElement>();
48
54
  _resizeTimeout: number | null | undefined;
49
55
  hasMounted: boolean | undefined;
50
56
 
@@ -113,7 +119,14 @@ class KeypadContainer extends React.Component<Props, State> {
113
119
  this.setState({
114
120
  viewportWidth: window.innerWidth,
115
121
  });
116
- this.props.onPageSizeChange?.(window.innerWidth, window.innerHeight);
122
+ const containerWidth = this._containerRef.current?.clientWidth || 0;
123
+ const containerHeight = this._containerRef.current?.clientHeight || 0;
124
+ this.props.onPageSizeChange?.(
125
+ window.innerWidth,
126
+ window.innerHeight,
127
+ containerWidth,
128
+ containerHeight,
129
+ );
117
130
  };
118
131
 
119
132
  renderKeypad = () => {
@@ -198,6 +211,7 @@ class KeypadContainer extends React.Component<Props, State> {
198
211
  style={keypadContainerStyle}
199
212
  dynamicStyle={dynamicStyle}
200
213
  extraClassName="keypad-container"
214
+ forwardRef={this._containerRef}
201
215
  >
202
216
  <View
203
217
  style={keypadStyle}
@@ -305,8 +319,20 @@ const mapStateToProps = (state: ReduxState): ReduxProps => {
305
319
 
306
320
  const mapDispatchToProps = (dispatch) => {
307
321
  return {
308
- onPageSizeChange: (pageWidthPx, pageHeightPx) => {
309
- dispatch(setPageSize(pageWidthPx, pageHeightPx));
322
+ onPageSizeChange: (
323
+ pageWidth: number,
324
+ pageHeight: number,
325
+ containerWidth: number,
326
+ containerHeight: number,
327
+ ) => {
328
+ dispatch(
329
+ setPageSize(
330
+ pageWidth,
331
+ pageHeight,
332
+ containerWidth,
333
+ containerHeight,
334
+ ),
335
+ );
310
336
  },
311
337
  };
312
338
  };
@@ -51,18 +51,24 @@ export const configureKeypad = (
51
51
 
52
52
  type SetPageSizeAction = {
53
53
  type: "SetPageSize";
54
- pageWidthPx: number;
55
- pageHeightPx: number;
54
+ pageWidth: number;
55
+ pageHeight: number;
56
+ containerWidth: number;
57
+ containerHeight: number;
56
58
  };
57
59
 
58
60
  export const setPageSize = (
59
- pageWidthPx: number,
60
- pageHeightPx: number,
61
+ pageWidth: number,
62
+ pageHeight: number,
63
+ containerWidth: number,
64
+ containerHeight: number,
61
65
  ): SetPageSizeAction => {
62
66
  return {
63
67
  type: "SetPageSize",
64
- pageWidthPx,
65
- pageHeightPx,
68
+ pageWidth,
69
+ pageHeight,
70
+ containerWidth,
71
+ containerHeight,
66
72
  };
67
73
  };
68
74
 
@@ -0,0 +1,171 @@
1
+ import {KeypadType} from "../../../enums";
2
+
3
+ import {configureKeypad, setPageSize} from "./actions";
4
+ import layoutReducer from "./layout-reducer";
5
+
6
+ function initState() {
7
+ // This is just simulating the Redux action that initializes state
8
+ // @ts-expect-error TS2345
9
+ let state = layoutReducer(undefined, {type: "@redux-init"});
10
+ state = layoutReducer(
11
+ state,
12
+ configureKeypad({keypadType: KeypadType.EXPRESSION}),
13
+ );
14
+ return state;
15
+ }
16
+
17
+ describe("layout reducer", () => {
18
+ it("enables pagination on small screens portrait (iPhone)", () => {
19
+ // Arrange
20
+ let state = initState();
21
+
22
+ // Act
23
+ state = layoutReducer(state, setPageSize(375, 812, 375, 812));
24
+
25
+ // Assert
26
+ expect(state.paginationEnabled).toBe(true);
27
+ });
28
+
29
+ it("does not enable navigation pad on small screens portrait (iPhone)", () => {
30
+ // Arrange
31
+ let state = initState();
32
+
33
+ // Act
34
+ state = layoutReducer(state, setPageSize(375, 812, 375, 812));
35
+
36
+ // Assert
37
+ expect(state.navigationPadEnabled).toBe(false);
38
+ });
39
+
40
+ it("does not enable pagination on medium screens portrait (iPad Mini)", () => {
41
+ // Arrange
42
+ let state = initState();
43
+
44
+ // Act
45
+ state = layoutReducer(state, setPageSize(768, 1024, 768, 1024));
46
+
47
+ // Assert
48
+ expect(state.paginationEnabled).toBe(false);
49
+ });
50
+
51
+ it("does not enable navigation pad on medium screens portrait (iPad Mini)", () => {
52
+ // Arrange
53
+ let state = initState();
54
+
55
+ // Act
56
+ state = layoutReducer(state, setPageSize(768, 1024, 768, 1024));
57
+
58
+ // Assert
59
+ expect(state.navigationPadEnabled).toBe(false);
60
+ });
61
+
62
+ it("does not enable pagination on large screens portrait (iPad)", () => {
63
+ // Arrange
64
+ let state = initState();
65
+
66
+ // Act
67
+ state = layoutReducer(state, setPageSize(810, 1080, 810, 1080));
68
+
69
+ // Assert
70
+ expect(state.paginationEnabled).toBe(false);
71
+ });
72
+
73
+ it("does enable navigation pad on large screens portrait (iPad)", () => {
74
+ // Arrange
75
+ let state = initState();
76
+
77
+ // Act
78
+ state = layoutReducer(state, setPageSize(810, 1080, 810, 1080));
79
+
80
+ // Assert
81
+ expect(state.navigationPadEnabled).toBe(true);
82
+ });
83
+
84
+ it("does not enable pagination on small screens landscape (iPhone)", () => {
85
+ // Arrange
86
+ let state = initState();
87
+
88
+ // Act
89
+ state = layoutReducer(state, setPageSize(812, 375, 812, 375));
90
+
91
+ // Assert
92
+ expect(state.paginationEnabled).toBe(false);
93
+ });
94
+
95
+ it("does enable navigation pad on small screens landscape (iPhone)", () => {
96
+ // Arrange
97
+ let state = initState();
98
+
99
+ // Act
100
+ state = layoutReducer(state, setPageSize(812, 375, 812, 375));
101
+
102
+ // Assert
103
+ expect(state.navigationPadEnabled).toBe(true);
104
+ });
105
+
106
+ it("does not enable pagination on medium screens landscape (iPad Mini)", () => {
107
+ // Arrange
108
+ let state = initState();
109
+
110
+ // Act
111
+ state = layoutReducer(state, setPageSize(1024, 768, 1024, 768));
112
+
113
+ // Assert
114
+ expect(state.paginationEnabled).toBe(false);
115
+ });
116
+
117
+ it("does enable navigation pad on medium screens landscape (iPad Mini)", () => {
118
+ // Arrange
119
+ let state = initState();
120
+
121
+ // Act
122
+ state = layoutReducer(state, setPageSize(1024, 768, 1024, 768));
123
+
124
+ // Assert
125
+ expect(state.navigationPadEnabled).toBe(true);
126
+ });
127
+
128
+ it("does not enable pagination on large screens landscape (iPad)", () => {
129
+ // Arrange
130
+ let state = initState();
131
+
132
+ // Act
133
+ state = layoutReducer(state, setPageSize(1080, 810, 1080, 810));
134
+
135
+ // Assert
136
+ expect(state.paginationEnabled).toBe(false);
137
+ });
138
+
139
+ it("does enable navigation pad on large screens landscape (iPad)", () => {
140
+ // Arrange
141
+ let state = initState();
142
+
143
+ // Act
144
+ state = layoutReducer(state, setPageSize(1080, 810, 1080, 810));
145
+
146
+ // Assert
147
+ expect(state.navigationPadEnabled).toBe(true);
148
+ });
149
+
150
+ it("does enable pagination in small containers on big screens", () => {
151
+ // Arrange
152
+ let state = initState();
153
+
154
+ // Act
155
+ state = layoutReducer(state, setPageSize(2000, 2000, 300, 300));
156
+
157
+ // Assert
158
+ expect(state.paginationEnabled).toBe(true);
159
+ });
160
+
161
+ it("does not enable navigation in small containers on big screens", () => {
162
+ // Arrange
163
+ let state = initState();
164
+
165
+ // Act
166
+ state = layoutReducer(state, setPageSize(2000, 2000, 300, 300));
167
+
168
+ // Assert
169
+ expect(state.navigationPadEnabled).toBe(false);
170
+ });
171
+ });