@applicaster/zapp-react-native-ui-components 15.0.0-alpha.1456157166 → 15.0.0-alpha.2239032089
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/Components/Focusable/Focusable.tsx +4 -2
- package/Components/Focusable/FocusableTvOS.tsx +5 -1
- package/Components/FocusableGroup/FocusableTvOS.tsx +5 -0
- package/Components/GeneralContentScreen/utils/useCurationAPI.ts +11 -9
- package/Components/River/TV/River.tsx +9 -3
- package/Components/River/TV/index.tsx +3 -3
- package/Components/River/TV/withFocusableGroupForContent.tsx +60 -0
- package/Decorators/RiverFeedLoader/utils/getDatasourceUrl.ts +10 -6
- package/events/index.ts +2 -0
- package/package.json +5 -5
- package/Components/River/TV/withTVEventHandler.tsx +0 -27
|
@@ -8,6 +8,8 @@ import { withFocusableContext } from "../../Contexts/FocusableGroupContext/withF
|
|
|
8
8
|
import { StyleSheet, ViewStyle } from "react-native";
|
|
9
9
|
import { AccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager";
|
|
10
10
|
|
|
11
|
+
import { isSearchInputId } from "@applicaster/search-screen/src/tv/utils";
|
|
12
|
+
|
|
11
13
|
type Props = {
|
|
12
14
|
initialFocus?: boolean;
|
|
13
15
|
id: string;
|
|
@@ -106,7 +108,7 @@ class Focusable extends BaseFocusable<Props> {
|
|
|
106
108
|
onMouseEnter() {
|
|
107
109
|
const { id } = this.props;
|
|
108
110
|
|
|
109
|
-
if (id
|
|
111
|
+
if (!isSearchInputId(id)) {
|
|
110
112
|
this.mouse = true;
|
|
111
113
|
this.props?.handleFocus?.({ mouse: true });
|
|
112
114
|
|
|
@@ -120,7 +122,7 @@ class Focusable extends BaseFocusable<Props> {
|
|
|
120
122
|
onMouseLeave() {
|
|
121
123
|
const { id } = this.props;
|
|
122
124
|
|
|
123
|
-
if (id
|
|
125
|
+
if (!isSearchInputId(id)) {
|
|
124
126
|
this.mouse = false;
|
|
125
127
|
this.blur(null);
|
|
126
128
|
}
|
|
@@ -10,8 +10,9 @@ import {
|
|
|
10
10
|
forceFocusableFocus,
|
|
11
11
|
} from "@applicaster/zapp-react-native-utils/appUtils/focusManager/index.ios";
|
|
12
12
|
import { findNodeHandle, ViewStyle } from "react-native";
|
|
13
|
+
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
13
14
|
|
|
14
|
-
|
|
15
|
+
import { emitFocused } from "@applicaster/zapp-react-native-utils/appUtils/focusManagerAux/utils/utils.ios";
|
|
15
16
|
|
|
16
17
|
type Props = {
|
|
17
18
|
id: string;
|
|
@@ -84,6 +85,9 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
84
85
|
});
|
|
85
86
|
}
|
|
86
87
|
|
|
88
|
+
const id: string = nativeEvent.itemID;
|
|
89
|
+
emitFocused(id);
|
|
90
|
+
|
|
87
91
|
onFocus(nativeEvent);
|
|
88
92
|
}
|
|
89
93
|
|
|
@@ -142,15 +142,17 @@ export const useCurationAPI = (
|
|
|
142
142
|
const url = path(SOURCE_PATH, component);
|
|
143
143
|
const mapping = path(MAPPING_PATH, component);
|
|
144
144
|
|
|
145
|
-
map[component.id] =
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
145
|
+
map[component.id] = mapping
|
|
146
|
+
? getInflatedDataSourceUrl({
|
|
147
|
+
source: url,
|
|
148
|
+
contexts: {
|
|
149
|
+
entry: entryContext,
|
|
150
|
+
screen: screenContext,
|
|
151
|
+
search: getSearchContext(searchContext, mapping),
|
|
152
|
+
},
|
|
153
|
+
mapping,
|
|
154
|
+
})
|
|
155
|
+
: url;
|
|
154
156
|
});
|
|
155
157
|
|
|
156
158
|
return map;
|
|
@@ -4,6 +4,7 @@ import * as React from "react";
|
|
|
4
4
|
import { Text } from "react-native";
|
|
5
5
|
import * as R from "ramda";
|
|
6
6
|
|
|
7
|
+
import { isNil } from "@applicaster/zapp-react-native-utils/utils";
|
|
7
8
|
import { GeneralContentScreen } from "../../GeneralContentScreen";
|
|
8
9
|
import { ScreenResolver } from "@applicaster/zapp-react-native-ui-components/Components/ScreenResolver";
|
|
9
10
|
import { utilsLogger } from "@applicaster/zapp-react-native-utils/logger";
|
|
@@ -24,6 +25,7 @@ type Props = {
|
|
|
24
25
|
isInsideContainer?: boolean;
|
|
25
26
|
extraAnchorPointYOffset: number;
|
|
26
27
|
river?: ZappRiver | ZappEntry;
|
|
28
|
+
groupId: string;
|
|
27
29
|
};
|
|
28
30
|
|
|
29
31
|
export const River = (props: Props) => {
|
|
@@ -35,6 +37,7 @@ export const River = (props: Props) => {
|
|
|
35
37
|
componentsMapExtraProps,
|
|
36
38
|
isInsideContainer,
|
|
37
39
|
extraAnchorPointYOffset,
|
|
40
|
+
groupId,
|
|
38
41
|
} = props;
|
|
39
42
|
|
|
40
43
|
const { title: screenTitle, summary: screenSummary } = useNavbarState();
|
|
@@ -52,7 +55,7 @@ export const River = (props: Props) => {
|
|
|
52
55
|
);
|
|
53
56
|
|
|
54
57
|
const stringOrEmpty = (value: string | number | undefined): string =>
|
|
55
|
-
|
|
58
|
+
isNil(value) ? "" : String(value);
|
|
56
59
|
|
|
57
60
|
React.useEffect(() => {
|
|
58
61
|
if (!isInsideContainer) {
|
|
@@ -92,8 +95,10 @@ export const River = (props: Props) => {
|
|
|
92
95
|
<ScreenResolver
|
|
93
96
|
screenType={river.type}
|
|
94
97
|
screenId={screenId}
|
|
95
|
-
screenData={
|
|
96
|
-
componentsMapExtraProps={componentsMapExtraProps}
|
|
98
|
+
screenData={Object.assign(river || {}, { groupId: extraData?.groupId })}
|
|
99
|
+
componentsMapExtraProps={Object.assign(componentsMapExtraProps || {}, {
|
|
100
|
+
groupId,
|
|
101
|
+
})}
|
|
97
102
|
{...extraData}
|
|
98
103
|
/>
|
|
99
104
|
);
|
|
@@ -106,6 +111,7 @@ export const River = (props: Props) => {
|
|
|
106
111
|
isScreenWrappedInContainer={isInsideContainer}
|
|
107
112
|
extraAnchorPointYOffset={extraAnchorPointYOffset}
|
|
108
113
|
componentsMapExtraProps={componentsMapExtraProps}
|
|
114
|
+
groupId={groupId}
|
|
109
115
|
/>
|
|
110
116
|
);
|
|
111
117
|
};
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { compose } from "ramda";
|
|
2
2
|
import { River as RiverComponent } from "./River";
|
|
3
|
-
import { withTvEventHandler } from "./withTVEventHandler";
|
|
4
3
|
import { withComponentsMapOffsetContext } from "../../../Contexts/ComponentsMapOffsetContext";
|
|
5
4
|
import { withRiverDataLoader } from "./withRiverDataLoader";
|
|
5
|
+
import { withFocusableGroupForContent } from "./withFocusableGroupForContent";
|
|
6
6
|
|
|
7
7
|
export const River = compose(
|
|
8
|
-
withTvEventHandler,
|
|
9
8
|
withComponentsMapOffsetContext,
|
|
10
|
-
withRiverDataLoader
|
|
9
|
+
withRiverDataLoader,
|
|
10
|
+
withFocusableGroupForContent
|
|
11
11
|
)(RiverComponent);
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { View } from "react-native";
|
|
3
|
+
|
|
4
|
+
import { FocusableGroup } from "@applicaster/zapp-react-native-ui-components/Components/FocusableGroup";
|
|
5
|
+
import { riverFocusManager } from "@applicaster/zapp-react-native-utils/appUtils/RiverFocusManager";
|
|
6
|
+
import { toNumberWithDefaultZero } from "@applicaster/zapp-react-native-utils/numberUtils";
|
|
7
|
+
|
|
8
|
+
import { useSubscriberFor } from "@applicaster/zapp-react-native-utils/reactHooks/useSubscriberFor";
|
|
9
|
+
import { QBUIComponentEvents } from "@applicaster/zapp-react-native-ui-components/events";
|
|
10
|
+
|
|
11
|
+
import { QUICK_BRICK_TOP_CONTAINER } from "@applicaster/quick-brick-core/const";
|
|
12
|
+
|
|
13
|
+
const useTopMenuLayout = () => {
|
|
14
|
+
const [layout, setLayout] = React.useState(undefined);
|
|
15
|
+
|
|
16
|
+
const handleLayout = React.useCallback((layout) => {
|
|
17
|
+
setLayout(layout);
|
|
18
|
+
}, []);
|
|
19
|
+
|
|
20
|
+
useSubscriberFor(QBUIComponentEvents.topMenuBarTV_onLayout, handleLayout);
|
|
21
|
+
|
|
22
|
+
return layout;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const withFocusableGroupForContent = (Component) => {
|
|
26
|
+
return function (props) {
|
|
27
|
+
const { screenId, isInsideContainer } = props;
|
|
28
|
+
|
|
29
|
+
const topMenuLayout = useTopMenuLayout();
|
|
30
|
+
|
|
31
|
+
const focusableId = React.useMemo(
|
|
32
|
+
() =>
|
|
33
|
+
riverFocusManager.screenFocusableGroupId({
|
|
34
|
+
screenId,
|
|
35
|
+
isInsideContainer,
|
|
36
|
+
}),
|
|
37
|
+
[screenId, isInsideContainer]
|
|
38
|
+
);
|
|
39
|
+
|
|
40
|
+
if (isInsideContainer) {
|
|
41
|
+
return <Component {...props} />;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const topMenuHeight = toNumberWithDefaultZero(topMenuLayout?.height);
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<FocusableGroup
|
|
48
|
+
key={focusableId}
|
|
49
|
+
id={focusableId}
|
|
50
|
+
// workaround to avoid intersection between FocusableGroup for content and FocusableGroup for top-menu
|
|
51
|
+
style={{ flex: 1, marginTop: topMenuHeight }}
|
|
52
|
+
groupId={QUICK_BRICK_TOP_CONTAINER}
|
|
53
|
+
>
|
|
54
|
+
<View style={{ flex: 1, marginTop: -1 * topMenuHeight }}>
|
|
55
|
+
<Component {...props} groupId={focusableId} />
|
|
56
|
+
</View>
|
|
57
|
+
</FocusableGroup>
|
|
58
|
+
);
|
|
59
|
+
};
|
|
60
|
+
};
|
|
@@ -24,12 +24,16 @@ export const getDatasourceUrl: (
|
|
|
24
24
|
) => {
|
|
25
25
|
const { source, mapping } = R.propOr({}, ["data"], component);
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
27
|
+
if (mapping) {
|
|
28
|
+
const contexts = {
|
|
29
|
+
entry: entryContext,
|
|
30
|
+
screen: screenContext || screenData,
|
|
31
|
+
search: getSearchContext(searchContext, mapping),
|
|
32
|
+
};
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
return getInflatedDataSourceUrl({ source, mapping, contexts });
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return source;
|
|
34
38
|
}
|
|
35
39
|
);
|
package/events/index.ts
CHANGED
|
@@ -5,4 +5,6 @@ export enum QBUIComponentEvents {
|
|
|
5
5
|
scrollVerticallyToInitialOffset = "scrollVerticallyToInitialOffset",
|
|
6
6
|
focusOnSelectedTab = "focusOnSelectedTab",
|
|
7
7
|
focusOnSelectedTopMenuItem = "focusOnSelectedTopMenuItem",
|
|
8
|
+
focusOnHomeTopMenuItem = "focusOnHomeTopMenuItem",
|
|
9
|
+
topMenuBarTV_onLayout = "topMenuBarTV_onLayout",
|
|
8
10
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@applicaster/zapp-react-native-ui-components",
|
|
3
|
-
"version": "15.0.0-alpha.
|
|
3
|
+
"version": "15.0.0-alpha.2239032089",
|
|
4
4
|
"description": "Applicaster Zapp React Native ui components for the Quick Brick App",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -28,10 +28,10 @@
|
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://github.com/applicaster/quickbrick#readme",
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@applicaster/applicaster-types": "15.0.0-alpha.
|
|
32
|
-
"@applicaster/zapp-react-native-bridge": "15.0.0-alpha.
|
|
33
|
-
"@applicaster/zapp-react-native-redux": "15.0.0-alpha.
|
|
34
|
-
"@applicaster/zapp-react-native-utils": "15.0.0-alpha.
|
|
31
|
+
"@applicaster/applicaster-types": "15.0.0-alpha.2239032089",
|
|
32
|
+
"@applicaster/zapp-react-native-bridge": "15.0.0-alpha.2239032089",
|
|
33
|
+
"@applicaster/zapp-react-native-redux": "15.0.0-alpha.2239032089",
|
|
34
|
+
"@applicaster/zapp-react-native-utils": "15.0.0-alpha.2239032089",
|
|
35
35
|
"promise": "^8.3.0",
|
|
36
36
|
"url": "^0.11.0",
|
|
37
37
|
"uuid": "^3.3.2"
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/* eslint max-len: off */
|
|
2
|
-
|
|
3
|
-
import React from "react";
|
|
4
|
-
import { TVEventHandlerComponent } from "@applicaster/zapp-react-native-tvos-ui-components/Components/TVEventHandlerComponent";
|
|
5
|
-
import { useNavigation } from "@applicaster/zapp-react-native-utils/reactHooks";
|
|
6
|
-
|
|
7
|
-
export const withTvEventHandler = (Component) => {
|
|
8
|
-
return function WithTVEventHandler(props) {
|
|
9
|
-
const navigator = useNavigation();
|
|
10
|
-
|
|
11
|
-
const remoteHandler = (event) => {
|
|
12
|
-
const { eventType } = event;
|
|
13
|
-
|
|
14
|
-
const canGoBack = navigator.canGoBack();
|
|
15
|
-
|
|
16
|
-
if (eventType === "menu" && canGoBack) {
|
|
17
|
-
navigator.goBack();
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
return (
|
|
22
|
-
<TVEventHandlerComponent tvEventHandler={remoteHandler}>
|
|
23
|
-
<Component {...props} />
|
|
24
|
-
</TVEventHandlerComponent>
|
|
25
|
-
);
|
|
26
|
-
};
|
|
27
|
-
};
|