Constructor initializes the event dispatcher and state manager.
Private Optional_The exact bound handler registered with the current data source, kept so it can be unregistered on detach.
Private_The current data source instance.
Private_Whether a data source change was skipped because the renderer was released.
Private_Re-entrancy guard: true while processing data source changes. Changes that arrive during processing are queued.
Private_Queued changes to process after the current batch completes (avoids onContentReady -> appendRows re-entrancy).
Private_True after hibernateVisibleRows until wakeVisibleRows.
OptionalactiveIf present, an animation currently targeting this view (or its subviews).
PrivateactiveDirection key for an in-flight long press handled by this collection view (Key.None if none).
IHosannaView
PrivateappliedLast direction propagated to mounted rows; avoids relayout for unrelated state updates.
OptionalaudioThis hint can be used in conjunction with the audio guide item
OptionalaudioBase animation duration for normal scrolling (in milliseconds).
PrivateblockPrivatecachedCached virtual Y position for the focused row.
PrivatecachedCached virtual Y position for the next row.
PrivatecachedRender events for the collection view. We maintain a pool of render events to avoid creating new ones for each render.
Indicates whether the element can receive focus.
These are the children that are rendered on screen in the tree structure of the view
Injected collection view DSL manager.
Focus manager for the collection view.
Indicdates whether the view is a focus group which means it can have a focused child Otherwise it will be focused itself
The root container group for the collection view.
OptionalcustomOptionaldataThe data source for the collection view.
Direction of navigation (1 for down/right, -1 for up/left).
Whether DSL is enabled for the collection view.
Private ReadonlyeventEvent dispatcher for handling collection view events.
Duration for fast scrolling animations (in milliseconds).
PrivatefirstThe index of the first visible row.
The height of the floating focus area.
PrivatefocusedThe X position of the currently focused cell's center for FocusOnClosestItem strategy.
OptionalfocusedThe indices of the currently focused row and item.
Private ReadonlyfocusState manager for focus event tracking.
The appearance of the focus indicator.
OptionalfocusPrivatehasGuard flag to prevent duplicate calls to onInteractionComplete for the same animation completion.
PrivatehasInjected instance pool for row reuse.
ReadonlyinteractionsInteraction queue manager for handling queued key presses during animations.
Whether the collection view is currently animating.
PrivateisWhether content has been set.
Indicates whether the element is currently focused.
PrivateisWhether the focus switch (refocusing) is internal. This is used to prevent the focus event from being dispatched when the collection view is "fake blurred" or "fake focused" coz CustomRow gets focus
PrivateisIf true, this view has been presented in an AggregateViewController
PrivateisWhether the collection view has been rendered.
Automatic keyboard avoidance opt-out. When a software keyboard appears, the framework translates the visible screen to keep the editing input in view; set 'none' on the screen or the input to disable. Plain field (not reactive) — checked at keyboard-show time.
PrivatelastPrivatelastPrivatelastPrivatelastPrivatelastPrivatelastLast key pressed on a row.
PrivatelastPrivatelastThe index of the last visible row.
PrivatelayoutPrivate OptionalnativeNative scroll gesture host (scrollMode native/auto on capable platforms).
PrivatenativePrivatenativevirtualY value mapping to native offset 0 (minScrollOffset at last sync).
PrivatenextThe index of the next row to be processed or rendered. This is used to keep track of the current position in the collection view.
PrivatenumberNumber of items (rows) in the collection view.
OptionalonOpt-in, per-frame handler for an item losing focus during horizontal motion.
OptionalonHandler for item focus events.
OptionalonOpt-in, per-frame handler for an item gaining focus during horizontal motion.
OptionalonHandler for item long press selected events.
OptionalonHandler for item selected events.
OptionalonHandler for settled layout events.
OptionalonHandler for item options key pressed events.
OptionalonHandler for row focus events.
The container for overlays like left fade effect, etc.
OptionalparentThe parent focusable element, if any.
PrivatependingThe index of the item to animate to when going to a specific row.
PrivatependingQueued interaction replay deferred until the next tick to avoid input re-entrancy during render completion.
PrivatepointerPrivatepointerOpt-in page-style landing for pointer and native scroll focus commits.
Default horizontal reading order inherited by rows.
PrivaterenderAn event object that describes the changes to be rendered in the collection view.
Injected row callbacks provider.
Spacing between rows in the collection view.
Additional vertical scroll extent around collection content.
Vertical scroll engine. 'auto' uses the native scroll host on platforms
with the scroll.nativeHost capability. Decide at construction time —
the host is created with the renderer.
Animation speed for row transitions.
Currently selected row and item indices.
Start indices for animations: [rowIndex, itemIndex].
Stack of sticky rows for nested header support.
The container for sticky rows.
These are the children that were created in getViews, in a flat strcuture - it contains EVERYTHING that we declared.
PrivatetargetTarget indices for animations: [rowIndex, itemIndex].
PrivatetargetThe target virtual Y position for animations.
PrivatetimeTime left from previous animation when animation is interrupted.
PrivatetimeTime to reach the next intermediate row during animation (in milliseconds).
PrivatetimeTime to reach the target row during animation (in milliseconds).
The type of vertical focus animation.
The IHosannaView subclass that created us in getViews
The height of the viewport.
The current virtual Y position (scroll offset).
Indicates whether the navigatable entity is visible.
Private Static ReadonlyMAX_Maximum drain iterations to prevent infinite loops from misbehaving onContentReady handlers.
Gets the opt-in high-fidelity item-blurring handler.
Gets the item focus event handler.
Gets the opt-in high-fidelity item-focusing handler.
Gets the row focus event handler.
Handles the tick event, processes the input, and updates the view accordingly.
The time delta since the last tick.
PrivateaddView Creation
PrivateanimateAnimates the view between the start index and the target index.
The time delta since the last animation step.
PrivateanimateConvenience: animate logical properties across this view's subtree.
Animation specification mapping view IDs to their target property values
Animation duration in milliseconds
OptionalonCompleted: () => voidOptional callback invoked when animation completes
Optionaloptions: Partial<AnimationOptions>Extra animation options; duration and useCurrentState here are ignored (see HosannaViewAnimator.animateViews).
PrivateapplyPrivateapplyPrivateapplyApplies state changes, including updating the data source if changed.
Optionalstate: CollectionViewStateThe new state to apply.
Builds the expected header chain for a given row based on parentSectionName hierarchy
Builds the view and attaches it to the view owner.
OptionalmountTarget: IHosannaView<ViewState>The target to mount the view.
The built view or undefined.
PrivatecalculatePrivatecalculateCalculates the range of visible rows within the viewport.
Uses each row's IBaseCollectionViewRow.renderedListPosition (same stacking contract as invalidateRowLayout, including peek-ahead / peek-into reductions between rows) plus getHeight for the row's painted extent — mirroring findFirstVisibleRow. Accumulating raw heights without rendered positions was incorrect when rows peek/overlap.
An object containing:
firstVisible: The index of the first visible row.lastVisible: The index of the last visible row, clamped between 0 and the total number of items.PrivatecancelComprehensive cleanup method that releases all rows, cells, and resets state. This ensures proper resource management when the CollectionView is removed or hidden.
The cleanup process:
PrivateclearComprehensive reset that releases all rows to the pool and resets all tracking state. Used for DataSourceChangeType.Clear so the CollectionView is ready for fresh data (e.g. after login/logout). Does NOT unregister tickable or clear _dataSource.
PrivateclearClears all sticky rows
PrivateclearClears all existing rows from the collection view.
PrivateclearPrivateclearPrivatecommitPrivatecommitSame focus landing as the JS vertical path (endPointerScrollSession).
PrivatecommitDetermines if the given child is contained within this collection view.
The child view to check.
True if the child is a descendant, false otherwise.
PrivatecorrectPrivatecreatePrivatecreateCreates row instances from the data source.
PrivatedetachUnregisters this view's change callback from the current data source.
The data source often outlives the CollectionView bound to it (screens keep one data source while their pooled CollectionView is reused). Failing to unregister accumulates duplicate callbacks, so a single change is delivered to this view multiple times and gets re-queued via the re-entrancy guard — producing duplicate rows.
PrivatedeterminePrivatedetermineOptionaloptions: IScreenDismissOptionsOptionalargs: Record<string, unknown>OptionalcancellationToken: HsCancellationTokenOptionaltaskId: stringAsync Support
Optionalargs: Record<string, unknown>Optionalcallback: AsyncCommandEventCallbackOptionaltaskId: stringDispatches an item focus event.
The row index.
OptionalitemIndex: numberThe percent completion.
The direction of focus.
Dispatches an opt-in per-frame horizontal item focus event.
PrivatedispatchDispatches an options key pressed event.
The row index.
OptionalitemIndex: numberThe item index.
PrivatedispatchDispatches an item selected event.
The row index.
OptionalitemIndex: numberThe item index.
OptionalisLongPress: booleanWhether the key press is a long press.
PrivatedispatchPrivatedispatchOptionaldatasource: CollectionViewDataSource.CollectionViewDataSourceOptionalrowDataSource: ICollectionViewDataSourceRow<any, ICollectionViewDataSourceItem>PrivateeaseEasing function for smooth animation.
The current animation time.
The starting value.
The change in value.
The duration of the animation.
The eased value.
Optionalpoint: CollectionViewPointerPointPrivateexitPrivatefindFinds the first focusable row: from startIndex to end, then from startIndex - 1 down to 0. Uses the same focusable criteria as getFirstFocusableRowIndex. Returns -1 if none found.
PrivatefindFinds the index of the first visible row based on the given virtual Y position. This method uses a binary search algorithm to efficiently locate the row.
The virtual Y position to find the first visible row for.
The index of the first visible row, clamped between 0 and the number of items minus one.
PrivatefindFinds the header row for a given section name
Finds the next focusable element based on the focus event.
The next focus resolution event.
The next focusable element or undefined.
PrivatefindFinds the root header row for a given section name
PrivategetSafely reads the android-native launch args. globalThis is undefined on Roku
(the transpiler does not emit it), so it MUST be guarded with typeof before
indexing — otherwise globalThis[...] throws "Array operation attempted on
variable not DIM'd" on device. Returns the args only when running android-native.
Default animation provider mapping for simple properties. By default, maps 'opacity' to the base renderer's 'opacity' field. Views can override to provide richer mappings.
Audio guide support
Measurement
Gets the cached virtual Y position for the next row.
Gets the cell for a given row and item index.
The row index.
The item index.
The cell, or undefined.
Returns the current scroll metrics for the collection view. Used by scroll controllers to clamp deltas and compute momentum.
Gets the data source instance.
The data source instance, or undefined.
Gets the data source item for a given row and item index.
The row index.
The item index.
The item, or undefined.
Gets the data source row for a given index.
The row index.
The data source row, or undefined.
PrivategetGets the Direction enum value from a Key (using bridge-lib Direction for HsInputEvent).
The key to get direction for.
The Direction value corresponding to the key.
Returns the index of the first visible row that can receive focus (a CustomViewRow or a row with content items). Returns -1 if none found or empty.
PrivategetGets the bottom edge of the unobstructed focus area.
Gets the top edge of the unobstructed focus area.
Gets the X position of the currently focused cell's center for FocusOnClosestItem strategy.
Gets the currently focused data source item.
The focused item, or undefined.
Gets the currently focused data source row.
The focused data source row, or undefined.
Gets the currently focused row instance.
The focused row, or undefined.
Retrieves the focus information for a specific row and item index.
The row index.
The item index (default: -1).
The focus info object, or undefined if not found.
Gets the focus manager for the collection view.
The collection view focus manager.
PrivategetGets the Hosanna view for the currently focused row, if any.
The focused Hosanna view, or undefined.
PrivategetReturns the last visible (not hidden) row in the collection view.
The last visible row or undefined if no visible rows exist.
PrivategetPrivategetPrivategetPrivategetPrivategetGiven a virtualY offset, returns the nearest row index using binary search. Pure lookup — no side effects.
PrivategetGets the next item indices.
The next item indices.
PrivategetPrivategetPrivategetPrivategetPrivategetPrivategetGets the row instance for a given data source row.
The data source row.
The row instance, or undefined.
Gets the row instance for a given index.
The row index.
The row instance, or undefined.
Gets all row instances.
The array of rows.
Gets the normalized bottom scroll inset.
Gets the normalized top scroll inset.
PrivategetOptionalvisibilityThreshold: numberGets one rendered item cell if its visible area meets the settled visibility threshold.
PrivategetGets rendered item cells whose visible area meets the settled visibility threshold. This inspects only the currently visible row window and each row's rendered cells.
Gets one rendered row if it contains at least one settled visible item.
PrivategetGets rendered rows that contain at least one settled visible item.
Gets the sticky rows.
The sticky rows.
PrivategetGets the time required to move to the next row.
The time in milliseconds.
PrivategetGets the total time required to move to the target row.
The time in milliseconds.
Gets the vertical focus animation strategy instance.
PrivategetPrivategetPrivategetPrivatehandleHandles focus event dispatching during animations.
PrivatehandlePrivatehandlePrivatehandlePrivatehandlePrivatehandleHandles a row key press event.
Whether the key press is a long press.
True if handled, false otherwise.
PrivatehandlePrivatehandlePrivatehandlePrivatehandlePrivatehandleRows cache this result when they are mounted. Keeping the test out of their render loop avoids constructing and dispatching progress events unless the collection explicitly opted into them.
Hibernates the CollectionView and its visible rows. Overrides BaseView.hibernateView() to also hibernate the rows (which are stored in this.rows[], not this.children[]).
Call when the hosting screen is covered by another (e.g. NavController push after transition). Runs BaseCollectionViewRow.onExitScreen on each row whose index lies within the CollectionView's current render/visibility buffer (from firstVisibleRow through lastVisibleRow, inclusive), as computed by calculateVisibleRows. This buffer may extend slightly beyond the strictly screen-visible rows. Indices with no row instance are skipped. Does not clear the data source or return rows to the pool (unlike cleanup). Idempotent while already hibernated.
Initializes a single tab group - hides all content rows except the default/current one
PrivateinitializeInitializes tab groups during data source setup - ensures only default/current tabs are visible
PrivateinitializeInitializes the collection view with the given data source.
The data source instance.
OptionalrestoreIndices: [number, number]Optional [rowIndex, itemIndex] to restore scroll/focus (from replaceAllRows).
The view to be added as a subview.
index of the child in the parent view, -1 means add to end
PrivateinvalidateInvalidates the current layout starting from the specified row index. Recalculates renderedListPosition for each row and triggers rendering if needed.
The index of the first row to start invalidating from.
When true, skip the initial render block (caller will jump/render).
PrivateisPrivateisFocus
PrivateisChecks if a row is focusable.
The row index.
True if the row is focusable, false otherwise.
PrivateisReturns whether one rendered item cell meets the settled visibility threshold.
Returns whether one rendered row contains at least one settled visible item.
PrivatejumpInstantly jumps to the specified row index without animation. Updates virtualY, focus, and row visibility immediately.
The target row index.
OptionalrowItemIndex: numberOptional target item index within the row.
PrivatenormalizeCalled when this view becomes the visible top again after having been covered by another screen on the same NavController (same transition finish as onAppear, immediately after it).
Prefer overriding onDidReappearInAggregateView; default implementation chains from it.
Called when the collection view loses focus.
PrivateonHandles changes to the data source and updates rows/layout accordingly. Uses a re-entrancy guard so that changes triggered during processing (e.g. from onContentReady handlers that append rows) are queued and processed in a drain loop instead of recursing.
The list of data source changes.
Called after the navigatable entity has been added to an aggregate view.
The aggregate view to which the entity has been added.
Called when this view becomes the visible top of its owning NavController stack for the first time (after onDidAddToAggregateView). Default implementation delegates to onAppear and onFirstAppear.
The aggregate view (e.g. NavController) whose transition finished.
Called when this view becomes the visible top again after having been covered by another screen on the same NavController. Default implementation delegates to onAppear and onAppearAgain.
The aggregate view (e.g. NavController) whose transition finished.
Called after the navigatable entity has been removed from an aggregate view.
The aggregate view from which the entity has been removed.
Called when this view is hidden during an aggregate transition or via BaseAggregateView.hideView.
Default implementation delegates to onDisappear.
The aggregate view from which this view is disappearing.
Called when this view becomes the visible top of a NavController stack for the first time for that controller (same transition finish as onAppear, immediately after it).
Prefer overriding onDidAppearInAggregateView; default implementation chains from it.
Called when the collection view receives focus.
Processes the input event based on the key state and key type.
The key event to process.
PrivateonCalled when an interaction (animation or jump) completes. Pops the next queued interaction and replays it as a keypress if it's a press/longPress interaction.
Handles the Down key press.
True if handled, false otherwise.
Handles the FastForward key press (increases speed).
True if handled, false otherwise.
Handles the Left key press.
True if handled, false otherwise.
Handles the OK key press (selects the current item).
True if handled, false otherwise.
Handles the Options key press.
True if handled, false otherwise.
Handles the Rewind key press (decreases speed).
True if handled, false otherwise.
Handles the Right key press.
True if handled, false otherwise.
Handles the Up key press.
True if handled, false otherwise.
PrivateonPrivateonPrivateonCalled when the view is unmounted.
Called before the navigatable entity is added to an aggregate view.
The aggregate view to which the entity will be added.
This method is called before applying state changes to the view. It is used to perform any necessary preparations before the state changes are applied.
Called before the navigatable entity is removed from an aggregate view.
The aggregate view from which the entity will be removed.
Lifecycle
PrivatepopPops the top sticky row from the stack
Presents a new screen in the navigation stack or as a dialog.
The screen to be presented, represented by a ViewStruct<ViewState>.
Optionaloptions: IScreenPresentationOptionsOptional presentation options.
If true, the screen will be presented as a dialog.
If true, the screen transition will be animated.
PrivateprocessProcesses a batch of data source changes. Called by onDataSourceChanged.
The list of data source changes to process.
PrivateprocessPrivatepushPushes a new sticky row onto the stack
PrivatereconcileReconciles the sticky rows stack with the expected header chain
PrivatereconfigurePrivatereconfigurePrivatereconfigurePrivaterefreshUnlike BaseView.release, does not call child.release() on subviews: list rows are
torn down and released by dedicated CollectionView paths, so iterating children here would
be redundant or unsafe.
PrivatereleasePrivatereleaseWhen scrolling vertically toward the start of the list (direction -1), release sticky if the row we have just moved to (nextItemIndices before recompute === segment destination) is sticky.
PrivateremovePrivateremoveRemoves a sticky row at a specific index from the stack
PrivaterenderRenders the currently focused row in the collection view.
The time delta since the last render.
Renders the collection view for the specified indices. Returns true if the rendering was successful, false otherwise.
The clamped row index.
The clamped item index.
True if the rendering was successful, false otherwise.
PrivaterenderPrivateRenders the rows that are currently visible within the viewport.
This method calculates the first and last visible rows based on the current
vertical scroll position (virtualY) and the height of the viewport (viewportHeight).
It then iterates through the rows, rendering only those that are visible.
The method performs the following steps:
visibleRows array.Sets which direct child this composite prefers on the next focus cascade, or moves focus to that child if this view is already in the focus chain.
First / Last: first or last direct child in children order with canReceiveFocus && visible.Default: clears focusedChildId only (next cascade uses getInitialFocusId()); does not call setFocus.Specific: same behavior as setFocusedSubview for a known child id.OptionalchildId: stringPrivateresolvePrivateresolvePrivateresolvePrivateschedulePrivateschedulePrivatescrollInstantly jumps to the specified row index without animation. Updates virtualY, focus, and row visibility immediately.
The target row index.
OptionalitemIndex: numberOptional target item index within the row.
Changes the visual z-order of a child by moving it to a new index. Higher indices render on top. Updates both the children array and the renderer. Requires removeChild before insertChild because the SG node's insertChild always adds (splices in) and does not move; calling it on an already-present child would duplicate.
Sets the content of the collection view with the provided rows.
The rows to use as the data source.
PrivatesetSets the data source for the collection view.
The data source instance.
Sets the scroll offset directly for external scroll (touch drag, mouse wheel). Only takes effect when no index animation is in progress. Clamps to valid bounds and refreshes visible rows.
true if the offset was applied, false if an animation is in progress.
PrivatesetPrivateThis method calculates and updates several properties related to the focus tracking of rows in the collection view. It ensures that the focus is within the valid range of rows and calculates the time to reach the next row for focus tracking.
PrivatesetNavigatable View
Handles reparenting of sticky rows when they gain focus.
PrivatesetPrivateshouldPrivatestartAnimates the view to the specified item index within the specified row.
The item index.
Whether to animate quickly.
OptionalrowIndex: numberThe row index, if not provided, the currently focused row will be used.
PrivatesyncPositions the focus indicator on the currently focused row/item. Uses the same vertical math as jumpToRow so grid rows scrolled within the collection stay aligned after blur/focus or aggregate reappear.
PrivatesyncPer-tick reconciliation with the native scroller: frame + content metrics flow down on change, and while the native side is idle the offset follows any JS-driven virtualY change (index animations, scrollToRow) so the next gesture starts from the right position. While dragging/decelerating the native offset is authoritative and is never pushed.
PrivateupdateUpdates the focused cell X position based on the current focused indices.
PrivateupdateUpdates the focus tracker based on the percentage of movement to the next row.
This method renders the focus manager while moving between items and updates the focus tracking fields when the movement to the next row is complete.
A number representing the percentage of movement to the next row. When this value is 1 or greater, the focus tracking fields are updated and the focus manager is set to the next focus information.
PrivateupdatePrivateupdateUpdates the visibility of rows in the collection view.
This method calculates the currently visible rows and updates the currentIndex
to the first visible row. It then iterates through all rows and triggers the
onEnterScreen method for rows that have become visible and the onExitScreen
method for rows that have gone off-screen.
PrivateupdateTrue when vertical scrolling is delegated to the platform scroller — the JS scroll controller must not drive the vertical axis itself.
Wakes up the CollectionView and restores its visible rows. Overrides BaseView.wakeView() to also wake the rows (which are stored in this.rows[], not this.children[]).
Call when the hosting screen becomes visible again (for example after a NavController pop). Delegates to refreshVisibleRows so row visibility is updated and visible rows are rendered.
updateRowVisibility alone is insufficient here: it runs BaseCollectionViewRow.onEnterScreen but does not run renderVisibleRows. Skipping that render pass can leave cell views mis-positioned or stale until the user scrolls. refreshVisibleRows performs both steps.
No-op if hibernateVisibleRows was not applied.
CollectionViewView is the main Hosanna collection view implementation. Handles row and item rendering, focus management, data source changes, and input events. It is highly optimized for performance and supports virtualized rendering. It is designed to handle large data sets efficiently and can handle different sets of cards, rows and is very flexible in terms of layout and rendering.