Skip to content

How It Works

weili edited this page Jan 13, 2023 · 8 revisions

Note: This page explains the inner workings of the library and is meant for engineers who want to contribute to the library. If you will like to find out how to use the library, please visit the storybook site.

Render

In a nutshell, the Frontend Engine renders the form according to the JSON schema passed through the data prop. It will iterate through the fields key to render each field / element in the form.

Frontend Engine render flow

The bulk of the rendering logic is in the Wrapper component. The child is wrapped within a ConditionalRender which handles the conditional rendering logic.

Next the wrapper identifies if the child is a field or an element:

  • Fields are components that add values to the form
    • i.e. they accept values that will get submitted.
    • e.g. textarea, select and radio-button.
    • These fields are wrapped within react-hook-form's Controller field to integrate the field lifecycle events into the form.
  • Elements, on the other hand, do not have values and are typically used for layouts and messages.
    • e.g. div, h1 and alert.
    • Hence they are rendered as it is.
    • Note: Wrapper is also considered an element

If the child is a Wrapper, it will go through the rendering flow again by iterating through its children.

Validation

Frontend Engine relies on Yup to generates the validation schema for react-hook-form to use. For Frontend Engine's JSON schema, each field comes with the validation config which is converted to the Yup schema.

Frontend Engine validation

YupProvider / useValidationSchema

The YupProvider is what holds and manipulates the formValidationConfig. The formValidationConfig is a key-value object that contains the Yup type and validation rules of each field.

// sample formValidationConfig
// these are added through setFieldValidationConfig()
{
	myField1: {
		schema: Yup.string(),
		validationRules: [ { required: true }, { max: 5, errorMessage: "Max. 5 characters" } ]
	},
	myField2: {
		schema: Yup.number(),
		validationRules: [ { required: true }, { min: 5, errorMessage: "Min. value of 5" } ]
	}
}

The config and methods are exposed through the useValidationSchema hook for each field to use. Every time a field is added, it will add to the validation config.

setFieldValidationConfig("myField1", Yup.string(), [{ required: true }, { max: 5, errorMessage: "Max. 5 characters" }]);

buildSchema

Every time the formValidationConfig changes, useValidationSchema will refresh the Yup validation schema by calling buildSchema(), which will loop through the validation config to generate the Yup validation schema accordingly. Thereafter, the schema is passed to react-hook-form to be used for validation.

Conditional Render

Conditional rendering is managed by the ConditionalRenderer component. Each component in Frontend Engine is wrapped within one. The way the ConditionalRenderer handles conditional rendering is similar to how validation is handled:

  1. Format the showIf key. (which is structured the same way as the validation)
  2. Convert it to a Yup schema via buildSchema()
  3. Runs the Yup schema through validation to determine whether to render the component or not.

Image Upload

The image upload component is able to handle inputs, annotation and upload to an endpoint specified. The underlying components are separated in a few groups:

Image upload components

ImageProvider

Shares images and error states and its respective methods between all the children.

ImageManager

A render-less component to manage all the images, its purpose is to ensures the images progress through the various statuses up till uploaded.

ImageInput

Offers drag & drop insertion of images as well as allow user to bring up the file dialog to select images to add. It also renders all the added images and their details.

ImageReview

It is the modal that will appear after adding an image (if editImage=true), this component handles everything the modal offers like adding / editing / deleting of images.

Image Statuses

Image statuses

The diagram above illustrates how the various image statuses will transition.

  • Most of the handling of image statuses are carried out in the ImageManager component
  • Images can be added via input or injected through schema
  • Depending on the compress key, images will be resampled/converted or compressed
  • Depending on the editImage key, images can be recompressed

Clone this wiki locally