@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,91 @@
|
|
|
1
|
+
// Copyright (c) 2026 Roku, Inc.
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
import type { IGroupProps } from "./group.props";
|
|
5
|
+
import type { EventHandler } from "./types";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Properties for the legacy TextEditBox fields exposed by {@link VoiceTextEditBox}.
|
|
9
|
+
*
|
|
10
|
+
* @see {@link https://developer.roku.com/dev/docs/texteditbox}
|
|
11
|
+
*/
|
|
12
|
+
export interface ITextEditBoxProps extends IGroupProps {
|
|
13
|
+
/** Current text displayed in the edit box. */
|
|
14
|
+
text: string;
|
|
15
|
+
/** Placeholder text shown when the edit box is empty. */
|
|
16
|
+
hintText: string;
|
|
17
|
+
/** Maximum number of characters that may be entered. */
|
|
18
|
+
maxTextLength: number;
|
|
19
|
+
/** Zero-based cursor position within the text string. */
|
|
20
|
+
cursorPosition: number;
|
|
21
|
+
/** When true, pressing Down clears the text field. */
|
|
22
|
+
clearOnDownKey: boolean;
|
|
23
|
+
/** When true, the edit box accepts focus and key input. */
|
|
24
|
+
active: boolean;
|
|
25
|
+
/** When true, entered characters are masked (for passwords/PINs). */
|
|
26
|
+
secureMode: boolean;
|
|
27
|
+
/** Color of the entered text. */
|
|
28
|
+
textColor: string | number;
|
|
29
|
+
/** Color of the hint text. */
|
|
30
|
+
hintTextColor: string | number;
|
|
31
|
+
/** Width of the voice-enabled text box. */
|
|
32
|
+
voiceTextBoxWidth: number;
|
|
33
|
+
/** Background image URI for the text box. */
|
|
34
|
+
backgroundUri: string;
|
|
35
|
+
/** When true, truncates long text with a leading ellipsis. */
|
|
36
|
+
leadingEllipsis: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Properties for the {@link VoiceTextEditBox} component.
|
|
41
|
+
*
|
|
42
|
+
* VoiceTextEditBox is similar to the legacy TextEditBox node but adds voice entry
|
|
43
|
+
* functionality. Only one voice-enabled VoiceTextEditBox may be on screen at a time.
|
|
44
|
+
*
|
|
45
|
+
* @see {@link https://developer.roku.com/dev/docs/voice-text-edit-box}
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```tsx
|
|
49
|
+
* <VoiceTextEditBox
|
|
50
|
+
* id="search-input"
|
|
51
|
+
* text={query()}
|
|
52
|
+
* hintText="Search…"
|
|
53
|
+
* maxTextLength={64}
|
|
54
|
+
* cursorPosition={query().length}
|
|
55
|
+
* clearOnDownKey={false}
|
|
56
|
+
* active
|
|
57
|
+
* secureMode={false}
|
|
58
|
+
* textColor="0xFFFFFFFF"
|
|
59
|
+
* hintTextColor="0x888888FF"
|
|
60
|
+
* voiceTextBoxWidth={800}
|
|
61
|
+
* backgroundUri=""
|
|
62
|
+
* leadingEllipsis={false}
|
|
63
|
+
* voiceEnabled
|
|
64
|
+
* voiceEntryType="generic"
|
|
65
|
+
* onText={setQuery}
|
|
66
|
+
* />
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export interface IVoiceTextEditBoxProps extends ITextEditBoxProps {
|
|
70
|
+
/**
|
|
71
|
+
* Enables voice entry for the text box (mic icon and voice hints).
|
|
72
|
+
* @default false
|
|
73
|
+
*/
|
|
74
|
+
voiceEntryType?: string;
|
|
75
|
+
/** When true, voice entry is enabled. */
|
|
76
|
+
voiceEnabled?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Maximum width of the voice hint tooltip.
|
|
79
|
+
* @default FHD: 321, HD: 214
|
|
80
|
+
*/
|
|
81
|
+
voiceToolTipWidth?: number;
|
|
82
|
+
/** Fired when dictation starts or stops. */
|
|
83
|
+
onIsDictating?: EventHandler<boolean>;
|
|
84
|
+
/**
|
|
85
|
+
* Regex filter restricting characters entered via dictation.
|
|
86
|
+
* Write-only on the native node.
|
|
87
|
+
*/
|
|
88
|
+
voiceInputRegexFilter?: string;
|
|
89
|
+
/** Fired when the text value changes. */
|
|
90
|
+
onText?: EventHandler<string>;
|
|
91
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Copyright (c) 2026 Roku, Inc.
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
import { Component } from "./types";
|
|
5
|
+
import type { IVoiceTextEditBoxProps } from "./voice-text-edit-box.props";
|
|
6
|
+
export type { ITextEditBoxProps, IVoiceTextEditBoxProps } from "./voice-text-edit-box.props";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Voice-enabled text edit box for standalone text entry (not inside a dialog).
|
|
10
|
+
*
|
|
11
|
+
* @see {@link https://developer.roku.com/dev/docs/voice-text-edit-box}
|
|
12
|
+
*/
|
|
13
|
+
export const VoiceTextEditBox: Component<IVoiceTextEditBoxProps> = props => {
|
|
14
|
+
return <voiceTextEditBox {...props}></voiceTextEditBox>;
|
|
15
|
+
};
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
// Copyright (c) 2026 Roku, Inc.
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
import type { IGroupProps } from "./group.props";
|
|
5
|
+
import type { RowItemPosition, RowListItemEventHandler } from "./row-list.props";
|
|
6
|
+
import type { EventHandler, FontValue, JSX, Rect2D, Uri, Vector2D } from "./types";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Controls whether rows above the focus row remain zoomed or unzoom as they scroll.
|
|
10
|
+
*
|
|
11
|
+
* - `focusIsAtTop`: when itemClippingRect top is 0, rows remain zoomed as they enter/exit from above
|
|
12
|
+
* - `never`: rows zoom up/down as they enter/exit the focus region from above
|
|
13
|
+
* - `always`: rows always remain zoomed as they enter/exit from above
|
|
14
|
+
*
|
|
15
|
+
* @default "focusIsAtTop"
|
|
16
|
+
*/
|
|
17
|
+
export type RemainZoomedAboveFocus = "focusIsAtTop" | "never" | "always";
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Controls whether rows above the focus row fade in/out as they scroll.
|
|
21
|
+
*
|
|
22
|
+
* - `focusIsAtTop`: when itemClippingRect top is 0, rows fade as they enter/exit from above
|
|
23
|
+
* - `never`: rows do not fade as they enter/exit from above
|
|
24
|
+
* - `always`: rows always fade as they enter/exit from above
|
|
25
|
+
*
|
|
26
|
+
* @default "focusIsAtTop"
|
|
27
|
+
*/
|
|
28
|
+
export type FadeOutAboveFocus = "focusIsAtTop" | "never" | "always";
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Properties for the ZoomRowList node.
|
|
32
|
+
*
|
|
33
|
+
* ZoomRowList allows a row of the Row-Row Grid to smoothly zoom up to a larger size when that row
|
|
34
|
+
* has focus. Rows are capable of gaining focus while scrolling and smoothly zooming by the specified
|
|
35
|
+
* amount. The amount to zoom can be specified on a per-row basis.
|
|
36
|
+
*
|
|
37
|
+
* ZoomRowList extends Group and uses the same data model as RowList: a root ContentNode with child
|
|
38
|
+
* ContentNodes for each row, each containing child ContentNodes for each item.
|
|
39
|
+
*
|
|
40
|
+
* @see {@link https://developer.roku.com/dev/docs/zoomrowlist}
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```tsx
|
|
44
|
+
* import "./compiled-components/MyRowItem.xml";
|
|
45
|
+
*
|
|
46
|
+
* <ZoomRowList
|
|
47
|
+
* itemComponentName="MyRowItem"
|
|
48
|
+
* rowWidth={1920}
|
|
49
|
+
* rowHeight={[120, 120, 120]}
|
|
50
|
+
* rowZoomHeight={[200, 200, 200]}
|
|
51
|
+
* rowItemHeight={[100, 100, 100]}
|
|
52
|
+
* rowItemZoomHeight={[180, 180, 180]}
|
|
53
|
+
* rowItemAspectRatio={[1.777]}
|
|
54
|
+
* content={listContent}
|
|
55
|
+
* onRowItemFocused={([row, col]) => setFocus(row, col)}
|
|
56
|
+
* onRowItemSelected={([row, col]) => navigate(row, col)}
|
|
57
|
+
* />
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
export interface IZoomRowListProps extends IGroupProps {
|
|
61
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
62
|
+
// Content
|
|
63
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Specifies the content for the ZoomRowList.
|
|
67
|
+
*
|
|
68
|
+
* The root ContentNode should have one child per row. Each row child should
|
|
69
|
+
* have one child ContentNode per item in that row.
|
|
70
|
+
*
|
|
71
|
+
* @see {@link https://developer.roku.com/dev/docs/zoomrowlist#zoomrowlist-data-model}
|
|
72
|
+
*/
|
|
73
|
+
content: JSX.Element;
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Specifies the name of the compiled component used to render each row item.
|
|
77
|
+
*
|
|
78
|
+
* Register the compiled component by importing its XML file before use.
|
|
79
|
+
* The component may define: width, height, index, rowIndex, itemHasFocus,
|
|
80
|
+
* rowHasFocus, rowListHasFocus, itemContent, focusPercent, rowFocusPercent, rowHeightPercent.
|
|
81
|
+
*
|
|
82
|
+
* @example "MyRowItem"
|
|
83
|
+
*/
|
|
84
|
+
itemComponentName?: string;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Specifies the name of an XML component to decorate each row.
|
|
88
|
+
* An instance is created for each visible row.
|
|
89
|
+
*
|
|
90
|
+
* @example "MyRowDecoration"
|
|
91
|
+
*/
|
|
92
|
+
rowDecorationComponentName?: string[];
|
|
93
|
+
|
|
94
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
95
|
+
// Layout
|
|
96
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Specifies the maximum width of items in each row before items wrap.
|
|
100
|
+
* Also used for Row Counter positioning.
|
|
101
|
+
*
|
|
102
|
+
* @default 0
|
|
103
|
+
*/
|
|
104
|
+
rowWidth?: number;
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Specifies the height of each ZoomRowItem when the row is not zoomed.
|
|
108
|
+
* At least one value must be specified.
|
|
109
|
+
*
|
|
110
|
+
* @example [120, 120, 120]
|
|
111
|
+
*/
|
|
112
|
+
rowHeight?: number[];
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Specifies the height of each ZoomRowItem when the row is zoomed.
|
|
116
|
+
* If not specified, rows do not zoom.
|
|
117
|
+
*
|
|
118
|
+
* @example [200, 200, 200]
|
|
119
|
+
*/
|
|
120
|
+
rowZoomHeight?: number[];
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Specifies the spacing between rows. Not scaled by zoom.
|
|
124
|
+
*
|
|
125
|
+
* @default 0
|
|
126
|
+
*/
|
|
127
|
+
spacingAfterRow?: number;
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Specifies a clipping region for the ZoomRowItem renders.
|
|
131
|
+
* For best performance, set to match what's visible onscreen.
|
|
132
|
+
*
|
|
133
|
+
* @default [0, 0, 0, 0]
|
|
134
|
+
*/
|
|
135
|
+
itemClippingRect?: Rect2D;
|
|
136
|
+
|
|
137
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
138
|
+
// Row Item Sizing
|
|
139
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Vertical position of the Row relative to the top of its ZoomRowItem when unfocused.
|
|
143
|
+
*
|
|
144
|
+
* @example [0, 0, 0]
|
|
145
|
+
*/
|
|
146
|
+
rowItemYOffset?: number[];
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Vertical position of the Row relative to the top of its ZoomRowItem when focused (zoomed).
|
|
150
|
+
*
|
|
151
|
+
* @example [10, 10, 10]
|
|
152
|
+
*/
|
|
153
|
+
rowItemZoomYOffset?: number[];
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Height of each Item in a Row when the row is unfocused.
|
|
157
|
+
*
|
|
158
|
+
* @example [100, 100, 100]
|
|
159
|
+
*/
|
|
160
|
+
rowItemHeight?: number[];
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Height of each Item in a Row when the row is focused (zoomed).
|
|
164
|
+
*
|
|
165
|
+
* @example [180, 180, 180]
|
|
166
|
+
*/
|
|
167
|
+
rowItemZoomHeight?: number[];
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Aspect ratio of Items in each Row (width/height).
|
|
171
|
+
* Used to compute item width from interpolated height.
|
|
172
|
+
* E.g. 16:9 = 1.7777778.
|
|
173
|
+
*
|
|
174
|
+
* @example [1.7777778]
|
|
175
|
+
*/
|
|
176
|
+
rowItemAspectRatio?: number[];
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Horizontal spacing between Items in each Row.
|
|
180
|
+
* Scales with zoom as the row gains focus.
|
|
181
|
+
*
|
|
182
|
+
* @example [20, 20, 20]
|
|
183
|
+
*/
|
|
184
|
+
spacingAfterRowItem?: number[];
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* If true, use rowItemAspectRatio for all items. If false, use aspectRatio
|
|
188
|
+
* from each item's ContentNode when available.
|
|
189
|
+
*
|
|
190
|
+
* @example [true, true, true]
|
|
191
|
+
*/
|
|
192
|
+
useDefaultAspectRatio?: boolean[];
|
|
193
|
+
|
|
194
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
195
|
+
// Row Title and Counter
|
|
196
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Specifies whether the row title is displayed for each row.
|
|
200
|
+
*
|
|
201
|
+
* @example [true, true, true]
|
|
202
|
+
*/
|
|
203
|
+
showRowTitle?: boolean[];
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Offset of the Row Title for each row. [x, y] from left edge and top.
|
|
207
|
+
*
|
|
208
|
+
* @example [[0, 0], [0, 10]]
|
|
209
|
+
*/
|
|
210
|
+
rowTitleOffset?: Vector2D[];
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Font for the Row Title text.
|
|
214
|
+
*/
|
|
215
|
+
rowTitleFont?: FontValue;
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Color of the Row Title text for each row.
|
|
219
|
+
*
|
|
220
|
+
* @example ["0xffffffff"]
|
|
221
|
+
*/
|
|
222
|
+
rowTitleColor?: string[];
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Specifies whether each row's Row Counter is displayed.
|
|
226
|
+
*
|
|
227
|
+
* @example [true, true, true]
|
|
228
|
+
*/
|
|
229
|
+
showRowCounter?: boolean[];
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Offset of the Row Counter for each row. X is right edge position (right-aligned).
|
|
233
|
+
*
|
|
234
|
+
* @example [[1920, 0]]
|
|
235
|
+
*/
|
|
236
|
+
rowCounterOffset?: Vector2D[];
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* Font for the Row Counter text.
|
|
240
|
+
*/
|
|
241
|
+
rowCounterFont?: FontValue;
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Color of the Row Counter text for each row.
|
|
245
|
+
*
|
|
246
|
+
* @example ["0xffffffff"]
|
|
247
|
+
*/
|
|
248
|
+
rowCounterColor?: string[];
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* When true, Row Counter is shown for all rows. When false, not shown for
|
|
252
|
+
* rows where total zoomed width of items is less than rowWidth.
|
|
253
|
+
*
|
|
254
|
+
* @default true
|
|
255
|
+
*/
|
|
256
|
+
showRowCounterForShortRows?: boolean;
|
|
257
|
+
|
|
258
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
259
|
+
// Focus Feedback
|
|
260
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* If true, the focus feedback indicator is drawn.
|
|
264
|
+
*
|
|
265
|
+
* @default true
|
|
266
|
+
*/
|
|
267
|
+
drawFocusFeedback?: boolean;
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* If true, the focus feedback indicator is drawn on top of the items.
|
|
271
|
+
*
|
|
272
|
+
* @default true
|
|
273
|
+
*/
|
|
274
|
+
drawFocusFeedbackOnTop?: boolean;
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* If true, focus indicator fades out during long-press scrolling.
|
|
278
|
+
*
|
|
279
|
+
* @default true
|
|
280
|
+
*/
|
|
281
|
+
fadeFocusFeedbackWhenLongPressScrolling?: boolean;
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Bitmap file for the focus feedback indicator.
|
|
285
|
+
* Use 9-patch for expandable regions and margins.
|
|
286
|
+
*/
|
|
287
|
+
focusBitmapUri?: Uri;
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Blend color for the focus bitmap.
|
|
291
|
+
*
|
|
292
|
+
* @default "0xFFFFFFFF"
|
|
293
|
+
*/
|
|
294
|
+
focusBitmapBlendColor?: string;
|
|
295
|
+
|
|
296
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
297
|
+
// Wrap Divider
|
|
298
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
299
|
+
|
|
300
|
+
/**
|
|
301
|
+
* If true, items wrap from bottom to top.
|
|
302
|
+
*
|
|
303
|
+
* @default true
|
|
304
|
+
*/
|
|
305
|
+
wrap?: boolean;
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Bitmap file for the wrap divider between last and first items.
|
|
309
|
+
*/
|
|
310
|
+
wrapDividerBitmapUri?: Uri;
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Blend color for the wrap divider bitmap.
|
|
314
|
+
*
|
|
315
|
+
* @default "0xFFFFFFFF"
|
|
316
|
+
*/
|
|
317
|
+
wrapDividerBitmapBlendColor?: string;
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* Height of the wrap divider bitmap.
|
|
321
|
+
*
|
|
322
|
+
* @default 0
|
|
323
|
+
*/
|
|
324
|
+
wrapDividerHeight?: number;
|
|
325
|
+
|
|
326
|
+
/**
|
|
327
|
+
* Width of the wrap divider bitmap. Defaults to rowWidth if not specified.
|
|
328
|
+
*
|
|
329
|
+
* @default 0
|
|
330
|
+
*/
|
|
331
|
+
wrapDividerWidth?: number;
|
|
332
|
+
|
|
333
|
+
/**
|
|
334
|
+
* Offset to adjust the wrap divider position from its default.
|
|
335
|
+
*
|
|
336
|
+
* @default [0, 0]
|
|
337
|
+
*/
|
|
338
|
+
wrapDividerOffset?: Vector2D;
|
|
339
|
+
|
|
340
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
341
|
+
// Zoom Behavior
|
|
342
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Controls whether rows above the focus row remain zoomed as they scroll.
|
|
346
|
+
*
|
|
347
|
+
* @default "focusIsAtTop"
|
|
348
|
+
*/
|
|
349
|
+
remainZoomedAboveFocus?: RemainZoomedAboveFocus;
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Controls whether rows above the focus row fade in/out as they scroll.
|
|
353
|
+
*
|
|
354
|
+
* @default "focusIsAtTop"
|
|
355
|
+
*/
|
|
356
|
+
fadeOutAboveFocus?: FadeOutAboveFocus;
|
|
357
|
+
|
|
358
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
359
|
+
// Navigation
|
|
360
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
361
|
+
|
|
362
|
+
/**
|
|
363
|
+
* When set to a valid row index, immediately moves focus to that row.
|
|
364
|
+
*
|
|
365
|
+
* @see {@link https://developer.roku.com/dev/docs/zoomrowlist}
|
|
366
|
+
*/
|
|
367
|
+
jumpToRow?: number;
|
|
368
|
+
|
|
369
|
+
/**
|
|
370
|
+
* When set to a valid [rowIndex, itemIndex], immediately moves focus to that item.
|
|
371
|
+
*
|
|
372
|
+
* @example [2, 0]
|
|
373
|
+
*/
|
|
374
|
+
jumpToRowItem?: RowItemPosition;
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* When set to a valid row index, scrolls to bring that row into focus.
|
|
378
|
+
*
|
|
379
|
+
* @see {@link https://developer.roku.com/dev/docs/zoomrowlist}
|
|
380
|
+
*/
|
|
381
|
+
animateToRow?: number;
|
|
382
|
+
|
|
383
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
384
|
+
// Events
|
|
385
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Fired when a row item is selected (OK pressed).
|
|
389
|
+
* Receives [rowIndex, itemIndex] of the selected item.
|
|
390
|
+
*/
|
|
391
|
+
onRowItemSelected?: RowListItemEventHandler;
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Fired when a row item gains focus.
|
|
395
|
+
* Receives [rowIndex, itemIndex] of the newly focused item.
|
|
396
|
+
*/
|
|
397
|
+
onRowItemFocused?: RowListItemEventHandler;
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* Fired when a row is selected.
|
|
401
|
+
* Receives the index of the selected row.
|
|
402
|
+
*/
|
|
403
|
+
onRowSelected?: EventHandler<number>;
|
|
404
|
+
|
|
405
|
+
/**
|
|
406
|
+
* Fired when a row gains focus.
|
|
407
|
+
* Receives the index of the focused row.
|
|
408
|
+
*/
|
|
409
|
+
onRowFocused?: EventHandler<number>;
|
|
410
|
+
|
|
411
|
+
/**
|
|
412
|
+
* Fired when a row loses focus.
|
|
413
|
+
* Receives the index of the unfocused row.
|
|
414
|
+
*/
|
|
415
|
+
onRowUnfocused?: EventHandler<number>;
|
|
416
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
// Copyright (c) 2026 Roku, Inc.
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
import { Component } from "./types";
|
|
5
|
+
import type { IZoomRowListProps } from "./zoom-row-list.props";
|
|
6
|
+
export type { RemainZoomedAboveFocus, FadeOutAboveFocus, IZoomRowListProps } from "./zoom-row-list.props";
|
|
7
|
+
|
|
8
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
9
|
+
// ZoomRowList Properties
|
|
10
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
11
|
+
|
|
12
|
+
// Re-export for consumers
|
|
13
|
+
export type { RowItemPosition, RowListItemEventHandler } from "./row-list";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* ZoomRowList displays a vertically scrolling list of rows where the focused row
|
|
17
|
+
* smoothly zooms to a larger size. Each row scrolls horizontally through its items.
|
|
18
|
+
* Item rendering is delegated to compiled components specified by itemComponentName.
|
|
19
|
+
*
|
|
20
|
+
* @see {@link https://developer.roku.com/dev/docs/zoomrowlist}
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```tsx
|
|
24
|
+
* import "./compiled-components/MyRowItem.xml";
|
|
25
|
+
*
|
|
26
|
+
* <zoomRowList
|
|
27
|
+
* itemComponentName="MyRowItem"
|
|
28
|
+
* rowWidth={1920}
|
|
29
|
+
* rowHeight={[120, 120, 120]}
|
|
30
|
+
* rowZoomHeight={[200, 200, 200]}
|
|
31
|
+
* rowItemHeight={[100, 100, 100]}
|
|
32
|
+
* rowItemZoomHeight={[180, 180, 180]}
|
|
33
|
+
* rowItemAspectRatio={[1.777]}
|
|
34
|
+
* content={listContent}
|
|
35
|
+
* onRowItemFocused={([row, col]) => setFocus(row, col)}
|
|
36
|
+
* onRowItemSelected={([row, col]) => navigate(row, col)}
|
|
37
|
+
* />
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export const ZoomRowList: Component<IZoomRowListProps> = props => {
|
|
41
|
+
return <zoomRowList {...props}></zoomRowList>;
|
|
42
|
+
};
|