formik#getIn TypeScript Examples
The following examples show how to use
formik#getIn.
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: useForm.tsx From SQForm with MIT License | 6 votes |
function _getHasValue(meta: FieldMetaProps<unknown>) {
const fieldValue = getIn(meta, 'value');
if (Array.isArray(fieldValue)) {
return !!fieldValue.length;
}
if (typeof fieldValue === 'number') {
return true;
}
if (typeof fieldValue === 'boolean') {
return true;
}
return !!fieldValue;
}
Example #2
Source File: useForm.tsx From SQForm with MIT License | 6 votes |
function _transformErrorMessageToString<TValue>(meta: FieldMetaProps<TValue>) {
const error = getIn(meta, 'error');
if (Array.isArray(error)) {
return error.join('').toLowerCase() || undefined;
}
return error;
}
Example #3
Source File: PhoneInput.tsx From glific-frontend with GNU Affero General Public License v3.0 | 6 votes |
PhoneInput: React.SFC<InputProps> = ({
enableSearch = true,
form: { errors, setFieldValue },
field,
inputProps = {
name: field.name,
required: true,
autoFocus: false,
},
...props
}) => {
const errorText = getIn(errors, field.name);
const { placeholder } = props;
return (
<div className={styles.Input} data-testid="phoneInput">
<FormControl>
<ReactPhoneInput
containerClass={styles.Container}
inputClass={styles.PhoneNumber}
data-testid="phoneNumber"
placeholder={placeholder}
enableSearch={enableSearch}
country="in"
autoFormat={false}
inputProps={inputProps}
{...field}
value={field.value}
onChange={(event) => {
setFieldValue(field.name, event);
}}
/>
{errorText ? (
<FormHelperText classes={{ root: styles.FormHelperText }}>{errorText}</FormHelperText>
) : null}
</FormControl>
</div>
);
}
Example #4
Source File: InputChip.tsx From frontegg-react with MIT License | 6 votes |
FInputChip: FC<InputChipProps & { name: string }> = ({ name, disabled, onChange, ...props }) => {
const [inputProps, { touched, error }, { setValue, setTouched }] = useField(name);
const { values, isSubmitting, validateForm } = useFormikContext();
const debounceError = useDebounce(error, 2000);
useEffect(() => {
!!debounceError && validateForm(values);
}, [validateForm, debounceError, values]);
const onValidate = useCallback(
async (value: string[]) => {
!touched && setTouched(true);
const errors = await validateForm(setIn(values, name, value));
return !getIn(errors, name);
},
[setTouched, name, values, validateForm]
);
return (
<InputChip
{...inputProps}
{...props}
validate={onValidate}
disabled={isSubmitting || disabled}
error={touched && error ? error : undefined}
onChange={onChange ?? ((val) => setValue(val))}
/>
);
}
Example #5
Source File: TextArrayField.tsx From netify with BSD 2-Clause "Simplified" License | 5 votes |
TextArrayField = memo<TextArrayFieldProps>(function TextArrayField(props) {
const {name, placeholder, addControlTitle = 'Add new one', removeControlTitle = 'Remove item'} = props;
return (
<ul className={styles.root}>
<FieldArray
name={name}
render={helpers => {
const list = getIn(helpers.form.values, name);
return list.map((_: any, index: number) => (
// eslint-disable-next-line react/no-array-index-key
<li key={index} className={styles.item}>
<div className={styles.entry}>
<TextField
className={styles.field}
name={`${name}[${index}]`}
placeholder={placeholder}
/>
{index === list.length - 1 ? (
<IconButton
className={styles.control}
icon={<AddIcon />}
tooltip={addControlTitle}
onClick={() => helpers.push('')}
/>
) : (
<IconButton
className={styles.control}
icon={<RemoveIcon />}
tooltip={removeControlTitle}
onClick={() => helpers.remove(index)}
/>
)}
</div>
<FieldError name={`${name}[${index}]`} />
</li>
));
}}
/>
</ul>
);
})
Example #6
Source File: KeyValueArrayField.tsx From netify with BSD 2-Clause "Simplified" License | 5 votes |
KeyValueArrayField = memo<KeyValueArrayFieldProps>(function KeyValueArrayField(props) {
const {
name,
keyNameSuffix,
valueNameSuffix,
keyPlaceholder,
valuePlaceholder,
addControlTitle = 'Add new one',
removeControlTitle = 'Remove item',
} = props;
return (
<ul className={styles.root}>
<FieldArray
name={name}
render={helpers => {
const list = getIn(helpers.form.values, name);
return list.map((_: any, index: number) => (
// eslint-disable-next-line react/no-array-index-key
<li key={index} className={styles.item}>
<div className={styles.entry}>
<TextField
className={styles.field}
name={`${name}[${index}].${keyNameSuffix}`}
placeholder={keyPlaceholder}
/>
<TextField
className={styles.field}
name={`${name}[${index}].${valueNameSuffix}`}
placeholder={valuePlaceholder}
/>
{index === list.length - 1 ? (
<IconButton
className={styles.control}
icon={<AddIcon />}
tooltip={addControlTitle}
onClick={() => helpers.push({[keyNameSuffix]: '', [valueNameSuffix]: ''})}
/>
) : (
<IconButton
className={styles.control}
icon={<RemoveIcon />}
tooltip={removeControlTitle}
onClick={() => helpers.remove(index)}
/>
)}
</div>
<FieldError name={`${name}[${index}].${keyNameSuffix}`} />
<FieldError name={`${name}[${index}].${valueNameSuffix}`} />
</li>
));
}}
/>
</ul>
);
})
Example #7
Source File: TimePicker.tsx From glific-frontend with GNU Affero General Public License v3.0 | 5 votes |
TimePicker: React.SFC<TimePickerProps> = ({
variant = 'inline',
inputVariant = 'outlined',
field,
form: { setFieldValue, touched, errors },
placeholder,
disabled = false,
helperText,
}) => {
moment.defaultFormat = 'Thh:mm:ss';
const dateValue = field.value ? moment(field.value, moment.defaultFormat).toDate() : null;
const [open, setOpen] = useState(false);
const errorText = getIn(errors, field.name);
const touchedVal = getIn(touched, field.name);
const hasError = touchedVal && errorText !== undefined;
const handleDateChange = (time: Date | null) => {
const value = time ? moment(time).format('THH:mm:ss') : null;
setFieldValue(field.name, value);
};
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<Grid className={styles.TimePicker}>
<KeyboardTimePicker
error={hasError}
autoOk
open={open}
variant={variant}
inputVariant={inputVariant}
label={placeholder}
data-testid="time-picker"
mask="__:__ _M"
value={dateValue}
onClick={() => !disabled && setOpen(true)}
onClose={() => setOpen(false)}
disabled={disabled}
onChange={(date) => handleDateChange(date)}
keyboardIcon={<ScheduleIcon />}
helperText={hasError ? errorText : ''}
className={styles.picker}
/>
{helperText && (
<div id="helper-text" className={styles.HelperText}>
{helperText}
</div>
)}
</Grid>
</MuiPickersUtilsProvider>
);
}
Example #8
Source File: OptionSet.tsx From amplication with Apache License 2.0 | 5 votes |
OptionSetOptions = ({
form,
name,
remove,
replace,
label,
}: {
label: string;
} & FieldArrayRenderProps) => {
const value = get(form.values, name) || [];
const [push, hasNew] = useVirtualPush(value);
const errors = useMemo(() => {
const error = getIn(form.errors, name);
if (typeof error === "string") return error;
return null;
}, [form.errors, name]);
const options = hasNew ? [...value, {}] : value;
return (
<div>
<h3>{label}</h3>
{errors && <div className="option-set__error-message">{errors}</div>}
{options.map((option: OptionItem, index: number) => (
<OptionSetOption
key={index}
index={index}
onChange={replace}
onRemove={remove}
name={name}
/>
))}
<Button onClick={push} buttonStyle={EnumButtonStyle.Clear}>
<Icon icon="plus" />
Add option
</Button>
</div>
);
}
Example #9
Source File: DateTimePicker.tsx From glific-frontend with GNU Affero General Public License v3.0 | 5 votes |
DateTimePicker: React.SFC<DateTimePickerProps> = ({
variant = 'inline',
inputVariant = 'outlined',
format = 'dd/MM/yyyy hh:mm a',
field,
form: { touched, errors, setFieldValue },
placeholder,
minDate,
onChange,
}) => {
const errorText = getIn(errors, field.name);
const touchedVal = getIn(touched, field.name);
const hasError = touchedVal && errorText !== undefined;
const dateValue = field.value ? field.value : null;
const handleDateChange = (date: Date | null | string) => {
const value = date && date.toString() !== 'Invalid Date' ? date : null;
setFieldValue(field.name, value);
if (onChange) onChange(value);
};
const icon = <CalenderIcon />;
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<Grid className={styles.DateTimePicker}>
<KeyboardDateTimePicker
className={styles.Text}
error={hasError}
autoOk
variant={variant}
inputVariant={inputVariant}
format={format}
data-testid="date-picker-inline"
label={placeholder}
value={dateValue}
onChange={handleDateChange}
helperText={hasError ? errorText : ''}
minDate={minDate}
keyboardIcon={icon}
/>
</Grid>
</MuiPickersUtilsProvider>
);
}
Example #10
Source File: Calendar.tsx From glific-frontend with GNU Affero General Public License v3.0 | 5 votes |
Calendar: React.SFC<CalendarProps> = ({
variant = 'inline',
inputVariant = 'outlined',
format = 'MM/dd/yyyy',
field,
disabled = false,
form: { touched, errors, setFieldValue },
placeholder,
minDate,
}) => {
const errorText = getIn(errors, field.name);
const touchedVal = getIn(touched, field.name);
const hasError = touchedVal && errorText !== undefined;
const dateValue = field.value ? field.value : null;
const [open, setOpen] = useState(false);
const handleDateChange = (date: Date | null | string) => {
if (date) {
if (date !== 'Invalid Date') setFieldValue(field.name, date);
} else {
setFieldValue(field.name, null);
}
};
return (
<MuiPickersUtilsProvider utils={DateFnsUtils}>
<Grid className={styles.Calendar}>
<KeyboardDatePicker
error={hasError}
autoOk
open={open}
variant={variant}
inputVariant={inputVariant}
format={format}
className={styles.CalendarInput}
disabled={disabled}
data-testid="date-picker-inline"
label={placeholder}
value={dateValue}
onClick={() => !disabled && setOpen(true)}
onClose={() => setOpen(false)}
onChange={handleDateChange}
helperText={hasError ? errorText : ''}
minDate={minDate}
/>
</Grid>
</MuiPickersUtilsProvider>
);
}
Example #11
Source File: Governance.tsx From homebase-app with MIT License | 4 votes |
GovernanceForm = ({
submitForm,
values,
setFieldValue,
errors,
touched,
}: any) => {
const { network } = useTezos();
const {
dispatch,
state: {
data: { orgSettings },
},
} = useContext(CreatorContext);
const match = useRouteMatch();
const history = useHistory();
const [blockTimeAverage, setBlockTimeAverage] = useState<number>(0);
const { votingBlocks, proposalFlushBlocks, proposalExpiryBlocks } = values;
const {
creationMoment,
closeMoment,
flushMoment,
expiryMoment,
votingTime,
flushDelayTime,
activeMoment,
expiryDelayTime,
} = useEstimatedBlockTimes({
votingBlocks,
proposalFlushBlocks,
proposalExpiryBlocks,
blockTimeAverage,
});
useEffect(() => {
(async () => {
const blockchainInfo = await getNetworkStats(network);
if (blockchainInfo) {
setBlockTimeAverage(blockchainInfo.minimal_block_delay);
}
})();
}, [network]);
useEffect(() => {
if (values) {
dispatch({
type: ActionTypes.UPDATE_NAVIGATION_BAR,
next: {
text: "CONTINUE",
handler: () => {
submitForm(values);
},
},
back: {
text: "BACK",
handler: () => history.push(`dao`),
},
});
}
}, [dispatch, errors, history, match.path, match.url, submitForm, values]);
return (
<>
<Grid container>
<Grid item style={{ marginRight: 15 }}>
<SecondContainer container direction="row">
<Typography
style={styles.voting}
variant="subtitle1"
color="textSecondary"
>
Voting Cycle Duration
</Typography>
</SecondContainer>
<GridItemContainer>
<CustomInputContainer item xs={12}>
<ItemContainer
container
direction="row"
alignItems="center"
justify="center"
>
<GridItemCenter item xs={6}>
<Field
name="votingBlocks"
type="number"
placeholder="00"
component={TextField}
inputProps={{ min: 0 }}
/>
</GridItemCenter>
<GridItemCenter item xs={6}>
<Typography color="textSecondary">blocks</Typography>
</GridItemCenter>
</ItemContainer>
</CustomInputContainer>
</GridItemContainer>
<Grid item>
{errors.votingBlocks && touched.votingBlocks ? (
<ErrorText>{errors.votingBlocks}</ErrorText>
) : null}
</Grid>
<Grid item style={{ margin: "14px 15px", height: 62 }}>
<EstimatedTime {...votingTime} />
</Grid>
</Grid>
<Grid item style={{ marginRight: 15 }}>
<SecondContainer container direction="row">
<Typography
style={styles.voting}
variant="subtitle1"
color="textSecondary"
>
Proposal Execution Delay
</Typography>
</SecondContainer>
<GridItemContainer>
<CustomInputContainer item xs={12}>
<ItemContainer
container
direction="row"
alignItems="center"
justify="center"
>
<GridItemCenter item xs={6}>
<Field
name="proposalFlushBlocks"
type="number"
placeholder="00"
component={TextField}
inputProps={{ min: 0 }}
/>
</GridItemCenter>
<GridItemCenter item xs={6}>
<Typography color="textSecondary">blocks</Typography>
</GridItemCenter>
</ItemContainer>
</CustomInputContainer>
</GridItemContainer>
<Grid item>
{errors.proposalFlushBlocks && touched.proposalFlushBlocks ? (
<ErrorText>{errors.proposalFlushBlocks}</ErrorText>
) : null}
</Grid>
<Grid item style={{ marginLeft: 15, height: 62, marginTop: 14 }}>
<EstimatedTime {...flushDelayTime} />
</Grid>
</Grid>
<Grid item style={{ marginRight: 15 }}>
<SecondContainer container direction="row">
<Typography
style={styles.voting}
variant="subtitle1"
color="textSecondary"
>
Proposal Expiration Threshold
</Typography>
</SecondContainer>
<GridItemContainer>
<CustomInputContainer item xs={12}>
<ItemContainer
container
direction="row"
alignItems="center"
justify="center"
>
<GridItemCenter item xs={6}>
<Field
name="proposalExpiryBlocks"
type="number"
placeholder="00"
component={TextField}
inputProps={{ min: 0 }}
/>
</GridItemCenter>
<GridItemCenter item xs={6}>
<Typography color="textSecondary">blocks</Typography>
</GridItemCenter>
</ItemContainer>
</CustomInputContainer>
</GridItemContainer>
<Grid item>
{errors.proposalExpiryBlocks && touched.proposalExpiryBlocks ? (
<ErrorText>{errors.proposalExpiryBlocks}</ErrorText>
) : null}
</Grid>
<Grid item style={{ marginLeft: 15, height: 62, marginTop: 14 }}>
<EstimatedTime {...expiryDelayTime} />
</Grid>
</Grid>
</Grid>
<Grid item style={{ margin: "24px 0" }}>
<Typography color={"textSecondary"}>
If Jane creates a DAO at{" "}
<CustomSpan>{dayjs().format("HH:mm MM/DD")}</CustomSpan>, she will be
able to create a proposal at{" "}
<CustomSpan>{creationMoment.format("HH:mm MM/DD")}</CustomSpan>, and
the DAO will vote on it from{" "}
<CustomSpan>{activeMoment.format("HH:mm MM/DD")} </CustomSpan>
through <CustomSpan>{closeMoment.format("HH:mm MM/DD")}</CustomSpan>.
If the proposal passes, it'll be executable at{" "}
<CustomSpan>{flushMoment.format("HH:mm MM/DD")}</CustomSpan> and will
expire at{" "}
<CustomSpan>{expiryMoment.format("HH:mm MM/DD")}</CustomSpan>
</Typography>
</Grid>
<Grid item style={{ marginTop: 12 }}>
<SecondContainer container direction="row">
<Typography
style={styles.voting}
variant="subtitle1"
color="textSecondary"
>
Required Stake to Propose
</Typography>
</SecondContainer>
<StakeContainer container direction="row" alignItems="center">
<AdditionContainer item xs={11} sm={4}>
<ItemContainer
container
direction="row"
alignItems="center"
justify="center"
>
<GridItemCenter item xs={6}>
<Field
name="proposeStakeRequired"
type="number"
placeholder="00"
inputProps={{ min: 0, defaultValue: 0 }}
component={TextField}
/>
</GridItemCenter>
<GridItemCenter
item
xs={6}
container
direction="row"
justify="space-around"
>
<Typography color="textSecondary">
{orgSettings.governanceToken.tokenMetadata?.symbol || ""}
</Typography>
<Tooltip
placement="bottom"
title={`Amount of ${
orgSettings.governanceToken.tokenMetadata?.symbol || ""
} required to make a proposal. Total supply: ${
orgSettings.governanceToken.tokenMetadata?.supply
}`}
>
<InfoIconInput color="secondary" />
</Tooltip>
</GridItemCenter>
</ItemContainer>
</AdditionContainer>
{errors.proposeStakeRequired || errors.proposeStakePercentage ? (
<ErrorText>
{errors.proposeStakeRequired || errors.proposeStakePercentage}
</ErrorText>
) : null}
</StakeContainer>
</Grid>
<SecondContainer container direction="row">
<Typography
style={styles.voting}
variant="subtitle1"
color="textSecondary"
>
Returned Stake After Proposal Rejection
</Typography>
<Grid
container
direction="row"
alignItems="center"
spacing={1}
style={{ marginTop: 14 }}
>
<GridNoPadding item xs={8} sm={9}>
<Field name="returnedTokenPercentage">
{() => (
<StyledSlider
value={getIn(values, "returnedTokenPercentage")}
onChange={(value: any, newValue: any) =>
setFieldValue("returnedTokenPercentage", newValue || 0)
}
/>
)}
</Field>
</GridNoPadding>
<GridNoPadding item xs={4} sm={3}>
<CustomSliderValue>
<Value variant="subtitle1" color="textSecondary">
{getIn(values, "returnedTokenPercentage")}%
</Value>
</CustomSliderValue>
</GridNoPadding>
</Grid>
</SecondContainer>
<SpacingContainer direction="row" container alignItems="center">
<Typography variant="subtitle1" color="textSecondary">
Min & Max Transfer Amounts
</Typography>
</SpacingContainer>
<Grid
container
direction="row"
alignItems="center"
style={{ marginTop: 14 }}
>
<AdditionContainer item xs={12} sm={4}>
<ItemContainer
container
direction="row"
alignItems="center"
justify="center"
>
<GridItemCenter item xs={5}>
<Field
name="minXtzAmount"
type="number"
placeholder="00"
component={TextField}
/>
</GridItemCenter>
<GridItemCenter
item
xs={7}
container
direction="row"
justify="space-around"
>
<ValueText color="textSecondary">Min. XTZ</ValueText>
<Tooltip
placement="bottom"
title="Minimum amount of XTZ that can be transferred"
>
<InfoIconInput color="secondary" />
</Tooltip>
</GridItemCenter>
</ItemContainer>
{errors.minXtzAmount && touched.minXtzAmount ? (
<ErrorText>{errors.minXtzAmount}</ErrorText>
) : null}
</AdditionContainer>
<AdditionContainer item xs={12} sm={4}>
<ItemContainer
container
direction="row"
alignItems="center"
justify="center"
>
<GridItemCenter item xs={5}>
<Field
name="maxXtzAmount"
type="number"
placeholder="00"
component={TextField}
/>
</GridItemCenter>
<GridItemCenter
item
xs={7}
container
direction="row"
justify="space-around"
>
<ValueText color="textSecondary">Max. XTZ </ValueText>
<Tooltip
placement="bottom"
title="Maximum amount of XTZ that can be transferred"
>
<InfoIconInput color="secondary" />
</Tooltip>
</GridItemCenter>
</ItemContainer>
{errors.maxXtzAmount && touched.maxXtzAmount ? (
<ErrorText>{errors.maxXtzAmount}</ErrorText>
) : null}
</AdditionContainer>
</Grid>
</>
);
}
Example #12
Source File: AutoComplete.tsx From glific-frontend with GNU Affero General Public License v3.0 | 4 votes |
AutoComplete: React.SFC<AutocompleteProps> = ({
options,
optionLabel,
additionalOptionLabel,
field,
icon,
chipIcon,
form: { touched, errors, setFieldValue },
textFieldProps,
helperText,
questionText,
multiple = true,
disabled = false,
freeSolo = false,
autoSelect = false,
getOptions,
asyncValues,
roleSelection,
onChange,
asyncSearch = false,
helpLink,
noOptionsText = 'No options available',
openOptions,
disableClearable = false,
listBoxProps,
classes = {},
renderTags = true,
selectedOptionsIds = [],
selectTextAsOption = false,
onInputChange = () => null,
valueElementName = 'id',
}) => {
const errorText = getIn(errors, field.name);
const touchedVal = getIn(touched, field.name);
const hasError = touchedVal && errorText !== undefined;
const [searchTerm, setSearchTerm] = useState('');
const [optionValue, setOptionValue] = useState([]);
const [open, setOpen] = useState(false);
useEffect(() => {
if (options.length > 0) {
setOptionValue(options);
}
}, [options]);
useEffect(() => {
if (getOptions && getOptions()) {
const optionList = getOptions();
if (optionList.length > 0) setOptionValue(optionList);
}
}, [open, getOptions]);
const getValue = (() => {
if (multiple && asyncSearch) return asyncValues.value;
if (multiple) {
if (optionValue.length > 0 && field.value) {
return optionValue.filter((option: any) =>
field.value.map((value: any) => value.id).includes(option.id)
);
}
return [];
}
return field.value;
})();
const getLabel = (option: any) => {
if (option[optionLabel]) {
return option[optionLabel];
}
if (additionalOptionLabel) {
return option[additionalOptionLabel];
}
return option;
};
/**
*
* @param value Callback value
* @param getTagProps Render tag props
*
*/
const getRenderTags = (value: Array<any>, getTagProps: any) => {
let tagsToRender = value;
/**
* when renderTags is true,
* default selected options along with newly selected options will be visible
* else,
* only post selected options will be visible
*/
if (!renderTags) {
tagsToRender = value.filter((option: any) => !selectedOptionsIds.includes(option.id));
}
return tagsToRender.map((option: any, index: number) => {
const props = getTagProps({ index });
/**
* If disableClearable is true, removing onDelete event
* deleteIcon component will be disabled, when onDelete is absent
*/
if (disableClearable) {
delete props.onDelete;
}
return (
<Chip
data-testid="searchChip"
style={{ backgroundColor: '#e2f1ea' }}
className={styles.Chip}
icon={chipIcon}
label={getLabel(option)}
{...props}
deleteIcon={<DeleteIcon className={styles.DeleteIcon} data-testid="deleteIcon" />}
/>
);
});
};
const getOptionDisabled = (option: any) => selectedOptionsIds.includes(option.id);
return (
<div className={styles.Input}>
<FormControl fullWidth error={hasError}>
{questionText ? <div className={styles.QuestionText}>{questionText}</div> : null}
<Autocomplete
classes={classes}
multiple={multiple}
data-testid="autocomplete-element"
options={optionValue}
freeSolo={freeSolo}
autoSelect={autoSelect}
disableClearable={disableClearable}
getOptionLabel={(option: any) => (option[optionLabel] ? option[optionLabel] : option)}
getOptionDisabled={getOptionDisabled}
getOptionSelected={(option, value) => {
if (value) {
return option[valueElementName] === value[valueElementName];
}
return false;
}}
onChange={(event, value: any) => {
if (roleSelection) {
roleSelection(value);
}
if (asyncSearch && value.length > 0) {
const filterValues = asyncValues.value.filter(
(val: any) => val.id !== value[value.length - 1].id
);
if (filterValues.length === value.length - 2) {
asyncValues.setValue(filterValues);
} else {
asyncValues.setValue([...value]);
}
setSearchTerm('');
onChange('');
} else if (asyncSearch && value.length === 0) {
asyncValues.setValue([]);
}
if (onChange) {
onChange(value);
}
setFieldValue(field.name, value);
}}
onInputChange={onInputChange}
inputValue={asyncSearch ? searchTerm : undefined}
value={getValue}
disabled={disabled}
disableCloseOnSelect={multiple}
renderTags={getRenderTags}
renderOption={(option: any, { selected }) => (
<>
{multiple ? (
<Checkbox
icon={icon}
checked={
asyncSearch
? asyncValues.value.map((value: any) => value.id).includes(option.id)
: selected
}
color="primary"
/>
) : (
''
)}
{getLabel(option)}
</>
)}
renderInput={(params: any) => {
const { inputProps } = params;
inputProps.value = selectTextAsOption ? field.value : inputProps.value;
const asyncChange = asyncSearch
? {
onChange: (event: any) => {
setSearchTerm(event.target.value);
return onChange(event.target.value);
},
}
: null;
return (
<TextField
{...params}
inputProps={inputProps}
{...asyncChange}
error={hasError}
helperText={hasError ? errorText : ''}
{...textFieldProps}
data-testid="AutocompleteInput"
/>
);
}}
open={openOptions || open}
onOpen={() => {
setOpen(true);
}}
onClose={() => {
setOpen(false);
}}
noOptionsText={noOptionsText}
ListboxProps={listBoxProps}
/>
{helperText ? (
<FormHelperText className={styles.HelperText}>{helperText}</FormHelperText>
) : null}
{helpLink ? (
<div
className={styles.HelpLink}
onKeyDown={() => helpLink.handleClick()}
onClick={() => helpLink.handleClick()}
role="button"
data-testid="helpButton"
tabIndex={0}
>
{helpLink.label}
</div>
) : null}
</FormControl>
</div>
);
}
Example #13
Source File: form_factory.tsx From firecms with MIT License | 4 votes |
function FieldInternal<T extends CMSType, M extends { [Key: string]: any }>
({
component,
componentProps: {
name,
property,
includeDescription,
underlyingValueHasChanged,
tableMode,
partOfArray,
autoFocus,
context,
disabled,
shouldAlwaysRerender
},
fieldProps
}:
{
component: ComponentType<FieldProps<T>>,
componentProps: CMSFormFieldProps<M>,
fieldProps: FormikFieldProps<T>
}) {
const customFieldProps: any = property.config?.customProps;
const value = fieldProps.field.value;
const initialValue = fieldProps.meta.initialValue;
const error = getIn(fieldProps.form.errors, name);
const touched = getIn(fieldProps.form.touched, name);
const showError: boolean = error &&
(fieldProps.form.submitCount > 0 || property.validation?.unique) &&
(!Array.isArray(error) || !!error.filter((e: any) => !!e).length);
const isSubmitting = fieldProps.form.isSubmitting;
const [internalValue, setInternalValue] = useState<T | null>(value);
useEffect(
() => {
const handler = setTimeout(() => {
fieldProps.form.setFieldValue(name, internalValue);
}, 50);
return () => {
clearTimeout(handler);
};
},
[internalValue]
);
useEffect(
() => {
if (!isEqual(value, internalValue)) {
setInternalValue(value);
}
},
[value]
);
const cmsFieldProps: FieldProps<T> = {
name,
value: internalValue as T,
initialValue,
setValue: (value: T | null) => {
fieldProps.form.setFieldTouched(name, true, false);
setInternalValue(value);
},
error,
touched,
showError,
isSubmitting,
includeDescription: includeDescription ?? true,
property: property as Property<T>,
disabled: disabled ?? false,
underlyingValueHasChanged: underlyingValueHasChanged ?? false,
tableMode: tableMode ?? false,
partOfArray: partOfArray ?? false,
autoFocus: autoFocus ?? false,
customProps: customFieldProps,
context,
shouldAlwaysRerender: shouldAlwaysRerender ?? true
};
return (
<>
{React.createElement(component, cmsFieldProps)}
{underlyingValueHasChanged && !isSubmitting &&
<FormHelperText>
This value has been updated elsewhere
</FormHelperText>}
</>);
}
Example #14
Source File: DaoSettings.tsx From homebase-app with MIT License | 4 votes |
DaoSettingsForm = withRouter(
({ submitForm, values, setFieldValue, errors, touched }: any) => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("md"));
const {
data: tokenMetadata,
isLoading: loading,
error,
} = useTokenMetadata(
values?.governanceToken?.address,
values?.governanceToken?.tokenId
);
useEffect(() => {
if (tokenMetadata) {
setFieldValue("governanceToken.tokenMetadata", tokenMetadata);
}
if (error) {
setFieldValue("governanceToken.tokenMetadata", undefined);
}
}, [error, setFieldValue, tokenMetadata]);
const { dispatch } = useContext(CreatorContext);
const match = useRouteMatch();
const history = useHistory();
useEffect(() => {
if (values) {
dispatch({
type: ActionTypes.UPDATE_NAVIGATION_BAR,
next: {
handler: () => {
submitForm(values);
},
text: "CONTINUE",
},
back: {
handler: () => history.push(`templates`),
text: "BACK",
},
});
}
}, [dispatch, errors, history, match.path, match.url, submitForm, values]);
return (
<>
<SecondContainer container item direction="row" spacing={2} wrap="wrap">
<Grid item xs={isMobile ? 12 : 9}>
<Typography variant="subtitle1" color="textSecondary">
{" "}
Token Address{" "}
</Typography>
<CustomInputContainer>
<Field
id="outlined-basic"
placeholder="KT1...."
name="governanceToken.address"
component={CustomFormikTextField}
/>
</CustomInputContainer>
{errors.governanceToken?.address &&
touched.governanceToken?.address ? (
<ErrorText>{errors.governanceToken?.address}</ErrorText>
) : null}
</Grid>
<Grid item xs={isMobile ? 12 : 3}>
<Typography variant="subtitle1" color="textSecondary">
{" "}
Token ID{" "}
</Typography>
<CustomInputContainer>
<Field
id="outlined-basic"
placeholder="0"
name="governanceToken.tokenId"
component={CustomFormikTextField}
/>
</CustomInputContainer>
{errors.governanceToken?.tokenId &&
touched.governanceToken?.tokenId ? (
<ErrorText>{errors.governanceToken?.tokenId}</ErrorText>
) : null}
</Grid>
{tokenMetadata && !loading && (
<MetadataContainer item xs={12}>
<Typography variant="subtitle2" color="secondary">
{tokenMetadata.name} ({tokenMetadata.symbol})
</Typography>
</MetadataContainer>
)}
<Grid item xs={isMobile ? 12 : 9}>
<Typography variant="subtitle1" color="textSecondary">
{" "}
DAO Name{" "}
</Typography>
<CustomInputContainer>
<Field
name="name"
inputProps={{ maxLength: 18 }}
type="text"
placeholder="My Group’s Token"
component={CustomFormikTextField}
InputProps={{
endAdornment: (
<InputAdornment position="start">
<Tooltip placement="bottom" title="DAO Name info">
<InfoIconInput color="secondary" />
</Tooltip>
</InputAdornment>
),
}}
></Field>
</CustomInputContainer>
{errors.name && touched.name ? (
<ErrorText>{errors.name}</ErrorText>
) : null}
</Grid>
<Grid item xs={isMobile ? 12 : 3}>
<Typography variant="subtitle1" color="textSecondary">
{" "}
Token Symbol{" "}
</Typography>
<CustomInputContainer>
<Field
name="symbol"
type="text"
inputProps={{
style: { textTransform: "uppercase" },
maxLength: 6,
}}
placeholder="MYTOK"
component={CustomFormikTextField}
InputProps={{
endAdornment: (
<InputAdornment position="start">
<Tooltip placement="bottom" title="Token symbol info">
<InfoIconInput color="secondary" />
</Tooltip>
</InputAdornment>
),
}}
></Field>
</CustomInputContainer>
{errors.symbol && touched.symbol ? (
<ErrorText>{errors.symbol}</ErrorText>
) : null}
</Grid>
</SecondContainer>
<SecondContainer container direction="row" alignItems="center">
<Grid item xs={12}>
<Typography variant="subtitle1" color="textSecondary">
Description
</Typography>
</Grid>
<TextareaContainer item xs={12}>
<Field name="description">
{() => (
<CustomTextarea
maxLength={1500}
aria-label="empty textarea"
placeholder="This is what we’re about..."
value={getIn(values, "description")}
onChange={(newValue: any) => {
setFieldValue("description", newValue.target.value);
}}
/>
)}
</Field>
<Tooltip placement="bottom" title="Description info">
<InfoIcon color="secondary" />
</Tooltip>
</TextareaContainer>
{errors.description && touched.description ? (
<ErrorText>{errors.description}</ErrorText>
) : null}
</SecondContainer>
<SecondContainer item container direction="row" alignItems="center">
<Grid item xs={12}>
<Typography variant="subtitle1" color="textSecondary">
{" "}
Administrator{" "}
</Typography>
</Grid>
<Grid item xs={12}>
<CustomInputContainer>
<Field
name="administrator"
type="text"
placeholder="tz1PXn...."
component={CustomFormikTextField}
InputProps={{
endAdornment: (
<InputAdornment position="start">
<Tooltip placement="bottom" title="DAO Name info">
<InfoIconInput color="secondary" />
</Tooltip>
</InputAdornment>
),
}}
></Field>
</CustomInputContainer>
{errors.administrator && touched.administrator ? (
<ErrorText>{errors.administrator}</ErrorText>
) : null}
</Grid>
</SecondContainer>
<SecondContainer item container direction="row" alignItems="center">
<Grid item xs={12}>
<Typography variant="subtitle1" color="textSecondary">
{" "}
Guardian{" "}
</Typography>
</Grid>
<Grid item xs={12}>
<CustomInputContainer>
<Field
name="guardian"
type="text"
placeholder="tz1PXn...."
component={CustomFormikTextField}
InputProps={{
endAdornment: (
<InputAdornment position="start">
<Tooltip placement="bottom" title="DAO Name info">
<InfoIconInput color="secondary" />
</Tooltip>
</InputAdornment>
),
}}
></Field>
</CustomInputContainer>
{errors.guardian && touched.guardian ? (
<ErrorText>{errors.guardian}</ErrorText>
) : null}
</Grid>
</SecondContainer>
</>
);
}
)
Example #15
Source File: useForm.tsx From SQForm with MIT License | 4 votes |
export function useForm<TValue, TChangeEvent>({
name,
onBlur,
onChange,
}: UseFormParam<TChangeEvent>): UseFormReturn<TValue, TChangeEvent> {
_handleError(name);
const [field, meta, helpers] = useField<TValue>(name);
const errorMessage = _transformErrorMessageToString<TValue>(meta);
const isTouched = getIn(meta, 'touched');
const isDirty = !isEqual(meta.initialValue, meta.value);
const hasValue = _getHasValue(meta);
const isError = !!errorMessage;
const isRequired = errorMessage?.toLowerCase() === 'required';
const getFieldStatus = () => {
if (isRequired && !hasValue && !isDirty && !isTouched) {
return 'REQUIRED';
}
if (isError) {
return 'ERROR';
}
if (hasValue && !isError && isDirty) {
return 'USER_FULFILLED';
}
return 'FULFILLED';
};
const isFieldRequired = getFieldStatus() === 'REQUIRED';
const isFieldError = getFieldStatus() === 'ERROR';
const isFulfilled = getFieldStatus() === 'USER_FULFILLED';
const handleChange: ChangeHandler<TChangeEvent> = React.useCallback(
(event) => {
field.onChange(event);
onChange && onChange(event);
},
[field, onChange]
);
const handleBlur = React.useCallback(
(event) => {
field.onBlur(event);
onBlur && onBlur(event);
},
[field, onBlur]
);
const HelperTextComponent = React.useMemo(() => {
if (isFieldError) {
return (
<>
<WarningIcon color="error" style={SPACE_STYLE} />
{errorMessage}
</>
);
}
if (isFieldRequired) {
return (
<>
<WarningIcon color="disabled" style={SPACE_STYLE} />
Required
</>
);
}
if (isFulfilled) {
return (
<VerifiedIcon
style={{color: 'var(--color-palmLeaf)', ...SPACE_STYLE}}
/>
);
}
return ' '; // return something so UI space always exists
}, [isFieldError, isFieldRequired, isFulfilled, errorMessage]);
return {
formikField: {field, meta, helpers},
fieldState: {
errorMessage,
isTouched,
isError,
isFieldError,
isFieldRequired,
isFulfilled,
},
fieldHelpers: {handleBlur, handleChange, HelperTextComponent},
};
}
Example #16
Source File: SQFormAutocomplete.tsx From SQForm with MIT License | 4 votes |
function SQFormAutocomplete({
children,
isDisabled = false,
displayEmpty = false,
label,
name,
onBlur,
onChange,
onInputChange,
size = 'auto',
lockWidthToField = true,
}: SQFormAutocompleteProps): React.ReactElement {
const classes = useStyles();
const autocompleteClasses = useAutocompleteStyles({lockWidthToField});
const gridContainerRef = React.useRef<HTMLDivElement>(null);
const baseWidth = calculateBaseWidth(gridContainerRef.current);
const left = gridContainerRef.current?.getBoundingClientRect().left;
const {setFieldValue, setTouched, values, touched} = useFormikContext();
const [{value}] = useField(name);
const {
fieldState: {isFieldError, isFieldRequired},
fieldHelpers: {HelperTextComponent},
} = useForm({name});
const initialValue = getInitialValue(children, value, displayEmpty);
const [inputValue, setInputValue] = React.useState('');
const prevValue = usePrevious(value);
React.useEffect(() => {
setInputValue(initialValue?.label || '');
}, [initialValue]);
React.useEffect(() => {
// Form Reset
if (prevValue && inputValue && !value) {
setInputValue(displayEmpty ? EMPTY_OPTION.label : '');
}
}, [value, inputValue, name, prevValue, values, displayEmpty]);
const handleAutocompleteBlur = React.useCallback(
(event) => {
setTouched({...touched, ...{[name]: true}});
onBlur && onBlur(event);
},
[name, onBlur, setTouched, touched]
);
const handleAutocompleteChange = React.useCallback(
(event, value, reason) => {
const selectedValue = getIn(value, 'value');
onChange && onChange(event, selectedValue, reason);
if (reason === 'clear') {
return setFieldValue(name, '');
}
return setFieldValue(name, selectedValue);
},
[name, onChange, setFieldValue]
);
const handleInputChange = React.useCallback(
(event, value) => {
setInputValue(value);
onInputChange && onInputChange(event, value);
},
[onInputChange]
);
const options = children ? [...children] : [];
displayEmpty && options.unshift(EMPTY_OPTION);
return (
<Grid item xs={size} ref={gridContainerRef} className={classes.grid}>
<Autocomplete
id={name}
style={{width: '100%'}}
disableListWrap
disablePortal={!lockWidthToField}
classes={autocompleteClasses}
ListboxComponent={
ListboxVirtualizedComponent as React.ComponentType<
React.HTMLAttributes<HTMLElement>
>
}
// Note: basewidth is not camel cased because React doesn't like it here
ListboxProps={{basewidth: baseWidth, left, lockWidthToField}}
options={options}
onBlur={handleAutocompleteBlur}
onChange={handleAutocompleteChange}
onInputChange={handleInputChange}
inputValue={inputValue}
value={initialValue || null}
disableClearable={isDisabled}
disabled={isDisabled}
getOptionLabel={(option) => option.label || ''}
getOptionDisabled={(option: SQFormOption) =>
option?.isDisabled || false
}
renderInput={(params) => {
return (
<TextField
{...params}
color="primary"
disabled={isDisabled}
error={isFieldError}
fullWidth={true}
InputLabelProps={{
...params.InputLabelProps,
shrink: true,
}}
inputProps={{
...params.inputProps,
disabled: isDisabled,
}}
FormHelperTextProps={{error: isFieldError}}
name={name}
label={label}
helperText={!isDisabled && HelperTextComponent}
required={isFieldRequired}
/>
);
}}
renderOption={(option) => (
<Typography variant="body2" noWrap>
{option.label}
</Typography>
)}
/>
</Grid>
);
}
Example #17
Source File: SQFormAsyncAutocomplete.tsx From SQForm with MIT License | 4 votes |
function SQFormAsyncAutocomplete({
children,
isDisabled = false,
label,
name,
onBlur,
onChange,
onInputChange,
handleAsyncInputChange,
loading = false,
open,
onOpen,
onClose,
size = 'auto',
}: SQFormAsyncAutocompleteProps): React.ReactElement {
const classes = useStyles();
const {setFieldValue, setTouched, values} = useFormikContext();
const [{value}] = useField(name);
const {
fieldState: {isFieldError, isFieldRequired},
fieldHelpers: {HelperTextComponent},
} = useForm({name});
const initialValue = React.useMemo(() => {
const optionInitialValue = children.find((option) => {
if (option.value === value) {
return option;
}
return null;
});
return optionInitialValue;
}, [children, value]);
const [inputValue, setInputValue] = React.useState('');
const prevValue = usePrevious(value);
React.useEffect(() => {
setInputValue(initialValue?.label || '');
}, [initialValue]);
React.useEffect(() => {
// Form Reset
if (prevValue && inputValue && !value) {
setInputValue('');
}
}, [value, inputValue, name, prevValue, values]);
const handleAutocompleteBlur = React.useCallback(
(event) => {
setTouched({[name]: true});
onBlur && onBlur(event);
},
[name, onBlur, setTouched]
);
const handleAutocompleteChange = React.useCallback(
(event, value, reason) => {
const selectedValue = getIn(value, 'value');
onChange && onChange(event, selectedValue, reason);
if (reason === 'clear') {
return setFieldValue(name, '');
}
return setFieldValue(name, selectedValue);
},
[name, onChange, setFieldValue]
);
const handleInputChange = React.useCallback(
(event, value) => {
setInputValue(value);
handleAsyncInputChange(value);
onInputChange && onInputChange(event, value);
},
[handleAsyncInputChange, onInputChange]
);
return (
<Grid item sm={size}>
<Autocomplete
id={name}
style={{width: '100%'}}
disableListWrap
classes={classes}
ListboxComponent={
ListboxVirtualizedComponent as React.ComponentType<
React.HTMLAttributes<HTMLElement>
>
}
options={children}
onBlur={handleAutocompleteBlur}
onChange={handleAutocompleteChange}
onInputChange={handleInputChange}
open={open}
onOpen={onOpen}
onClose={onClose}
inputValue={inputValue}
disabled={isDisabled}
getOptionLabel={(option) => option.label}
getOptionDisabled={(option: SQFormOption) => option.isDisabled || false}
renderInput={(params) => {
return (
<TextField
{...params}
color="primary"
disabled={isDisabled}
error={isFieldError}
fullWidth={true}
InputLabelProps={{
...params.InputLabelProps,
shrink: true,
}}
inputProps={{
...params.inputProps,
disabled: isDisabled,
}}
InputProps={{
...params.InputProps,
endAdornment: (
<>
{loading ? (
<CircularProgress color="inherit" size={20} />
) : null}
{params.InputProps.endAdornment}
</>
),
}}
FormHelperTextProps={{error: isFieldError}}
name={name}
label={label}
helperText={!isDisabled && HelperTextComponent}
required={isFieldRequired}
/>
);
}}
renderOption={(option) => (
<Typography variant="body2" noWrap>
{option.label}
</Typography>
)}
/>
</Grid>
);
}