@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
package/src/tween.tsx ADDED
@@ -0,0 +1,173 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import { type DomNode } from "@roku-sdk/interfaces";
5
+ import { type Component, createEffect, onCleanup, tmTransaction, untrack } from "@roku-sdk/solid";
6
+
7
+ import type { AnimationState } from "./sg-nodes/animation.props";
8
+ import type { ITweenProps } from "./sg-nodes/tween.props";
9
+ import type { Vector2D } from "./sg-nodes/types";
10
+
11
+ declare const __DEV__: boolean;
12
+
13
+ /**
14
+ * Unified `<tween>` primitive.
15
+ *
16
+ * Animate a target node using the unified native field contract.
17
+ *
18
+ * One component presenting the unified tween field contract, replacing the four earlier
19
+ * tween wrappers (`Tween`/GridTween, `TweenFloat`, `FloatTween`, `ScaleTween`). On device
20
+ * it renders a `<tween>` element, which is the firmware's native node when
21
+ * `roku.hasFeature("tween")` reports support. Otherwise `@roku-sdk/compat` aliases the tag
22
+ * to its `RsgTweenShim`; without compat creating it throws an error naming the missing feature. A renderer that
23
+ * provides its own tween implementation aliases this module to it at build time.
24
+ */
25
+ export interface TweenProps extends Omit<ITweenProps, "targetNode" | "onAnimationState"> {
26
+ /** Node reference to animate, or a getter returning it. Takes precedence over targetRef. */
27
+ targetNode?: unknown | (() => unknown);
28
+ /** @deprecated Use targetNode. Retained for one minor release. */
29
+ targetRef?: unknown | (() => unknown);
30
+ /** Called with separate state and value arguments, unlike the intrinsic's tuple event. */
31
+ onAnimationState?: (state: AnimationState, value: number | Vector2D) => void;
32
+ }
33
+
34
+ let tweenIdCounter = 0;
35
+
36
+ /** Fields the dev-only `proposedStops` shape check knows to be vector2d. */
37
+ const VECTOR_FIELDS: ReadonlySet<string> = new Set(["translation", "scale", "scaleRotateCenter"]);
38
+ /** Fields the dev-only `proposedStops` shape check knows to be float. */
39
+ const FLOAT_FIELDS: ReadonlySet<string> = new Set(["opacity", "width", "height", "rotation"]);
40
+
41
+ /**
42
+ * Dev-only: describe each way `proposedStops` (and `axis`) does not match the shape the field
43
+ * and axis call for. Returns `[key, message]` pairs, where `key` names the distinct problem so a
44
+ * caller can report each one once. A field outside the known lists is not checked.
45
+ *
46
+ * The expected shapes: float fields, and `axis` `"x"` / `"y"` on a vector field, take
47
+ * `number[]`; `axis` `"all"` (the default) on a vector field takes `[number, number][]`; `axis`
48
+ * is ignored on float fields.
49
+ */
50
+ function proposedStopsShapeProblems(
51
+ field: string,
52
+ axis: string | undefined,
53
+ stops: readonly unknown[] | undefined
54
+ ): [key: string, message: string][] {
55
+ const problems: [string, string][] = [];
56
+ const list = Array.isArray(stops) ? stops : [];
57
+ if (VECTOR_FIELDS.has(field)) {
58
+ if (axis === "x" || axis === "y") {
59
+ if (list.some(stop => Array.isArray(stop))) {
60
+ problems.push([
61
+ `${axis}:array`,
62
+ `Tween: proposedStops on "${field}" with axis "${axis}" must be scalars (the ${axis} coordinate); got an array. Array entries are skipped.`
63
+ ]);
64
+ }
65
+ } else {
66
+ const shown = axis ?? "all";
67
+ if (list.some(stop => !Array.isArray(stop))) {
68
+ problems.push([
69
+ "all:scalar",
70
+ `Tween: proposedStops on "${field}" with axis "${shown}" must be [x, y] pairs; got a scalar. Scalar entries are skipped.`
71
+ ]);
72
+ }
73
+ const wrongLength = list.find(stop => Array.isArray(stop) && stop.length !== 2) as unknown[] | undefined;
74
+ if (wrongLength) {
75
+ problems.push([
76
+ "all:length",
77
+ `Tween: proposedStops on "${field}" with axis "${shown}" must be [x, y] pairs; got an array of length ${wrongLength.length}. Entries that are not pairs are skipped.`
78
+ ]);
79
+ }
80
+ }
81
+ } else if (FLOAT_FIELDS.has(field)) {
82
+ if (axis !== undefined) {
83
+ problems.push(["float:axis", `Tween: axis "${axis}" is ignored on float field "${field}"; remove it.`]);
84
+ }
85
+ if (list.some(stop => Array.isArray(stop))) {
86
+ problems.push([
87
+ "float:array",
88
+ `Tween: proposedStops on float field "${field}" must be numbers; got an array. Array entries are skipped.`
89
+ ]);
90
+ }
91
+ }
92
+ return problems;
93
+ }
94
+
95
+ const resolveTarget = (targetRef: unknown | (() => unknown)): unknown =>
96
+ typeof targetRef === "function" ? (targetRef as () => unknown)() : targetRef;
97
+
98
+ export const Tween: Component<TweenProps> = props => {
99
+ const animationId = `tweenAnim_${props.id ?? ""}_${tweenIdCounter++}`;
100
+ const field = props.field ?? "translation";
101
+
102
+ let tweenRef: unknown;
103
+ let boundTarget: unknown;
104
+
105
+ const bindTarget = (target: unknown): void => {
106
+ if (tweenRef == null || target == null || target === boundTarget) return;
107
+ boundTarget = target;
108
+ tmTransaction.setProperty(tweenRef as DomNode, "targetNode", target as DomNode, undefined);
109
+ };
110
+
111
+ // A trigger fires on whatever node is bound when it lands, so a target switched in the
112
+ // same update as a trigger has to be written first, whichever effect runs first.
113
+ const withTarget = <V,>(value: V): V => {
114
+ bindTarget(untrack(() => resolveTarget(props.targetNode ?? props.targetRef)));
115
+ return value;
116
+ };
117
+
118
+ // Keep the node's targetNode bound to the current ref (parents may populate a ref after
119
+ // mount, and pooled nodes are recycled onto new cells).
120
+ createEffect(function syncTargetNodeEffect() {
121
+ bindTarget(resolveTarget(props.targetNode ?? props.targetRef));
122
+ });
123
+
124
+ // The node and its target reference each other on the render thread, so a disposed tween
125
+ // still holding the target keeps its whole subtree alive. `prev` stays undefined: a node
126
+ // passed as `prev` is queued for removal.
127
+ onCleanup(() => {
128
+ if (tweenRef == null) return;
129
+ tmTransaction.setProperty(tweenRef as DomNode, "targetNode", null as unknown as DomNode, undefined);
130
+ tweenRef = undefined;
131
+ boundTarget = undefined;
132
+ });
133
+
134
+ // Dev-only: warn when proposedStops (or axis) does not have the shape the field and axis
135
+ // call for, once per distinct problem per instance. DCE'd when __DEV__ is false.
136
+ if (typeof __DEV__ !== "undefined" && __DEV__) {
137
+ const warned = new Set<string>();
138
+ createEffect(function checkProposedStopsShapeEffect() {
139
+ for (const [key, message] of proposedStopsShapeProblems(field, props.axis, props.proposedStops)) {
140
+ if (warned.has(key)) continue;
141
+ warned.add(key);
142
+ console.warn(message);
143
+ }
144
+ });
145
+ }
146
+
147
+ const bindTween = (el: unknown): void => {
148
+ tweenRef = el;
149
+ bindTarget(resolveTarget(props.targetNode ?? props.targetRef));
150
+ };
151
+ const onAnimationState = ([state, value]: [AnimationState, number | Vector2D]): void => {
152
+ props.onAnimationState?.(state, value);
153
+ };
154
+
155
+ return (
156
+ <tween
157
+ ref={bindTween}
158
+ id={`tween-${animationId}`}
159
+ field={field}
160
+ duration={props.duration ?? 0.333}
161
+ easeFunction={props.easeFunction ?? "outCubic"}
162
+ axis={props.axis ?? "all"}
163
+ preserveOther={props.preserveOther ?? 0}
164
+ targetValue={withTarget(props.targetValue)}
165
+ targetVector={withTarget(props.targetVector)}
166
+ proposedStops={withTarget(props.proposedStops)}
167
+ control={withTarget(props.control)}
168
+ onAnimationStart={props.onAnimationStart}
169
+ onAnimationStop={props.onAnimationStop}
170
+ onAnimationState={props.onAnimationState ? onAnimationState : undefined}
171
+ />
172
+ );
173
+ };
package/src/types.ts ADDED
@@ -0,0 +1,8 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ export * from "./sg-nodes/types";
5
+
6
+ export type MediaControl = "none" | "play" | "pause" | "stop" | "resume" | "replay" | "prebuffer" | "skipcontent";
7
+
8
+ export type MediaState = "none" | "buffering" | "playing" | "paused" | "stopping" | "stopped" | "finished" | "error";
@@ -0,0 +1,13 @@
1
+ Sub onUriChanged()
2
+ top = m.top
3
+ poster = top.poster
4
+
5
+ poster.uri = top.uri
6
+ End Sub
7
+
8
+ Sub onBlendColorChanged()
9
+ top = m.top
10
+ poster = top.poster
11
+
12
+ poster.blendColor = top.blendColor
13
+ End Sub
@@ -0,0 +1,10 @@
1
+ <?xml version="1.0" encoding="utf-8"?>
2
+
3
+ <component name="BlendedBusySpinner" extends="BusySpinner">
4
+ <script type="text/brightscript" uri="BlendedBusySpinner.brs" />
5
+ <interface>
6
+ <field id="uri" type="string" onChange="onUriChanged" />
7
+ <field id="blendColor" type="string" onChange="onBlendColorChanged" />
8
+ </interface>
9
+
10
+ </component>
@@ -0,0 +1,42 @@
1
+ // Auto-generated TypeScript declarations for XML component import.
2
+ // DO NOT EDIT — this file is regenerated during build.
3
+ //
4
+ // Source component: BlendedBusySpinner
5
+ // Extends: BusySpinner
6
+
7
+ import type { IBusySpinnerProps } from "@roku-sdk/components";
8
+ import type { TypedXmlComponent } from "@roku-sdk/interfaces";
9
+
10
+ interface BlendedBusySpinnerFields {
11
+ uri: string;
12
+ blendColor: string;
13
+ }
14
+
15
+ export interface IBlendedBusySpinnerProps extends IBusySpinnerProps, Partial<BlendedBusySpinnerFields> {}
16
+
17
+ declare const _default: TypedXmlComponent<"BlendedBusySpinner", BlendedBusySpinnerFields>;
18
+ export default _default;
19
+
20
+ declare module "@roku-sdk/solid" {
21
+ namespace JSX {
22
+ interface IntrinsicElements {
23
+ blendedBusySpinner: IBlendedBusySpinnerProps;
24
+ }
25
+ }
26
+ }
27
+
28
+ declare module "@roku-sdk/solid/jsx-runtime" {
29
+ namespace JSX {
30
+ interface IntrinsicElements {
31
+ blendedBusySpinner: IBlendedBusySpinnerProps;
32
+ }
33
+ }
34
+ }
35
+
36
+ declare module "solid-js" {
37
+ namespace JSX {
38
+ interface IntrinsicElements {
39
+ blendedBusySpinner: IBlendedBusySpinnerProps;
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,26 @@
1
+ ' Copyright (c) 2026 Roku, Inc.
2
+ ' SPDX-License-Identifier: MIT
3
+
4
+ sub init()
5
+ m.top.BoundsChange = m.top.boundingRect()
6
+ m.top.observeField("change", "onChange")
7
+ m.top.observeField("doMeasure", "doMeasure")
8
+ end sub
9
+
10
+ sub onChange()
11
+ setBoundingRect()
12
+ end sub
13
+
14
+ sub doMeasure(msg as Object)
15
+ data = msg.getData()
16
+ if data = true
17
+ setBoundingRect()
18
+ end if
19
+ end sub
20
+
21
+ sub setBoundingRect()
22
+ rect = m.top.boundingRect()
23
+ if rect.x <> m.top.BoundsChange.x or rect.y <> m.top.BoundsChange.y or rect.width <> m.top.BoundsChange.width or rect.height <> m.top.BoundsChange.height then
24
+ m.top.BoundsChange = rect
25
+ end if
26
+ end sub
@@ -0,0 +1,14 @@
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="bounding-tracker" extends="Group" focusable="true">
9
+ <script type="text/brightscript" uri="BoundingTracker.brs" />
10
+ <interface>
11
+ <field id="BoundsChange" type="assocarray" />
12
+ <field id="doMeasure" type="bool" />
13
+ </interface>
14
+ </component>
@@ -0,0 +1,42 @@
1
+ // Auto-generated TypeScript declarations for XML component import.
2
+ // DO NOT EDIT — this file is regenerated during build.
3
+ //
4
+ // Source component: bounding-tracker
5
+ // Extends: Group
6
+
7
+ import type { IGroupProps } from "@roku-sdk/components";
8
+ import type { TypedXmlComponent } from "@roku-sdk/interfaces";
9
+
10
+ interface boundingTrackerFields {
11
+ BoundsChange: Record<string, unknown>;
12
+ doMeasure: boolean;
13
+ }
14
+
15
+ export interface IboundingTrackerProps extends IGroupProps, Partial<boundingTrackerFields> {}
16
+
17
+ declare const _default: TypedXmlComponent<"bounding-tracker", boundingTrackerFields>;
18
+ export default _default;
19
+
20
+ declare module "@roku-sdk/solid" {
21
+ namespace JSX {
22
+ interface IntrinsicElements {
23
+ boundingTracker: IboundingTrackerProps;
24
+ }
25
+ }
26
+ }
27
+
28
+ declare module "@roku-sdk/solid/jsx-runtime" {
29
+ namespace JSX {
30
+ interface IntrinsicElements {
31
+ boundingTracker: IboundingTrackerProps;
32
+ }
33
+ }
34
+ }
35
+
36
+ declare module "solid-js" {
37
+ namespace JSX {
38
+ interface IntrinsicElements {
39
+ boundingTracker: IboundingTrackerProps;
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,159 @@
1
+ ' Copyright (c) 2026 Roku, Inc.
2
+ ' SPDX-License-Identifier: MIT
3
+
4
+ Sub init()
5
+ m.top.observeField("userData", "updateUserData")
6
+ m.top.observeField("userRegionData", "updateUserRegionData")
7
+ m.top.observeField("requestedUserDataInfoObject", "updateRequestedUserDataInfo")
8
+ m.top.observeField("storeChannelCredDataStatus", "updateChannelCredDataStatus")
9
+ m.top.observeField("channelCred", "updateChannelCred")
10
+ m.top.observeField("catalog", "updateCatalog")
11
+ m.top.observeField("order", "updateOrder")
12
+ m.top.observeField("orderStatus", "updateOrderStatus")
13
+ m.top.observeField("purchases", "updatePurchases")
14
+ m.top.observeField("requestPartnerOrderObject", "updateRequestPartnerOrder")
15
+ m.top.observeField("requestPartnerOrderStatus", "updateRequestPartnerOrderStatus")
16
+ m.top.observeField("confirmPartnerOrderObject", "updateConfirmPartnerOrder")
17
+ m.top.observeField("confirmPartnerOrderStatus", "updateConfirmPartnerOrderStatus")
18
+ m.top.observeField("deviceAttestationToken", "updateDeviceAttestationToken")
19
+ end Sub
20
+
21
+ sub updateUserData()
22
+ userData = m.top.userData
23
+ if userData <> invalid
24
+ m.top.userDataObject = m.top.userData.getFields()
25
+ else
26
+ m.top.userDataObject = {}
27
+ end if
28
+ end sub
29
+
30
+ sub updateUserRegionData()
31
+ userRegionData = m.top.userRegionData
32
+ if userRegionData <> invalid
33
+ m.top.userRegionDataObject = m.top.userRegionData.getFields()
34
+ else
35
+ m.top.userRegionDataObject = {}
36
+ end if
37
+ end sub
38
+
39
+ sub updateRequestedUserDataInfo()
40
+ cn = CreateObject("roSGNode","ContentNode")
41
+ cn.Update(m.top.requestedUserDataInfoObject, true)
42
+ m.top.requestedUserDataInfo = cn
43
+ end sub
44
+
45
+ sub updateChannelCredDataStatus()
46
+ storeChannelCredDataStatus = m.top.storeChannelCredDataStatus
47
+ if storeChannelCredDataStatus <> invalid
48
+ m.top.storeChannelCredDataStatusObject = m.top.storeChannelCredDataStatus.getFields()
49
+ else
50
+ m.top.storeChannelCredDataStatusObject = {}
51
+ end if
52
+ end sub
53
+
54
+ sub updateChannelCred()
55
+ channelCred = m.top.channelCred
56
+ if channelCred <> invalid
57
+ m.top.channelCredObject = m.top.channelCred.getFields()
58
+ else
59
+ m.top.channelCredObject = {}
60
+ end if
61
+ end sub
62
+
63
+ sub updateCatalog()
64
+ catalog = m.top.catalog
65
+ if catalog <> invalid
66
+ result = []
67
+ products = catalog.getChildren(-1, 0)
68
+ for each product in products
69
+ result.push(product.getFields())
70
+ end for
71
+ m.top.catalogObject = result
72
+ else
73
+ m.top.catalogObject = []
74
+ end if
75
+ end sub
76
+
77
+ sub updateOrder()
78
+ order = m.top.orderObject
79
+ cn = CreateObject("roSGNode","ContentNode")
80
+ for each item in order
81
+ itemCn = cn.appendChild("ContentNode")
82
+ itemCn.Update(item, true)
83
+ end for
84
+ m.top.order = cn
85
+ end sub
86
+
87
+ sub updateOrderStatus()
88
+ orderStatus = m.top.orderStatus
89
+ if orderStatus <> invalid
90
+ m.top.orderStatusObject = orderStatus.getFields()
91
+
92
+ orderItems = []
93
+ items = orderStatus.getChildren(-1, 0)
94
+ for each item in items
95
+ orderItems.push(item.getFields())
96
+ end for
97
+ m.top.orderItemsStatusObject = orderItems
98
+ else
99
+ m.top.orderItemsStatusObject = []
100
+ end if
101
+ end sub
102
+
103
+ sub updatePurchases()
104
+ purchases = m.top.purchases
105
+ if purchases <> invalid
106
+ m.top.purchasesStatusObject = purchases.getFields()
107
+
108
+ purchaseItems = []
109
+ items = purchases.getChildren(-1, 0)
110
+ for each item in items
111
+ purchaseItems.push(item.getFields())
112
+ end for
113
+ m.top.purchasesObject = purchaseItems
114
+ else
115
+ m.top.purchasesStatusObject = {}
116
+ m.top.purchasesObject = []
117
+ end if
118
+ end sub
119
+
120
+ sub updateRequestPartnerOrder()
121
+ partnerOrder = m.top.requestPartnerOrderObject
122
+ cn = CreateObject("roSGNode","ContentNode")
123
+ cn.Update(partnerOrder, true)
124
+ m.top.requestPartnerOrder = cn
125
+ end sub
126
+
127
+ sub updateRequestPartnerOrderStatus()
128
+ partnerOrderStatus = m.top.requestPartnerOrderStatus
129
+ if partnerOrderStatus <> invalid
130
+ m.top.requestPartnerOrderStatusObject = partnerOrderStatus.getFields()
131
+ else
132
+ m.top.requestPartnerOrderStatusObject = {}
133
+ end if
134
+ end sub
135
+
136
+ sub updateConfirmPartnerOrder()
137
+ partnerOrder = m.top.confirmPartnerOrderObject
138
+ cn = CreateObject("roSGNode","ContentNode")
139
+ cn.Update(partnerOrder, true)
140
+ m.top.confirmPartnerOrder = cn
141
+ end sub
142
+
143
+ sub updateConfirmPartnerOrderStatus()
144
+ partnerOrderStatus = m.top.confirmPartnerOrderStatus
145
+ if partnerOrderStatus <> invalid
146
+ m.top.confirmPartnerOrderStatusObject = partnerOrderStatus.getFields()
147
+ else
148
+ m.top.confirmPartnerOrderStatusObject = {}
149
+ end if
150
+ end sub
151
+
152
+ sub updateDeviceAttestationToken()
153
+ deviceAttestationToken = m.top.deviceAttestationToken
154
+ if deviceAttestationToken <> invalid
155
+ m.top.deviceAttestationTokenObject = deviceAttestationToken.getFields()
156
+ else
157
+ m.top.deviceAttestationTokenObject = {}
158
+ end if
159
+ end sub
@@ -0,0 +1,29 @@
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="channelStoreExt" extends="ChannelStore" focusable="false">
9
+ <script type="text/brightscript" uri="channelStoreExt.brs" />
10
+ <interface>
11
+ <field id="userDataObject" type="assocarray" />
12
+ <field id="userRegionDataObject" type="assocarray" />
13
+ <field id="requestedUserDataInfoObject" type="assocarray" />
14
+ <field id="storeChannelCredDataStatusObject" type="assocarray" />
15
+ <field id="channelCredObject" type="assocarray" />
16
+ <field id="catalogObject" type="array" />
17
+ <field id="orderObject" type="array" />
18
+ <field id="deltaOrderObject" type="assocarray" />
19
+ <field id="orderStatusObject" type="assocarray" />
20
+ <field id="orderItemsStatusObject" type="array" />
21
+ <field id="purchasesStatusObject" type="assocarray" />
22
+ <field id="purchasesObject" type="array" />
23
+ <field id="requestPartnerOrderObject" type="assocarray" />
24
+ <field id="requestPartnerOrderStatusObject" type="assocarray" />
25
+ <field id="confirmPartnerOrderObject" type="assocarray" />
26
+ <field id="confirmPartnerOrderStatusObject" type="assocarray" />
27
+ <field id="deviceAttestationTokenObject" type="assocarray" />
28
+ </interface>
29
+ </component>
@@ -0,0 +1,57 @@
1
+ // Auto-generated TypeScript declarations for XML component import.
2
+ // DO NOT EDIT — this file is regenerated during build.
3
+ //
4
+ // Source component: channelStoreExt
5
+ // Extends: ChannelStore
6
+
7
+ import type { IChannelStoreProps } from "@roku-sdk/components";
8
+ import type { TypedXmlComponent } from "@roku-sdk/interfaces";
9
+
10
+ interface channelStoreExtFields {
11
+ userDataObject: Record<string, unknown>;
12
+ userRegionDataObject: Record<string, unknown>;
13
+ requestedUserDataInfoObject: Record<string, unknown>;
14
+ storeChannelCredDataStatusObject: Record<string, unknown>;
15
+ channelCredObject: Record<string, unknown>;
16
+ catalogObject: unknown[];
17
+ orderObject: unknown[];
18
+ deltaOrderObject: Record<string, unknown>;
19
+ orderStatusObject: Record<string, unknown>;
20
+ orderItemsStatusObject: unknown[];
21
+ purchasesStatusObject: Record<string, unknown>;
22
+ purchasesObject: unknown[];
23
+ requestPartnerOrderObject: Record<string, unknown>;
24
+ requestPartnerOrderStatusObject: Record<string, unknown>;
25
+ confirmPartnerOrderObject: Record<string, unknown>;
26
+ confirmPartnerOrderStatusObject: Record<string, unknown>;
27
+ deviceAttestationTokenObject: Record<string, unknown>;
28
+ }
29
+
30
+ export interface IchannelStoreExtProps extends IChannelStoreProps, Partial<channelStoreExtFields> {}
31
+
32
+ declare const _default: TypedXmlComponent<"channelStoreExt", channelStoreExtFields>;
33
+ export default _default;
34
+
35
+ declare module "@roku-sdk/solid" {
36
+ namespace JSX {
37
+ interface IntrinsicElements {
38
+ channelStoreExt: IchannelStoreExtProps;
39
+ }
40
+ }
41
+ }
42
+
43
+ declare module "@roku-sdk/solid/jsx-runtime" {
44
+ namespace JSX {
45
+ interface IntrinsicElements {
46
+ channelStoreExt: IchannelStoreExtProps;
47
+ }
48
+ }
49
+ }
50
+
51
+ declare module "solid-js" {
52
+ namespace JSX {
53
+ interface IntrinsicElements {
54
+ channelStoreExt: IchannelStoreExtProps;
55
+ }
56
+ }
57
+ }