@tvuikit/navigation-react 0.1.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/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +607 -0
- package/dist/index.js.map +1 -0
- package/dist/react/CustomFocusable.d.ts +87 -0
- package/dist/react/CustomFocusable.d.ts.map +1 -0
- package/dist/react/DebugPanel.d.ts +42 -0
- package/dist/react/DebugPanel.d.ts.map +1 -0
- package/dist/react/FocusGroup.d.ts +51 -0
- package/dist/react/FocusGroup.d.ts.map +1 -0
- package/dist/react/Focusable.d.ts +39 -0
- package/dist/react/Focusable.d.ts.map +1 -0
- package/dist/react/NavigationProvider.d.ts +166 -0
- package/dist/react/NavigationProvider.d.ts.map +1 -0
- package/dist/react/focusGroupContext.d.ts +5 -0
- package/dist/react/focusGroupContext.d.ts.map +1 -0
- package/dist/react/useCustomFocusable.d.ts +76 -0
- package/dist/react/useCustomFocusable.d.ts.map +1 -0
- package/dist/react/useFocusEvents.d.ts +39 -0
- package/dist/react/useFocusEvents.d.ts.map +1 -0
- package/dist/react/useFocusable.d.ts +44 -0
- package/dist/react/useFocusable.d.ts.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import type { NodeId, Rect, NavigationStore } from "@tvuikit/navigation";
|
|
2
|
+
export type UseCustomFocusableOptions = {
|
|
3
|
+
/**
|
|
4
|
+
* The navigation store instance.
|
|
5
|
+
* Required - pass the store directly to avoid cross-reconciler context issues.
|
|
6
|
+
*/
|
|
7
|
+
store: NavigationStore;
|
|
8
|
+
/**
|
|
9
|
+
* Source name for this focusable (e.g., "pixi", "three").
|
|
10
|
+
* Default: "custom"
|
|
11
|
+
*/
|
|
12
|
+
source?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Unique identifier for this focusable node (local ID, without source prefix).
|
|
15
|
+
* Will be namespaced as "source:id" internally.
|
|
16
|
+
*/
|
|
17
|
+
id: NodeId;
|
|
18
|
+
/**
|
|
19
|
+
* Bounding rectangle in viewport coordinates.
|
|
20
|
+
* Must be in the same coordinate space as DOM elements (client coordinates).
|
|
21
|
+
* For canvas/WebGL elements, add the canvas offset to local coordinates.
|
|
22
|
+
*/
|
|
23
|
+
rect: Rect;
|
|
24
|
+
/**
|
|
25
|
+
* Optional focus group id for this node.
|
|
26
|
+
* If not provided, attempts to inherit from the nearest FocusGroup context.
|
|
27
|
+
*/
|
|
28
|
+
groupId?: string | null;
|
|
29
|
+
/**
|
|
30
|
+
* If true, element cannot receive focus.
|
|
31
|
+
*/
|
|
32
|
+
disabled?: boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Called when this element gains focus.
|
|
35
|
+
*/
|
|
36
|
+
onFocus?: () => void;
|
|
37
|
+
/**
|
|
38
|
+
* Called when this element loses focus.
|
|
39
|
+
*/
|
|
40
|
+
onBlur?: () => void;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Hook to register a custom (non-DOM) element as focusable and track its focus state.
|
|
44
|
+
*
|
|
45
|
+
* Use this for elements rendered via WebGL, Canvas, or other non-DOM technologies.
|
|
46
|
+
* Unlike `useFocusable`, you must provide the bounding rect manually and pass
|
|
47
|
+
* the store directly (to avoid cross-reconciler context issues).
|
|
48
|
+
*
|
|
49
|
+
* Uses `useSyncExternalStore` for tear-free focus state updates,
|
|
50
|
+
* compatible with React concurrent features.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```tsx
|
|
54
|
+
* function PixiTile({ store, id, x, y, canvasOffset }: Props) {
|
|
55
|
+
* const rect = useMemo(() => ({
|
|
56
|
+
* x: canvasOffset.x + x,
|
|
57
|
+
* y: canvasOffset.y + y,
|
|
58
|
+
* w: 200,
|
|
59
|
+
* h: 150,
|
|
60
|
+
* }), [canvasOffset.x, canvasOffset.y, x, y]);
|
|
61
|
+
*
|
|
62
|
+
* const { focused } = useCustomFocusable({
|
|
63
|
+
* store,
|
|
64
|
+
* source: "pixi",
|
|
65
|
+
* id,
|
|
66
|
+
* rect,
|
|
67
|
+
* });
|
|
68
|
+
*
|
|
69
|
+
* return <Graphics draw={(g) => drawTile(g, focused)} />;
|
|
70
|
+
* }
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export declare function useCustomFocusable(opts: UseCustomFocusableOptions): {
|
|
74
|
+
focused: boolean;
|
|
75
|
+
};
|
|
76
|
+
//# sourceMappingURL=useCustomFocusable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCustomFocusable.d.ts","sourceRoot":"","sources":["../../src/react/useCustomFocusable.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAGzE,MAAM,MAAM,yBAAyB,GAAG;IACtC;;;OAGG;IACH,KAAK,EAAE,eAAe,CAAC;IACvB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;;;OAIG;IACH,IAAI,EAAE,IAAI,CAAC;IACX;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,yBAAyB,GAAG;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,CA+DxF"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { NavigationEventMap, NavigationStore } from "@tvuikit/navigation";
|
|
2
|
+
type EventType = keyof NavigationEventMap;
|
|
3
|
+
/**
|
|
4
|
+
* Handler map for subscribing to multiple events at once.
|
|
5
|
+
*/
|
|
6
|
+
export type FocusEventHandlers = {
|
|
7
|
+
[K in EventType]?: (detail: NavigationEventMap[K]["detail"]) => void;
|
|
8
|
+
};
|
|
9
|
+
type UseFocusEventsOptions = {
|
|
10
|
+
store?: NavigationStore;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Subscribe to a single navigation event.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```tsx
|
|
17
|
+
* useFocusEvents("focus", ({ nodeId }) => {
|
|
18
|
+
* console.log("Focused:", nodeId);
|
|
19
|
+
* });
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
export declare function useFocusEvents<T extends EventType>(type: T, handler: (detail: NavigationEventMap[T]["detail"]) => void, options?: UseFocusEventsOptions): void;
|
|
23
|
+
/**
|
|
24
|
+
* Subscribe to multiple navigation events at once.
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```tsx
|
|
28
|
+
* useFocusEvents({
|
|
29
|
+
* focus: ({ nodeId }) => console.log("Focused:", nodeId),
|
|
30
|
+
* move: ({ from, to, direction }) => console.log("Moved:", direction),
|
|
31
|
+
* reject: ({ reason }) => {
|
|
32
|
+
* if (reason === "boundary-blocked") playBoundarySound();
|
|
33
|
+
* },
|
|
34
|
+
* });
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function useFocusEvents(handlers: FocusEventHandlers, options?: UseFocusEventsOptions): void;
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=useFocusEvents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFocusEvents.d.ts","sourceRoot":"","sources":["../../src/react/useFocusEvents.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAG/E,KAAK,SAAS,GAAG,MAAM,kBAAkB,CAAC;AAE1C;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG;KAC9B,CAAC,IAAI,SAAS,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,IAAI;CACrE,CAAC;AAEF,KAAK,qBAAqB,GAAG;IAC3B,KAAK,CAAC,EAAE,eAAe,CAAC;CACzB,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,SAAS,EAChD,IAAI,EAAE,CAAC,EACP,OAAO,EAAE,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,IAAI,EAC1D,OAAO,CAAC,EAAE,qBAAqB,GAC9B,IAAI,CAAC;AAER;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,kBAAkB,EAC5B,OAAO,CAAC,EAAE,qBAAqB,GAC9B,IAAI,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import type { NodeId } from "@tvuikit/navigation";
|
|
2
|
+
export type UseFocusableOptions = {
|
|
3
|
+
id: NodeId;
|
|
4
|
+
/**
|
|
5
|
+
* Optional focus group id for this node.
|
|
6
|
+
* If not provided, inherits from the nearest FocusGroup context.
|
|
7
|
+
*/
|
|
8
|
+
groupId?: string | null;
|
|
9
|
+
/**
|
|
10
|
+
* If true, element cannot receive focus.
|
|
11
|
+
*/
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Called when this element gains focus.
|
|
15
|
+
*/
|
|
16
|
+
onFocus?: () => void;
|
|
17
|
+
/**
|
|
18
|
+
* Called when this element loses focus.
|
|
19
|
+
*/
|
|
20
|
+
onBlur?: () => void;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Hook to register a DOM element as focusable and track its focus state.
|
|
24
|
+
*
|
|
25
|
+
* Uses `useSyncExternalStore` for tear-free focus state updates,
|
|
26
|
+
* compatible with React concurrent features.
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```tsx
|
|
30
|
+
* function Button({ id }: { id: string }) {
|
|
31
|
+
* const { ref, focused } = useFocusable({ id });
|
|
32
|
+
* return (
|
|
33
|
+
* <button ref={ref} className={focused ? "focused" : ""}>
|
|
34
|
+
* Click me
|
|
35
|
+
* </button>
|
|
36
|
+
* );
|
|
37
|
+
* }
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare function useFocusable(opts: UseFocusableOptions): {
|
|
41
|
+
ref: (el: HTMLElement | null) => void;
|
|
42
|
+
focused: boolean;
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=useFocusable.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useFocusable.d.ts","sourceRoot":"","sources":["../../src/react/useFocusable.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAIlD,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,MAAM,CAAC;IACX;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB;;OAEG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;OAEG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;CACrB,CAAC;AAEF;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,mBAAmB;cAgD7C,WAAW,GAAG,IAAI;;EAsB1B"}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@tvuikit/navigation-react",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "React integration for TVKit Navigation. Hooks, components, and providers for spatial navigation.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"sideEffects": false,
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"author": "TVKit Team",
|
|
9
|
+
"homepage": "https://github.com/tvkit/navigation#readme",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/tvkit/navigation.git",
|
|
13
|
+
"directory": "packages/react"
|
|
14
|
+
},
|
|
15
|
+
"bugs": {
|
|
16
|
+
"url": "https://github.com/tvkit/navigation/issues"
|
|
17
|
+
},
|
|
18
|
+
"keywords": [
|
|
19
|
+
"tv",
|
|
20
|
+
"navigation",
|
|
21
|
+
"react",
|
|
22
|
+
"hooks",
|
|
23
|
+
"focus",
|
|
24
|
+
"spatial",
|
|
25
|
+
"tvkit",
|
|
26
|
+
"smart-tv"
|
|
27
|
+
],
|
|
28
|
+
"publishConfig": {
|
|
29
|
+
"access": "public"
|
|
30
|
+
},
|
|
31
|
+
"files": ["dist"],
|
|
32
|
+
"exports": {
|
|
33
|
+
".": {
|
|
34
|
+
"types": "./dist/index.d.ts",
|
|
35
|
+
"import": "./dist/index.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"main": "./dist/index.js",
|
|
39
|
+
"module": "./dist/index.js",
|
|
40
|
+
"types": "./dist/index.d.ts",
|
|
41
|
+
"peerDependencies": {
|
|
42
|
+
"@tvuikit/navigation": "^0.1.0",
|
|
43
|
+
"react": ">=18.0.0",
|
|
44
|
+
"react-dom": ">=18.0.0"
|
|
45
|
+
},
|
|
46
|
+
"peerDependenciesMeta": {
|
|
47
|
+
"react-dom": {
|
|
48
|
+
"optional": true
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@tvuikit/navigation": "file:../core"
|
|
53
|
+
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"build": "vite build && npm run build:types",
|
|
56
|
+
"build:types": "tsc -p tsconfig.types.json",
|
|
57
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|