Primitives / foldkit-primitives/interaction

GridNavigation

namespace · packages/primitives/src/interaction/grid-navigation.ts:10

export * as GridNavigation from './grid-navigation.js'

Two-dimensional arrow keys over a set of items laid out in rows of columns (a calendar grid, a color swatch picker, an emoji palette). The Model slice is the current item's id, as with RovingTabindex, so a reorder keeps the same item current. Which cell a key lands on is the pure move; the Behavior wires it to a container slot and a per-item slot and shares RovingTabindex's item attributes, so the two are interchangeable on a view.

In the guides

Members

GridNavigation.Args

const · packages/primitives/src/interaction/grid-navigation.ts:30

const Args: Schema.Struct<{
  readonly columns: Schema.Number
  readonly wrap: Schema.Boolean
  readonly virtual: Schema.Boolean
}>

GridNavigation.behavior

function · packages/primitives/src/interaction/grid-navigation.ts:149

function behavior<Field extends string>(
  declared: Declared<typeof bundle, Field>,
  args: Args,
): <Slots>(
  slots: Slots,
) => <Input extends { readonly [K in Field]: Model }, ParentMessage>(
  options: BehaviorOptions<Input, Slots>,
) => Behavior.NamedBehavior<Slots, Input, ParentMessage>

Wires a placed GridNavigation to the slots exactly as RovingTabindex does, with move above deciding the cell: the container's arrows, Home and End focus the next cell (synchronously, then dispatch) or, under virtual, only dispatch and point with aria-activedescendant; each cell gets tabindex 0 or -1 and reports Focused when focused.

GridNavigation.BehaviorOptions

interface · packages/primitives/src/interaction/grid-navigation.ts:132

interface BehaviorOptions<Input, Slots> {
  readonly container: keyof Slots & string
  readonly item: keyof Slots & string
  readonly items: (input: Input) => Behaviors.Collection.Items<unknown>
  readonly direction?: (input: Input) => RovingTabindex.Direction
}

GridNavigation.bundle

const · packages/primitives/src/interaction/grid-navigation.ts:42

const bundle: Bundle.Bundle<
  'GridNavigation',
  {
    readonly columns: number
    readonly wrap: boolean
    readonly virtual: boolean
  },
  { readonly current: string | null },
  { readonly _tag: 'Focused'; readonly id: string },
  never,
  never,
  never,
  void,
  {},
  {}
>

GridNavigation.Message

const · packages/primitives/src/interaction/grid-navigation.ts:24

const Message: MessageUnion<{
  readonly Focused: { readonly id: Schema.String }
}>

GridNavigation.Model

const · packages/primitives/src/interaction/grid-navigation.ts:18

const Model: Schema.Struct<{ readonly current: Schema.NullOr<Schema.String> }>

GridNavigation.move

function · packages/primitives/src/interaction/grid-navigation.ts:69

function move(
  enabled: ReadonlyArray<number>,
  count: number,
  current: number,
  key: string,
  modifiers: KeyboardModifiers,
  options: MoveOptions,
): number | undefined

The index the key moves to from current over a grid of count cells in rows of columns, skipping cells not in enabled, or undefined when the key is not a grid key. Left and right step within the row, and across rows under wrap; up and down step within the column, and across columns under wrap. Home and End are the row's first and last enabled cell; with Ctrl they are the grid's. At an edge without wrap the key is consumed and current is returned. From -1 (nothing current) a forward key lands on the first enabled cell and a backward key on the last. Under rtl, left and right swap.

GridNavigation.MoveOptions

interface · packages/primitives/src/interaction/grid-navigation.ts:52

interface MoveOptions {
  readonly columns: number
  readonly wrap: boolean
  readonly direction: RovingTabindex.Direction
}