diff --git a/src/frontend/src/components/forms/StandaloneField.tsx b/src/frontend/src/components/forms/StandaloneField.tsx index 0e5d498b1c..318797f566 100644 --- a/src/frontend/src/components/forms/StandaloneField.tsx +++ b/src/frontend/src/components/forms/StandaloneField.tsx @@ -9,13 +9,15 @@ export function StandaloneField({ fieldName = 'field', defaultValue, hideLabels, - error + error, + selectAndFocus = false }: Readonly<{ fieldDefinition: ApiFormFieldType; fieldName?: string; defaultValue?: any; hideLabels?: boolean; error?: string; + selectAndFocus?: boolean; }>) { // Field must have a defined name const name = useMemo(() => fieldName ?? 'field', [fieldName]); @@ -49,6 +51,7 @@ export function StandaloneField({ control={form.control} hideLabels={hideLabels} setFields={undefined} + selectAndFocus={selectAndFocus} /> ); diff --git a/src/frontend/src/components/forms/fields/ApiFormField.tsx b/src/frontend/src/components/forms/fields/ApiFormField.tsx index 85e128a1fd..ad50d87a25 100644 --- a/src/frontend/src/components/forms/fields/ApiFormField.tsx +++ b/src/frontend/src/components/forms/fields/ApiFormField.tsx @@ -31,7 +31,8 @@ export function ApiFormField({ navigate, url, setFields, - onKeyDown + onKeyDown, + selectAndFocus = false }: Readonly<{ fieldName: string; definition: ApiFormFieldType; @@ -41,6 +42,7 @@ export function ApiFormField({ url?: string; setFields?: React.Dispatch>; onKeyDown?: (value: any) => void; + selectAndFocus?: boolean; }>) { const fieldId = useId(); const controller = useController({ @@ -196,6 +198,7 @@ export function ApiFormField({ onChange={(value: any) => { onChange(value); }} + selectAndFocus={selectAndFocus} /> ); case 'choice': diff --git a/src/frontend/src/components/forms/fields/NumberField.tsx b/src/frontend/src/components/forms/fields/NumberField.tsx index 0369d0935a..fa0f119a7a 100644 --- a/src/frontend/src/components/forms/fields/NumberField.tsx +++ b/src/frontend/src/components/forms/fields/NumberField.tsx @@ -1,5 +1,5 @@ import { NumberInput } from '@mantine/core'; -import { useId, useMemo } from 'react'; +import { useEffect, useId, useMemo, useRef } from 'react'; import type { FieldValues, UseControllerReturn } from 'react-hook-form'; import AutoFillRightSection, { AutoFillWarning } from './AutoFillRightSection'; @@ -14,7 +14,8 @@ export default function NumberField({ placeholderAutofill, placeholderWarningCompare, placeholderWarning, - onChange + onChange, + selectAndFocus = false }: Readonly<{ controller: UseControllerReturn; definition: any; @@ -23,8 +24,11 @@ export default function NumberField({ placeholderWarningCompare?: number | string; placeholderWarning?: string; onChange: (value: any) => void; + selectAndFocus?: boolean; }>) { const fieldId = useId(); + const inputRef = useRef(null); + const { field, fieldState: { error } @@ -60,6 +64,18 @@ export default function NumberField({ return val; }, [definition.field_type, value]); + useEffect(() => { + if (!selectAndFocus) return; + if (!inputRef.current) return; + + inputRef.current.focus(); + requestAnimationFrame(() => { + const el = inputRef.current; + if (!el) return; + el.setSelectionRange(0, el.value.length); + }); + }, [selectAndFocus]); + const rightSection = useMemo(() => { if ( definition.placeholder && @@ -101,7 +117,10 @@ export default function NumberField({ { + inputRef.current = node; + field.ref(node); + }} id={fieldId} aria-label={`number-field-${field.name}`} error={definition.error ?? error?.message} diff --git a/src/frontend/src/forms/StockForms.tsx b/src/frontend/src/forms/StockForms.tsx index a0de3608b2..ea845ff0bc 100644 --- a/src/frontend/src/forms/StockForms.tsx +++ b/src/frontend/src/forms/StockForms.tsx @@ -587,6 +587,7 @@ function StockOperationsRow({ transferMerge?: boolean; returnStock?: boolean; record?: any; + focusAndSelect?: boolean; }) { const form = useFormContext(); @@ -691,6 +692,7 @@ function StockOperationsRow({ void; }) { const baseParams: any = { part_detail: true, @@ -1371,7 +1375,10 @@ function useStockOperationModal({ successMessage: successMessage, onFormSuccess: () => refresh(), onClose: () => setOpened(false), - onOpen: () => setOpened(true) + onOpen: () => { + setOpened(true); + onOpen?.(); + } }); } @@ -1386,7 +1393,17 @@ export function useAddStockItem(props: StockOperationProps) { {t`Increase the quantity of the selected stock items by a given amount.`} - ) + ), + onOpen: () => { + setTimeout(() => { + const input = document.querySelector( + '#number-field-quantity, input[aria-label="number-field-quantity"]' + ); + + input?.focus(); + input?.select(); + }, 0); + } }); } @@ -1401,7 +1418,17 @@ export function useRemoveStockItem(props: StockOperationProps) { {t`Decrease the quantity of the selected stock items by a given amount.`} - ) + ), + onOpen: () => { + setTimeout(() => { + const input = document.querySelector( + 'input[aria-label="number-field-quantity"]' + ); + + input?.focus(); + input?.select(); + }, 0); + } }); } @@ -1457,7 +1484,17 @@ export function useCountStockItem(props: StockOperationProps) { {t`Count the selected stock items, and adjust the quantity accordingly.`} - ) + ), + onOpen: () => { + setTimeout(() => { + const input = document.querySelector( + 'input[aria-label="number-field-quantity"]' + ); + + input?.focus(); + input?.select(); + }, 0); + } }); }