@lightningtv/solid
Advanced tools
Comparing version
@@ -1,14 +0,13 @@ | ||
import { Component, ValidComponent } from "solid-js"; | ||
export declare const Grid: Component<{ | ||
import { ValidComponent } from "solid-js"; | ||
import { type NodeProps, type ElementNode } from "@lightningtv/solid"; | ||
export declare const Grid: <T>(props: { | ||
item: ValidComponent; | ||
itemHeight: number; | ||
itemWidth: number; | ||
itemHeight?: number; | ||
itemWidth?: number; | ||
itemOffset?: number; | ||
items: Array<{ | ||
id: string; | ||
}>; | ||
items: T[]; | ||
columns?: number; | ||
looping?: boolean; | ||
refocusParent?: () => void; | ||
}>; | ||
onSelectedChanged?: (index: number, grid: ElementNode, elm?: ElementNode) => void; | ||
} & NodeProps) => import("solid-js").JSX.Element; | ||
export default Grid; |
import { For, createSignal, createMemo } from "solid-js"; | ||
import { View, Dynamic } from "@lightningtv/solid"; | ||
import { createEffect } from "solid-js"; | ||
export const Grid = props => { | ||
const [focusedIndex, setFocusedIndex] = createSignal(0, { equals: false }); | ||
import { View, Dynamic, isFunction } from "@lightningtv/solid"; | ||
export const Grid = (props) => { | ||
const [focusedIndex, setFocusedIndex] = createSignal(0); | ||
const baseColumns = 4; | ||
const columns = createMemo(() => props.columns || baseColumns); | ||
const totalWidth = createMemo(() => (props.itemWidth || 300) + (props.itemOffset || 0)); | ||
const totalHeight = createMemo(() => (props.itemHeight || 300) + (props.itemOffset || 0)); | ||
const moveFocus = (delta) => { | ||
const totalWidth = createMemo(() => (props.itemWidth ?? 300) + (props.itemOffset ?? 0)); | ||
const totalHeight = createMemo(() => (props.itemHeight ?? 300) + (props.itemOffset ?? 0)); | ||
const moveFocus = (delta, elm) => { | ||
if (!props.items || props.items.length === 0) | ||
return false; | ||
const newIndex = focusedIndex() + delta; | ||
@@ -18,4 +19,3 @@ if (newIndex >= 0 && newIndex < props.items.length) { | ||
if (delta < 0) { | ||
// Handle wrap to the last row | ||
const lastRowStart = totalItems - (totalItems % columns()); | ||
const lastRowStart = totalItems - (totalItems % columns()) || totalItems - columns(); | ||
const target = lastRowStart + (focusedIndex() % columns()); | ||
@@ -25,14 +25,13 @@ setFocusedIndex(target < totalItems ? target : target - columns()); | ||
else { | ||
// Handle wrap to the first row | ||
setFocusedIndex(focusedIndex() % columns()); | ||
} | ||
} | ||
else if (props.refocusParent) { | ||
props.refocusParent(); | ||
} | ||
const focusedElm = elm.children[focusedIndex()]; | ||
focusedElm.setFocus(); | ||
isFunction(props.onSelectedChanged) && props.onSelectedChanged.call(elm, focusedIndex(), elm, focusedElm); | ||
return true; | ||
}; | ||
const handleHorizontalFocus = (delta) => { | ||
if (!props.items) { | ||
return; | ||
} | ||
const handleHorizontalFocus = (delta, elm) => { | ||
if (!props.items || props.items.length === 0) | ||
return false; | ||
const newIndex = focusedIndex() + delta; | ||
@@ -45,17 +44,22 @@ const isWithinRow = Math.floor(newIndex / columns()) === Math.floor(focusedIndex() / columns()); | ||
const rowStart = Math.floor(focusedIndex() / columns()) * columns(); | ||
const rowEnd = rowStart + columns() - 1; | ||
const rowEnd = Math.min(rowStart + columns() - 1, props.items.length - 1); | ||
setFocusedIndex(delta > 0 ? (newIndex > rowEnd ? rowStart : newIndex) : newIndex < rowStart ? rowEnd : newIndex); | ||
} | ||
else if (props.refocusParent) { | ||
props.refocusParent(); | ||
else { | ||
return false; | ||
} | ||
const focusedElm = elm.children[focusedIndex()]; | ||
focusedElm.setFocus(); | ||
isFunction(props.onSelectedChanged) && props.onSelectedChanged.call(elm, focusedIndex(), elm, focusedElm); | ||
return true; | ||
}; | ||
let gridRef; | ||
createEffect(() => { | ||
const index = focusedIndex(); | ||
gridRef.children[index]?.setFocus(); | ||
}); | ||
return (<View {...props} ref={gridRef} onUp={() => moveFocus(-columns())} onDown={() => moveFocus(columns())} onLeft={() => handleHorizontalFocus(-1)} onRight={() => handleHorizontalFocus(1)} onFocus={() => handleHorizontalFocus(0)} strictBounds={false} x={20} y={-Math.floor(focusedIndex() / columns()) * totalHeight() + 20} transition={{ y: true }}> | ||
function onFocus() { | ||
handleHorizontalFocus(0, this); | ||
} | ||
const scrollY = createMemo(() => -Math.floor(focusedIndex() / columns()) * totalHeight() + (props.y || 0)); | ||
return (<View {...props} onUp={(_e, elm) => moveFocus(-columns(), elm)} onDown={(_e, elm) => moveFocus(columns(), elm)} onLeft={(_e, elm) => handleHorizontalFocus(-1, elm)} onRight={(_e, elm) => handleHorizontalFocus(1, elm)} onFocus={onFocus} strictBounds={false} y={scrollY()} transition={{ y: true }}> | ||
<For each={props.items}> | ||
{(item, index) => (<Dynamic component={props.item} item={item} x={(index() % columns()) * totalWidth()} y={Math.floor(index() / columns()) * totalHeight()} width={props.itemWidth} height={props.itemHeight}/>)} | ||
{(item, index) => { | ||
return (<Dynamic component={props.item} item={item} x={(index() % columns()) * totalWidth()} y={Math.floor(index() / columns()) * totalHeight()} width={props.itemWidth} height={props.itemHeight}/>); | ||
}} | ||
</For> | ||
@@ -62,0 +66,0 @@ </View>); |
{ | ||
"name": "@lightningtv/solid", | ||
"version": "2.7.1", | ||
"version": "2.7.2", | ||
"description": "Lightning Renderer for Solid Universal", | ||
@@ -5,0 +5,0 @@ "type": "module", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
246208
0.65%3464
0.06%