Keyboard, input and drag
Hearing a key
Section titled “Hearing a key”onKey fires on every component that carries it while the interface is open:
<text x={0} y={22} w="fill" h={16} text={`${amount}*`} font={Fonts.PLAIN} align="center" valign="middle" shadow color={Colors.WHITE} onKey={(event) => { if (event.keyCode === KEY_ENTER) { setWithdraw(amount); setAmount(0); return; } if (event.keyCode === KEY_BACKSPACE) { setAmount(amount / 10); return; } if (event.keyChar >= CHAR_ZERO && event.keyChar <= CHAR_NINE && amount < 100000) { setAmount(amount * 10 + (event.keyChar - CHAR_ZERO)); } }} />event.keyCode is the client’s own code for the key, not a character code:
Escape is 13, Enter 84, Backspace 85. event.keyChar is the typed character’s
code, and is what a digit or letter is read from. Name the codes once:
/** The client's key codes for the keys this prompt understands. */const KEY_ENTER = 84;const KEY_BACKSPACE = 85;
/** The character codes of '0' and '9'. */const CHAR_ZERO = 48;const CHAR_NINE = 57;For “Escape closes it”, put a hotkey on an option instead (Keys on options).
Building a value from keys
Section titled “Building a value from keys”Keep what is typed in a cell and draw the cell:
export const Committed = (): Component => { const [amount] = useState(withdrawAmount);Interface state has the three kinds of cell.
A key handler builds numbers, not text; for free text, use an <input>.
The field the player types into
Section titled “The field the player types into”<input> is a text field. focus gives it the caret when the interface opens:
<input x={4} y="center" w={{ fill: 8 }} h={16} font={Fonts.PLAIN} text="selling rune scimitar" valign="middle" shadow color={Colors.YELLOW} promptColor={Colors.DIM} selectColor={Colors.WHITE} selectBgColor={0x3d5a8a} lineWidthLimit={40} focus />| Prop | |
|---|---|
text | what the field starts with |
focus | the field has the caret when the interface opens |
promptColor, selectColor, selectBgColor | the caret, the selected text, and its background |
lineWidthLimit, lineCountLimit, lineWrapWidth | how much may be typed, and where it wraps |
What the player types goes to the server; the interface cannot read it back.
<input> has the full prop
list.
Drag and drop
Section titled “Drag and drop”draggable takes a ref to the container the drag is measured in. The component
cannot leave that box, and every position the drag reports is relative to it:
<layer ref={zone} x={ZONE_INSET} y={0} w={ZONE_W} h={PIECE} onClick={(event) => { setLevel(Math.clamp(0, 100, (event.mouseX - PIECE / 2) * 100 / TRAVEL)); }}> <sprite x={level * TRAVEL / 100} y={0} w={PIECE} h={PIECE} sprite={Slider.THUMB} draggable={zone} dragMoves dragDeadZone={0} dragDeadTime={0} onDrag={(event) => { setLevel(Math.clamp(0, 100, event.mouseX * 100 / TRAVEL)); }} /></layer>| Prop | |
|---|---|
dragMoves | the component stays where its props put it; nothing is carried under the pointer |
dragDeadZone | how many pixels the pointer moves before a press becomes a drag |
dragDeadTime | how many cycles it is held before a press becomes a drag |
Without dragMoves, the client carries a copy of the component under the
pointer, as it does an item in the backpack. A slider thumb wants dragMoves.
A drag is a value
Section titled “A drag is a value”onDrag fires as the pointer moves, and event.mouseX is the dragged
component’s left edge inside the container. Write it to a cell and draw from
the cell:
<text x="right" y="center" w={36} h={14} text={`${level}%`} font={Fonts.PLAIN} align="right" valign="middle" shadow color={Colors.YELLOW} />Where a drag may land
Section titled “Where a drag may land”dragTarget marks a component as somewhere a drag may end. On release,
onDragComplete fires on the dragged component, and event.dragTarget is the
target it landed on, or -1 for nothing:
<sprite x="center" y="center" w={36} h={32} item={left} itemCountMode="never" draggable={row} dragTarget onDragComplete={(event) => { if (event.dragTarget !== -1) { setFirst(1 - first); } }} />A drop between the item cells of a backpack or bank reaches the server on its own.