@roku-sdk/components 0.0.0-stage → 2.19.0

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 (212) hide show
  1. package/BREAKING_CHANGES.md +84 -0
  2. package/LICENSE +21 -0
  3. package/README.md +19 -2
  4. package/core-jsx.d.ts +53 -0
  5. package/eslint.config.mjs +3 -0
  6. package/jsx.d.ts +273 -0
  7. package/package.json +85 -3
  8. package/src/__tests__/container.test.tsx +150 -0
  9. package/src/__tests__/effect-gradient-validation.test.tsx +133 -0
  10. package/src/__tests__/glyphs.test.ts +202 -0
  11. package/src/__tests__/modal-boundary-export.test.ts +12 -0
  12. package/src/__tests__/native-modal.test.tsx +224 -0
  13. package/src/__tests__/tween-release.test.tsx +125 -0
  14. package/src/__tests__/tween-stops-shape.test.tsx +165 -0
  15. package/src/__tests__/tween-without-compat.test.tsx +64 -0
  16. package/src/__tests__/tween.test.tsx +195 -0
  17. package/src/blended-busy-spinner.props.ts +37 -0
  18. package/src/blended-busy-spinner.tsx +13 -0
  19. package/src/bounding-tracker.props.ts +18 -0
  20. package/src/bounding-tracker.tsx +13 -0
  21. package/src/button-row.tsx +126 -0
  22. package/src/channel-store.props.ts +425 -0
  23. package/src/channel-store.tsx +76 -0
  24. package/src/container.tsx +130 -0
  25. package/src/core/jsx-runtime.ts +39 -0
  26. package/src/focusable-group.props.ts +8 -0
  27. package/src/focusable-group.tsx +17 -0
  28. package/src/focusable.props.ts +14 -0
  29. package/src/focusable.tsx +17 -0
  30. package/src/glyphs.ts +116 -0
  31. package/src/helpers/index.tsx +4 -0
  32. package/src/helpers/resolution-context.tsx +68 -0
  33. package/src/helpers/scale-for-device-resolution.ts +31 -0
  34. package/src/index.tsx +70 -0
  35. package/src/jsx-props.ts +87 -0
  36. package/src/kdfs.d.ts +14 -0
  37. package/src/kdfs.ts +15 -0
  38. package/src/key-handler.props.ts +33 -0
  39. package/src/key-handler.tsx +24 -0
  40. package/src/modal-dialog.props.ts +38 -0
  41. package/src/modal-dialog.tsx +41 -0
  42. package/src/retain-asset.ts +24 -0
  43. package/src/sg-intrinsics.json +1153 -0
  44. package/src/sg-nodes/__tests__/__snapshots__/font.test.tsx.snap +13 -0
  45. package/src/sg-nodes/__tests__/__snapshots__/prop-forwarding.test.tsx.snap +4409 -0
  46. package/src/sg-nodes/__tests__/core-props.test.ts +301 -0
  47. package/src/sg-nodes/__tests__/font.test.tsx +141 -0
  48. package/src/sg-nodes/__tests__/imperative-methods.test.ts +276 -0
  49. package/src/sg-nodes/__tests__/prop-forwarding.test.tsx +1049 -0
  50. package/src/sg-nodes/__tests__/solid-integration.test.tsx +719 -0
  51. package/src/sg-nodes/animated-image.props.ts +64 -0
  52. package/src/sg-nodes/animated-image.tsx +23 -0
  53. package/src/sg-nodes/animation.props.ts +292 -0
  54. package/src/sg-nodes/animation.tsx +190 -0
  55. package/src/sg-nodes/array-grid.ts +602 -0
  56. package/src/sg-nodes/audio.props.ts +302 -0
  57. package/src/sg-nodes/audio.tsx +57 -0
  58. package/src/sg-nodes/busy-spinner.props.ts +59 -0
  59. package/src/sg-nodes/busy-spinner.tsx +84 -0
  60. package/src/sg-nodes/button-group.props.ts +141 -0
  61. package/src/sg-nodes/button-group.tsx +30 -0
  62. package/src/sg-nodes/button.props.ts +119 -0
  63. package/src/sg-nodes/button.tsx +31 -0
  64. package/src/sg-nodes/check-list.props.ts +71 -0
  65. package/src/sg-nodes/check-list.tsx +55 -0
  66. package/src/sg-nodes/content-node.props.ts +1316 -0
  67. package/src/sg-nodes/content-node.tsx +153 -0
  68. package/src/sg-nodes/core-props.ts +197 -0
  69. package/src/sg-nodes/custom-keyboard.props.ts +108 -0
  70. package/src/sg-nodes/custom-keyboard.tsx +48 -0
  71. package/src/sg-nodes/dialog.props.ts +159 -0
  72. package/src/sg-nodes/dialog.tsx +36 -0
  73. package/src/sg-nodes/dynamic-key-grid.props.ts +22 -0
  74. package/src/sg-nodes/dynamic-key-grid.tsx +16 -0
  75. package/src/sg-nodes/dynamic-keyboard.props.ts +30 -0
  76. package/src/sg-nodes/dynamic-keyboard.tsx +18 -0
  77. package/src/sg-nodes/dynamic-mini-keyboard.props.ts +22 -0
  78. package/src/sg-nodes/dynamic-mini-keyboard.tsx +18 -0
  79. package/src/sg-nodes/dynamic-pinpad.props.ts +57 -0
  80. package/src/sg-nodes/dynamic-pinpad.tsx +18 -0
  81. package/src/sg-nodes/effect.props.ts +119 -0
  82. package/src/sg-nodes/effect.tsx +167 -0
  83. package/src/sg-nodes/font.props.ts +45 -0
  84. package/src/sg-nodes/font.tsx +80 -0
  85. package/src/sg-nodes/group.props.ts +105 -0
  86. package/src/sg-nodes/group.tsx +30 -0
  87. package/src/sg-nodes/label-list.props.ts +86 -0
  88. package/src/sg-nodes/label-list.tsx +64 -0
  89. package/src/sg-nodes/label.props.ts +207 -0
  90. package/src/sg-nodes/label.tsx +56 -0
  91. package/src/sg-nodes/layout-group.props.ts +69 -0
  92. package/src/sg-nodes/layout-group.tsx +75 -0
  93. package/src/sg-nodes/list-panel.props.ts +103 -0
  94. package/src/sg-nodes/list-panel.tsx +49 -0
  95. package/src/sg-nodes/markup-grid.props.ts +78 -0
  96. package/src/sg-nodes/markup-grid.tsx +38 -0
  97. package/src/sg-nodes/markup-list.props.ts +66 -0
  98. package/src/sg-nodes/markup-list.tsx +38 -0
  99. package/src/sg-nodes/mask-group.props.ts +78 -0
  100. package/src/sg-nodes/mask-group.tsx +59 -0
  101. package/src/sg-nodes/media-playback-methods.ts +20 -0
  102. package/src/sg-nodes/node.ts +77 -0
  103. package/src/sg-nodes/overhang.props.ts +169 -0
  104. package/src/sg-nodes/overhang.tsx +29 -0
  105. package/src/sg-nodes/panel-set.props.ts +71 -0
  106. package/src/sg-nodes/panel-set.tsx +53 -0
  107. package/src/sg-nodes/panel.props.ts +176 -0
  108. package/src/sg-nodes/panel.tsx +56 -0
  109. package/src/sg-nodes/poster-grid.props.ts +277 -0
  110. package/src/sg-nodes/poster-grid.tsx +45 -0
  111. package/src/sg-nodes/poster.props.ts +125 -0
  112. package/src/sg-nodes/poster.tsx +44 -0
  113. package/src/sg-nodes/radio-button-list.props.ts +59 -0
  114. package/src/sg-nodes/radio-button-list.tsx +68 -0
  115. package/src/sg-nodes/rectangle.props.ts +29 -0
  116. package/src/sg-nodes/rectangle.tsx +27 -0
  117. package/src/sg-nodes/row-list.props.ts +288 -0
  118. package/src/sg-nodes/row-list.tsx +47 -0
  119. package/src/sg-nodes/scene.props.ts +65 -0
  120. package/src/sg-nodes/scene.tsx +15 -0
  121. package/src/sg-nodes/scrollable-text.props.ts +133 -0
  122. package/src/sg-nodes/scrollable-text.tsx +64 -0
  123. package/src/sg-nodes/scrolling-label.props.ts +106 -0
  124. package/src/sg-nodes/scrolling-label.tsx +42 -0
  125. package/src/sg-nodes/simple-label.props.ts +156 -0
  126. package/src/sg-nodes/simple-label.tsx +59 -0
  127. package/src/sg-nodes/sound-effect.props.ts +130 -0
  128. package/src/sg-nodes/sound-effect.tsx +65 -0
  129. package/src/sg-nodes/standard-dialog.props.ts +520 -0
  130. package/src/sg-nodes/standard-dialog.tsx +428 -0
  131. package/src/sg-nodes/standard-keyboard-dialog.props.ts +84 -0
  132. package/src/sg-nodes/standard-keyboard-dialog.tsx +58 -0
  133. package/src/sg-nodes/standard-message-dialog.props.ts +56 -0
  134. package/src/sg-nodes/standard-message-dialog.tsx +47 -0
  135. package/src/sg-nodes/standard-pinpad-dialog.props.ts +64 -0
  136. package/src/sg-nodes/standard-pinpad-dialog.tsx +44 -0
  137. package/src/sg-nodes/standard-progress-dialog.props.ts +30 -0
  138. package/src/sg-nodes/standard-progress-dialog.tsx +40 -0
  139. package/src/sg-nodes/target-group.props.ts +278 -0
  140. package/src/sg-nodes/target-group.tsx +63 -0
  141. package/src/sg-nodes/target-list.props.ts +128 -0
  142. package/src/sg-nodes/target-list.tsx +66 -0
  143. package/src/sg-nodes/target-set.props.ts +63 -0
  144. package/src/sg-nodes/target-set.tsx +42 -0
  145. package/src/sg-nodes/time-grid.props.ts +646 -0
  146. package/src/sg-nodes/time-grid.tsx +87 -0
  147. package/src/sg-nodes/tween.props.ts +115 -0
  148. package/src/sg-nodes/types.ts +150 -0
  149. package/src/sg-nodes/video.props.ts +642 -0
  150. package/src/sg-nodes/video.tsx +75 -0
  151. package/src/sg-nodes/voice-text-edit-box.props.ts +91 -0
  152. package/src/sg-nodes/voice-text-edit-box.tsx +15 -0
  153. package/src/sg-nodes/zoom-row-list.props.ts +416 -0
  154. package/src/sg-nodes/zoom-row-list.tsx +42 -0
  155. package/src/standard-dialog-next/__tests__/standard-dialog-next.test.tsx +186 -0
  156. package/src/standard-dialog-next/index.ts +5 -0
  157. package/src/standard-dialog-next/standard-dialog-next.props.ts +80 -0
  158. package/src/standard-dialog-next/standard-dialog-next.tsx +326 -0
  159. package/src/test-helpers/tween-test-setup.ts +78 -0
  160. package/src/tween.tsx +173 -0
  161. package/src/types.ts +8 -0
  162. package/src/xml-components/blended-busy-spinner/BlendedBusySpinner.brs +13 -0
  163. package/src/xml-components/blended-busy-spinner/BlendedBusySpinner.xml +10 -0
  164. package/src/xml-components/blended-busy-spinner/BlendedBusySpinner.xml.d.ts +42 -0
  165. package/src/xml-components/bounding-tracker/BoundingTracker.brs +26 -0
  166. package/src/xml-components/bounding-tracker/BoundingTracker.xml +14 -0
  167. package/src/xml-components/bounding-tracker/BoundingTracker.xml.d.ts +42 -0
  168. package/src/xml-components/channel-store/channelStoreExt.brs +159 -0
  169. package/src/xml-components/channel-store/channelStoreExt.xml +29 -0
  170. package/src/xml-components/channel-store/channelStoreExt.xml.d.ts +57 -0
  171. package/src/xml-components/focus/focusable-group.brs +251 -0
  172. package/src/xml-components/focus/focusable-group.xml +15 -0
  173. package/src/xml-components/focus/focusable-group.xml.d.ts +42 -0
  174. package/src/xml-components/focus/focusable.xml +18 -0
  175. package/src/xml-components/focus/focusable.xml.d.ts +48 -0
  176. package/src/xml-components/keyboards/CustomAddressKDF.keyboard.json +547 -0
  177. package/src/xml-components/keyboards/CustomKeyboard.brs +322 -0
  178. package/src/xml-components/keyboards/CustomKeyboard.xml +45 -0
  179. package/src/xml-components/keyboards/CustomKeyboard.xml.d.ts +73 -0
  180. package/src/xml-components/keyboards/KeyGridExt.xml +4 -0
  181. package/src/xml-components/keyboards/KeyGridExt.xml.d.ts +37 -0
  182. package/src/xml-components/keyboards/KeyboardExt.xml +4 -0
  183. package/src/xml-components/keyboards/KeyboardExt.xml.d.ts +37 -0
  184. package/src/xml-components/keyboards/MOPPinPadCustomKDF.keyboard.json +151 -0
  185. package/src/xml-components/keyboards/MiniKeyboardExt.xml +4 -0
  186. package/src/xml-components/keyboards/MiniKeyboardExt.xml.d.ts +37 -0
  187. package/src/xml-components/keyboards/PhonePadCustomKDF.keyboard.json +42 -0
  188. package/src/xml-components/keyboards/PinPadExt.brs +102 -0
  189. package/src/xml-components/keyboards/PinPadExt.xml +17 -0
  190. package/src/xml-components/keyboards/PinPadExt.xml.d.ts +49 -0
  191. package/src/xml-components/keyboards/WifiCustomKDF.keyboard.json +1242 -0
  192. package/src/xml-components/keyhandler/KeyHandler.brs +30 -0
  193. package/src/xml-components/keyhandler/KeyHandler.xml +16 -0
  194. package/src/xml-components/keyhandler/KeyHandler.xml.d.ts +45 -0
  195. package/src/xml-components/managed-list-panel/ManagedListPanel.brs +137 -0
  196. package/src/xml-components/managed-list-panel/ManagedListPanel.xml +10 -0
  197. package/src/xml-components/managed-list-panel/ManagedListPanel.xml.d.ts +37 -0
  198. package/src/xml-components/modal/Modal.brs +105 -0
  199. package/src/xml-components/modal/Modal.xml +22 -0
  200. package/src/xml-components/modal/Modal.xml.d.ts +54 -0
  201. package/src/xml-components/modal/StandardDialogExt.xml +10 -0
  202. package/src/xml-components/modal/StandardDialogExt.xml.d.ts +37 -0
  203. package/src/xml-components/modal/StandardKeyboardDialogExt.xml +10 -0
  204. package/src/xml-components/modal/StandardKeyboardDialogExt.xml.d.ts +37 -0
  205. package/src/xml-components/modal/StandardMessageDialogExt.xml +10 -0
  206. package/src/xml-components/modal/StandardMessageDialogExt.xml.d.ts +37 -0
  207. package/src/xml-components/modal/StandardPinPadDialogExt.xml +10 -0
  208. package/src/xml-components/modal/StandardPinPadDialogExt.xml.d.ts +37 -0
  209. package/src/xml-components/modal/StandardProgressDialogExt.xml +10 -0
  210. package/src/xml-components/modal/StandardProgressDialogExt.xml.d.ts +37 -0
  211. package/src/xml-components/modal/tests/Modal.test.brs +195 -0
  212. package/tsconfig.json +10 -0
@@ -0,0 +1,75 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import { registerImperativeMethods } from "@roku-sdk/solid";
5
+
6
+ import type { IBifDisplayProps, IProgressBarProps, ITrickPlayBarProps, IVideoProps } from "./video.props";
7
+ export { VideoSeekMode, StreamingSegmentHdrMode, StreamingSegmentType, GlobalCaptionMode } from "./video.props";
8
+
9
+ export type {
10
+ IPlayStartInfo,
11
+ ILicenseStatus,
12
+ VideoControl,
13
+ VideoState,
14
+ VideoErrorInfo,
15
+ IDecoderStats,
16
+ IPlaybackActionButton,
17
+ SubtitleSelectionPreferenceRule,
18
+ ISubtitleSelectionPreferences,
19
+ AudioSelectionPreferenceRule,
20
+ IAudioSelectionPreferences,
21
+ IVideoPlaybackProps,
22
+ IPositionInfo,
23
+ IStreamingSegmentInfo,
24
+ IDownloadedSegmentInfo,
25
+ ITrickPlayProps,
26
+ IVideoUiProps,
27
+ IVideoAudioTrack,
28
+ IVideoSubtitleTrack,
29
+ IVideoCaptionProps,
30
+ IVideoAudioProps,
31
+ IVideoMiscProps,
32
+ IVideoProps,
33
+ VideoRef,
34
+ IBifDisplayProps,
35
+ ITrickPlayBarProps,
36
+ IProgressBarProps
37
+ } from "./video.props";
38
+
39
+ import { mediaPlaybackMethods } from "./media-playback-methods";
40
+ import { Component } from "./types";
41
+
42
+ export { DownloadedSegmentHdrMode } from "./video.props";
43
+
44
+ registerImperativeMethods("video", mediaPlaybackMethods);
45
+
46
+ /**
47
+ * Video provides controlled playback of live or VOD content with optional built-in UI, trick play,
48
+ * and captions.
49
+ *
50
+ * @see {@link https://developer.roku.com/dev/docs/video}
51
+ *
52
+ * @example
53
+ * <video
54
+ * width={1280}
55
+ * height={720}
56
+ * content={<VideoContentNode url={url} />}
57
+ * control="play"
58
+ * onState={state => console.log(state)}
59
+ * />
60
+ */
61
+ export const Video: Component<IVideoProps> = props => {
62
+ return <video {...props}></video>;
63
+ };
64
+
65
+ export const BifDisplay: Component<IBifDisplayProps> = props => {
66
+ return <bifDisplay {...props}></bifDisplay>;
67
+ };
68
+
69
+ export const TrickPlayBar: Component<ITrickPlayBarProps> = props => {
70
+ return <trickPlayBar {...props}></trickPlayBar>;
71
+ };
72
+
73
+ export const ProgressBar: Component<IProgressBarProps> = props => {
74
+ return <progressBar {...props}></progressBar>;
75
+ };
@@ -0,0 +1,91 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { IGroupProps } from "./group.props";
5
+ import type { EventHandler } from "./types";
6
+
7
+ /**
8
+ * Properties for the legacy TextEditBox fields exposed by {@link VoiceTextEditBox}.
9
+ *
10
+ * @see {@link https://developer.roku.com/dev/docs/texteditbox}
11
+ */
12
+ export interface ITextEditBoxProps extends IGroupProps {
13
+ /** Current text displayed in the edit box. */
14
+ text: string;
15
+ /** Placeholder text shown when the edit box is empty. */
16
+ hintText: string;
17
+ /** Maximum number of characters that may be entered. */
18
+ maxTextLength: number;
19
+ /** Zero-based cursor position within the text string. */
20
+ cursorPosition: number;
21
+ /** When true, pressing Down clears the text field. */
22
+ clearOnDownKey: boolean;
23
+ /** When true, the edit box accepts focus and key input. */
24
+ active: boolean;
25
+ /** When true, entered characters are masked (for passwords/PINs). */
26
+ secureMode: boolean;
27
+ /** Color of the entered text. */
28
+ textColor: string | number;
29
+ /** Color of the hint text. */
30
+ hintTextColor: string | number;
31
+ /** Width of the voice-enabled text box. */
32
+ voiceTextBoxWidth: number;
33
+ /** Background image URI for the text box. */
34
+ backgroundUri: string;
35
+ /** When true, truncates long text with a leading ellipsis. */
36
+ leadingEllipsis: boolean;
37
+ }
38
+
39
+ /**
40
+ * Properties for the {@link VoiceTextEditBox} component.
41
+ *
42
+ * VoiceTextEditBox is similar to the legacy TextEditBox node but adds voice entry
43
+ * functionality. Only one voice-enabled VoiceTextEditBox may be on screen at a time.
44
+ *
45
+ * @see {@link https://developer.roku.com/dev/docs/voice-text-edit-box}
46
+ *
47
+ * @example
48
+ * ```tsx
49
+ * <VoiceTextEditBox
50
+ * id="search-input"
51
+ * text={query()}
52
+ * hintText="Search…"
53
+ * maxTextLength={64}
54
+ * cursorPosition={query().length}
55
+ * clearOnDownKey={false}
56
+ * active
57
+ * secureMode={false}
58
+ * textColor="0xFFFFFFFF"
59
+ * hintTextColor="0x888888FF"
60
+ * voiceTextBoxWidth={800}
61
+ * backgroundUri=""
62
+ * leadingEllipsis={false}
63
+ * voiceEnabled
64
+ * voiceEntryType="generic"
65
+ * onText={setQuery}
66
+ * />
67
+ * ```
68
+ */
69
+ export interface IVoiceTextEditBoxProps extends ITextEditBoxProps {
70
+ /**
71
+ * Enables voice entry for the text box (mic icon and voice hints).
72
+ * @default false
73
+ */
74
+ voiceEntryType?: string;
75
+ /** When true, voice entry is enabled. */
76
+ voiceEnabled?: boolean;
77
+ /**
78
+ * Maximum width of the voice hint tooltip.
79
+ * @default FHD: 321, HD: 214
80
+ */
81
+ voiceToolTipWidth?: number;
82
+ /** Fired when dictation starts or stops. */
83
+ onIsDictating?: EventHandler<boolean>;
84
+ /**
85
+ * Regex filter restricting characters entered via dictation.
86
+ * Write-only on the native node.
87
+ */
88
+ voiceInputRegexFilter?: string;
89
+ /** Fired when the text value changes. */
90
+ onText?: EventHandler<string>;
91
+ }
@@ -0,0 +1,15 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import { Component } from "./types";
5
+ import type { IVoiceTextEditBoxProps } from "./voice-text-edit-box.props";
6
+ export type { ITextEditBoxProps, IVoiceTextEditBoxProps } from "./voice-text-edit-box.props";
7
+
8
+ /**
9
+ * Voice-enabled text edit box for standalone text entry (not inside a dialog).
10
+ *
11
+ * @see {@link https://developer.roku.com/dev/docs/voice-text-edit-box}
12
+ */
13
+ export const VoiceTextEditBox: Component<IVoiceTextEditBoxProps> = props => {
14
+ return <voiceTextEditBox {...props}></voiceTextEditBox>;
15
+ };
@@ -0,0 +1,416 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { IGroupProps } from "./group.props";
5
+ import type { RowItemPosition, RowListItemEventHandler } from "./row-list.props";
6
+ import type { EventHandler, FontValue, JSX, Rect2D, Uri, Vector2D } from "./types";
7
+
8
+ /**
9
+ * Controls whether rows above the focus row remain zoomed or unzoom as they scroll.
10
+ *
11
+ * - `focusIsAtTop`: when itemClippingRect top is 0, rows remain zoomed as they enter/exit from above
12
+ * - `never`: rows zoom up/down as they enter/exit the focus region from above
13
+ * - `always`: rows always remain zoomed as they enter/exit from above
14
+ *
15
+ * @default "focusIsAtTop"
16
+ */
17
+ export type RemainZoomedAboveFocus = "focusIsAtTop" | "never" | "always";
18
+
19
+ /**
20
+ * Controls whether rows above the focus row fade in/out as they scroll.
21
+ *
22
+ * - `focusIsAtTop`: when itemClippingRect top is 0, rows fade as they enter/exit from above
23
+ * - `never`: rows do not fade as they enter/exit from above
24
+ * - `always`: rows always fade as they enter/exit from above
25
+ *
26
+ * @default "focusIsAtTop"
27
+ */
28
+ export type FadeOutAboveFocus = "focusIsAtTop" | "never" | "always";
29
+
30
+ /**
31
+ * Properties for the ZoomRowList node.
32
+ *
33
+ * ZoomRowList allows a row of the Row-Row Grid to smoothly zoom up to a larger size when that row
34
+ * has focus. Rows are capable of gaining focus while scrolling and smoothly zooming by the specified
35
+ * amount. The amount to zoom can be specified on a per-row basis.
36
+ *
37
+ * ZoomRowList extends Group and uses the same data model as RowList: a root ContentNode with child
38
+ * ContentNodes for each row, each containing child ContentNodes for each item.
39
+ *
40
+ * @see {@link https://developer.roku.com/dev/docs/zoomrowlist}
41
+ *
42
+ * @example
43
+ * ```tsx
44
+ * import "./compiled-components/MyRowItem.xml";
45
+ *
46
+ * <ZoomRowList
47
+ * itemComponentName="MyRowItem"
48
+ * rowWidth={1920}
49
+ * rowHeight={[120, 120, 120]}
50
+ * rowZoomHeight={[200, 200, 200]}
51
+ * rowItemHeight={[100, 100, 100]}
52
+ * rowItemZoomHeight={[180, 180, 180]}
53
+ * rowItemAspectRatio={[1.777]}
54
+ * content={listContent}
55
+ * onRowItemFocused={([row, col]) => setFocus(row, col)}
56
+ * onRowItemSelected={([row, col]) => navigate(row, col)}
57
+ * />
58
+ * ```
59
+ */
60
+ export interface IZoomRowListProps extends IGroupProps {
61
+ // ─────────────────────────────────────────────────────────────────────────
62
+ // Content
63
+ // ─────────────────────────────────────────────────────────────────────────
64
+
65
+ /**
66
+ * Specifies the content for the ZoomRowList.
67
+ *
68
+ * The root ContentNode should have one child per row. Each row child should
69
+ * have one child ContentNode per item in that row.
70
+ *
71
+ * @see {@link https://developer.roku.com/dev/docs/zoomrowlist#zoomrowlist-data-model}
72
+ */
73
+ content: JSX.Element;
74
+
75
+ /**
76
+ * Specifies the name of the compiled component used to render each row item.
77
+ *
78
+ * Register the compiled component by importing its XML file before use.
79
+ * The component may define: width, height, index, rowIndex, itemHasFocus,
80
+ * rowHasFocus, rowListHasFocus, itemContent, focusPercent, rowFocusPercent, rowHeightPercent.
81
+ *
82
+ * @example "MyRowItem"
83
+ */
84
+ itemComponentName?: string;
85
+
86
+ /**
87
+ * Specifies the name of an XML component to decorate each row.
88
+ * An instance is created for each visible row.
89
+ *
90
+ * @example "MyRowDecoration"
91
+ */
92
+ rowDecorationComponentName?: string[];
93
+
94
+ // ─────────────────────────────────────────────────────────────────────────
95
+ // Layout
96
+ // ─────────────────────────────────────────────────────────────────────────
97
+
98
+ /**
99
+ * Specifies the maximum width of items in each row before items wrap.
100
+ * Also used for Row Counter positioning.
101
+ *
102
+ * @default 0
103
+ */
104
+ rowWidth?: number;
105
+
106
+ /**
107
+ * Specifies the height of each ZoomRowItem when the row is not zoomed.
108
+ * At least one value must be specified.
109
+ *
110
+ * @example [120, 120, 120]
111
+ */
112
+ rowHeight?: number[];
113
+
114
+ /**
115
+ * Specifies the height of each ZoomRowItem when the row is zoomed.
116
+ * If not specified, rows do not zoom.
117
+ *
118
+ * @example [200, 200, 200]
119
+ */
120
+ rowZoomHeight?: number[];
121
+
122
+ /**
123
+ * Specifies the spacing between rows. Not scaled by zoom.
124
+ *
125
+ * @default 0
126
+ */
127
+ spacingAfterRow?: number;
128
+
129
+ /**
130
+ * Specifies a clipping region for the ZoomRowItem renders.
131
+ * For best performance, set to match what's visible onscreen.
132
+ *
133
+ * @default [0, 0, 0, 0]
134
+ */
135
+ itemClippingRect?: Rect2D;
136
+
137
+ // ─────────────────────────────────────────────────────────────────────────
138
+ // Row Item Sizing
139
+ // ─────────────────────────────────────────────────────────────────────────
140
+
141
+ /**
142
+ * Vertical position of the Row relative to the top of its ZoomRowItem when unfocused.
143
+ *
144
+ * @example [0, 0, 0]
145
+ */
146
+ rowItemYOffset?: number[];
147
+
148
+ /**
149
+ * Vertical position of the Row relative to the top of its ZoomRowItem when focused (zoomed).
150
+ *
151
+ * @example [10, 10, 10]
152
+ */
153
+ rowItemZoomYOffset?: number[];
154
+
155
+ /**
156
+ * Height of each Item in a Row when the row is unfocused.
157
+ *
158
+ * @example [100, 100, 100]
159
+ */
160
+ rowItemHeight?: number[];
161
+
162
+ /**
163
+ * Height of each Item in a Row when the row is focused (zoomed).
164
+ *
165
+ * @example [180, 180, 180]
166
+ */
167
+ rowItemZoomHeight?: number[];
168
+
169
+ /**
170
+ * Aspect ratio of Items in each Row (width/height).
171
+ * Used to compute item width from interpolated height.
172
+ * E.g. 16:9 = 1.7777778.
173
+ *
174
+ * @example [1.7777778]
175
+ */
176
+ rowItemAspectRatio?: number[];
177
+
178
+ /**
179
+ * Horizontal spacing between Items in each Row.
180
+ * Scales with zoom as the row gains focus.
181
+ *
182
+ * @example [20, 20, 20]
183
+ */
184
+ spacingAfterRowItem?: number[];
185
+
186
+ /**
187
+ * If true, use rowItemAspectRatio for all items. If false, use aspectRatio
188
+ * from each item's ContentNode when available.
189
+ *
190
+ * @example [true, true, true]
191
+ */
192
+ useDefaultAspectRatio?: boolean[];
193
+
194
+ // ─────────────────────────────────────────────────────────────────────────
195
+ // Row Title and Counter
196
+ // ─────────────────────────────────────────────────────────────────────────
197
+
198
+ /**
199
+ * Specifies whether the row title is displayed for each row.
200
+ *
201
+ * @example [true, true, true]
202
+ */
203
+ showRowTitle?: boolean[];
204
+
205
+ /**
206
+ * Offset of the Row Title for each row. [x, y] from left edge and top.
207
+ *
208
+ * @example [[0, 0], [0, 10]]
209
+ */
210
+ rowTitleOffset?: Vector2D[];
211
+
212
+ /**
213
+ * Font for the Row Title text.
214
+ */
215
+ rowTitleFont?: FontValue;
216
+
217
+ /**
218
+ * Color of the Row Title text for each row.
219
+ *
220
+ * @example ["0xffffffff"]
221
+ */
222
+ rowTitleColor?: string[];
223
+
224
+ /**
225
+ * Specifies whether each row's Row Counter is displayed.
226
+ *
227
+ * @example [true, true, true]
228
+ */
229
+ showRowCounter?: boolean[];
230
+
231
+ /**
232
+ * Offset of the Row Counter for each row. X is right edge position (right-aligned).
233
+ *
234
+ * @example [[1920, 0]]
235
+ */
236
+ rowCounterOffset?: Vector2D[];
237
+
238
+ /**
239
+ * Font for the Row Counter text.
240
+ */
241
+ rowCounterFont?: FontValue;
242
+
243
+ /**
244
+ * Color of the Row Counter text for each row.
245
+ *
246
+ * @example ["0xffffffff"]
247
+ */
248
+ rowCounterColor?: string[];
249
+
250
+ /**
251
+ * When true, Row Counter is shown for all rows. When false, not shown for
252
+ * rows where total zoomed width of items is less than rowWidth.
253
+ *
254
+ * @default true
255
+ */
256
+ showRowCounterForShortRows?: boolean;
257
+
258
+ // ─────────────────────────────────────────────────────────────────────────
259
+ // Focus Feedback
260
+ // ─────────────────────────────────────────────────────────────────────────
261
+
262
+ /**
263
+ * If true, the focus feedback indicator is drawn.
264
+ *
265
+ * @default true
266
+ */
267
+ drawFocusFeedback?: boolean;
268
+
269
+ /**
270
+ * If true, the focus feedback indicator is drawn on top of the items.
271
+ *
272
+ * @default true
273
+ */
274
+ drawFocusFeedbackOnTop?: boolean;
275
+
276
+ /**
277
+ * If true, focus indicator fades out during long-press scrolling.
278
+ *
279
+ * @default true
280
+ */
281
+ fadeFocusFeedbackWhenLongPressScrolling?: boolean;
282
+
283
+ /**
284
+ * Bitmap file for the focus feedback indicator.
285
+ * Use 9-patch for expandable regions and margins.
286
+ */
287
+ focusBitmapUri?: Uri;
288
+
289
+ /**
290
+ * Blend color for the focus bitmap.
291
+ *
292
+ * @default "0xFFFFFFFF"
293
+ */
294
+ focusBitmapBlendColor?: string;
295
+
296
+ // ─────────────────────────────────────────────────────────────────────────
297
+ // Wrap Divider
298
+ // ─────────────────────────────────────────────────────────────────────────
299
+
300
+ /**
301
+ * If true, items wrap from bottom to top.
302
+ *
303
+ * @default true
304
+ */
305
+ wrap?: boolean;
306
+
307
+ /**
308
+ * Bitmap file for the wrap divider between last and first items.
309
+ */
310
+ wrapDividerBitmapUri?: Uri;
311
+
312
+ /**
313
+ * Blend color for the wrap divider bitmap.
314
+ *
315
+ * @default "0xFFFFFFFF"
316
+ */
317
+ wrapDividerBitmapBlendColor?: string;
318
+
319
+ /**
320
+ * Height of the wrap divider bitmap.
321
+ *
322
+ * @default 0
323
+ */
324
+ wrapDividerHeight?: number;
325
+
326
+ /**
327
+ * Width of the wrap divider bitmap. Defaults to rowWidth if not specified.
328
+ *
329
+ * @default 0
330
+ */
331
+ wrapDividerWidth?: number;
332
+
333
+ /**
334
+ * Offset to adjust the wrap divider position from its default.
335
+ *
336
+ * @default [0, 0]
337
+ */
338
+ wrapDividerOffset?: Vector2D;
339
+
340
+ // ─────────────────────────────────────────────────────────────────────────
341
+ // Zoom Behavior
342
+ // ─────────────────────────────────────────────────────────────────────────
343
+
344
+ /**
345
+ * Controls whether rows above the focus row remain zoomed as they scroll.
346
+ *
347
+ * @default "focusIsAtTop"
348
+ */
349
+ remainZoomedAboveFocus?: RemainZoomedAboveFocus;
350
+
351
+ /**
352
+ * Controls whether rows above the focus row fade in/out as they scroll.
353
+ *
354
+ * @default "focusIsAtTop"
355
+ */
356
+ fadeOutAboveFocus?: FadeOutAboveFocus;
357
+
358
+ // ─────────────────────────────────────────────────────────────────────────
359
+ // Navigation
360
+ // ─────────────────────────────────────────────────────────────────────────
361
+
362
+ /**
363
+ * When set to a valid row index, immediately moves focus to that row.
364
+ *
365
+ * @see {@link https://developer.roku.com/dev/docs/zoomrowlist}
366
+ */
367
+ jumpToRow?: number;
368
+
369
+ /**
370
+ * When set to a valid [rowIndex, itemIndex], immediately moves focus to that item.
371
+ *
372
+ * @example [2, 0]
373
+ */
374
+ jumpToRowItem?: RowItemPosition;
375
+
376
+ /**
377
+ * When set to a valid row index, scrolls to bring that row into focus.
378
+ *
379
+ * @see {@link https://developer.roku.com/dev/docs/zoomrowlist}
380
+ */
381
+ animateToRow?: number;
382
+
383
+ // ─────────────────────────────────────────────────────────────────────────
384
+ // Events
385
+ // ─────────────────────────────────────────────────────────────────────────
386
+
387
+ /**
388
+ * Fired when a row item is selected (OK pressed).
389
+ * Receives [rowIndex, itemIndex] of the selected item.
390
+ */
391
+ onRowItemSelected?: RowListItemEventHandler;
392
+
393
+ /**
394
+ * Fired when a row item gains focus.
395
+ * Receives [rowIndex, itemIndex] of the newly focused item.
396
+ */
397
+ onRowItemFocused?: RowListItemEventHandler;
398
+
399
+ /**
400
+ * Fired when a row is selected.
401
+ * Receives the index of the selected row.
402
+ */
403
+ onRowSelected?: EventHandler<number>;
404
+
405
+ /**
406
+ * Fired when a row gains focus.
407
+ * Receives the index of the focused row.
408
+ */
409
+ onRowFocused?: EventHandler<number>;
410
+
411
+ /**
412
+ * Fired when a row loses focus.
413
+ * Receives the index of the unfocused row.
414
+ */
415
+ onRowUnfocused?: EventHandler<number>;
416
+ }
@@ -0,0 +1,42 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import { Component } from "./types";
5
+ import type { IZoomRowListProps } from "./zoom-row-list.props";
6
+ export type { RemainZoomedAboveFocus, FadeOutAboveFocus, IZoomRowListProps } from "./zoom-row-list.props";
7
+
8
+ // ─────────────────────────────────────────────────────────────────────────────
9
+ // ZoomRowList Properties
10
+ // ─────────────────────────────────────────────────────────────────────────────
11
+
12
+ // Re-export for consumers
13
+ export type { RowItemPosition, RowListItemEventHandler } from "./row-list";
14
+
15
+ /**
16
+ * ZoomRowList displays a vertically scrolling list of rows where the focused row
17
+ * smoothly zooms to a larger size. Each row scrolls horizontally through its items.
18
+ * Item rendering is delegated to compiled components specified by itemComponentName.
19
+ *
20
+ * @see {@link https://developer.roku.com/dev/docs/zoomrowlist}
21
+ *
22
+ * @example
23
+ * ```tsx
24
+ * import "./compiled-components/MyRowItem.xml";
25
+ *
26
+ * <zoomRowList
27
+ * itemComponentName="MyRowItem"
28
+ * rowWidth={1920}
29
+ * rowHeight={[120, 120, 120]}
30
+ * rowZoomHeight={[200, 200, 200]}
31
+ * rowItemHeight={[100, 100, 100]}
32
+ * rowItemZoomHeight={[180, 180, 180]}
33
+ * rowItemAspectRatio={[1.777]}
34
+ * content={listContent}
35
+ * onRowItemFocused={([row, col]) => setFocus(row, col)}
36
+ * onRowItemSelected={([row, col]) => navigate(row, col)}
37
+ * />
38
+ * ```
39
+ */
40
+ export const ZoomRowList: Component<IZoomRowListProps> = props => {
41
+ return <zoomRowList {...props}></zoomRowList>;
42
+ };