@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.
- package/BREAKING_CHANGES.md +84 -0
- package/LICENSE +21 -0
- package/README.md +19 -2
- package/core-jsx.d.ts +53 -0
- package/eslint.config.mjs +3 -0
- package/jsx.d.ts +273 -0
- package/package.json +84 -3
- package/src/__tests__/container.test.tsx +150 -0
- package/src/__tests__/glyphs.test.ts +202 -0
- package/src/__tests__/modal-boundary-export.test.ts +12 -0
- package/src/__tests__/native-modal.test.tsx +224 -0
- package/src/__tests__/tween-release.test.tsx +125 -0
- package/src/__tests__/tween-stops-shape.test.tsx +165 -0
- package/src/__tests__/tween-without-compat.test.tsx +64 -0
- package/src/__tests__/tween.test.tsx +195 -0
- package/src/blended-busy-spinner.props.ts +37 -0
- package/src/blended-busy-spinner.tsx +13 -0
- package/src/bounding-tracker.props.ts +18 -0
- package/src/bounding-tracker.tsx +13 -0
- package/src/button-row.tsx +126 -0
- package/src/channel-store.props.ts +425 -0
- package/src/channel-store.tsx +76 -0
- package/src/container.tsx +130 -0
- package/src/core/jsx-runtime.ts +39 -0
- package/src/focusable-group.props.ts +8 -0
- package/src/focusable-group.tsx +17 -0
- package/src/focusable.props.ts +14 -0
- package/src/focusable.tsx +17 -0
- package/src/glyphs.ts +116 -0
- package/src/helpers/index.tsx +4 -0
- package/src/helpers/resolution-context.tsx +68 -0
- package/src/helpers/scale-for-device-resolution.ts +31 -0
- package/src/index.tsx +70 -0
- package/src/jsx-props.ts +87 -0
- package/src/kdfs.d.ts +14 -0
- package/src/kdfs.ts +15 -0
- package/src/key-handler.props.ts +33 -0
- package/src/key-handler.tsx +24 -0
- package/src/modal-dialog.props.ts +38 -0
- package/src/modal-dialog.tsx +41 -0
- package/src/retain-asset.ts +24 -0
- package/src/sg-intrinsics.json +1153 -0
- package/src/sg-nodes/__tests__/__snapshots__/font.test.tsx.snap +13 -0
- package/src/sg-nodes/__tests__/__snapshots__/prop-forwarding.test.tsx.snap +4409 -0
- package/src/sg-nodes/__tests__/core-props.test.ts +301 -0
- package/src/sg-nodes/__tests__/font.test.tsx +141 -0
- package/src/sg-nodes/__tests__/imperative-methods.test.ts +268 -0
- package/src/sg-nodes/__tests__/prop-forwarding.test.tsx +1049 -0
- package/src/sg-nodes/__tests__/solid-integration.test.tsx +719 -0
- package/src/sg-nodes/animated-image.props.ts +64 -0
- package/src/sg-nodes/animated-image.tsx +23 -0
- package/src/sg-nodes/animation.props.ts +292 -0
- package/src/sg-nodes/animation.tsx +190 -0
- package/src/sg-nodes/array-grid.ts +602 -0
- package/src/sg-nodes/audio.props.ts +302 -0
- package/src/sg-nodes/audio.tsx +57 -0
- package/src/sg-nodes/busy-spinner.props.ts +59 -0
- package/src/sg-nodes/busy-spinner.tsx +84 -0
- package/src/sg-nodes/button-group.props.ts +141 -0
- package/src/sg-nodes/button-group.tsx +30 -0
- package/src/sg-nodes/button.props.ts +119 -0
- package/src/sg-nodes/button.tsx +31 -0
- package/src/sg-nodes/check-list.props.ts +71 -0
- package/src/sg-nodes/check-list.tsx +55 -0
- package/src/sg-nodes/content-node.props.ts +1316 -0
- package/src/sg-nodes/content-node.tsx +153 -0
- package/src/sg-nodes/core-props.ts +197 -0
- package/src/sg-nodes/custom-keyboard.props.ts +108 -0
- package/src/sg-nodes/custom-keyboard.tsx +48 -0
- package/src/sg-nodes/dialog.props.ts +159 -0
- package/src/sg-nodes/dialog.tsx +36 -0
- package/src/sg-nodes/dynamic-key-grid.props.ts +22 -0
- package/src/sg-nodes/dynamic-key-grid.tsx +16 -0
- package/src/sg-nodes/dynamic-keyboard.props.ts +30 -0
- package/src/sg-nodes/dynamic-keyboard.tsx +18 -0
- package/src/sg-nodes/dynamic-mini-keyboard.props.ts +22 -0
- package/src/sg-nodes/dynamic-mini-keyboard.tsx +18 -0
- package/src/sg-nodes/dynamic-pinpad.props.ts +57 -0
- package/src/sg-nodes/dynamic-pinpad.tsx +18 -0
- package/src/sg-nodes/effect.props.ts +116 -0
- package/src/sg-nodes/effect.tsx +39 -0
- package/src/sg-nodes/font.props.ts +45 -0
- package/src/sg-nodes/font.tsx +80 -0
- package/src/sg-nodes/group.props.ts +105 -0
- package/src/sg-nodes/group.tsx +30 -0
- package/src/sg-nodes/label-list.props.ts +86 -0
- package/src/sg-nodes/label-list.tsx +64 -0
- package/src/sg-nodes/label.props.ts +207 -0
- package/src/sg-nodes/label.tsx +56 -0
- package/src/sg-nodes/layout-group.props.ts +69 -0
- package/src/sg-nodes/layout-group.tsx +75 -0
- package/src/sg-nodes/list-panel.props.ts +104 -0
- package/src/sg-nodes/list-panel.tsx +49 -0
- package/src/sg-nodes/markup-grid.props.ts +78 -0
- package/src/sg-nodes/markup-grid.tsx +38 -0
- package/src/sg-nodes/markup-list.props.ts +68 -0
- package/src/sg-nodes/markup-list.tsx +38 -0
- package/src/sg-nodes/mask-group.props.ts +78 -0
- package/src/sg-nodes/mask-group.tsx +59 -0
- package/src/sg-nodes/media-playback-methods.ts +20 -0
- package/src/sg-nodes/node.ts +77 -0
- package/src/sg-nodes/overhang.props.ts +169 -0
- package/src/sg-nodes/overhang.tsx +29 -0
- package/src/sg-nodes/panel-set.props.ts +71 -0
- package/src/sg-nodes/panel-set.tsx +53 -0
- package/src/sg-nodes/panel.props.ts +176 -0
- package/src/sg-nodes/panel.tsx +56 -0
- package/src/sg-nodes/poster-grid.props.ts +277 -0
- package/src/sg-nodes/poster-grid.tsx +45 -0
- package/src/sg-nodes/poster.props.ts +125 -0
- package/src/sg-nodes/poster.tsx +44 -0
- package/src/sg-nodes/radio-button-list.props.ts +59 -0
- package/src/sg-nodes/radio-button-list.tsx +68 -0
- package/src/sg-nodes/rectangle.props.ts +29 -0
- package/src/sg-nodes/rectangle.tsx +27 -0
- package/src/sg-nodes/row-list.props.ts +288 -0
- package/src/sg-nodes/row-list.tsx +47 -0
- package/src/sg-nodes/scene.props.ts +65 -0
- package/src/sg-nodes/scene.tsx +15 -0
- package/src/sg-nodes/scrollable-text.props.ts +133 -0
- package/src/sg-nodes/scrollable-text.tsx +64 -0
- package/src/sg-nodes/scrolling-label.props.ts +106 -0
- package/src/sg-nodes/scrolling-label.tsx +42 -0
- package/src/sg-nodes/simple-label.props.ts +156 -0
- package/src/sg-nodes/simple-label.tsx +59 -0
- package/src/sg-nodes/sound-effect.props.ts +130 -0
- package/src/sg-nodes/sound-effect.tsx +65 -0
- package/src/sg-nodes/standard-dialog.props.ts +520 -0
- package/src/sg-nodes/standard-dialog.tsx +428 -0
- package/src/sg-nodes/standard-keyboard-dialog.props.ts +84 -0
- package/src/sg-nodes/standard-keyboard-dialog.tsx +59 -0
- package/src/sg-nodes/standard-message-dialog.props.ts +56 -0
- package/src/sg-nodes/standard-message-dialog.tsx +48 -0
- package/src/sg-nodes/standard-pinpad-dialog.props.ts +64 -0
- package/src/sg-nodes/standard-pinpad-dialog.tsx +46 -0
- package/src/sg-nodes/standard-progress-dialog.props.ts +30 -0
- package/src/sg-nodes/standard-progress-dialog.tsx +43 -0
- package/src/sg-nodes/target-group.props.ts +278 -0
- package/src/sg-nodes/target-group.tsx +63 -0
- package/src/sg-nodes/target-list.props.ts +128 -0
- package/src/sg-nodes/target-list.tsx +66 -0
- package/src/sg-nodes/target-set.props.ts +63 -0
- package/src/sg-nodes/target-set.tsx +42 -0
- package/src/sg-nodes/time-grid.props.ts +646 -0
- package/src/sg-nodes/time-grid.tsx +87 -0
- package/src/sg-nodes/tween.props.ts +115 -0
- package/src/sg-nodes/types.ts +150 -0
- package/src/sg-nodes/video.props.ts +573 -0
- package/src/sg-nodes/video.tsx +73 -0
- package/src/sg-nodes/voice-text-edit-box.props.ts +91 -0
- package/src/sg-nodes/voice-text-edit-box.tsx +15 -0
- package/src/sg-nodes/zoom-row-list.props.ts +416 -0
- package/src/sg-nodes/zoom-row-list.tsx +42 -0
- package/src/standard-dialog-next/__tests__/standard-dialog-next.test.tsx +186 -0
- package/src/standard-dialog-next/index.ts +5 -0
- package/src/standard-dialog-next/standard-dialog-next.props.ts +80 -0
- package/src/standard-dialog-next/standard-dialog-next.tsx +326 -0
- package/src/test-helpers/tween-test-setup.ts +78 -0
- package/src/tween.tsx +173 -0
- package/src/types.ts +8 -0
- package/src/xml-components/blended-busy-spinner/BlendedBusySpinner.brs +13 -0
- package/src/xml-components/blended-busy-spinner/BlendedBusySpinner.xml +10 -0
- package/src/xml-components/blended-busy-spinner/BlendedBusySpinner.xml.d.ts +42 -0
- package/src/xml-components/bounding-tracker/BoundingTracker.brs +26 -0
- package/src/xml-components/bounding-tracker/BoundingTracker.xml +14 -0
- package/src/xml-components/bounding-tracker/BoundingTracker.xml.d.ts +42 -0
- package/src/xml-components/channel-store/channelStoreExt.brs +159 -0
- package/src/xml-components/channel-store/channelStoreExt.xml +29 -0
- package/src/xml-components/channel-store/channelStoreExt.xml.d.ts +57 -0
- package/src/xml-components/focus/focusable-group.brs +251 -0
- package/src/xml-components/focus/focusable-group.xml +15 -0
- package/src/xml-components/focus/focusable-group.xml.d.ts +42 -0
- package/src/xml-components/focus/focusable.xml +18 -0
- package/src/xml-components/focus/focusable.xml.d.ts +48 -0
- package/src/xml-components/keyboards/CustomAddressKDF.keyboard.json +547 -0
- package/src/xml-components/keyboards/CustomKeyboard.brs +322 -0
- package/src/xml-components/keyboards/CustomKeyboard.xml +45 -0
- package/src/xml-components/keyboards/CustomKeyboard.xml.d.ts +73 -0
- package/src/xml-components/keyboards/KeyGridExt.xml +4 -0
- package/src/xml-components/keyboards/KeyGridExt.xml.d.ts +37 -0
- package/src/xml-components/keyboards/KeyboardExt.xml +4 -0
- package/src/xml-components/keyboards/KeyboardExt.xml.d.ts +37 -0
- package/src/xml-components/keyboards/MOPPinPadCustomKDF.keyboard.json +151 -0
- package/src/xml-components/keyboards/MiniKeyboardExt.xml +4 -0
- package/src/xml-components/keyboards/MiniKeyboardExt.xml.d.ts +37 -0
- package/src/xml-components/keyboards/PhonePadCustomKDF.keyboard.json +42 -0
- package/src/xml-components/keyboards/PinPadExt.brs +102 -0
- package/src/xml-components/keyboards/PinPadExt.xml +17 -0
- package/src/xml-components/keyboards/PinPadExt.xml.d.ts +49 -0
- package/src/xml-components/keyboards/WifiCustomKDF.keyboard.json +1242 -0
- package/src/xml-components/keyhandler/KeyHandler.brs +30 -0
- package/src/xml-components/keyhandler/KeyHandler.xml +16 -0
- package/src/xml-components/keyhandler/KeyHandler.xml.d.ts +45 -0
- package/src/xml-components/managed-list-panel/ManagedListPanel.brs +137 -0
- package/src/xml-components/managed-list-panel/ManagedListPanel.xml +10 -0
- package/src/xml-components/managed-list-panel/ManagedListPanel.xml.d.ts +37 -0
- package/src/xml-components/modal/Modal.brs +105 -0
- package/src/xml-components/modal/Modal.xml +22 -0
- package/src/xml-components/modal/Modal.xml.d.ts +54 -0
- package/src/xml-components/modal/StandardDialogExt.xml +10 -0
- package/src/xml-components/modal/StandardDialogExt.xml.d.ts +37 -0
- package/src/xml-components/modal/StandardKeyboardDialogExt.xml +10 -0
- package/src/xml-components/modal/StandardKeyboardDialogExt.xml.d.ts +37 -0
- package/src/xml-components/modal/StandardMessageDialogExt.xml +10 -0
- package/src/xml-components/modal/StandardMessageDialogExt.xml.d.ts +37 -0
- package/src/xml-components/modal/StandardPinPadDialogExt.xml +10 -0
- package/src/xml-components/modal/StandardPinPadDialogExt.xml.d.ts +37 -0
- package/src/xml-components/modal/StandardProgressDialogExt.xml +10 -0
- package/src/xml-components/modal/StandardProgressDialogExt.xml.d.ts +37 -0
- package/src/xml-components/modal/tests/Modal.test.brs +195 -0
- 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
|
+
}
|