diff --git a/docs/api.md b/docs/api.md
index 57e59135..fb5bced7 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -51,12 +51,9 @@ The `SpatialNavigationNode` component receives the following props:
| `onSelect` | `function` | `undefined` | Callback function to be called when the node is selected. |
| `orientation` | `'vertical' \| 'horizontal` | `'vertical'` | Determines the orientation of the node. |
| `isFocusable` | `boolean` | `false` | Determines if the node is focusable or not. If it's `true`, the `children` prop must be a function that returns a React element and accepts a parameter with a `isFocused` property. If it's `false` or not provided, `children` can be any valid React node. |
-
-| `alignInGrid` | `boolean` | `false` | Determines whether child lists should behave like a grid.
-
-| `indexRange` | `number[]` | `undefined` | Determines the indexes when using long nodes in a grid. If a grid row has one `indexRange`, you should specify each element's `indexRange`. You can check for more details in [`GridWithLongNodesPage`](https://github.com/bamlab/react-tv-space-navigation/blob/31bfe1def4a7e18e9e41f26a520090d1b7a5b149/packages/example/src/pages/GridWithLongNodesPage.tsx) example or in [lrud documentation](https://github.com/bbc/lrud/blob/master/docs/usage.md#indexrange).
-
-| `children` | `function` or `ReactNode` | `null` | Child elements of the component. It can be a function that returns a React element and accepts a parameter with a `isFocused` property when `isFocusable` is `true`. If `isFocusable` is `false` or not provided, it can be any valid React node. |
+| `alignInGrid` | `boolean` | `false` | Determines whether child lists should behave like a grid. |
+| `indexRange` | `number[]` | `undefined` | Determines the indexes when using long nodes in a grid. If a grid row has one `indexRange`, you should specify each element's `indexRange`. You can check for more details in [`GridWithLongNodesPage`](https://github.com/bamlab/react-tv-space-navigation/blob/31bfe1def4a7e18e9e41f26a520090d1b7a5b149/packages/example/src/pages/GridWithLongNodesPage.tsx) example or in [lrud documentation](https://github.com/bbc/lrud/blob/master/docs/usage.md#indexrange). |
+| `children` | `({ isFocused, isActive }: { isFocused: boolean, isActive: boolean }) => ReactNode` or `ReactNode` | `null` | Child elements of the component. It can be a function that returns a React element and accepts a parameter with a `isFocused` property when `isFocusable` is `true`. If `isFocusable` is `false` or not provided, it can be any valid React node. |
## Usage
@@ -71,6 +68,21 @@ The `SpatialNavigationNode` component receives the following props:
```
+```jsx
+
+ {({ isActive }) => (
+ // This node is active if one of its nodes is focused
+
+
+ )}
+
+```
+
+Note : It is not recommend to use isActive on virtualized focusable nodes, as this can lead to unexpected behaviour.
+
## Important note
The SpatialNavigationNode will use the ref of your component to handle the scrolling.
diff --git a/packages/example/src/design-system/theme/colors.ts b/packages/example/src/design-system/theme/colors.ts
index c948494a..de45b475 100644
--- a/packages/example/src/design-system/theme/colors.ts
+++ b/packages/example/src/design-system/theme/colors.ts
@@ -16,6 +16,7 @@ export const colors = {
background: {
main: '#111111',
mainHover: '#1a1a1a',
+ mainActive: '#2a2a2a',
light: '#EEF0F5',
lightHover: '#D5D7DC',
contrastText: '#FFFFFF',
diff --git a/packages/example/src/modules/program/view/ProgramList.tsx b/packages/example/src/modules/program/view/ProgramList.tsx
index 30ded24e..2272eab5 100644
--- a/packages/example/src/modules/program/view/ProgramList.tsx
+++ b/packages/example/src/modules/program/view/ProgramList.tsx
@@ -3,7 +3,7 @@ import { useTheme } from '@emotion/react';
import { useNavigation } from '@react-navigation/native';
import { NativeStackNavigationProp } from '@react-navigation/native-stack';
import { useCallback, useMemo } from 'react';
-import { SpatialNavigationVirtualizedList } from 'react-tv-space-navigation';
+import { SpatialNavigationNode, SpatialNavigationVirtualizedList } from 'react-tv-space-navigation';
import { RootStackParamList } from '../../../../App';
import { ProgramInfo } from '../domain/programInfo';
import { getPrograms } from '../infra/programInfos';
@@ -37,17 +37,21 @@ export const ProgramList = ({
const programInfos = useMemo(() => getPrograms(), []);
return (
-
-
-
+
+ {({ isActive }) => (
+
+
+
+ )}
+
);
};
@@ -63,8 +67,10 @@ export const ProgramsRow = ({ containerStyle }: { containerStyle?: object }) =>
);
};
-const Container = styled.View(({ theme }) => ({
- backgroundColor: theme.colors.background.mainHover,
+const Container = styled.View<{ isActive: boolean }>(({ isActive, theme }) => ({
+ backgroundColor: isActive
+ ? theme.colors.background.mainActive
+ : theme.colors.background.mainHover,
padding: theme.spacings.$8,
borderRadius: scaledPixels(20),
overflow: 'hidden',
diff --git a/packages/lib/src/spatial-navigation/components/Node.tsx b/packages/lib/src/spatial-navigation/components/Node.tsx
index 32d4f3e7..ab34c1aa 100644
--- a/packages/lib/src/spatial-navigation/components/Node.tsx
+++ b/packages/lib/src/spatial-navigation/components/Node.tsx
@@ -11,11 +11,11 @@ import { NodeIndexRange } from '@bam.tech/lrud';
type FocusableProps = {
isFocusable: true;
- children: (props: { isFocused: boolean }) => React.ReactElement;
+ children: (props: { isFocused: boolean; isActive: boolean }) => React.ReactElement;
};
type NonFocusableProps = {
isFocusable?: false;
- children: React.ReactElement;
+ children: React.ReactElement | ((props: { isActive: boolean }) => React.ReactElement);
};
type DefaultProps = {
onFocus?: () => void;
@@ -79,6 +79,7 @@ export const SpatialNavigationNode = ({
const spatialNavigator = useSpatialNavigator();
const parentId = useParentId();
const [isFocused, setIsFocused] = useState(false);
+ const [isActive, setIsActive] = useState(false);
// If parent changes, we have to re-register the Node + all children -> adding the parentId to the nodeId makes the children re-register.
const id = useUniqueId({ prefix: `${parentId}_node_` });
@@ -122,6 +123,8 @@ export const SpatialNavigationNode = ({
orientation,
isIndexAlign: alignInGrid,
indexRange,
+ onActive: () => setIsActive(true),
+ onInactive: () => setIsActive(false),
});
return () => spatialNavigator.unregisterNode(id);
@@ -135,7 +138,9 @@ export const SpatialNavigationNode = ({
return (
- {typeof children === 'function' ? bindRefToChild(children({ isFocused })) : children}
+ {typeof children === 'function'
+ ? bindRefToChild(children({ isFocused, isActive }))
+ : children}
);
};