Mason is a utility built for dynamically rendering UI components, currently for React environment. All it needs to render a complete UI is a JSON describing the type, id and various other parameters like validation clauses, display clauses and event handling by using a configurative DSL.
It also needs a map of component type vs React component factories to render the corresponding components mentioned in the config.
The root node has a little different structure than rest of the nodes. It has two properties as page and config which basically represents the page or route of your web app you're trying to configure the UI for. That said, mason is not limited to page levels only. You can use it to created nested UI as well.
Note: The config property can be an array of nodes as well striaght-away if you don't want to wrap them in an uber level layout element.
id field represents the element id used to uniquely identify the current state and updations for a given element. Make sure to keep it unique since this drives any updations during prop change of a given component
type field will help render the corresponding component during the render phase. It'll get matched against the components mapping that's passed while creating the renderer during usage.
meta field can be used to pass any properties to an UI Component that'll be added as inline props to the component being rendered. You can pass component props or normal HTML element props in it.
Note: Setting up value property in meta is helpful when you want to make your component controllable to avoid React warnings
show property will completely unmount or not render the component in the first place if it evaluated to falsy. It can accept either a boolean or a boolean confguration as
ComparisonOperators and CompoundOperators are discussed in detail further.
style property simply represents inline styles object passed in the Component.
data property will work as onMount fetching of data. You can specify a remote data source to fetch data asynchronously or set it statically.
AJAX_CALL: The most common scenario is of loading data on mount of a given component. type attribute set to AJAX_CALL is meant to handle the same. On successful ajax call, it'll set the datasource prop on the component. Also, when the Ajax call starts, a loading prop is set to true on the component and set as false on promise settling (either resolved or caught).
In the meta config, you can pass things like the endpoint and dynamic query params can be passed as the key value pairs to it.
queryParams property can incorporate query params value to be set from another component value by enclosing the desired componentId or fieldId in special syntax as <%fieldId%>. It'll dynamically take the current value of that component and interpolate it here to make the Ajax Call.
credentials property can be set to control sending same or cross origin cookies
fieldId property can be used to tell which component datasource prop you want to set.
dataProcessor: It might be the case that you want to massage or prune the ajax data before applying it to your component. So, you can tailor the data received as per your component needs by passing a function name here that can be referred from the paramters passed by the caller of the mason renderer as:
It's like a resolver function that'll be called before applying the datasource prop to the component.
fieldIds is an object that contains key value pairs of fieldIds and their corresponding dataProcessors. It's useful in the cases where in the root level you wanna make an ajax call and set the children's data based on extracting properties from it.
SET_DATASOURCE: To statically set the datasource of the current component or some other component by specifying the optional fieldId.
The Custom function needs to be passed in the resolvers map while creating the renderer. It'll be called with one parameter as ({ event, value, id }) from which the values can be destructured during invocation.
events property can either accept a map of event name vs their handlers configuration. Each event could have multiple handlers, hence both the array config and object config is supported. Below is the TypeScript typing for the same.
Here, the onChange event of the component will execute two event handlers viz set value of itself (required for controlled components - same as setState the value), and the other one makes an ajax call to a remote api to fetch data of a listing component based on the query text entered in the current/self component.
Note how the query param is able to take <%SELF%> as it's value. It's a special value to get the current value of the current component in consideration. You could pass the id of the self component here as well, but it'll give a stale value since this is the event handler which will change it in the end.
The when clause is a conditional clause which is discussed in detail further.
Next, the onFocus event is executing a single handler to set the datasource property of the given fieldId. No need to pass an array form here.
And, the onClick event is useful in case of a button component wherein you want to execute a custom event handler by matching it's name against what was passed in the dataProcessors property while creating the Renderer.
validations can be used to configure the form validations on a given component. It's very useful in case of rendering forms. Here's a sample configuration for a simple Login Form.
The validations property expects an array of validation configuration to be supplied. Each configuration has a type field which can take either of the following values.
REQUIRED : It'll guard against any value which is a blank string '', undefined or null (and not blank array or objects).
{
"type": "REQUIRED"
}
REGEX : You can specify a Regular Expression for pattern matching the current value of the component against it.
The corresponding validator function has to be specified in the caller environment by passing a validators object containing these custom validator functions as
A validator function takes value as input and returns either a string in case of an invalid value or undefined otherwise. undefined means there was no error and the value was valid.
disabled clause can be use to pass disabled property to the component. It can either take a boolean straight-forwardly or a Conditional config which has the following structure.
ATOMIC: It's like a one level condition. A single expression like x === true
COMPOUND: Compound condition can have multiple expressions joined via Compound operators like && or ||
The operators could be either compound operators as mentioned above or comparison operators like =, !=, <, <=, >, >=
Contributing
Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.
Fork the Project
Create your Feature Branch (git checkout -b feature/AmazingFeature)
Commit your Changes (git commit -m 'Add some AmazingFeature)
Push to the Branch (git push origin feature/AmazingFeature)
Open a Pull Request
License
Distributed under the MIT License. See LICENSE for more information.