on master help sign in
activate-ux: auto-advance focus to next key field
commit782bb34c0ec9f646b35e950e70c21c546cc68303 authortomholford <tomholford@users.noreply.github.com> dateSun 7 Nov 2021, 16:03 (5 years ago) parent36aafee
1 file changed+47−18
src/form/Inputs.tsx+47−18
src/form/Inputs.tsx+47−18
@@ -1,4 +1,4 @@
1−import React from 'react';
1+import React, { useCallback } from 'react';
22import * as ob from 'urbit-ob';
33import { Input, AccessoryIcon } from 'indigo-react';
44import { useField, useForm } from 'react-final-form';
@@ -224,30 +224,59 @@ export function TicketSegmentInput({ name, ...rest }: TicketSegmentInputProps) {
224224 const { input } = useField(name);
225225 const { change } = useForm();
226226
227− const onPaste = (event: React.ClipboardEvent<HTMLInputElement>) => {
228− try {
229− const pasteBuffer = event.clipboardData.getData('text');
230− const patp = ensurePatFormat(pasteBuffer);
231− if (!ob.isValidPatp(patp)) {
232− throw new Error('invalid patp');
227+ const onPaste = useCallback(
228+ (event: React.ClipboardEvent<HTMLInputElement>) => {
229+ try {
230+ const pasteBuffer = event.clipboardData.getData('text');
231+ const patp = ensurePatFormat(pasteBuffer);
232+ if (!ob.isValidPatp(patp)) {
233+ throw new Error('invalid patp');
234+ }
235+
236+ // prevent pasting the entire clipboard text into the field
237+ event.preventDefault();
238+
239+ const segments = ticketToSegments(pasteBuffer);
240+ segments.forEach((s, i) => {
241+ change(`ticket${i}`, s);
242+ });
243+ } catch (error) {
244+ console.log(`skipping ticket autofill: ${error}`);
233245 }
246+ },
247+ [change]
248+ );
234249
235− // prevent pasting the entire clipboard text into the field
236− event.preventDefault();
250+ // Advance the focused field after typing 6 characters
251+ const onChange = useCallback(
252+ (event: React.ChangeEvent<HTMLInputElement>) => {
253+ const currentIndex = Number(name.replace('ticket', ''));
254+ if (currentIndex < 3 && event.target.value.length === 6) {
255+ const nextField = document.querySelector(
256+ `input[name=ticket${currentIndex + 1}]`
257+ );
237258
238− const segments = ticketToSegments(pasteBuffer);
239− change('ticket0', segments[0]);
240− change('ticket1', segments[1]);
241− change('ticket2', segments[2]);
242− change('ticket3', segments[3]);
243− } catch (error) {
244− console.log(`skipping ticket autofill: ${error}`);
245− }
259+ if (nextField !== null) {
260+ nextField.focus();
261+ }
262+ }
263+ },
264+ [name]
265+ );
266+
267+ // Run the react-final-form onChange handler,
268+ // and our own custom one to advance the form cursor
269+ const mergedInput = {
270+ ...input,
271+ onChange: e => {
272+ input.onChange(e);
273+ onChange(e);
274+ },
246275 };
247276
248277 return (
249278 <StatelessTextInput
250− {...input}
279+ {...mergedInput}
251280 autoCapitalize="none"
252281 autoCorrect="off"
253282 type="text"