Skip to content

@astrolabe/player/interaction

For component elements that move things or keep a roving tab stop: Lit reactive controllers with keyboard, tap and tap, pointer, touch and announcements done once. A separate entry, so the player's first load never includes it.

Pick and place, with every way in (WCAG 2.2: 2.1.1 keyboard, 2.5.7 dragging movements):

  • keyboard: Space or Enter on an item picks it (a native button click), the arrow keys choose a destination (Home and End: the first and the last), Space or Enter on it again puts it there, Escape puts it back;
  • one pointer, no dragging: tap an item, then a destination (put) or another item (with a place: put there; without: pick that one instead);
  • a drag once the pointer travels DRAG_THRESHOLD px, with pointer capture; the click after a drag is not a tap; a touch drags after a long press (hold) or from a handle (handle), so other touches scroll the page. Escape and a press outside the host work wherever the focus is; held keys do not repeat a pick; Alt, Ctrl and Meta shortcuts stay with the browser; a disabled host forgets any pick. Announcements go through context.announce.

Wire each item: @click=${(e) => pick.click(e, id)}, @keydown=${(e) => pick.keydown(e, id)}, @pointerdown=${(e) => pick.pointerdown(e, id)} and, for touches that may scroll first (hold), @touchmove=${pick.touchmove}. A press's moves, release and menu are heard on the document, also for items outside the host.

Type Parameter
D
  • ReactiveController
new PickAndPlace<D>(host, options): PickAndPlace<D>;
Parameter Type
host PickAndPlaceHost
options PickAndPlaceOptions<D>

PickAndPlace<D>

Property Modifier Type Description
touchmove readonly AddEventListenerOptions & EventListenerObject While a touch may still scroll (hold), the page must not scroll once it drags. Bound on items, not the host: a non-passive touch listener makes the browser wait for it before scrolling.
get dragging(): string | null;

The item being dragged.

string | null

get over(): D | null;

The destination under the dragged item.

D | null

get picked(): string | null;

The item picked with the keyboard or a tap, waiting for a destination.

string | null

get target(): D | null;

The destination the arrow keys chose for the picked item; null: where it is.

D | null

cancel(): void;

Puts the picked item back where it is, announced.

void

click(
event,
item,
place?
): void;

A click on item (a tap, or Space or Enter on its button) picks it. While an item is picked: with a place (the clicked item stands for a destination, like a position in a list) the picked item is put there; without, a click on the picked item puts it at its target (or back), and a click on another item picks that one instead.

Parameter Type
event MouseEvent
item string
place? D

void

hostDisconnected(): void;

Called when the host is disconnected from the component tree. For custom element hosts, this corresponds to the disconnectedCallback() lifecycle, which is called the host or an ancestor component is disconnected from the document.

void

ReactiveController.hostDisconnected
hostUpdate(): void;

Called during the client-side host update, just before the host calls its own update.

Code in update() can depend on the DOM as it is not called in server-side rendering.

void

ReactiveController.hostUpdate
keydown(event, item): boolean;

Arrow keys (and Home, End) on the picked item choose its target; returns true when the key was used.

Parameter Type
event KeyboardEvent
item string

boolean

pick(item): void;

Picks item, announced.

Parameter Type
item string

void

pointerdown(event, item): void;

A press on item with the primary button, a finger or a pen: a tap or the start of a drag.

Parameter Type
event PointerEvent
item string

void

put(to): void;

Puts the picked item at to, announced; where it already is, it goes back (unless the preview is live).

Parameter Type
to D

void

reset(): void;

Forgets any pick and drag without a word, e.g. when answers are set from outside.

void

tap(event): boolean;

Whether a click is a tap (or Space or Enter on a button), not the click a drag's release brings, which it uses up: for clicks that do more than click.

Parameter Type
event MouseEvent

boolean


Roving tabindex (WAI-ARIA APG): many items, one tab stop. The arrow keys move it (a grid: Left and Right along the row, Up and Down along the column), Home and End go to the ends (a grid: of the row; with Ctrl, of the grid), PageUp and PageDown move a few rows of a grid. Render each item with tabindex=${roving.tabIndex(i)}; after a render the active item gets the focus back, but only while the focus is in the host (never pulled from elsewhere).

  • ReactiveController
new RovingFocus(host, options): RovingFocus;
Parameter Type
host ReactiveControllerHost & HTMLElement
options RovingFocusOptions

RovingFocus

get active(): number;

The item with the tab stop.

number

focus(index): void;

Makes item index the tab stop and, when the focus is in the host now, moves it there after the next render (also when the render replaces the focused element).

Parameter Type
index number

void

hostUpdate(): void;

Called during the client-side host update, just before the host calls its own update.

Code in update() can depend on the DOM as it is not called in server-side rendering.

void

ReactiveController.hostUpdate
hostUpdated(): void;

Called after a host update, just before the host calls firstUpdated and updated. It is not called in server-side rendering.

void

ReactiveController.hostUpdated
keydown(event, from?): boolean;

Moves the tab stop from item from (default: the active one) for a navigation key and returns true (the key is used); false for other keys and for Alt and Meta shortcuts (also Ctrl, except Ctrl+Home and Ctrl+End in a grid).

Parameter Type
event KeyboardEvent
from? number

boolean

tabIndex(index): -1 | 0;
Parameter Type
index number

-1 | 0

The element a PickAndPlace works for: a component element (an AstlElement) or anything shaped like one.

  • ReactiveControllerHost
  • HTMLElement
Property Modifier Type
context readonly Pick<ElementContext, "announce">
disabled readonly boolean

What a component tells PickAndPlace. Read on every use, so a getter can follow an attribute.

Type Parameter
D
Property Modifier Type Description
axis? readonly Axis The arrow keys that step through the destinations. Default both.
box? readonly string follow: a CSS selector for the box, around the pressed element, that moves with the pointer.
handle? readonly string | null Touches drag only from this part of an item (CSS selector); elsewhere they scroll. Mouse and pen drag anywhere.
hold? readonly number A touch drags only after it is held this long (ms) without moving; a touch that moves sooner scrolls the page.
leave? readonly "cancel" | "drop" Focus leaving the host (or a press outside it) with an item picked: cancel (default) puts it back without a word; drop puts it at its target (announced) when it has one other than where it is, else puts it back.
preview? readonly "follow" | "live" follow (default): a dragged item stays where it is until it is put, over names the destination under the pointer and the box around the pressed element moves with the pointer; a pick from before the drag stays until the drag ends. Putting an item where it is changes nothing: it goes back. live: the item is shown where it would go (a list being reordered): a drag picks the item and its target follows the pointer, and putting it down is an answer even where it started.
wrap? readonly boolean Past the last destination comes the first, and back.
at(
x,
y,
item
): D | null;

The destination under a pointer at viewport point x, y while item is dragged, or null.

Parameter Type
x number
y number
item string

D | null

optional changed(item): void;

After an item is picked, gets a new target, is put or goes back: e.g. to move a roving tab stop along with it.

Parameter Type
item string

void

commit(item, to): void;

Puts item at to: the answer changes (report it with emitChange).

Parameter Type
item string
to D

void

current(item): D;

Where item is now (its answer, or where it starts).

Parameter Type
item string

D

destinations(item): readonly D[];

Where item can go, in the order the arrow keys step through.

Parameter Type
item string

readonly D[]

optional parts(): Iterable<Element>;

Elements outside the host that take part, such as destinations elsewhere in the page (the gaps of a word bank): focus moving to them and presses on them keep a pick. Items may sit there too (a gap holding a word).

Iterable<Element>

say(
moment,
item,
to,
from
): string;

The announcement of a moment, in the component's own messages. to is where the item is (or would go: target) after the moment; from is where the student last knew it to be (where it was picked, or the last target).

Parameter Type
moment PickMoment
item string
to D
from D

string


Property Modifier Type Description
axis readonly Axis | "grid" A list along an axis (see Axis), or grid: rows of columns items in reading order.
columns? readonly number Items per row of a grid.
page? readonly number Rows that PageUp and PageDown move in a grid. Default 5.
wrap? readonly boolean Past the last item comes the first (in a grid: the next row, or the top of the column), and back.
count(): number;

How many items share the one tab stop, now.

number

item(index): HTMLElement | null;

The rendered element of item index (focused after a render), or null.

Parameter Type
index number

HTMLElement | null

type Axis = "block" | "inline" | "both";

Arrow keys that move: Up and Down (block), Left and Right (inline, in the writing direction) or all four (both, for destinations laid out in two dimensions).


type PickMoment = "pick" | "target" | "put" | "cancel";

The moments a student hears: an item is picked, a destination is chosen (arrow keys), the item is put somewhere, or it goes back where it was.

const DRAG_THRESHOLD: 6 = 6;

Pointer travel (px) that turns a press into a drag; anything shorter is a tap.

function arrowDelta(
event,
axis,
host
): -1 | 0 | 1;

The step an arrow key makes along axis: 1 forward (Down, or Right in left-to-right text), -1 back, 0 for any other key. Left and Right swap when host is laid out right to left, so the next item is always the one read next.

Parameter Type
event KeyboardEvent
axis Axis
host Element

-1 | 0 | 1