Skip to content

Responding to events

An event prop takes a function, a handler, that runs when the player does that thing.

Write the handler inline, on the element that is the target:

src/settings.ts2
<layer x={0} y={ROW_H} w="fill" h={ROW_H} onClick={() => { setShiftDrop(1 - shiftDrop); }}>
<CheckboxRow label="Shift-click to drop" on={shiftDrop} />
</layer>

To handle a click on a component you wrote, such as <CheckboxRow>, put a <layer> around the call and give the layer the handler.

A handler that is one call can call a function you named:

src/settings.ts2
<text x="center" y={180} w={120} h={16} text="Restore defaults" font={Fonts.SMALL}
align="center" valign="middle" shadow color={Colors.DIM}
onClick={() => { restoreDefaults(); }} />
PropFires when
onClickthe player clicks
onClickRepeatrepeatedly, while the button is held down
onHoldwhile the pointer is held on the component
onReleasethe button is released
onMouseEnterthe pointer enters
onMouseLeavethe pointer leaves
onMouseRepeatrepeatedly, while the pointer is inside
onScrollWheelthe wheel turns over the component
onOptionSelecta right-click menu option is chosen — Hover and menus
onDrag, onDragCompletethe component is dragged, and dropped — Drag and drop
onTargetEnter, onTargetLeavea spell or item on this component is selected as something to use, and unselected
onKeya key is pressed while the interface is open — Keyboard, input and drag
onResizethe game window resized the component
onTimerabout fifty times a second, until stopped. See Timers
onLoadonce, when the interface opens

onLoad can fill in a label as the interface opens:

src/watch.ts2
<text ref={poisonLabel} x="right" y="center" w={120} h={16} text="Poison: -"
font={Fonts.PLAIN} align="right" valign="middle" shadow color={Colors.WHITE}
onLoad={(event) => { writePoison(event.self); }} />

An event that carries information passes it as the handler’s parameter. For the wheel, event.mouseY is how far it turned and in which direction:

src/chrome.ts2
content.onScrollWheel = (event) => {
content.scrollY = content.scrollY + event.mouseY * WHEEL;
trackScroll(gutter, thumb, capTop, capBottom, content);
};
Field
selfa handle to the component the event fired on — a ref you did not have to declare
component, subIdthe same component as an address: which component, and which child of it
mouseX, mouseYthe pointer, relative to the component
optionwhich menu option was chosen, numbered from 1
optionSubjectthe subject the menu showed beside the verb
keyCode, keyCharthe key pressed: the client’s code for the key, and the character it typed
dragTarget, dragTargetSubIdwhat a drag was dropped on, or -1 for nothing

Declare the parameter only if you read it; the name event is a convention. Event has the full list.

event.self changes the component the handler is on without a declared ref. It reads geometry, and can be passed to any function that takes a component:

src/marker.ts2
<layer ref={plate} x="left" y="center" w={PLATE} h={PLATE}
options={['Nudge right']}
onClick={(event) => { report(event.self, readout); }}
src/marker.ts2
const report = (target: ComponentId, into: ComponentId): void => {
into.text = `x ${target.x!} · ${target.width!} wide`;
};

To change another component, declare a ref for it.

In a .map() list, the callback’s index says which row was clicked: setTab(i).

A handler body calls functions, reads props, locals, game state and cells, calls setters, and writes through refs. It returns nothing:

src/settings.ts2
const restoreDefaults = (): void => {
const [, setRoofs] = useState(roofRemoval);
const [, setShiftDrop] = useState(shiftClickDrop);
// …
setRoofs(1);
setShiftDrop(0);
// …
};

A read in a handler is the value at that moment.

Leaving a prop off writes nothing. To take a bound handler off, write null on one arm of a conditional, or through a ref as ref.onOptionSelect = null:

src/menu.ts2
<layer x={4} y="center" w={36} h={32}
optionSubject="Rune scimitar" optionPriority={1}
options={locked === 1 ? LOCKED_OPTIONS : OPEN_OPTIONS}
onOptionSelect={locked === 1 ? null : (event) => { setChosen(nameOf(event.option)); }}>

To react to a server value changing, read it in the markup or use useWatch; see Watching and reacting.