@applicaster/zapp-react-native-utils 15.0.0-rc.12 → 15.0.0-rc.121

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 (159) hide show
  1. package/README.md +0 -6
  2. package/actionsExecutor/ActionExecutorContext.tsx +3 -6
  3. package/actionsExecutor/feedDecorator.ts +6 -6
  4. package/adsUtils/__tests__/createVMAP.test.ts +419 -0
  5. package/adsUtils/index.ts +2 -2
  6. package/analyticsUtils/README.md +1 -1
  7. package/analyticsUtils/analyticsMapper.ts +10 -2
  8. package/appDataUtils/__tests__/urlScheme.test.ts +678 -0
  9. package/appUtils/HooksManager/__tests__/__snapshots__/hooksManager.test.js.snap +0 -188
  10. package/appUtils/HooksManager/__tests__/hooksManager.test.js +16 -2
  11. package/appUtils/HooksManager/index.ts +10 -10
  12. package/appUtils/RiverFocusManager/{index.js → index.ts} +25 -18
  13. package/appUtils/accessibilityManager/__tests__/utils.test.ts +360 -0
  14. package/appUtils/accessibilityManager/const.ts +4 -0
  15. package/appUtils/accessibilityManager/hooks.ts +20 -13
  16. package/appUtils/accessibilityManager/index.ts +28 -1
  17. package/appUtils/accessibilityManager/utils.ts +59 -8
  18. package/appUtils/contextKeysManager/__tests__/getKeys/failure.test.ts +7 -2
  19. package/appUtils/contextKeysManager/__tests__/getKeys/success.test.ts +48 -0
  20. package/appUtils/contextKeysManager/contextResolver.ts +51 -22
  21. package/appUtils/contextKeysManager/index.ts +65 -10
  22. package/appUtils/focusManager/__tests__/__snapshots__/focusManager.test.js.snap +4 -0
  23. package/appUtils/focusManager/index.ios.ts +59 -3
  24. package/appUtils/focusManager/treeDataStructure/Tree/__tests__/Tree.test.js +46 -0
  25. package/appUtils/focusManager/treeDataStructure/Tree/index.js +18 -18
  26. package/appUtils/focusManagerAux/utils/index.ios.ts +122 -0
  27. package/appUtils/focusManagerAux/utils/index.ts +21 -5
  28. package/appUtils/focusManagerAux/utils/utils.ios.ts +234 -0
  29. package/appUtils/keyCodes/keys/keys.web.ts +1 -4
  30. package/appUtils/localizationsHelper.ts +4 -0
  31. package/appUtils/orientationHelper.ts +2 -4
  32. package/appUtils/platform/platformUtils.ts +117 -18
  33. package/appUtils/playerManager/OverlayObserver/OverlaysObserver.ts +94 -4
  34. package/appUtils/playerManager/OverlayObserver/utils.ts +32 -20
  35. package/appUtils/playerManager/player.ts +4 -0
  36. package/appUtils/playerManager/playerNative.ts +31 -17
  37. package/appUtils/playerManager/usePlayerState.tsx +14 -2
  38. package/arrayUtils/__tests__/allTruthy.test.ts +24 -0
  39. package/arrayUtils/__tests__/anyThruthy.test.ts +24 -0
  40. package/arrayUtils/index.ts +5 -0
  41. package/cellUtils/index.ts +32 -0
  42. package/cloudEventsUtils/__tests__/index.test.ts +529 -0
  43. package/cloudEventsUtils/index.ts +65 -1
  44. package/configurationUtils/__tests__/imageSrcFromMediaItem.test.ts +38 -0
  45. package/configurationUtils/__tests__/manifestKeyParser.test.ts +26 -26
  46. package/configurationUtils/index.ts +17 -11
  47. package/dateUtils/__tests__/dayjs.test.ts +330 -0
  48. package/enumUtils/__tests__/getEnumKeyByEnumValue.test.ts +207 -0
  49. package/errorUtils/__tests__/GeneralError.test.ts +97 -0
  50. package/errorUtils/__tests__/HttpStatusCode.test.ts +344 -0
  51. package/errorUtils/__tests__/MissingPluginError.test.ts +113 -0
  52. package/errorUtils/__tests__/NetworkError.test.ts +202 -0
  53. package/errorUtils/__tests__/getParsedResponse.test.ts +188 -0
  54. package/errorUtils/__tests__/invariant.test.ts +112 -0
  55. package/focusManager/aux/index.ts +1 -1
  56. package/headersUtils/__tests__/headersUtils.test.js +11 -1
  57. package/headersUtils/index.ts +2 -1
  58. package/manifestUtils/defaultManifestConfigurations/player.js +115 -11
  59. package/manifestUtils/keys.js +21 -0
  60. package/manifestUtils/platformIsTV.js +13 -0
  61. package/manifestUtils/sharedConfiguration/screenPicker/utils.js +1 -0
  62. package/manifestUtils/tvAction/container/index.js +1 -1
  63. package/navigationUtils/index.ts +15 -5
  64. package/numberUtils/__tests__/toNumber.test.ts +27 -0
  65. package/numberUtils/__tests__/toPositiveNumber.test.ts +193 -0
  66. package/numberUtils/index.ts +23 -1
  67. package/package.json +4 -4
  68. package/playerUtils/usePlayerTTS.ts +8 -3
  69. package/pluginUtils/index.ts +4 -0
  70. package/reactHooks/advertising/index.ts +2 -2
  71. package/reactHooks/analytics/__tests__/useSendAnalyticsOnPress.test.ts +537 -0
  72. package/reactHooks/app/__tests__/useAppState.test.ts +1 -1
  73. package/reactHooks/autoscrolling/__tests__/useTrackCurrentAutoScrollingElement.test.ts +1 -1
  74. package/reactHooks/autoscrolling/__tests__/useTrackedView.test.tsx +1 -2
  75. package/reactHooks/cell-click/__tests__/index.test.js +1 -3
  76. package/reactHooks/configuration/__tests__/index.test.tsx +1 -1
  77. package/reactHooks/connection/__tests__/index.test.js +1 -1
  78. package/reactHooks/debugging/__tests__/index.test.js +4 -4
  79. package/reactHooks/dev/__tests__/useReRenderLog.test.ts +188 -0
  80. package/reactHooks/device/useIsTablet.tsx +14 -19
  81. package/reactHooks/device/useMemoizedIsTablet.ts +3 -3
  82. package/reactHooks/events/index.ts +20 -0
  83. package/reactHooks/feed/__tests__/useBatchLoading.test.tsx +32 -23
  84. package/reactHooks/feed/__tests__/useBuildPipesUrl.test.tsx +19 -19
  85. package/reactHooks/feed/__tests__/useEntryScreenId.test.tsx +4 -1
  86. package/reactHooks/feed/__tests__/useFeedLoader.test.tsx +42 -30
  87. package/reactHooks/feed/__tests__/{useInflatedUrl.test.ts → useInflatedUrl.test.tsx} +62 -7
  88. package/reactHooks/feed/index.ts +0 -2
  89. package/reactHooks/feed/useBatchLoading.ts +7 -1
  90. package/reactHooks/feed/useEntryScreenId.ts +2 -2
  91. package/reactHooks/feed/useInflatedUrl.ts +44 -18
  92. package/reactHooks/feed/usePipesCacheReset.ts +3 -1
  93. package/reactHooks/flatList/useLoadNextPageIfNeeded.ts +13 -16
  94. package/reactHooks/hookModal/hooks/useHookModalScreenData.ts +12 -8
  95. package/reactHooks/index.ts +2 -0
  96. package/reactHooks/layout/__tests__/index.test.tsx +1 -1
  97. package/reactHooks/layout/__tests__/useLayoutVersion.test.tsx +1 -1
  98. package/reactHooks/layout/index.ts +1 -1
  99. package/reactHooks/layout/useDimensions/__tests__/{useDimensions.test.ts → useDimensions.test.tsx} +105 -25
  100. package/reactHooks/layout/useDimensions/useDimensions.ts +2 -2
  101. package/reactHooks/navigation/__tests__/index.test.tsx +40 -9
  102. package/reactHooks/navigation/index.ts +27 -11
  103. package/reactHooks/navigation/useRoute.ts +11 -7
  104. package/reactHooks/player/TVSeekControlller/TVSeekController.ts +27 -10
  105. package/reactHooks/player/__tests__/useAutoSeek._test.tsx +1 -1
  106. package/reactHooks/player/__tests__/useTapSeek._test.ts +1 -1
  107. package/reactHooks/resolvers/__tests__/useCellResolver.test.tsx +1 -1
  108. package/reactHooks/resolvers/__tests__/useComponentResolver.test.tsx +1 -1
  109. package/reactHooks/resolvers/useCellResolver.ts +6 -2
  110. package/reactHooks/resolvers/useComponentResolver.ts +19 -3
  111. package/reactHooks/screen/__tests__/useCurrentScreenData.test.tsx +2 -2
  112. package/reactHooks/screen/__tests__/useScreenBackgroundColor.test.tsx +1 -1
  113. package/reactHooks/screen/__tests__/useScreenData.test.tsx +1 -1
  114. package/reactHooks/screen/__tests__/useTargetScreenData.test.tsx +12 -4
  115. package/reactHooks/screen/useTargetScreenData.ts +4 -2
  116. package/reactHooks/state/__tests__/useComponentScreenState.test.ts +246 -0
  117. package/reactHooks/state/index.ts +2 -0
  118. package/reactHooks/state/useComponentScreenState.ts +45 -0
  119. package/reactHooks/state/useRefWithInitialValue.ts +10 -0
  120. package/reactHooks/state/useRivers.ts +1 -1
  121. package/reactHooks/ui/__tests__/useFadeOutWhenBlurred.test.ts +580 -0
  122. package/reactHooks/usePluginConfiguration.ts +2 -2
  123. package/reactHooks/utils/__tests__/index.test.js +1 -1
  124. package/rectUtils/__tests__/index.test.ts +549 -0
  125. package/rectUtils/index.ts +2 -2
  126. package/refreshUtils/RefreshCoordinator/__tests__/refreshCoordinator.test.ts +161 -0
  127. package/refreshUtils/RefreshCoordinator/index.ts +216 -0
  128. package/refreshUtils/RefreshCoordinator/utils/__tests__/getDataRefreshConfig.test.ts +104 -0
  129. package/refreshUtils/RefreshCoordinator/utils/index.ts +29 -0
  130. package/screenPickerUtils/__tests__/index.test.ts +333 -0
  131. package/screenPickerUtils/index.ts +5 -0
  132. package/screenState/__tests__/index.test.ts +1 -1
  133. package/screenUtils/index.ts +3 -0
  134. package/searchUtils/const.ts +7 -0
  135. package/searchUtils/index.ts +3 -0
  136. package/services/storageServiceSync.web.ts +1 -1
  137. package/stringUtils/index.ts +1 -1
  138. package/testUtils/index.tsx +30 -21
  139. package/time/__tests__/BackgroundTimer.test.ts +156 -0
  140. package/time/__tests__/Timer.test.ts +236 -0
  141. package/typeGuards/__tests__/isString.test.ts +21 -0
  142. package/typeGuards/index.ts +4 -0
  143. package/utils/__tests__/clone.test.ts +158 -0
  144. package/utils/__tests__/mapAccum.test.ts +73 -0
  145. package/utils/__tests__/mergeRight.test.ts +48 -0
  146. package/utils/__tests__/path.test.ts +7 -0
  147. package/utils/__tests__/selectors.test.ts +124 -0
  148. package/utils/clone.ts +7 -0
  149. package/utils/index.ts +22 -1
  150. package/utils/mapAccum.ts +23 -0
  151. package/utils/mergeRight.ts +5 -0
  152. package/utils/path.ts +6 -3
  153. package/utils/pathOr.ts +5 -1
  154. package/utils/selectors.ts +46 -0
  155. package/zappFrameworkUtils/HookCallback/callbackNavigationAction.ts +49 -12
  156. package/zappFrameworkUtils/HookCallback/hookCallbackManifestExtensions.config.js +1 -1
  157. package/reactHooks/componentsMap/index.ts +0 -55
  158. package/reactHooks/feed/__tests__/useFeedRefresh.test.tsx +0 -75
  159. package/reactHooks/feed/useFeedRefresh.tsx +0 -65
@@ -123,6 +123,12 @@ function getPlayerConfiguration({ platform, version }) {
123
123
  key: "skip_button_localization_text_skip_intro",
124
124
  initial_value: "Skip Intro",
125
125
  },
126
+ {
127
+ type: "text_input",
128
+ label: "Stream error message",
129
+ key: "stream_error_message",
130
+ initial_value: "Cannot play stream",
131
+ },
126
132
  {
127
133
  type: "text_input",
128
134
  label: "Locked message",
@@ -331,10 +337,53 @@ function getPlayerConfiguration({ platform, version }) {
331
337
  label_tooltip: "Hint for skip intro button accessibility",
332
338
  type: "text_input",
333
339
  },
340
+ {
341
+ type: "text_input",
342
+ label: "Text Tracks Label",
343
+ key: "text_tracks_label",
344
+ initial_value: "Subtitles",
345
+ label_tooltip: "Label for the text tracks list",
346
+ },
347
+ {
348
+ type: "text_input",
349
+ label: "Audio Tracks Label",
350
+ key: "audio_tracks_label",
351
+ initial_value: "Audio",
352
+ label_tooltip: "Label for the audio tracks list",
353
+ },
354
+ {
355
+ type: "text_input",
356
+ label: "Off Track Label",
357
+ key: "off_track_label",
358
+ initial_value: "Off",
359
+ label_tooltip: "Label for the 'Off' option in text tracks list",
360
+ },
361
+ {
362
+ type: "text_input",
363
+ label: "Default Track Label",
364
+ key: "default_track_label",
365
+ initial_value: "Default",
366
+ label_tooltip:
367
+ "Label for the 'Default' audio track in audio tracks list",
368
+ },
334
369
  ],
335
370
  };
336
371
 
337
372
  if (isTV(platform)) {
373
+ localizations.fields.push({
374
+ key: "back_to_live_label",
375
+ label: "Back to live label",
376
+ initial_value: "Back To Live",
377
+ type: "text_input",
378
+ });
379
+
380
+ localizations.fields.push({
381
+ key: "start_over_label",
382
+ label: "Start over label",
383
+ initial_value: "Start Over",
384
+ type: "text_input",
385
+ });
386
+
338
387
  styles.fields.push(
339
388
  fieldsGroup("Always Show Scrub Bar & Timestamp", "", [
340
389
  {
@@ -447,7 +496,7 @@ function getPlayerConfiguration({ platform, version }) {
447
496
  ),
448
497
  fieldsGroup(
449
498
  "Skip Button",
450
- "This section allows you to configure the skip button styles for tv",
499
+ "This section allows you to configure the skip button behaviour",
451
500
  [
452
501
  {
453
502
  type: "switch",
@@ -464,6 +513,12 @@ function getPlayerConfiguration({ platform, version }) {
464
513
  label: "Persistent Button Toggle",
465
514
  initial_value: true,
466
515
  },
516
+ ]
517
+ ),
518
+ fieldsGroup(
519
+ "Labeled Button Style",
520
+ "This section allows you to configure the labeled button styles",
521
+ [
467
522
  {
468
523
  type: "color_picker_rgba",
469
524
  label_tooltip: "",
@@ -619,6 +674,44 @@ function getPlayerConfiguration({ platform, version }) {
619
674
  );
620
675
  }
621
676
 
677
+ if (isTV(platform)) {
678
+ general.fields.push(
679
+ {
680
+ key: "liveSeekingEnabled",
681
+ label: "Live Seeking Enabled",
682
+ initial_value: false,
683
+ type: "switch",
684
+ label_tooltip: "Enable Live Seek",
685
+ },
686
+ {
687
+ key: "minimumAllowedSeekableDurationInSeconds",
688
+ label: "Minimum allowed seekable duration in seconds",
689
+ initial_value: 300,
690
+ type: "number_input",
691
+ label_tooltip:
692
+ "If duration less than this value, player will disable 'liveSeekingEnabled' value",
693
+ },
694
+ {
695
+ key: "live_image",
696
+ label: "Live badge",
697
+ type: "uploader",
698
+ label_tooltip: "Override default live badge / icon",
699
+ },
700
+ {
701
+ key: "live_width",
702
+ label: "Live badge width",
703
+ type: "number_input",
704
+ initial_value: 85,
705
+ },
706
+ {
707
+ key: "live_height",
708
+ label: "Live badge height",
709
+ type: "number_input",
710
+ initial_value: 50,
711
+ }
712
+ );
713
+ }
714
+
622
715
  if (isMobile(platform)) {
623
716
  general.fields.push(
624
717
  {
@@ -1142,40 +1235,35 @@ function getPlayerConfiguration({ platform, version }) {
1142
1235
  label: "Playback Speed 0.8x",
1143
1236
  type: "uploader",
1144
1237
  label_tooltip: "Playback Speed 0.8x",
1145
- initial_value:
1146
- "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAYAAAA5ZDbSAAAACXBIWXMAACE4AAAhOAFFljFgAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAeMSURBVHgB7Z3/Vds6FMcvnPc/yQRVJyhM8MIEhQkaJihM8MIEwAQNE0AnwJ2g6QR1J4Au0D5dfHNqUuvqShbUcb+fc3R8Elm2oq9+3msrRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMjx0qyP39/cQfZj44H175wJ8ffPjuw4rDdDqtaSAE8st8oya/tc/viraYIgL7gpr5w3/UFFaMyodrX3BL+gOIqHMf3pItvzU1eT4fUuW00ktgX1jOHz6QraA2qX04fMlCk4rI+XWUx8Ln95y2iGyBpbBu6Fe3lgN33ye+0G7pmfH55R5mQf3hLvt4W1pzlsC+sPb94TOVg1tyRc9EQXHX1D4c+Dw/0MDZpUSkW76hstzIdYvjrzunuLgsVOXDUo515HxHzZxj8CQL7LkgfQyrfDj2wVfwKfcQUx9OSC807uY/0POgCfE4RPjw2ueVe5ETOb723x2SnudTGaYGTVIXLa1BE4JnmgslPcdpBV60q/b3O6Jwb1OTYZLnr3FHgUnk7u7ucm9v74QGTGoLfh+8kP+xmriMxF8pp5Tu9mZKnHXZw71R51j748ePIxo4ZoFlYrUfiK79j7UuHxYUKDDPrHC39ybw/YN1HS4TqY+B6ImsqwdLSgueK3HX1mWDFJjWil+iVdSURq3EjUbgf5W4JaVxqcS9pXKEeopiogx9PWwSWLqhUPdcpf5IacVVINoV7Pa+BL5P7VpDXf3g7dTWFryvxH2hPLR0MypDFfiexTUNBbI+D537iQZOCYErykOr/Y4KIEuuKhB9YTSuXAS+515IG2oGgVVgp8TlmuueXWCB16ldeeRWfCdr+9/g2bysgUOtN8m7xENCX2tdzjX+MZ73SomrKY9gxfBr6j0qBIvgC4WtUizW5rjrfPggtupVK0/akpBhcc2t11//HTWtnQWqKcOL5tOxDWKReg1rC9YmJFktWMucX1M7Kog47Q8oXBkdNS11LiEkLv/Ws5hBp41M5vj8SetedyktUSrg5cY1Ti1pc2zRT9gGjwrDFaplY64ojbbNOnXcZVHcxnf82SSy4gl7QwZ6C7wtyPjFhcW26RmlsXaGXIhFz4z0VHVHlKOIyBE3p2n18lcILGPgV3raVeYw9+Gzv95FYrqQZ8pRQOSIuGw5fJkueuhIQS1JF7aSc9iefiWftaGHXYXmBx6kFZtFNog7JyPWWfS3UARnLMdcFxl/vlMBYs7+nZ2d258/f5515V8mR9xKQh6ufW7JPu0ZGZDZPHumQrP5O5ntvwvlmfM7mUzmlECJFpzb5TklrqaeSAXS3I/nvrCOQ5WTJ48yW+bZd6g1Jzn9ZTZ/GLieo+YxqEUg+cpXxmTfs1VgzSiRNOlooVWMmvozo0Alsviu14goWsEm+bAjIofK5DFNzorFKnCtxOUKrKUrYcQPPpyQ4Lt+RJ76rALRs1TnSETkTbLFZawCV0qcaT3WgeZ+LCFw0FiR6eLTliVHlIhR5F7iMiaB5QZ1IDq5Bsv4OAtEr/oaTyITuNzKo+Updx7yJpJ2Qj191ymTrI9KnGlN1mIWivDjY4nWq+GoPMkiyNp8GTnNUaJZc5MUgW+VuPfWViznBScmfny8pv5orS33gYJiQ4pR3DWOeohsFjjiW1VF24DPc4G4WntsVsyNvDRZhNx8TOSJkXUezMjjtzPlFLPAEXHbHq02jjJFTl0Haw/LnYoFJojEa935uZJ2bW5kMyFfh918X5Uf/alPXlv3dRR2+jPmV2IN4h6Svk5OFjn53STtQXCBM8rWncfJUut5rtjrpWtvT9c9HTXidt7PpzvoSDORNFp3vPThatrxDrCk56XWaeQaJ5ZHcC3irieX4tDosngxNSX4k3MEdtRYXHrN7jbgH3YQynTuGxGRNxva1BLaDn9nSHdlMfqniNtKU0TkZFOlXNRkf03gJJJZRzqd8WKgsBg1HDW9y5EEZ0hTGcVlgZaB6E5xmZhZ0682TENMli1auqRS7+RY3g9e5caLSZIrpDazToVb7qHx3Gzzoyay9amXbGeDiKw9BhOjpqZbXhrO5XNCBXE7jeyjIU9hcF77LsEqakSJttzWvWv6vYyi4rbSh0T+RAaSx+AuZMmiLX/acIbZaHKZYrGSMelm4x4Vxbv3zes4aiZOvK7dNyThPHIPcz3NfPOxtdUFH7mSJf32rmtYnSVFBG5lggtsRk93ramp8e/ysZr23LVGJk6P1532fNW0NcN39LTiPEhIfmsDAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAArCn66soQkXd6+EXu9muhKwlb+Z/AKYxaYNkl/TJy2mLb/hM4hdHuNtvaJT3GwrpfxzYyyhZs+BPNLo6nL/BH1S/NWAXmzVccpRHcBGabGV0XLdv7OkrH3W/B/wGnMsYx2PLW/nOkHSRjFLjP9k590g6SMQrcZzedkjvxDIIxCtxnD5Be+4cMEcyif4FZ9BaRsxPfKK1ZoxQ4YQvDNefGDdm2jrHbohcU3xv6bJr+f4Rbw9/iTVpQ8/8I63VuTb9226tpxPwPlwURv/dAZk0AAAAASUVORK5CYII=",
1238
+ initial_value: null,
1147
1239
  },
1148
1240
  {
1149
1241
  key: "speed_1",
1150
1242
  label: "Playback Speed 1x",
1151
1243
  type: "uploader",
1152
1244
  label_tooltip: "Playback Speed 1x",
1153
- initial_value:
1154
- "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAYAAAA5ZDbSAAAACXBIWXMAACE4AAAhOAFFljFgAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAI4SURBVHgB7dzhcRJBGIDhT8cCkg6SDmIHsQNLiBUYKwAqUCtIC5ZACVqBdIAdxN3JMSLecXcE8Tt5npkdJlxyf97ZcLcLRAAAAAAAAAAAAAAAAAAAAAAAAADAMb2IiViv17fl4aGMq45fub68vFwFv3kVyZWwF+VhVsZ9MFrqwANmLT1SBm5mbQ37NniWl5FMifu+PHwPcY8izQwuYa/iadbeBkeTaQbfxf64P8r4GoyS7l90h89lXJfxLRgl+23Sqox35f52WX8o/8aDcTLP4EUZrzdxOUzGGbws40MJ6/X2CDIFrhdRNeyn4GjSBBb275jKVTQHEvg/d/aB69Lo+sljGR/jADvnmEUiZx242a2qr/0XzVP35bmHkeeY7Zxj3pw3hXOfwTctz90NjdzEnbccuo0kzj1w1712b+Q9cfed9+TOOnCzSrboONwZuSfuopz3SyRx9hdZJcY8RkQeELfr2D/hNimGR55a3Cr9m+5OpcZpdqvabnNq5HpBdtPx5ynjVmbwlp6ZPLm4lcA7eiLvSh23ErjFwMjp41YCd3t85vEUBG7Rc7W8Mc+27txG4B0D426kjyzwlp64y47nU0cWuDFgEeNNdF94pY0scAxfoeq5uk4Z2Yb/yOXHqUW24X/A2vKAyGk+OGfDv13vIsaBy5onZ8P/T4NXqPZEtuGfwdaG/yp+vfF+HiNsRV5tnSPNhv9kvoSlaj75f9F2zBewAAAAAAAAAAAAAAAAAAAAAAAAwHT8BNhH51wNSx95AAAAAElFTkSuQmCC",
1245
+ initial_value: null,
1155
1246
  },
1156
1247
  {
1157
1248
  key: "speed_1_2",
1158
1249
  label: "Playback Speed 1.2x",
1159
1250
  type: "uploader",
1160
1251
  label_tooltip: "Playback Speed 1.2x",
1161
- initial_value:
1162
- "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAYAAAA5ZDbSAAAACXBIWXMAACE4AAAhOAFFljFgAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAUjSURBVHgB7d3bUeNIFAbgA7Xv2EUCmgiWjWBNBAwRYCKYdQQrIliIYEUEw0awymDIYDQBUFC8g+eccWsulPomteTu1v9VdZlSGyP0W1KrWxciAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgPgc0Mw8Pj4u+KUt4mm5XDaUqVED5oX5gV/ea6o3vGDvaQI8Hyt+ueAir4XmbTIvNZebnAIfJWBeoCf88g/tFqjOKS/ImkbE8/FezUdBfu5o9wVsKHGHFJBs/rjIAv1E5nBHpebjX/7xI/mHK+SL8Zk/429K3G8UiNoMykItaI/UPvZ/Lic0XMmfR7wmX1GiBq/BP621slAL2j9Z60KE25KQ/6JEDdoHD9jHieD7YJ6fNe22IjpPXG5p16Bq1DT5MpyReZciv/eO5/eJEtN7E63C/Wh5myyQBU1Hu888ODi42263lx0h1Vyu1ZdDvqxd8yvTZC0uKTFDNtGm4GQhbrjc0ERUy73QVNeLxeLctAZyXcUv56R3QQkK2or+9oGHhxXtNmfXNK2Voe6SHKhdxq2muuAvUUGJCRlww+X06Ojock/7qj810+89j2fvDHUFJSZUwLIp/mPsjgsL3S7jC/mZpHdtKkOPg2VhbPYcbEuOVbs2rw35mbJROLohAdeqYRKFgF+ywlCX3GFS7010xiMwZ5rpzVSDIyEFb0WnTLWS1111fHRQU4IQ8K+0vWCvr69J9kcjYEWNHK001c5jxNIvz2XLpfdolIyEtZ/x/Pw8qIMFAdP3ExNKTXVDjl2UqruzHZgoaDdQ4RWyGuZct5/x8vJSqRGyXmYfMC88WUNMvW6nHh03q45pziG/Cdf2uU5mHbAKtzK8xfesjloz3RqyIVzRu/U+24Adwr3y7U+XfgFujOn6srUhW8K9GnJIOsuAHcMtqYfj4+O1T8gO4ZY0wOwCdgj3duhCdQ157HDFrAJ2DHdNATiELCcmrjX1QcIVswl4ynBblpB1540FC1fMImB1nFsZ3hI83JYl5LeChiuyD1jt70yt4dHCbTmGHDxckXXAKtzS8JbRw23xYMXW8hZbfb+/S5mKKVxLa7nl3a3pItiVDaGpoTs5NVf6YeW8qjuP300t3FbwKymiDLgrIJ4m3XXWfuGEwpX/p6slHTTk6AJWIzJlR5UsDDnR/tTwu7ZwGy6Vuo6qF9dTg1w6MR4eHireN3cNBwYLOcY1+MxQt5Khs661WF0/VJJZQbtrqPpquLyzvcm1h0pa1xwyjRlyjI0s29jnief0Sfl2P/r2XfuKMWDbeczRnvimdi9rTbX2ONch5N5f3hgDrgx1N8u4r/BbaaZbOzEsIRfUU3QBq0aMXEvUvKmS1m/s1+nWHdOce6gMIffeao3dyJJj10ZTp5v+beCcN0s17farsk9uHFqvFenPqAjFuPVQ813wjx/UJO+TBiRk/gz5Oxfq7w0a8AcAAAAAAAAAAAAAAAAAAAAAAAAAAAAAANif7B8Q/dOlJHI7iEJNvlcl+8tCsg5Y3R/Ldm1QuUz46aI2ud9lx+XCr1HubhOLLNdgh6eQdjn3uZNPKnIN+DP5XzQtl6ha77+Rmuw20eoOOgX5K4bcfSdWOe6Dh9yMJYobuYSUY8BDnj2Y1XMLRY4BD7lJS3LPJrTJMeAht1lK7tmENmhF/4BWdEI25C/L3qwsA1YdFj6BXcX0LOSQcu+LLvnF1g258b2XVUrmMppUcvmdfhznNlz+43Kd+2jSV0z9PFgMpokeAAAAAElFTkSuQmCC",
1252
+ initial_value: null,
1163
1253
  },
1164
1254
  {
1165
1255
  key: "speed_1_5",
1166
1256
  label: "Playback Speed 1.5x",
1167
1257
  type: "uploader",
1168
1258
  label_tooltip: "Playback Speed 1.5x",
1169
- initial_value:
1170
- "data:image/png;base64,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",
1259
+ initial_value: null,
1171
1260
  },
1172
1261
  {
1173
1262
  key: "speed_2",
1174
1263
  label: "Playback Speed 2x",
1175
1264
  type: "uploader",
1176
1265
  label_tooltip: "Playback Speed 2x",
1177
- initial_value:
1178
- "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAHgAAAB4CAYAAAA5ZDbSAAAACXBIWXMAACE4AAAhOAFFljFgAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAQnSURBVHgB7d2PUdRAFMfxh2MBUIGxArECjwqECjwqUCowV4FYgdABVCAdSAekg7ME35pFgnOb3ZDAvmy+n5lMGJLL3dzvkuyfZCMCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA2LMnM7Hdbvd11p2ag4ODRtDLdMAa6kpnH3U61qkKrHbrp0sN/EbwiMmAfbBfdVrJMI1OZxr0leAvcwFruC7YWsY515DPBLYC1nC/6eyLTONCQz6VhXslRvg9d6pwnbX/wSyaiT1Yg6h0dhdZzZ1Xr6U9zzqHOn2QtgDW52jJhS8rAf/Q2Tqw2JWQT0JVIv/j+CnhUvaNvvZIFip7wL5+uw0sbqTdA5vINiqd/ZK2fryLbuLgtyyQhXPwYc+yTUpjhl/ne88qK1koCwGvQgs0uAtJ17duJQtlIeDQYfVWBojs6fuyUK8lP1c63hXmlOfMRZ5/newBT1WF0YJW37m8kYUy09Axgb6ABx3uSzKb7sI+vqrlqknVjsXJ9WC/HRlTpZpiG1MqZQ92zZxVYNmlJPBNpdv2z6c1cfrXjdrG1Ga/B+sX+Vln54HFV7onnUh8GytpW8O6BnVWBFrjTnJ3Xc56D/YFq1C47hCZ2mW46/y99qGlfI5QU+uhZDbbgDtt0CFJrWBeqBAWDTnSjn4jmc0y4E64oQYMF+65JPJVtU1gcTDkSLgbC71YszsHJ/QeuWuz1vK0bdfSFth2eXROTgi3FgNmFXBCuLf6xb6Xce9RSyTkuYTrzOmyWVdg6Tssu/Po0RT1z0jIjYR/YKbCdWYR8EuG23nPWsIh72IuXMd8wDnC7bx3LWkhmwzXsX7he7ZwO5+hlv6QzYbrmK0mWQjXezNyeVZW72wwEW6ktNxl9hpsc3uwfqmfZF7hOsnNmi/NVMA+3AsJh9tI24CfM9ybwP9Nhmzpzob7cEMaSbiEdoLPEWvEcH3Lg5s1c7Fy4Xss3PueoUaeKKVdeEgL1ZBmzZwsXPi+kv5eoUnoF74X+Rx9N77trArNIWQLh+hKMtOgjmVguI7/f9/h+lgyK+miuzGqwP+jjRiRkOnwN2JXh39yC1VPyFeSGQHLvwKYu3bLBd1IOwxELQP49U//28atZGahkFXJC9wcNvA+JwAAAAAAAAAAAAAAAAAAAAAAAIxWxIjvffytMW5M6e4ziO+fOTxkRNpZKjrgyGDh92oNeSOFKvbuQj9Ef8qQwrVft0hF7sEa2FpnQwdDyT78/nMoNeA7GT40RKMBv5XCFHeI9oO6VDJc5V9blBLPwWPGxcg+psbUSgx4X55uzGtNKjHgMcMcPvfItS+uxIDHDHySfdCUqVGKfkApekZSn3jWVWRrVpEB+waLIYFtSh1mqfS26FriD9U4G/KUtLlZSm9SrdM7eajnNjpd63Reem/SH2FDq35f8ateAAAAAElFTkSuQmCC",
1266
+ initial_value: null,
1179
1267
  },
1180
1268
  {
1181
1269
  key: "sleep_timer",
@@ -3429,6 +3517,22 @@ function getPlayerConfiguration({ platform, version }) {
3429
3517
  label_tooltip:
3430
3518
  "This field allows you to override the player configuration / initialization options. i.e. html5: { vhs: { limitRenditionByPlayerDimensions: false } } Please ensure your configuration matches the player you are targeting, and that it is a valid json. See config options here: https://videojs.com/guides/options/",
3431
3519
  },
3520
+ {
3521
+ key: "advanced_player_styles",
3522
+ label: "Advanced Player Styles",
3523
+ type: "text_input",
3524
+ multiline: true,
3525
+ initial_value: `.vjs-text-track-cue {
3526
+ inset: unset !important;
3527
+ top: 94% !important;
3528
+ bottom: 0 !important;
3529
+ left: 0 !important;
3530
+ right: 0 !important;
3531
+ width: 100% !important;
3532
+ }`,
3533
+ label_tooltip:
3534
+ "This field allows you to inject custom CSS styles to override default player styles. The styles will be injected into the document head and can be used to customize the appearance of the player. Leave empty to use only default styles.",
3535
+ },
3432
3536
  {
3433
3537
  key: "use_dashjs_player",
3434
3538
  label: "Use Enhanced Player for DASH streams",
@@ -959,6 +959,27 @@ const TV_CELL_LABEL_FIELDS = [
959
959
  rules: "conditional",
960
960
  conditions: [{ key: "switch", section: "styles", value: true }],
961
961
  },
962
+ {
963
+ type: ZAPPIFEST_FIELDS.font_selector.roku,
964
+ suffix: "roku font family",
965
+ tooltip: "",
966
+ rules: "conditional",
967
+ conditions: [{ key: "switch", section: "styles", value: true }],
968
+ },
969
+ {
970
+ type: ZAPPIFEST_FIELDS.number_input,
971
+ suffix: "roku font size",
972
+ tooltip: "",
973
+ rules: "conditional",
974
+ conditions: [{ key: "switch", section: "styles", value: true }],
975
+ },
976
+ {
977
+ type: ZAPPIFEST_FIELDS.number_input,
978
+ suffix: "roku line height",
979
+ tooltip: "",
980
+ rules: "conditional",
981
+ conditions: [{ key: "switch", section: "styles", value: true }],
982
+ },
962
983
  {
963
984
  type: ZAPPIFEST_FIELDS.select,
964
985
  suffix: "text alignment",
@@ -0,0 +1,13 @@
1
+ function platformIsTV(platform) {
2
+ return [
3
+ "tvos_for_quickbrick",
4
+ "android_tv_for_quickbrick",
5
+ "amazon_fire_tv_for_quickbrick",
6
+ "lg_tv",
7
+ "samsung_tv",
8
+ "web",
9
+ "vizio",
10
+ ].includes(platform);
11
+ }
12
+
13
+ module.exports = { platformIsTV };
@@ -3,6 +3,7 @@ const defaultPlatforms = {
3
3
  android_tv: "Android TV",
4
4
  lg_tv: "LG TV",
5
5
  samsung_tv: "Samsung TV",
6
+ roku: "Roku TV",
6
7
  };
7
8
 
8
9
  const global_defaults = {
@@ -38,7 +38,7 @@ function tvActionButtonsContainer({ label, description, defaults }) {
38
38
  generateFieldsFromDefaultsWithoutPrefixedLabel(
39
39
  label,
40
40
  defaults,
41
- tvActionButtonContainerFields(defaults["position"])
41
+ tvActionButtonContainerFields(defaults.position)
42
42
  )
43
43
  );
44
44
 
@@ -5,7 +5,8 @@ import { layoutV2TypeMatcher } from "./layoutV2TypeMatcher";
5
5
  import { HOOKS_EVENTS } from "../appUtils/HooksManager/constants";
6
6
  import { HooksManager } from "../appUtils/HooksManager";
7
7
  import { appStore } from "@applicaster/zapp-react-native-redux/AppStore";
8
- import { HookModalContextT } from "@applicaster/zapp-react-native-ui-components/Contexts/ZappHookModalContext";
8
+
9
+ import { zappHookModalStore } from "@applicaster/zapp-react-native-ui-components/Contexts/ZappHookModalContext";
9
10
  import { logger } from "@applicaster/zapp-react-native-utils/logger";
10
11
  import {
11
12
  isGeneralPlugin,
@@ -15,6 +16,8 @@ import {
15
16
  } from "./itemTypeMatchers";
16
17
  import { RootState } from "@applicaster/zapp-react-native-redux/store";
17
18
 
19
+ import { pick } from "@applicaster/zapp-react-native-utils/utils";
20
+
18
21
  type PathAttribute = {
19
22
  screenType: string;
20
23
  screenId: string;
@@ -403,15 +406,22 @@ export const mapContentTypesToRivers = (
403
406
  };
404
407
 
405
408
  export const runZappHooksForEntry = async (
406
- entry: HookPluginProps["payload"],
407
- {
409
+ entry: HookPluginProps["payload"]
410
+ ): Promise<{ success: boolean; payload: ZappEntry }> => {
411
+ const {
408
412
  setState,
409
413
  resetState,
410
414
  setIsHooksExecutionInProgress,
411
415
  setIsPresentingFullScreen,
412
416
  setIsRunningInBackground,
413
- }: Partial<HookModalContextT>
414
- ): Promise<{ success: boolean; payload: ZappEntry }> => {
417
+ } = pick(zappHookModalStore.getState(), [
418
+ "setState",
419
+ "resetState",
420
+ "setIsHooksExecutionInProgress",
421
+ "setIsPresentingFullScreen",
422
+ "setIsRunningInBackground",
423
+ ]);
424
+
415
425
  resetState?.();
416
426
 
417
427
  let success;
@@ -24,6 +24,8 @@ describe("toNumber", () => {
24
24
  it("return undefined if input is not a number", () => {
25
25
  const inputs = [
26
26
  "vfdvf",
27
+ "5n",
28
+ "-5n",
27
29
  null,
28
30
  undefined,
29
31
  NaN,
@@ -41,4 +43,29 @@ describe("toNumber", () => {
41
43
  expect(output).toBeUndefined();
42
44
  });
43
45
  });
46
+
47
+ describe("BigInt support", () => {
48
+ // Conditional test based on BigInt availability
49
+ const isBigIntSupported = typeof BigInt !== "undefined";
50
+
51
+ if (isBigIntSupported) {
52
+ it("converts BigInt to number when BigInt is supported", () => {
53
+ expect(toNumber(BigInt(5))).toBe(5);
54
+ expect(toNumber(BigInt(0))).toBe(0);
55
+ expect(toNumber(BigInt(-10))).toBe(-10);
56
+ expect(toNumber(BigInt(1000))).toBe(1000);
57
+ });
58
+
59
+ it("handles large BigInt values that may lose precision", () => {
60
+ const largeBigInt = BigInt(Number.MAX_SAFE_INTEGER) + BigInt(1);
61
+ const result = toNumber(largeBigInt);
62
+ expect(result).toBe(Number(largeBigInt));
63
+ });
64
+ } else {
65
+ it("skips BigInt tests when BigInt is not supported", () => {
66
+ // Placeholder test to indicate BigInt is not available
67
+ expect(typeof BigInt).toBe("undefined");
68
+ });
69
+ }
70
+ });
44
71
  });
@@ -0,0 +1,193 @@
1
+ import { toPositiveNumber } from "..";
2
+
3
+ describe("toPositiveNumber", () => {
4
+ describe("valid positive numbers", () => {
5
+ it("returns the number for positive integers", () => {
6
+ expect(toPositiveNumber(5)).toBe(5);
7
+ expect(toPositiveNumber(1000)).toBe(1000);
8
+ });
9
+
10
+ it("returns the number for positive floats", () => {
11
+ expect(toPositiveNumber(0.1)).toBe(0.1);
12
+ expect(toPositiveNumber(3.14159)).toBe(3.14159);
13
+ });
14
+
15
+ it("returns the number for very small positive numbers", () => {
16
+ expect(toPositiveNumber(1e-300)).toBe(1e-300);
17
+ });
18
+
19
+ it("returns the number for very large positive numbers", () => {
20
+ expect(toPositiveNumber(1e300)).toBe(1e300);
21
+ });
22
+
23
+ it("returns Infinity for positive infinity", () => {
24
+ expect(toPositiveNumber(Infinity)).toBe(Infinity);
25
+ });
26
+
27
+ it("converts valid positive strings to numbers", () => {
28
+ expect(toPositiveNumber("5")).toBe(5);
29
+ expect(toPositiveNumber("3.14")).toBe(3.14);
30
+ expect(toPositiveNumber(" 100 ")).toBe(100);
31
+ });
32
+
33
+ it("converts boolean true to undefined", () => {
34
+ expect(toPositiveNumber(true)).toBeUndefined();
35
+ });
36
+
37
+ it("converts single-element arrays to undefined", () => {
38
+ expect(toPositiveNumber([5])).toBeUndefined();
39
+ expect(toPositiveNumber(["10"])).toBeUndefined();
40
+ });
41
+ });
42
+
43
+ describe("invalid cases (return undefined)", () => {
44
+ describe("zero values", () => {
45
+ it("returns undefined for zero", () => {
46
+ expect(toPositiveNumber(0)).toBeUndefined();
47
+ expect(toPositiveNumber(-0)).toBeUndefined();
48
+ });
49
+
50
+ it("returns undefined for string zero", () => {
51
+ expect(toPositiveNumber("0")).toBeUndefined();
52
+ expect(toPositiveNumber(" 0 ")).toBeUndefined();
53
+ });
54
+
55
+ it("returns undefined for boolean false", () => {
56
+ expect(toPositiveNumber(false)).toBeUndefined();
57
+ });
58
+
59
+ it("returns undefined for empty arrays", () => {
60
+ expect(toPositiveNumber([])).toBeUndefined();
61
+ });
62
+
63
+ it("returns undefined for empty strings", () => {
64
+ expect(toPositiveNumber("")).toBeUndefined();
65
+ expect(toPositiveNumber(" ")).toBeUndefined();
66
+ });
67
+ });
68
+
69
+ describe("negative values", () => {
70
+ it("returns undefined for negative numbers", () => {
71
+ expect(toPositiveNumber(-5)).toBeUndefined();
72
+ expect(toPositiveNumber(-0.1)).toBeUndefined();
73
+ });
74
+
75
+ it("returns undefined for negative strings", () => {
76
+ expect(toPositiveNumber("-5")).toBeUndefined();
77
+ expect(toPositiveNumber(" -10 ")).toBeUndefined();
78
+ });
79
+
80
+ it("returns undefined for negative infinity", () => {
81
+ expect(toPositiveNumber(-Infinity)).toBeUndefined();
82
+ });
83
+ });
84
+
85
+ describe("non-convertible values", () => {
86
+ it("returns undefined for null", () => {
87
+ expect(toPositiveNumber(null)).toBeUndefined();
88
+ });
89
+
90
+ it("returns undefined for undefined", () => {
91
+ expect(toPositiveNumber(undefined)).toBeUndefined();
92
+ });
93
+
94
+ it("returns undefined for objects", () => {
95
+ expect(toPositiveNumber({})).toBeUndefined();
96
+ expect(toPositiveNumber({ a: 1 })).toBeUndefined();
97
+ });
98
+
99
+ it("returns undefined for multi-element arrays", () => {
100
+ expect(toPositiveNumber([1, 2])).toBeUndefined();
101
+ expect(toPositiveNumber(["a", "b"])).toBeUndefined();
102
+ });
103
+
104
+ it("returns undefined for non-numeric strings", () => {
105
+ expect(toPositiveNumber("abc")).toBeUndefined();
106
+ expect(toPositiveNumber("5px")).toBeUndefined();
107
+ expect(toPositiveNumber("123.45.67")).toBeUndefined();
108
+ });
109
+
110
+ it("returns undefined for NaN", () => {
111
+ expect(toPositiveNumber(NaN)).toBeUndefined();
112
+ expect(toPositiveNumber(Number("abc"))).toBeUndefined();
113
+ });
114
+ });
115
+ });
116
+
117
+ describe("special cases", () => {
118
+ it("handles exponential notation correctly", () => {
119
+ expect(toPositiveNumber("1e5")).toBe(100000);
120
+ expect(toPositiveNumber("1e-5")).toBe(0.00001);
121
+ expect(toPositiveNumber("-1e5")).toBeUndefined();
122
+ });
123
+
124
+ it("preserves precision for decimal numbers", () => {
125
+ expect(toPositiveNumber(0.1 + 0.2)).toBeCloseTo(0.3);
126
+ expect(toPositiveNumber("0.1")).toBe(0.1);
127
+ });
128
+
129
+ it("handles numeric strings with leading zeros", () => {
130
+ expect(toPositiveNumber("005")).toBe(5);
131
+ expect(toPositiveNumber("0.5")).toBe(0.5);
132
+ });
133
+
134
+ it("returns undefined for numeric strings with trailing non-numeric characters", () => {
135
+ expect(toPositiveNumber("5px")).toBeUndefined();
136
+ expect(toPositiveNumber("10%")).toBeUndefined();
137
+ });
138
+
139
+ it("handles scientific notation correctly", () => {
140
+ expect(toPositiveNumber("1.5e2")).toBe(150);
141
+ expect(toPositiveNumber("-2.5e3")).toBeUndefined();
142
+ });
143
+ });
144
+
145
+ describe("type conversion behavior", () => {
146
+ it("converts Date objects correctly", () => {
147
+ const date = new Date(2026, 1, 17);
148
+ expect(toPositiveNumber(date)).toBeUndefined();
149
+ });
150
+
151
+ it("converts functions to NaN (returns undefined)", () => {
152
+ expect(toPositiveNumber(() => {})).toBeUndefined();
153
+ expect(toPositiveNumber(Math.sqrt)).toBeUndefined();
154
+ });
155
+
156
+ it("handles Symbol values", () => {
157
+ expect(toPositiveNumber(Symbol("test"))).toBeUndefined();
158
+ });
159
+ });
160
+
161
+ describe("BigInt support", () => {
162
+ // Conditional test based on BigInt availability
163
+ const isBigIntSupported = typeof BigInt !== "undefined";
164
+
165
+ if (isBigIntSupported) {
166
+ it("converts positive BigInt values to numbers when BigInt is supported", () => {
167
+ expect(toPositiveNumber(BigInt(5))).toBe(5);
168
+ expect(toPositiveNumber(BigInt(100))).toBe(100);
169
+ expect(toPositiveNumber(BigInt(1000))).toBe(1000);
170
+ });
171
+
172
+ it("returns undefined for zero BigInt", () => {
173
+ expect(toPositiveNumber(BigInt(0))).toBeUndefined();
174
+ });
175
+
176
+ it("returns undefined for negative BigInt values", () => {
177
+ expect(toPositiveNumber(BigInt(-5))).toBeUndefined();
178
+ expect(toPositiveNumber(BigInt(-100))).toBeUndefined();
179
+ });
180
+
181
+ it("handles large positive BigInt values", () => {
182
+ const largeBigInt = BigInt(Number.MAX_SAFE_INTEGER);
183
+ const result = toPositiveNumber(largeBigInt);
184
+ expect(result).toBe(Number(largeBigInt));
185
+ });
186
+ } else {
187
+ it("skips BigInt tests when BigInt is not supported", () => {
188
+ // Placeholder test to indicate BigInt is not available
189
+ expect(typeof BigInt).toBe("undefined");
190
+ });
191
+ }
192
+ });
193
+ });
@@ -8,7 +8,11 @@ export const toNumber = (value: unknown): number | undefined => {
8
8
  return undefined;
9
9
  }
10
10
 
11
- if (R.is(Number, value) || R.is(String, value)) {
11
+ // Feature-detect BigInt support to avoid ReferenceError on older runtimes
12
+ const isBigIntSupported = typeof BigInt !== "undefined";
13
+ const isBigIntValue = isBigIntSupported && R.is(BigInt, value);
14
+
15
+ if (R.is(Number, value) || isBigIntValue || R.is(String, value)) {
12
16
  const numberOrNan = Number(value);
13
17
 
14
18
  return Number.isNaN(numberOrNan) ? undefined : numberOrNan;
@@ -69,6 +73,24 @@ export const isMinusZero = (value: number) => {
69
73
  return 1 / value === -Infinity;
70
74
  };
71
75
 
76
+ export const toPositiveNumber = (value: unknown): number | undefined => {
77
+ const possibleNumber = toNumber(value);
78
+
79
+ if (R.isNil(possibleNumber)) {
80
+ return undefined;
81
+ }
82
+
83
+ if (possibleNumber < 0) {
84
+ return undefined;
85
+ }
86
+
87
+ if (isZero(possibleNumber)) {
88
+ return undefined;
89
+ }
90
+
91
+ return possibleNumber;
92
+ };
93
+
72
94
  export const toPositiveNumberWithDefault = (
73
95
  defaultValue: number,
74
96
  value: unknown
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-utils",
3
- "version": "15.0.0-rc.12",
3
+ "version": "15.0.0-rc.121",
4
4
  "description": "Applicaster Zapp React Native utilities package",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
@@ -27,13 +27,13 @@
27
27
  },
28
28
  "homepage": "https://github.com/applicaster/quickbrick#readme",
29
29
  "dependencies": {
30
- "@applicaster/applicaster-types": "15.0.0-rc.12",
30
+ "@applicaster/applicaster-types": "15.0.0-rc.121",
31
31
  "buffer": "^5.2.1",
32
32
  "camelize": "^1.0.0",
33
33
  "dayjs": "^1.11.10",
34
+ "handlebars": "4.7.8",
34
35
  "memoizee": "0.4.15",
35
- "prop-types": "^15.0.0",
36
- "react-native-handlebars": "^5.0.0-alpha.1"
36
+ "prop-types": "^15.0.0"
37
37
  },
38
38
  "peerDependencies": {
39
39
  "@applicaster/zapp-pipes-v2-client": "*",
@@ -1,14 +1,19 @@
1
1
  import * as React from "react";
2
2
  import { usePlayer } from "@applicaster/zapp-react-native-utils/appUtils/playerManager/usePlayer";
3
- import { useAccessibilityManager } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks";
3
+ import {
4
+ useAccessibilityManager,
5
+ useAccessibilityState,
6
+ } from "@applicaster/zapp-react-native-utils/appUtils/accessibilityManager/hooks";
4
7
  import { PlayerTTS } from "@applicaster/zapp-react-native-utils/playerUtils/PlayerTTS";
5
8
 
6
9
  export const usePlayerTTS = () => {
7
10
  const player = usePlayer();
8
11
  const accessibilityManager = useAccessibilityManager({});
12
+ const accessibilityState = useAccessibilityState();
13
+ const isScreenReaderEnabled = accessibilityState.screenReaderEnabled;
9
14
 
10
15
  React.useEffect(() => {
11
- if (player && accessibilityManager) {
16
+ if (player && accessibilityManager && isScreenReaderEnabled) {
12
17
  const playerTTS = new PlayerTTS(player, accessibilityManager);
13
18
  const unsubscribe = playerTTS.init();
14
19
 
@@ -17,5 +22,5 @@ export const usePlayerTTS = () => {
17
22
  playerTTS.destroy();
18
23
  };
19
24
  }
20
- }, [player, accessibilityManager]);
25
+ }, [player, accessibilityManager, isScreenReaderEnabled]);
21
26
  };
@@ -6,6 +6,7 @@ import { deprecationMessage } from "../appUtils";
6
6
 
7
7
  import { pluginUtilsLogger } from "./logger";
8
8
  import { platformSelect } from "../reactUtils";
9
+ import { get } from "../utils";
9
10
 
10
11
  type PluginModule = any;
11
12
  type Plugin = {
@@ -254,3 +255,6 @@ const getPluginType = R.pathOr("unknown_plugin_type", [
254
255
 
255
256
  export const isPlayerPlugin = (routeState): boolean =>
256
257
  getPluginType(routeState) === "player";
258
+
259
+ export const getPluginModuleUrlScheme = (plugin) =>
260
+ get(plugin, ["module", "urlScheme"]);