0.0.8 • Published 2 years ago

@psytech/react-render-engine v0.0.8

Weekly downloads
-
License
MIT
Repository
github
Last release
2 years ago

@psytech/react-render-engine

Server-Driven UI (SDUI) is a technique which allows to render dynamic user interfaces for the web & native apps using structured data received from the server which describes different parts of the user interface & the data contained inside it. In this case, we call this structured data, a "template".

Here's a good explanation of SDUI: https://www.judo.app/blog/server-driven-ui/

This package allows the rendering of templates using React with structured template data received from the server.

Here are some of the examples of cards that have been rendered using this package which you can access using this demo link, while the structured template data for rendering these cards can be accessed using this link: Template examples

Table of contents

Structure

Each template consists of the following key-value pairs:

  1. id: A unique identification string for recognising the template.

  2. topElementId: A unique identification string for recognising the topmost node element whose element data is stored in the element object.

  3. element: An object storing the template elements in the form of key-value pair, template_element_id: template_element_object.

  4. text: An object containing the textual style objects in the form of key-value pair, text_style_id: text_style_object, where each text_style_object stores the textual styles (e.g. font-weight, font-style, text-decoration) which will be used for styling the individual layout elements.

  5. design: An object containing non-textual style objects in the form of key-value pair, design_style_id: design_style_object, where each design_style_object stores the non-textual styles (e.g. height, width, background, color) which will be used by individual layout elements.

Each template will have the following form:

{
	id: <STRING>"UID",
	topElementId: <STRING>"UID",
	element: <OBJECT>{...},
	design: <OBJECT>{...},
	text: <OBJECT>{...}
}

An example of the design style object is:

{
	background: "#fc6a03"
	color: "#fff"
	height: "fit-content"
	id: "3d87f501-3941-474e-8ce2-5489faf99ba2"
	margin:	"0px"
	padding: "5px"
	width: "fit-content"
}

An example of the text style object is:

{
  "id": "d0f71ec4-095b-485a-b145-ac242defa74b",
  "fontFamily": "'Merriweather', serif",
  "fontWeight": "400",
  "fontStyle": "normal",
  "textAlign": "left",
  "textDecoration": "none"
}

NOTE: The obvious question here would be, why aren't we storing all the styles in a single style object instead of separating the styles for a single layout element into text & design properties, despite the fact that during the execution, these styles are eventually merged into a single object that is being passed to the style prop of the respective components?

The answer lies with the process of automating user interface styles, where any user interface can be generated by a combination of textual & non-textual properties which can be stored separately. Here's an example of the three cards with varying text & design properties from the demo link:

Combination of design x text styles

Each template element consists of the following the following key-value pairs or properties:

Structural properties

  1. id: It describes a unique identification string to recognise the layout element.

  2. type: It describes the type of layout element. For now, we only have three layout element types: container, text & image & this can be used to render any almost any static content.

    The reason this property has been used is that, in the end, each layout element has to be rendered or expressed in form of HTML tags (or JSX in case of react) & different tags have different relevant attributes. e.g. src attribute is relevant to an image tag, but it is not relevant to a div tag, similarly, href attribute is relevant to an anchor tag, but it is not relevant to an img tag.

  3. parent: It describes the unique identification string of the parent layout element. It can have two possible values, null or string of a valid parent node or element. This is required because every HTML document has a tree structure, where there’s a parent tag & each parent tag can have 0 to N child elements, but each HTML tag (except for <html>) only has one parent tag.

  4. children: It is a array of strings that describes the unique identification string of the child elements of any given layout element. If it is an empty array, then it means that a layout element has no child elements, or simply, “It is an empty tag”, which is the case with <img> tag.

Non-structural properties:

  1. text: It describes a unique identification string for the text style objects that contains textual styling properties such as font-size, font-weight, font-style, text-decoration etc.

    Using this string, the rendering script searches for the text style object present in the post data & once the required text style is found using the provided identification string, then it is added to an object which is assigned to a layout element’s style attributes.

  2. design: It describes a unique identification string for design style objects that contains non-textual styling properties such as color, margin, padding, border, etc. The above process for adding text style objects is also used for adding design style objects to a card’s elements.

  3. properties: It is a array of strings that describes the classes &/or the attributes of a layout element. Since both attributes & classes are described in the same way, the rendering script differentiates the class name & the attribute name-value pair is quite simple: the attribute name-value pairs are expressed as a string in the form attrName=attrValue, whereas class names are just plain text e.g. p1, h2.

So, each template element will have the following form:

{
	type: <STRING>"text"/<STRING>"container"/<STRING>"image"
	id: <STRING>"element_id",
	parent: <STRING>"parent_id"/null,
	children: <ARRAY>["child_id_1", ... , "child_id_n"],
	text: <STRING>"text_style_id",
	design: <STRING>"design_style_id",
	properties: <STRING>["class","attrName=attrVal"]
}

Styles

The package also comes with some styles such as:

  • m-card: To be used with a container with a height of 58vh & aspect ratio of 0.75.
  • m-rh-{5-100}: Defines relative height with respect to card with +5% increment.
  • m-rw-{5-100}: Defines relative width with respect to card with +5% increment.

Example

To underst& how this package works, let's look at this card structure & how it can be rendered using this package: Card DOM structure

The above card structure consists of 4 template elements & for simplicity we're not going to use any custom design & text style properties, rather we're using Bootstrap 5 classes:

A container template element containing other template elements of the card:

{
	id: "1",
	type: "container"
	design: "",
	text: "",
	parent: null,
	children: ["2","3","4"],
	properties: ["m-card","d-flex","flex-column","border"]
}

An image element contained in the above container element:

{
	id: "2",
	type: "image"
	design: "",
	text: "",
	parent: "1",
	children: [],
	properties: ["m-rh-40","m-rw-100","src=https://sm.mashable.com/mashable_sea/photo/default/man-fakes-death-cat-q6u_2z9w.png"]
}

An text element for heading contained in the above container element:

{
	id: "3",
	type: "text"
	design: "",
	text: "",
	parent: "1",
	children: ["Lorem ipsum dolor sit amet, consectetur"],
	properties: ["m-rh-90","h3"]
}

An text element for paragraph contained in the above container element:

{
	id: "4",
	type: "text"
	design: "",
	text: "",
	parent: "1",
	children: ["Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam mollis, mi sit amet lobortis iaculis, velit leo ultrices ipsum, vitae lobortis dui nibh vitae lacus. In commodo lacus a magna dapibus dignissim."],
	properties: ["m-rh-90","small"]
}

The above-mentioned layout elements will can be used to create template which will be rendered in the above form:

{
	id: 0,
	topElementId: 1,
	design: {},
	text: {},
	element: {
		1: {
			id: "1",
			type: "container"
			design: "",
			text: "",
			parent: null,
			children: ["2","3","4"],
			properties: ["m-card","d-flex","flex-column","border"]
		},
		2: {
			id: "2",
			type: "image"
			design: "",
			text: "",
			parent: "1",
			children: [],
			properties: ["m-rh-40","m-rw-100","src=https://sm.mashable.com/mashable_sea/photo/default/man-fakes-death-cat-q6u_2z9w.png"]
		},
		3: {
			id: "3",
			type: "text"
			design: "",
			text: "",
			parent: "1",
			children: ["Lorem ipsum dolor sit amet, consectetur"],
			properties: ["m-rh-90","h3"]
		},
		4: {
  			id: "4",
			type: "text"
  			design: "",
  			text: "",
			parent: "1",
			children: ["Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam mollis, mi sit amet lobortis iaculis, velit leo ultrices ipsum, vitae lobortis dui nibh vitae lacus. In commodo lacus a magna dapibus dignissim."],
			properties: ["m-rh-90","small"]
  		}
	}
}

Usage

The components can be imported and used using:

import {Container, Image, Text} from "@psytech/react-render-engine";
<Container id={id} template={template} inputStyle={inputStyle} />
<Image id={id} template={template} inputStyle={inputStyle} />
<Text id={id} template={template} inputStyle={inputStyle} />

Where id is the identification string of the template layout element which needs to be rendered, template is the structured template data which will be used to render the user interface & inputStyle is a style object which will be passed to all the child elements from a given node.

License

MIT

Credits

The template element structure was inspired by Notion's data model. Built from 🇮🇳, for the 🌐, by psytech.ai. For questions or suggestions drop us a mail at asxyzp-@-psytech-dot-ai.