@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 { JSX } from "@roku-sdk/solid";
5
+
6
+ import type { ILayoutGroupProps } from "./layout-group.props";
7
+ export type { ILayoutGroupProps } from "./layout-group.props";
8
+
9
+ // Re-export types for convenience
10
+ export type { LayoutGroupHorizAlign, LayoutDirection, LayoutGroupVertAlign } from "./types";
11
+
12
+ /**
13
+ * A container node that automatically positions its child nodes in either
14
+ * a horizontal row or vertical column layout with configurable alignment
15
+ * and spacing.
16
+ *
17
+ * LayoutGroup simplifies the task of positioning nodes by automatically
18
+ * calculating and applying the proper translation to each child node
19
+ * based on the `layoutDirection`, alignment settings, and `itemSpacings`.
20
+ *
21
+ * **Alignment and Translation**:
22
+ * The `horizAlignment` and `vertAlignment` properties align children relative
23
+ * to the LayoutGroup's `translation` point (default `[0, 0]`). To center
24
+ * the LayoutGroup and its content on screen, you must set the `translation`
25
+ * to the desired center point.
26
+ *
27
+ * For FHD (1920×1080) resolution:
28
+ * - Horizontal center: `1920 / 2 = 960`
29
+ * - Vertical center: `1080 / 2 = 540`
30
+ *
31
+ * @see https://developer.roku.com/dev/docs/layoutgroup
32
+ *
33
+ * @example
34
+ * // Vertical layout with left-aligned children (default)
35
+ * <layoutGroup
36
+ * layoutDirection="vert"
37
+ * itemSpacings={[20, 20, 20]}
38
+ * >
39
+ * <label text="Item 1" />
40
+ * <label text="Item 2" />
41
+ * <label text="Item 3" />
42
+ * </layoutGroup>
43
+ *
44
+ * @example
45
+ * // Center a vertical layout on screen (FHD 1920×1080)
46
+ * // translation must be set to screen center for alignment to work as expected
47
+ * <layoutGroup
48
+ * translation={[960, 540]}
49
+ * layoutDirection="vert"
50
+ * horizAlignment="center"
51
+ * vertAlignment="center"
52
+ * itemSpacings={[20, 20]}
53
+ * >
54
+ * <label text="Centered Item 1" />
55
+ * <label text="Centered Item 2" />
56
+ * <label text="Centered Item 3" />
57
+ * </layoutGroup>
58
+ *
59
+ * @example
60
+ * // Horizontal layout centered at bottom of screen (FHD)
61
+ * <layoutGroup
62
+ * translation={[960, 980]}
63
+ * layoutDirection="horiz"
64
+ * horizAlignment="center"
65
+ * vertAlignment="bottom"
66
+ * itemSpacings={[30, 30]}
67
+ * >
68
+ * <poster width={100} height={100} />
69
+ * <poster width={100} height={100} />
70
+ * <poster width={100} height={100} />
71
+ * </layoutGroup>
72
+ */
73
+ export function LayoutGroup(props: ILayoutGroupProps): JSX.Element {
74
+ return <layoutGroup {...props}></layoutGroup>;
75
+ }
@@ -0,0 +1,103 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { EventHandler, JSX } from "../types";
5
+ import type { IPanelProps } from "./panel.props";
6
+
7
+ /**
8
+ * Properties for the ListPanel component.
9
+ *
10
+ * ListPanel extends Panel to add a list of items that can be used to navigate
11
+ * to other panels using the Roku Sliding Panels pattern. The list can be a
12
+ * LabelList or MarkupList node, and supports the "Create Next Panel" mechanism
13
+ * for dynamic panel creation.
14
+ *
15
+ * @see {@link https://developer.roku.com/dev/docs/listpanel | Roku ListPanel Documentation}
16
+ */
17
+ export interface IListPanelProps extends IPanelProps {
18
+ /**
19
+ * A Label node to be displayed just above the upper-left corner of the list.
20
+ * Typically used to show a title or category name.
21
+ *
22
+ * @default Label node
23
+ */
24
+ leftLabel?: JSX.Element;
25
+
26
+ /**
27
+ * A Label node to be displayed just above the upper-right corner of the list.
28
+ * Typically used to show "N of M" item count information.
29
+ *
30
+ * @default Label node
31
+ */
32
+ rightLabel?: JSX.Element;
33
+
34
+ /**
35
+ * If set to true and the list is a MarkupList with sections, the section
36
+ * title for the currently focused section will be displayed as the `leftLabel`.
37
+ *
38
+ * @default false
39
+ */
40
+ showSectionLabels?: boolean;
41
+
42
+ /**
43
+ * Fired when the "Create Next Panel" mechanism is triggered. The event value
44
+ * contains the index of the list item that triggered the panel creation.
45
+ *
46
+ * This is the READ_ONLY `createNextPanelIndex` field from the SceneGraph ListPanel,
47
+ * exposed as an event handler for reactive usage.
48
+ *
49
+ * @see {@link https://developer.roku.com/dev/docs/listpanel#createNextPanelIndex | createNextPanelIndex Field}
50
+ */
51
+ onCreateNextPanelIndex?: EventHandler<number>;
52
+
53
+ /**
54
+ * A Panel node to be added to the parent PanelSet as the next panel.
55
+ * Setting this field adds the panel to the right of the current ListPanel.
56
+ *
57
+ * When using the managed `ListPanel` component, children extending Panel
58
+ * are automatically assigned to this field.
59
+ *
60
+ * @default false
61
+ */
62
+ nextPanel?: JSX.Element;
63
+
64
+ /**
65
+ * Controls whether the "Create Next Panel" mechanism is enabled.
66
+ * When true, navigating to a list item triggers the `onCreateNextPanelIndex` event.
67
+ * Set to false to disable dynamic panel creation.
68
+ *
69
+ * @default true
70
+ */
71
+ createNextPanelOnItemFocus?: boolean;
72
+ }
73
+
74
+ /**
75
+ * Properties for the raw `<listPanel>` SceneGraph element.
76
+ *
77
+ * These are the {@link IListPanelProps} plus the `list` and `nextPanel` node fields, which the
78
+ * managed `ListPanel` component fills in from its children. They type the lower-case
79
+ * `listPanel` JSX intrinsic and the generated SceneGraph declarations. Prefer the managed
80
+ * `ListPanel` component; use the raw element only when you set `list` and `nextPanel` yourself.
81
+ */
82
+ export interface IFullPanelProps extends IListPanelProps {
83
+ /**
84
+ * A LabelList or MarkupList node to be displayed in the ListPanel.
85
+ * The list provides the navigation items for the panel.
86
+ *
87
+ * When using the managed `ListPanel` component, children extending ArrayGrid
88
+ * are automatically assigned to this field.
89
+ *
90
+ * @default null
91
+ */
92
+ list?: JSX.Element;
93
+ /**
94
+ * A Panel node to be added to the parent PanelSet as the next panel.
95
+ * Setting this field adds the panel to the right of the current ListPanel.
96
+ *
97
+ * When using the managed `ListPanel` component, children extending Panel
98
+ * are automatically assigned to this field.
99
+ *
100
+ * @default false
101
+ */
102
+ nextPanel?: JSX.Element;
103
+ }
@@ -0,0 +1,49 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import { retainAsset } from "../retain-asset";
5
+ import { Component } from "../types";
6
+ import ManagedListPanelXML from "../xml-components/managed-list-panel/ManagedListPanel.xml";
7
+ import type { IListPanelProps } from "./list-panel.props";
8
+ export type { IListPanelProps, IFullPanelProps } from "./list-panel.props";
9
+
10
+ /**
11
+ * A panel component that displays a navigable list of items for the Roku
12
+ * Sliding Panels interface pattern.
13
+ *
14
+ * The `ListPanel` component creates a `managedListPanel` SceneGraph component
15
+ * that automatically handles `list` and `nextPanel` properties internally:
16
+ * - Children extending `ArrayGrid` (LabelList, MarkupList) are automatically assigned to `list`
17
+ * - Children extending `Panel` are automatically assigned to `nextPanel`
18
+ *
19
+ * Declare the list child before the panel child. The panel is matched to the row it was
20
+ * built for by consulting the list, so a panel declared first cannot be attributed to a row.
21
+ *
22
+ * While an asynchronously supplied `nextPanel` is still the previous row's, `ListPanel`
23
+ * transiently overrides {@link IFullPanelProps.selectButtonMovesPanelForward} to stop the
24
+ * platform opening the stale panel, restoring it once the correct panel arrives.
25
+ *
26
+ * This managed behavior simplifies the common pattern of defining a list and
27
+ * its associated next panel as JSX children rather than explicit property assignments.
28
+ *
29
+ * @see {@link https://developer.roku.com/dev/docs/listpanel | Roku ListPanel Documentation}
30
+ * @see **ListPanel, GridPanel Best Practices** at the internal RSG 2.0 SDK documentation (knowledge-base/list-grid-panel-best-practice.md)
31
+ *
32
+ * @example
33
+ * ```tsx
34
+ * import { ListPanel } from "@roku-sdk/components";
35
+ *
36
+ * // Using managed child assignment
37
+ * <ListPanel
38
+ * showSectionLabels={true}
39
+ * onCreateNextPanelIndex={(index) => console.log(`Selected item: ${index}`)}
40
+ * >
41
+ * <labelList content={items} /> // Automatically becomes list
42
+ * <DetailPanel /> // Automatically becomes nextPanel
43
+ * </ListPanel>
44
+ * ```
45
+ */
46
+ export const ListPanel: Component<IListPanelProps> = props => {
47
+ retainAsset(ManagedListPanelXML);
48
+ return <managedListPanel {...props} />;
49
+ };
@@ -0,0 +1,78 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { IArrayGridProps } from "./array-grid";
5
+ import type { JSX, Uri } from "./types";
6
+
7
+ /**
8
+ * Properties for the MarkupGrid node.
9
+ *
10
+ * MarkupGrid is a generic grid class that displays a set of items arranged in a
11
+ * 2D grid. The content of each grid item is an instance of an XML component
12
+ * specified by the `itemComponentName` field.
13
+ *
14
+ * The number of columns in the MarkupGrid is fixed and the number of rows varies
15
+ * as items fill from left to right, then top to bottom. Layouts range from simple
16
+ * uniform item sizes to complex multi-row/column spanning with `fixedLayout`.
17
+ *
18
+ * Grid items may be organized into sections demarcated by labelled horizontal
19
+ * divider lines between sections.
20
+ *
21
+ * @see {@link https://developer.roku.com/dev/docs/markupgrid}
22
+ *
23
+ * @example Basic MarkupGrid
24
+ * ```tsx
25
+ * <MarkupGrid
26
+ * itemComponentName="SimpleGridItem"
27
+ * itemSize={[240, 135]}
28
+ * numColumns={4}
29
+ * content={
30
+ * <contentNode>
31
+ * <contentNode HDPOSTERURL="pkg:/images/item1.jpg" title="Item 1" />
32
+ * <contentNode HDPOSTERURL="pkg:/images/item2.jpg" title="Item 2" />
33
+ * </contentNode>
34
+ * }
35
+ * onItemSelected={(index) => console.log(`Selected: ${index}`)}
36
+ * />
37
+ * ```
38
+ */
39
+ export interface IMarkupGridProps extends IArrayGridProps {
40
+ /**
41
+ * Specifies the name of the compiled component used to render each grid item.
42
+ *
43
+ * Register the compiled component by importing its XML file before use:
44
+ * ```ts
45
+ * import "./compiled-components/MyGridItem.xml";
46
+ * ```
47
+ *
48
+ * The compiled component may define interface fields that MarkupGrid will
49
+ * automatically update: `width`, `height`, `index`, `itemContent`,
50
+ * `focusPercent`, and `itemHasFocus`.
51
+ *
52
+ * @example "MyGridItem"
53
+ * @see {@link https://developer.roku.com/dev/docs/markupgrid | MarkupGrid itemComponentName}
54
+ */
55
+ itemComponentName: string;
56
+
57
+ /**
58
+ * Specifies the content for the grid.
59
+ *
60
+ * Should be a single root `ContentNode` with one child `ContentNode` per item.
61
+ * If the data contains section markers (`CONTENTTYPE="SECTION"`), section dividers
62
+ * will be drawn between each section.
63
+ *
64
+ * @see {@link https://developer.roku.com/dev/docs/markupgrid#data-bindings | Data bindings}
65
+ */
66
+ content: JSX.Element;
67
+
68
+ /**
69
+ * Specifies the bitmap file to use to suggest where images would appear for
70
+ * empty grids and empty sections of grids.
71
+ *
72
+ * Only set this field to specify a custom bitmap that differs in appearance
73
+ * from the default bitmap.
74
+ *
75
+ * @example "pkg:/images/image-well.png"
76
+ */
77
+ imageWellBitmapUri?: Uri;
78
+ }
@@ -0,0 +1,38 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { IMarkupGridProps } from "./markup-grid.props";
5
+ import { Component } from "./types";
6
+ export type { IMarkupGridProps } from "./markup-grid.props";
7
+
8
+ // ─────────────────────────────────────────────────────────────────────────────
9
+ // MarkupGrid Properties
10
+ // ─────────────────────────────────────────────────────────────────────────────
11
+
12
+ /**
13
+ * MarkupGrid is a generic grid class that can be used to display a set of items
14
+ * arranged in a 2D grid. The content of each grid item is an instance of an XML
15
+ * component specified by the `itemComponentName` field.
16
+ *
17
+ * The grid supports flexible layouts: simple uniform items, rows/columns with
18
+ * varying heights/widths, and fixed multi-cell spanning items. Items can be
19
+ * organized into labeled sections with horizontal dividers.
20
+ *
21
+ * @see {@link https://developer.roku.com/dev/docs/markupgrid}
22
+ * @see {@link https://github.com/rokudev/samples/blob/master/ux%20components/lists%20and%20grids/SimpleMarkupList | SimpleMarkupList Sample App}
23
+ *
24
+ * @example
25
+ * ```tsx
26
+ * <markupGrid
27
+ * itemComponentName="MyGridItem"
28
+ * itemSize={[300, 200]}
29
+ * numColumns={3}
30
+ * content={gridContent}
31
+ * onItemFocused={(index) => setFocusedIndex(index)}
32
+ * onItemSelected={(index) => navigateToDetail(index)}
33
+ * />
34
+ * ```
35
+ */
36
+ export const MarkupGrid: Component<IMarkupGridProps> = props => {
37
+ return <markupGrid {...props}></markupGrid>;
38
+ };
@@ -0,0 +1,66 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { IArrayGridProps } from "./array-grid";
5
+ import type { JSX } from "./types";
6
+
7
+ /**
8
+ * Properties for the MarkupList node.
9
+ *
10
+ * MarkupList is a generic list class that displays a vertical list of items,
11
+ * where each item's appearance is defined by an XML component specified via
12
+ * `itemComponentName`. Item appearance as it enters/exits focus can be
13
+ * customized using BrightScript scripting in the item XML component.
14
+ *
15
+ * List items can be organized into sections demarcated by labelled horizontal
16
+ * divider lines between them.
17
+ *
18
+ * @see {@link https://developer.roku.com/dev/docs/markuplist}
19
+ *
20
+ * @example Basic MarkupList
21
+ * ```tsx
22
+ * <MarkupList
23
+ * itemComponentName="SimpleListItem"
24
+ * itemSize={[440, 72]}
25
+ * numRows={8}
26
+ * content={
27
+ * <contentNode>
28
+ * <contentNode title="Drama" HDPOSTERURL="pkg:/images/drama.jpg" />
29
+ * <contentNode title="Action" HDPOSTERURL="pkg:/images/action.jpg" />
30
+ * </contentNode>
31
+ * }
32
+ * onItemSelected={(index) => console.log(`Selected: ${index}`)}
33
+ * />
34
+ * ```
35
+ */
36
+ export interface IMarkupListProps extends IArrayGridProps {
37
+ /**
38
+ * Specifies the name of the compiled component used to render each list item.
39
+ *
40
+ * Register the compiled component by importing its XML file before use:
41
+ * ```ts
42
+ * import "./compiled-components/MyListItem.xml";
43
+ * ```
44
+ *
45
+ * The compiled component may define interface fields that MarkupList will
46
+ * automatically update: `width`, `height`, `index`, `listHasFocus`,
47
+ * `itemContent`, `focusPercent`, and `itemHasFocus`.
48
+ *
49
+ * @example "MyListItem"
50
+ * @see {@link https://developer.roku.com/dev/docs/markuplist | MarkupList itemComponentName}
51
+ */
52
+ itemComponentName: string;
53
+
54
+ /**
55
+ * Specifies the content for the list.
56
+ *
57
+ * Should be a single root ContentNode with one child ContentNode per item. If the data contains section markers (`CONTENTTYPE="SECTION"`), section dividers will be drawn between each section, optionally with an icon and/or label.
58
+ *
59
+ * **Important:** Place `content` before `jumpToItem` and `animateToItem` in the
60
+ * component. When content is updated dynamically, update `jumpToItem`/`animateToItem`
61
+ * in the same transaction or after content has been updated.
62
+ *
63
+ * @see {@link https://developer.roku.com/dev/docs/markuplist#data-bindings | Data bindings}
64
+ */
65
+ content?: JSX.Element;
66
+ }
@@ -0,0 +1,38 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { IMarkupListProps } from "./markup-list.props";
5
+ import { Component } from "./types";
6
+ export type { IMarkupListProps } from "./markup-list.props";
7
+
8
+ // ─────────────────────────────────────────────────────────────────────────────
9
+ // MarkupList Properties
10
+ // ─────────────────────────────────────────────────────────────────────────────
11
+
12
+ /**
13
+ * MarkupList is a generic list class that displays a vertical list of items,
14
+ * where the visual content of each item is an instance of an XML component
15
+ * specified by the `itemComponentName` field.
16
+ *
17
+ * The item XML component receives injected fields (`width`, `height`, `index`,
18
+ * `listHasFocus`, `itemContent`, `focusPercent`, `itemHasFocus`) from the
19
+ * MarkupList, allowing BrightScript to customize item appearance as focus moves.
20
+ *
21
+ * @see {@link https://developer.roku.com/dev/docs/markuplist}
22
+ * @see {@link https://github.com/rokudev/samples/tree/master/ux%20components/lists%20and%20grids | SimpleMarkupList Sample App}
23
+ *
24
+ * @example
25
+ * ```tsx
26
+ * <markupList
27
+ * itemComponentName="MyListItem"
28
+ * itemSize={[440, 72]}
29
+ * numRows={8}
30
+ * content={listContent}
31
+ * onItemFocused={(index) => setFocusedIndex(index)}
32
+ * onItemSelected={(index) => navigateToDetail(index)}
33
+ * />
34
+ * ```
35
+ */
36
+ export const MarkupList: Component<IMarkupListProps> = props => {
37
+ return <markupList {...props}></markupList>;
38
+ };
@@ -0,0 +1,78 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { IGroupProps } from "./group.props";
5
+ import type { EventHandler, Uri, Vector2D } from "./types";
6
+
7
+ /**
8
+ * Properties for the MaskGroup node.
9
+ *
10
+ * MaskGroup allows an alpha mask bitmap to be applied to the rendering of its children.
11
+ * This enables effects such as having content fade out at edges.
12
+ *
13
+ * **Important Notes:**
14
+ * - MaskGroup only works on Roku players that support OpenGL
15
+ * - On non-OpenGL players, children render without the mask effect
16
+ * - Should only be used for decorative purposes (fading effects, etc.)
17
+ * - Does NOT work with 9-patch images
18
+ * - If mask size doesn't match group bounds, edge rows/columns are repeated
19
+ *
20
+ * @extends Group
21
+ * @see {@link https://developer.roku.com/dev/docs/maskgroup}
22
+ *
23
+ * @example
24
+ * <MaskGroup maskUri="pkg:/images/fade-mask.png">
25
+ * <Poster uri="pkg:/images/content.jpg" width={400} height={300} />
26
+ * </MaskGroup>
27
+ */
28
+ export interface IMaskGroupProps extends IGroupProps {
29
+ /**
30
+ * Specifies the bitmap to use for the group alpha mask.
31
+ *
32
+ * The alpha value of each pixel rendered in the group is multiplied by the
33
+ * corresponding pixel value in the alpha mask. The mapping from pixel
34
+ * coordinates in the group to mask pixel coordinates is controlled by
35
+ * the `maskSize` and `maskOffset` field values.
36
+ *
37
+ * @default ""
38
+ */
39
+ maskUri?: Uri;
40
+
41
+ /**
42
+ * Specifies a scaling factor of the alpha mask coordinate system relative
43
+ * to the group coordinate system.
44
+ *
45
+ * If either element doesn't match the corresponding mask bitmap size
46
+ * (reported via `onMaskBitmapWidth` / `onMaskBitmapHeight`), the mask
47
+ * is scaled to the specified size in that dimension.
48
+ *
49
+ * Setting either element to `0` causes the mask bitmap to be used at its
50
+ * actual size in that dimension.
51
+ *
52
+ * @default [0, 0]
53
+ */
54
+ maskSize?: Vector2D;
55
+
56
+ /**
57
+ * Specifies an offset of the mask coordinate system relative to the group
58
+ * coordinate system.
59
+ *
60
+ * For example, if set to `[100, 0]`, then mask pixel [0, 0] is used as
61
+ * the alpha value for pixels rendered at group coordinate [100, 0].
62
+ *
63
+ * @default [0, 0]
64
+ */
65
+ maskOffset?: Vector2D;
66
+
67
+ /**
68
+ * Invoked when the mask bitmap loads, with the actual width in pixels.
69
+ * Use this to size child content to match the mask bitmap dimensions.
70
+ */
71
+ onMaskBitmapWidth?: EventHandler<number>;
72
+
73
+ /**
74
+ * Invoked when the mask bitmap loads, with the actual height in pixels.
75
+ * Use this to size child content to match the mask bitmap dimensions.
76
+ */
77
+ onMaskBitmapHeight?: EventHandler<number>;
78
+ }
@@ -0,0 +1,59 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { IMaskGroupProps } from "./mask-group.props";
5
+ import { Component } from "./types";
6
+ export type { IMaskGroupProps } from "./mask-group.props";
7
+
8
+ /**
9
+ * MaskGroup component for applying alpha masks to child content.
10
+ *
11
+ * Use MaskGroup to create decorative effects like fading content at edges,
12
+ * vignette effects, or shaped reveals. The mask bitmap's alpha channel
13
+ * determines the opacity of the rendered children.
14
+ *
15
+ * **How Masking Works:**
16
+ * - Each pixel's alpha is multiplied by the corresponding mask pixel value
17
+ * - White (255) in the mask = fully visible
18
+ * - Black (0) in the mask = fully transparent
19
+ * - Gray values = partial transparency
20
+ *
21
+ * **Limitations:**
22
+ * - Only works on OpenGL-capable Roku devices
23
+ * - On other devices, children render normally without the mask
24
+ * - Not suitable for critical UI elements due to device variability
25
+ * - Does not support 9-patch images
26
+ *
27
+ * @example
28
+ * ```tsx
29
+ * // Basic fade effect at bottom
30
+ * <maskGroup maskUri="pkg:/images/bottom-fade.png">
31
+ * <poster uri="pkg:/images/hero.jpg" width={1920} height={1080} />
32
+ * </maskGroup>
33
+ * ```
34
+ *
35
+ * @example
36
+ * ```tsx
37
+ * // Scaled and offset mask
38
+ * <maskGroup
39
+ * maskUri="pkg:/images/vignette.png"
40
+ * maskSize={[800, 600]}
41
+ * maskOffset={[100, 50]}
42
+ * >
43
+ * <rectangle width={1000} height={700} color="#FF0000FF" />
44
+ * </maskGroup>
45
+ * ```
46
+ *
47
+ * @example
48
+ * ```tsx
49
+ * // Circular reveal effect
50
+ * <maskGroup maskUri="pkg:/images/circle-mask.png">
51
+ * <poster uri={thumbnailUri} width={200} height={200} />
52
+ * </maskGroup>
53
+ * ```
54
+ *
55
+ * @see {@link https://developer.roku.com/dev/docs/maskgroup}
56
+ */
57
+ export const MaskGroup: Component<IMaskGroupProps> = props => {
58
+ return <maskGroup {...props}></maskGroup>;
59
+ };
@@ -0,0 +1,20 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import { setPropMethod } from "@roku-sdk/solid";
5
+
6
+ /**
7
+ * Shared imperative method descriptors for media playback nodes (Video, Audio).
8
+ * Both tags expose the same control surface for playback management.
9
+ */
10
+ export const mediaPlaybackMethods = {
11
+ play: setPropMethod("control", "play"),
12
+ pause: setPropMethod("control", "pause"),
13
+ stop: setPropMethod("control", "stop"),
14
+ resume: setPropMethod("control", "resume"),
15
+ replay: setPropMethod("control", "replay"),
16
+ prebuffer: setPropMethod("control", "prebuffer"),
17
+ skipcontent: setPropMethod("control", "skipcontent"),
18
+ seekTo: setPropMethod("seek"),
19
+ setNextContentIndex: setPropMethod("nextContentIndex")
20
+ };