@roku-sdk/solid 2.18.0 → 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/EXPORTS.md +1 -0
- package/package.json +5 -5
- package/src/solid.ts +39 -0
package/EXPORTS.md
CHANGED
|
@@ -192,6 +192,7 @@ These are SDK-owned symbols — not re-exports from `solid-js`. They power the R
|
|
|
192
192
|
|---|---|---|
|
|
193
193
|
| `registerTagAlias` | Function | `registerTagAlias(tag, resolve)` — create the SceneGraph node type `resolve()` returns whenever `tag` is created. Used by `@roku-sdk/runtime` and `@roku-sdk/compat` to choose between a firmware node and its shim; apps do not normally call it. |
|
|
194
194
|
| `hasTagAlias` | Function | `hasTagAlias(tag)` — whether `tag` already has an alias, so a default can be registered without replacing one installed earlier. |
|
|
195
|
+
| `registerSetPropertyObserver` | Function | `registerSetPropertyObserver(observer)` — invoke `observer(node, name, value)` after every `tmTransaction.setProperty`. Used by `__DEV__` diagnostics in `@roku-sdk/components` (Effect gradient validation); apps do not normally call it. Empty-list fast path when nothing is registered. |
|
|
195
196
|
|
|
196
197
|
### Renderer Runtime Hooks
|
|
197
198
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@roku-sdk/solid",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.19.0",
|
|
4
4
|
"description": "Roku SceneGraph modules",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -28,13 +28,13 @@
|
|
|
28
28
|
"node": ">=24.0.0"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"solid-js": "^1.9.
|
|
32
|
-
"@roku-sdk/common": "2.
|
|
33
|
-
"@roku-sdk/interfaces": "2.
|
|
31
|
+
"solid-js": "^1.9.17",
|
|
32
|
+
"@roku-sdk/common": "2.19.0",
|
|
33
|
+
"@roku-sdk/interfaces": "2.19.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"typescript": "^5.9.3",
|
|
37
|
-
"@roku-sdk/dev-tools": "2.
|
|
37
|
+
"@roku-sdk/dev-tools": "2.19.0"
|
|
38
38
|
},
|
|
39
39
|
"author": "Roku Inc",
|
|
40
40
|
"license": "MIT",
|
package/src/solid.ts
CHANGED
|
@@ -173,6 +173,43 @@ type TmTransaction = {
|
|
|
173
173
|
preCommit(): void;
|
|
174
174
|
};
|
|
175
175
|
|
|
176
|
+
/** Called after `tmTransaction.setProperty` applies a property (including event handlers). */
|
|
177
|
+
export type SetPropertyObserver = (node: DomNode, name: string, value: TmValue) => void;
|
|
178
|
+
|
|
179
|
+
const setPropertyObservers: SetPropertyObserver[] = [];
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Register a callback invoked after every successful `tmTransaction.setProperty`.
|
|
183
|
+
* Observers are skipped entirely when none are registered (empty-list fast path).
|
|
184
|
+
*
|
|
185
|
+
* Intended for `__DEV__` diagnostics that need to see intrinsic JSX props (e.g. Effect
|
|
186
|
+
* gradient validation). Production builds that never register pay only an array-length check.
|
|
187
|
+
*
|
|
188
|
+
* Returns an unsubscribe function.
|
|
189
|
+
*/
|
|
190
|
+
export const registerSetPropertyObserver = (observer: SetPropertyObserver): (() => void) => {
|
|
191
|
+
setPropertyObservers.push(observer);
|
|
192
|
+
return () => {
|
|
193
|
+
const index = setPropertyObservers.indexOf(observer);
|
|
194
|
+
if (index !== -1) {
|
|
195
|
+
setPropertyObservers.splice(index, 1);
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const notifySetPropertyObservers = (node: DomNode, name: string, value: TmValue): void => {
|
|
201
|
+
if (setPropertyObservers.length === 0) return;
|
|
202
|
+
for (const observer of setPropertyObservers) {
|
|
203
|
+
// Observers are dev-only diagnostics; one that throws must not abort the
|
|
204
|
+
// transaction's setProperty call for every other observer and consumer.
|
|
205
|
+
try {
|
|
206
|
+
observer(node, name, value);
|
|
207
|
+
} catch (error) {
|
|
208
|
+
console.error("[solid] setProperty observer threw:", error);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
|
|
176
213
|
export interface Renderer<NodeType> {
|
|
177
214
|
render(code: () => NodeType, node: NodeType): () => void;
|
|
178
215
|
effect<T>(fn: (prev?: T) => T, init?: T): void;
|
|
@@ -456,6 +493,7 @@ export const tmTransaction: TmTransaction = {
|
|
|
456
493
|
observerCallbacks.set(nodeRef, callbacks);
|
|
457
494
|
}
|
|
458
495
|
callbacks.set(propRef, value as () => void);
|
|
496
|
+
notifySetPropertyObservers(node, name, value);
|
|
459
497
|
return;
|
|
460
498
|
} else {
|
|
461
499
|
switch (typeof value) {
|
|
@@ -499,6 +537,7 @@ export const tmTransaction: TmTransaction = {
|
|
|
499
537
|
if (typeof prev === "object" && isDomNode(prev as DomNode)) {
|
|
500
538
|
nodesToRemove.add(prev as DomNode);
|
|
501
539
|
}
|
|
540
|
+
notifySetPropertyObservers(node, name, value);
|
|
502
541
|
},
|
|
503
542
|
insertNode: (parent: DomNode, node: DomNode, anchor?: DomNode): void => {
|
|
504
543
|
// Do nothing if the node is anchor itself
|