@24i/bigscreen-sdk 1.1.0 → 2.1.1-alpha.2133
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/README.md +1 -1
- package/package.json +34 -53
- package/packages/adobe-heartbeat/src/AdobeHeartbeat.ts +9 -9
- package/packages/async-image/src/AsyncImage.tsx +10 -15
- package/packages/developer-tools/PlayerDebugWindow/README.md +1 -1
- package/packages/developer-tools/src/DeveloperToolsService/DeveloperToolsList.tsx +0 -11
- package/packages/developer-tools/src/PlayerDebugWindow/PlayerDebugWindow.tsx +5 -5
- package/packages/developer-tools/src/PlayerDebugWindow/constants.ts +0 -15
- package/packages/developer-tools/src/TechnicalInfo/TechnicalInfoDetail.tsx +1 -2
- package/packages/developer-tools/src/TechnicalInfo/TechnicalInfoProvider.ts +3 -34
- package/packages/developer-tools/src/TechnicalInfo/__mocks__/Device.ts +0 -4
- package/packages/developer-tools/src/TechnicalInfo/translations.ts +0 -4
- package/packages/device/src/getKeyDigit.ts +2 -2
- package/packages/device/src/resolver/resolver.ts +5 -18
- package/packages/digital-clock/src/DigitalClock.tsx +4 -15
- package/packages/driver-androidtv/src/DeviceAndroidTV.ts +9 -54
- package/packages/driver-androidtv/src/__mocks__/javaScriptBridge.ts +5 -29
- package/packages/driver-androidtv/src/keymap.ts +0 -18
- package/packages/driver-androidtv/src/types.ts +16 -102
- package/packages/driver-base/src/DeviceBase.ts +2 -61
- package/packages/driver-base/src/KeyMap/Key.ts +1 -8
- package/packages/driver-base/src/KeyMap/KeyMap.ts +0 -4
- package/packages/driver-base/src/KeyMap/interface.ts +0 -1
- package/packages/driver-base/src/KeyMap/overrideValues.ts +1 -2
- package/packages/driver-base/src/__mocks__/keyMap.ts +0 -1
- package/packages/driver-base/src/types/DeviceEvent.ts +0 -2
- package/packages/driver-base/src/types/KeycodeKeyMap.ts +0 -1
- package/packages/driver-browser/src/keymap.ts +0 -8
- package/packages/driver-entone/src/keymap.ts +0 -1
- package/packages/driver-tizen/src/TizenKeys.ts +0 -2
- package/packages/driver-vidaa/src/DeviceVidaa.ts +2 -3
- package/packages/driver-vidaa/src/__mocks__/vidaa.ts +1 -1
- package/packages/driver-vidaa/src/keymap.ts +0 -2
- package/packages/driver-webos/src/DeviceWebos.ts +0 -8
- package/packages/driver-webos/src/keymap.ts +1 -2
- package/packages/driver-xbox/src/keymap.ts +1 -1
- package/packages/epg/README.md +1 -3
- package/packages/epg/src/v2/Cell.tsx +2 -16
- package/packages/epg/src/v2/DataManager.ts +41 -112
- package/packages/epg/src/v2/DatePicker.tsx +3 -9
- package/packages/epg/src/v2/DateToast/DateToast.tsx +9 -12
- package/packages/epg/src/v2/Day.tsx +3 -6
- package/packages/epg/src/v2/Epg.tsx +5 -5
- package/packages/epg/src/v2/MockGenerator/generator.ts +2 -3
- package/packages/epg/src/v2/ProgramInfo/utils.ts +3 -4
- package/packages/epg/src/v2/Row.tsx +1 -3
- package/packages/epg/src/v2/TimelineSection.tsx +1 -4
- package/packages/epg/src/v2/basic/CellsManager.tsx +2 -7
- package/packages/epg/src/v2/basic/RowsManager.tsx +1 -3
- package/packages/epg/src/v2/interface.ts +0 -13
- package/packages/events-manager/src/EventsManager.ts +56 -1
- package/packages/focus/README.md +0 -33
- package/packages/focus/src/IFocusable.ts +0 -1
- package/packages/focus/src/Layout/Base.tsx +6 -41
- package/packages/focus/src/Layout/Matrix.tsx +19 -51
- package/packages/focus/src/Layout/__test__/Base.spec.ts +180 -0
- package/packages/focus/src/Layout/__test__/Horizontal.spec.ts +94 -0
- package/packages/focus/src/Layout/__test__/Matrix.spec.ts +261 -0
- package/packages/focus/src/Layout/__test__/Vertical.spec.ts +46 -0
- package/packages/focus/src/Layout/__test__/isRtl.spec.ts +23 -0
- package/packages/focus/src/Layout/__test__/shared.ts +19 -0
- package/packages/focus/src/focusFirstExisting.ts +1 -7
- package/packages/focus/src/index.ts +1 -2
- package/packages/gallup/src/Gallup.ts +3 -3
- package/packages/grid/src/Base/Base.tsx +10 -15
- package/packages/grid/src/FirstOnlyGrid/FirstOnlyGrid.tsx +2 -4
- package/packages/icon/src/Icon.tsx +5 -27
- package/packages/input/README.md +1 -4
- package/packages/input/src/Input.tsx +29 -65
- package/packages/input/src/handleOverflow.ts +29 -0
- package/packages/interactable/README.md +1 -2
- package/packages/interactable/src/Interactable.tsx +3 -9
- package/packages/interactable/src/interface.ts +0 -1
- package/packages/jsx/src/index.ts +1 -1
- package/packages/jsx/src/test-utils/index.ts +0 -1
- package/packages/keyboard/src/Backdrop/Backdrop.scss +0 -2
- package/packages/keyboard/src/KeyboardBase.tsx +4 -16
- package/packages/keyboard/src/WhitelabelKeyboard/Keyboard.scss +0 -4
- package/packages/keyboard/src/WhitelabelKeyboard/Keyboard.tsx +20 -28
- package/packages/keyboard/src/WhitelabelKeyboard/_sizes.1080.scss +0 -1
- package/packages/keyboard/src/WhitelabelKeyboard/_sizes.scss +0 -1
- package/packages/keyboard/src/WhitelabelKeyboard/layouts/index.ts +0 -11
- package/packages/keyboard/src/WhitelabelKeyboard/types.ts +0 -1
- package/packages/l10n/README.md +0 -18
- package/packages/l10n/src/date/common.ts +6 -18
- package/packages/l10n/src/date/cs.ts +8 -2
- package/packages/l10n/src/date/en-001.ts +3 -3
- package/packages/l10n/src/date/en-common.ts +4 -5
- package/packages/l10n/src/date/en-us.ts +3 -3
- package/packages/l10n/src/date/iso.ts +13 -12
- package/packages/l10n/src/date/types.ts +0 -9
- package/packages/l10n/src/l10n.ts +3 -61
- package/packages/list/src/Base/Base.tsx +9 -19
- package/packages/list/src/Base/interface.ts +2 -2
- package/packages/list/src/CenteredList/controller.ts +1 -0
- package/packages/list/src/EdgeOffsetList/EdgeOffsetList.tsx +3 -3
- package/packages/list/src/UnifiedListController/UnifiedListController.ts +2 -6
- package/packages/logger/src/loggers/SentryLogger/Sentry.ts +0 -1
- package/packages/logger/src/loggers/SentryLogger/SentryLogger.ts +2 -2
- package/packages/menu/src/MenuAndContentContainer/MenuAndContentContainer.tsx +3 -31
- package/packages/menu/src/MenuAndContentContainer/interface.ts +0 -8
- package/packages/modal-service/README.md +1 -4
- package/packages/modal-service/src/ModalService.tsx +5 -29
- package/packages/perf-utils/README.md +120 -1
- package/packages/perf-utils/src/array/filter.ts +54 -1
- package/packages/perf-utils/src/array/find.ts +43 -1
- package/packages/perf-utils/src/array/findIndex.ts +43 -1
- package/packages/perf-utils/src/array/forEach.ts +48 -1
- package/packages/perf-utils/src/array/includes.ts +41 -1
- package/packages/perf-utils/src/array/includesNaN.ts +32 -1
- package/packages/perf-utils/src/array/index.ts +7 -1
- package/packages/perf-utils/src/array/map.ts +52 -1
- package/packages/player-ui/README.md +1 -1
- package/packages/player-ui/src/CurrentTime.tsx +2 -2
- package/packages/player-ui/src/Duration.tsx +2 -2
- package/packages/player-ui/src/PauseButton.tsx +0 -8
- package/packages/player-ui/src/PlayerInteractable.tsx +0 -1
- package/packages/player-ui/src/PlayerTime.tsx +1 -3
- package/packages/player-ui/src/PlayerUI.tsx +35 -68
- package/packages/player-ui/src/RemainingTime.tsx +2 -2
- package/packages/player-ui/src/Seekbar.tsx +18 -110
- package/packages/player-ui/src/Seeking.ts +16 -57
- package/packages/player-ui/src/Subtitles.tsx +2 -2
- package/packages/player-ui/src/index.ts +0 -1
- package/packages/player-ui/src/mocks.ts +8 -32
- package/packages/player-ui/src/timeUtils.ts +3 -3
- package/packages/player-ui/src/types.ts +3 -9
- package/packages/router/src/Route.tsx +27 -61
- package/packages/router/src/Router.tsx +13 -59
- package/packages/router/src/history.ts +1 -8
- package/packages/router/src/index.ts +1 -1
- package/packages/router/src/utils.ts +4 -9
- package/packages/sass-utils/src/linear-gradient.scss +4 -9
- package/packages/sass-utils/src/scale.1080.scss +1 -3
- package/packages/sass-utils/src/scale.720.scss +1 -1
- package/packages/time/README.md +1 -4
- package/packages/time/src/Time.ts +13 -35
- package/packages/time/src/constants.ts +0 -1
- package/packages/toast/src/ToastService.tsx +5 -16
- package/packages/types-bigscreen-jsx/README.md +4 -5
- package/packages/types-bigscreen-jsx/index.d.ts +67 -72
- package/packages/utils/README.md +0 -27
- package/packages/utils/src/elementUtils.ts +0 -25
- package/packages/utils/src/index.ts +0 -8
- package/packages/utils/src/scaledImage.ts +3 -6
- package/packages/utils/src/textUtils.ts +14 -46
- package/packages/utils/src/wait.ts +1 -3
- package/packages/utils/src/xhr/xhrSend.ts +1 -3
- package/packages/utils/src/xhr/xhrSendRetry.ts +1 -3
- package/packages/zapping/src/ChannelZapping.ts +0 -9
- package/packages/zapping/src/Zapping.tsx +0 -10
- package/.vscode/settings.json +0 -6
- package/packages/analytics/README.md +0 -8
- package/packages/analytics/src/A.ts +0 -1
- package/packages/analytics/src/Analytics.ts +0 -1
- package/packages/analytics/src/analyticsOnScroll.ts +0 -1
- package/packages/analytics/src/clients/ConsoleAnalytics/ConsoleAnalytics.ts +0 -1
- package/packages/analytics/src/clients/ConsoleAnalytics/index.ts +0 -1
- package/packages/analytics/src/clients/GoogleAnalytics/GoogleAnalytics.ts +0 -200
- package/packages/analytics/src/clients/GoogleAnalytics/constants.ts +0 -118
- package/packages/analytics/src/clients/GoogleAnalytics/getUrl.ts +0 -17
- package/packages/analytics/src/clients/GoogleAnalytics/index.ts +0 -2
- package/packages/analytics/src/clients/GoogleAnalytics/interface.ts +0 -77
- package/packages/analytics/src/clients/GoogleAnalytics/mapPayload.ts +0 -50
- package/packages/analytics/src/clients/GoogleAnalytics/prepareBody.ts +0 -14
- package/packages/analytics/src/clients/TealiumAnalytics/TealiumAnalytics.ts +0 -169
- package/packages/analytics/src/clients/TealiumAnalytics/constants.ts +0 -102
- package/packages/analytics/src/clients/TealiumAnalytics/findIdForLanguage.ts +0 -9
- package/packages/analytics/src/clients/TealiumAnalytics/index.ts +0 -4
- package/packages/analytics/src/clients/TealiumAnalytics/interface.ts +0 -33
- package/packages/analytics/src/clients/TealiumAnalytics/mappers/__mocks__/mediaPayload.ts +0 -70
- package/packages/analytics/src/clients/TealiumAnalytics/mappers/helper.ts +0 -36
- package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapAppError.ts +0 -13
- package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapFavoriteAdd.ts +0 -11
- package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapFavoriteRemove.ts +0 -11
- package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapPlayerClose.ts +0 -15
- package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapPlayerOpen.ts +0 -15
- package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapSceneView.ts +0 -18
- package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapSearch.ts +0 -18
- package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapSearchFailed.ts +0 -8
- package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapSearchSuccess.ts +0 -8
- package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapVideoPause.ts +0 -15
- package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapVideoProgress.ts +0 -18
- package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapVideoResume.ts +0 -15
- package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapVideoStart.ts +0 -15
- package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapVideoStop.ts +0 -15
- package/packages/analytics/src/clients/TealiumAnalytics/types.ts +0 -156
- package/packages/analytics/src/clients/TwentyFourIQ/TwentyFourIQClient.ts +0 -116
- package/packages/analytics/src/clients/TwentyFourIQ/constants.ts +0 -99
- package/packages/analytics/src/clients/TwentyFourIQ/helper.ts +0 -34
- package/packages/analytics/src/clients/TwentyFourIQ/index.ts +0 -2
- package/packages/analytics/src/clients/TwentyFourIQ/interface.ts +0 -31
- package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapAdLoaded.ts +0 -13
- package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapAdSkipped.ts +0 -16
- package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapBase.ts +0 -21
- package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapBuffering.ts +0 -15
- package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapPlayerClose.ts +0 -24
- package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapPlayerOpen.ts +0 -18
- package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapSceneView.ts +0 -15
- package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapScroll.ts +0 -17
- package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapVideoComplete.ts +0 -21
- package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapVideoPause.ts +0 -24
- package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapVideoProgress.ts +0 -24
- package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapVideoStart.ts +0 -34
- package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapVideoStop.ts +0 -32
- package/packages/analytics/src/clients/TwentyFourIQ/types.ts +0 -115
- package/packages/analytics/src/constants.ts +0 -1
- package/packages/analytics/src/index.ts +0 -3
- package/packages/analytics/src/interface.ts +0 -1
- package/packages/analytics/src/utils/generateSessionId.ts +0 -8
- package/packages/create-package/dist/createPackage.js +0 -66
- package/packages/create-package/dist/createPackage.js.map +0 -1
- package/packages/create-package/dist/index.js +0 -5
- package/packages/create-package/dist/index.js.map +0 -1
- package/packages/create-package/dist/questionnaire/questions.js +0 -35
- package/packages/create-package/dist/questionnaire/questions.js.map +0 -1
- package/packages/create-package/dist/settings/Settings.js +0 -10
- package/packages/create-package/dist/settings/Settings.js.map +0 -1
- package/packages/create-package/dist/types.js +0 -3
- package/packages/create-package/dist/types.js.map +0 -1
- package/packages/device/src/driver/index.firetv.ts +0 -1
- package/packages/device/src/driver/index.smartcast.tv.ts +0 -1
- package/packages/driver-firetv/src/DeviceFireTV.ts +0 -18
- package/packages/driver-firetv/src/__mocks__/javaScriptBridge.ts +0 -36
- package/packages/driver-firetv/src/index.ts +0 -1
- package/packages/driver-smartcast/src/DeviceSmartCast.ts +0 -317
- package/packages/driver-smartcast/src/__mocks__/api.ts +0 -49
- package/packages/driver-smartcast/src/index.ts +0 -1
- package/packages/driver-smartcast/src/keymap.ts +0 -9
- package/packages/driver-smartcast/src/types.ts +0 -65
- package/packages/focus/src/hasFocus.ts +0 -36
- package/packages/input/src/utils.ts +0 -71
- package/packages/jsx/src/test-utils/keyup.ts +0 -27
- package/packages/keyboard/src/WhitelabelKeyboard/layouts/arabic.ts +0 -27
- package/packages/keyboard/src/WhitelabelKeyboard/layouts/burmese.ts +0 -27
- package/packages/keyboard/src/WhitelabelKeyboard/layouts/dari.ts +0 -28
- package/packages/keyboard/src/WhitelabelKeyboard/layouts/korean.ts +0 -26
- package/packages/keyboard/src/WhitelabelKeyboard/layouts/pashto.ts +0 -27
- package/packages/keyboard/src/WhitelabelKeyboard/layouts/persian.ts +0 -27
- package/packages/keyboard/src/WhitelabelKeyboard/layouts/russian.ts +0 -27
- package/packages/keyboard/src/WhitelabelKeyboard/layouts/tibetan.ts +0 -26
- package/packages/keyboard/src/WhitelabelKeyboard/layouts/turkish.ts +0 -26
- package/packages/keyboard/src/WhitelabelKeyboard/layouts/ukrainian.ts +0 -27
- package/packages/keyboard/src/WhitelabelKeyboard/layouts/urdu.ts +0 -26
- package/packages/l10n/src/date/de.ts +0 -97
- package/packages/l10n/src/date/es.ts +0 -71
- package/packages/l10n/src/date/fr.ts +0 -94
- package/packages/l10n/src/date/he.ts +0 -101
- package/packages/time/src/adapters/24iMediaTimeApi.ts +0 -47
- package/packages/time/src/services/24iMediaTimeApi/24iMediaTimeApi.ts +0 -43
- package/packages/time/src/services/24iMediaTimeApi/index.ts +0 -6
- package/packages/utils/src/forceReflow.ts +0 -14
- package/packages/utils/src/keyPress/index.ts +0 -6
- package/packages/utils/src/keyPress/keyPressSimulator.ts +0 -74
- package/packages/utils/src/keyPress/simulateKeyPress.ts +0 -25
- package/utils/release/release.ts +0 -154
package/packages/focus/README.md
CHANGED
|
@@ -14,13 +14,11 @@ IFocusable is an interface that should be implemented by anything that can be fo
|
|
|
14
14
|
interface IFocusable {
|
|
15
15
|
focus(options?: FocusOptions): void,
|
|
16
16
|
hasDom?(element: HTMLElement): boolean,
|
|
17
|
-
hasFocus?(): boolean,
|
|
18
17
|
}
|
|
19
18
|
```
|
|
20
19
|
- focus is the main function that is called when focusing component/element.
|
|
21
20
|
- hasDom is optional optimization for components to help Layout components locate the currently
|
|
22
21
|
focused child.
|
|
23
|
-
- hasFocus is optional check if the component has focus inside or is itself focused.
|
|
24
22
|
|
|
25
23
|
## Layout components
|
|
26
24
|
- Vertical: Use it to create focus between elements vertically (up/down)
|
|
@@ -42,7 +40,6 @@ to the focused element and its index. Ideal place to change other elements
|
|
|
42
40
|
- onBeforeFocusChange: Optional callback just before focus change. It receives a reference
|
|
43
41
|
to the focused element and its index. Ideal place for preparing for the change
|
|
44
42
|
(e.g. moving the container to fit new element in the screen)
|
|
45
|
-
- circular: makes focus circular, e.g. when pressing left at leftmost element focus will go to rightmost element
|
|
46
43
|
- dir: Optional forceful setting of the component direction. Defaults to `'auto'` which follows
|
|
47
44
|
the direction of the app.
|
|
48
45
|
`'ltr'` always forces left-to-right layout,
|
|
@@ -131,16 +128,6 @@ const matrix = [
|
|
|
131
128
|
];
|
|
132
129
|
```
|
|
133
130
|
|
|
134
|
-
## Prevent blur on long press
|
|
135
|
-
When the user holds a navigation key, he usually scrolls to the boundary of the layout
|
|
136
|
-
and then releases the key. This operation is very quick and most of the time he releases
|
|
137
|
-
the key too late, so the keydown event from the layout will propagate to another component
|
|
138
|
-
or another layout. In some cases, we don't want this behavior and for those situations and
|
|
139
|
-
to have better control above the layout navigation, there is a prop `preventBlurOnLongPress`.
|
|
140
|
-
When the user scrolls to the boundary of the layout while holding a navigation key,
|
|
141
|
-
he needs to release the key and press it again to propagate the event higher and focus
|
|
142
|
-
another component or layout.
|
|
143
|
-
|
|
144
131
|
## Limitations
|
|
145
132
|
For the div to properly receive keydown events it needs to have set `tabIndex`. If you do not set `tabIndex` then it won't receive keydown events and those will not propagate to the Vertical/Horizontal component.
|
|
146
133
|
|
|
@@ -315,11 +302,6 @@ Method to focus between multiple focusable components. The first existing (non-n
|
|
|
315
302
|
const focusFirstExisting = (...toFocus: Reference<IFocusable>[]) => () => void;
|
|
316
303
|
```
|
|
317
304
|
|
|
318
|
-
If you need to enable `preventScroll` in element focus options, wrap your reference with `preventScrollOnFocus` function like this:
|
|
319
|
-
```ts
|
|
320
|
-
focusFirstExisting(this.navigation, preventScrollOnFocus(this.div))
|
|
321
|
-
```
|
|
322
|
-
|
|
323
305
|
## refocusAfterHashChange
|
|
324
306
|
When the hash is changed, the browser automatically blurs the currently focused element and focuses body.
|
|
325
307
|
This can be problematic when the overlay component is active (development tools, modals). Focus is lost and
|
|
@@ -331,18 +313,3 @@ outside of the component and not focused.
|
|
|
331
313
|
```ts
|
|
332
314
|
const refocusAfterHashChange = (focusWrapperOrReference: HTMLElement | Reference<HTMLElement>) => void;
|
|
333
315
|
```
|
|
334
|
-
|
|
335
|
-
## hasFocus
|
|
336
|
-
Test if the element (or element in the reference) has the `activeElement` inside or optionally,
|
|
337
|
-
if the element itself is the `activeElement`.
|
|
338
|
-
|
|
339
|
-
```ts
|
|
340
|
-
const hasFocus = (elementOrReference: HTMLElement | Reference<HTMLElement>, includeElementItself = false) => boolean;
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
## isFocused
|
|
344
|
-
Test if the element (or element in the reference) is the `activeElement`.
|
|
345
|
-
|
|
346
|
-
```ts
|
|
347
|
-
const isFocused = (elementOrReference: HTMLElement | Reference<HTMLElement>) => boolean;
|
|
348
|
-
```
|
|
@@ -1,22 +1,14 @@
|
|
|
1
1
|
import { Component, DeclareProps, Reference } from '@24i/bigscreen-sdk/jsx';
|
|
2
2
|
import { noop } from '@24i/bigscreen-sdk/utils/noop';
|
|
3
|
-
import { stopEvent } from '@24i/bigscreen-sdk/utils/stopEvent';
|
|
4
3
|
import { IFocusable } from '../IFocusable';
|
|
5
4
|
import { Errors, hasValidDomRef } from './constants';
|
|
6
5
|
import { SharedProps } from './types';
|
|
7
6
|
|
|
8
|
-
const PREVENT_BLUR_ON_LONG_PRESS_KEYDOWNS = 2;
|
|
9
|
-
|
|
10
7
|
export type Props = SharedProps & {
|
|
11
8
|
focusOptions?: FocusOptions;
|
|
12
9
|
focusableChildren: Array<Reference>,
|
|
13
10
|
onFocusChanged?: (focused: Reference, index: number) => any,
|
|
14
11
|
onBeforeFocusChange?: (focused: Reference, index: number) => any,
|
|
15
|
-
circular?: boolean,
|
|
16
|
-
preventBlurOnLongPress?: {
|
|
17
|
-
forward?: boolean,
|
|
18
|
-
backward?: boolean,
|
|
19
|
-
}
|
|
20
12
|
};
|
|
21
13
|
|
|
22
14
|
export interface ILayout {
|
|
@@ -33,16 +25,12 @@ export const getLayoutBase = (onKeyDown: (event: KeyboardEvent, layout: ILayout)
|
|
|
33
25
|
class Layout extends Component<Props> implements ILayout, IFocusable {
|
|
34
26
|
index = 0;
|
|
35
27
|
|
|
36
|
-
preventBlurCounter = 0;
|
|
37
|
-
|
|
38
28
|
static defaultProps = {
|
|
39
29
|
onFocusChanged: noop,
|
|
40
30
|
onBeforeFocusChange: noop,
|
|
41
31
|
focusOptions: { preventScroll: true },
|
|
42
32
|
dir: 'auto',
|
|
43
|
-
|
|
44
|
-
preventBlurOnLongPress: {},
|
|
45
|
-
} as const;
|
|
33
|
+
};
|
|
46
34
|
|
|
47
35
|
declare props: DeclareProps<Props, typeof Layout.defaultProps>;
|
|
48
36
|
|
|
@@ -52,7 +40,6 @@ export const getLayoutBase = (onKeyDown: (event: KeyboardEvent, layout: ILayout)
|
|
|
52
40
|
throw new Error(Errors.DOM_REF_ERROR);
|
|
53
41
|
}
|
|
54
42
|
domRef.current!.addEventListener('keydown', this.onKeyDown, false);
|
|
55
|
-
window.document.addEventListener('keyup', this.onGlobalKeyUp, true);
|
|
56
43
|
}
|
|
57
44
|
|
|
58
45
|
componentWillUnmount() {
|
|
@@ -61,17 +48,12 @@ export const getLayoutBase = (onKeyDown: (event: KeyboardEvent, layout: ILayout)
|
|
|
61
48
|
throw new Error(Errors.DOM_REF_ERROR);
|
|
62
49
|
}
|
|
63
50
|
domRef.current!.removeEventListener('keydown', this.onKeyDown, false);
|
|
64
|
-
window.document.removeEventListener('keyup', this.onGlobalKeyUp, true);
|
|
65
51
|
}
|
|
66
52
|
|
|
67
53
|
onKeyDown = (e: KeyboardEvent) => {
|
|
68
54
|
onKeyDown(e, this);
|
|
69
55
|
};
|
|
70
56
|
|
|
71
|
-
onGlobalKeyUp = () => {
|
|
72
|
-
this.preventBlurCounter = 0;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
57
|
getFromIndex(target: HTMLElement) {
|
|
76
58
|
const { focusableChildren } = this.props;
|
|
77
59
|
if (
|
|
@@ -96,42 +78,25 @@ export const getLayoutBase = (onKeyDown: (event: KeyboardEvent, layout: ILayout)
|
|
|
96
78
|
}
|
|
97
79
|
|
|
98
80
|
backward(e: KeyboardEvent) {
|
|
99
|
-
const { focusableChildren, preventBlurOnLongPress, circular } = this.props;
|
|
100
81
|
const { target } = e;
|
|
101
82
|
const fromIndex = this.getFromIndex(target as HTMLElement);
|
|
102
|
-
if (preventBlurOnLongPress.backward) {
|
|
103
|
-
this.preventBlurCounter += 1;
|
|
104
|
-
}
|
|
105
83
|
if (fromIndex > 0) {
|
|
106
84
|
this.setIndex(fromIndex - 1);
|
|
107
85
|
this.focusCurrentIndex();
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
this.setIndex(focusableChildren.length - 1);
|
|
111
|
-
this.focusCurrentIndex();
|
|
112
|
-
stopEvent(e);
|
|
113
|
-
} else if (this.preventBlurCounter >= PREVENT_BLUR_ON_LONG_PRESS_KEYDOWNS) {
|
|
114
|
-
stopEvent(e);
|
|
86
|
+
e.preventDefault();
|
|
87
|
+
e.stopPropagation();
|
|
115
88
|
}
|
|
116
89
|
}
|
|
117
90
|
|
|
118
91
|
forward(e: KeyboardEvent) {
|
|
119
|
-
const { focusableChildren
|
|
92
|
+
const { focusableChildren } = this.props;
|
|
120
93
|
const { target } = e;
|
|
121
94
|
const fromIndex = this.getFromIndex(target as HTMLElement);
|
|
122
|
-
if (preventBlurOnLongPress.forward) {
|
|
123
|
-
this.preventBlurCounter += 1;
|
|
124
|
-
}
|
|
125
95
|
if (fromIndex < focusableChildren.length - 1) {
|
|
126
96
|
this.setIndex(fromIndex + 1);
|
|
127
97
|
this.focusCurrentIndex();
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
this.setIndex(0);
|
|
131
|
-
this.focusCurrentIndex();
|
|
132
|
-
stopEvent(e);
|
|
133
|
-
} else if (this.preventBlurCounter >= PREVENT_BLUR_ON_LONG_PRESS_KEYDOWNS) {
|
|
134
|
-
stopEvent(e);
|
|
98
|
+
e.preventDefault();
|
|
99
|
+
e.stopPropagation();
|
|
135
100
|
}
|
|
136
101
|
}
|
|
137
102
|
|
|
@@ -8,8 +8,6 @@ import { isRtl } from './isRtl';
|
|
|
8
8
|
import { Errors, hasValidDomRef } from './constants';
|
|
9
9
|
import { SharedProps } from './types';
|
|
10
10
|
|
|
11
|
-
const PREVENT_BLUR_ON_LONG_PRESS_KEYDOWNS = 2;
|
|
12
|
-
|
|
13
11
|
// Used in binary operations for shorter checks
|
|
14
12
|
export enum CircularDirection {
|
|
15
13
|
NONE = 0,
|
|
@@ -23,13 +21,7 @@ export type Props = SharedProps & {
|
|
|
23
21
|
matrix: Array<Array<Reference>>,
|
|
24
22
|
onFocusChanged?: (focused: Reference, index: Index2D) => any,
|
|
25
23
|
onBeforeFocusChange?: (focused: Reference, index: Index2D) => any,
|
|
26
|
-
circular?: CircularDirection
|
|
27
|
-
preventBlurOnLongPress?: {
|
|
28
|
-
left?: boolean,
|
|
29
|
-
right?: boolean,
|
|
30
|
-
up?: boolean,
|
|
31
|
-
down?: boolean,
|
|
32
|
-
},
|
|
24
|
+
circular?: CircularDirection;
|
|
33
25
|
};
|
|
34
26
|
|
|
35
27
|
export type Index2D = {
|
|
@@ -40,14 +32,11 @@ export type Index2D = {
|
|
|
40
32
|
export class Matrix extends Component<Props> implements IFocusable {
|
|
41
33
|
index: Index2D = { x: 0, y: 0 };
|
|
42
34
|
|
|
43
|
-
preventBlurCounter = 0;
|
|
44
|
-
|
|
45
35
|
static defaultProps = {
|
|
46
36
|
onFocusChanged: noop,
|
|
47
37
|
onBeforeFocusChange: noop,
|
|
48
38
|
circular: CircularDirection.NONE,
|
|
49
39
|
dir: 'auto',
|
|
50
|
-
preventBlurOnLongPress: {},
|
|
51
40
|
} as const;
|
|
52
41
|
|
|
53
42
|
declare props: DeclareProps<Props, typeof Matrix.defaultProps>;
|
|
@@ -58,7 +47,6 @@ export class Matrix extends Component<Props> implements IFocusable {
|
|
|
58
47
|
throw new Error(Errors.DOM_REF_ERROR);
|
|
59
48
|
}
|
|
60
49
|
domRef.current!.addEventListener('keydown', this.onKeyDown, false);
|
|
61
|
-
window.document.addEventListener('keyup', this.onGlobalKeyUp, true);
|
|
62
50
|
}
|
|
63
51
|
|
|
64
52
|
componentWillUnmount() {
|
|
@@ -67,46 +55,26 @@ export class Matrix extends Component<Props> implements IFocusable {
|
|
|
67
55
|
throw new Error(Errors.DOM_REF_ERROR);
|
|
68
56
|
}
|
|
69
57
|
domRef.current!.removeEventListener('keydown', this.onKeyDown, false);
|
|
70
|
-
window.document.removeEventListener('keyup', this.onGlobalKeyUp, true);
|
|
71
58
|
}
|
|
72
59
|
|
|
73
60
|
onKeyDown = (e: KeyboardEvent) => {
|
|
74
|
-
const { preventBlurOnLongPress } = this.props;
|
|
75
61
|
let newIndex: Index2D | null = null;
|
|
76
62
|
if (this.isDirectionLeft(e)) {
|
|
77
63
|
newIndex = this.moveHorizontaly('left');
|
|
78
|
-
if (preventBlurOnLongPress.left) {
|
|
79
|
-
this.preventBlurCounter += 1;
|
|
80
|
-
}
|
|
81
64
|
} else if (this.isDirectionRight(e)) {
|
|
82
65
|
newIndex = this.moveHorizontaly('right');
|
|
83
|
-
if (preventBlurOnLongPress.right) {
|
|
84
|
-
this.preventBlurCounter += 1;
|
|
85
|
-
}
|
|
86
66
|
} else if (device.isDirectionUp(e)) {
|
|
87
67
|
newIndex = this.moveVerticaly('up');
|
|
88
|
-
if (preventBlurOnLongPress.up) {
|
|
89
|
-
this.preventBlurCounter += 1;
|
|
90
|
-
}
|
|
91
68
|
} else if (device.isDirectionDown(e)) {
|
|
92
69
|
newIndex = this.moveVerticaly('down');
|
|
93
|
-
if (preventBlurOnLongPress.down) {
|
|
94
|
-
this.preventBlurCounter += 1;
|
|
95
|
-
}
|
|
96
70
|
}
|
|
97
71
|
if (newIndex) {
|
|
98
72
|
stopEvent(e);
|
|
99
73
|
this.index = newIndex;
|
|
100
74
|
this.focusCurrentIndex();
|
|
101
|
-
} else if (this.preventBlurCounter >= PREVENT_BLUR_ON_LONG_PRESS_KEYDOWNS) {
|
|
102
|
-
stopEvent(e);
|
|
103
75
|
}
|
|
104
76
|
};
|
|
105
77
|
|
|
106
|
-
onGlobalKeyUp = () => {
|
|
107
|
-
this.preventBlurCounter = 0;
|
|
108
|
-
};
|
|
109
|
-
|
|
110
78
|
getRefAt({ x, y }: Index2D): Reference {
|
|
111
79
|
const { matrix } = this.props;
|
|
112
80
|
if (matrix[y] && matrix[y][x]) return matrix[y][x];
|
|
@@ -144,6 +112,24 @@ export class Matrix extends Component<Props> implements IFocusable {
|
|
|
144
112
|
return false;
|
|
145
113
|
}
|
|
146
114
|
|
|
115
|
+
isDirectionLeft(event: KeyboardEvent) {
|
|
116
|
+
const { dir } = this.props;
|
|
117
|
+
const rtl = isRtl(dir);
|
|
118
|
+
return (
|
|
119
|
+
(!rtl && LEFT.is(event))
|
|
120
|
+
|| (rtl && RIGHT.is(event))
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
isDirectionRight(event: KeyboardEvent) {
|
|
125
|
+
const { dir } = this.props;
|
|
126
|
+
const rtl = isRtl(dir);
|
|
127
|
+
return (
|
|
128
|
+
(!rtl && RIGHT.is(event))
|
|
129
|
+
|| (rtl && LEFT.is(event))
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
147
133
|
moveForwards = (isCircular: boolean) => (x: number, length: number) => {
|
|
148
134
|
if (x === length - 1) {
|
|
149
135
|
return isCircular ? 0 : length - 1;
|
|
@@ -186,24 +172,6 @@ export class Matrix extends Component<Props> implements IFocusable {
|
|
|
186
172
|
return this.searchVertical(column, fromY, this.moveForwards(!!isCircular));
|
|
187
173
|
};
|
|
188
174
|
|
|
189
|
-
isDirectionLeft(event: KeyboardEvent) {
|
|
190
|
-
const { dir } = this.props;
|
|
191
|
-
const rtl = isRtl(dir);
|
|
192
|
-
return (
|
|
193
|
-
(!rtl && LEFT.is(event))
|
|
194
|
-
|| (rtl && RIGHT.is(event))
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
isDirectionRight(event: KeyboardEvent) {
|
|
199
|
-
const { dir } = this.props;
|
|
200
|
-
const rtl = isRtl(dir);
|
|
201
|
-
return (
|
|
202
|
-
(!rtl && RIGHT.is(event))
|
|
203
|
-
|| (rtl && LEFT.is(event))
|
|
204
|
-
);
|
|
205
|
-
}
|
|
206
|
-
|
|
207
175
|
isDifferentReferenceFromCurrent(index: Index2D): boolean {
|
|
208
176
|
const { current } = this.getRefAt(this.index);
|
|
209
177
|
const { current: searched } = this.getRefAt(index);
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { IFocusable } from '../../IFocusable';
|
|
2
|
+
import { getLayoutBase } from '../Base';
|
|
3
|
+
import { rootRef, refChildA, refChildB, refChildC, refChildD } from './shared';
|
|
4
|
+
|
|
5
|
+
const mockKeydown = jest.fn();
|
|
6
|
+
const mockEvent: any = {
|
|
7
|
+
target: null,
|
|
8
|
+
preventDefault: jest.fn(),
|
|
9
|
+
stopPropagation: jest.fn(),
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const Base = getLayoutBase(mockKeydown);
|
|
13
|
+
|
|
14
|
+
describe('Focus Layout Base', () => {
|
|
15
|
+
let base: any;
|
|
16
|
+
beforeEach(() => {
|
|
17
|
+
base = new Base({
|
|
18
|
+
domRef: rootRef,
|
|
19
|
+
children: 'children',
|
|
20
|
+
focusableChildren: [refChildA, refChildB, refChildC],
|
|
21
|
+
onFocusChanged: jest.fn(),
|
|
22
|
+
onBeforeFocusChange: jest.fn(),
|
|
23
|
+
});
|
|
24
|
+
mockKeydown.mockClear();
|
|
25
|
+
refChildA.current!.focus.mockClear();
|
|
26
|
+
refChildB.current!.focus.mockClear();
|
|
27
|
+
refChildC.current!.focus.mockClear();
|
|
28
|
+
mockEvent.preventDefault.mockClear();
|
|
29
|
+
mockEvent.stopPropagation.mockClear();
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('should throw without domRef on componentDidMount', () => {
|
|
33
|
+
// @ts-ignore - the point of the test is to test possible runtime problem
|
|
34
|
+
const invalidBase = new Base({ domRef: null, children: [], focusableChildren: [] });
|
|
35
|
+
expect(() => invalidBase.componentDidMount()).toThrow();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should throw without domRef on componentWillUnmount', () => {
|
|
39
|
+
// @ts-ignore - the point of the test is to test possible runtime problem
|
|
40
|
+
const invalidBase = new Base({ domRef: null, children: [], focusableChildren: [] });
|
|
41
|
+
expect(() => invalidBase.componentWillUnmount()).toThrow();
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should not throw with valid domRef on componentDidMount', () => {
|
|
45
|
+
expect(() => base.componentDidMount()).not.toThrow();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should not throw with valid domRef on componentWillUnmount', () => {
|
|
49
|
+
expect(() => base.componentWillUnmount()).not.toThrow();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should render children', () => {
|
|
53
|
+
expect(base.render()).toBe('children');
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it('should return false when setting index out of range', () => {
|
|
57
|
+
expect(base.setIndex(4)).toBe(false);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should return true when setting index out of range', () => {
|
|
61
|
+
expect(base.setIndex(1)).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('should increase index by one on forward', () => {
|
|
65
|
+
const oldIndex = base.index;
|
|
66
|
+
base.forward(mockEvent);
|
|
67
|
+
expect(base.index).toBe(oldIndex + 1);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should deecrease index by one on backward', () => {
|
|
71
|
+
base.index = 2;
|
|
72
|
+
const oldIndex = base.index;
|
|
73
|
+
base.backward(mockEvent);
|
|
74
|
+
expect(base.index).toBe(oldIndex - 1);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('should not increase index above focusableChildren.length - 1', () => {
|
|
78
|
+
base.index = base.props.focusableChildren.length - 1;
|
|
79
|
+
base.forward(mockEvent);
|
|
80
|
+
expect(base.index).toBe(base.props.focusableChildren.length - 1);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('should not decrease index below 0', () => {
|
|
84
|
+
base.index = 0;
|
|
85
|
+
base.backward(mockEvent);
|
|
86
|
+
expect(base.index).toBe(0);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should call focus on new element when going forward', () => {
|
|
90
|
+
base.forward(mockEvent);
|
|
91
|
+
expect(refChildB.current!.focus).toHaveBeenCalled();
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should call focus on new element when going backward', () => {
|
|
95
|
+
base.index = 1;
|
|
96
|
+
base.backward(mockEvent);
|
|
97
|
+
expect(refChildA.current!.focus).toHaveBeenCalled();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('should not call focus when can\'t go forward', () => {
|
|
101
|
+
base.index = 2;
|
|
102
|
+
base.forward(mockEvent);
|
|
103
|
+
expect(refChildC.current!.focus).not.toHaveBeenCalled();
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
it('should not call focus when can\'t go backward', () => {
|
|
107
|
+
base.backward(mockEvent);
|
|
108
|
+
expect(refChildA.current!.focus).not.toHaveBeenCalled();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('should call preventDefault and stopPropagation when going forward', () => {
|
|
112
|
+
base.forward(mockEvent);
|
|
113
|
+
expect(mockEvent.preventDefault).toHaveBeenCalled();
|
|
114
|
+
expect(mockEvent.stopPropagation).toHaveBeenCalled();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it('should call preventDefault and stopPropagation when going backward', () => {
|
|
118
|
+
base.index = 1;
|
|
119
|
+
base.backward(mockEvent);
|
|
120
|
+
expect(mockEvent.preventDefault).toHaveBeenCalled();
|
|
121
|
+
expect(mockEvent.stopPropagation).toHaveBeenCalled();
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('should not call preventDefault and stopPropagation when can\'t go forward', () => {
|
|
125
|
+
base.index = 2;
|
|
126
|
+
base.forward(mockEvent);
|
|
127
|
+
expect(mockEvent.preventDefault).not.toHaveBeenCalled();
|
|
128
|
+
expect(mockEvent.stopPropagation).not.toHaveBeenCalled();
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should not call preventDefault and stopPropagation when can\'t go backward', () => {
|
|
132
|
+
base.backward(mockEvent);
|
|
133
|
+
expect(mockEvent.preventDefault).not.toHaveBeenCalled();
|
|
134
|
+
expect(mockEvent.stopPropagation).not.toHaveBeenCalled();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('should call onFocusChanged when focusing current index', () => {
|
|
138
|
+
base.focusCurrentIndex();
|
|
139
|
+
expect(base.props.onFocusChanged).toHaveBeenCalled();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should call onBeforeFocusChange when focusing current index', () => {
|
|
143
|
+
base.focusCurrentIndex();
|
|
144
|
+
expect(base.props.onBeforeFocusChange).toHaveBeenCalled();
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('should focus current index on focus', () => {
|
|
148
|
+
base.index = 2;
|
|
149
|
+
base.focus();
|
|
150
|
+
expect(refChildC.current!.focus).toHaveBeenCalled();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should call passed onKeyDown on onKeyDown', () => {
|
|
154
|
+
base.onKeyDown();
|
|
155
|
+
expect(mockKeydown).toHaveBeenCalled();
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should throw in focusCurrentIndex when element does not implement focus', () => {
|
|
159
|
+
base.props.focusableChildren[2] = {};
|
|
160
|
+
base.index = 2;
|
|
161
|
+
expect(() => base.focusCurrentIndex()).toThrow();
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('should take result of hasDom into account of determining current focus position', () => {
|
|
165
|
+
base = new Base({
|
|
166
|
+
domRef: rootRef,
|
|
167
|
+
children: 'children',
|
|
168
|
+
focusableChildren: [refChildA, refChildB, refChildC, refChildD],
|
|
169
|
+
onFocusChanged: jest.fn(),
|
|
170
|
+
onBeforeFocusChange: jest.fn(),
|
|
171
|
+
});
|
|
172
|
+
((refChildD.current as IFocusable).hasDom as jest.MockedFn<
|
|
173
|
+
Exclude<IFocusable['hasDom'], undefined>
|
|
174
|
+
>).mockReturnValueOnce(true);
|
|
175
|
+
base.backward(mockEvent);
|
|
176
|
+
expect(base.index).toBe(2);
|
|
177
|
+
base.backward(mockEvent);
|
|
178
|
+
expect(base.index).toBe(1);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { isRtl } from '@24i/bigscreen-sdk/i18n';
|
|
2
|
+
import { Horizontal } from '../Horizontal';
|
|
3
|
+
import { rootRef, refChildA, refChildB, refChildC } from './shared';
|
|
4
|
+
|
|
5
|
+
jest.mock('@24i/bigscreen-sdk/i18n', () => ({
|
|
6
|
+
...jest.requireActual('@24i/bigscreen-sdk/i18n'),
|
|
7
|
+
isRtl: jest.fn().mockReturnValue(false),
|
|
8
|
+
}));
|
|
9
|
+
const isRtlMock = isRtl as jest.MockedFn<typeof isRtl>;
|
|
10
|
+
|
|
11
|
+
const mockEvent = {
|
|
12
|
+
target: false,
|
|
13
|
+
preventDefault: jest.fn(),
|
|
14
|
+
stopPropagation: jest.fn(),
|
|
15
|
+
};
|
|
16
|
+
const mockLEFTEvent = {
|
|
17
|
+
code: 'ArrowLeft',
|
|
18
|
+
...mockEvent,
|
|
19
|
+
};
|
|
20
|
+
const mockRIGHTEvent = {
|
|
21
|
+
code: 'ArrowRight',
|
|
22
|
+
...mockEvent,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
describe('Horizontal Focus Layout', () => {
|
|
26
|
+
let horizontal: any;
|
|
27
|
+
beforeEach(() => {
|
|
28
|
+
horizontal = new Horizontal({
|
|
29
|
+
domRef: rootRef,
|
|
30
|
+
children: 'children',
|
|
31
|
+
focusableChildren: [refChildA, refChildB, refChildC],
|
|
32
|
+
onFocusChanged: jest.fn(),
|
|
33
|
+
onBeforeFocusChange: jest.fn(),
|
|
34
|
+
});
|
|
35
|
+
horizontal.forward = jest.fn();
|
|
36
|
+
horizontal.backward = jest.fn();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should be a class component', () => {
|
|
40
|
+
expect(Horizontal.isClass).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should call forward on RIGHT', () => {
|
|
44
|
+
horizontal.onKeyDown(mockRIGHTEvent);
|
|
45
|
+
expect(horizontal.forward).toHaveBeenCalled();
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should call backward on LEFT', () => {
|
|
49
|
+
horizontal.setIndex(1);
|
|
50
|
+
horizontal.onKeyDown(mockLEFTEvent);
|
|
51
|
+
expect(horizontal.backward).toHaveBeenCalled();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should call backward on RIGHT when RTL', () => {
|
|
55
|
+
isRtlMock.mockReturnValueOnce(true);
|
|
56
|
+
horizontal.setIndex(1);
|
|
57
|
+
horizontal.onKeyDown(mockRIGHTEvent);
|
|
58
|
+
expect(horizontal.backward).toHaveBeenCalled();
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should call forward on LEFT when RTL', () => {
|
|
62
|
+
isRtlMock.mockReturnValueOnce(true);
|
|
63
|
+
horizontal.onKeyDown(mockLEFTEvent);
|
|
64
|
+
expect(horizontal.forward).toHaveBeenCalled();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
it('should call backward on RIGHT when forced RTL', () => {
|
|
68
|
+
horizontal.props.dir = 'rtl';
|
|
69
|
+
horizontal.setIndex(1);
|
|
70
|
+
horizontal.onKeyDown(mockRIGHTEvent);
|
|
71
|
+
expect(horizontal.backward).toHaveBeenCalled();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should call forward on LEFT when forced RTL', () => {
|
|
75
|
+
horizontal.props.dir = 'rtl';
|
|
76
|
+
horizontal.onKeyDown(mockLEFTEvent);
|
|
77
|
+
expect(horizontal.forward).toHaveBeenCalled();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
it('should call backward on LEFT when RTL and forced LTR', () => {
|
|
81
|
+
isRtlMock.mockReturnValueOnce(true);
|
|
82
|
+
horizontal.props.dir = 'ltr';
|
|
83
|
+
horizontal.setIndex(1);
|
|
84
|
+
horizontal.onKeyDown(mockLEFTEvent);
|
|
85
|
+
expect(horizontal.backward).toHaveBeenCalled();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('should call forward on RIGHT when RTL and forced LTR', () => {
|
|
89
|
+
isRtlMock.mockReturnValueOnce(true);
|
|
90
|
+
horizontal.props.dir = 'ltr';
|
|
91
|
+
horizontal.onKeyDown(mockRIGHTEvent);
|
|
92
|
+
expect(horizontal.forward).toHaveBeenCalled();
|
|
93
|
+
});
|
|
94
|
+
});
|