@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,30 @@
1
+ ' Copyright (c) 2026 Roku, Inc.
2
+ ' SPDX-License-Identifier: MIT
3
+
4
+ Sub init()
5
+ print "init keyhandler"
6
+ m.top.observeField("keys", "updateKeyMap")
7
+ updateKeyMap()
8
+ end Sub
9
+
10
+ function onKeyEvent(key as String, press as Boolean) as Boolean
11
+ ' print "Key Event: "; key; " Press: "; press
12
+
13
+ if m.top.handleAllKeys = true
14
+ m.top.SetField("keyEvent", {"key": key, "press": press})
15
+ return true
16
+ end if
17
+
18
+ if m.keyMap[key] <> true and m.top.bubbleUnhandledKeys = true
19
+ return false
20
+ end if
21
+ m.top.SetField("keyEvent", {"key": key, "press": press})
22
+ return true
23
+ end function
24
+
25
+ sub updateKeyMap()
26
+ m.keyMap = {}
27
+ for each key in m.top.keys
28
+ m.keyMap[key] = true
29
+ end for
30
+ end sub
@@ -0,0 +1,16 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!--
3
+ Copyright (c) 2026 Roku, Inc.
4
+ SPDX-License-Identifier: MIT
5
+ -->
6
+
7
+
8
+ <component name="key-handler" extends="Group" focusable="true">
9
+ <script type="text/brightscript" uri="KeyHandler.brs" />
10
+ <interface>
11
+ <field id="bubbleUnhandledKeys" type="boolean" value="true" />
12
+ <field id="keyEvent" type="assocarray" />
13
+ <field id="keys" type="stringarray" />
14
+ <field id="handleAllKeys" type="boolean" />
15
+ </interface>
16
+ </component>
@@ -0,0 +1,45 @@
1
+ // Auto-generated TypeScript declarations for XML component import.
2
+ // DO NOT EDIT — this file is regenerated during build.
3
+ //
4
+ // Source component: key-handler
5
+ // Extends: Group
6
+
7
+ import type { IGroupProps } from "@roku-sdk/components";
8
+ import type { TypedXmlComponent } from "@roku-sdk/interfaces";
9
+
10
+ interface keyHandlerFields {
11
+ /** @default "true" */
12
+ bubbleUnhandledKeys: boolean;
13
+ keyEvent: Record<string, unknown>;
14
+ keys: string[];
15
+ handleAllKeys: boolean;
16
+ }
17
+
18
+ export interface IkeyHandlerProps extends IGroupProps, Partial<keyHandlerFields> {}
19
+
20
+ declare const _default: TypedXmlComponent<"key-handler", keyHandlerFields>;
21
+ export default _default;
22
+
23
+ declare module "@roku-sdk/solid" {
24
+ namespace JSX {
25
+ interface IntrinsicElements {
26
+ keyHandler: IkeyHandlerProps;
27
+ }
28
+ }
29
+ }
30
+
31
+ declare module "@roku-sdk/solid/jsx-runtime" {
32
+ namespace JSX {
33
+ interface IntrinsicElements {
34
+ keyHandler: IkeyHandlerProps;
35
+ }
36
+ }
37
+ }
38
+
39
+ declare module "solid-js" {
40
+ namespace JSX {
41
+ interface IntrinsicElements {
42
+ keyHandler: IkeyHandlerProps;
43
+ }
44
+ }
45
+ }
@@ -0,0 +1,137 @@
1
+ ' Copyright (c) 2026 Roku, Inc.
2
+ ' SPDX-License-Identifier: MIT
3
+
4
+ sub Init()
5
+ ' The row the attached nextPanel was built for, and a select still waiting for its panel.
6
+ m.attachedIndex = -1
7
+ m.pendingSelectIndex = -1
8
+ m.forwardSuppressed = false
9
+ ' Read rather than assume the default, so this does not have to be kept in step with it.
10
+ m.savedSelectForward = m.top.selectButtonMovesPanelForward
11
+ m.observedList = invalid
12
+ m.top.observeField("change", "onChildrenChange")
13
+ handleChildren()
14
+ end sub
15
+
16
+ ' The app supplies nextPanel asynchronously, a render-thread hop after the list focus
17
+ ' moves, so in between it still holds the previous row's panel. Stop the built-in
18
+ ' forward move for as long as that is true. Clearing nextPanel instead would be
19
+ ' destructive: a ListPanel does not re-host a next panel once the field has been set
20
+ ' invalid, leaving the slot permanently empty.
21
+ sub suppressForward()
22
+ if m.forwardSuppressed then return
23
+ m.savedSelectForward = m.top.selectButtonMovesPanelForward
24
+ m.forwardSuppressed = true
25
+ m.top.selectButtonMovesPanelForward = false
26
+ end sub
27
+
28
+ sub restoreForward()
29
+ if not m.forwardSuppressed then return
30
+ m.forwardSuppressed = false
31
+ m.top.selectButtonMovesPanelForward = m.savedSelectForward
32
+ end sub
33
+
34
+ sub onListItemFocused()
35
+ if m.observedList = invalid then return
36
+ focused = m.observedList.itemFocused
37
+ ' Navigating away abandons a select that was still waiting for its panel.
38
+ if m.pendingSelectIndex >= 0 and focused <> m.pendingSelectIndex
39
+ m.pendingSelectIndex = -1
40
+ end if
41
+ if m.attachedIndex >= 0 and focused <> m.attachedIndex
42
+ if m.top.createNextPanelOnItemFocus
43
+ m.attachedIndex = -1
44
+ ' Focus-driven panels arrive per row; suppress until the matching child lands.
45
+ suppressForward()
46
+ else
47
+ ' Static next panel: one panel serves every row. Keep attachedIndex in sync so
48
+ ' Select is not blocked waiting for a per-row panel that never arrives.
49
+ m.attachedIndex = focused
50
+ end if
51
+ end if
52
+ end sub
53
+
54
+ ' Select on a row whose panel has not landed yet. The forward move is suppressed, so
55
+ ' remember the press rather than lose it and replay it once the panel arrives.
56
+ sub onListItemSelected()
57
+ if m.observedList = invalid then return
58
+ ' If the app-level setting already blocks forward, there is nothing to replay.
59
+ if not m.savedSelectForward then return
60
+ selected = m.observedList.itemSelected
61
+ if m.attachedIndex <> selected
62
+ ' Record the press only when we are in the suppression window (stale-panel swap in
63
+ ' progress) or when no panel exists yet (first panel still on its way). In both cases
64
+ ' the native Select cannot do the right thing; flushPendingSelect will replay it once
65
+ ' the correct panel arrives. For static panels with a valid nextPanel and no active
66
+ ' suppression, skip recording and let the native behaviour handle it.
67
+ if m.forwardSuppressed or m.top.nextPanel = invalid
68
+ m.pendingSelectIndex = selected
69
+ end if
70
+ end if
71
+ end sub
72
+
73
+ ' Replay a remembered select. The panel cannot be focused where it sits: nextPanel holds
74
+ ' it outside the tree, so setFocus alone is a no-op. Appending it to the PanelSet is what
75
+ ' performs the forward slide, the same move the suppressed Select would have made.
76
+ sub flushPendingSelect()
77
+ if m.pendingSelectIndex < 0 or m.pendingSelectIndex <> m.attachedIndex then return
78
+ ' Honour the app-level setting: if selectButtonMovesPanelForward was false before
79
+ ' suppression began, replaying the select must not slide the panel forward either.
80
+ if not m.savedSelectForward then return
81
+ np = m.top.nextPanel
82
+ if np = invalid then return
83
+ panelSet = m.top.getParent()
84
+ if panelSet = invalid or not panelSet.isSubtype("PanelSet") then return
85
+ m.pendingSelectIndex = -1
86
+ panelSet.appendChild(np)
87
+ np.setFocus(true)
88
+ end sub
89
+
90
+ ' Handle changes to the children of the managed list panel
91
+ sub onChildrenChange(msg as Object)
92
+ changeDta = msg.getData()
93
+ operation = changeDta.operation
94
+ handleChildren()
95
+ end sub
96
+
97
+ ' Depends on the list child being declared before the panel child: only the ArrayGrid branch
98
+ ' sets m.observedList, and the Panel branch needs it to learn which row the panel belongs to.
99
+ ' A consumer that puts the panel first would leave m.attachedIndex unset on the first pass, so
100
+ ' the stale-panel guard below would never arm. ListPanel documents the required child order.
101
+ sub handleChildren()
102
+ for c = 0 to m.top.getChildCount() - 1
103
+ child = m.top.getChild(c)
104
+ if child <> invalid
105
+ hasBeenAssigned = false
106
+ subtype = child.subtype()
107
+ if child.isSubtype("Panel")
108
+ m.top.nextPanel = child
109
+ m.top.removeChild(child)
110
+ if m.observedList <> invalid
111
+ ' A list that has not resolved a focused item yet reports -1, and
112
+ ' the first panel arrives in exactly that window. Storing -1 leaves
113
+ ' onListItemFocused unable to arm on the very first row change (it
114
+ ' skips while attachedIndex is negative), so the first Select after
115
+ ' the first Down is neither suppressed nor replayed — it is lost.
116
+ ' The panel that just arrived is row 0's: index 0 is what the app
117
+ ' was asked to build before the list reported any focus.
118
+ attachedRow = m.observedList.itemFocused
119
+ if attachedRow < 0 then attachedRow = 0
120
+ m.attachedIndex = attachedRow
121
+ restoreForward()
122
+ flushPendingSelect()
123
+ end if
124
+ hasBeenAssigned = true
125
+ else if child.isSubtype("ArrayGrid")
126
+ if not child.isSameNode(m.top.list)
127
+ m.top.list = child
128
+ m.observedList = child
129
+ ' Scoped so the callbacks resolve in this component, not the list's.
130
+ child.observeFieldScoped("itemFocused", "onListItemFocused")
131
+ child.observeFieldScoped("itemSelected", "onListItemSelected")
132
+ hasBeenAssigned = true
133
+ end if
134
+ end if
135
+ end if
136
+ end for
137
+ end sub
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!--
3
+ Copyright (c) 2026 Roku, Inc.
4
+ SPDX-License-Identifier: MIT
5
+ -->
6
+
7
+
8
+ <component name="managedListPanel" extends="ListPanel">
9
+ <script type="text/brightscript" uri="ManagedListPanel.brs" />
10
+ </component>
@@ -0,0 +1,37 @@
1
+ // Auto-generated TypeScript declarations for XML component import.
2
+ // DO NOT EDIT — this file is regenerated during build.
3
+ //
4
+ // Source component: managedListPanel
5
+ // Extends: ListPanel
6
+
7
+ import type { IListPanelProps } from "@roku-sdk/components";
8
+ import type { TypedXmlComponent } from "@roku-sdk/interfaces";
9
+
10
+ export interface ImanagedListPanelProps extends IListPanelProps {}
11
+
12
+ declare const _default: TypedXmlComponent<"managedListPanel", Record<string, never>>;
13
+ export default _default;
14
+
15
+ declare module "@roku-sdk/solid" {
16
+ namespace JSX {
17
+ interface IntrinsicElements {
18
+ managedListPanel: ImanagedListPanelProps;
19
+ }
20
+ }
21
+ }
22
+
23
+ declare module "@roku-sdk/solid/jsx-runtime" {
24
+ namespace JSX {
25
+ interface IntrinsicElements {
26
+ managedListPanel: ImanagedListPanelProps;
27
+ }
28
+ }
29
+ }
30
+
31
+ declare module "solid-js" {
32
+ namespace JSX {
33
+ interface IntrinsicElements {
34
+ managedListPanel: ImanagedListPanelProps;
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,105 @@
1
+ ' Copyright (c) 2026 Roku, Inc.
2
+ ' SPDX-License-Identifier: MIT
3
+
4
+ sub init()
5
+ m.dialog = invalid
6
+ m.dismissed = false
7
+ m.presented = false
8
+ m.prepared = []
9
+ end sub
10
+
11
+ sub onDialogChange()
12
+ m.dismissed = false
13
+ updateDialog()
14
+ end sub
15
+
16
+ sub onOpenChange()
17
+ if m.top.open then m.dismissed = false
18
+ updateDialog()
19
+ end sub
20
+
21
+ function sameDialog(left as Dynamic, right as Dynamic) as Boolean
22
+ if left = invalid or right = invalid then return false
23
+ return left.isSameNode(right)
24
+ end function
25
+
26
+ sub updateDialog()
27
+ if not m.top.mounted then
28
+ closeSession(true)
29
+ m.prepared = []
30
+ return
31
+ end if
32
+ scene = m.top.getScene()
33
+ if scene = invalid then return
34
+ prepareDialogs(scene)
35
+ if not m.top.open or m.top.dialog = invalid then
36
+ m.dismissed = true
37
+ if sameDialog(scene.dialog, m.dialog) then
38
+ m.dialog.close = true
39
+ else
40
+ closeSession(false)
41
+ end if
42
+ return
43
+ end if
44
+ dialog = m.top.dialog
45
+ if not m.top.ready then dialog = m.top.fallback
46
+ if dialog = invalid then
47
+ releaseDialog(true)
48
+ return
49
+ end if
50
+ if m.dismissed or sameDialog(m.dialog, dialog) then return
51
+ if scene.dialog <> invalid and not sameDialog(scene.dialog, m.dialog) and not m.top.replaceExisting then
52
+ m.dismissed = true
53
+ closeSession(false)
54
+ m.top.blocked = true
55
+ return
56
+ end if
57
+ releaseDialog(false)
58
+ m.dialog = dialog
59
+ dialog.observeFieldScopedEx("wasClosed", "onNativeClosed")
60
+ scene.dialog = dialog
61
+ m.presented = true
62
+ if m.top.ready and m.top.initialFocusId <> "" then
63
+ target = dialog.findNode(m.top.initialFocusId)
64
+ if target <> invalid then target.setFocus(true)
65
+ end if
66
+ if m.top.ready then m.top.opened = true
67
+ end sub
68
+
69
+ sub prepareDialogs(scene as Object)
70
+ for each old in m.prepared
71
+ if old <> invalid and not sameDialog(old, m.top.dialog) and not sameDialog(old, m.top.fallback) then
72
+ if sameDialog(old.getParent(), m.top) then m.top.removeChild(old)
73
+ end if
74
+ end for
75
+ m.prepared = [m.top.dialog, m.top.fallback]
76
+ for each dialog in m.prepared
77
+ if dialog <> invalid and not sameDialog(scene.dialog, dialog) then
78
+ if not sameDialog(dialog.getParent(), m.top) then m.top.appendChild(dialog)
79
+ end if
80
+ end for
81
+ end sub
82
+
83
+ sub onNativeClosed(event as Object)
84
+ if not sameDialog(m.dialog, event.getRoSGNode()) then return
85
+ m.dismissed = true
86
+ closeSession(false)
87
+ end sub
88
+
89
+ sub closeSession(closeNative as Boolean)
90
+ releaseDialog(closeNative)
91
+ if not m.presented then return
92
+ m.presented = false
93
+ m.top.wasClosed = true
94
+ end sub
95
+
96
+ sub releaseDialog(closeNative as Boolean)
97
+ dialog = m.dialog
98
+ if dialog = invalid then return
99
+ m.dialog = invalid
100
+ dialog.unobserveFieldScoped("wasClosed")
101
+ scene = dialog.getScene()
102
+ if closeNative and scene <> invalid then
103
+ if sameDialog(scene.dialog, dialog) then dialog.close = true
104
+ end if
105
+ end sub
@@ -0,0 +1,22 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!--
3
+ Copyright (c) 2026 Roku, Inc.
4
+ SPDX-License-Identifier: MIT
5
+ -->
6
+
7
+
8
+ <component name="modal" extends="Group">
9
+ <script type="text/brightscript" uri="Modal.brs" />
10
+ <interface>
11
+ <field id="dialog" type="node" onChange="onDialogChange" />
12
+ <field id="initialFocusId" type="string" />
13
+ <field id="open" type="boolean" value="true" onChange="onOpenChange" />
14
+ <field id="fallback" type="node" onChange="updateDialog" />
15
+ <field id="replaceExisting" type="boolean" value="true" />
16
+ <field id="ready" type="boolean" value="true" onChange="updateDialog" />
17
+ <field id="mounted" type="boolean" value="false" onChange="updateDialog" />
18
+ <field id="opened" type="boolean" alwaysNotify="true" />
19
+ <field id="wasClosed" type="boolean" alwaysNotify="true" />
20
+ <field id="blocked" type="boolean" alwaysNotify="true" />
21
+ </interface>
22
+ </component>
@@ -0,0 +1,54 @@
1
+ // Auto-generated TypeScript declarations for XML component import.
2
+ // DO NOT EDIT — this file is regenerated during build.
3
+ //
4
+ // Source component: modal
5
+ // Extends: Group
6
+
7
+ import type { IGroupProps } from "@roku-sdk/components";
8
+ import type { TypedXmlComponent } from "@roku-sdk/interfaces";
9
+
10
+ interface modalFields {
11
+ dialog: import("@roku-sdk/interfaces").DomNode;
12
+ initialFocusId: string;
13
+ /** @default "true" */
14
+ open: boolean;
15
+ fallback: import("@roku-sdk/interfaces").DomNode;
16
+ /** @default "true" */
17
+ replaceExisting: boolean;
18
+ /** @default "true" */
19
+ ready: boolean;
20
+ /** @default "false" */
21
+ mounted: boolean;
22
+ opened: boolean;
23
+ wasClosed: boolean;
24
+ blocked: boolean;
25
+ }
26
+
27
+ export interface ImodalProps extends IGroupProps, Partial<modalFields> {}
28
+
29
+ declare const _default: TypedXmlComponent<"modal", modalFields>;
30
+ export default _default;
31
+
32
+ declare module "@roku-sdk/solid" {
33
+ namespace JSX {
34
+ interface IntrinsicElements {
35
+ modal: ImodalProps;
36
+ }
37
+ }
38
+ }
39
+
40
+ declare module "@roku-sdk/solid/jsx-runtime" {
41
+ namespace JSX {
42
+ interface IntrinsicElements {
43
+ modal: ImodalProps;
44
+ }
45
+ }
46
+ }
47
+
48
+ declare module "solid-js" {
49
+ namespace JSX {
50
+ interface IntrinsicElements {
51
+ modal: ImodalProps;
52
+ }
53
+ }
54
+ }
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!--
3
+ Copyright (c) 2026 Roku, Inc.
4
+ SPDX-License-Identifier: MIT
5
+ -->
6
+
7
+
8
+
9
+ <component name="StandardDialogExt" extends="StandardDialog">
10
+ </component>
@@ -0,0 +1,37 @@
1
+ // Auto-generated TypeScript declarations for XML component import.
2
+ // DO NOT EDIT — this file is regenerated during build.
3
+ //
4
+ // Source component: StandardDialogExt
5
+ // Extends: StandardDialog
6
+
7
+ import type { IStandardDialogProps } from "@roku-sdk/components";
8
+ import type { TypedXmlComponent } from "@roku-sdk/interfaces";
9
+
10
+ export interface IStandardDialogExtProps extends IStandardDialogProps {}
11
+
12
+ declare const _default: TypedXmlComponent<"StandardDialogExt", Record<string, never>>;
13
+ export default _default;
14
+
15
+ declare module "@roku-sdk/solid" {
16
+ namespace JSX {
17
+ interface IntrinsicElements {
18
+ standardDialogExt: IStandardDialogExtProps;
19
+ }
20
+ }
21
+ }
22
+
23
+ declare module "@roku-sdk/solid/jsx-runtime" {
24
+ namespace JSX {
25
+ interface IntrinsicElements {
26
+ standardDialogExt: IStandardDialogExtProps;
27
+ }
28
+ }
29
+ }
30
+
31
+ declare module "solid-js" {
32
+ namespace JSX {
33
+ interface IntrinsicElements {
34
+ standardDialogExt: IStandardDialogExtProps;
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!--
3
+ Copyright (c) 2026 Roku, Inc.
4
+ SPDX-License-Identifier: MIT
5
+ -->
6
+
7
+
8
+
9
+ <component name="StandardKeyboardDialogExt" extends="StandardKeyboardDialog">
10
+ </component>
@@ -0,0 +1,37 @@
1
+ // Auto-generated TypeScript declarations for XML component import.
2
+ // DO NOT EDIT — this file is regenerated during build.
3
+ //
4
+ // Source component: StandardKeyboardDialogExt
5
+ // Extends: StandardKeyboardDialog
6
+
7
+ import type { IStandardKeyboardDialogProps } from "@roku-sdk/components";
8
+ import type { TypedXmlComponent } from "@roku-sdk/interfaces";
9
+
10
+ export interface IStandardKeyboardDialogExtProps extends IStandardKeyboardDialogProps {}
11
+
12
+ declare const _default: TypedXmlComponent<"StandardKeyboardDialogExt", Record<string, never>>;
13
+ export default _default;
14
+
15
+ declare module "@roku-sdk/solid" {
16
+ namespace JSX {
17
+ interface IntrinsicElements {
18
+ standardKeyboardDialogExt: IStandardKeyboardDialogExtProps;
19
+ }
20
+ }
21
+ }
22
+
23
+ declare module "@roku-sdk/solid/jsx-runtime" {
24
+ namespace JSX {
25
+ interface IntrinsicElements {
26
+ standardKeyboardDialogExt: IStandardKeyboardDialogExtProps;
27
+ }
28
+ }
29
+ }
30
+
31
+ declare module "solid-js" {
32
+ namespace JSX {
33
+ interface IntrinsicElements {
34
+ standardKeyboardDialogExt: IStandardKeyboardDialogExtProps;
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!--
3
+ Copyright (c) 2026 Roku, Inc.
4
+ SPDX-License-Identifier: MIT
5
+ -->
6
+
7
+
8
+
9
+ <component name="StandardMessageDialogExt" extends="StandardMessageDialog">
10
+ </component>
@@ -0,0 +1,37 @@
1
+ // Auto-generated TypeScript declarations for XML component import.
2
+ // DO NOT EDIT — this file is regenerated during build.
3
+ //
4
+ // Source component: StandardMessageDialogExt
5
+ // Extends: StandardMessageDialog
6
+
7
+ import type { IStandardMessageDialogProps } from "@roku-sdk/components";
8
+ import type { TypedXmlComponent } from "@roku-sdk/interfaces";
9
+
10
+ export interface IStandardMessageDialogExtProps extends IStandardMessageDialogProps {}
11
+
12
+ declare const _default: TypedXmlComponent<"StandardMessageDialogExt", Record<string, never>>;
13
+ export default _default;
14
+
15
+ declare module "@roku-sdk/solid" {
16
+ namespace JSX {
17
+ interface IntrinsicElements {
18
+ standardMessageDialogExt: IStandardMessageDialogExtProps;
19
+ }
20
+ }
21
+ }
22
+
23
+ declare module "@roku-sdk/solid/jsx-runtime" {
24
+ namespace JSX {
25
+ interface IntrinsicElements {
26
+ standardMessageDialogExt: IStandardMessageDialogExtProps;
27
+ }
28
+ }
29
+ }
30
+
31
+ declare module "solid-js" {
32
+ namespace JSX {
33
+ interface IntrinsicElements {
34
+ standardMessageDialogExt: IStandardMessageDialogExtProps;
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!--
3
+ Copyright (c) 2026 Roku, Inc.
4
+ SPDX-License-Identifier: MIT
5
+ -->
6
+
7
+
8
+
9
+ <component name="StandardPinPadDialogExt" extends="StandardPinPadDialog">
10
+ </component>
@@ -0,0 +1,37 @@
1
+ // Auto-generated TypeScript declarations for XML component import.
2
+ // DO NOT EDIT — this file is regenerated during build.
3
+ //
4
+ // Source component: StandardPinPadDialogExt
5
+ // Extends: StandardPinPadDialog
6
+
7
+ import type { IStandardPinPadDialogProps } from "@roku-sdk/components";
8
+ import type { TypedXmlComponent } from "@roku-sdk/interfaces";
9
+
10
+ export interface IStandardPinPadDialogExtProps extends IStandardPinPadDialogProps {}
11
+
12
+ declare const _default: TypedXmlComponent<"StandardPinPadDialogExt", Record<string, never>>;
13
+ export default _default;
14
+
15
+ declare module "@roku-sdk/solid" {
16
+ namespace JSX {
17
+ interface IntrinsicElements {
18
+ standardPinPadDialogExt: IStandardPinPadDialogExtProps;
19
+ }
20
+ }
21
+ }
22
+
23
+ declare module "@roku-sdk/solid/jsx-runtime" {
24
+ namespace JSX {
25
+ interface IntrinsicElements {
26
+ standardPinPadDialogExt: IStandardPinPadDialogExtProps;
27
+ }
28
+ }
29
+ }
30
+
31
+ declare module "solid-js" {
32
+ namespace JSX {
33
+ interface IntrinsicElements {
34
+ standardPinPadDialogExt: IStandardPinPadDialogExtProps;
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+ <!--
3
+ Copyright (c) 2026 Roku, Inc.
4
+ SPDX-License-Identifier: MIT
5
+ -->
6
+
7
+
8
+
9
+ <component name="StandardProgressDialogExt" extends="StandardProgressDialog">
10
+ </component>