@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,33 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { RemoteKeyName } from "@roku-sdk/interfaces";
5
+
6
+ import type { IGroupProps } from "./sg-nodes/group.props";
7
+ import type { EventHandler, JSX } from "./sg-nodes/types";
8
+
9
+ export interface CommonKeyHandlerProps extends IGroupProps {
10
+ onKeyEvent: EventHandlerKey;
11
+ children?: JSX.Element;
12
+ }
13
+
14
+ export interface IKeyHandlerData {
15
+ key: RemoteKeyName;
16
+ press: boolean;
17
+ }
18
+
19
+ export type EventHandlerKey = EventHandler<IKeyHandlerData>;
20
+
21
+ export interface ScopedKeyHandlerProps extends CommonKeyHandlerProps {
22
+ handleAllKeys?: false;
23
+ keys: RemoteKeyName[];
24
+ bubbleUnhandledKeys?: boolean;
25
+ }
26
+
27
+ export interface AllKeysKeyHandlerProps extends CommonKeyHandlerProps {
28
+ handleAllKeys: true;
29
+ keys?: never;
30
+ bubbleUnhandledKeys?: never;
31
+ }
32
+
33
+ export type IKeyHandlerProps = AllKeysKeyHandlerProps | ScopedKeyHandlerProps;
@@ -0,0 +1,24 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { IKeyHandlerProps } from "./key-handler.props";
5
+ export type { CommonKeyHandlerProps } from "./key-handler.props";
6
+
7
+ export type {
8
+ IKeyHandlerData,
9
+ EventHandlerKey,
10
+ ScopedKeyHandlerProps,
11
+ AllKeysKeyHandlerProps,
12
+ IKeyHandlerProps
13
+ } from "./key-handler.props";
14
+
15
+ import { retainAsset } from "./retain-asset";
16
+ import { Component } from "./types";
17
+ import KeyHandlerXML from "./xml-components/keyhandler/KeyHandler.xml";
18
+
19
+ // Only allow either 'handleAllKeys' or ('keys' and 'bubbleUnhandledKeys'), not both
20
+
21
+ export const KeyHandler: Component<IKeyHandlerProps> = props => {
22
+ retainAsset(KeyHandlerXML);
23
+ return <key-handler {...props}>{props.children}</key-handler>;
24
+ };
@@ -0,0 +1,38 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { IGroupProps } from "./sg-nodes/group.props";
5
+ import type { EventHandler, JSX } from "./sg-nodes/types";
6
+
7
+ export interface IModalLifecycleProps {
8
+ /** Present the dialog. False prepares its children without taking focus. @default true */
9
+ open?: boolean;
10
+ /** Prepare the dialog while showing fallback, without granting it focus. @default true */
11
+ ready?: boolean;
12
+ /** Native dialog shown while ready=false; use a standardDialog intrinsic, not another Modal. */
13
+ fallback?: JSX.Element;
14
+ /** Allow replacing another native modal. False reports onBlocked instead. @default true */
15
+ replaceExisting?: boolean;
16
+ /** Fired after native attachment and initial focus, not after artwork has drawn. */
17
+ onOpened?: EventHandler<void>;
18
+ /** Fired at most once per presented lifetime while mounted, including native dismissal and open=false. */
19
+ onWasClosed?: EventHandler<void>;
20
+ /** Another native dialog prevented presentation. Toggle open to retry explicitly. */
21
+ onBlocked?: EventHandler<void>;
22
+ /** ID of the child that receives focus when the dialog opens. */
23
+ initialFocusId?: string;
24
+ }
25
+
26
+ /**
27
+ * Props for the custom Modal XML component.
28
+ *
29
+ * Intentionally does not derive from `JSX.IntrinsicElements["modal"]` — that tag is
30
+ * declared as `IModalProps` in jsx.d.ts, so referencing the intrinsic here would create
31
+ * a circular type.
32
+ */
33
+ export interface IModalProps extends IGroupProps, IModalLifecycleProps {
34
+ dialog?: JSX.Element;
35
+ }
36
+
37
+ /** @deprecated Use {@link IModalProps}. Kept for call-site casts onto the native modal tag. */
38
+ export type ModalIntrinsicProps = IModalProps;
@@ -0,0 +1,41 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ import type { DomNode } from "@roku-sdk/interfaces";
5
+ import { createMemo, onCleanup, onMount, setProp, splitProps } from "@roku-sdk/solid";
6
+
7
+ import type { IModalProps } from "./modal-dialog.props";
8
+ import { retainAsset } from "./retain-asset";
9
+ import { Component } from "./types";
10
+ import ModalXML from "./xml-components/modal/Modal.xml";
11
+ export type { ModalIntrinsicProps, IModalProps, IModalLifecycleProps } from "./modal-dialog.props";
12
+
13
+ export const modalPropKeys = [
14
+ "initialFocusId",
15
+ "open",
16
+ "ready",
17
+ "fallback",
18
+ "replaceExisting",
19
+ "onOpened",
20
+ "onWasClosed",
21
+ "onBlocked"
22
+ ] as const;
23
+
24
+ export const Modal: Component<IModalProps> = (props: IModalProps) => {
25
+ retainAsset(ModalXML);
26
+ // JSX node getters must not reconstruct their subtrees when lifecycle props change.
27
+ const [content, rest] = splitProps(props, ["dialog", "fallback"]);
28
+ const dialog = createMemo(() => content.dialog);
29
+ const fallback = createMemo(() => content.fallback);
30
+ const element = <modal {...rest} dialog={dialog()} fallback={fallback()} visible={false} />;
31
+ const node = element as unknown as DomNode;
32
+ // Present only after the wrapper and all node-valued children have been attached.
33
+ onMount(() => setProp(node, "mounted", true));
34
+ onCleanup(() => {
35
+ setProp(node, "mounted", false);
36
+ // Node-valued props are not ordinary children; retire their observers explicitly.
37
+ setProp(node, "dialog", null, dialog());
38
+ setProp(node, "fallback", null, fallback());
39
+ });
40
+ return element;
41
+ };
@@ -0,0 +1,24 @@
1
+ // Copyright (c) 2026 Roku, Inc.
2
+ // SPDX-License-Identifier: MIT
3
+
4
+ /**
5
+ * Keeps an imported asset live when its component survives tree-shaking.
6
+ *
7
+ * The asset import plugin uses esbuild's metafile to copy only assets referenced
8
+ * by bundled modules. This function is a no-op at runtime; its only job is to
9
+ * create a reference esbuild can see so TypeScript/esbuild does not elide the
10
+ * asset's import binding as unused.
11
+ *
12
+ * Call this inside the component function, not at module scope. Placement matters
13
+ * when a module exports more than one component: a module-scope reference keeps
14
+ * the asset alive whenever the module is loaded, even if the specific component
15
+ * export is dead-code-eliminated. Keeping the reference in the component body
16
+ * ties the asset to that export, so the two are removed together.
17
+ *
18
+ * Do NOT place this inside `createEffect`, `onMount`, or other lazy closures. The
19
+ * asset copies unconditionally once the module-scope import survives DCE, so a
20
+ * lazy call site would be misleading without changing packaging behavior.
21
+ */
22
+ export function retainAsset(asset: unknown): void {
23
+ void asset;
24
+ }