@applicaster/zapp-react-native-ui-components 14.0.0-alpha.3514550494 → 14.0.0-alpha.3652810444
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/Cell/Cell.tsx +64 -91
- package/Components/Cell/CellWithFocusable.tsx +0 -3
- package/Components/FeedLoader/FeedLoader.tsx +1 -1
- package/Components/Focusable/Focusable.tsx +3 -10
- package/Components/Focusable/FocusableTvOS.tsx +2 -2
- package/Components/Focusable/Touchable.tsx +6 -3
- package/Components/Focusable/index.android.tsx +11 -4
- package/Components/FocusableGroup/FocusableTvOS.tsx +1 -1
- package/Components/FocusableList/FocusableItem.tsx +18 -3
- package/Components/FocusableList/FocusableListItemWrapper.tsx +2 -1
- package/Components/FocusableList/hooks/useCellState.android.ts +13 -3
- package/Components/FocusableList/index.tsx +16 -9
- package/Components/MasterCell/DefaultComponents/ActionButton.tsx +4 -2
- package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +12 -0
- package/Components/MasterCell/DefaultComponents/Text/index.tsx +6 -26
- package/Components/PlayerContainer/PlayerContainer.tsx +4 -1
- package/Components/Screen/__tests__/navigationHandler.test.ts +133 -22
- package/Components/Screen/navigationHandler.ts +20 -2
- package/Components/Tabs/TV/Tabs.android.tsx +1 -1
- package/Components/TextInputTv/__tests__/__snapshots__/TextInputTv.test.js.snap +0 -13
- package/Components/TextInputTv/index.tsx +0 -11
- package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.web.tsx +294 -0
- package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.web.tsx +93 -0
- package/package.json +5 -5
- package/Contexts/CellFocusedStateContext/index.tsx +0 -27
package/Components/Cell/Cell.tsx
CHANGED
|
@@ -8,7 +8,6 @@ import { getItemType } from "@applicaster/zapp-react-native-utils/navigationUtil
|
|
|
8
8
|
import { SCREEN_TYPES } from "@applicaster/zapp-react-native-utils/navigationUtils/itemTypes";
|
|
9
9
|
import { sendSelectCellEvent } from "@applicaster/zapp-react-native-utils/analyticsUtils";
|
|
10
10
|
import { noop } from "@applicaster/zapp-react-native-utils/functionUtils";
|
|
11
|
-
import { CellFocusedStateContextProvider } from "@applicaster/zapp-react-native-ui-components/Contexts/CellFocusedStateContext";
|
|
12
11
|
|
|
13
12
|
import { CellWithFocusable } from "./CellWithFocusable";
|
|
14
13
|
import { BaseFocusable } from "../BaseFocusable";
|
|
@@ -16,7 +15,6 @@ import { AccessibilityManager } from "@applicaster/zapp-react-native-utils/appUt
|
|
|
16
15
|
import { styles } from "./styles";
|
|
17
16
|
|
|
18
17
|
type Props = {
|
|
19
|
-
dataLength: number;
|
|
20
18
|
item: ZappEntry;
|
|
21
19
|
index: number;
|
|
22
20
|
shouldScrollHorizontally: (arg1: [any]) => boolean | null | undefined;
|
|
@@ -69,12 +67,9 @@ type Props = {
|
|
|
69
67
|
|
|
70
68
|
type State = {
|
|
71
69
|
hasFocusableInside: boolean;
|
|
72
|
-
cellFocused: boolean;
|
|
73
70
|
};
|
|
74
71
|
|
|
75
72
|
export class CellComponent extends React.Component<Props, State> {
|
|
76
|
-
accessibilityManager: AccessibilityManager;
|
|
77
|
-
|
|
78
73
|
constructor(props) {
|
|
79
74
|
super(props);
|
|
80
75
|
this.onPress = this.onPress.bind(this);
|
|
@@ -84,14 +79,10 @@ export class CellComponent extends React.Component<Props, State> {
|
|
|
84
79
|
this.hasReceivedFocus = this.hasReceivedFocus.bind(this);
|
|
85
80
|
this.scrollVertically = this.scrollVertically.bind(this);
|
|
86
81
|
this.scrollToIndex = this.scrollToIndex.bind(this);
|
|
87
|
-
this.handleAccessibilityFocus = this.handleAccessibilityFocus.bind(this);
|
|
88
82
|
|
|
89
83
|
this.state = {
|
|
90
84
|
hasFocusableInside: props.CellRenderer.hasFocusableInside?.(props.item),
|
|
91
|
-
cellFocused: false,
|
|
92
85
|
};
|
|
93
|
-
|
|
94
|
-
this.accessibilityManager = AccessibilityManager.getInstance();
|
|
95
86
|
}
|
|
96
87
|
|
|
97
88
|
setScreenLayout(componentAnchorPointY, screenLayout) {
|
|
@@ -139,8 +130,6 @@ export class CellComponent extends React.Component<Props, State> {
|
|
|
139
130
|
} = this.props;
|
|
140
131
|
|
|
141
132
|
if (isFocusable) {
|
|
142
|
-
this.setState({ cellFocused: true });
|
|
143
|
-
|
|
144
133
|
if (
|
|
145
134
|
shouldUpdate &&
|
|
146
135
|
shouldScrollVertically?.(mouse, focusable, id, title)
|
|
@@ -150,9 +139,7 @@ export class CellComponent extends React.Component<Props, State> {
|
|
|
150
139
|
}
|
|
151
140
|
}
|
|
152
141
|
|
|
153
|
-
onBlur() {
|
|
154
|
-
this.setState({ cellFocused: false });
|
|
155
|
-
}
|
|
142
|
+
onBlur() {}
|
|
156
143
|
|
|
157
144
|
willReceiveFocus() {}
|
|
158
145
|
|
|
@@ -196,25 +183,6 @@ export class CellComponent extends React.Component<Props, State> {
|
|
|
196
183
|
return !isFocusable ? false : focused || focusableFocused;
|
|
197
184
|
}
|
|
198
185
|
|
|
199
|
-
handleAccessibilityFocus(index, dataLength) {
|
|
200
|
-
// For loop scrolling, calculate the correct logical index
|
|
201
|
-
const logicalIndex = dataLength ? index % dataLength : index;
|
|
202
|
-
|
|
203
|
-
const positionLabel = dataLength
|
|
204
|
-
? `item ${logicalIndex + 1} of ${dataLength}`
|
|
205
|
-
: "";
|
|
206
|
-
|
|
207
|
-
if (this.state.hasFocusableInside) {
|
|
208
|
-
this.accessibilityManager.readText({
|
|
209
|
-
text: " ",
|
|
210
|
-
});
|
|
211
|
-
} else {
|
|
212
|
-
this.accessibilityManager.readText({
|
|
213
|
-
text: `${positionLabel}`,
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
186
|
componentDidUpdate(prevProps: Readonly<Props>) {
|
|
219
187
|
if (prevProps.item !== this.props.item) {
|
|
220
188
|
this.setState({
|
|
@@ -223,8 +191,6 @@ export class CellComponent extends React.Component<Props, State> {
|
|
|
223
191
|
),
|
|
224
192
|
});
|
|
225
193
|
}
|
|
226
|
-
|
|
227
|
-
this.handleAccessibilityFocus(this.props.index, this.props.dataLength);
|
|
228
194
|
}
|
|
229
195
|
|
|
230
196
|
render() {
|
|
@@ -246,6 +212,7 @@ export class CellComponent extends React.Component<Props, State> {
|
|
|
246
212
|
} = this.props;
|
|
247
213
|
|
|
248
214
|
const { id } = item;
|
|
215
|
+
|
|
249
216
|
const focusableId = join("-", [component?.id, id, index]);
|
|
250
217
|
|
|
251
218
|
const handleFocus = (focusable, mouse) => {
|
|
@@ -256,67 +223,73 @@ export class CellComponent extends React.Component<Props, State> {
|
|
|
256
223
|
|
|
257
224
|
if (this.state.hasFocusableInside) {
|
|
258
225
|
return (
|
|
259
|
-
<
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
behavior={behavior}
|
|
272
|
-
/>
|
|
273
|
-
</CellFocusedStateContextProvider>
|
|
226
|
+
<CellWithFocusable
|
|
227
|
+
CellRenderer={CellRenderer}
|
|
228
|
+
item={item}
|
|
229
|
+
id={focusableId}
|
|
230
|
+
groupId={groupId || component?.id}
|
|
231
|
+
onFocus={handleFocus}
|
|
232
|
+
index={index}
|
|
233
|
+
scrollTo={this.scrollToIndex()}
|
|
234
|
+
isFocusable={isFocusable}
|
|
235
|
+
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
236
|
+
behavior={behavior}
|
|
237
|
+
/>
|
|
274
238
|
);
|
|
275
239
|
}
|
|
276
240
|
|
|
277
241
|
return (
|
|
278
|
-
<
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
242
|
+
<View
|
|
243
|
+
testID={`${component?.id}-${id}`}
|
|
244
|
+
accessible={false}
|
|
245
|
+
style={styles.touchableCell}
|
|
246
|
+
>
|
|
247
|
+
<Focusable
|
|
248
|
+
id={focusableId}
|
|
249
|
+
groupId={groupId || component?.id}
|
|
250
|
+
onFocus={handleFocus}
|
|
251
|
+
onBlur={onBlur || this.onBlur}
|
|
252
|
+
onPress={this.onPress}
|
|
253
|
+
willReceiveFocus={willReceiveFocus || this.willReceiveFocus}
|
|
254
|
+
hasReceivedFocus={hasReceivedFocus || this.hasReceivedFocus}
|
|
255
|
+
preferredFocus={preferredFocus}
|
|
256
|
+
offsetUpdater={offsetUpdater}
|
|
257
|
+
style={styles.baseCell}
|
|
258
|
+
isFocusable={isFocusable}
|
|
259
|
+
skipFocusManagerRegistration={skipFocusManagerRegistration}
|
|
283
260
|
>
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
}}
|
|
317
|
-
</Focusable>
|
|
318
|
-
</View>
|
|
319
|
-
</CellFocusedStateContextProvider>
|
|
261
|
+
{(focused, event) => {
|
|
262
|
+
const isFocused = this.isCellFocused(focused);
|
|
263
|
+
|
|
264
|
+
if (isFocused) {
|
|
265
|
+
const accessibilityManager = AccessibilityManager.getInstance();
|
|
266
|
+
|
|
267
|
+
const accessibilityTitle =
|
|
268
|
+
item?.extensions?.accessibility?.label || item?.title || "";
|
|
269
|
+
|
|
270
|
+
const accessibilityHint =
|
|
271
|
+
item?.extensions?.accessibility?.hint || "";
|
|
272
|
+
|
|
273
|
+
accessibilityManager.readText({
|
|
274
|
+
text: `${accessibilityTitle} ${accessibilityHint}`,
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
return (
|
|
279
|
+
<FocusableCell
|
|
280
|
+
{...{
|
|
281
|
+
index,
|
|
282
|
+
CellRenderer,
|
|
283
|
+
item,
|
|
284
|
+
focused: isFocused,
|
|
285
|
+
scrollTo: this.scrollToIndex(event),
|
|
286
|
+
behavior,
|
|
287
|
+
}}
|
|
288
|
+
/>
|
|
289
|
+
);
|
|
290
|
+
}}
|
|
291
|
+
</Focusable>
|
|
292
|
+
</View>
|
|
320
293
|
);
|
|
321
294
|
}
|
|
322
295
|
}
|
|
@@ -14,7 +14,6 @@ type Props = {
|
|
|
14
14
|
id: string;
|
|
15
15
|
groupId: string;
|
|
16
16
|
onFocus: Function;
|
|
17
|
-
onBlur?: Function;
|
|
18
17
|
index: number;
|
|
19
18
|
scrollTo: Function;
|
|
20
19
|
preferredFocus?: boolean;
|
|
@@ -34,7 +33,6 @@ export function CellWithFocusable(props: Props) {
|
|
|
34
33
|
id,
|
|
35
34
|
groupId,
|
|
36
35
|
onFocus,
|
|
37
|
-
onBlur = noop,
|
|
38
36
|
scrollTo = noop,
|
|
39
37
|
preferredFocus,
|
|
40
38
|
skipFocusManagerRegistration,
|
|
@@ -80,7 +78,6 @@ export function CellWithFocusable(props: Props) {
|
|
|
80
78
|
const onGroupBlur = React.useCallback(() => {
|
|
81
79
|
if (!skipFocusManagerRegistration) {
|
|
82
80
|
setIsFocused(false);
|
|
83
|
-
onBlur?.();
|
|
84
81
|
}
|
|
85
82
|
}, [skipFocusManagerRegistration]);
|
|
86
83
|
|
|
@@ -8,7 +8,7 @@ type Props = {
|
|
|
8
8
|
typeof import("@applicaster/zapp-react-native-utils/reactHooks/feed").useLoadPipesDataDispatch
|
|
9
9
|
>;
|
|
10
10
|
feedUrl: string;
|
|
11
|
-
children: (feed: ZappFeed) => React.
|
|
11
|
+
children: (feed: ZappFeed) => React.ReactNode;
|
|
12
12
|
onFeedLoaded: (feed: ZappFeed) => {};
|
|
13
13
|
onError: (error: ZappPipesData["error"]) => {};
|
|
14
14
|
refreshing: boolean;
|
|
@@ -6,7 +6,6 @@ import { focusManager } from "@applicaster/zapp-react-native-utils/appUtils/focu
|
|
|
6
6
|
import { LONG_KEY_PRESS_TIMEOUT } from "@applicaster/quick-brick-core/const";
|
|
7
7
|
import { withFocusableContext } from "../../Contexts/FocusableGroupContext/withFocusableContext";
|
|
8
8
|
import { StyleSheet, ViewStyle } from "react-native";
|
|
9
|
-
import { AccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager";
|
|
10
9
|
|
|
11
10
|
type Props = {
|
|
12
11
|
initialFocus?: boolean;
|
|
@@ -21,7 +20,7 @@ type Props = {
|
|
|
21
20
|
onPressOut?: () => void;
|
|
22
21
|
onLongPress?: () => void;
|
|
23
22
|
handleFocus?: ({ mouse }: { mouse: boolean }) => void;
|
|
24
|
-
children: (boolean, string) => React.
|
|
23
|
+
children: (boolean, string) => React.ReactNode;
|
|
25
24
|
selected?: boolean;
|
|
26
25
|
style?: ViewStyle[] | ViewStyle;
|
|
27
26
|
};
|
|
@@ -30,7 +29,6 @@ class Focusable extends BaseFocusable<Props> {
|
|
|
30
29
|
isGroup: boolean;
|
|
31
30
|
mouse: boolean;
|
|
32
31
|
longPressTimeout = null;
|
|
33
|
-
accessibilityManager: AccessibilityManager;
|
|
34
32
|
|
|
35
33
|
constructor(props) {
|
|
36
34
|
super(props);
|
|
@@ -45,8 +43,6 @@ class Focusable extends BaseFocusable<Props> {
|
|
|
45
43
|
this.resetLongPressTimeout = this.resetLongPressTimeout.bind(this);
|
|
46
44
|
this.longPress = this.longPress.bind(this);
|
|
47
45
|
this.press = this.press.bind(this);
|
|
48
|
-
|
|
49
|
-
this.accessibilityManager = AccessibilityManager.getInstance();
|
|
50
46
|
}
|
|
51
47
|
|
|
52
48
|
/**
|
|
@@ -127,15 +123,12 @@ class Focusable extends BaseFocusable<Props> {
|
|
|
127
123
|
}
|
|
128
124
|
|
|
129
125
|
render() {
|
|
130
|
-
const { children, style } = this.props;
|
|
126
|
+
const { children, style, ...otherProps } = this.props;
|
|
131
127
|
const { focused } = this.state;
|
|
132
128
|
|
|
133
129
|
const id = this.getId();
|
|
134
130
|
const focusableId = `focusable-${id}`;
|
|
135
131
|
|
|
136
|
-
const accessibilityProps =
|
|
137
|
-
this.accessibilityManager.getWebAccessibilityProps(this.props);
|
|
138
|
-
|
|
139
132
|
return (
|
|
140
133
|
<div
|
|
141
134
|
id={focusableId}
|
|
@@ -148,7 +141,7 @@ class Focusable extends BaseFocusable<Props> {
|
|
|
148
141
|
data-testid={focusableId}
|
|
149
142
|
focused-teststate={focused ? "focused" : "default"}
|
|
150
143
|
style={StyleSheet.flatten(style) as any as React.CSSProperties}
|
|
151
|
-
{...
|
|
144
|
+
{...otherProps}
|
|
152
145
|
>
|
|
153
146
|
{children(focused, { mouse: this.mouse })}
|
|
154
147
|
</div>
|
|
@@ -19,7 +19,7 @@ type Props = {
|
|
|
19
19
|
onPress?: (nativeEvent: any) => void;
|
|
20
20
|
onFocus?: (nativeEvent: any) => void;
|
|
21
21
|
onBlur?: (nativeEvent: any) => void;
|
|
22
|
-
children: (focused?: boolean) => React.ReactNode;
|
|
22
|
+
children: ((focused?: boolean) => React.ReactNode) | React.ReactNode;
|
|
23
23
|
isParallaxDisabled: boolean;
|
|
24
24
|
preferredFocus?: boolean;
|
|
25
25
|
selected?: boolean;
|
|
@@ -204,7 +204,7 @@ export class Focusable extends BaseFocusable<Props> {
|
|
|
204
204
|
{...this.nextFocusableReactTags}
|
|
205
205
|
{...otherProps}
|
|
206
206
|
>
|
|
207
|
-
{
|
|
207
|
+
{typeof children === "function" ? children(focused) : children}
|
|
208
208
|
</FocusableItemNative>
|
|
209
209
|
);
|
|
210
210
|
}
|
|
@@ -9,7 +9,8 @@ type Props = {
|
|
|
9
9
|
onLongPress?: (ref: FocusManager.TouchableRef) => void;
|
|
10
10
|
onFocus?: (
|
|
11
11
|
ref: FocusManager.TouchableRef,
|
|
12
|
-
options: FocusManager.Android.CallbackOptions
|
|
12
|
+
options: FocusManager.Android.CallbackOptions,
|
|
13
|
+
context: Option<FocusManager.FocusContext>
|
|
13
14
|
) => void;
|
|
14
15
|
onBlur?: (
|
|
15
16
|
ref: FocusManager.TouchableRef,
|
|
@@ -18,6 +19,7 @@ type Props = {
|
|
|
18
19
|
|
|
19
20
|
disableFocus?: boolean;
|
|
20
21
|
blockFocus?: boolean;
|
|
22
|
+
isSelected: (id?: string) => boolean;
|
|
21
23
|
} & Partial<ParentFocus>;
|
|
22
24
|
|
|
23
25
|
export class Touchable extends React.Component<Props> {
|
|
@@ -39,9 +41,10 @@ export class Touchable extends React.Component<Props> {
|
|
|
39
41
|
|
|
40
42
|
onFocus(
|
|
41
43
|
focusableRef: FocusManager.TouchableRef,
|
|
42
|
-
options: FocusManager.Android.CallbackOptions
|
|
44
|
+
options: FocusManager.Android.CallbackOptions,
|
|
45
|
+
context: Option<FocusManager.FocusContext>
|
|
43
46
|
): void {
|
|
44
|
-
this.props?.onFocus?.(focusableRef, options);
|
|
47
|
+
this.props?.onFocus?.(focusableRef, options, context);
|
|
45
48
|
}
|
|
46
49
|
|
|
47
50
|
onBlur(
|
|
@@ -22,7 +22,8 @@ type Props = {
|
|
|
22
22
|
onPress?: (ref: FocusManager.FocusableRef) => void;
|
|
23
23
|
onFocus?: (
|
|
24
24
|
ref: FocusManager.FocusableRef,
|
|
25
|
-
options: FocusManager.Android.CallbackOptions
|
|
25
|
+
options: FocusManager.Android.CallbackOptions,
|
|
26
|
+
context?: FocusManager.FocusContext
|
|
26
27
|
) => void;
|
|
27
28
|
onBlur?: (
|
|
28
29
|
ref: FocusManager.FocusableRef,
|
|
@@ -32,9 +33,11 @@ type Props = {
|
|
|
32
33
|
onPressOut?: (ref: FocusManager.FocusableRef) => void;
|
|
33
34
|
onLongPress?: (ref: FocusManager.FocusableRef) => void;
|
|
34
35
|
onRegister?: () => void;
|
|
36
|
+
onUnregister?: () => void;
|
|
35
37
|
isFocusableCell?: boolean;
|
|
36
38
|
/** only for FocusableScrollView */
|
|
37
39
|
onSetIsFocusable?: (isFocusable: boolean) => void;
|
|
40
|
+
isSelected?: (id?: string) => boolean;
|
|
38
41
|
} & ParentFocus;
|
|
39
42
|
|
|
40
43
|
export const FocusableContext = React.createContext<
|
|
@@ -70,8 +73,10 @@ function FocusableComponent(props: Props, forwardedRef) {
|
|
|
70
73
|
onPressOut,
|
|
71
74
|
onLongPress,
|
|
72
75
|
onRegister = noop,
|
|
76
|
+
onUnregister = noop,
|
|
73
77
|
isFocusableCell = true,
|
|
74
78
|
onSetIsFocusable,
|
|
79
|
+
isSelected,
|
|
75
80
|
} = props;
|
|
76
81
|
|
|
77
82
|
const isRTL = useIsRTL();
|
|
@@ -113,9 +118,10 @@ function FocusableComponent(props: Props, forwardedRef) {
|
|
|
113
118
|
|
|
114
119
|
return () => {
|
|
115
120
|
unregister();
|
|
121
|
+
onUnregister();
|
|
116
122
|
};
|
|
117
123
|
}
|
|
118
|
-
}, [id, onRegister, isFocusableCell, parentFocusableId]);
|
|
124
|
+
}, [id, onRegister, onUnregister, isFocusableCell, parentFocusableId]);
|
|
119
125
|
|
|
120
126
|
if (R.isNil(id)) {
|
|
121
127
|
// eslint-disable-next-line no-console
|
|
@@ -125,9 +131,9 @@ function FocusableComponent(props: Props, forwardedRef) {
|
|
|
125
131
|
}
|
|
126
132
|
|
|
127
133
|
const _onFocus = React.useCallback(
|
|
128
|
-
(ref, options) => {
|
|
134
|
+
(ref, options, context) => {
|
|
129
135
|
setFocused(true);
|
|
130
|
-
onFocus?.(ref, options);
|
|
136
|
+
onFocus?.(ref, options, context);
|
|
131
137
|
},
|
|
132
138
|
[onFocus]
|
|
133
139
|
);
|
|
@@ -183,6 +189,7 @@ function FocusableComponent(props: Props, forwardedRef) {
|
|
|
183
189
|
blockFocus={blockFocus}
|
|
184
190
|
onPressIn={onPressIn}
|
|
185
191
|
onPressOut={onPressOut}
|
|
192
|
+
isSelected={isSelected}
|
|
186
193
|
{...parentFocus}
|
|
187
194
|
>
|
|
188
195
|
<FocusableContext.Provider value={contextState}>
|
|
@@ -10,7 +10,8 @@ type FocusableItemComponentProps = {
|
|
|
10
10
|
onFocus: (
|
|
11
11
|
element: FocusManager.FocusableRef,
|
|
12
12
|
renderArgs: { item: FocusableItemComponentProps["item"]; index: number },
|
|
13
|
-
|
|
13
|
+
options: FocusManager.Android.CallbackOptions,
|
|
14
|
+
context: Option<FocusManager.FocusContext>
|
|
14
15
|
) => void;
|
|
15
16
|
onListElementFocus?: (any, RenderItemProps, Direction) => void;
|
|
16
17
|
onListElementBlur?: (any, RenderItemProps, Direction) => void;
|
|
@@ -45,8 +46,8 @@ const FocusableItemComponent = ({
|
|
|
45
46
|
const renderArgs = { item, index };
|
|
46
47
|
|
|
47
48
|
const onFocusHandler = React.useCallback(
|
|
48
|
-
(element,
|
|
49
|
-
onFocus?.(element, renderArgs,
|
|
49
|
+
(element, options, context) => {
|
|
50
|
+
onFocus?.(element, renderArgs, options, context);
|
|
50
51
|
},
|
|
51
52
|
[item, onFocus]
|
|
52
53
|
);
|
|
@@ -79,6 +80,19 @@ const FocusableItemComponent = ({
|
|
|
79
80
|
[item, onListElementPressOut]
|
|
80
81
|
);
|
|
81
82
|
|
|
83
|
+
const isSelected = React.useCallback(
|
|
84
|
+
(itemId: Option<string>) => {
|
|
85
|
+
if (itemId) {
|
|
86
|
+
// case for checking tab item into screen-picker is selected
|
|
87
|
+
return itemId === item.id;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// case for checking top-navbar item is selected
|
|
91
|
+
return item?.data?.target === extraChildrenData;
|
|
92
|
+
},
|
|
93
|
+
[item, extraChildrenData]
|
|
94
|
+
);
|
|
95
|
+
|
|
82
96
|
return (
|
|
83
97
|
<Focusable
|
|
84
98
|
nextFocusDown={nextFocusDown}
|
|
@@ -91,6 +105,7 @@ const FocusableItemComponent = ({
|
|
|
91
105
|
onLongPress={onLongPressHandler}
|
|
92
106
|
onPressOut={onPressOutHandler}
|
|
93
107
|
id={id}
|
|
108
|
+
isSelected={isSelected}
|
|
94
109
|
{...focusableItemProps}
|
|
95
110
|
>
|
|
96
111
|
<FocusableChild
|
|
@@ -17,7 +17,8 @@ type Props = {
|
|
|
17
17
|
onFocus: (
|
|
18
18
|
element: FocusManager.FocusableRef,
|
|
19
19
|
renderArgs: { item: Item; index: number },
|
|
20
|
-
|
|
20
|
+
options: FocusManager.Android.CallbackOptions,
|
|
21
|
+
context: FocusManager.FocusContext
|
|
21
22
|
) => void;
|
|
22
23
|
onListElementBlur?: (any, RenderItemProps, Direction) => void;
|
|
23
24
|
onListElementPress?: (any, RenderItemProps) => void;
|
|
@@ -10,15 +10,25 @@ export const useCellState = (id: string) => {
|
|
|
10
10
|
);
|
|
11
11
|
|
|
12
12
|
React.useEffect(() => {
|
|
13
|
-
const
|
|
13
|
+
const focusHandler = (focusable) => {
|
|
14
14
|
const isChildren = focusManager.isFocusableChildOf(focusable, id);
|
|
15
|
+
|
|
15
16
|
setCurrentCellFocused(isChildren);
|
|
16
17
|
};
|
|
17
18
|
|
|
18
|
-
focusManager.on(FOCUS_EVENTS.FOCUS,
|
|
19
|
+
focusManager.on(FOCUS_EVENTS.FOCUS, focusHandler);
|
|
20
|
+
|
|
21
|
+
const resetHandler = ({ focusedId }) => {
|
|
22
|
+
if (id === focusedId) {
|
|
23
|
+
setCurrentCellFocused(false);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
focusManager.on(FOCUS_EVENTS.RESET, resetHandler);
|
|
19
28
|
|
|
20
29
|
return () => {
|
|
21
|
-
focusManager.removeHandler(FOCUS_EVENTS.FOCUS,
|
|
30
|
+
focusManager.removeHandler(FOCUS_EVENTS.FOCUS, focusHandler);
|
|
31
|
+
focusManager.removeHandler(FOCUS_EVENTS.RESET, resetHandler);
|
|
22
32
|
};
|
|
23
33
|
}, [id]);
|
|
24
34
|
|
|
@@ -20,27 +20,34 @@ import { FocusableScrollView } from "../FocusableScrollView";
|
|
|
20
20
|
const mapIndexed = R.addIndex(R.map);
|
|
21
21
|
|
|
22
22
|
export type IListRenderItem<ItemT> = (
|
|
23
|
-
info:
|
|
23
|
+
info: {
|
|
24
24
|
focused: boolean;
|
|
25
25
|
onLoadFinished: () => void;
|
|
26
26
|
onLoadFailed: () => void;
|
|
27
|
-
}
|
|
27
|
+
} & IListRenderItemInfo<ItemT>
|
|
28
28
|
) => React.ReactElement | null;
|
|
29
29
|
|
|
30
30
|
export const getFocusableId = (parentId, index) =>
|
|
31
31
|
`${parentId}___index:${index}`;
|
|
32
32
|
|
|
33
|
+
type Item = ZappEntry | ZappUIComponent | any;
|
|
34
|
+
|
|
33
35
|
export type Props<ItemT> = FlatListProps<ItemT> & {
|
|
34
36
|
id?: number | string;
|
|
35
37
|
horizontal?: boolean;
|
|
36
38
|
loop?: boolean;
|
|
37
39
|
numColumns?: number;
|
|
38
40
|
data: ZappEntry[] | ZappUIComponent[] | any[];
|
|
39
|
-
onListElementFocus?: (
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
41
|
+
onListElementFocus?: (
|
|
42
|
+
element: FocusManager.FocusableRef,
|
|
43
|
+
renderItemProps: { item: Item; index: number },
|
|
44
|
+
options: FocusManager.Android.CallbackOptions,
|
|
45
|
+
context: FocusManager.FocusContext
|
|
46
|
+
) => void;
|
|
47
|
+
onListElementBlur?: (element, renderItemProps, direction) => void;
|
|
48
|
+
onListElementPress?: (element, renderItemProps) => void;
|
|
49
|
+
onListElementPressOut?: (element, renderItemProps) => void;
|
|
50
|
+
onListElementLongPress?: (element, renderItemProps) => void;
|
|
44
51
|
focusableItemProps?: any;
|
|
45
52
|
focused?: boolean;
|
|
46
53
|
initialScrollIndex?: number;
|
|
@@ -138,11 +145,11 @@ function FocusableListComponent<ItemT>(props: Props<ItemT>, ref) {
|
|
|
138
145
|
);
|
|
139
146
|
|
|
140
147
|
const onFocus = React.useCallback(
|
|
141
|
-
(element, renderArgs,
|
|
148
|
+
(element, renderArgs, options, context) => {
|
|
142
149
|
const { index } = renderArgs;
|
|
143
150
|
|
|
144
151
|
updateFocusedIndex?.(index);
|
|
145
|
-
onListElementFocus?.(element, renderArgs,
|
|
152
|
+
onListElementFocus?.(element, renderArgs, options, context);
|
|
146
153
|
},
|
|
147
154
|
[onListElementFocus, updateFocusedIndex]
|
|
148
155
|
);
|
|
@@ -49,7 +49,9 @@ function getAssetValue(asset, flavour, fallbackAsset = null) {
|
|
|
49
49
|
return asset.src || fallbackAsset;
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
export
|
|
52
|
+
export const ActionButton = React.memo(function ActionButtonComponent(
|
|
53
|
+
props: Props
|
|
54
|
+
) {
|
|
53
55
|
const { item, action, asset, flavour = "flavour_1", cellUUID } = props;
|
|
54
56
|
const actionContext = useActions(action?.identifier);
|
|
55
57
|
|
|
@@ -120,4 +122,4 @@ export function ActionButton(props: Props) {
|
|
|
120
122
|
)}
|
|
121
123
|
</TouchableOpacity>
|
|
122
124
|
);
|
|
123
|
-
}
|
|
125
|
+
});
|
|
@@ -4,6 +4,7 @@ import { Focusable } from "@applicaster/zapp-react-native-ui-components/Componen
|
|
|
4
4
|
import { useActions } from "@applicaster/zapp-react-native-utils/reactHooks/actions";
|
|
5
5
|
import { getXray } from "@applicaster/zapp-react-native-utils/logger";
|
|
6
6
|
import { toBooleanWithDefaultFalse } from "@applicaster/zapp-react-native-utils/booleanUtils";
|
|
7
|
+
import { useAccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks";
|
|
7
8
|
|
|
8
9
|
const { Logger } = getXray();
|
|
9
10
|
|
|
@@ -43,6 +44,11 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
|
|
|
43
44
|
|
|
44
45
|
const actionContext = useActions(pluginIdentifier);
|
|
45
46
|
|
|
47
|
+
const accessibilityManager = useAccessibilityManager({});
|
|
48
|
+
|
|
49
|
+
const { ttsLabel = "" } =
|
|
50
|
+
actionContext?.initialEntryState(item)?.getAccessibility?.(item) || {};
|
|
51
|
+
|
|
46
52
|
const onPress = (event) => {
|
|
47
53
|
event?.preventDefault?.();
|
|
48
54
|
|
|
@@ -65,6 +71,12 @@ export function FocusableView({ style, children, item, ...otherProps }: Props) {
|
|
|
65
71
|
focusedButtonId,
|
|
66
72
|
mouse: focusable.mouse,
|
|
67
73
|
});
|
|
74
|
+
|
|
75
|
+
if (ttsLabel) {
|
|
76
|
+
accessibilityManager.readText({
|
|
77
|
+
text: ttsLabel,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
68
80
|
};
|
|
69
81
|
|
|
70
82
|
const handleBlur = (_focusable, _direction) => {
|