@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.
Files changed (25) hide show
  1. package/Components/Cell/Cell.tsx +64 -91
  2. package/Components/Cell/CellWithFocusable.tsx +0 -3
  3. package/Components/FeedLoader/FeedLoader.tsx +1 -1
  4. package/Components/Focusable/Focusable.tsx +3 -10
  5. package/Components/Focusable/FocusableTvOS.tsx +2 -2
  6. package/Components/Focusable/Touchable.tsx +6 -3
  7. package/Components/Focusable/index.android.tsx +11 -4
  8. package/Components/FocusableGroup/FocusableTvOS.tsx +1 -1
  9. package/Components/FocusableList/FocusableItem.tsx +18 -3
  10. package/Components/FocusableList/FocusableListItemWrapper.tsx +2 -1
  11. package/Components/FocusableList/hooks/useCellState.android.ts +13 -3
  12. package/Components/FocusableList/index.tsx +16 -9
  13. package/Components/MasterCell/DefaultComponents/ActionButton.tsx +4 -2
  14. package/Components/MasterCell/DefaultComponents/FocusableView/index.tsx +12 -0
  15. package/Components/MasterCell/DefaultComponents/Text/index.tsx +6 -26
  16. package/Components/PlayerContainer/PlayerContainer.tsx +4 -1
  17. package/Components/Screen/__tests__/navigationHandler.test.ts +133 -22
  18. package/Components/Screen/navigationHandler.ts +20 -2
  19. package/Components/Tabs/TV/Tabs.android.tsx +1 -1
  20. package/Components/TextInputTv/__tests__/__snapshots__/TextInputTv.test.js.snap +0 -13
  21. package/Components/TextInputTv/index.tsx +0 -11
  22. package/Components/VideoModal/ModalAnimation/AnimatedScrollModal.web.tsx +294 -0
  23. package/Components/VideoModal/ModalAnimation/AnimatedVideoPlayerComponent.web.tsx +93 -0
  24. package/package.json +5 -5
  25. package/Contexts/CellFocusedStateContext/index.tsx +0 -27
@@ -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
- <CellFocusedStateContextProvider cellFocused={this.state.cellFocused}>
260
- <CellWithFocusable
261
- CellRenderer={CellRenderer}
262
- item={item}
263
- id={focusableId}
264
- groupId={groupId || component?.id}
265
- onFocus={handleFocus}
266
- onBlur={onBlur || this.onBlur}
267
- index={index}
268
- scrollTo={this.scrollToIndex()}
269
- isFocusable={isFocusable}
270
- skipFocusManagerRegistration={skipFocusManagerRegistration}
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
- <CellFocusedStateContextProvider cellFocused={this.state.cellFocused}>
279
- <View
280
- testID={`${component?.id}-${id}`}
281
- accessible={false}
282
- style={styles.touchableCell}
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
- <Focusable
285
- id={focusableId}
286
- groupId={groupId || component?.id}
287
- onFocus={handleFocus}
288
- onBlur={onBlur || this.onBlur}
289
- onPress={this.onPress}
290
- willReceiveFocus={willReceiveFocus || this.willReceiveFocus}
291
- hasReceivedFocus={hasReceivedFocus || this.hasReceivedFocus}
292
- preferredFocus={preferredFocus}
293
- offsetUpdater={offsetUpdater}
294
- style={styles.baseCell}
295
- isFocusable={isFocusable}
296
- skipFocusManagerRegistration={skipFocusManagerRegistration}
297
- {...this.accessibilityManager.getButtonAccessibilityProps(
298
- item?.extensions?.accessibility?.label || item?.title
299
- )}
300
- >
301
- {(focused, event) => {
302
- const isFocused = this.isCellFocused(focused);
303
-
304
- return (
305
- <FocusableCell
306
- {...{
307
- index,
308
- CellRenderer,
309
- item,
310
- focused: isFocused,
311
- scrollTo: this.scrollToIndex(event),
312
- behavior,
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.ComponentType<any>;
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.ComponentType<any>;
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
- {...accessibilityProps}
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
- {R.is(Function, children) ? children(focused) : children}
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}>
@@ -22,7 +22,7 @@ type FocusableGroupNativeEvent = {
22
22
 
23
23
  type Props = {
24
24
  id: string;
25
- children: (arg1: boolean) => React.ComponentType<any>;
25
+ children: React.ReactNode;
26
26
  isFocusDisabled: boolean;
27
27
  isWithMemory: boolean;
28
28
  focusGroupRef: React.Component;
@@ -10,7 +10,8 @@ type FocusableItemComponentProps = {
10
10
  onFocus: (
11
11
  element: FocusManager.FocusableRef,
12
12
  renderArgs: { item: FocusableItemComponentProps["item"]; index: number },
13
- direction: FocusManager.Android.FocusNavigationDirections
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, direction) => {
49
- onFocus?.(element, renderArgs, direction);
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
- direction: FocusManager.Android.FocusNavigationDirections
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 handler = (focusable) => {
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, handler);
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, handler);
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: IListRenderItemInfo<ItemT> & {
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?: (any, RenderItemProps, Direction) => void;
40
- onListElementBlur?: (any, RenderItemProps, Direction) => void;
41
- onListElementPress?: (any, RenderItemProps) => void;
42
- onListElementPressOut?: (any, RenderItemProps) => void;
43
- onListElementLongPress?: (any, RenderItemProps) => void;
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, direction) => {
148
+ (element, renderArgs, options, context) => {
142
149
  const { index } = renderArgs;
143
150
 
144
151
  updateFocusedIndex?.(index);
145
- onListElementFocus?.(element, renderArgs, direction);
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 function ActionButton(props: Props) {
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) => {