react-hook-form#Controller TypeScript Examples
The following examples show how to use
react-hook-form#Controller.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: SideDrawerField.tsx From firetable with Apache License 2.0 | 7 votes |
export default function Email({
control,
column,
disabled,
}: ISideDrawerFieldProps) {
return (
<Controller
control={control}
name={column.key}
render={({ onChange, onBlur, value }) => {
return (
<TextField
variant="filled"
fullWidth
margin="none"
placeholder={column.name}
onChange={onChange}
onBlur={onBlur}
value={value}
id={`sidedrawer-field-${column.key}`}
label=""
hiddenLabel
disabled={disabled}
inputProps={{
autoComplete: "email",
maxLength: column.config?.maxLength,
}}
/>
);
}}
/>
);
}
Example #2
Source File: CustomFields.stories.tsx From react-hook-form-generator with MIT License | 6 votes |
ReactSelectField = ({ name, label, placeholder, options }) => {
const { control } = useFormContext();
return (
<FormControl>
<FormLabel>{label}</FormLabel>
<Controller
name={name}
control={control}
as={
<Select
placeholder={placeholder}
options={options}
/>
}
onChange={([selected]) => {
return selected;
}}
/>
</FormControl>
);
}
Example #3
Source File: controlled-checkbox.tsx From tams-club-cal with MIT License | 6 votes |
ControlledCheckbox = (props: ControlledCheckboxProps) => {
useEffect(() => {
if (!props.value) return;
props.setValue(props.name, props.value);
}, [props.value]);
return (
<Controller
control={props.control}
name={props.name}
defaultValue={props.value}
render={({ field: { onChange, onBlur, value } }) => (
<FormControlLabel
control={<Checkbox />}
label={props.label}
disabled={props.disabled}
onChange={onChange}
onBlur={onBlur}
checked={value}
sx={props.sx}
/>
)}
/>
);
}
Example #4
Source File: DateSelector.tsx From backstage with Apache License 2.0 | 6 votes |
DateSelector = ({ name, control, setValue }: Props) => {
const label = `${
name.charAt(0).toLocaleUpperCase('en-US') + name.slice(1, name.indexOf('D'))
} date`;
return (
<Controller
name={name}
control={control}
render={({ field }) => (
<FormControl>
<MuiPickersUtilsProvider utils={LuxonUtils}>
<KeyboardDatePicker
disableToolbar
format="dd-MM-yyyy"
label={label}
value={field.value}
onChange={date => {
setValue(name, date?.toISO());
}}
InputProps={{
endAdornment: (
<IconButton onClick={() => setValue(name, null)}>
<ClearIcon />
</IconButton>
),
}}
InputAdornmentProps={{
position: 'start',
}}
/>
</MuiPickersUtilsProvider>
</FormControl>
)}
/>
);
}
Example #5
Source File: SwitchElement.tsx From react-hook-form-mui with MIT License | 6 votes |
export default function SwitchElement({ name, control, ...other }: SwitchElementProps) {
return (
<FormControlLabel
control={
<Controller
name={name}
control={control}
render={({ field }) => <Switch {...field} checked={field.value} />}
/>
}
{...other}
/>
)
}
Example #6
Source File: TimestampEditor.tsx From firebase-tools-ui with Apache License 2.0 | 6 votes |
TimestampEditor: React.FC<
React.PropsWithChildren<{
value: firebase.firestore.Timestamp;
onChange: (value: firebase.firestore.Timestamp) => void;
name: string;
}>
> = ({ value, onChange, name }) => {
return (
<Controller
name={name}
rules={{
validate: (e) => {
return !isNaN(Date.parse(e)) || 'Must be a date-time';
},
}}
render={({ field: { ref, ...field }, fieldState }) => (
<Field
label="Value"
type="datetime-local"
step={1}
defaultValue={dateToLocale(value.toDate())}
error={fieldState.error?.message}
{...field}
onChange={(e) => {
const timestamp = Date.parse(e.currentTarget.value);
field.onChange(e.currentTarget.value);
if (!isNaN(timestamp) && timestamp !== value.toMillis()) {
onChange(firebase.firestore.Timestamp.fromMillis(timestamp));
}
}}
/>
)}
/>
);
}
Example #7
Source File: Form.tsx From plasmic with MIT License | 6 votes |
export function FormTextInput({
name,
children,
defaultValue,
}: {
name?: string;
children: any;
defaultValue?: string;
}) {
const contexts = useAllContexts();
const form = useContext(FormContext);
let isLoading = false;
//check loading
if (!!defaultValue && isContextValueRef(defaultValue)) {
const { contextName } = getContextAndField(defaultValue);
//const context = useContext(contextTable[contextName]);
//isLoading = !context;
isLoading = !contexts[contextName];
}
if (!form || !name || isLoading) {
return React.cloneElement(children, {
...children.props,
value: "Loading...",
});
}
return (
<Controller
name={name}
control={form.control}
defaultValue={getPropValue(defaultValue ?? "", contexts)}
render={({ field }) =>
React.cloneElement(children, { ...children.props, ...field, name })
}
/>
);
}
Example #8
Source File: LabeledRadio.tsx From UsTaxes with GNU Affero General Public License v3.0 | 6 votes |
export function LabeledRadio<A>(props: LabeledRadioProps<A>): ReactElement {
const { label, name, values, useGrid = true, sizes = { xs: 12 } } = props
const classes = useStyles()
const { control } = useFormContext<A>()
return (
<ConditionallyWrap
condition={useGrid}
wrapper={(children) => (
<Grid item {...sizes}>
{children}
</Grid>
)}
>
<Controller
name={name}
render={({ field: { value, onChange } }) => (
<div className={classes.root}>
<FormControl component="fieldset">
<FormLabel>{label}</FormLabel>
<RadioGroup name={name} value={value} onChange={onChange}>
{values.map(([rowLabel, rowValue], i) => (
<FormControlLabel
key={i}
value={rowValue}
control={<Radio color="primary" />}
label={rowLabel}
/>
))}
</RadioGroup>
</FormControl>
</div>
)}
control={control}
/>
</ConditionallyWrap>
)
}
Example #9
Source File: ReadOnlyInput.tsx From calories-in with MIT License | 6 votes |
function ReadOnlyInput({
name,
inputType,
nutritionValueUnit,
isBold = false,
}: Props) {
return (
<Controller
name={name}
render={({ field }) => {
let { value } = field
if (inputType === 'foodCategory') {
const foodCategory = foodCategories.find(({ id }) => id === value)
if (foodCategory) {
value = foodCategory.name
}
}
return (
<Text
fontWeight={isBold ? 'semibold' : 'normal'}
fontSize={isBold ? 'lg' : 'md'}
>
{inputType === 'nutritionValue'
? `${formatNutritionValue(value)}${nutritionValueUnit}`
: value}
</Text>
)
}}
/>
)
}
Example #10
Source File: formItem.tsx From Search-Next with GNU General Public License v3.0 | 6 votes |
FormItem: React.FC<FormItemProps> = (props) => {
const {
name,
children,
size,
rules,
defaultValue = '',
label,
control,
} = props;
return (
<div style={{ padding: '6px 0' }}>
<Controller
name={name}
control={control}
rules={rules}
defaultValue={defaultValue}
render={({
field: { onChange: controllerOnChange, ref, ...field },
fieldState: { error },
}) =>
React.cloneElement(children, {
onChange: (e: any) => {
if (children.props.onChange) children.props.onChange(e);
controllerOnChange(e);
},
label,
size,
inputRef: ref,
...field,
error: !!error,
helperText: error ? error.message : '',
})
}
/>
</div>
);
}
Example #11
Source File: SideDrawerField.tsx From firetable with Apache License 2.0 | 5 votes |
export default function Action({
column,
control,
docRef,
disabled,
}: ISideDrawerFieldProps) {
const classes = useStyles();
const fieldClasses = useFieldStyles();
const row = useWatch({ control });
return (
<Controller
control={control}
name={column.key}
render={({ onChange, value }) => {
const hasRan = value && value.status;
return (
<Grid container alignItems="center" wrap="nowrap" spacing={2}>
<Grid item xs className={classes.labelGridItem}>
<div className={fieldClasses.root}>
<Typography variant="body1" className={classes.label}>
{hasRan && isUrl(value.status) ? (
<Link
href={value.status}
target="_blank"
rel="noopener noreferrer"
variant="body2"
underline="always"
>
{value.status}
</Link>
) : hasRan ? (
value.status
) : (
sanitiseCallableName(column.key)
)}
</Typography>
</div>
</Grid>
<Grid item>
<ActionFab
row={{ ...row, ref: docRef }}
column={{ config: column.config, key: column.key }}
onSubmit={onChange}
value={value}
disabled={disabled}
/>
</Grid>
</Grid>
);
}}
/>
);
}
Example #12
Source File: NumberField.tsx From react-hook-form-generator with MIT License | 5 votes |
NumberField: FC<FieldProps<NumberFieldSchema>> = ({
id,
name,
field,
defaultValue,
}) => {
const {
label,
placeholder,
helperText,
isRequired,
shouldDisplay,
styles = {},
} = field;
const fieldStyles = useStyles<FieldStyles>('numberField', styles);
const { control, watch } = useFormContext();
const values = watch(name);
const errorMessage = useErrorMessage(name, label);
const isVisible = useMemo(() => {
return shouldDisplay ? shouldDisplay(values) : true;
}, [values, shouldDisplay]);
return isVisible ? (
<FormControl
key={`${name}-control`}
isRequired={isRequired}
isInvalid={!!errorMessage}
{...fieldStyles.control}
>
{!!label && (
<FormLabel htmlFor={name} {...fieldStyles.errorMessage}>
{label}
</FormLabel>
)}
<Controller
name={name}
control={control}
defaultValue={defaultValue || 0}
as={
<NumberInput>
<NumberInputField
id={id}
data-testid={id}
placeholder={placeholder}
{...fieldStyles.input}
/>
<NumberInputStepper>
<NumberIncrementStepper />
<NumberDecrementStepper />
</NumberInputStepper>
</NumberInput>
}
/>
{!!helperText && (
<FormHelperText {...fieldStyles.helperText}>
{helperText}
</FormHelperText>
)}
<FormErrorMessage {...fieldStyles.errorMessage}>
{errorMessage}
</FormErrorMessage>
</FormControl>
) : null;
}
Example #13
Source File: index.tsx From taskcafe with MIT License | 5 votes |
AddUserPopup: React.FC<AddUserPopupProps> = ({ onAddUser }) => {
const {
register,
handleSubmit,
formState: { errors },
setError,
control,
} = useForm<CreateUserData>();
const createUser = (data: CreateUserData) => {
onAddUser(data, setError);
};
return (
<CreateUserForm onSubmit={handleSubmit(createUser)}>
<AddUserInput
width="100%"
label="Full Name"
variant="alternate"
{...register('fullName', { required: 'Full name is required' })}
/>
{errors.fullName && <InputError>{errors.fullName.message}</InputError>}
<AddUserInput
floatingLabel
width="100%"
label="Email"
variant="alternate"
{...register('email', { required: 'Email is required' })}
/>
{errors.email && <InputError>{errors.email.message}</InputError>}
<Controller
control={control}
name="roleCode"
rules={{ required: 'Role is required' }}
render={({ field }) => (
<Select
{...field}
label="Role"
options={[
{ label: 'Admin', value: 'admin' },
{ label: 'Member', value: 'member' },
]}
/>
)}
/>
{errors.roleCode && errors.roleCode.value && <InputError>{errors.roleCode.value.message}</InputError>}
<AddUserInput
floatingLabel
width="100%"
label="Username"
variant="alternate"
{...register('username', { required: 'Username is required' })}
/>
{errors.username && <InputError>{errors.username.message}</InputError>}
<AddUserInput
floatingLabel
width="100%"
label="Initials"
variant="alternate"
{...register('initials', { required: 'Initials is required' })}
/>
{errors.initials && <InputError>{errors.initials.message}</InputError>}
<AddUserInput
floatingLabel
width="100%"
label="Password"
variant="alternate"
type="password"
{...register('password', { required: 'Password is required' })}
/>
{errors.password && <InputError>{errors.password.message}</InputError>}
<CreateUserButton type="submit">Create</CreateUserButton>
</CreateUserForm>
);
}
Example #14
Source File: CreditCardForm.tsx From storefront with MIT License | 5 votes |
CreditCardForm = React.forwardRef<HTMLFormElement, Props>(({ onSubmit }, ref) => {
const innerRef = useRef<HTMLFormElement>(null);
const { control, formState, handleSubmit } = useForm<CreditCardFormData>({
defaultValues: { ccNumber: '', ccExp: '', ccCsc: '' },
});
// Override standard form methods, this works for now:
useImperativeHandle(ref, () => ({
...(innerRef.current ?? new HTMLFormElement()),
checkValidity: () => innerRef.current?.checkValidity() ?? false,
reportValidity: () => innerRef.current?.reportValidity() ?? false,
submit: () => {
handleSubmit(onSubmit)();
},
}));
return (
<form ref={innerRef} onSubmit={handleSubmit(onSubmit)}>
<Controller
control={control}
name="ccNumber"
render={({ field }) => (
<NumberFormat
fullWidth
required
autoComplete="cc-number"
customInput={TextField}
error={'ccNumber' in formState.errors}
format="#### #### #### ####"
label="Number"
margin="normal"
{...field}
/>
)}
/>
<Grid container spacing={2}>
<Grid item xs={6}>
<Controller
control={control}
name="ccExp"
render={({ field }) => (
<NumberFormat
fullWidth
required
autoComplete="cc-csc"
customInput={TextField}
error={'ccExp' in formState.errors}
format="## / ##"
label="Expiry date"
margin="normal"
{...field}
/>
)}
/>
</Grid>
<Grid item xs={6}>
<Controller
control={control}
name="ccCsc"
render={({ field }) => (
<NumberFormat
fullWidth
required
autoComplete="cc-csc"
customInput={TextField}
error={'ccCsc' in formState.errors}
format="###"
label="CVC"
margin="normal"
{...field}
/>
)}
/>
</Grid>
</Grid>
</form>
);
})
Example #15
Source File: InputSelector.tsx From backstage with Apache License 2.0 | 5 votes |
InputSelector = ({ name, options, control, error }: Props) => {
const label = name.charAt(0).toLocaleUpperCase('en-US') + name.slice(1);
return (
<Controller
name={name}
control={control}
rules={{
required: true,
}}
render={({ field }) => (
<FormControl fullWidth>
<InputLabel
required
htmlFor="demo-simple-select-outlined"
id="demo-simple-select-outlined-label"
style={{
marginTop: '0.25rem',
}}
>
{label}
</InputLabel>
<Select
{...field}
labelId="demo-simple-select-outlined-label"
id="demo-simple-select-outlined"
label={label}
error={!!error}
>
{options.map(option => {
return (
<MenuItem button key={option} value={option}>
{option}
</MenuItem>
);
})}
</Select>
</FormControl>
)}
/>
);
}
Example #16
Source File: DelegationChangeProposalForm.tsx From homebase-app with MIT License | 5 votes |
DelegationChangeProposalForm: React.FC<Props> = ({ open, handleClose, defaultValues }) => {
const daoId = useDAOID();
const { data: dao } = useDAO(daoId);
const { data: daoHoldings } = useDAOHoldings(daoId);
const methods = useForm<Values>({
defaultValues: useMemo(
() => ({
newDelegationAddress: "",
...defaultValues,
}),
[defaultValues]
),
// resolver: yupResolver(validationSchema as any),
});
const newDelegationAddress = methods.watch("newDelegationAddress");
useEffect(() => {
methods.reset(defaultValues);
}, [defaultValues, methods]);
const { mutate } = useProposeDelegationChange();
const onSubmit = useCallback(
(values: Values) => {
if (dao) {
mutate({ dao, newDelegationAddress: values.newDelegationAddress });
handleClose();
}
},
[dao, handleClose, mutate]
);
return (
<FormProvider {...methods}>
<ResponsiveDialog
open={open}
onClose={handleClose}
aria-labelledby='alert-dialog-title'
aria-describedby='alert-dialog-description'
title={"Change Delegate"}>
<Content container direction={"column"} style={{ gap: 18 }}>
<Grid item>
<ProposalFormInput label={"New Delegate Address"}>
<Controller
control={methods.control}
name={`newDelegationAddress`}
render={({ field }) => (
<TextField
{...field}
type='text'
placeholder=' tz1...'
InputProps={{ disableUnderline: true }}
/>
)}
/>
</ProposalFormInput>
</Grid>
<Grid item>
<Typography align='left' variant='subtitle2' color='textPrimary' display={"inline"}>
Proposal Fee:{" "}
</Typography>
<Typography align='left' variant='subtitle2' color='secondary' display={"inline"}>
{dao && dao.data.extra.frozen_extra_value.toString()} {dao ? dao.data.token.symbol : ""}
</Typography>
</Grid>
<SendButton
onClick={methods.handleSubmit(onSubmit as any)}
disabled={!dao || !daoHoldings || !newDelegationAddress}>
Submit
</SendButton>
</Content>
</ResponsiveDialog>
</FormProvider>
);
}
Example #17
Source File: CheckboxElement.tsx From react-hook-form-mui with MIT License | 5 votes |
export default function CheckboxElement({
name,
validation = {},
required,
parseError,
label,
control,
...rest
}: CheckboxElementProps): JSX.Element {
if (required) {
validation.required = 'This field is required'
}
return (
<Controller
name={name}
rules={validation}
control={control}
render={({ field: { value, onChange }, fieldState: { invalid, error } }) => {
const helperText = error ? (typeof parseError === 'function' ? parseError(error) : error.message) : rest.helperText
return (
<FormControl required={required} error={invalid}>
<FormGroup row>
<FormControlLabel
label={label || ''}
control={
<Checkbox
color={'primary'}
sx={{
color: invalid ? "error.main" : undefined,
}}
value={value}
checked={!!value}
onChange={() => {
onChange(!value)
//setValue(name, !formValue, { shouldValidate: true })
}}
/>
}
/>
</FormGroup>
{helperText && <FormHelperText error={invalid}>{helperText}</FormHelperText>}
</FormControl>
)
}}
/>
)
}
Example #18
Source File: CollectionFilter.tsx From firebase-tools-ui with Apache License 2.0 | 5 votes |
ConditionSelect: React.FC<React.PropsWithChildren<unknown>> = ({
children,
}) => {
const options: Array<{
label: string;
value: firebase.firestore.WhereFilterOp;
}> = [
{
label: '(==) equal to',
value: '==',
},
{
label: '(!=) not equal to',
value: '!=',
},
{
label: '(>) greater than',
value: '>',
},
{
label: '(>=) greater than or equal to',
value: '>=',
},
{
label: '(<) less than',
value: '<',
},
{
label: '(<=) less than or equal to',
value: '<=',
},
{
label: '(in) equal to any of the following',
value: 'in',
},
{
label: '(not-in) not equal to any of the following',
value: 'not-in',
},
{
label: '(array-contains) an array containing',
value: 'array-contains',
},
{
label: '(array-contains-any) an array containing any',
value: 'array-contains-any',
},
];
return (
<>
<Controller
name="operator"
render={({ field: { ref, ...field } }) => (
<SelectField
label="Only show documents where the specified field is..."
placeholder="No condition"
options={options}
{...field}
onChange={(selected) => {
field.onChange(selected.currentTarget.value || undefined);
}}
/>
)}
/>
{children}
</>
);
}
Example #19
Source File: FormTextField.tsx From rn-credit-card with MIT License | 5 votes |
FormTextField = React.forwardRef<TextInput, Props>((props, ref) => {
const {
name,
rules,
validationLength = 1,
formatter,
onBlur,
onValid,
...restOfProps
} = props
const { control, formState, trigger, watch } = useFormContext()
const value = watch(name)
useEffect(() => {
async function validate() {
const isValid = await trigger(name)
if (isValid) onValid?.()
}
if (value?.length >= validationLength) {
validate()
}
}, [value, name, validationLength, trigger]) // eslint-disable-line react-hooks/exhaustive-deps
return (
<Controller
control={control}
render={({ field }) => (
<TextField
// passing everything down to TextField
// to be able to support all TextInput props
{...restOfProps}
ref={ref}
testID={`TextField.${name}`}
errorText={formState.errors[name]?.message}
onBlur={(event) => {
field.onBlur()
onBlur?.(event)
}}
onChangeText={(text) => {
const formatted = formatter ? formatter(field.value, text) : text
field.onChange(formatted)
}}
value={field.value}
/>
)}
name={name}
rules={rules}
/>
)
})
Example #20
Source File: index.tsx From admin with MIT License | 5 votes |
ControlledCheckbox = ({
control,
name,
id,
index,
value,
...props
}: ControlledCheckboxProps) => {
const variants = useWatch<string[]>({
control,
name,
})
return (
<Controller
control={control}
name={name}
render={(field) => {
return (
<Checkbox
className="shrink-0 inter-small-regular"
{...props}
{...field}
checked={variants?.some((variant) => variant === value)}
onChange={(e) => {
// copy field value
const valueCopy = [...(variants || [])] as any[]
// update checkbox value
valueCopy[index] = e.target.checked ? id : null
// update field value
field.onChange(valueCopy)
}}
/>
)
}}
/>
)
}
Example #21
Source File: ContactForm.tsx From keycapsets.com with GNU General Public License v3.0 | 5 votes |
function ContactForm(): JSX.Element {
const { register, handleSubmit, errors, control, reset } = useForm<ContactKCSInputs>();
const close = useModalStore((s) => s.controls.close);
const [loading, setLoading] = useState(false);
async function submitContact(formValues: ContactKCSInputs, e: any) {
setLoading(true);
const body = {
...formValues,
source: 'PROMOTE_YOUR_SET',
};
try {
const URL = 'https://api.keycapsets.com/contact-kcs';
await fetch(URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(body),
});
setLoading(false);
e.target.reset();
} catch (err) {
console.log(err);
setLoading(false);
}
}
return (
<div className="column">
<h2>Contact</h2>
<br />
<form onSubmit={handleSubmit(submitContact)} className="contact-form">
<Input
id="name"
label="Full name"
reference={register({ required: `I'd like to know your name.` })}
className={errors.name ? 'invalid' : ''}
errorMessage={errors.name && (errors.name.message as string)}
/>
<Input
id="email"
label="Email address"
reference={register({
required: 'Email address is required',
pattern: {
value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i,
message: 'Email address is invalid',
},
})}
defaultValue={user.email}
className={errors.email ? 'invalid' : ''}
errorMessage={errors.email && (errors.email.message as string)}
/>
<Controller
as={TextArea}
control={control}
id="text"
name="text"
label="Message"
reference={register({ required: 'Let me know where you want to talk about!' })}
errorMessage={errors.text && (errors.text.message as string)}
/>
<div className="controls flex v-center">
<button className="btn secondary md" onClick={close}>
Cancel
</button>
<button className="btn primary md" type="submit">
{loading ? 'Loading...' : 'Send'}
</button>
</div>
</form>
</div>
);
}
Example #22
Source File: LabeledCheckbox.tsx From UsTaxes with GNU Affero General Public License v3.0 | 5 votes |
export function LabeledCheckbox<TFormValues>(
props: LabeledCheckboxProps<TFormValues>
): ReactElement {
const { label, name, useGrid = true, sizes = { xs: 12 } } = props
const { control } = useFormContext<TFormValues>()
return (
<ConditionallyWrap
condition={useGrid}
wrapper={(children) => (
<Grid item {...sizes}>
{children}
</Grid>
)}
>
<Controller
name={name}
render={({ field: { value, onChange } }) => (
<FormControl component="fieldset">
<FormGroup>
<FormControlLabel
control={
<Checkbox
name={name}
checked={value as boolean}
onChange={(_, checked) => onChange(checked)}
color="primary"
/>
}
label={label}
value={value}
/>
</FormGroup>
</FormControl>
)}
control={control}
/>
</ConditionallyWrap>
)
}
Example #23
Source File: VolumeFormFields.tsx From calories-in with MIT License | 5 votes |
function VolumeFields({ canEdit, food }: Props) {
const { register } = useFormContext<FoodForm>()
const { portionsById, volumeBasedPortions } = usePortions()
const portion = food?.volume ? portionsById[food.volume.portionId] : undefined
return (
<Flex minHeight={canEdit ? '200px' : undefined} flexDirection="column">
{canEdit && (
<Alert status="info" mb={3}>
<AlertIcon color="teal.400" />
Enter the food weight in grams per some volume measurement if you want
to convert between weight and volume (for example: between grams and
cups).
</Alert>
)}
<HStack spacing={2}>
{canEdit && <Text fontWeight="medium">1 x</Text>}
{canEdit ? (
<PortionsSelect
width="200px"
portions={volumeBasedPortions}
{...register('volumeForm.portionId')}
/>
) : (
<Text fontWeight="medium">
1 x {`${portion?.singular} (${portion?.millilitersPerAmount} ml)`}
</Text>
)}
<Text fontWeight="medium">=</Text>
<HStack spacing={1} alignItems="center">
{canEdit ? (
<Controller
name="volumeForm.weightInGrams"
render={({ field }) => (
<AmountInput value={field.value} onChange={field.onChange} />
)}
/>
) : (
<Text>{food?.volume?.weightInGrams}g</Text>
)}
{canEdit && <Text textColor="gray.500">g</Text>}
</HStack>
</HStack>
</Flex>
)
}
Example #24
Source File: APIBasicDetailsForm.tsx From one-platform with MIT License | 4 votes |
APIBasicDetailsForm = forwardRef<HTMLDivElement, Props>(
({ onSearchOwners }: Props, ref): JSX.Element => {
const { control, trigger } = useFormContext<FormData>();
// PFE select selected value could be either string or object
// Object when its a select from the list of provided
// String when creating or deleting
const onSelectOwner = (
onChange: (...event: any[]) => void,
value: FormData['owners'],
selected: string | SelectOptionObject,
isPlaceholder?: boolean
) => {
if (isPlaceholder) return;
const isSelectedString = typeof selected === 'string';
const id =
typeof selected === 'string' ? selected : (selected as { rhatUUID: string }).rhatUUID;
const isSelected = value.findIndex(({ mid, email }) => mid === id || email === id) !== -1;
if (isSelected) {
onChange(value.filter(({ mid, email }) => mid !== id && email !== id));
} else if (isSelectedString) {
onChange([...value, { group: ApiEmailGroup.MAILING_LIST, mid: selected, email: selected }]);
} else {
onChange([
...value,
{ group: ApiEmailGroup.USER, mid: id, email: (selected as { mail: string }).mail },
]);
}
// What it does: This triggers a validation on owner field after onChange
// Why: when react hook form in blur validation mode. The multi select has a text field and a selected view component
// On clicking select onblur is triggered before onchange on select view causing the validtion to fail
// thus onchange i trigger validation again
trigger('owners', { shouldFocus: false });
};
return (
<Card ref={ref}>
<CardTitle>
<Title headingLevel="h1">Add API to Catalog</Title>
</CardTitle>
<CardBody>
<Stack hasGutter>
<StackItem>
<Controller
control={control}
name="name"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormGroup
label="API Source name"
fieldId="api-source-name"
validated={error ? 'error' : 'success'}
helperTextInvalid={error?.message}
>
<TextInput
id="api-source-name"
placeholder="Give a name for the API datasource"
{...field}
/>
</FormGroup>
)}
/>
</StackItem>
<StackItem>
<Controller
control={control}
name="description"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormGroup
label="Description"
fieldId="api-desc-name"
validated={error ? 'error' : 'success'}
helperTextInvalid={error?.message}
>
<TextArea
id="api-source-name"
placeholder="Give a name for the API datasource"
{...field}
/>
</FormGroup>
)}
/>
</StackItem>
<StackItem>
<Controller
control={control}
name="owners"
defaultValue={[]}
render={({ field: { onChange, value, onBlur, name }, fieldState: { error } }) => (
<FormGroup
label="Owners"
fieldId="api-owners"
validated={error ? 'error' : 'success'}
helperTextInvalid={error?.message}
>
<AsyncSelect
render={debouncePromise(onSearchOwners)}
variant={SelectVariant.typeaheadMulti}
isCreatable
// onCreateOption={(mid) =>
// onChange([...value, { group: ApiEmailGroup.MAILING_LIST, mid, email: mid }])
// }
onSelect={(_, selected, isPlaceholder) =>
onSelectOwner(onChange, value, selected, isPlaceholder)
}
name={name}
onBlur={onBlur}
selections={value.map(({ email }) => email)}
createText="Use mailing list: "
placeholderText="Search by kerberos id or add mailing list"
customFilter={() => true}
maxHeight="320px"
/>
</FormGroup>
)}
/>
</StackItem>
</Stack>
</CardBody>
</Card>
);
}
)
Example #25
Source File: SideDrawerField.tsx From firetable with Apache License 2.0 | 4 votes |
export default function Slider({
control,
column,
disabled,
}: ISideDrawerFieldProps) {
const config: {
max: number;
min: number;
minLabel?: string;
maxLabel?: string;
step: number;
unit: string;
marks?: boolean;
} = {
max: 10,
step: 1,
units: "",
min: 0,
...(column as any).config,
};
const { max, marks, min, unit, minLabel, maxLabel, step } = config;
return (
<Controller
control={control}
name={column.key}
render={({ onChange, onBlur, value }) => {
const handleChange = (_: any, value: number | number[]) => {
onChange(value);
onBlur();
};
const getAriaValueText = (value: number) =>
`${value}${unit ? " " + unit : ""}`;
const getValueLabelFormat = (value: number) =>
`${value}${unit ? " " + unit : ""}`;
return (
<Grid container spacing={2} alignItems="center">
<Grid item>
<Typography
variant="overline"
component="span"
color="textSecondary"
>
{minLabel ?? `${min}${unit ? " " + unit : ""}`}
</Typography>
</Grid>
<Grid item xs>
<MuiSlider
valueLabelDisplay="auto"
min={min}
max={max}
marks={marks}
step={step ?? 1}
getAriaValueText={getAriaValueText}
valueLabelFormat={getValueLabelFormat}
value={value ?? min}
onClick={onBlur}
onChange={handleChange}
disabled={disabled}
style={{ display: "block" }}
/>
</Grid>
<Grid item>
<Typography
variant="overline"
component="span"
color="textSecondary"
>
{maxLabel ?? `${max}${unit ? " " + unit : ""}`}
</Typography>
</Grid>
</Grid>
);
}}
/>
);
}
Example #26
Source File: SetUp.tsx From atlas with GNU General Public License v3.0 | 4 votes |
SetUp: React.FC<SetUpProps> = ({
selectedType,
activeInputs,
setActiveInputs,
maxEndDate,
maxStartDate,
handleGoForward,
}) => {
const {
register,
setValue,
getValues,
watch,
reset,
trigger,
control,
formState: { errors },
} = useFormContext<NftFormFields>()
const startDate = watch('startDate')
const endDate = watch('endDate')
const { getNumberOfBlocks, chainState } = useNftFormUtils()
const { convertToUSD } = useTokenPrice()
const numberOfBlocks = getNumberOfBlocks(startDate, endDate) || 0
const totalDaysAndHours = getTotalDaysAndHours(startDate, endDate)
const isEnglishAuction = watch('type') === 'english'
const buyNowPrice = watch('buyNowPrice')
const startingPrice = watch('startingPrice')
useEffect(() => {
setTimeout(() => {
setValue(
'endDate',
isEnglishAuction
? getValues('endDate') || {
type: 'duration',
durationDays: 1,
}
: null
)
}, 0)
}, [getValues, isEnglishAuction, setValue])
useEffect(() => {
setValue('auctionDurationBlocks', numberOfBlocks || undefined)
}, [numberOfBlocks, setValue])
const toggleActiveInput = (event?: React.ChangeEvent<HTMLInputElement>) => {
if (!event) {
return
}
const { name } = event.target
setActiveInputs((prevState) => {
if (!prevState.includes(name)) {
if (name === 'buyNowPrice') {
setValue('buyNowPrice', 2)
trigger() // trigger form validation to make sure starting price is valid
}
return [...prevState, name]
}
if (name === 'whitelistedMembers') {
setValue('whitelistedMembers', [])
}
if (name === 'auctionDuration') {
setValue('startDate', null)
setValue('endDate', null)
} else if (name === 'startingPrice') {
setValue('startingPrice', chainState.nftMinStartingPrice || undefined)
} else {
reset({ ...getValues(), [name]: undefined })
}
return prevState.filter((inputName) => inputName !== name)
})
}
const headerText = {
'Auction': {
header: 'Auction',
caption: 'Pick a timed or open auction. Optionally set up a buy now price.',
},
'Fixed price': {
header: 'Fixed price',
caption: 'Set up the price for your NFT. It can be changed later. Cancel anytime.',
},
}
const days = [1, 3, 5, 7] as const
const expirationDateItems = days.map((value) => ({
name: pluralizeNoun(value, 'day'),
value: {
type: 'duration' as const,
durationDays: value,
},
}))
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault()
handleGoForward()
}
const handleNumberInputBlur = (event: React.FocusEvent<HTMLInputElement>) => {
const { target } = event
if (Number(target.value) % 1 !== 0) {
setValue(target.name as 'buyNowPrice' | 'startingPrice', Math.floor(Number(event.target.value)))
}
}
return (
<>
<Header variant="h500">{selectedType && headerText[selectedType].header}</Header>
<Text variant="t300" secondary>
{selectedType && headerText[selectedType].caption}
</Text>
<form onSubmit={handleSubmit}>
{selectedType === 'Fixed price' && (
<StyledFormField title="">
<TextField
{...register('buyNowPrice', { valueAsNumber: true })}
type="number"
nodeStart={<JoyTokenIcon variant="gray" size={24} />}
nodeEnd={!!buyNowPrice && <Pill variant="overlay" label={`${convertToUSD(buyNowPrice)}`} />}
error={!!errors.buyNowPrice}
helperText={errors.buyNowPrice?.message}
onBlur={handleNumberInputBlur}
/>
</StyledFormField>
)}
{selectedType === 'Auction' && (
<>
<Controller
name="type"
control={control}
defaultValue="open"
render={({ field: { value, onChange } }) => (
<OptionCardRadioWrapper>
<OptionCardRadio
value="open"
label="Open auction"
helperText="Pick the winning bid or cancel anytime"
onChange={() => onChange('open')}
selectedValue={value}
/>
<OptionCardRadio
value="english"
label="Timed auction"
helperText="Highest bidder wins, cannot be cancelled once started"
onChange={() => onChange('english')}
selectedValue={value}
/>
</OptionCardRadioWrapper>
)}
/>
<AuctionDatePickerWrapper columns={isEnglishAuction ? 2 : 1}>
<Controller
name="startDate"
control={control}
render={({ field: { onChange, value }, fieldState: { error } }) => (
<AuctionDatePicker
size="regular"
label="Starts"
error={!!error}
helperText={error?.message}
minDate={new Date()}
maxDate={endDate?.type === 'date' && endDate.date < maxStartDate ? endDate.date : maxStartDate}
items={[
{
value: null,
name: 'Now',
},
]}
onChange={onChange}
value={value}
/>
)}
/>
{isEnglishAuction && (
<Controller
name="endDate"
control={control}
render={({ field: { onChange, value }, fieldState: { error } }) => (
<AuctionDatePicker
size="regular"
label="Ends"
error={!!error}
helperText={error?.message}
minDate={(startDate?.type === 'date' && startDate.date) || new Date()}
maxDate={maxEndDate}
onChange={onChange}
items={expirationDateItems}
value={
value || {
type: 'duration',
durationDays: 1,
}
}
/>
)}
/>
)}
</AuctionDatePickerWrapper>
{numberOfBlocks > 0 && (
<DaysSummary>
<Text variant="t200-strong" color={cVar('colorTextMuted', true)}>
Total:
</Text>
<Text variant="t200-strong">{totalDaysAndHours}</Text>
<Text variant="t200-strong" secondary>
/ {formatNumber(numberOfBlocks)} blocks
</Text>
<DaysSummaryInfo text="On blockchain, duration is expressed in number of blocks" placement="top" />
</DaysSummary>
)}
<FormField
title="Minimum bid"
switchProps={{
name: 'startingPrice',
onChange: toggleActiveInput,
value: activeInputs.includes('startingPrice'),
}}
infoTooltip={{ text: 'Only bids higher than this value will be accepted' }}
>
<TextField
{...register('startingPrice', { valueAsNumber: true })}
type="number"
defaultValue={chainState.nftMinStartingPrice?.toString()}
nodeStart={<JoyTokenIcon variant="gray" size={24} />}
nodeEnd={!!startingPrice && <Pill variant="overlay" label={`${convertToUSD(startingPrice)}`} />}
disabled={!activeInputs.includes('startingPrice')}
error={!!errors.startingPrice}
helperText={errors.startingPrice?.message}
onBlur={handleNumberInputBlur}
/>
</FormField>
<FormField
title="Buy now price"
switchProps={{
name: 'buyNowPrice',
onChange: toggleActiveInput,
value: activeInputs.includes('buyNowPrice'),
}}
infoTooltip={{
text: 'Bids matching this value will automatically end your auction',
}}
>
<TextField
{...register('buyNowPrice', { valueAsNumber: true })}
placeholder="—"
type="number"
nodeStart={<JoyTokenIcon variant="gray" size={24} />}
nodeEnd={!!buyNowPrice && <Pill variant="overlay" label={`${convertToUSD(buyNowPrice)}`} />}
disabled={!activeInputs.includes('buyNowPrice')}
error={!!errors.buyNowPrice}
helperText={errors.buyNowPrice?.message}
onBlur={(event) => {
trigger() // trigger form validation to make sure starting price is valid
handleNumberInputBlur(event)
}}
/>
</FormField>
<FormField
title="Whitelist"
switchProps={{
name: 'whitelistedMembers',
onChange: toggleActiveInput,
value: activeInputs.includes('whitelistedMembers'),
}}
infoTooltip={{
text: 'Only members included in the whitelist will be able to bid on this auction',
}}
>
<Controller
name="whitelistedMembers"
control={control}
render={({ field: { onChange, value: existingMembers }, fieldState: { error } }) => {
return (
<MemberComboBox
disabled={!activeInputs.includes('whitelistedMembers')}
selectedMembers={existingMembers || []}
error={!!error}
helperText={error?.message}
onSelectMember={(member) => onChange([member, ...(existingMembers ? existingMembers : [])])}
onRemoveMember={(memberId) =>
onChange(existingMembers?.filter((existingMember) => existingMember.id !== memberId))
}
/>
)
}}
/>
</FormField>
</>
)}
</form>
</>
)
}
Example #27
Source File: [[...id]].tsx From tams-club-cal with MIT License | 4 votes |
EditVolunteering = ({ volunteering, id, error }: InferGetServerSidePropsType<typeof getServerSideProps>) => {
const router = useRouter();
const [backdrop, setBackdrop] = useState(false);
const [popupEvent, setPopupEvent] = useState<PopupEvent>(null);
const { handleSubmit, control, setValue } = useForm();
// When the user submits the form, either create or update the volunteering opportunity
const onSubmit = async (data) => {
// If the name is empty, do nothing
if (!('name' in data)) return;
// Create the volunteering object from the data
const newVolunteering = createVolunteering(
id,
data.name,
data.club,
data.description,
createFilters(data.limited, data.semester, data.setTimes, data.weekly, data.open),
volunteering.history
);
// Start the upload process
setBackdrop(true);
// If the ID is null, create the volunteering, otherwise update it
const res = id === null ? await postVolunteering(newVolunteering) : await putVolunteering(newVolunteering, id);
// Finished uploading
setBackdrop(false);
// If the request was successful, redirect to the volunteering page, otherwise display an error
if (res.status === 204) {
new Cookies().set('success', id ? 'update-volunteering' : 'add-volunteering', {
sameSite: 'strict',
path: '/',
});
back();
} else setPopupEvent(createPopupEvent('Unable to upload data. Please refresh the page or try again.', 4));
};
// Returns the user back to the volunteering display page
const back = () => {
router.push(`/volunteering${id ? `/${id}` : ''}`);
};
// On load
useEffect(() => {
// Send error if can't fetch resource
if (error) {
setPopupEvent(
createPopupEvent('Error fetching volunteering info. Please refresh the page or add a new event.', 4)
);
}
// When the volunteering data is loaded, set the open value to the controller as a seperate variable
setValue('open', volunteering.filters.open);
}, []);
return (
<EditWrapper>
<TitleMeta title={`${id ? 'Edit' : 'Add'} Volunteering`} path={`/edit/volunteering/${id ? id : ''}`} />
<UploadBackdrop open={backdrop} />
<Popup event={popupEvent} />
<Typography variant="h1" sx={{ textAlign: 'center', fontSize: '3rem' }}>
{id ? 'Edit Volunteering' : 'Add Volunteering'}
</Typography>
{id ? <AddButton editHistory path={`/edit/history/volunteering/${id}`} /> : null}
<FormWrapper onSubmit={handleSubmit(onSubmit)}>
{/* TODO: Make a BoxWrapper component as this css is repeated so much across all forms */}
<Box sx={{ marginBottom: 3, display: 'flex', flexDirection: { lg: 'row', xs: 'column' } }}>
<Controller
control={control}
name="open"
render={({ field: { onChange, onBlur, value } }) => (
<FormControlLabel
label="Open"
labelPlacement="start"
control={
<Switch
color="primary"
value={value}
onChange={onChange}
onBlur={onBlur}
checked={value}
defaultChecked={volunteering.filters.open}
/>
}
/>
)}
/>
<Spacer />
<ControlledTextField
control={control}
setValue={setValue}
value={volunteering.name}
label="Volunteering Name"
name="name"
variant="outlined"
grow
required
errorMessage="Please enter a name"
sx={{ marginLeft: { lg: 2, xs: 0 } }}
/>
<Spacer />
<ControlledTextField
control={control}
setValue={setValue}
value={volunteering.club}
label="Club"
name="club"
variant="outlined"
grow
required
errorMessage="Please enter a club name"
/>
</Box>
<Hidden mdDown>
<Typography sx={{ display: 'inline', marginRight: { lg: 16, xs: 0 } }}>Filters:</Typography>
</Hidden>
<ControlledFilterCheckbox
control={control}
setValue={setValue}
name="limited"
label="Limited Slots"
value={volunteering.filters.limited}
/>
<ControlledFilterCheckbox
control={control}
setValue={setValue}
name="semester"
label="Semester Long Committment"
value={volunteering.filters.semester}
/>
<ControlledFilterCheckbox
control={control}
setValue={setValue}
name="setTimes"
label="Set Time Slots"
value={volunteering.filters.setTimes}
/>
<ControlledFilterCheckbox
control={control}
setValue={setValue}
name="weekly"
label="Repeats Weekly"
value={volunteering.filters.weekly}
/>
<ControlledTextField
control={control}
setValue={setValue}
value={volunteering.description}
label="Description (optional)"
name="description"
variant="outlined"
area
sx={{ marginTop: 2 }}
/>
<TwoButtonBox success="Submit" onCancel={back} onSuccess={onSubmit} submit right />
</FormWrapper>
</EditWrapper>
);
}
Example #28
Source File: LoginView.tsx From storefront with MIT License | 4 votes |
LoginView: React.VFC = () => {
const [alert, setAlert] = useState<string>();
const { closeModal } = useUI();
const [login, { loading }] = useLoginMutation();
const { control, formState, handleSubmit } = useForm<LoginMutationVariables>({
resolver: yupResolver(validationSchema),
});
const onSubmit = handleSubmit(async (variables) => {
try {
const { data } = await login({ variables });
if (data?.login?.authToken != null) {
localStorage.setItem('authToken', data.login.authToken);
}
if (data?.login?.refreshToken != null) {
localStorage.setItem('refreshToken', data.login.refreshToken);
}
closeModal();
} catch (error) {
if (isApolloError(error)) {
setAlert(error.graphQLErrors[0].message);
}
}
});
return (
<>
<Box sx={{ textAlign: 'center', mb: 6 }}>
<Logo />
</Box>
<form onSubmit={onSubmit}>
{alert && (
<Box sx={{ mb: 2 }}>
<Alert severity="error">{alert}</Alert>
</Box>
)}
{/* Username or email */}
<Controller
control={control}
name="username"
render={({ field }) => (
<TextField
required
autoCapitalize="off"
autoCorrect="off"
error={'username' in formState.errors}
helperText={formState.errors.username?.message}
label="Username or email"
type="text"
{...field}
/>
)}
/>
{/* Password */}
<Controller
control={control}
name="password"
render={({ field }) => (
<TextField
required
error={'password' in formState.errors}
helperText={formState.errors.password?.message}
label="Password"
type="password"
{...field}
/>
)}
/>
<Box sx={{ mt: 1 }}>
<Button fullWidth type="submit" color="primary" loading={loading}>
Log in
</Button>
</Box>
<Box sx={{ mt: 1, textAlign: 'center' }}>
Don’t have an account? <Link href="/register">Register</Link>
</Box>
</form>
</>
);
}
Example #29
Source File: ShortcutForm.tsx From backstage with Apache License 2.0 | 4 votes |
ShortcutForm = ({ formValues, onSave, onClose }: Props) => {
const classes = useStyles();
const {
handleSubmit,
reset,
control,
formState: { errors },
} = useForm<FormValues>({
mode: 'onChange',
defaultValues: {
url: formValues?.url ?? '',
title: formValues?.title ?? '',
},
});
useEffect(() => {
reset(formValues);
}, [reset, formValues]);
return (
<>
<CardContent>
<Controller
name="url"
control={control}
rules={{
required: true,
pattern: {
value: /^\//,
message: 'Must be a relative URL (starts with a /)',
},
}}
render={({ field }) => (
<TextField
{...field}
error={!!errors.url}
helperText={errors.url?.message}
type="text"
placeholder="Enter a URL"
InputLabelProps={{
shrink: true,
}}
className={classes.field}
fullWidth
label="Shortcut URL"
variant="outlined"
autoComplete="off"
/>
)}
/>
<Controller
name="title"
control={control}
rules={{
required: true,
minLength: {
value: 2,
message: 'Must be at least 2 characters',
},
}}
render={({ field }) => (
<TextField
{...field}
error={!!errors.title}
helperText={errors.title?.message}
type="text"
placeholder="Enter a display name"
InputLabelProps={{
shrink: true,
}}
className={classes.field}
fullWidth
label="Display Name"
variant="outlined"
autoComplete="off"
/>
)}
/>
</CardContent>
<CardActions classes={{ root: classes.actionRoot }}>
<Button
variant="contained"
color="primary"
size="large"
onClick={handleSubmit(onSave)}
>
Save
</Button>
<Button variant="outlined" size="large" onClick={onClose}>
Cancel
</Button>
</CardActions>
</>
);
}