@roku-sdk/components 0.0.0-stage → 2.18.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 (211) 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 +84 -3
  8. package/src/__tests__/container.test.tsx +150 -0
  9. package/src/__tests__/glyphs.test.ts +202 -0
  10. package/src/__tests__/modal-boundary-export.test.ts +12 -0
  11. package/src/__tests__/native-modal.test.tsx +224 -0
  12. package/src/__tests__/tween-release.test.tsx +125 -0
  13. package/src/__tests__/tween-stops-shape.test.tsx +165 -0
  14. package/src/__tests__/tween-without-compat.test.tsx +64 -0
  15. package/src/__tests__/tween.test.tsx +195 -0
  16. package/src/blended-busy-spinner.props.ts +37 -0
  17. package/src/blended-busy-spinner.tsx +13 -0
  18. package/src/bounding-tracker.props.ts +18 -0
  19. package/src/bounding-tracker.tsx +13 -0
  20. package/src/button-row.tsx +126 -0
  21. package/src/channel-store.props.ts +425 -0
  22. package/src/channel-store.tsx +76 -0
  23. package/src/container.tsx +130 -0
  24. package/src/core/jsx-runtime.ts +39 -0
  25. package/src/focusable-group.props.ts +8 -0
  26. package/src/focusable-group.tsx +17 -0
  27. package/src/focusable.props.ts +14 -0
  28. package/src/focusable.tsx +17 -0
  29. package/src/glyphs.ts +116 -0
  30. package/src/helpers/index.tsx +4 -0
  31. package/src/helpers/resolution-context.tsx +68 -0
  32. package/src/helpers/scale-for-device-resolution.ts +31 -0
  33. package/src/index.tsx +70 -0
  34. package/src/jsx-props.ts +87 -0
  35. package/src/kdfs.d.ts +14 -0
  36. package/src/kdfs.ts +15 -0
  37. package/src/key-handler.props.ts +33 -0
  38. package/src/key-handler.tsx +24 -0
  39. package/src/modal-dialog.props.ts +38 -0
  40. package/src/modal-dialog.tsx +41 -0
  41. package/src/retain-asset.ts +24 -0
  42. package/src/sg-intrinsics.json +1153 -0
  43. package/src/sg-nodes/__tests__/__snapshots__/font.test.tsx.snap +13 -0
  44. package/src/sg-nodes/__tests__/__snapshots__/prop-forwarding.test.tsx.snap +4409 -0
  45. package/src/sg-nodes/__tests__/core-props.test.ts +301 -0
  46. package/src/sg-nodes/__tests__/font.test.tsx +141 -0
  47. package/src/sg-nodes/__tests__/imperative-methods.test.ts +268 -0
  48. package/src/sg-nodes/__tests__/prop-forwarding.test.tsx +1049 -0
  49. package/src/sg-nodes/__tests__/solid-integration.test.tsx +719 -0
  50. package/src/sg-nodes/animated-image.props.ts +64 -0
  51. package/src/sg-nodes/animated-image.tsx +23 -0
  52. package/src/sg-nodes/animation.props.ts +292 -0
  53. package/src/sg-nodes/animation.tsx +190 -0
  54. package/src/sg-nodes/array-grid.ts +602 -0
  55. package/src/sg-nodes/audio.props.ts +302 -0
  56. package/src/sg-nodes/audio.tsx +57 -0
  57. package/src/sg-nodes/busy-spinner.props.ts +59 -0
  58. package/src/sg-nodes/busy-spinner.tsx +84 -0
  59. package/src/sg-nodes/button-group.props.ts +141 -0
  60. package/src/sg-nodes/button-group.tsx +30 -0
  61. package/src/sg-nodes/button.props.ts +119 -0
  62. package/src/sg-nodes/button.tsx +31 -0
  63. package/src/sg-nodes/check-list.props.ts +71 -0
  64. package/src/sg-nodes/check-list.tsx +55 -0
  65. package/src/sg-nodes/content-node.props.ts +1316 -0
  66. package/src/sg-nodes/content-node.tsx +153 -0
  67. package/src/sg-nodes/core-props.ts +197 -0
  68. package/src/sg-nodes/custom-keyboard.props.ts +108 -0
  69. package/src/sg-nodes/custom-keyboard.tsx +48 -0
  70. package/src/sg-nodes/dialog.props.ts +159 -0
  71. package/src/sg-nodes/dialog.tsx +36 -0
  72. package/src/sg-nodes/dynamic-key-grid.props.ts +22 -0
  73. package/src/sg-nodes/dynamic-key-grid.tsx +16 -0
  74. package/src/sg-nodes/dynamic-keyboard.props.ts +30 -0
  75. package/src/sg-nodes/dynamic-keyboard.tsx +18 -0
  76. package/src/sg-nodes/dynamic-mini-keyboard.props.ts +22 -0
  77. package/src/sg-nodes/dynamic-mini-keyboard.tsx +18 -0
  78. package/src/sg-nodes/dynamic-pinpad.props.ts +57 -0
  79. package/src/sg-nodes/dynamic-pinpad.tsx +18 -0
  80. package/src/sg-nodes/effect.props.ts +116 -0
  81. package/src/sg-nodes/effect.tsx +39 -0
  82. package/src/sg-nodes/font.props.ts +45 -0
  83. package/src/sg-nodes/font.tsx +80 -0
  84. package/src/sg-nodes/group.props.ts +105 -0
  85. package/src/sg-nodes/group.tsx +30 -0
  86. package/src/sg-nodes/label-list.props.ts +86 -0
  87. package/src/sg-nodes/label-list.tsx +64 -0
  88. package/src/sg-nodes/label.props.ts +207 -0
  89. package/src/sg-nodes/label.tsx +56 -0
  90. package/src/sg-nodes/layout-group.props.ts +69 -0
  91. package/src/sg-nodes/layout-group.tsx +75 -0
  92. package/src/sg-nodes/list-panel.props.ts +104 -0
  93. package/src/sg-nodes/list-panel.tsx +49 -0
  94. package/src/sg-nodes/markup-grid.props.ts +78 -0
  95. package/src/sg-nodes/markup-grid.tsx +38 -0
  96. package/src/sg-nodes/markup-list.props.ts +68 -0
  97. package/src/sg-nodes/markup-list.tsx +38 -0
  98. package/src/sg-nodes/mask-group.props.ts +78 -0
  99. package/src/sg-nodes/mask-group.tsx +59 -0
  100. package/src/sg-nodes/media-playback-methods.ts +20 -0
  101. package/src/sg-nodes/node.ts +77 -0
  102. package/src/sg-nodes/overhang.props.ts +169 -0
  103. package/src/sg-nodes/overhang.tsx +29 -0
  104. package/src/sg-nodes/panel-set.props.ts +71 -0
  105. package/src/sg-nodes/panel-set.tsx +53 -0
  106. package/src/sg-nodes/panel.props.ts +176 -0
  107. package/src/sg-nodes/panel.tsx +56 -0
  108. package/src/sg-nodes/poster-grid.props.ts +277 -0
  109. package/src/sg-nodes/poster-grid.tsx +45 -0
  110. package/src/sg-nodes/poster.props.ts +125 -0
  111. package/src/sg-nodes/poster.tsx +44 -0
  112. package/src/sg-nodes/radio-button-list.props.ts +59 -0
  113. package/src/sg-nodes/radio-button-list.tsx +68 -0
  114. package/src/sg-nodes/rectangle.props.ts +29 -0
  115. package/src/sg-nodes/rectangle.tsx +27 -0
  116. package/src/sg-nodes/row-list.props.ts +288 -0
  117. package/src/sg-nodes/row-list.tsx +47 -0
  118. package/src/sg-nodes/scene.props.ts +65 -0
  119. package/src/sg-nodes/scene.tsx +15 -0
  120. package/src/sg-nodes/scrollable-text.props.ts +133 -0
  121. package/src/sg-nodes/scrollable-text.tsx +64 -0
  122. package/src/sg-nodes/scrolling-label.props.ts +106 -0
  123. package/src/sg-nodes/scrolling-label.tsx +42 -0
  124. package/src/sg-nodes/simple-label.props.ts +156 -0
  125. package/src/sg-nodes/simple-label.tsx +59 -0
  126. package/src/sg-nodes/sound-effect.props.ts +130 -0
  127. package/src/sg-nodes/sound-effect.tsx +65 -0
  128. package/src/sg-nodes/standard-dialog.props.ts +520 -0
  129. package/src/sg-nodes/standard-dialog.tsx +428 -0
  130. package/src/sg-nodes/standard-keyboard-dialog.props.ts +84 -0
  131. package/src/sg-nodes/standard-keyboard-dialog.tsx +59 -0
  132. package/src/sg-nodes/standard-message-dialog.props.ts +56 -0
  133. package/src/sg-nodes/standard-message-dialog.tsx +48 -0
  134. package/src/sg-nodes/standard-pinpad-dialog.props.ts +64 -0
  135. package/src/sg-nodes/standard-pinpad-dialog.tsx +46 -0
  136. package/src/sg-nodes/standard-progress-dialog.props.ts +30 -0
  137. package/src/sg-nodes/standard-progress-dialog.tsx +43 -0
  138. package/src/sg-nodes/target-group.props.ts +278 -0
  139. package/src/sg-nodes/target-group.tsx +63 -0
  140. package/src/sg-nodes/target-list.props.ts +128 -0
  141. package/src/sg-nodes/target-list.tsx +66 -0
  142. package/src/sg-nodes/target-set.props.ts +63 -0
  143. package/src/sg-nodes/target-set.tsx +42 -0
  144. package/src/sg-nodes/time-grid.props.ts +646 -0
  145. package/src/sg-nodes/time-grid.tsx +87 -0
  146. package/src/sg-nodes/tween.props.ts +115 -0
  147. package/src/sg-nodes/types.ts +150 -0
  148. package/src/sg-nodes/video.props.ts +573 -0
  149. package/src/sg-nodes/video.tsx +73 -0
  150. package/src/sg-nodes/voice-text-edit-box.props.ts +91 -0
  151. package/src/sg-nodes/voice-text-edit-box.tsx +15 -0
  152. package/src/sg-nodes/zoom-row-list.props.ts +416 -0
  153. package/src/sg-nodes/zoom-row-list.tsx +42 -0
  154. package/src/standard-dialog-next/__tests__/standard-dialog-next.test.tsx +186 -0
  155. package/src/standard-dialog-next/index.ts +5 -0
  156. package/src/standard-dialog-next/standard-dialog-next.props.ts +80 -0
  157. package/src/standard-dialog-next/standard-dialog-next.tsx +326 -0
  158. package/src/test-helpers/tween-test-setup.ts +78 -0
  159. package/src/tween.tsx +173 -0
  160. package/src/types.ts +8 -0
  161. package/src/xml-components/blended-busy-spinner/BlendedBusySpinner.brs +13 -0
  162. package/src/xml-components/blended-busy-spinner/BlendedBusySpinner.xml +10 -0
  163. package/src/xml-components/blended-busy-spinner/BlendedBusySpinner.xml.d.ts +42 -0
  164. package/src/xml-components/bounding-tracker/BoundingTracker.brs +26 -0
  165. package/src/xml-components/bounding-tracker/BoundingTracker.xml +14 -0
  166. package/src/xml-components/bounding-tracker/BoundingTracker.xml.d.ts +42 -0
  167. package/src/xml-components/channel-store/channelStoreExt.brs +159 -0
  168. package/src/xml-components/channel-store/channelStoreExt.xml +29 -0
  169. package/src/xml-components/channel-store/channelStoreExt.xml.d.ts +57 -0
  170. package/src/xml-components/focus/focusable-group.brs +251 -0
  171. package/src/xml-components/focus/focusable-group.xml +15 -0
  172. package/src/xml-components/focus/focusable-group.xml.d.ts +42 -0
  173. package/src/xml-components/focus/focusable.xml +18 -0
  174. package/src/xml-components/focus/focusable.xml.d.ts +48 -0
  175. package/src/xml-components/keyboards/CustomAddressKDF.keyboard.json +547 -0
  176. package/src/xml-components/keyboards/CustomKeyboard.brs +322 -0
  177. package/src/xml-components/keyboards/CustomKeyboard.xml +45 -0
  178. package/src/xml-components/keyboards/CustomKeyboard.xml.d.ts +73 -0
  179. package/src/xml-components/keyboards/KeyGridExt.xml +4 -0
  180. package/src/xml-components/keyboards/KeyGridExt.xml.d.ts +37 -0
  181. package/src/xml-components/keyboards/KeyboardExt.xml +4 -0
  182. package/src/xml-components/keyboards/KeyboardExt.xml.d.ts +37 -0
  183. package/src/xml-components/keyboards/MOPPinPadCustomKDF.keyboard.json +151 -0
  184. package/src/xml-components/keyboards/MiniKeyboardExt.xml +4 -0
  185. package/src/xml-components/keyboards/MiniKeyboardExt.xml.d.ts +37 -0
  186. package/src/xml-components/keyboards/PhonePadCustomKDF.keyboard.json +42 -0
  187. package/src/xml-components/keyboards/PinPadExt.brs +102 -0
  188. package/src/xml-components/keyboards/PinPadExt.xml +17 -0
  189. package/src/xml-components/keyboards/PinPadExt.xml.d.ts +49 -0
  190. package/src/xml-components/keyboards/WifiCustomKDF.keyboard.json +1242 -0
  191. package/src/xml-components/keyhandler/KeyHandler.brs +30 -0
  192. package/src/xml-components/keyhandler/KeyHandler.xml +16 -0
  193. package/src/xml-components/keyhandler/KeyHandler.xml.d.ts +45 -0
  194. package/src/xml-components/managed-list-panel/ManagedListPanel.brs +137 -0
  195. package/src/xml-components/managed-list-panel/ManagedListPanel.xml +10 -0
  196. package/src/xml-components/managed-list-panel/ManagedListPanel.xml.d.ts +37 -0
  197. package/src/xml-components/modal/Modal.brs +105 -0
  198. package/src/xml-components/modal/Modal.xml +22 -0
  199. package/src/xml-components/modal/Modal.xml.d.ts +54 -0
  200. package/src/xml-components/modal/StandardDialogExt.xml +10 -0
  201. package/src/xml-components/modal/StandardDialogExt.xml.d.ts +37 -0
  202. package/src/xml-components/modal/StandardKeyboardDialogExt.xml +10 -0
  203. package/src/xml-components/modal/StandardKeyboardDialogExt.xml.d.ts +37 -0
  204. package/src/xml-components/modal/StandardMessageDialogExt.xml +10 -0
  205. package/src/xml-components/modal/StandardMessageDialogExt.xml.d.ts +37 -0
  206. package/src/xml-components/modal/StandardPinPadDialogExt.xml +10 -0
  207. package/src/xml-components/modal/StandardPinPadDialogExt.xml.d.ts +37 -0
  208. package/src/xml-components/modal/StandardProgressDialogExt.xml +10 -0
  209. package/src/xml-components/modal/StandardProgressDialogExt.xml.d.ts +37 -0
  210. package/src/xml-components/modal/tests/Modal.test.brs +195 -0
  211. package/tsconfig.json +10 -0
@@ -0,0 +1,36 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import { Modal } from "../modal-dialog";
5
+ import type { IDialogProps } from "./dialog.props";
6
+ import { Component } from "./types";
7
+ export type { IDialogProps } from "./dialog.props";
8
+
9
+ /**
10
+ * Dialog is a modal pop-up used to present the user with information requiring their
11
+ * immediate attention. It supports a title, message, bullet text, graphic, and button
12
+ * regions. Dialogs intercept all key events except Home and are closed automatically
13
+ * by Back or Home.
14
+ *
15
+ * > **Note:** Consider using StandardDialog (Roku OS 10.0+) for new development, which
16
+ * > provides updated graphics and color palette support.
17
+ *
18
+ * @example
19
+ * ```tsx
20
+ * <Dialog
21
+ * title="Confirm Action"
22
+ * message="Are you sure you want to proceed?"
23
+ * iconUri="pkg:/images/dialog-icon.png"
24
+ * buttons={["OK", "Cancel"]}
25
+ * close={false}
26
+ * onButtonSelected={(index) => {
27
+ * if (index === 0) handleConfirm();
28
+ * else handleCancel();
29
+ * }}
30
+ * onWasClosed={() => console.log("Dialog closed")}
31
+ * />
32
+ * ```
33
+ *
34
+ * @see {@link https://developer.roku.com/dev/docs/dialog}
35
+ */
36
+ export const Dialog: Component<IDialogProps> = props => <Modal dialog={<dialog {...props}></dialog>} />;
@@ -0,0 +1,22 @@
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 {@link DynamicKeyGrid} component.
9
+ *
10
+ * @see {@link https://developer.roku.com/dev/docs/dynamic-key-grid}
11
+ */
12
+ export interface IDynamicKeyGridProps extends IGroupProps {
13
+ /** URI of a packaged `.keyboard.json` Key Definition File. */
14
+ keyDefinitionUri?: string;
15
+ /** Active grid mode (must match a mode in the KDF). */
16
+ mode?: string;
17
+ /** Fired when the `keySelected` field changes after a key press. */
18
+ onKeySelected?: EventHandler<string>;
19
+ focusVisible?: boolean;
20
+ horizWrap?: boolean;
21
+ vertWrap?: boolean;
22
+ }
@@ -0,0 +1,16 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import { retainAsset } from "../retain-asset";
5
+ import KeyGridExtXML from "../xml-components/keyboards/KeyGridExt.xml";
6
+ import type { IDynamicKeyGridProps } from "./dynamic-key-grid.props";
7
+ import { Component } from "./types";
8
+ export type { IDynamicKeyGridProps } from "./dynamic-key-grid.props";
9
+
10
+ /**
11
+ * Standalone key grid driven by a Key Definition File (no text edit box).
12
+ */
13
+ export const DynamicKeyGrid: Component<IDynamicKeyGridProps> = props => {
14
+ retainAsset(KeyGridExtXML);
15
+ return <keyGridExt {...props}></keyGridExt>;
16
+ };
@@ -0,0 +1,30 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { KeyboardDomain } from "./custom-keyboard.props";
5
+ import type { IGroupProps } from "./group.props";
6
+ import type { EventHandler } from "./types";
7
+
8
+ /**
9
+ * Properties for the {@link DynamicKeyboard} component.
10
+ *
11
+ * Voice-enabled full keyboard with a fixed OS key layout (email/password style).
12
+ *
13
+ * @see {@link https://developer.roku.com/dev/docs/dynamic-keyboard}
14
+ */
15
+ export interface IDynamicKeyboardProps extends IGroupProps {
16
+ /** Current text in the internal VoiceTextEditBox. */
17
+ text?: string;
18
+ /** Fired when entered text changes. */
19
+ onText?: EventHandler<string>;
20
+ /** Speech-recognition domain for voice entry. */
21
+ domain?: KeyboardDomain;
22
+ /** Placeholder text shown when empty. */
23
+ hintText?: string;
24
+ /** Maximum number of characters that may be entered. */
25
+ maxTextLength?: number;
26
+ /** Shows underscore placeholders in the text edit box. */
27
+ showUnderscores?: boolean;
28
+ /** When true, entered characters are masked. */
29
+ secureMode?: boolean;
30
+ }
@@ -0,0 +1,18 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import { retainAsset } from "../retain-asset";
5
+ import KeyboardExtXML from "../xml-components/keyboards/KeyboardExt.xml";
6
+ import type { IDynamicKeyboardProps } from "./dynamic-keyboard.props";
7
+ import { Component } from "./types";
8
+ export type { IDynamicKeyboardProps } from "./dynamic-keyboard.props";
9
+
10
+ /**
11
+ * Standalone {@link DynamicKeyboard} with built-in key layout and voice entry.
12
+ *
13
+ * Voice is always enabled on this fixed OS layout; there is no `voiceEnabled` prop.
14
+ */
15
+ export const DynamicKeyboard: Component<IDynamicKeyboardProps> = props => {
16
+ retainAsset(KeyboardExtXML);
17
+ return <keyboardExt {...props}></keyboardExt>;
18
+ };
@@ -0,0 +1,22 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { KeyboardDomain } from "./custom-keyboard.props";
5
+ import type { IGroupProps } from "./group.props";
6
+ import type { EventHandler } from "./types";
7
+
8
+ /**
9
+ * Properties for the {@link DynamicMiniKeyboard} component.
10
+ *
11
+ * @see {@link https://developer.roku.com/dev/docs/dynamic-mini-keyboard}
12
+ */
13
+ export interface IDynamicMiniKeyboardProps extends IGroupProps {
14
+ text?: string;
15
+ onText?: EventHandler<string>;
16
+ /** Speech-recognition domain for voice entry. */
17
+ domain?: KeyboardDomain;
18
+ /** Placeholder text shown when empty. */
19
+ hintText?: string;
20
+ /** Maximum number of characters that may be entered. */
21
+ maxTextLength?: number;
22
+ }
@@ -0,0 +1,18 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import { retainAsset } from "../retain-asset";
5
+ import MiniKeyboardExtXML from "../xml-components/keyboards/MiniKeyboardExt.xml";
6
+ import type { IDynamicMiniKeyboardProps } from "./dynamic-mini-keyboard.props";
7
+ import { Component } from "./types";
8
+ export type { IDynamicMiniKeyboardProps } from "./dynamic-mini-keyboard.props";
9
+
10
+ /**
11
+ * Standalone search-style mini keyboard (A–Z, 0–9) with voice entry.
12
+ *
13
+ * Voice is always enabled on this fixed OS layout; there is no `voiceEnabled` prop.
14
+ */
15
+ export const DynamicMiniKeyboard: Component<IDynamicMiniKeyboardProps> = props => {
16
+ retainAsset(MiniKeyboardExtXML);
17
+ return <miniKeyboardExt {...props}></miniKeyboardExt>;
18
+ };
@@ -0,0 +1,57 @@
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 {@link DynamicPinPad} component.
9
+ *
10
+ * DynamicPinPad is similar to the legacy PinPad node but adds voice entry functionality.
11
+ * It enables text and voice entry of numeric characters and is typically used for short
12
+ * PIN codes. The key layout is fixed based on the node's pre-built Key Definition File.
13
+ *
14
+ * This wrapper extends the native DynamicPinPad node via PinPadExt, forwarding text-edit-box
15
+ * styling fields to the internal VoiceTextEditBox.
16
+ *
17
+ * @see {@link https://developer.roku.com/dev/docs/dynamic-pinpad}
18
+ * @see {@link https://developer.roku.com/dev/docs/dynamic-keyboard-base}
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * <DynamicPinPad
23
+ * id="pinpad"
24
+ * text={pin()}
25
+ * hintText="Enter PIN"
26
+ * maxTextLength={4}
27
+ * secureMode
28
+ * onText={setPin}
29
+ * translation={[80, 200]}
30
+ * />
31
+ * ```
32
+ */
33
+ export interface IDynamicPinPadProps extends IGroupProps {
34
+ /** Current PIN/text value. */
35
+ text?: string;
36
+ /** Fired when the entered text changes. */
37
+ onText?: EventHandler<string>;
38
+ /** When true, entered characters are masked. */
39
+ secureMode?: boolean;
40
+ /** Placeholder text shown when empty. */
41
+ hintText?: string;
42
+ /**
43
+ * Maximum number of characters that may be entered.
44
+ * @default 4
45
+ */
46
+ maxTextLength?: number;
47
+ /** Disables voice underscore control in the internal text edit box. */
48
+ disableVoiceUnderscoreControl?: boolean;
49
+ /** Shows underscore placeholders for each digit position. */
50
+ showUnderscores?: boolean;
51
+ /** Centers underscore placeholders within the text box. */
52
+ centerUnderscores?: boolean;
53
+ /** Color of the hint text. */
54
+ hintTextColor?: string;
55
+ /** Color of the entered text. */
56
+ textColor?: string;
57
+ }
@@ -0,0 +1,18 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import { retainAsset } from "../retain-asset";
5
+ import PinPadExtXML from "../xml-components/keyboards/PinPadExt.xml";
6
+ import type { IDynamicPinPadProps } from "./dynamic-pinpad.props";
7
+ import { Component } from "./types";
8
+ export type { IDynamicPinPadProps } from "./dynamic-pinpad.props";
9
+
10
+ /**
11
+ * Voice-enabled numeric PIN pad for standalone on-screen entry (not inside a dialog).
12
+ *
13
+ * @see {@link https://developer.roku.com/dev/docs/dynamic-pinpad}
14
+ */
15
+ export const DynamicPinPad: Component<IDynamicPinPadProps> = props => {
16
+ retainAsset(PinPadExtXML);
17
+ return <pinPadExt {...props}></pinPadExt>;
18
+ };
@@ -0,0 +1,116 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { INodeProps } from "./node";
5
+ import type { Vector2D } from "./types";
6
+
7
+ export type GradientStyle = "none" | "linear" | "radial";
8
+
9
+ /**
10
+ * Properties for the Effect node.
11
+ *
12
+ * Effect applies GPU shader-based rendering to a Rectangle or Poster, enabling rounded corners,
13
+ * borders, and gradient fills. Attach an Effect node to a Rectangle or Poster via the `effect`
14
+ * prop.
15
+ *
16
+ * **Platform availability**: Effects require Roku OS 16.0 or later and the OpenGL graphics backend.
17
+ * Elsewhere the `effect` prop is ignored without an error and the content renders unstyled. To branch
18
+ * on it, read `getDeviceInfo()` from `@roku-sdk/rsg-ts/runtime` once:
19
+ * `Number(info.osVersion.major) >= 16 && info.graphicsPlatform === "opengl"`. The node's own `supported`
20
+ * field is set when the node is created and cannot be read from TypeScript, and effects disabled by
21
+ * device configuration are invisible to that check.
22
+ *
23
+ * Hoist the effect into a `const`. A signal read by the `effect={...}` expression itself builds a new
24
+ * effect node on every change; signals read by the effect's own fields update it in place.
25
+ *
26
+ * {@includeCode ../../../../examples/showcase/src/components/showcases/effect-showcase/shared-effect-showcase.tsx#docs:effect-shared}
27
+ *
28
+ * @example
29
+ * // Rounded border and linear gradient, each hoisted once.
30
+ * const framed = <effect borderRadius={16} borderWidth={2} borderColor="0xFF0000FF" />;
31
+ * <rectangle width={400} height={200} effect={framed} />;
32
+ * const fill = <effect gradientStyle="linear" gradientColors={["0xFF0000FF", "0x0000FFFF"]} />;
33
+ * <rectangle width={400} height={200} effect={fill} />;
34
+ *
35
+ * @since Roku OS 16.0
36
+ */
37
+ export interface IEffectProps extends INodeProps {
38
+ /**
39
+ * Per-corner border radius in pixels.
40
+ * - A single number applies a uniform radius to all corners.
41
+ * - A four-element tuple sets each corner independently: `[topLeft, topRight, bottomRight, bottomLeft]`.
42
+ * The tuple is one Vector4 field, so a `FloatFieldInterpolator` cannot animate it.
43
+ * @default 0
44
+ */
45
+ borderRadius?: number | [number, number, number, number];
46
+
47
+ /**
48
+ * Border stroke width in pixels. The border is drawn **outside** the content rect.
49
+ * @default 0
50
+ */
51
+ borderWidth?: number;
52
+
53
+ /**
54
+ * Padding in pixels between the border and the content rect. It changes nothing while
55
+ * `borderWidth` is 0, so it is not content padding.
56
+ * @default 0
57
+ */
58
+ borderPadding?: number;
59
+
60
+ /**
61
+ * Border stroke color as an RGBA hex string (e.g. `"0xFF0000FF"`).
62
+ * @default "0xFFFFFFFF"
63
+ */
64
+ borderColor?: string;
65
+
66
+ /**
67
+ * Gradient fill style applied over the content area. No gradient renders while this is `"none"`.
68
+ * @default "none"
69
+ */
70
+ gradientStyle?: GradientStyle;
71
+
72
+ /**
73
+ * Ordered list of RGBA color stops for the gradient (e.g. `["0xFF0000FF", "0x0000FFFF"]`).
74
+ * At least two colors are required for the gradient to render. Maximum of 8 colors.
75
+ */
76
+ gradientColors?: string[];
77
+
78
+ /**
79
+ * Normalized stop positions `[0, 1]` corresponding to each entry in `gradientColors`.
80
+ * If omitted, colors are distributed evenly across the gradient. A length mismatch is not reported.
81
+ */
82
+ gradientStops?: number[];
83
+
84
+ /**
85
+ * Rotation angle of a linear gradient in degrees.
86
+ * The gradient fills the available space from opposite corners.
87
+ * @default 0
88
+ */
89
+ gradientAngle?: number;
90
+
91
+ /**
92
+ * Center point of a radial gradient in normalized coordinates.
93
+ * `[0, 0]` = top-left, `[1, 1]` = bottom-right.
94
+ * @default [0.5, 0.5]
95
+ */
96
+ gradientCentre?: Vector2D;
97
+
98
+ /**
99
+ * Radii of the radial gradient ellipse in normalized coordinates.
100
+ * `1.0` equals the rectangle's width or height respectively.
101
+ * @default [0.5, 0.5]
102
+ */
103
+ gradientRadius?: Vector2D;
104
+
105
+ /**
106
+ * Whether the gradient fills the content area (inside the border).
107
+ * @default true
108
+ */
109
+ gradientFillContent?: boolean;
110
+
111
+ /**
112
+ * Whether the gradient fills the border area.
113
+ * @default false
114
+ */
115
+ gradientFillBorder?: boolean;
116
+ }
@@ -0,0 +1,39 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { IEffectProps } from "./effect.props";
5
+ import { Component } from "./types";
6
+ export type { GradientStyle, IEffectProps } from "./effect.props";
7
+
8
+ /**
9
+ * Effect applies GPU shader-based rendering to a Rectangle or Poster.
10
+ *
11
+ * Hoist it into a `const` and pass that as the `effect` prop on a Rectangle or
12
+ * Poster to enable rounded corners, borders, and gradient fills. Set
13
+ * `shaderCompatible` on a Poster that takes one.
14
+ *
15
+ * Prefer the `<effect>` intrinsic for most uses. The `Effect` wrapper is a pure
16
+ * passthrough (`<effect {...props} />`) and exists for consistency with the component
17
+ * library.
18
+ *
19
+ * {@includeCode ../../../../examples/showcase/src/components/showcases/effect-showcase/shared-effect-showcase.tsx#docs:effect-shared}
20
+ *
21
+ * @example
22
+ * import { Effect } from "@roku-sdk/components";
23
+ * const framed = <Effect borderRadius={24} borderWidth={6} borderColor="0xF39C12FF" />;
24
+ * <rectangle width={300} height={140} effect={framed} />;
25
+ *
26
+ * @platformAvailability Effects require Roku OS 16.0 or later and the OpenGL graphics backend.
27
+ * Elsewhere the `effect` prop is ignored without an error and the content renders unstyled. To branch
28
+ * on it, read `getDeviceInfo()` from `@roku-sdk/rsg-ts/runtime` once:
29
+ * `Number(info.osVersion.major) >= 16 && info.graphicsPlatform === "opengl"`. The node's own `supported`
30
+ * field is set when the node is created and cannot be read from TypeScript, and effects disabled by
31
+ * device configuration are invisible to that check.
32
+ *
33
+ * @since Roku OS 16.0
34
+ *
35
+ * @intrinsic effect
36
+ */
37
+ export const Effect: Component<IEffectProps> = props => {
38
+ return <effect {...props}></effect>;
39
+ };
@@ -0,0 +1,45 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { INodeProps } from "./node";
5
+ import type { Uri } from "./types";
6
+
7
+ /**
8
+ * Properties for the Font node.
9
+ *
10
+ * Font specifies the font to be used by a Label node, or any other nodes that render text.
11
+ * The uri field can be set to any TrueType/OpenType font file included in the application package.
12
+ *
13
+ * @see {@link https://developer.roku.com/dev/docs/font}
14
+ *
15
+ * @example
16
+ * // Using with a Label component
17
+ * <Label text="Hello World" font={<Font uri="pkg:/fonts/custom.ttf" size={24} />} />
18
+ */
19
+ export interface IFontProps extends INodeProps {
20
+ /**
21
+ * Specifies a TrueType or OpenType font file.
22
+ * Currently only font files included in the application package can be specified.
23
+ * @default ""
24
+ */
25
+ uri?: Uri;
26
+
27
+ /**
28
+ * Specifies the size of the font in points.
29
+ * @default 1
30
+ */
31
+ size?: number;
32
+
33
+ /**
34
+ * String representation of a Unicode character to display when an unsupported glyph is encountered.
35
+ * For example, "u0020" would render a space for any unrenderable characters.
36
+ * @default ""
37
+ */
38
+ fallbackGlyph?: string;
39
+
40
+ /**
41
+ * If true, forces SceneGraph to update the component before it is rendered
42
+ * @default false
43
+ */
44
+ preUpdate?: boolean;
45
+ }
@@ -0,0 +1,80 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { IFontProps } from "./font.props";
5
+ import { Component } from "./types";
6
+ export type { IFontProps } from "./font.props";
7
+
8
+ /**
9
+ * Font specifies the font to be used by a Label node, or any other nodes that render text.
10
+ *
11
+ * The uri field can be set to any TrueType/OpenType font file. A default system font can also
12
+ * be specified using the `font:` prefix (e.g., `font:MediumBoldSystemFont`).
13
+ *
14
+ * **Components that support Font:**
15
+ * - `Label` / `MultiStyleLabel`: via `font` prop
16
+ * - `ScrollableText`: via `font` prop
17
+ * - `ScrollingLabel`: via `font` prop
18
+ * - `LabelList`: via `font` and `focusedFont` props
19
+ * - `PosterGrid`: via `caption1Font` and `caption2Font` props
20
+ *
21
+ * @see {@link https://developer.roku.com/dev/docs/font}
22
+ *
23
+ * @example
24
+ * ```tsx
25
+ * // Inline font prop with Label
26
+ * <label text="Custom styled text" font={<font uri="pkg:/fonts/orbitron-font.ttf" size={32} />} />
27
+ * ```
28
+ *
29
+ * @example
30
+ * ```tsx
31
+ * // Reusable font definition (declared outside JSX return)
32
+ * const myFont = <font uri="pkg:/fonts/cookie-regular.ttf" size={28} />;
33
+ *
34
+ * // Then in return statement:
35
+ * return (
36
+ * <group>
37
+ * <label text="ABCDEFGHIJKLMNOPQRSTUVWXYZ" font={myFont} />
38
+ * <label text="abcdefghijklmnopqrstuvwxyz" font={myFont} />
39
+ * </group>
40
+ * );
41
+ * ```
42
+ *
43
+ * @example
44
+ * ```tsx
45
+ * // Using with ScrollableText
46
+ * <scrollableText
47
+ * text="Long scrollable content..."
48
+ * width={800}
49
+ * height={400}
50
+ * font={<font uri="pkg:/fonts/readable.ttf" size={24} />}
51
+ * />
52
+ * ```
53
+ *
54
+ * @example
55
+ * ```tsx
56
+ * // Using with LabelList
57
+ * <labelList
58
+ * itemSize={[440, 48]}
59
+ * font={<font uri="pkg:/fonts/menu.ttf" size={20} />}
60
+ * focusedFont={<font uri="pkg:/fonts/menu-bold.ttf" size={22} />}
61
+ * content={content}
62
+ * />
63
+ * ```
64
+ *
65
+ * @example
66
+ * ```tsx
67
+ * // Using with PosterGrid captions
68
+ * <posterGrid
69
+ * basePosterSize={[200, 300]}
70
+ * caption1Font={<font uri="pkg:/fonts/title.ttf" size={18} />}
71
+ * caption2Font={<font uri="pkg:/fonts/subtitle.ttf" size={14} />}
72
+ * caption1NumLines={1}
73
+ * caption2NumLines={1}
74
+ * content={content}
75
+ * />
76
+ * ```
77
+ */
78
+ export const Font: Component<IFontProps> = props => {
79
+ return <font {...props}></font>;
80
+ };
@@ -0,0 +1,105 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { INodeProps } from "./node";
5
+ import type { EventHandler, Rect2D, ResType, Vector2D } from "./types";
6
+
7
+ /**
8
+ * Properties for the Group node.
9
+ *
10
+ * Group is a layout container node that serves as the base class for organizing and positioning
11
+ * child nodes in the SceneGraph. It provides transformation, rendering, and clipping capabilities
12
+ * for managing visual hierarchies.
13
+ *
14
+ * @see {@link https://developer.roku.com/dev/docs/group}
15
+ */
16
+ export interface IGroupProps extends INodeProps {
17
+ /** If true, the node and its children are rendered. If false, the node and its children do not render. */
18
+ visible?: boolean;
19
+ /** Defines the origin of the node local coordinate system relative to its parent node. */
20
+ translation?: ResType<Vector2D>;
21
+ /**
22
+ * Sets the opacity of the node and its children. Opacity is the opposite of transparency.
23
+ * Opacity values range from 0.0 (fully transparent) to 1.0 (fully opaque). As the SceneGraph
24
+ * is traversed, the opacity values are combined by multiplying the current accumulated opacity
25
+ * with the node opacity, so that if the accumulated opacity of a node ancestors is 0.25 (75%
26
+ * transparent), the node will have opacity of 0.25 or less. This allows entire branches of the
27
+ * SceneGraph to fade in and out by animating the opacity of the node at the root of the branch.
28
+ */
29
+ opacity?: number;
30
+ /**
31
+ * Defines the rotation angle about the scaleRotateCenter point (in radians) of the node local
32
+ * coordinate system. Positive values specify a counterclockwise rotation, negative values specify
33
+ * a clockwise rotation. For some Roku Player hardware, specifically Roku Players without OpenGL
34
+ * graphics support, only rotations of 0, 90, 180 and 270 degrees (in equivalent radians) are supported.
35
+ */
36
+ rotation?: number;
37
+ /** Defines the scale factor to be applied to the node local coordinate. */
38
+ scale?: Vector2D;
39
+ /** Describes the location of a point in the node local coordinate that serves as the center of the scale and rotation operations. */
40
+ scaleRotateCenter?: ResType<Vector2D>;
41
+ /**
42
+ * Controls the rendering order of the node relative to its children.
43
+ * - "renderFirst": any drawing done by this node will be done before the node children are rendered
44
+ * - "renderLast": any drawing done by this node will be done after the node children are rendered (default)
45
+ */
46
+ childRenderOrder?: "renderFirst" | "renderLast";
47
+ /**
48
+ * If true, the node overall transformation is determined by combining the accumulated transformation
49
+ * matrix of all of its ancestors in the SceneGraph with the node local 2D transformation matrix
50
+ * described by its translation, rotation, scale and scaleRotateCenter fields. If false, the accumulated
51
+ * transformation of all of its ancestors in the SceneGraph is ignored and only the node local
52
+ * transformation matrix is used. This causes the node to be transformed relative to the root of the
53
+ * SceneGraph (that is, the Scene component).
54
+ */
55
+ inheritParentTransform?: boolean;
56
+ /**
57
+ * If true, the node opacity is determined by multiplying opacity attribute of the node by the opacity
58
+ * of the parent node, which may have been determined by multiplying the opacity of its ancestor nodes.
59
+ * If false, the node opacity is determined by the opacity attribute set for the node or the default
60
+ * opacity attribute value.
61
+ */
62
+ inheritParentOpacity?: boolean;
63
+ /**
64
+ * Specifies a rectangle in the node local coordinate system that is used to limit the region where
65
+ * this node and its children can render. If a non-empty rectangle is specified, then all drawing by
66
+ * this node and its children will be limited to that rectangular area.
67
+ * ClippingRects can be specified by the node or by any of its ancestors in the SceneGraph.
68
+ * ClippingRects are automatically set by some nodes such as lists and grids.
69
+ * ClippingRects are always clipped to the screen boundaries, so if a clippingRect is specified that
70
+ * is partially or completely offscreen, it will be clipped to the screen boundaries. With respect to
71
+ * render tracking, although the node could be completely within the bounds of the specified clippingRect,
72
+ * it's renderTracking field could be set to "none" if the portion of the clippingRect it occupies is
73
+ * completely offscreen.
74
+ */
75
+ clippingRect?: ResType<Rect2D>;
76
+ /**
77
+ * Used in combination with the numRenderPasses field of nodes extended from the ArrayGrid abstract
78
+ * node class, to optimize rendering of lists and grids. This should never be set to a non-zero value
79
+ * unless you are optimizing the performance of a list or grid rendering by specifying the sequence of
80
+ * rendering operations for sub-elements of the list or grid items, and have set the numRenderPasses
81
+ * field value for the list or grid to a value greater than 1. If the numRenderPasses field value for
82
+ * the list or grid is set to a value greater than 1, you must set this field to a value greater than 0
83
+ * for all sub-elements of the list or grid items, and not greater than the numRenderPasses field value.
84
+ * If the numRenderPasses field is set to a value greater than 1, and you set this field for a list or
85
+ * grid item sub-element to 0 (the default), or a value greater than the numRenderPasses field value,
86
+ * the list or grid item sub-element will not render.
87
+ */
88
+ renderPass?: number;
89
+ /** Set to true to suppress the default CVAA text to speech. This allows apps to provide their own custom implementation. */
90
+ muteAudioGuide?: boolean;
91
+ /** If true, renderTracking will be set to a string describing how much of the node is rendered on screen. */
92
+ enableRenderTracking?: boolean;
93
+ /**
94
+ * Event fired when the render tracking state changes. The value is set to "disabled" when enableRenderTracking
95
+ * is set to false. The following options are only available when enableRenderTracking is set to true:
96
+ * - "disabled": Set when enableRenderTracking is false.
97
+ * - "none": Set when the node's visible field is false, opacity is 0.0, the node is completely offscreen,
98
+ * or lies completely outside the clippingRect's coordinates.
99
+ * - "partial": Set when the node is visible with opacity > 0.0 and is partially offscreen or lies partially
100
+ * inside the clippingRect's coordinates.
101
+ * - "full": Set when the node is visible with opacity > 0.0 and is completely onscreen or lies completely
102
+ * inside the clippingRect's coordinates.
103
+ */
104
+ onRenderTracking?: EventHandler<"disabled" | "none" | "partial" | "full">;
105
+ }
@@ -0,0 +1,30 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { IGroupProps } from "./group.props";
5
+ import { Component } from "./types";
6
+ export type { IGroupProps } from "./group.props";
7
+
8
+ /**
9
+ * Group component - a layout container for organizing and positioning child nodes.
10
+ *
11
+ * Group is a layout container node that serves as the base class for organizing and positioning
12
+ * child nodes in the SceneGraph. It provides transformation, rendering, and clipping capabilities
13
+ * for managing visual hierarchies.
14
+ *
15
+ * @example
16
+ * ```tsx
17
+ * <group
18
+ * translation={[100, 50]}
19
+ * opacity={0.8}
20
+ * >
21
+ * <rectangle width={200} height={100} color="#0000FFFF" />
22
+ * <label text="Hello World" />
23
+ * </group>
24
+ * ```
25
+ *
26
+ * @see {@link https://developer.roku.com/dev/docs/group}
27
+ */
28
+ export const Group: Component<IGroupProps> = (props: IGroupProps) => {
29
+ return <group {...props}></group>;
30
+ };