@24i/bigscreen-sdk 1.0.0 → 1.0.1-alpha.2074
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/package.json +12 -11
- package/packages/developer-tools/src/EnvironmentSelection/styles/EnvironmentSelection.scss +1 -1
- package/packages/device/src/driver/index.vidaa.tv.ts +1 -0
- package/packages/device/src/resolver/resolver.ts +5 -0
- package/packages/driver-vidaa/src/DeviceVidaa.ts +134 -0
- package/packages/driver-vidaa/src/__mocks__/vidaa.ts +20 -0
- package/packages/driver-vidaa/src/formatUserAgent.ts +16 -0
- package/packages/driver-vidaa/src/index.ts +1 -0
- package/packages/driver-vidaa/src/keymap.ts +54 -0
- package/packages/driver-vidaa/src/types.ts +82 -0
- package/packages/grid/src/Base/Base.tsx +25 -6
- package/packages/grid/src/Base/MouseNavigation/MouseNavigation.tsx +58 -0
- package/packages/grid/src/Base/MouseNavigation/MouseNavigationFallback.ts +4 -0
- package/packages/grid/src/Base/MouseNavigation/index.tizen.tv.ts +1 -0
- package/packages/grid/src/Base/MouseNavigation/index.ts +1 -0
- package/packages/grid/src/Base/MouseNavigation/index.webos.tv.ts +1 -0
- package/packages/grid/src/Base/MouseNavigation/index.webtv.ts +1 -0
- package/packages/grid/src/Base/interface.ts +47 -0
- package/packages/grid/src/UnifiedGridController/UnifiedGridController.ts +4 -1
- package/packages/list/src/Base/Base.tsx +16 -5
- package/packages/list/src/Base/MouseNavigation/MouseNavigation.tsx +58 -0
- package/packages/list/src/Base/MouseNavigation/MouseNavigationFallback.ts +4 -0
- package/packages/list/src/Base/MouseNavigation/index.tizen.tv.ts +1 -0
- package/packages/list/src/Base/MouseNavigation/index.ts +1 -0
- package/packages/list/src/Base/MouseNavigation/index.webos.tv.ts +1 -0
- package/packages/list/src/Base/MouseNavigation/index.webtv.ts +1 -0
- package/packages/list/src/Base/interface.ts +39 -0
- package/packages/list/src/BasicList/BasicList.tsx +4 -1
- package/packages/list/src/EdgeOffsetList/EdgeOffsetList.tsx +4 -3
- package/packages/list/src/FirstOnlyList/FirstOnlyList.tsx +2 -2
- package/packages/list/src/FirstOnlyVariedList/FirstOnlyVariedList.tsx +2 -2
- package/packages/list/src/FixedToEndList/FixedToEndList.tsx +2 -2
- package/packages/list/src/interface.ts +2 -0
- package/packages/logger/README.md +1 -1
- package/packages/menu/src/MenuAndContentContainer/MenuAndContentContainer.tsx +3 -1
- package/packages/menu/src/MenuAndContentContainer/interface.ts +1 -1
- package/packages/mouse-navigation/src/MouseNavigation.tsx +2 -2
- package/packages/scroll-text/src/Base.tsx +5 -0
- package/utils/create-export-maps/src/__tests__/createExportMaps.spec.ts +2 -2
- package/utils/create-export-maps/src/createExportMaps.ts +1 -1
- package/packages/focus/src/__test__/candidate.spec.tsx +0 -245
- package/packages/focus/src/__test__/focusFirstExisting.spec.tsx +0 -21
- package/packages/focus/src/__test__/refocusAfterHashChange.spec.tsx +0 -41
- package/packages/focus/src/__test__/safeFocus.spec.tsx +0 -41
- package/packages/grid/src/Base/Base.mouse.tsx +0 -24
- package/packages/grid/src/Base/index.tizen.tv.ts +0 -1
- package/packages/grid/src/Base/index.webos.tv.ts +0 -1
- package/packages/grid/src/Base/index.webtv.ts +0 -1
- package/packages/list/src/Base/Base.mouse.tsx +0 -28
- package/packages/list/src/Base/index.tizen.tv.ts +0 -1
- package/packages/list/src/Base/index.webos.tv.ts +0 -1
- package/packages/list/src/Base/index.webtv.ts +0 -1
- package/packages/mouse-navigation/src/__test__/MouseElementWrapper.spec.tsx +0 -61
- package/packages/mouse-navigation/src/__test__/MouseNavigation.spec.tsx +0 -107
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { createRef, Component, Reference, DeclareProps } from '@24i/bigscreen-sdk/jsx';
|
|
2
|
-
import { MouseNavigation } from '@24i/bigscreen-sdk/mouse-navigation';
|
|
3
2
|
import { device } from '@24i/bigscreen-sdk/device';
|
|
4
3
|
import { Scroller } from '@24i/bigscreen-sdk/scroller';
|
|
5
4
|
import { forEach } from '@24i/bigscreen-sdk/perf-utils/array';
|
|
@@ -10,8 +9,12 @@ import {
|
|
|
10
9
|
ICounter,
|
|
11
10
|
createTimeout,
|
|
12
11
|
} from '@24i/bigscreen-sdk/utils';
|
|
12
|
+
import { MouseNavigation } from './MouseNavigation';
|
|
13
13
|
import { FastFocusingOptimizer } from '../FastFocusingOptimizer/FastFocusingOptimizer';
|
|
14
14
|
import { BasicProps, Item } from '../types';
|
|
15
|
+
import {
|
|
16
|
+
MouseNavigation as IMouseNavigation,
|
|
17
|
+
} from './interface';
|
|
15
18
|
|
|
16
19
|
export type Props<T extends Item<U>, U> = BasicProps<T, U> & {
|
|
17
20
|
forward: () => boolean,
|
|
@@ -21,7 +24,6 @@ export type Props<T extends Item<U>, U> = BasicProps<T, U> & {
|
|
|
21
24
|
shouldShowMrcuForward?: () => boolean,
|
|
22
25
|
shouldShowMrcuBackward?: () => boolean,
|
|
23
26
|
adjustFocusFromTarget?: (itemRefIndex: number) => void,
|
|
24
|
-
mrcuRef?: Reference<MouseNavigation>;
|
|
25
27
|
limit?: number,
|
|
26
28
|
shouldApplySlowdown?: () => boolean,
|
|
27
29
|
};
|
|
@@ -45,6 +47,8 @@ export class ListBase<T extends Item<U>, U>
|
|
|
45
47
|
|
|
46
48
|
scrollerDom = createRef<HTMLDivElement>();
|
|
47
49
|
|
|
50
|
+
mrcuRef = createRef<IMouseNavigation>();
|
|
51
|
+
|
|
48
52
|
itemRefs: Reference<T>[] = [];
|
|
49
53
|
|
|
50
54
|
index = 0;
|
|
@@ -123,15 +127,16 @@ export class ListBase<T extends Item<U>, U>
|
|
|
123
127
|
|
|
124
128
|
onWheel = (event: WheelEvent) => {
|
|
125
129
|
const {
|
|
126
|
-
forward, backward,
|
|
130
|
+
horizontal, forward, backward, shouldApplySlowdown,
|
|
127
131
|
} = this.props;
|
|
128
132
|
let processed;
|
|
133
|
+
if (horizontal) return;
|
|
129
134
|
if (event.deltaY > 0) processed = shouldApplySlowdown() || forward();
|
|
130
135
|
else if (event.deltaY < 0) processed = shouldApplySlowdown() || backward();
|
|
131
136
|
if (processed) {
|
|
132
137
|
stopEvent(event);
|
|
133
138
|
this.fastScrollingCounter?.add();
|
|
134
|
-
mrcuRef?.current?.handleArrowState();
|
|
139
|
+
this.mrcuRef?.current?.handleArrowState();
|
|
135
140
|
this.fakeWheelStop();
|
|
136
141
|
} else if (processed === false) {
|
|
137
142
|
this.fastFocusingOptimizer.stop();
|
|
@@ -348,7 +353,13 @@ export class ListBase<T extends Item<U>, U>
|
|
|
348
353
|
onKeyDown={this.onKeyDown}
|
|
349
354
|
horizontal={horizontal}
|
|
350
355
|
>
|
|
351
|
-
{this.renderData()}
|
|
356
|
+
<>{this.renderData()}</>
|
|
357
|
+
<MouseNavigation
|
|
358
|
+
// @ts-ignore - needed to convert fallback (false) to interface
|
|
359
|
+
ref={this.mrcuRef}
|
|
360
|
+
getMountingPoint={() => this.scroller.current!.wrapRef}
|
|
361
|
+
{...this.props}
|
|
362
|
+
/>
|
|
352
363
|
</Scroller>
|
|
353
364
|
);
|
|
354
365
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Component, createRef } from '@24i/bigscreen-sdk/jsx';
|
|
2
|
+
import { MouseNavigation as MouseNavigationBase } from '@24i/bigscreen-sdk/mouse-navigation';
|
|
3
|
+
import { device } from '@24i/bigscreen-sdk/device';
|
|
4
|
+
import {
|
|
5
|
+
MouseNavigationProps as Props,
|
|
6
|
+
MouseNavigation as IMouseNavigation,
|
|
7
|
+
} from '../interface';
|
|
8
|
+
|
|
9
|
+
export class MouseNavigation extends Component<Props> implements IMouseNavigation {
|
|
10
|
+
private readonly div = createRef<HTMLDivElement>();
|
|
11
|
+
|
|
12
|
+
private readonly base = createRef<MouseNavigationBase>();
|
|
13
|
+
|
|
14
|
+
componentDidMount() {
|
|
15
|
+
if (device.isMouseUsed()) {
|
|
16
|
+
this.renderArrows();
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
handleArrowState() {
|
|
21
|
+
this.base?.current?.handleArrowState();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
renderArrows() {
|
|
25
|
+
const {
|
|
26
|
+
horizontal,
|
|
27
|
+
forward,
|
|
28
|
+
backward,
|
|
29
|
+
shouldShowMrcuForward,
|
|
30
|
+
shouldShowMrcuBackward,
|
|
31
|
+
getMountingPoint,
|
|
32
|
+
} = this.props;
|
|
33
|
+
|
|
34
|
+
const direction = horizontal ? 'horizontal' : 'vertical';
|
|
35
|
+
|
|
36
|
+
this.appendMount(
|
|
37
|
+
<div ref={this.div} className="mouse-navigation">
|
|
38
|
+
<MouseNavigationBase
|
|
39
|
+
// @ts-ignore - needed to convert fallback (false) to interface
|
|
40
|
+
ref={this.base}
|
|
41
|
+
getMountingPoint={() => this.div}
|
|
42
|
+
direction={direction}
|
|
43
|
+
forward={forward}
|
|
44
|
+
backward={backward}
|
|
45
|
+
shouldShowMrcuForward={shouldShowMrcuForward}
|
|
46
|
+
shouldShowMrcuBackward={shouldShowMrcuBackward}
|
|
47
|
+
>
|
|
48
|
+
{null as unknown as JSX.Element}
|
|
49
|
+
</MouseNavigationBase>
|
|
50
|
+
</div>,
|
|
51
|
+
getMountingPoint(),
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
render() {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { MouseNavigation } from './MouseNavigation';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { MouseNavigation } from './MouseNavigationFallback';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { MouseNavigation } from './MouseNavigation';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { MouseNavigation } from './MouseNavigation';
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Reference, Component } from '@24i/bigscreen-sdk/jsx';
|
|
2
|
+
|
|
3
|
+
export type MouseNavigationProps = {
|
|
4
|
+
/**
|
|
5
|
+
* Function to call on the press of the right arrow.
|
|
6
|
+
*/
|
|
7
|
+
forward(): boolean,
|
|
8
|
+
/**
|
|
9
|
+
* Function to call on the press of the left arrow.
|
|
10
|
+
*/
|
|
11
|
+
backward(): boolean,
|
|
12
|
+
/**
|
|
13
|
+
* Function which determines whether to show the forward arrow.
|
|
14
|
+
*/
|
|
15
|
+
shouldShowMrcuForward?(): boolean,
|
|
16
|
+
/**
|
|
17
|
+
* Function which determines whether to show the backward arrow.
|
|
18
|
+
*/
|
|
19
|
+
shouldShowMrcuBackward?(): boolean,
|
|
20
|
+
/**
|
|
21
|
+
* Returns a reference to the element where your `children` should be rendered.
|
|
22
|
+
*/
|
|
23
|
+
getMountingPoint(): Reference<HTMLElement>;
|
|
24
|
+
/**
|
|
25
|
+
* Property determines whether navigation is horizontal.
|
|
26
|
+
*/
|
|
27
|
+
horizontal?: boolean,
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
export interface MouseNavigation extends Component<MouseNavigationProps> {
|
|
31
|
+
/**
|
|
32
|
+
* Function to disable showing an arrow in the given direction.
|
|
33
|
+
*/
|
|
34
|
+
handleArrowState(): void,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export interface MouseNavigationComponent {
|
|
38
|
+
new (props: MouseNavigationProps): MouseNavigation,
|
|
39
|
+
}
|
|
@@ -103,7 +103,10 @@ export class BasicList<T extends Item<U>, U>
|
|
|
103
103
|
|
|
104
104
|
shouldShowMrcuForward = () => {
|
|
105
105
|
const { visibleItems, data } = this.props;
|
|
106
|
-
return
|
|
106
|
+
return (
|
|
107
|
+
this.controller.scrollIndex < data.length - 1 - visibleItems + VISIBLE_ITEMS_OFFSET
|
|
108
|
+
&& data.length > visibleItems - 2
|
|
109
|
+
);
|
|
107
110
|
};
|
|
108
111
|
|
|
109
112
|
shouldShowMrcuBackward = () => this.controller.scrollIndex > 0;
|
|
@@ -93,11 +93,12 @@ export class EdgeOffsetList<T extends Item<U>, U>
|
|
|
93
93
|
};
|
|
94
94
|
|
|
95
95
|
shouldShowMrcuForward = () => {
|
|
96
|
-
const { edgeOffset, visibleItems } = this.props;
|
|
96
|
+
const { data, edgeOffset, visibleItems } = this.props;
|
|
97
97
|
const { scrollIndex } = this.controller;
|
|
98
|
-
|
|
98
|
+
|
|
99
99
|
return (
|
|
100
|
-
scrollIndex <
|
|
100
|
+
scrollIndex < data.length - visibleItems + VISIBLE_ITEMS_OFFSET - edgeOffset
|
|
101
|
+
&& data.length > visibleItems - 2
|
|
101
102
|
);
|
|
102
103
|
};
|
|
103
104
|
|
|
@@ -70,9 +70,9 @@ export class FirstOnlyList<T extends Item<U>, U>
|
|
|
70
70
|
};
|
|
71
71
|
|
|
72
72
|
shouldShowMrcuForward = () => {
|
|
73
|
-
const { data } = this.props;
|
|
73
|
+
const { data, visibleItems } = this.props;
|
|
74
74
|
const list = this.base.current!;
|
|
75
|
-
return list.index < data.length - 1;
|
|
75
|
+
return list.index < data.length - 1 && data.length > visibleItems - 2;
|
|
76
76
|
};
|
|
77
77
|
|
|
78
78
|
shouldShowMrcuBackward = () => {
|
|
@@ -80,9 +80,9 @@ export class FirstOnlyVariedList<T extends Item<U>, U> extends Component<Props<T
|
|
|
80
80
|
};
|
|
81
81
|
|
|
82
82
|
shouldShowMrcuForward = () => {
|
|
83
|
-
const { data } = this.props;
|
|
83
|
+
const { data, visibleItems } = this.props;
|
|
84
84
|
const list = this.base.current!;
|
|
85
|
-
return list.index < data.length - 1;
|
|
85
|
+
return list.index < data.length - 1 && data.length > visibleItems - 2;
|
|
86
86
|
};
|
|
87
87
|
|
|
88
88
|
shouldShowMrcuBackward = () => {
|
|
@@ -76,9 +76,9 @@ export class FixedToEndList<T extends Item<U>, U>
|
|
|
76
76
|
};
|
|
77
77
|
|
|
78
78
|
shouldShowMrcuForward = () => {
|
|
79
|
-
const { visibleItems } = this.props;
|
|
79
|
+
const { data, visibleItems } = this.props;
|
|
80
80
|
const list = this.base.current!;
|
|
81
|
-
return list.index <=
|
|
81
|
+
return list.index <= data.length - visibleItems + 1 && data.length > visibleItems - 2;
|
|
82
82
|
};
|
|
83
83
|
|
|
84
84
|
shouldShowMrcuBackward = () => this.controller.scrollIndex > 0;
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { Component, Reference } from '@24i/bigscreen-sdk/jsx';
|
|
2
2
|
import { IFocusable } from '@24i/bigscreen-sdk/focus';
|
|
3
3
|
import { SharedProps, SharedVariedProps, Item } from './types';
|
|
4
|
+
import { ListBase } from './Base';
|
|
4
5
|
|
|
5
6
|
export interface List<
|
|
6
7
|
T extends Item<U>, U, V extends SharedProps<T, U> = SharedProps<T, U>,
|
|
7
8
|
> extends IFocusable, Component<V> {
|
|
9
|
+
base: Reference<ListBase<T, U>>,
|
|
8
10
|
appendData(data: U[]): void,
|
|
9
11
|
prependData(data: U[]): void,
|
|
10
12
|
scrollTo(index: number): void,
|
|
@@ -55,7 +55,7 @@ the output would be:
|
|
|
55
55
|
## Logger Manager
|
|
56
56
|
|
|
57
57
|
Logger Manager is used for managing loggers. We are able to add individual loggers to the Logger Manager and perform various operations on them.
|
|
58
|
-
All loggers that we want to add to the Logger Manager should inherit from the [LoggerBase](./src/loggers/LoggerBase/README
|
|
58
|
+
All loggers that we want to add to the Logger Manager should inherit from the [LoggerBase](./src/loggers/LoggerBase/README) abstract class.
|
|
59
59
|
|
|
60
60
|
### Methods
|
|
61
61
|
|
|
@@ -116,7 +116,9 @@ export class MenuAndContentContainer<T extends string = string>
|
|
|
116
116
|
isMenuAvailable() {
|
|
117
117
|
const { router: { current: router } } = this.props;
|
|
118
118
|
const scene = router?.getActiveRoute()?.component.current as SceneWithMenuAvailability;
|
|
119
|
-
|
|
119
|
+
const { isMenuEnabled } = scene.constructor;
|
|
120
|
+
if (typeof isMenuEnabled === 'function') return isMenuEnabled();
|
|
121
|
+
return !!isMenuEnabled;
|
|
120
122
|
}
|
|
121
123
|
|
|
122
124
|
/**
|
|
@@ -8,8 +8,8 @@ type Props = {
|
|
|
8
8
|
children: JSX.Element;
|
|
9
9
|
getMountingPoint: () => Reference<HTMLElement>;
|
|
10
10
|
direction: Direction;
|
|
11
|
-
forward: () =>
|
|
12
|
-
backward: () =>
|
|
11
|
+
forward: () => any;
|
|
12
|
+
backward: () => any;
|
|
13
13
|
shouldShowMrcuForward?: () => boolean;
|
|
14
14
|
shouldShowMrcuBackward?: () => boolean;
|
|
15
15
|
};
|
|
@@ -78,6 +78,10 @@ export class ScrollTextBase extends Component<Props> implements IFocusable {
|
|
|
78
78
|
if (processed) stopEvent(event);
|
|
79
79
|
};
|
|
80
80
|
|
|
81
|
+
onMouseEnter = () => {
|
|
82
|
+
this.focus({ preventScroll: true });
|
|
83
|
+
};
|
|
84
|
+
|
|
81
85
|
updateArrowNavigation(enable: boolean) {
|
|
82
86
|
if (enable) {
|
|
83
87
|
removeClass(this.arrowNavRef.current!.domRef, DISABLED_CLASS);
|
|
@@ -118,6 +122,7 @@ export class ScrollTextBase extends Component<Props> implements IFocusable {
|
|
|
118
122
|
className={className}
|
|
119
123
|
ref={this.domRef}
|
|
120
124
|
onKeyDown={this.onKeyDown}
|
|
125
|
+
onMouseEnter={this.onMouseEnter}
|
|
121
126
|
tabIndex={0}
|
|
122
127
|
>
|
|
123
128
|
<Scroller
|
|
@@ -37,14 +37,14 @@ describe('createExportMaps', () => {
|
|
|
37
37
|
createExportMaps();
|
|
38
38
|
expect(writeFileSync).toHaveBeenCalledWith(
|
|
39
39
|
expect.stringContaining('package.json'),
|
|
40
|
-
JSON.stringify({
|
|
40
|
+
`${JSON.stringify({
|
|
41
41
|
name: 'mock-root-package',
|
|
42
42
|
exports: {
|
|
43
43
|
'./adobe-heartbeat': './packages/adobe-heartbeat/src/index.ts',
|
|
44
44
|
'./animations/mock': './packages/animations/src/__mocks__/JSAnimations.ts',
|
|
45
45
|
'./animations': './packages/animations/src/index.ts',
|
|
46
46
|
}
|
|
47
|
-
}, null, 4)
|
|
47
|
+
}, null, 4)}\n`,
|
|
48
48
|
);
|
|
49
49
|
});
|
|
50
50
|
});
|
|
@@ -52,7 +52,7 @@ const createPackageJsonMapping = () => {
|
|
|
52
52
|
exports[`./${exportAlias}`] = `./packages/${exportPath}`;
|
|
53
53
|
});
|
|
54
54
|
(packageJson.exports as Record<string, string>) = exports;
|
|
55
|
-
fs.writeFileSync(resolve('./package.json'), JSON.stringify(packageJson, null, 4));
|
|
55
|
+
fs.writeFileSync(resolve('./package.json'), `${JSON.stringify(packageJson, null, 4)}\n`);
|
|
56
56
|
};
|
|
57
57
|
|
|
58
58
|
export const createExportMaps = () => {
|
|
@@ -1,245 +0,0 @@
|
|
|
1
|
-
import { Component, createRef, removeNode } from '@24i/bigscreen-sdk/jsx';
|
|
2
|
-
import { shallow, MountedComponent } from '@24i/bigscreen-sdk/jsx/test-utils';
|
|
3
|
-
import {
|
|
4
|
-
focusCandidate,
|
|
5
|
-
setFocusCandidate,
|
|
6
|
-
setActiveElementAsFocusCandidate,
|
|
7
|
-
setNextFocusCandidate,
|
|
8
|
-
setCandidateFallback,
|
|
9
|
-
getLastCandidate,
|
|
10
|
-
getCandidateStack,
|
|
11
|
-
clearCandidateStack,
|
|
12
|
-
} from '../candidate';
|
|
13
|
-
|
|
14
|
-
class MockComponent extends Component<{}> {
|
|
15
|
-
wrapperRef = createRef<HTMLDivElement>();
|
|
16
|
-
|
|
17
|
-
focus(options?: FocusOptions) {
|
|
18
|
-
this.wrapperRef.current!.focus(options);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
render() {
|
|
22
|
-
return <div tabIndex={0} ref={this.wrapperRef} />;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
describe('Focus candidate', () => {
|
|
27
|
-
let elementStructure: MountedComponent<HTMLDivElement>;
|
|
28
|
-
const refs = {
|
|
29
|
-
testElement: createRef<HTMLDivElement>(),
|
|
30
|
-
testComponent1: createRef<MockComponent>(),
|
|
31
|
-
testComponent2: createRef<MockComponent>(),
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
beforeEach(() => {
|
|
35
|
-
elementStructure = shallow<HTMLDivElement>(
|
|
36
|
-
<div tabIndex={0}>
|
|
37
|
-
<div
|
|
38
|
-
ref={refs.testElement}
|
|
39
|
-
tabIndex={0}
|
|
40
|
-
className="test-element"
|
|
41
|
-
/>
|
|
42
|
-
<MockComponent ref={refs.testComponent1} />
|
|
43
|
-
<MockComponent ref={refs.testComponent2} />
|
|
44
|
-
</div>,
|
|
45
|
-
);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
afterEach(() => {
|
|
49
|
-
jest.clearAllMocks();
|
|
50
|
-
clearCandidateStack();
|
|
51
|
-
elementStructure.unmount();
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('should register a candidate', () => {
|
|
55
|
-
refs.testElement.current!.focus();
|
|
56
|
-
setActiveElementAsFocusCandidate();
|
|
57
|
-
expect(getLastCandidate()).toBe(refs.testElement.current!);
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('should register a manual candidate', () => {
|
|
61
|
-
setFocusCandidate(refs.testComponent1.current!);
|
|
62
|
-
expect(getLastCandidate()).toBe(refs.testComponent1.current!);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
it('should register the next candidate', () => {
|
|
66
|
-
setNextFocusCandidate(refs.testComponent1.current!);
|
|
67
|
-
expect(getLastCandidate()).toBe(refs.testComponent1.current!);
|
|
68
|
-
});
|
|
69
|
-
|
|
70
|
-
it('should not register the same candidates twice', () => {
|
|
71
|
-
refs.testElement.current!.focus();
|
|
72
|
-
setActiveElementAsFocusCandidate();
|
|
73
|
-
setActiveElementAsFocusCandidate();
|
|
74
|
-
expect(getCandidateStack()).toEqual([
|
|
75
|
-
refs.testElement.current!,
|
|
76
|
-
]);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it('should the focus candidate', () => {
|
|
80
|
-
elementStructure.ref().focus();
|
|
81
|
-
setActiveElementAsFocusCandidate();
|
|
82
|
-
refs.testElement.current!.focus();
|
|
83
|
-
focusCandidate();
|
|
84
|
-
expect(document.activeElement).toBe(elementStructure.ref());
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
it('should fill and pop the candidate stack properly', () => {
|
|
88
|
-
elementStructure.ref().focus();
|
|
89
|
-
setActiveElementAsFocusCandidate();
|
|
90
|
-
refs.testElement.current!.focus();
|
|
91
|
-
setActiveElementAsFocusCandidate();
|
|
92
|
-
refs.testComponent1.current!.focus();
|
|
93
|
-
setActiveElementAsFocusCandidate();
|
|
94
|
-
refs.testComponent2.current!.focus();
|
|
95
|
-
setActiveElementAsFocusCandidate();
|
|
96
|
-
expect(getCandidateStack()).toEqual([
|
|
97
|
-
elementStructure.ref(),
|
|
98
|
-
refs.testElement.current!,
|
|
99
|
-
refs.testComponent1.current!.wrapperRef.current!,
|
|
100
|
-
refs.testComponent2.current!.wrapperRef.current!,
|
|
101
|
-
]);
|
|
102
|
-
// the last registered is skipped, because it's the current activeElement
|
|
103
|
-
// so the method should be called only 3x
|
|
104
|
-
focusCandidate();
|
|
105
|
-
focusCandidate();
|
|
106
|
-
focusCandidate();
|
|
107
|
-
expect(getCandidateStack()).toEqual([]);
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
it('should focus candidates during stack popping', () => {
|
|
111
|
-
elementStructure.ref().focus();
|
|
112
|
-
setActiveElementAsFocusCandidate();
|
|
113
|
-
refs.testElement.current!.focus();
|
|
114
|
-
setActiveElementAsFocusCandidate();
|
|
115
|
-
refs.testComponent1.current!.focus();
|
|
116
|
-
setActiveElementAsFocusCandidate();
|
|
117
|
-
refs.testComponent2.current!.focus();
|
|
118
|
-
focusCandidate();
|
|
119
|
-
expect(document.activeElement).toBe(refs.testComponent1.current!.wrapperRef.current!);
|
|
120
|
-
focusCandidate();
|
|
121
|
-
expect(document.activeElement).toBe(refs.testElement.current!);
|
|
122
|
-
focusCandidate();
|
|
123
|
-
expect(document.activeElement).toBe(elementStructure.ref());
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('should work with the next candidate', () => {
|
|
127
|
-
elementStructure.ref().focus();
|
|
128
|
-
setActiveElementAsFocusCandidate();
|
|
129
|
-
setNextFocusCandidate(refs.testElement.current!);
|
|
130
|
-
refs.testElement.current!.focus();
|
|
131
|
-
focusCandidate();
|
|
132
|
-
expect(document.activeElement).toBe(elementStructure.ref());
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
it('should work with the candidate as a component', () => {
|
|
136
|
-
refs.testComponent1.current!.focus();
|
|
137
|
-
setNextFocusCandidate(refs.testComponent1.current!);
|
|
138
|
-
refs.testComponent2.current!.focus();
|
|
139
|
-
setNextFocusCandidate(refs.testComponent2.current!);
|
|
140
|
-
expect(getCandidateStack()).toEqual([
|
|
141
|
-
refs.testComponent1.current!,
|
|
142
|
-
refs.testComponent2.current!,
|
|
143
|
-
]);
|
|
144
|
-
// last candidate shoul'd not be focused
|
|
145
|
-
// because last focused candidate can't be currently focused element
|
|
146
|
-
focusCandidate();
|
|
147
|
-
expect(document.activeElement).toBe(refs.testComponent1.current!.wrapperRef.current!);
|
|
148
|
-
});
|
|
149
|
-
|
|
150
|
-
it('should work with the candidate as a reference', () => {
|
|
151
|
-
refs.testComponent1.current!.focus();
|
|
152
|
-
setNextFocusCandidate(refs.testComponent1);
|
|
153
|
-
refs.testComponent2.current!.focus();
|
|
154
|
-
setNextFocusCandidate(refs.testComponent2);
|
|
155
|
-
expect(getCandidateStack()).toEqual([
|
|
156
|
-
refs.testComponent1,
|
|
157
|
-
refs.testComponent2,
|
|
158
|
-
]);
|
|
159
|
-
focusCandidate();
|
|
160
|
-
expect(document.activeElement).toBe(refs.testComponent1.current!.wrapperRef.current!);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
it('should work with the candidate as multiple types and focus only unique elements', () => {
|
|
164
|
-
refs.testElement.current!.focus();
|
|
165
|
-
setActiveElementAsFocusCandidate();
|
|
166
|
-
refs.testComponent1.current!.focus();
|
|
167
|
-
setNextFocusCandidate(refs.testComponent1);
|
|
168
|
-
refs.testComponent2.current!.focus();
|
|
169
|
-
setNextFocusCandidate(refs.testComponent2.current!);
|
|
170
|
-
expect(getCandidateStack()).toEqual([
|
|
171
|
-
refs.testElement.current!,
|
|
172
|
-
refs.testComponent1,
|
|
173
|
-
refs.testComponent2.current!,
|
|
174
|
-
]);
|
|
175
|
-
focusCandidate();
|
|
176
|
-
expect(document.activeElement).toBe(refs.testComponent1.current!.wrapperRef.current!);
|
|
177
|
-
focusCandidate();
|
|
178
|
-
expect(document.activeElement).toBe(refs.testElement.current!);
|
|
179
|
-
});
|
|
180
|
-
|
|
181
|
-
it('should work with the next candidate as a component', () => {
|
|
182
|
-
refs.testComponent1.current!.focus();
|
|
183
|
-
setFocusCandidate(refs.testComponent1.current!);
|
|
184
|
-
refs.testComponent2.current!.focus();
|
|
185
|
-
setNextFocusCandidate(refs.testComponent2.current!);
|
|
186
|
-
expect(getCandidateStack()).toEqual([
|
|
187
|
-
refs.testComponent1.current!,
|
|
188
|
-
refs.testComponent2.current!,
|
|
189
|
-
]);
|
|
190
|
-
focusCandidate();
|
|
191
|
-
expect(document.activeElement).toBe(refs.testComponent1.current!.wrapperRef.current!);
|
|
192
|
-
});
|
|
193
|
-
|
|
194
|
-
it('should not focus an unavailable candidate', () => {
|
|
195
|
-
elementStructure.ref().focus();
|
|
196
|
-
setActiveElementAsFocusCandidate();
|
|
197
|
-
refs.testElement.current!.focus();
|
|
198
|
-
setActiveElementAsFocusCandidate();
|
|
199
|
-
refs.testComponent1.current!.focus();
|
|
200
|
-
setFocusCandidate(refs.testComponent1.current!);
|
|
201
|
-
|
|
202
|
-
refs.testElement.current!.style.display = 'none';
|
|
203
|
-
removeNode(refs.testComponent1.current!.wrapperRef);
|
|
204
|
-
|
|
205
|
-
focusCandidate();
|
|
206
|
-
expect(document.activeElement).toBe(elementStructure.ref());
|
|
207
|
-
});
|
|
208
|
-
|
|
209
|
-
it('should set and work with a candidate fallback', () => {
|
|
210
|
-
setCandidateFallback(elementStructure.ref());
|
|
211
|
-
|
|
212
|
-
refs.testElement.current!.focus();
|
|
213
|
-
setActiveElementAsFocusCandidate();
|
|
214
|
-
refs.testComponent1.current!.focus();
|
|
215
|
-
setActiveElementAsFocusCandidate();
|
|
216
|
-
refs.testComponent2.current!.focus();
|
|
217
|
-
setActiveElementAsFocusCandidate();
|
|
218
|
-
|
|
219
|
-
refs.testElement.current!.style.display = 'none';
|
|
220
|
-
removeNode(refs.testComponent1.current!.wrapperRef);
|
|
221
|
-
removeNode(refs.testComponent2.current!.wrapperRef);
|
|
222
|
-
|
|
223
|
-
focusCandidate();
|
|
224
|
-
expect(document.activeElement).toBe(elementStructure.ref());
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
it('should clear the candidate stack', () => {
|
|
228
|
-
elementStructure.ref().focus();
|
|
229
|
-
setActiveElementAsFocusCandidate();
|
|
230
|
-
refs.testElement.current!.focus();
|
|
231
|
-
setActiveElementAsFocusCandidate();
|
|
232
|
-
refs.testComponent1.current!.focus();
|
|
233
|
-
setActiveElementAsFocusCandidate();
|
|
234
|
-
|
|
235
|
-
expect(getCandidateStack()).toEqual([
|
|
236
|
-
elementStructure.ref(),
|
|
237
|
-
refs.testElement.current!,
|
|
238
|
-
refs.testComponent2.current!.wrapperRef.current!,
|
|
239
|
-
]);
|
|
240
|
-
|
|
241
|
-
clearCandidateStack();
|
|
242
|
-
|
|
243
|
-
expect(getCandidateStack()).toEqual([]);
|
|
244
|
-
});
|
|
245
|
-
});
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { focusFirstExisting } from '../focusFirstExisting';
|
|
2
|
-
|
|
3
|
-
describe('focusFirstExisting', () => {
|
|
4
|
-
const mockFocus1 = jest.fn();
|
|
5
|
-
const mockFocus2 = jest.fn();
|
|
6
|
-
|
|
7
|
-
it('should properly focus references', () => {
|
|
8
|
-
focusFirstExisting(
|
|
9
|
-
{ current: { focus: mockFocus1 } },
|
|
10
|
-
{ current: { focus: mockFocus2 } },
|
|
11
|
-
)();
|
|
12
|
-
expect(mockFocus1).toHaveBeenCalledTimes(1);
|
|
13
|
-
expect(mockFocus2).toHaveBeenCalledTimes(0);
|
|
14
|
-
focusFirstExisting(
|
|
15
|
-
{ current: null },
|
|
16
|
-
{ current: { focus: mockFocus2 } },
|
|
17
|
-
)();
|
|
18
|
-
expect(mockFocus1).toHaveBeenCalledTimes(1);
|
|
19
|
-
expect(mockFocus2).toHaveBeenCalledTimes(1);
|
|
20
|
-
});
|
|
21
|
-
});
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { createRef } from '@24i/bigscreen-sdk/jsx';
|
|
2
|
-
import { shallow } from '@24i/bigscreen-sdk/jsx/test-utils';
|
|
3
|
-
import { refocusAfterHashChange } from '../refocusAfterHashChange';
|
|
4
|
-
|
|
5
|
-
jest.useFakeTimers();
|
|
6
|
-
|
|
7
|
-
describe('refocusAfterHashChange', () => {
|
|
8
|
-
const wrapper = createRef<HTMLDivElement>();
|
|
9
|
-
const elementInsideWrapper = createRef<HTMLDivElement>();
|
|
10
|
-
const elementOutsideWrapper = createRef<HTMLDivElement>();
|
|
11
|
-
shallow(
|
|
12
|
-
<div>
|
|
13
|
-
<div ref={wrapper}>
|
|
14
|
-
<div ref={elementInsideWrapper} tabIndex={0} />
|
|
15
|
-
</div>
|
|
16
|
-
<div ref={elementOutsideWrapper} tabIndex={0} />
|
|
17
|
-
</div>,
|
|
18
|
-
);
|
|
19
|
-
|
|
20
|
-
afterEach(() => {
|
|
21
|
-
jest.clearAllMocks();
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
it('should refocus active element inside wrapper', () => {
|
|
25
|
-
elementInsideWrapper.current!.focus();
|
|
26
|
-
const activeElement = document.activeElement as HTMLElement;
|
|
27
|
-
const spyOnFocus = jest.spyOn(activeElement, 'focus');
|
|
28
|
-
refocusAfterHashChange(wrapper);
|
|
29
|
-
jest.runAllTimers();
|
|
30
|
-
expect(spyOnFocus).toHaveBeenCalledTimes(1);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
|
-
it('should not refocus active element outside wrapper', () => {
|
|
34
|
-
elementOutsideWrapper.current!.focus();
|
|
35
|
-
const activeElement = document.activeElement as HTMLElement;
|
|
36
|
-
const spyOnFocus = jest.spyOn(activeElement, 'focus');
|
|
37
|
-
refocusAfterHashChange(wrapper);
|
|
38
|
-
jest.runAllTimers();
|
|
39
|
-
expect(spyOnFocus).toHaveBeenCalledTimes(0);
|
|
40
|
-
});
|
|
41
|
-
});
|