Preface
The GUI config panel can be used in any low-code platform, such as prototyping tools (Figma), website building platforms (Webflow, Framer), BI reports (Power BI, Looker Studio), 3D model building (Spline, Womp), animation editor (Rive), etc., these are some very famous online tools.
Acrodata GUI is a lightweight GUI library for low-code platforms, now it's open sourced. 🎉
GitHub: https://github.com/acrodata/gui
Playground: https://acrodata.github.io/gui/playground
What is GUI
In front-end, we rarely use the description like GUI, so many people mistakenly think that GUI = UI library
.
So what exactly is a GUI? For ease of understanding, we can refer to the more famous GUI project dat.gui. For those who have done 3D visualization or ThreeJS must be very familiar with this library. The main purpose of dat.gui
is to convert configuration items into graphical controls to debug parameters.
In addition to dat.gui, there are several other GUI projects that are also doing well, tweakpane, lil-gui, leva.
Configuration panel in low-code platform
For those who have used low-code platforms or developed similar products, the layout of low-code platforms has become commonplace. On the right side of the layout is usually a configuration panel. Of course, the same goes for a lot of the software we use. Just post a few screenshots of some tools.
First of all, not every low-code product requires GUI generation configuration. For example, in the Webflow (first screenshot), the configuration items of all its components are the same (all are CSS visual configurations). In this case, it will be simpler to develop a common component.
However, for products like Looker Studio (third screenshot), each chart component has a different configuration and it allows users to customize chart component, so this type of product is in great need of a flexible and easy-to-use GUI library.
On the homepage of the Acrodata GUI documentation site, I used the GUI to create a complex CSS gradient generator. It is very similar to the configuration panel in the low-code platform. You are welcome to try it out.
👉 View CSS gradient generator source code
How to design a lightweight GUI?
Due to the complexity of low-code platforms, GUI libraries must be designed to be able to combine arbitrary data structures while being simple and easy to use.
JSON-based configuration items
To support custom components, GUI libraries are more suitable for configuration using JSON data. This is very different from the use of the GUI libraries mentioned above. Let's take dat.gui
and Acrodata GUI as examples.
Assume that the configuration items of a certain component are as follows:
const options = {
content: 'Hello world',
opacity: 0.3,
visible: false,
}
The usage of dat.gui
is as follows:
const gui = new dat.GUI();
gui.add(options, 'content');
gui.add(options, 'opacity', 0, 1).step(0.1);
gui.add(options, 'visible');
Although the usage of dat.gui
is very simple, this functional declaration method is not suitable for dynamic components and is not conducive to data storage.
The usage in Acrodata GUI is like this:
<gui-form [config]="config" />
const config = {
content: {
type: 'text',
name: 'content',
default: 'Hello world'
},
opacity: {
type: 'slider',
name: 'opacity',
min: 0,
max: 1,
step: 0.1,
default: 0.3
},
visible: {
type: 'switch',
name: 'visible',
default: false
},
}
The structure of the above GUI configuration items is the same as that of the component. You only need to convert the value of each field in options
into the JSON declaration of the UI control.
👉 View more basic control examples
Nested data structure
If you want to ensure that the GUI can generate any data structure, you need to design the definition format of JSON configuration items for five basic data (string
, number
, boolean
, object
, array
). The above example has shown how three basic data types are defined.
The definition of object
in Acrodata GUI is as follows:
{
"size": {
"type": "group",
"name": "Size",
"children": {
"width": {
"name": "Width",
"type": "number",
"default": 1920,
"suffix": "px"
},
"height": {
"name": "Height",
"type": "number",
"default": 1080,
"suffix": "px"
}
}
}
}
The last array type is the most complex. Commonly used arrays include basic data arrays and object arrays, and each array also supports dynamic deletion of array items.
The following is how a dynamically deletable object array is defined:
{
"series": {
"type": "tabs",
"name": "Series",
"default": [
{ "id": 1, "name": "bar" },
{ "id": 2, "name": "foo" }
],
"template": {
"name": "No.<%= i + 1 %>",
"children": {
"id": {
"type": "number",
"name": "ID"
},
"name": {
"type": "text",
"name": "Name"
}
}
}
}
}
If the array items of the object array are not the same, they must be defined with the tab
type:
{
"misc": {
"type": "tabs",
"name": "Misc",
"children": [
{
"type": "tab",
"name": "Full Name",
"children": {
"firstName": {
"type": "text",
"name": "First Name",
"default": "James"
},
"lastName": {
"type": "text",
"name": "Last Name",
"default": "Bob"
}
}
},
{
"type": "tab",
"name": "Contact",
"children": {
"phone": {
"type": "text",
"name": "Phone",
"default": "5550100"
}
}
}
]
}
}
👉 View more group control examples
With the above five basic controls, any data structure can be generated through nested combination.
Limitations of JSON Schema
Why not use JSON Schema? Many people may think that using JSON Schema to define JSON data will be more standardized and more general. This idea makes sense, but JSON Schema also has certain limitations.
First of all, JSON Schema can only define the data type of the field, but cannot define the UI type of the field, so some dynamic form solutions that use JSON Schema will also add UI Schema, such as react-jsonschema-form.
In addition, the format of JSON Schema is relatively complex, and the mapping relationship between component configuration items and JSON Schema is very unintuitive.
Build a GUI based on reactive forms
Acrodata GUI is built based on Angular's reactive form, with only about 200 lines of core code (View source code ).
In order to facilitate traversing data in the template, you need to convert the GUI config
object into an array, and use the registerControl
of the reactive form to register all form controls in the instance of FormGroup
. Then use the reactive form directives formGroupName
, formControlName
, formArrayName
in the template to bind controls of different type
.
Acrodata GUI uses Angular Material as the basic component library. All styles and components are imported in modules, so redundant code will not be generated. Other component libraries can also be used.
Start using GUI components
<gui-form [config]="config" [model]="model" [form]="form" />
config
represents the JSON configuration items of the GUI. The configuration items of different types of controls are slightly different, see the documentation for details. In addition to using default
to define the default value of the control, you can also use model
(form value, equivalent to the component's configuration item options) to define or update the default value of the form, thanks to Angular's reactive formpatchValue
method.
If you need to monitor the state or value changes of the form, you can use the form
parameter, which can track all state changes of the form.
form = new FormGroup({});
this.form.valueChanges.subscribe(v =>{...});
this.form.get('opacity').valueChanges.subscribe(v =>{...});
Summarize
The GUI shown above is very powerful, but GUI can't completely replace the dynamic forms and not all configuration items are suitable for using GUI. Because the GUI has limited control types and does not have complex logic, maybe you should make a choice to use or not in a low-code platform.
If you like Acrodata GUI or have better ideas, please feel free to communicate with me!
Top comments (0)