formik#FastField TypeScript Examples

The following examples show how to use formik#FastField. 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: ArrayOneOfField.tsx    From firecms with MIT License 4 votes vote down vote up
function ArrayOneOfEntry({
                             name,
                             index,
                             value,
                             typeField,
                             valueField,
                             properties,
                             autoFocus,
                             context
                         }: ArrayOneOfEntryProps) {


    const type = value && value[typeField];
    const [typeInternal, setTypeInternal] = useState<string | undefined>(type ?? undefined);

    useEffect(() => {
        if (type !== typeInternal) {
            setTypeInternal(type);
        }
    }, [type]);

    const property = typeInternal ? properties[typeInternal] : undefined;

    const enumValues: EnumValues = Object.entries(properties).map(([key, property]) => ({ [key]: property.title ?? key })).reduce((a, b) => ({ ...a, ...b }));

    const typeFieldName = `${name}[${typeField}]`;
    const valueFieldName = `${name}[${valueField}]`;

    return (
        <Paper sx={(theme) => ({
            elevation: 0,
            padding: theme.spacing(2),
            [theme.breakpoints.up("md")]: {
                padding: theme.spacing(2)
            }
        })} elevation={0}>

            <FastField
                required={true}
                name={typeFieldName}
            >
                {(fieldProps: FormikFieldProps) =>
                    (
                        <FormControl fullWidth>
                            <InputLabel
                                id={`${name}_${index}_select_label`}>
                                <span>Type</span>
                            </InputLabel>
                            <Select
                                fullWidth
                                sx={{ marginBottom: 2 }}
                                labelId={`${name}_${index}_select_label`}
                                value={fieldProps.field.value !== undefined && fieldProps.field.value !== null ? fieldProps.field.value : ""}
                                onChange={(evt: any) => {
                                    const eventValue = evt.target.value;
                                    fieldProps.form.setFieldTouched(typeFieldName);
                                    setTypeInternal(eventValue);
                                    fieldProps.form.setFieldValue(typeFieldName, eventValue);
                                    fieldProps.form.setFieldValue(valueFieldName, null);
                                }}
                                renderValue={(enumKey: any) =>
                                    <EnumValuesChip
                                        enumKey={enumKey}
                                        enumValues={enumValues}
                                        small={true}/>
                                }>
                                {enumToObjectEntries(enumValues)
                                    .map(([enumKey, labelOrConfig]) => {
                                        return (
                                            <MenuItem
                                                key={`select_${name}_${index}_${enumKey}`}
                                                value={enumKey}>
                                                <EnumValuesChip
                                                    enumKey={enumKey}
                                                    enumValues={enumValues}
                                                    small={true}/>
                                            </MenuItem>
                                        );
                                    })}
                            </Select>
                        </FormControl>
                    )
                }
            </FastField>

            {property && (
                <FormControl fullWidth
                             key={`form_control_${name}_${typeInternal}`}>
                    {buildPropertyField({
                        name: valueFieldName,
                        property: property,
                        context: context,
                        autoFocus: autoFocus
                    })}
                </FormControl>
            )}

        </Paper>
    );
}
Example #2
Source File: form_factory.tsx    From firecms with MIT License 4 votes vote down vote up
/**
 * This factory method renders a form field creating the corresponding configuration
 * from a property. For example if bound to a string property, it will generate
 * a text field.
 *
 * You can use it when you are creating a custom field, and need to
 * render additional fields mapped to properties. This is useful if you
 * need to build a complex property mapping, like an array where each index
 * is a different property.
 *
 * Please note that if you build a custom field in a component, the
 * **validation** passed in the property will have no effect. You need to set
 * the validation in the `EntitySchema` definition.
 *
 * @param name You can use nested names such as `address.street` or `friends[2]`
 * @param property
 * @param context
 * @param includeDescription
 * @param underlyingValueHasChanged
 * @param disabled
 * @param tableMode
 * @param partOfArray
 * @param autoFocus
 * @param shouldAlwaysRerender
 * @category Form custom fields
 */
export function buildPropertyField<T extends CMSType = any, M = any>
({
     name,
     property,
     context,
     includeDescription,
     underlyingValueHasChanged,
     disabled,
     tableMode,
     partOfArray,
     autoFocus,
     shouldAlwaysRerender
 }: CMSFormFieldProps<M>): ReactElement<CMSFormFieldProps<M>> {

    let component: ComponentType<FieldProps<T, any, M>> | undefined;
    if (isReadOnly(property)) {
        component = ReadOnlyField;
    } else if (property.config?.Field) {
        component = property.config?.Field as ComponentType<FieldProps<T>>;
    } else if (property.dataType === "array") {
        const of = (property as ArrayProperty).of;
        if (of) {
            if ((of.dataType === "string" || of.dataType === "number") && of.config?.enumValues) {
                component = ArrayEnumSelect as ComponentType<FieldProps<T>>;
            } else if (of.dataType === "string" && of.config?.storageMeta) {
                component = StorageUploadField as ComponentType<FieldProps<T>>;
            } else if (of.dataType === "reference") {
                component = ArrayOfReferencesField as ComponentType<FieldProps<T>>;
            } else {
                component = ArrayDefaultField as ComponentType<FieldProps<T>>;
            }
        }
        const oneOf = (property as ArrayProperty).oneOf;
        if (oneOf) {
            component = ArrayOneOfField as ComponentType<FieldProps<T>>;
        }
        if (!of && !oneOf) {
            throw Error(`You need to specify an 'of' or 'oneOf' prop (or specify a custom field) in your array property ${name}`);
        }
    } else if (property.dataType === "map") {
        component = MapField as ComponentType<FieldProps<T>>;
    } else if (property.dataType === "reference") {
        if (!property.path)
            component = ReadOnlyField as ComponentType<FieldProps<T>>;
        else {
            component = ReferenceField as ComponentType<FieldProps<T>>;
        }
    } else if (property.dataType === "timestamp") {
        component = DateTimeField as ComponentType<FieldProps<T>>;
    } else if (property.dataType === "boolean") {
        component = SwitchField as ComponentType<FieldProps<T>>;
    } else if (property.dataType === "number") {
        if (property.config?.enumValues) {
            component = Select as ComponentType<FieldProps<T>>;
        } else {
            component = TextField as ComponentType<FieldProps<T>>;
        }
    } else if (property.dataType === "string") {
        if (property.config?.storageMeta) {
            component = StorageUploadField as ComponentType<FieldProps<T>>;
        } else if (property.config?.markdown) {
            component = MarkdownField as ComponentType<FieldProps<T>>;
        } else if (property.config?.enumValues) {
            component = Select as ComponentType<FieldProps<T>>;
        } else {
            component = TextField as ComponentType<FieldProps<T>>;
        }
    }

    if (component) {

        const componentProps = {
            name,
            property,
            includeDescription,
            underlyingValueHasChanged,
            context,
            disabled,
            tableMode,
            partOfArray,
            autoFocus,
            shouldAlwaysRerender
        };

        // we use the standard Field for user defined fields, since it rebuilds
        // when there are changes in other values, in contrast to FastField
        const FieldComponent = shouldAlwaysRerender || property.config?.Field ? Field : FastField;

        return (
            <FieldComponent
                required={property.validation?.required}
                name={`${name}`}
            >
                {(fieldProps: FormikFieldProps<T>) => {
                    return <FieldInternal
                        component={component as ComponentType<FieldProps<T>>}
                        componentProps={componentProps}
                        fieldProps={fieldProps}/>;
                }}
            </FieldComponent>
        );

    }

    return (
        <div>{`Currently the field ${property.dataType} is not supported`}</div>
    );
}