@roku-sdk/components 0.0.0-stage → 2.19.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 +85 -3
- package/src/__tests__/container.test.tsx +150 -0
- package/src/__tests__/effect-gradient-validation.test.tsx +133 -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 +276 -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 +119 -0
- package/src/sg-nodes/effect.tsx +167 -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 +103 -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 +66 -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 +58 -0
- package/src/sg-nodes/standard-message-dialog.props.ts +56 -0
- package/src/sg-nodes/standard-message-dialog.tsx +47 -0
- package/src/sg-nodes/standard-pinpad-dialog.props.ts +64 -0
- package/src/sg-nodes/standard-pinpad-dialog.tsx +44 -0
- package/src/sg-nodes/standard-progress-dialog.props.ts +30 -0
- package/src/sg-nodes/standard-progress-dialog.tsx +40 -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 +642 -0
- package/src/sg-nodes/video.tsx +75 -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,425 @@
|
|
|
1
|
+
// Copyright (c) 2026 Roku, Inc.
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
import type { EventHandler, ResObject } from "./sg-nodes/types";
|
|
5
|
+
|
|
6
|
+
export interface IChannelStoreRequestStatusEvent {
|
|
7
|
+
command: string;
|
|
8
|
+
context: Record<string, string>;
|
|
9
|
+
requestid: number;
|
|
10
|
+
result: Record<string, string | number | boolean>;
|
|
11
|
+
status: number;
|
|
12
|
+
statusmessage: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Command strings supported by the ChannelStore node.
|
|
17
|
+
*
|
|
18
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore}
|
|
19
|
+
*/
|
|
20
|
+
export type ChannelStoreCommand =
|
|
21
|
+
| "none"
|
|
22
|
+
| "getUserData"
|
|
23
|
+
| "getUserRegionData"
|
|
24
|
+
| "storeChannelCredData"
|
|
25
|
+
| "getChannelCred"
|
|
26
|
+
| "getCatalog"
|
|
27
|
+
| "doOrder"
|
|
28
|
+
| "getPurchases"
|
|
29
|
+
| "getAllPurchases"
|
|
30
|
+
| "requestPartnerOrder"
|
|
31
|
+
| "confirmPartnerOrder"
|
|
32
|
+
| "getDeviceAttestationToken";
|
|
33
|
+
|
|
34
|
+
/** Context for the RFI (Request for Information) screen. */
|
|
35
|
+
export type ChannelStoreUserDataContext = "signin" | "signup";
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Custom request object for advanced ChannelStore operations.
|
|
39
|
+
*/
|
|
40
|
+
export interface IChannelStoreRequest {
|
|
41
|
+
command?: string;
|
|
42
|
+
params?: ResObject<Record<string, string | number | boolean>>;
|
|
43
|
+
context?: ResObject<Record<string, string>>;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Roku customer account information returned by the `getUserData` command.
|
|
48
|
+
*
|
|
49
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | getUserData Command}
|
|
50
|
+
*/
|
|
51
|
+
export interface IUserData {
|
|
52
|
+
email?: string;
|
|
53
|
+
phone?: string;
|
|
54
|
+
firstName?: string;
|
|
55
|
+
lastName?: string;
|
|
56
|
+
street?: string;
|
|
57
|
+
city?: string;
|
|
58
|
+
state?: string;
|
|
59
|
+
zip?: string;
|
|
60
|
+
country?: string;
|
|
61
|
+
birth?: string;
|
|
62
|
+
gender?: string;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export type EventHandlerUserData = EventHandler<IUserData>;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Region data returned by the `getUserRegionData` command.
|
|
69
|
+
*
|
|
70
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | getUserRegionData Command}
|
|
71
|
+
*/
|
|
72
|
+
export interface IUserRegionData {
|
|
73
|
+
state: string;
|
|
74
|
+
zip: string;
|
|
75
|
+
country: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export type EventHandlerUserRegionData = EventHandler<IUserRegionData>;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Configuration for the RFI (Request for Information) screen.
|
|
82
|
+
*
|
|
83
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | requestedUserDataInfo Field}
|
|
84
|
+
*/
|
|
85
|
+
export interface IRequestedUserDataInfo {
|
|
86
|
+
/** Whether the RFI screen is for sign-up or sign-in. */
|
|
87
|
+
context?: ChannelStoreUserDataContext;
|
|
88
|
+
/**
|
|
89
|
+
* When true, the RFI signup screen displays the values of the requested customer
|
|
90
|
+
* information. Has no effect if context is "signin".
|
|
91
|
+
* @default false
|
|
92
|
+
*/
|
|
93
|
+
forceShowData?: boolean;
|
|
94
|
+
[key: string]: unknown;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Status returned by the `storeChannelCredData` command.
|
|
99
|
+
*
|
|
100
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | storeChannelCredData Command}
|
|
101
|
+
*/
|
|
102
|
+
export interface IStoreChannelCredDataStatus {
|
|
103
|
+
/** JSON string with status, error, and error_detail fields. */
|
|
104
|
+
response: string;
|
|
105
|
+
/** Request status; 0 indicates success. */
|
|
106
|
+
status: number;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export type EventHandlerStoreChannelCredDataStatus = EventHandler<IStoreChannelCredDataStatus>;
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Channel credential data returned by the `getChannelCred` command.
|
|
113
|
+
*
|
|
114
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | getChannelCred Command}
|
|
115
|
+
*/
|
|
116
|
+
export interface IChannelCred {
|
|
117
|
+
/** The app ID (e.g., "2213" for Roku Media Player). */
|
|
118
|
+
channelId: string;
|
|
119
|
+
/** Error description; empty string on success. */
|
|
120
|
+
errorCode: string;
|
|
121
|
+
/** JSON string containing roku_pucid, token_type, channel_data, and error fields. */
|
|
122
|
+
json: string;
|
|
123
|
+
/** Unique identifier of the device. */
|
|
124
|
+
publisherDeviceId: string;
|
|
125
|
+
/** Request status; 0 indicates success. */
|
|
126
|
+
status: number;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
export type EventHandlerChannelCred = EventHandler<IChannelCred>;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Product information returned by the `getCatalog` command.
|
|
133
|
+
*
|
|
134
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | getCatalog Command}
|
|
135
|
+
*/
|
|
136
|
+
export interface IProduct {
|
|
137
|
+
/** Product identifier from the Developer Dashboard. */
|
|
138
|
+
code: string;
|
|
139
|
+
/** Item name / description. */
|
|
140
|
+
name: string;
|
|
141
|
+
/** Quantity (for consumable products). */
|
|
142
|
+
qty: number;
|
|
143
|
+
/** Product type (e.g., "MonthlySub"). */
|
|
144
|
+
productType: string;
|
|
145
|
+
/** Localized cost with currency symbol. */
|
|
146
|
+
cost: string;
|
|
147
|
+
/** Free trial length (e.g., 1 for 1-month, 7 for 7-day). */
|
|
148
|
+
freeTrialQuantity: number;
|
|
149
|
+
/** Free trial unit ("Days" or "Months"). */
|
|
150
|
+
freeTrialType: string;
|
|
151
|
+
/** Introductory pricing discounted price. */
|
|
152
|
+
trialCost: number;
|
|
153
|
+
/** Months of introductory pricing. */
|
|
154
|
+
trialQuantity: number;
|
|
155
|
+
/** Unit for introductory pricing ("months"). */
|
|
156
|
+
trialType: string;
|
|
157
|
+
/** Whether the product is "saved" or "approved for sale". */
|
|
158
|
+
status: string;
|
|
159
|
+
/** Subscription purchase date. */
|
|
160
|
+
purchaseDate: string;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export type EventHandlerCatalog = EventHandler<IProduct[]>;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* An item in an order for the `doOrder` command.
|
|
167
|
+
*
|
|
168
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | order Field}
|
|
169
|
+
*/
|
|
170
|
+
export interface IOrderItem {
|
|
171
|
+
/** Product identifier. */
|
|
172
|
+
code: string;
|
|
173
|
+
/** Quantity to purchase. */
|
|
174
|
+
qty: number;
|
|
175
|
+
/** Set to "Upgrade" or "Downgrade" for subscription plan changes. */
|
|
176
|
+
action?: string;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Status returned by the `doOrder` command.
|
|
181
|
+
*
|
|
182
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | doOrder Command}
|
|
183
|
+
*/
|
|
184
|
+
export interface IOrderStatus {
|
|
185
|
+
/** Completion status (1 = success, 2 = interrupted, 0 = network error, etc.). */
|
|
186
|
+
status: number;
|
|
187
|
+
/** Description of the completion status. */
|
|
188
|
+
statusMessage: string;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export type EventHandlerOrderStatus = EventHandler<IOrderStatus>;
|
|
192
|
+
|
|
193
|
+
export type EventHandlerOrderItemsStatus = EventHandler<IPurchase[]>;
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Status returned by `getPurchases` / `getAllPurchases` commands.
|
|
197
|
+
*/
|
|
198
|
+
export interface IPurchasesStatus {
|
|
199
|
+
status: number;
|
|
200
|
+
statusMessage: string;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export type EventHandlerPurchasesStatus = EventHandler<IPurchasesStatus>;
|
|
204
|
+
|
|
205
|
+
/**
|
|
206
|
+
* Purchase information returned by `getPurchases` or `getAllPurchases` commands.
|
|
207
|
+
*
|
|
208
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | getPurchases Command}
|
|
209
|
+
*/
|
|
210
|
+
export interface IPurchase {
|
|
211
|
+
/** Product identifier. */
|
|
212
|
+
code: string;
|
|
213
|
+
/** Localized cost with currency symbol. */
|
|
214
|
+
cost: string;
|
|
215
|
+
/** Subscription expiration date (ISO 8601). */
|
|
216
|
+
expirationDate: string;
|
|
217
|
+
/** Free trial length. */
|
|
218
|
+
freeTrialQuantity: number;
|
|
219
|
+
/** Free trial unit ("Days" or "Months"). */
|
|
220
|
+
freeTrialType: string;
|
|
221
|
+
/** Whether subscription is past due ("true" if in dunning state). */
|
|
222
|
+
inDunning: string;
|
|
223
|
+
/** Item name / description. */
|
|
224
|
+
name: string;
|
|
225
|
+
/** Product type (e.g., "MonthlySub"). */
|
|
226
|
+
productType: string;
|
|
227
|
+
/** Where the purchase was made ("web" or "device"). */
|
|
228
|
+
purchaseChannel: string;
|
|
229
|
+
/** How the purchase was made ("isu" or "iap"). */
|
|
230
|
+
purchaseContext: string;
|
|
231
|
+
/** Purchase date (ISO 8601). */
|
|
232
|
+
purchaseDate: string;
|
|
233
|
+
/** Transaction ID. */
|
|
234
|
+
purchaseId: string;
|
|
235
|
+
/** Quantity purchased. */
|
|
236
|
+
qty: number;
|
|
237
|
+
/** Subscription renewal date (ISO 8601). */
|
|
238
|
+
renewalDate: string;
|
|
239
|
+
/** "Valid" for current subscriptions, "Invalid" for canceled/expired. */
|
|
240
|
+
status: string;
|
|
241
|
+
/** Description of the status. */
|
|
242
|
+
statusMessage: string;
|
|
243
|
+
/** Introductory pricing discounted price. */
|
|
244
|
+
trialCost: number;
|
|
245
|
+
/** Months of introductory pricing. */
|
|
246
|
+
trialQuantity: number;
|
|
247
|
+
/** Unit for introductory pricing ("months"). */
|
|
248
|
+
trialType: string;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
export type EventHandlerPurchases = EventHandler<IPurchase[]>;
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
* Partner order data for TVOD apps (`requestPartnerOrder` / `confirmPartnerOrder`).
|
|
255
|
+
*
|
|
256
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | requestPartnerOrder Field}
|
|
257
|
+
*/
|
|
258
|
+
export interface IPartnerOrder {
|
|
259
|
+
/** Original price of the product (no currency symbol, e.g., "3.99"). */
|
|
260
|
+
priceDisplay: string;
|
|
261
|
+
/** Final price including discounts (no currency symbol). */
|
|
262
|
+
price: string;
|
|
263
|
+
/** Alphanumeric coupon code for discounted pricing. */
|
|
264
|
+
couponCode?: string;
|
|
265
|
+
/** Publisher-specific SKU or unique identifier. */
|
|
266
|
+
contentKey: string;
|
|
267
|
+
/** Product identifier. */
|
|
268
|
+
code: string;
|
|
269
|
+
/** Product description (e.g., movie title). */
|
|
270
|
+
title?: string;
|
|
271
|
+
/** Order ID returned by Roku (for confirmPartnerOrder). */
|
|
272
|
+
orderID?: string;
|
|
273
|
+
pin?: string;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export type EventHandlerPartnerOrder = EventHandler<IPartnerOrder>;
|
|
277
|
+
|
|
278
|
+
/**
|
|
279
|
+
* Device attestation token returned by the `getDeviceAttestationToken` command.
|
|
280
|
+
*
|
|
281
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | getDeviceAttestationToken Command}
|
|
282
|
+
*/
|
|
283
|
+
export interface IDeviceAttestationToken {
|
|
284
|
+
/** Request status; 0 indicates success. */
|
|
285
|
+
status: number;
|
|
286
|
+
/** The nonce used to generate the token. */
|
|
287
|
+
nonce: string;
|
|
288
|
+
/** Signed JWT for device attestation verification. */
|
|
289
|
+
token: string;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export type EventHandlerDeviceAttestationToken = EventHandler<IDeviceAttestationToken>;
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* Properties for the ChannelStore component.
|
|
296
|
+
*
|
|
297
|
+
* The ChannelStore component provides an interface to the Roku Streaming Store, enabling in-app purchases,
|
|
298
|
+
* user authentication, and data retrieval. It supports commands for fetching user data, managing orders,
|
|
299
|
+
* retrieving catalogs, and handling credentials. This component wraps the `<channelStoreExt>` XML element
|
|
300
|
+
* and exposes its fields as TypeScript props and event handlers.
|
|
301
|
+
*
|
|
302
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore}
|
|
303
|
+
*/
|
|
304
|
+
export interface IChannelStoreProps {
|
|
305
|
+
id?: string;
|
|
306
|
+
/**
|
|
307
|
+
* Specifies the command to be executed (e.g., "getUserData", "getCatalog").
|
|
308
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | ChannelStore Commands}
|
|
309
|
+
*/
|
|
310
|
+
command?: ChannelStoreCommand;
|
|
311
|
+
/**
|
|
312
|
+
* Specifies the Roku customer account fields to be retrieved when the `getUserData` command
|
|
313
|
+
* is executed. Set to "all" for all available fields, or a comma-separated list of specific
|
|
314
|
+
* fields (e.g., "email,firstname,lastname").
|
|
315
|
+
* @default "all"
|
|
316
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | requestedUserData Field}
|
|
317
|
+
*/
|
|
318
|
+
requestedUserData?: string;
|
|
319
|
+
/**
|
|
320
|
+
* Configures whether the RFI screen is used for sign-ups or sign-ins.
|
|
321
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | requestedUserDataInfo Field}
|
|
322
|
+
*/
|
|
323
|
+
requestedUserDataInfoObject?: IRequestedUserDataInfo;
|
|
324
|
+
/**
|
|
325
|
+
* Fired when user data is retrieved from the `getUserData` command. Returns `invalid`
|
|
326
|
+
* if the user clicked Cancel on the RFI screen.
|
|
327
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | userData Field}
|
|
328
|
+
*/
|
|
329
|
+
onUserDataObject?: EventHandlerUserData;
|
|
330
|
+
/**
|
|
331
|
+
* Fired when user region data is retrieved from the `getUserRegionData` command.
|
|
332
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | getUserRegionData Command}
|
|
333
|
+
*/
|
|
334
|
+
onUserRegionDataObject?: EventHandlerUserRegionData;
|
|
335
|
+
/**
|
|
336
|
+
* Custom request object for advanced ChannelStore operations.
|
|
337
|
+
*/
|
|
338
|
+
request?: IChannelStoreRequest;
|
|
339
|
+
/**
|
|
340
|
+
* Fired when a custom request completes.
|
|
341
|
+
*/
|
|
342
|
+
onRequestStatus?: EventHandler<IChannelStoreRequestStatusEvent>;
|
|
343
|
+
/**
|
|
344
|
+
* Data to be stored securely for channel credentials via the `storeChannelCredData` command.
|
|
345
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | channelCredData Field}
|
|
346
|
+
*/
|
|
347
|
+
channelCredData?: string;
|
|
348
|
+
/**
|
|
349
|
+
* Fired when storing channel credential data completes.
|
|
350
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | storeChannelCredData Command}
|
|
351
|
+
*/
|
|
352
|
+
onStoreChannelCredDataStatusObject?: EventHandlerStoreChannelCredDataStatus;
|
|
353
|
+
/**
|
|
354
|
+
* Fired when channel credentials are retrieved via the `getChannelCred` command.
|
|
355
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | getChannelCred Command}
|
|
356
|
+
*/
|
|
357
|
+
onChannelCredObject?: EventHandlerChannelCred;
|
|
358
|
+
/**
|
|
359
|
+
* Fired when the catalog is retrieved from the `getCatalog` command.
|
|
360
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | catalog Field}
|
|
361
|
+
*/
|
|
362
|
+
onCatalogObject?: EventHandlerCatalog;
|
|
363
|
+
/**
|
|
364
|
+
* Contains the order to be filled when the `doOrder` command is executed.
|
|
365
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | order Field}
|
|
366
|
+
*/
|
|
367
|
+
orderObject?: IOrderItem[];
|
|
368
|
+
/**
|
|
369
|
+
* Enables incremental population of the order field. Each time this is set,
|
|
370
|
+
* the order is modified (use negative `qty` to remove items).
|
|
371
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | deltaOrder Field}
|
|
372
|
+
*/
|
|
373
|
+
deltaOrder?: IOrderItem;
|
|
374
|
+
/**
|
|
375
|
+
* Fired when the `doOrder` command completes with completion status.
|
|
376
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | orderStatus Field}
|
|
377
|
+
*/
|
|
378
|
+
onOrderStatusObject?: EventHandlerOrderStatus;
|
|
379
|
+
/**
|
|
380
|
+
* Fired when order items are processed (child nodes of orderStatus).
|
|
381
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | doOrder Command}
|
|
382
|
+
*/
|
|
383
|
+
onOrderItemsStatusObject?: EventHandlerOrderItemsStatus;
|
|
384
|
+
/**
|
|
385
|
+
* Fired when purchases are retrieved from `getPurchases` or `getAllPurchases` commands
|
|
386
|
+
* (completion status).
|
|
387
|
+
*
|
|
388
|
+
* Receives the command's status, not the purchase data: the backing field
|
|
389
|
+
* `purchasesStatusObject` is an `assocarray` holding the request node's own fields, and is
|
|
390
|
+
* `{}` when the request failed. The purchases themselves arrive on
|
|
391
|
+
* {@link IChannelStoreProps.onPurchasesObject}.
|
|
392
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | purchases Field}
|
|
393
|
+
*/
|
|
394
|
+
onPurchasesStatusObject?: EventHandlerPurchasesStatus;
|
|
395
|
+
/**
|
|
396
|
+
* Fired when purchase data is available from `getPurchases` or `getAllPurchases` commands.
|
|
397
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | purchases Field}
|
|
398
|
+
*/
|
|
399
|
+
onPurchasesObject?: EventHandlerPurchases;
|
|
400
|
+
/**
|
|
401
|
+
* Specifies the product to be ordered from a TVOD app.
|
|
402
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | requestPartnerOrder Field}
|
|
403
|
+
*/
|
|
404
|
+
requestPartnerOrderObject?: IPartnerOrder;
|
|
405
|
+
/**
|
|
406
|
+
* Fired when requesting a partner order completes.
|
|
407
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | requestPartnerOrderStatus Field}
|
|
408
|
+
*/
|
|
409
|
+
onRequestPartnerOrderStatusObject?: EventHandlerPartnerOrder;
|
|
410
|
+
/**
|
|
411
|
+
* Confirms the product being ordered from a TVOD app.
|
|
412
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | confirmPartnerOrder Field}
|
|
413
|
+
*/
|
|
414
|
+
confirmPartnerOrderObject?: IPartnerOrder;
|
|
415
|
+
/**
|
|
416
|
+
* Fired when confirming a partner order completes.
|
|
417
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | confirmPartnerOrderStatus Field}
|
|
418
|
+
*/
|
|
419
|
+
onConfirmPartnerOrderStatusObject?: EventHandlerPartnerOrder;
|
|
420
|
+
/**
|
|
421
|
+
* Fired when a device attestation token is generated via `getDeviceAttestationToken`.
|
|
422
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore | getDeviceAttestationToken Command}
|
|
423
|
+
*/
|
|
424
|
+
onDeviceAttestationTokenObject?: EventHandlerDeviceAttestationToken;
|
|
425
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// Copyright (c) 2026 Roku, Inc.
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
// TODO: This component uses a custom XML extension (channelStoreExt) rather than a
|
|
5
|
+
// native SG node, so it lives in src/ alongside other custom components (like modal-dialog)
|
|
6
|
+
// instead of in sg-nodes/.
|
|
7
|
+
|
|
8
|
+
import type { IChannelStoreProps } from "./channel-store.props";
|
|
9
|
+
import { retainAsset } from "./retain-asset";
|
|
10
|
+
import { Component } from "./sg-nodes/types";
|
|
11
|
+
import ChannelStoreXML from "./xml-components/channel-store/channelStoreExt.xml";
|
|
12
|
+
export type { IChannelStoreRequestStatusEvent } from "./channel-store.props";
|
|
13
|
+
|
|
14
|
+
export type {
|
|
15
|
+
ChannelStoreCommand,
|
|
16
|
+
ChannelStoreUserDataContext,
|
|
17
|
+
IChannelStoreRequest,
|
|
18
|
+
IUserData,
|
|
19
|
+
EventHandlerUserData,
|
|
20
|
+
IUserRegionData,
|
|
21
|
+
EventHandlerUserRegionData,
|
|
22
|
+
IRequestedUserDataInfo,
|
|
23
|
+
IStoreChannelCredDataStatus,
|
|
24
|
+
EventHandlerStoreChannelCredDataStatus,
|
|
25
|
+
IChannelCred,
|
|
26
|
+
EventHandlerChannelCred,
|
|
27
|
+
IProduct,
|
|
28
|
+
EventHandlerCatalog,
|
|
29
|
+
IOrderItem,
|
|
30
|
+
IOrderStatus,
|
|
31
|
+
EventHandlerOrderStatus,
|
|
32
|
+
EventHandlerOrderItemsStatus,
|
|
33
|
+
IPurchasesStatus,
|
|
34
|
+
EventHandlerPurchasesStatus,
|
|
35
|
+
IPurchase,
|
|
36
|
+
EventHandlerPurchases,
|
|
37
|
+
IPartnerOrder,
|
|
38
|
+
EventHandlerPartnerOrder,
|
|
39
|
+
IDeviceAttestationToken,
|
|
40
|
+
EventHandlerDeviceAttestationToken,
|
|
41
|
+
IChannelStoreProps
|
|
42
|
+
} from "./channel-store.props";
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* ChannelStore provides an interface to the Roku Streaming Store for in-app purchases,
|
|
46
|
+
* user authentication, subscription management, and credential storage.
|
|
47
|
+
*
|
|
48
|
+
* Usage follows a command pattern: set required data fields, observe the result event,
|
|
49
|
+
* then set `command` to trigger execution. Results arrive asynchronously via event handlers.
|
|
50
|
+
*
|
|
51
|
+
* @example
|
|
52
|
+
* ```tsx
|
|
53
|
+
* // Retrieve user data for sign-in
|
|
54
|
+
* <ChannelStore
|
|
55
|
+
* requestedUserData="email,firstname,lastname"
|
|
56
|
+
* command="getUserData"
|
|
57
|
+
* onUserDataObject={(data) => console.log("User data:", data)}
|
|
58
|
+
* />
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* ```tsx
|
|
63
|
+
* // Perform an in-app purchase
|
|
64
|
+
* <ChannelStore
|
|
65
|
+
* orderObject={[{ code: "item1", qty: 1 }]}
|
|
66
|
+
* command="doOrder"
|
|
67
|
+
* onOrderStatusObject={(status) => console.log("Order status:", status)}
|
|
68
|
+
* />
|
|
69
|
+
* ```
|
|
70
|
+
*
|
|
71
|
+
* @see {@link https://developer.roku.com/dev/docs/channelstore}
|
|
72
|
+
*/
|
|
73
|
+
export const ChannelStore: Component<IChannelStoreProps> = props => {
|
|
74
|
+
retainAsset(ChannelStoreXML);
|
|
75
|
+
return <channelStoreExt {...props}></channelStoreExt>;
|
|
76
|
+
};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// Copyright (c) 2026 Roku, Inc.
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
import { transactionManager } from "@roku-sdk/common/transaction";
|
|
5
|
+
import { ComponentRef, DomNode } from "@roku-sdk/interfaces";
|
|
6
|
+
import { Component, JSX, splitProps, tmTransaction } from "@roku-sdk/solid";
|
|
7
|
+
|
|
8
|
+
import { IGroupProps } from "./sg-nodes/group";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Reference type for the Container component.
|
|
12
|
+
*
|
|
13
|
+
* Extends {@link ComponentRef} with imperative methods for dynamic node
|
|
14
|
+
* insertion and removal. This provides a typed public API for pooling
|
|
15
|
+
* patterns that need to reparent nodes at runtime.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* let containerRef!: ContainerRef;
|
|
20
|
+
*
|
|
21
|
+
* // Acquire a pooled node and insert it
|
|
22
|
+
* const node = pool.acquire();
|
|
23
|
+
* containerRef.insertNode(node.element);
|
|
24
|
+
*
|
|
25
|
+
* // Later, remove the node (returns it to pool)
|
|
26
|
+
* containerRef.removeNode(node.element);
|
|
27
|
+
* pool.release(node);
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
export interface ContainerRef extends ComponentRef<IGroupProps> {
|
|
31
|
+
/**
|
|
32
|
+
* Inserts a node as a child of this container.
|
|
33
|
+
* The node is appended to the end of the children list.
|
|
34
|
+
*
|
|
35
|
+
* @param node - The DomNode to insert into this container
|
|
36
|
+
*/
|
|
37
|
+
insertNode: (node: DomNode) => void;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Removes a node from this container.
|
|
41
|
+
* The node is marked for removal and will be detached on the next commit.
|
|
42
|
+
*
|
|
43
|
+
* On firmware 15.2.x the parent link is the only strong reference to a
|
|
44
|
+
* SceneGraph node, so a committed detach destroys it and a later
|
|
45
|
+
* `insertNode` of the same node hands the render thread a deleted
|
|
46
|
+
* reference. Pooling that has to run on 15.2.x should reparent through
|
|
47
|
+
* {@link ContainerRef.insertNode} into a hidden container rather than
|
|
48
|
+
* detaching.
|
|
49
|
+
*
|
|
50
|
+
* @param node - The DomNode to remove from this container
|
|
51
|
+
*/
|
|
52
|
+
removeNode: (node: DomNode) => void;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Props for the Container component.
|
|
57
|
+
*/
|
|
58
|
+
export interface IContainerProps extends Omit<IGroupProps, "ref"> {
|
|
59
|
+
/** Callback ref to receive the ContainerRef with imperative methods. */
|
|
60
|
+
ref?: (ref: ContainerRef) => void;
|
|
61
|
+
/** Child elements to render inside the container. */
|
|
62
|
+
children?: JSX.Element;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Container is a Group wrapper that exposes typed imperative methods for
|
|
67
|
+
* dynamic node insertion and removal.
|
|
68
|
+
*
|
|
69
|
+
* This component is designed for advanced pooling patterns where nodes need
|
|
70
|
+
* to be reparented at runtime without triggering full reactive re-renders.
|
|
71
|
+
* It wraps the raw `tmTransaction.insertNode/removeNode` calls with a typed
|
|
72
|
+
* API, eliminating the need for `as any` casts and eslint-disable comments.
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* ```tsx
|
|
76
|
+
* import { Container, ContainerRef } from "@roku-sdk/components";
|
|
77
|
+
*
|
|
78
|
+
* const PooledGrid: Component = () => {
|
|
79
|
+
* let slotContainerRef!: ContainerRef;
|
|
80
|
+
*
|
|
81
|
+
* createEffect(() => {
|
|
82
|
+
* const node = pool.acquire();
|
|
83
|
+
* slotContainerRef.insertNode(node.element);
|
|
84
|
+
* });
|
|
85
|
+
*
|
|
86
|
+
* return (
|
|
87
|
+
* <Container ref={(el) => (slotContainerRef = el)}>
|
|
88
|
+
* {/* Pooled nodes are inserted here dynamically *\/}
|
|
89
|
+
* </Container>
|
|
90
|
+
* );
|
|
91
|
+
* };
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* @see {@link ContainerRef} for the imperative methods available on the ref
|
|
95
|
+
*/
|
|
96
|
+
export const Container: Component<IContainerProps> = props => {
|
|
97
|
+
// Use splitProps to preserve reactivity on spread props
|
|
98
|
+
const [local, groupProps] = splitProps(props, ["ref", "children"]);
|
|
99
|
+
|
|
100
|
+
return (
|
|
101
|
+
<group
|
|
102
|
+
{...groupProps}
|
|
103
|
+
ref={(el: DomNode) => {
|
|
104
|
+
// Extend the element with imperative methods
|
|
105
|
+
const containerRef = el as ContainerRef;
|
|
106
|
+
|
|
107
|
+
// `tmTransaction` assumes an open transaction — the Solid renderer
|
|
108
|
+
// opens one before every call it makes. These methods run outside the
|
|
109
|
+
// renderer, so they open it themselves. `insertNode` reaches native
|
|
110
|
+
// `appendNode` synchronously (firmware 15.2.x raises a render-thread
|
|
111
|
+
// exception if no transaction is open) and `removeNode` only queues
|
|
112
|
+
// the detach for the pre-commit hook, which a commit has to drive.
|
|
113
|
+
containerRef.insertNode = (node: DomNode) => {
|
|
114
|
+
transactionManager.startTransaction();
|
|
115
|
+
tmTransaction.insertNode(el, node);
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
containerRef.removeNode = (node: DomNode) => {
|
|
119
|
+
transactionManager.startTransaction();
|
|
120
|
+
tmTransaction.removeNode(el, node);
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
// Pass the extended ref to the consumer
|
|
124
|
+
local.ref?.(containerRef);
|
|
125
|
+
}}
|
|
126
|
+
>
|
|
127
|
+
{local.children}
|
|
128
|
+
</group>
|
|
129
|
+
);
|
|
130
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Copyright (c) 2026 Roku, Inc.
|
|
2
|
+
// SPDX-License-Identifier: MIT
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* JSX runtime entry point for the **frozen core** property contract.
|
|
6
|
+
*
|
|
7
|
+
* This module exists to be named by `jsxImportSource` in an application's tsconfig:
|
|
8
|
+
*
|
|
9
|
+
* ```jsonc
|
|
10
|
+
* { "compilerOptions": { "jsxImportSource": "@roku-sdk/components/core" } }
|
|
11
|
+
* ```
|
|
12
|
+
*
|
|
13
|
+
* TypeScript then resolves JSX intrinsic element types from
|
|
14
|
+
* `@roku-sdk/components/core/jsx-runtime`, and the sibling `core-jsx.d.ts` augments exactly this
|
|
15
|
+
* specifier with an intrinsic map keyed to the `I*CoreProps` interfaces. So `<poster>` resolves to
|
|
16
|
+
* `IPosterCoreProps` rather than the full `IPosterProps`, and a property outside the frozen subset
|
|
17
|
+
* is a compile error naming the property.
|
|
18
|
+
*
|
|
19
|
+
* Two things make this the enforcement point rather than a convenience:
|
|
20
|
+
*
|
|
21
|
+
* 1. **A module-scoped `JSX` namespace replaces the global one, it does not merge with it.** The
|
|
22
|
+
* full intrinsic map in `rsg-ts/src/types/sg-jsx.d.ts` augments a different specifier, so it is
|
|
23
|
+
* not in scope for a build that points here — provided that map is kept out of the program.
|
|
24
|
+
* That is the one easily-missed part of the setup: an app opting in must also drop
|
|
25
|
+
* `@roku-sdk/components/jsx` from `types[]` and the inherited `sg-jsx.d.ts` from `files[]`,
|
|
26
|
+
* because the star re-export below would otherwise carry those augmentations back in.
|
|
27
|
+
* 2. **Application source is unchanged.** Only the tsconfig differs.
|
|
28
|
+
*
|
|
29
|
+
* The runtime behaviour is unchanged — the factory is re-exported from `@roku-sdk/solid` — because
|
|
30
|
+
* the divergence is purely a compile-time *type* contract, not a second implementation. Builds do
|
|
31
|
+
* not read `jsxImportSource` at all: esbuild is configured with a classic `jsxFactory` and
|
|
32
|
+
* `babel-preset-solid` is pinned to `moduleName: "@roku-sdk/solid"`.
|
|
33
|
+
*
|
|
34
|
+
* The re-export must stay a star re-export. TypeScript resolves `JSX.Element`,
|
|
35
|
+
* `JSX.ElementChildrenAttribute` and `JSX.IntrinsicAttributes` from this same module, and those
|
|
36
|
+
* come from SolidJS; a named re-export of the factory alone would leave them undefined.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
export * from "@roku-sdk/solid/jsx-runtime";
|