@24i/bigscreen-sdk 1.0.4 → 1.0.5-4.alpha-2832

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 (292) hide show
  1. package/README.md +2 -3
  2. package/ci/is_ci_job_skippable.sh +153 -0
  3. package/package.json +55 -34
  4. package/packages/adobe-heartbeat/src/AdobeHeartbeat.ts +9 -9
  5. package/packages/analytics/README.md +8 -0
  6. package/packages/analytics/src/A.ts +1 -0
  7. package/packages/analytics/src/Analytics.ts +1 -0
  8. package/packages/analytics/src/analyticsOnScroll.ts +1 -0
  9. package/packages/analytics/src/clients/ConsoleAnalytics/ConsoleAnalytics.ts +1 -0
  10. package/packages/analytics/src/clients/ConsoleAnalytics/index.ts +1 -0
  11. package/packages/analytics/src/clients/GoogleAnalytics/GoogleAnalytics.ts +196 -0
  12. package/packages/analytics/src/clients/GoogleAnalytics/constants.ts +126 -0
  13. package/packages/analytics/src/clients/GoogleAnalytics/getUrl.ts +17 -0
  14. package/packages/analytics/src/clients/GoogleAnalytics/index.ts +2 -0
  15. package/packages/analytics/src/clients/GoogleAnalytics/interface.ts +82 -0
  16. package/packages/analytics/src/clients/GoogleAnalytics/mapPayload.ts +51 -0
  17. package/packages/analytics/src/clients/GoogleAnalytics/prepareBody.ts +14 -0
  18. package/packages/analytics/src/clients/TealiumAnalytics/TealiumAnalytics.ts +181 -0
  19. package/packages/analytics/src/clients/TealiumAnalytics/constants.ts +106 -0
  20. package/packages/analytics/src/clients/TealiumAnalytics/findForLanguage.ts +9 -0
  21. package/packages/analytics/src/clients/TealiumAnalytics/index.ts +4 -0
  22. package/packages/analytics/src/clients/TealiumAnalytics/interface.ts +35 -0
  23. package/packages/analytics/src/clients/TealiumAnalytics/mappers/__mocks__/mediaPayload.ts +72 -0
  24. package/packages/analytics/src/clients/TealiumAnalytics/mappers/helper.ts +36 -0
  25. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapAppError.ts +13 -0
  26. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapAppOpen.ts +13 -0
  27. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapFavoriteAdd.ts +11 -0
  28. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapFavoriteRemove.ts +11 -0
  29. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapPlayerClose.ts +15 -0
  30. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapPlayerOpen.ts +15 -0
  31. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapSceneView.ts +18 -0
  32. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapSearch.ts +18 -0
  33. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapSearchFailed.ts +8 -0
  34. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapSearchSuccess.ts +8 -0
  35. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapVideoPause.ts +15 -0
  36. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapVideoProgress.ts +18 -0
  37. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapVideoResume.ts +15 -0
  38. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapVideoStart.ts +15 -0
  39. package/packages/analytics/src/clients/TealiumAnalytics/mappers/mapVideoStop.ts +15 -0
  40. package/packages/analytics/src/clients/TealiumAnalytics/types.ts +161 -0
  41. package/packages/analytics/src/clients/TwentyFourIQ/TwentyFourIQClient.ts +107 -0
  42. package/packages/analytics/src/clients/TwentyFourIQ/constants.ts +111 -0
  43. package/packages/analytics/src/clients/TwentyFourIQ/helper.ts +34 -0
  44. package/packages/analytics/src/clients/TwentyFourIQ/index.ts +2 -0
  45. package/packages/analytics/src/clients/TwentyFourIQ/interface.ts +34 -0
  46. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapAdEvent.ts +20 -0
  47. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapBase.ts +24 -0
  48. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapBuffering.ts +15 -0
  49. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapPlayerClose.ts +25 -0
  50. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapPlayerOpen.ts +17 -0
  51. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapSceneView.ts +15 -0
  52. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapScroll.ts +17 -0
  53. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapVideoComplete.ts +22 -0
  54. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapVideoPause.ts +25 -0
  55. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapVideoProgress.ts +25 -0
  56. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapVideoStart.ts +34 -0
  57. package/packages/analytics/src/clients/TwentyFourIQ/mappers/mapVideoStop.ts +32 -0
  58. package/packages/analytics/src/clients/TwentyFourIQ/types.ts +132 -0
  59. package/packages/analytics/src/constants.ts +1 -0
  60. package/packages/analytics/src/index.ts +3 -0
  61. package/packages/analytics/src/interface.ts +1 -0
  62. package/packages/analytics/src/utils/generateSessionId.ts +8 -0
  63. package/packages/async-image/src/AsyncImage.tsx +15 -10
  64. package/packages/developer-tools/PlayerDebugWindow/README.md +1 -1
  65. package/packages/developer-tools/src/DeveloperConsole/DeveloperConsole.tsx +1 -0
  66. package/packages/developer-tools/src/DeveloperToolsService/DeveloperToolsList.tsx +11 -0
  67. package/packages/developer-tools/src/PlayerDebugWindow/PlayerDebugWindow.tsx +5 -5
  68. package/packages/developer-tools/src/PlayerDebugWindow/constants.ts +15 -0
  69. package/packages/developer-tools/src/TechnicalInfo/TechnicalInfo.tsx +2 -0
  70. package/packages/developer-tools/src/TechnicalInfo/TechnicalInfoDetail.tsx +2 -1
  71. package/packages/developer-tools/src/TechnicalInfo/TechnicalInfoProvider.ts +57 -5
  72. package/packages/developer-tools/src/TechnicalInfo/__mocks__/Device.ts +12 -0
  73. package/packages/developer-tools/src/TechnicalInfo/translations.ts +8 -0
  74. package/packages/device/src/driver/index.android.tv.ts +1 -0
  75. package/packages/device/src/driver/index.firetv.ts +1 -0
  76. package/packages/device/src/driver/index.smartcast.tv.ts +1 -0
  77. package/packages/device/src/getKeyDigit.ts +2 -2
  78. package/packages/device/src/resolver/resolver.ts +19 -0
  79. package/packages/digital-clock/src/DigitalClock.tsx +15 -4
  80. package/packages/driver-androidtv/src/DeviceAndroidTV.ts +262 -0
  81. package/packages/driver-androidtv/src/__mocks__/javaScriptBridge.ts +45 -0
  82. package/packages/driver-androidtv/src/formatUserAgent.ts +11 -0
  83. package/packages/driver-androidtv/src/index.ts +2 -0
  84. package/packages/driver-androidtv/src/keymap.ts +27 -0
  85. package/packages/driver-androidtv/src/types.ts +155 -0
  86. package/packages/driver-base/src/DeviceBase.ts +73 -2
  87. package/packages/driver-base/src/KeyMap/Key.ts +8 -1
  88. package/packages/driver-base/src/KeyMap/KeyMap.ts +4 -0
  89. package/packages/driver-base/src/KeyMap/interface.ts +1 -0
  90. package/packages/driver-base/src/KeyMap/overrideValues.ts +2 -1
  91. package/packages/driver-base/src/__mocks__/DeviceBase.ts +24 -0
  92. package/packages/driver-base/src/__mocks__/keyMap.ts +1 -0
  93. package/packages/driver-base/src/index.ts +3 -0
  94. package/packages/driver-base/src/types/AdInfo.ts +5 -0
  95. package/packages/driver-base/src/types/DeviceEvent.ts +2 -0
  96. package/packages/driver-base/src/types/InAppPurchase.ts +20 -0
  97. package/packages/driver-base/src/types/KeycodeKeyMap.ts +1 -0
  98. package/packages/driver-browser/src/DeviceBrowser.ts +26 -0
  99. package/packages/driver-browser/src/keymap.ts +8 -0
  100. package/packages/driver-entone/src/DeviceEntone.ts +31 -1
  101. package/packages/driver-entone/src/keymap.ts +1 -0
  102. package/packages/driver-firetv/src/DeviceFireTV.ts +86 -0
  103. package/packages/driver-firetv/src/__mocks__/javaScriptBridge.ts +45 -0
  104. package/packages/driver-firetv/src/index.ts +1 -0
  105. package/packages/driver-firetv/src/types.ts +1 -0
  106. package/packages/driver-hbbtv/src/DeviceHbbTV.ts +26 -0
  107. package/packages/driver-kreatv/src/DeviceKreaTV.ts +26 -0
  108. package/packages/driver-saphi/src/DeviceSaphi.ts +26 -0
  109. package/packages/driver-smartcast/src/DeviceSmartCast.ts +380 -0
  110. package/packages/driver-smartcast/src/__mocks__/api.ts +69 -0
  111. package/packages/driver-smartcast/src/index.ts +1 -0
  112. package/packages/driver-smartcast/src/keymap.ts +9 -0
  113. package/packages/driver-smartcast/src/types.ts +102 -0
  114. package/packages/driver-tizen/src/DeviceTizen.ts +121 -7
  115. package/packages/driver-tizen/src/ITizen.ts +15116 -202
  116. package/packages/driver-tizen/src/IWebapis.ts +8643 -87
  117. package/packages/driver-tizen/src/TizenKeys.ts +4 -2
  118. package/packages/driver-tizen/src/__mocks__/tizen.ts +7 -8
  119. package/packages/driver-tizen/src/constants.ts +1 -195
  120. package/packages/driver-vidaa/src/DeviceVidaa.ts +29 -2
  121. package/packages/driver-vidaa/src/__mocks__/vidaa.ts +1 -1
  122. package/packages/driver-vidaa/src/keymap.ts +2 -0
  123. package/packages/driver-webos/src/DeviceWebos.ts +55 -0
  124. package/packages/driver-webos/src/__mocks__/webos.ts +33 -0
  125. package/packages/driver-webos/src/constants.ts +1 -0
  126. package/packages/driver-webos/src/keymap.ts +2 -1
  127. package/packages/driver-webos/src/types.ts +30 -0
  128. package/packages/driver-xbox/src/DeviceXbox.ts +30 -1
  129. package/packages/driver-xbox/src/keymap.ts +1 -1
  130. package/packages/epg/README.md +3 -1
  131. package/packages/epg/src/v2/Cell.tsx +16 -2
  132. package/packages/epg/src/v2/DataManager.ts +112 -41
  133. package/packages/epg/src/v2/DatePicker.tsx +9 -3
  134. package/packages/epg/src/v2/DateToast/DateToast.tsx +12 -9
  135. package/packages/epg/src/v2/Day.tsx +6 -3
  136. package/packages/epg/src/v2/Epg.tsx +5 -5
  137. package/packages/epg/src/v2/MockGenerator/generator.ts +3 -2
  138. package/packages/epg/src/v2/ProgramInfo/utils.ts +4 -3
  139. package/packages/epg/src/v2/Row.tsx +3 -1
  140. package/packages/epg/src/v2/TimelineSection.tsx +4 -1
  141. package/packages/epg/src/v2/basic/CellsManager.tsx +7 -2
  142. package/packages/epg/src/v2/basic/RowsManager.tsx +3 -1
  143. package/packages/epg/src/v2/interface.ts +13 -0
  144. package/packages/events-manager/src/EventsManager.ts +1 -56
  145. package/packages/focus/README.md +33 -0
  146. package/packages/focus/src/IFocusable.ts +1 -0
  147. package/packages/focus/src/Layout/Base.tsx +41 -6
  148. package/packages/focus/src/Layout/Matrix.tsx +51 -19
  149. package/packages/focus/src/focusFirstExisting.ts +7 -1
  150. package/packages/focus/src/hasFocus.ts +36 -0
  151. package/packages/focus/src/index.ts +2 -1
  152. package/packages/gallup/src/Gallup.ts +3 -3
  153. package/packages/grid/src/Base/Base.tsx +15 -10
  154. package/packages/grid/src/FirstOnlyGrid/FirstOnlyGrid.tsx +4 -2
  155. package/packages/grid/src/UnifiedGridController/UnifiedGridController.ts +6 -6
  156. package/packages/icon/src/Icon.tsx +27 -5
  157. package/packages/input/README.md +1 -1
  158. package/packages/input/src/Input.tsx +10 -10
  159. package/packages/interactable/README.md +2 -1
  160. package/packages/interactable/src/Interactable.tsx +9 -3
  161. package/packages/interactable/src/interface.ts +1 -0
  162. package/packages/jsx/src/index.ts +1 -1
  163. package/packages/jsx/src/test-utils/index.ts +1 -0
  164. package/packages/jsx/src/test-utils/keyup.ts +27 -0
  165. package/packages/keyboard/README.md +2 -0
  166. package/packages/keyboard/src/Backdrop/Backdrop.scss +2 -0
  167. package/packages/keyboard/src/KeyboardBase.tsx +16 -4
  168. package/packages/keyboard/src/WhitelabelKeyboard/Keyboard.scss +10 -0
  169. package/packages/keyboard/src/WhitelabelKeyboard/Keyboard.tsx +128 -142
  170. package/packages/keyboard/src/WhitelabelKeyboard/WhitelabelStyles/whitelabel.scss +4 -0
  171. package/packages/keyboard/src/WhitelabelKeyboard/_sizes.1080.scss +1 -0
  172. package/packages/keyboard/src/WhitelabelKeyboard/_sizes.scss +1 -0
  173. package/packages/keyboard/src/WhitelabelKeyboard/icons/key_language.svg +20 -0
  174. package/packages/keyboard/src/WhitelabelKeyboard/index.ts +1 -1
  175. package/packages/keyboard/src/WhitelabelKeyboard/layouts/arabic.ts +27 -0
  176. package/packages/keyboard/src/WhitelabelKeyboard/layouts/burmese.ts +27 -0
  177. package/packages/keyboard/src/WhitelabelKeyboard/layouts/dari.ts +28 -0
  178. package/packages/keyboard/src/WhitelabelKeyboard/layouts/hebrew.ts +28 -0
  179. package/packages/keyboard/src/WhitelabelKeyboard/layouts/index.ts +15 -0
  180. package/packages/keyboard/src/WhitelabelKeyboard/layouts/korean.ts +26 -0
  181. package/packages/keyboard/src/WhitelabelKeyboard/layouts/latin.ts +26 -0
  182. package/packages/keyboard/src/WhitelabelKeyboard/layouts/pashto.ts +27 -0
  183. package/packages/keyboard/src/WhitelabelKeyboard/layouts/persian.ts +27 -0
  184. package/packages/keyboard/src/WhitelabelKeyboard/layouts/russian.ts +27 -0
  185. package/packages/keyboard/src/WhitelabelKeyboard/layouts/spanish.ts +26 -0
  186. package/packages/keyboard/src/WhitelabelKeyboard/layouts/special.ts +28 -0
  187. package/packages/keyboard/src/WhitelabelKeyboard/layouts/tibetan.ts +26 -0
  188. package/packages/keyboard/src/WhitelabelKeyboard/layouts/turkish.ts +26 -0
  189. package/packages/keyboard/src/WhitelabelKeyboard/layouts/ukrainian.ts +27 -0
  190. package/packages/keyboard/src/WhitelabelKeyboard/layouts/urdu.ts +26 -0
  191. package/packages/keyboard/src/WhitelabelKeyboard/types.ts +22 -2
  192. package/packages/keyboard/src/types/index.ts +1 -1
  193. package/packages/keyboard/src/utils/caret.ts +5 -8
  194. package/packages/keyboard/src/utils/input.ts +5 -6
  195. package/packages/keyboard/src/utils/setInputSelectionRange.ts +10 -0
  196. package/packages/l10n/README.md +18 -0
  197. package/packages/l10n/src/date/common.ts +18 -6
  198. package/packages/l10n/src/date/cs.ts +2 -8
  199. package/packages/l10n/src/date/de.ts +97 -0
  200. package/packages/l10n/src/date/en-001.ts +3 -3
  201. package/packages/l10n/src/date/en-common.ts +5 -4
  202. package/packages/l10n/src/date/en-us.ts +3 -3
  203. package/packages/l10n/src/date/es.ts +71 -0
  204. package/packages/l10n/src/date/fr.ts +94 -0
  205. package/packages/l10n/src/date/he.ts +101 -0
  206. package/packages/l10n/src/date/iso.ts +12 -13
  207. package/packages/l10n/src/date/types.ts +9 -0
  208. package/packages/l10n/src/l10n.ts +61 -3
  209. package/packages/list/src/Base/Base.tsx +19 -9
  210. package/packages/list/src/Base/interface.ts +2 -2
  211. package/packages/list/src/BasicList/BasicList.tsx +7 -7
  212. package/packages/list/src/CenteredList/CenteredList.tsx +2 -2
  213. package/packages/list/src/CenteredList/controller.ts +0 -1
  214. package/packages/list/src/EdgeOffsetList/EdgeOffsetList.tsx +10 -10
  215. package/packages/list/src/FirstOnlyList/FirstOnlyList.tsx +2 -2
  216. package/packages/list/src/FirstOnlyVariedList/FirstOnlyVariedList.tsx +2 -2
  217. package/packages/list/src/FixedToEndList/FixedToEndList.tsx +2 -2
  218. package/packages/list/src/UnifiedListController/UnifiedListController.ts +6 -2
  219. package/packages/list/src/interface.ts +2 -2
  220. package/packages/logger/src/loggers/ConsoleLogger/ConsoleLogger.ts +7 -1
  221. package/packages/logger/src/loggers/SentryLogger/Sentry.ts +1 -0
  222. package/packages/logger/src/loggers/SentryLogger/SentryLogger.ts +5 -3
  223. package/packages/menu/src/MenuAndContentContainer/MenuAndContentContainer.tsx +31 -3
  224. package/packages/menu/src/MenuAndContentContainer/interface.ts +8 -0
  225. package/packages/modal-service/README.md +4 -1
  226. package/packages/modal-service/src/ModalService.tsx +29 -5
  227. package/packages/perf-utils/README.md +1 -120
  228. package/packages/perf-utils/src/array/filter.ts +1 -54
  229. package/packages/perf-utils/src/array/find.ts +1 -43
  230. package/packages/perf-utils/src/array/findIndex.ts +1 -43
  231. package/packages/perf-utils/src/array/forEach.ts +1 -48
  232. package/packages/perf-utils/src/array/includes.ts +1 -41
  233. package/packages/perf-utils/src/array/includesNaN.ts +1 -32
  234. package/packages/perf-utils/src/array/index.ts +1 -7
  235. package/packages/perf-utils/src/array/map.ts +1 -52
  236. package/packages/player-ui/README.md +1 -1
  237. package/packages/player-ui/src/CurrentTime.tsx +2 -2
  238. package/packages/player-ui/src/Duration.tsx +2 -2
  239. package/packages/player-ui/src/PauseButton.tsx +8 -0
  240. package/packages/player-ui/src/PlayerInteractable.tsx +1 -0
  241. package/packages/player-ui/src/PlayerTime.tsx +3 -1
  242. package/packages/player-ui/src/PlayerUI.tsx +68 -35
  243. package/packages/player-ui/src/RemainingTime.tsx +2 -2
  244. package/packages/player-ui/src/Seekbar.tsx +110 -18
  245. package/packages/player-ui/src/Seeking.ts +57 -16
  246. package/packages/player-ui/src/Subtitles.tsx +2 -2
  247. package/packages/player-ui/src/index.ts +1 -0
  248. package/packages/player-ui/src/mocks.ts +32 -8
  249. package/packages/player-ui/src/timeUtils.ts +3 -3
  250. package/packages/player-ui/src/types.ts +9 -3
  251. package/packages/router/README.md +1 -0
  252. package/packages/router/src/Route.tsx +61 -27
  253. package/packages/router/src/Router.tsx +63 -14
  254. package/packages/router/src/history.ts +8 -1
  255. package/packages/router/src/index.ts +1 -1
  256. package/packages/router/src/utils.ts +9 -4
  257. package/packages/sass-utils/src/linear-gradient.scss +9 -4
  258. package/packages/sass-utils/src/scale.1080.scss +3 -1
  259. package/packages/sass-utils/src/scale.720.scss +1 -1
  260. package/packages/time/README.md +4 -1
  261. package/packages/time/src/Time.ts +35 -13
  262. package/packages/time/src/adapters/24iMediaTimeApi.ts +47 -0
  263. package/packages/time/src/constants.ts +1 -0
  264. package/packages/time/src/services/24iMediaTimeApi/24iMediaTimeApi.ts +43 -0
  265. package/packages/time/src/services/24iMediaTimeApi/index.ts +6 -0
  266. package/packages/toast/src/ToastService.scss +1 -0
  267. package/packages/toast/src/ToastService.tsx +16 -5
  268. package/packages/types-bigscreen-jsx/README.md +5 -4
  269. package/packages/types-bigscreen-jsx/index.d.ts +72 -67
  270. package/packages/utils/README.md +27 -0
  271. package/packages/utils/src/elementUtils.ts +25 -0
  272. package/packages/utils/src/forceReflow.ts +14 -0
  273. package/packages/utils/src/index.ts +8 -0
  274. package/packages/utils/src/keyPress/index.ts +6 -0
  275. package/packages/utils/src/keyPress/keyPressSimulator.ts +74 -0
  276. package/packages/utils/src/keyPress/simulateKeyPress.ts +25 -0
  277. package/packages/utils/src/scaledImage.ts +6 -3
  278. package/packages/utils/src/textUtils.ts +46 -14
  279. package/packages/utils/src/wait.ts +3 -1
  280. package/packages/utils/src/xhr/xhrSend.ts +3 -1
  281. package/packages/utils/src/xhr/xhrSendRetry.ts +3 -1
  282. package/packages/zapping/src/ChannelZapping.ts +9 -0
  283. package/packages/zapping/src/Zapping.tsx +10 -0
  284. package/utils/release/release.ts +156 -0
  285. package/packages/driver-tizen/src/types.ts +0 -14
  286. package/packages/focus/src/Layout/__test__/Base.spec.ts +0 -180
  287. package/packages/focus/src/Layout/__test__/Horizontal.spec.ts +0 -94
  288. package/packages/focus/src/Layout/__test__/Matrix.spec.ts +0 -261
  289. package/packages/focus/src/Layout/__test__/Vertical.spec.ts +0 -46
  290. package/packages/focus/src/Layout/__test__/isRtl.spec.ts +0 -23
  291. package/packages/focus/src/Layout/__test__/shared.ts +0 -19
  292. package/packages/keyboard/src/WhitelabelKeyboard/focusMatrix.ts +0 -19
@@ -1,6 +1,7 @@
1
1
  import { filter, find, findIndex, map } from '@24i/bigscreen-sdk/perf-utils/array';
2
2
  import { Asset } from '@24i/smartapps-datalayer/models';
3
3
  import { i18n } from '@24i/bigscreen-sdk/i18n';
4
+ import { MINUTE_IN_MS } from '@24i/bigscreen-sdk/utils/timeConstants';
4
5
  import { isStartVisible, isEndVisible, isOverFullWidth } from './utils';
5
6
  import {
6
7
  DataRange,
@@ -14,6 +15,7 @@ const START = 0;
14
15
  const END = 1;
15
16
 
16
17
  const TIMELINE_WIDTHS_TO_FETCH = 3;
18
+ const MINIMUM_BREAK_LENGTH = MINUTE_IN_MS;
17
19
 
18
20
  export class DataManager implements IDataManager {
19
21
  private readonly data: Asset[] = [];
@@ -84,50 +86,115 @@ export class DataManager implements IDataManager {
84
86
  return [data[0].program!.startTime, data[data.length - 1].program!.endTime] as DataRange;
85
87
  }
86
88
 
87
- // TODO: Wait for fixes from @thepretiso before looking at this.
88
- // eslint-disable-next-line sonarjs/cognitive-complexity
89
- private getRangesMissingFromDataInRange([start, end]: DataRange) {
90
- const rangesLength = this.dataRanges.length;
91
- if (this.dataRanges.length === 0) return [[start, end]] as DataRange[];
92
- const firstRangeFrom = this.dataRanges[0][START];
93
- if (end <= firstRangeFrom) return [[start, end]] as DataRange[];
94
- if (start < firstRangeFrom && end <= this.dataRanges[0][END]) {
95
- return [
96
- [firstRangeFrom - TIMELINE_WIDTHS_TO_FETCH * this.timelineWidthMs, firstRangeFrom],
97
- ] as DataRange[];
89
+ private isInterceptingDataRanges = (firstDataRange: DataRange, secondDataRange: DataRange) => (
90
+ (firstDataRange[START] < secondDataRange[END]
91
+ && firstDataRange[START] > secondDataRange[START])
92
+ || (secondDataRange[START] < firstDataRange[END]
93
+ && secondDataRange[START] > firstDataRange[START])
94
+ );
95
+
96
+ private findRangeBeforeAndAfter = (currentRange: DataRange) => {
97
+ const rangeAfterIndex = findIndex(
98
+ this.dataRanges,
99
+ (dataRange) => dataRange[END] >= currentRange[END],
100
+ );
101
+ if (rangeAfterIndex === -1) {
102
+ return {
103
+ rangeAfter: undefined,
104
+ rangeBefore: this.dataRanges[this.dataRanges.length - 1],
105
+ };
98
106
  }
99
- const lastRangeTo = this.dataRanges[rangesLength - 1][END];
100
- if (end > lastRangeTo && start <= lastRangeTo) {
101
- return [
102
- [lastRangeTo, lastRangeTo + TIMELINE_WIDTHS_TO_FETCH * this.timelineWidthMs],
103
- ] as DataRange[];
107
+ const rangeAfter = this.dataRanges[rangeAfterIndex];
108
+ const rangeBefore = this.dataRanges[rangeAfterIndex - 1];
109
+ return { rangeAfter, rangeBefore };
110
+ };
111
+
112
+ private generateDataRangesForward = (start: number, end: number, cellSize: number) => {
113
+ const dataRanges: DataRange[] = [[start, start + cellSize]];
114
+ let currentStart = start + cellSize;
115
+ let currentEnd = currentStart + cellSize;
116
+ while (currentStart < end) {
117
+ if (currentEnd >= end) {
118
+ dataRanges.push([currentStart, end]);
119
+ break;
120
+ }
121
+ dataRanges.push([currentStart, currentEnd]);
122
+ currentStart += cellSize;
123
+ currentEnd += cellSize;
104
124
  }
105
- const ranges: DataRange[] = [];
106
- let newRange: DataRange = [start, end];
107
- for (let i = 0; i < rangesLength; i++) {
108
- const [rangeFrom, rangeTo] = this.dataRanges[i];
109
- // eslint-disable-next-line no-continue
110
- if (start >= rangeTo) continue;
111
- if (start < rangeFrom) {
112
- if (end <= rangeFrom) {
113
- if (newRange[START] !== newRange[END]) ranges.push(newRange);
114
- return ranges;
125
+ return dataRanges;
126
+ };
127
+
128
+ private generateDataRangesBackward = (start: number, end: number, cellSize: number) => {
129
+ const dataRanges: DataRange[] = [[start - cellSize, start]];
130
+ let currentEnd = start - cellSize;
131
+ let currentStart = currentEnd - cellSize;
132
+ while (currentEnd > start) {
133
+ if (currentStart <= start) {
134
+ dataRanges.push([start, currentEnd]);
135
+ break;
136
+ }
137
+ dataRanges.push([currentStart, currentEnd]);
138
+ currentStart -= cellSize;
139
+ currentEnd -= cellSize;
140
+ }
141
+ return dataRanges;
142
+ };
143
+
144
+ /* eslint-disable complexity */
145
+ // eslint-disable-next-line sonarjs/cognitive-complexity
146
+ private getRangesMissingFromDataInRange([start, end]: DataRange) {
147
+ const currentRange = [start, end] as DataRange;
148
+ const cellSize = TIMELINE_WIDTHS_TO_FETCH * this.timelineWidthMs;
149
+ if (this.dataRanges.length === 0) return [currentRange] as DataRange[];
150
+ const { rangeBefore, rangeAfter } = this.findRangeBeforeAndAfter(currentRange);
151
+ if (rangeAfter == null) {
152
+ const lastDataRange = this.dataRanges[this.dataRanges.length - 1];
153
+ if (this.isInterceptingDataRanges(lastDataRange, currentRange)) {
154
+ if (end > lastDataRange[END]) {
155
+ return this.generateDataRangesForward(lastDataRange[END], end, cellSize);
156
+ }
157
+ if (start < lastDataRange[START]) {
158
+ return this.generateDataRangesBackward(start, lastDataRange[START], cellSize);
115
159
  }
116
- newRange[END] = rangeFrom;
117
- if (newRange[START] !== newRange[END]) ranges.push(newRange);
118
- if (end <= rangeTo) {
119
- return ranges;
160
+ }
161
+ return [currentRange] as DataRange[];
162
+ }
163
+ if (rangeBefore == null) {
164
+ const firstDataRange = this.dataRanges[0];
165
+ if (this.isInterceptingDataRanges(firstDataRange, currentRange)) {
166
+ if (end > firstDataRange[END]) {
167
+ return this.generateDataRangesForward(firstDataRange[END], end, cellSize);
120
168
  }
121
- newRange = [rangeTo, end];
122
- } else if (start < rangeTo) {
123
- if (end <= rangeTo) {
124
- return ranges;
169
+ if (start < firstDataRange[START]) {
170
+ return this.generateDataRangesBackward(firstDataRange[START], start, cellSize);
125
171
  }
126
- newRange = [rangeTo, end];
127
172
  }
173
+ return [currentRange] as DataRange[];
174
+ }
175
+ const rangeAfterFrom = rangeAfter[START];
176
+ const rangeBeforeTo = rangeBefore[END];
177
+ // Ranges are collapsed
178
+ if (rangeBeforeTo === rangeAfterFrom) return [];
179
+ // Both are not null and don't intercept
180
+ if (
181
+ !this.isInterceptingDataRanges(rangeAfter, currentRange)
182
+ && !this.isInterceptingDataRanges(rangeBefore, currentRange)
183
+ ) {
184
+ return [currentRange];
185
+ }
186
+ // Left intercepts
187
+ if (this.isInterceptingDataRanges(rangeBefore, currentRange)) {
188
+ return [rangeBefore, ...this.generateDataRangesForward(rangeBeforeTo, end, cellSize)];
189
+ }
190
+ // Right intercepts
191
+ if (this.isInterceptingDataRanges(rangeAfter, currentRange)) {
192
+ return [
193
+ ...this.generateDataRangesBackward(rangeAfterFrom, start, cellSize),
194
+ rangeAfter,
195
+ ];
128
196
  }
129
- if (newRange[START] !== newRange[END]) ranges.push(newRange);
130
- return ranges;
197
+ return [currentRange] as DataRange[];
131
198
  }
132
199
 
133
200
  private getMissingRanges(range: DataRange) {
@@ -211,7 +278,7 @@ export class DataManager implements IDataManager {
211
278
  try {
212
279
  fetchedData = await this.fetchPrograms(this.channel, start, end);
213
280
  } catch (e) {
214
- return null;
281
+ fetchedData = [];
215
282
  }
216
283
  this.fillInSpaces([start, end], fetchedData);
217
284
  if (fetchedData.length === 0) return null;
@@ -290,11 +357,15 @@ export class DataManager implements IDataManager {
290
357
  for (let i = data.length - 1; i > 0; i--) {
291
358
  const current = data[i];
292
359
  const previous = data[i - 1];
293
- if (previous.program!.endTime < current.program!.startTime) {
294
- data.splice(i, 0,
360
+ const breakLength = current.program!.startTime - previous.program!.endTime;
361
+ if (breakLength > 0 && breakLength >= MINIMUM_BREAK_LENGTH) {
362
+ data.splice(
363
+ i,
364
+ 0,
295
365
  this.generateNoDataProgram(
296
366
  previous.program!.endTime, current.program!.startTime,
297
- ));
367
+ ),
368
+ );
298
369
  }
299
370
  }
300
371
  }
@@ -1,4 +1,5 @@
1
1
  import { Component, createRef, DeclareProps } from '@24i/bigscreen-sdk/jsx';
2
+ import { time } from '@24i/bigscreen-sdk/time';
2
3
  import { Picker } from '@24i/bigscreen-sdk/picker';
3
4
  import { DatePicker as NativeDatePicker } from '@24i/bigscreen-sdk/picker/DatePicker';
4
5
  import { DAY_IN_MS, HOUR_IN_MS, MINUTE_IN_MS, SECOND_IN_MS } from '@24i/bigscreen-sdk/utils';
@@ -44,9 +45,14 @@ const prepareDateData = ({
44
45
  return { selectedValue, from, to, overrides };
45
46
  };
46
47
 
47
- const defaultFormat = (date: Date) => l10n.date(date).toLocaleDateString(
48
- { weekday: 'short', day: 'numeric', month: 'short' },
49
- );
48
+ const defaultFormat = (date: Date) => {
49
+ const locale = i18n.getLanguage();
50
+ return l10n
51
+ .date(date.getTime() + time.getTimezoneOffsetMs(), locale)
52
+ .toLocaleDateString({
53
+ weekday: 'short', day: 'numeric', month: 'short', formatType: 'dateFormatShort',
54
+ });
55
+ };
50
56
 
51
57
  export class DatePicker extends Component<Props> implements IDatePicker {
52
58
  datePicker = createRef<Picker<number>>();
@@ -6,28 +6,31 @@ import { time } from '@24i/bigscreen-sdk/time';
6
6
  import { HOUR_IN_MS } from '@24i/bigscreen-sdk/utils/timeConstants';
7
7
  import { InternalEpg, Plugin } from '../interface';
8
8
 
9
- const formatTime = (timestamp: number) => l10n.date(timestamp).toLocaleTimeString(
10
- { hour: 'numeric', minute: '2-digit' },
9
+ const formatTime = (localTimestamp: number) => l10n.date(localTimestamp).toLocaleTimeString(
10
+ { hour: 'numeric', minute: '2-digit', formatType: 'timeFormat' },
11
11
  );
12
12
 
13
- const formatDate = (timestamp: number) => {
14
- if (time.isToday(timestamp)) {
13
+ const formatDate = (localTimestamp: number) => {
14
+ if (time.isToday(localTimestamp)) {
15
15
  return i18n.t('date.today');
16
16
  }
17
- if (time.isYesterday(timestamp)) {
17
+ if (time.isYesterday(localTimestamp)) {
18
18
  return i18n.t('date.yesterday');
19
19
  }
20
- if (time.isTomorrow(timestamp)) {
20
+ if (time.isTomorrow(localTimestamp)) {
21
21
  return i18n.t('date.tomorrow');
22
22
  }
23
- return l10n.date(timestamp).toLocaleString({
23
+ return l10n.date(localTimestamp).toLocaleString({
24
24
  weekday: 'short',
25
25
  day: 'numeric',
26
26
  month: 'short',
27
+ formatType: 'dateFormatShort',
27
28
  });
28
29
  };
29
30
 
30
- const formatDatetime = (timestamp: number) => `${formatDate(timestamp)} • ${formatTime(timestamp)}`;
31
+ const formatDatetime = (localTimestamp: number) => (
32
+ `${formatDate(localTimestamp)} • ${formatTime(localTimestamp)}`
33
+ );
31
34
 
32
35
  type Props = {
33
36
  epg: InternalEpg<any, any, any, any>,
@@ -44,7 +47,7 @@ export class DateToast extends Component<Props> implements Plugin {
44
47
 
45
48
  onScrolledToTimestamp(timestamp: number) {
46
49
  const { epg } = this.props;
47
- const day = formatDatetime(timestamp);
50
+ const day = formatDatetime(timestamp + time.getTimezoneOffsetMs());
48
51
  if (this.lastDay === null) { // we do not want to display it after render and first move
49
52
  this.lastDay = day;
50
53
  return;
@@ -1,4 +1,5 @@
1
1
  import { Component, createRef, setText } from '@24i/bigscreen-sdk/jsx';
2
+ import { time } from '@24i/bigscreen-sdk/time';
2
3
  import { l10n } from '@24i/bigscreen-sdk/l10n';
3
4
  import { DayProps as Props, Day as IDay } from './interface';
4
5
 
@@ -15,9 +16,11 @@ export class Day extends Component<Props> implements IDay {
15
16
  }
16
17
 
17
18
  private formatCurrentTimestamp() {
18
- return l10n.date(this.timestamp).toLocaleDateString(
19
- { weekday: 'long', day: 'numeric', month: 'short' },
20
- );
19
+ return l10n
20
+ .date(this.timestamp + time.getTimezoneOffsetMs())
21
+ .toLocaleDateString({
22
+ weekday: 'long', day: 'numeric', month: 'short', formatType: 'dateFormatShort',
23
+ });
21
24
  }
22
25
 
23
26
  render() {
@@ -83,6 +83,7 @@ export class Epg<
83
83
  timeProvider: Date.now,
84
84
  scrollStepMs: HALF_HOUR_IN_MS,
85
85
  timelineSectionWidthMs: HALF_HOUR_IN_MS,
86
+ smallestAllowedCellPx: 0,
86
87
  limitFromMs: -Infinity,
87
88
  limitToMs: Infinity,
88
89
  initialChannelIndex: 0,
@@ -297,6 +298,8 @@ export class Epg<
297
298
  return ref;
298
299
  }
299
300
 
301
+ isFocusInRows = () => this.focused === 'epg';
302
+
300
303
  focus(options?: FocusOptions) {
301
304
  if (this.focused === 'datepicker') {
302
305
  this.datePickerComponent.current!.focus(options);
@@ -376,15 +379,11 @@ export class Epg<
376
379
  return this.inputEvents.isVerticallyFastScrolling();
377
380
  }
378
381
 
379
- isFocusInRows = () => {
380
- return this.focused === 'epg';
381
- };
382
-
383
382
  render() {
384
383
  const {
385
384
  datePickerProps, timelineWidthPx, channelHeaderWidthPx, scrollStepMs, rowHeightPx,
386
385
  timelineSectionWidthMs, timelineWidthMs, initialChannelIndex, plugins,
387
- navigatableRows, additionalRows, programTextModeResolver,
386
+ navigatableRows, additionalRows, programTextModeResolver, smallestAllowedCellPx,
388
387
  renderDay, renderTime, renderProgram, renderChannelHeader, renderNowLineHeader,
389
388
  } = this.props;
390
389
  return (
@@ -444,6 +443,7 @@ export class Epg<
444
443
  renderChannelHeader={renderChannelHeader}
445
444
  renderProgram={renderProgram}
446
445
  isFocusInRows={this.isFocusInRows}
446
+ smallestAllowedCellPx={smallestAllowedCellPx}
447
447
  />
448
448
  <EpgMouseNavigation
449
449
  // @ts-ignore - needed to convert fallback (false) to interface
@@ -1,6 +1,6 @@
1
1
  import { HOUR_IN_MS } from '@24i/bigscreen-sdk/utils/timeConstants';
2
2
  import {
3
- Asset, ID, UIElement, UIElementType,
3
+ Asset, AssetType, ID, UIElement, UIElementType,
4
4
  } from '@24i/smartapps-datalayer/models';
5
5
  import {
6
6
  randomFromRange, getRandomItemFromArray, shuffleArray, getProgramImageUrl,
@@ -56,9 +56,10 @@ const generateChannels = (count: number): Asset[] => {
56
56
  uiElements: [
57
57
  {
58
58
  type: UIElementType.IMAGE,
59
- url: getChannelImageUrl(),
59
+ url: getChannelImageUrl() ?? '',
60
60
  } as UIElement,
61
61
  ],
62
+ type: AssetType.CHANNEL,
62
63
  });
63
64
  }
64
65
 
@@ -1,4 +1,5 @@
1
1
  import { l10n } from '@24i/bigscreen-sdk/l10n';
2
+ import { time } from '@24i/bigscreen-sdk/time';
2
3
  import { Asset } from '@24i/smartapps-datalayer/models';
3
4
 
4
5
  export const cutString = (string: string, length: number) => {
@@ -16,9 +17,9 @@ export const getSubtitle = (asset: Asset) => (
16
17
  : ''
17
18
  );
18
19
 
19
- const toLocaleTimeString = (timestamp: number) => l10n.date(timestamp).toLocaleTimeString(
20
- { hour: 'numeric', minute: '2-digit' },
21
- );
20
+ const toLocaleTimeString = (timestamp: number) => l10n
21
+ .date(timestamp + time.getTimezoneOffsetMs())
22
+ .toLocaleTimeString({ hour: 'numeric', minute: '2-digit', formatType: 'timeFormat' });
22
23
 
23
24
  export const getBroadcastTime = (asset: Asset) => {
24
25
  const start = toLocaleTimeString(asset.program!.startTime);
@@ -109,7 +109,8 @@ export class Row<
109
109
 
110
110
  render() {
111
111
  const {
112
- timelineWidthMs, timelineWidthPx, timestamp, time, pixelInMs,
112
+ timelineWidthMs, timestamp, time,
113
+ pixelInMs, timelineWidthPx, smallestAllowedCellPx,
113
114
  programTextModeResolver, onMouseEnter, renderProgram,
114
115
  } = this.props;
115
116
  return (
@@ -126,6 +127,7 @@ export class Row<
126
127
  onItemPress={this.onItemPress}
127
128
  onMouseEnter={onMouseEnter}
128
129
  renderProgram={renderProgram}
130
+ smallestAllowedCellPx={smallestAllowedCellPx}
129
131
  />
130
132
  );
131
133
  }
@@ -1,4 +1,5 @@
1
1
  import { Component, createRef, setText } from '@24i/bigscreen-sdk/jsx';
2
+ import { time } from '@24i/bigscreen-sdk/time';
2
3
  import { l10n } from '@24i/bigscreen-sdk/l10n';
3
4
  import { offsetPosition } from '@24i/bigscreen-sdk/utils';
4
5
  import { TimelineSectionProps as Props, TimelineSection as ITimelineSection } from './interface';
@@ -23,7 +24,9 @@ export class TimelineSection extends Component<Props> implements ITimelineSectio
23
24
  }
24
25
 
25
26
  private formatCurrentTimestamp() {
26
- return l10n.date(this.timestamp).toLocaleTimeString({ hour: 'numeric', minute: '2-digit' });
27
+ return l10n
28
+ .date(this.timestamp + time.getTimezoneOffsetMs())
29
+ .toLocaleTimeString({ hour: 'numeric', minute: '2-digit', formatType: 'timeFormat' });
27
30
  }
28
31
 
29
32
  render() {
@@ -180,7 +180,8 @@ export class CellsManager<
180
180
 
181
181
  private addCell(item: Asset) {
182
182
  const {
183
- time, programTextModeResolver, onMouseEnter, onItemPress, onFocusChange, renderProgram,
183
+ time, smallestAllowedCellPx,
184
+ programTextModeResolver, onMouseEnter, onItemPress, onFocusChange, renderProgram,
184
185
  } = this.props;
185
186
  const cell = createRef<ICell<T>>();
186
187
  this.mountBefore((
@@ -195,6 +196,7 @@ export class CellsManager<
195
196
  onFocusChange={onFocusChange}
196
197
  onMouseEnter={onMouseEnter}
197
198
  renderProgram={renderProgram}
199
+ smallestAllowedCellPx={smallestAllowedCellPx}
198
200
  />
199
201
  ), this.endLoadingCell.current!.div);
200
202
  this.cells.push(cell);
@@ -241,7 +243,7 @@ export class CellsManager<
241
243
 
242
244
  render() {
243
245
  const {
244
- timelineWidthPx, time, dataGetter, programTextModeResolver,
246
+ timelineWidthPx, smallestAllowedCellPx, time, dataGetter, programTextModeResolver,
245
247
  onMouseEnter, onItemPress, onFocusChange, renderProgram,
246
248
  } = this.props;
247
249
  const visibleData = dataGetter(this.getRange());
@@ -257,6 +259,7 @@ export class CellsManager<
257
259
  onFocusChange={onFocusChange}
258
260
  onMouseEnter={onMouseEnter}
259
261
  renderProgram={renderProgram}
262
+ smallestAllowedCellPx={smallestAllowedCellPx}
260
263
  isLoading
261
264
  />
262
265
  {map(visibleData, (item) => {
@@ -274,6 +277,7 @@ export class CellsManager<
274
277
  onFocusChange={onFocusChange}
275
278
  onMouseEnter={onMouseEnter}
276
279
  renderProgram={renderProgram}
280
+ smallestAllowedCellPx={smallestAllowedCellPx}
277
281
  />
278
282
  );
279
283
  })}
@@ -288,6 +292,7 @@ export class CellsManager<
288
292
  onMouseEnter={onMouseEnter}
289
293
  renderProgram={renderProgram}
290
294
  isLoading
295
+ smallestAllowedCellPx={smallestAllowedCellPx}
291
296
  />
292
297
  </div>
293
298
  );
@@ -465,7 +465,8 @@ export class RowsManager<
465
465
 
466
466
  render() {
467
467
  const {
468
- timelineWidthMs, timelineWidthPx, timestamp, time, scrollStepMs, pixelInMs,
468
+ timelineWidthMs, timestamp, time, scrollStepMs,
469
+ pixelInMs, timelineWidthPx, smallestAllowedCellPx,
469
470
  programTextModeResolver, onItemPress, onMouseEnter, renderProgram, renderChannelHeader,
470
471
  } = this.props;
471
472
  const visibleData = this.getVisibleChannels();
@@ -492,6 +493,7 @@ export class RowsManager<
492
493
  onFocusChange={this.onFocusChange}
493
494
  onMouseEnter={onMouseEnter}
494
495
  renderProgram={renderProgram}
496
+ smallestAllowedCellPx={smallestAllowedCellPx}
495
497
  />
496
498
  ))}
497
499
  </Scroller>
@@ -241,6 +241,14 @@ type ScrollStepMsProp = {
241
241
  scrollStepMs: number,
242
242
  };
243
243
 
244
+ type SmallestAllowedCellPxProp = {
245
+ /**
246
+ * If the width of the cell is smaller than this the cell will have a special
247
+ * class `too-small`. Value in pixels.
248
+ */
249
+ smallestAllowedCellPx: number,
250
+ };
251
+
244
252
  type IdleTimerMsProp = {
245
253
  /**
246
254
  * The number of milliseconds of inactivity (no input) after which EPG starts jumps
@@ -823,6 +831,7 @@ export type RowsManagerProps<
823
831
  & RenderChannelHeaderProp<T>
824
832
  & RenderProgramProp<U>
825
833
  & IsFocusInRowsProp
834
+ & SmallestAllowedCellPxProp
826
835
  );
827
836
 
828
837
  /**
@@ -933,6 +942,7 @@ export type RowProps<
933
942
  & TimestampProp
934
943
  & TimeProp
935
944
  & ScrollStepMsProp
945
+ & SmallestAllowedCellPxProp
936
946
  & ProgramTextModeResolverProp
937
947
  & OnItemPressProp<T>
938
948
  & OnMouseEnterProp
@@ -1046,6 +1056,7 @@ export type CellsManagerProps<
1046
1056
  & ProgramTextModeResolverProp
1047
1057
  & OnMouseEnterProp
1048
1058
  & RenderProgramProp<T>
1059
+ & SmallestAllowedCellPxProp
1049
1060
  );
1050
1061
 
1051
1062
  /**
@@ -1133,6 +1144,7 @@ export type CellProps<
1133
1144
  & ProgramTextModeResolverProp
1134
1145
  & OnMouseEnterProp
1135
1146
  & RenderProgramProp<T>
1147
+ & SmallestAllowedCellPxProp
1136
1148
  );
1137
1149
 
1138
1150
  /**
@@ -1275,6 +1287,7 @@ export type Props<
1275
1287
  & Partial<InitialTimestampProp>
1276
1288
  & Partial<InitialChannelIndexProp>
1277
1289
  & Partial<ProgramTextModeResolverProp>
1290
+ & Partial<SmallestAllowedCellPxProp>
1278
1291
  & OnItemPressProp<U>
1279
1292
  & Partial<OnFocusChangeProp<U>>
1280
1293
  & Partial<OnScrolledToTimestampProp>
@@ -1,56 +1 @@
1
- import { forEach, map } from '@24i/bigscreen-sdk/perf-utils/array';
2
-
3
- type PayloadOf<T> = T extends (payload: infer Payload) => any ? Payload : never;
4
-
5
- export type EventMapType = { [key: string]: (payload: any) => void };
6
-
7
- export interface IEvents<EventMap extends EventMapType> {
8
- addEventListener: <K extends keyof EventMap>(
9
- eventName: K,
10
- listener: EventMap[K],
11
- ) => void,
12
- removeEventListener: <K extends keyof EventMap>(
13
- eventName: K,
14
- listener: EventMap[K],
15
- ) => void,
16
- triggerEvent: <K extends keyof EventMap>(
17
- eventName: K,
18
- payload: PayloadOf<EventMap[K]>,
19
- ) => void,
20
- }
21
-
22
- export class EventsManager<EventMap extends EventMapType> implements IEvents<EventMap> {
23
- eventListeners: Partial<{
24
- [key in keyof EventMap]: EventMap[key][]
25
- }> = {};
26
-
27
- addEventListener = <K extends keyof EventMap>(
28
- eventName: K,
29
- listener: EventMap[K],
30
- ): void => {
31
- if (!this.eventListeners[eventName]) this.eventListeners[eventName] = [];
32
- const listeners = this.eventListeners[eventName] as EventMap[K][];
33
- listeners.push(listener);
34
- };
35
-
36
- removeEventListener = <K extends keyof EventMap>(
37
- eventName: K,
38
- listener: EventMap[K],
39
- ): void => {
40
- const listeners = this.eventListeners[eventName] as EventMap[K][] | undefined;
41
- if (!listeners) return;
42
- const index = listeners.indexOf(listener);
43
- if (index !== -1) listeners.splice(index, 1);
44
- };
45
-
46
- triggerEvent = <K extends keyof EventMap>(
47
- eventName: K,
48
- payload?: PayloadOf<EventMap[K]>,
49
- ): void => {
50
- const eventListeners = this.eventListeners[eventName] as EventMap[K][] | undefined;
51
- if (!eventListeners) return;
52
- // In case listener removes itself during listening we need loop on a copy
53
- const listeners = map(eventListeners, (l) => l);
54
- forEach(listeners, (listener) => listener(payload));
55
- };
56
- }
1
+ export * from '@24i/appstage-shared-events-manager/dist/EventsManager';
@@ -14,11 +14,13 @@ IFocusable is an interface that should be implemented by anything that can be fo
14
14
  interface IFocusable {
15
15
  focus(options?: FocusOptions): void,
16
16
  hasDom?(element: HTMLElement): boolean,
17
+ hasFocus?(): boolean,
17
18
  }
18
19
  ```
19
20
  - focus is the main function that is called when focusing component/element.
20
21
  - hasDom is optional optimization for components to help Layout components locate the currently
21
22
  focused child.
23
+ - hasFocus is optional check if the component has focus inside or is itself focused.
22
24
 
23
25
  ## Layout components
24
26
  - Vertical: Use it to create focus between elements vertically (up/down)
@@ -40,6 +42,7 @@ to the focused element and its index. Ideal place to change other elements
40
42
  - onBeforeFocusChange: Optional callback just before focus change. It receives a reference
41
43
  to the focused element and its index. Ideal place for preparing for the change
42
44
  (e.g. moving the container to fit new element in the screen)
45
+ - circular: makes focus circular, e.g. when pressing left at leftmost element focus will go to rightmost element
43
46
  - dir: Optional forceful setting of the component direction. Defaults to `'auto'` which follows
44
47
  the direction of the app.
45
48
  `'ltr'` always forces left-to-right layout,
@@ -128,6 +131,16 @@ const matrix = [
128
131
  ];
129
132
  ```
130
133
 
134
+ ## Prevent blur on long press
135
+ When the user holds a navigation key, he usually scrolls to the boundary of the layout
136
+ and then releases the key. This operation is very quick and most of the time he releases
137
+ the key too late, so the keydown event from the layout will propagate to another component
138
+ or another layout. In some cases, we don't want this behavior and for those situations and
139
+ to have better control above the layout navigation, there is a prop `preventBlurOnLongPress`.
140
+ When the user scrolls to the boundary of the layout while holding a navigation key,
141
+ he needs to release the key and press it again to propagate the event higher and focus
142
+ another component or layout.
143
+
131
144
  ## Limitations
132
145
  For the div to properly receive keydown events it needs to have set `tabIndex`. If you do not set `tabIndex` then it won't receive keydown events and those will not propagate to the Vertical/Horizontal component.
133
146
 
@@ -302,6 +315,11 @@ Method to focus between multiple focusable components. The first existing (non-n
302
315
  const focusFirstExisting = (...toFocus: Reference<IFocusable>[]) => () => void;
303
316
  ```
304
317
 
318
+ If you need to enable `preventScroll` in element focus options, wrap your reference with `preventScrollOnFocus` function like this:
319
+ ```ts
320
+ focusFirstExisting(this.navigation, preventScrollOnFocus(this.div))
321
+ ```
322
+
305
323
  ## refocusAfterHashChange
306
324
  When the hash is changed, the browser automatically blurs the currently focused element and focuses body.
307
325
  This can be problematic when the overlay component is active (development tools, modals). Focus is lost and
@@ -313,3 +331,18 @@ outside of the component and not focused.
313
331
  ```ts
314
332
  const refocusAfterHashChange = (focusWrapperOrReference: HTMLElement | Reference<HTMLElement>) => void;
315
333
  ```
334
+
335
+ ## hasFocus
336
+ Test if the element (or element in the reference) has the `activeElement` inside or optionally,
337
+ if the element itself is the `activeElement`.
338
+
339
+ ```ts
340
+ const hasFocus = (elementOrReference: HTMLElement | Reference<HTMLElement>, includeElementItself = false) => boolean;
341
+ ```
342
+
343
+ ## isFocused
344
+ Test if the element (or element in the reference) is the `activeElement`.
345
+
346
+ ```ts
347
+ const isFocused = (elementOrReference: HTMLElement | Reference<HTMLElement>) => boolean;
348
+ ```