Adaptive Framework 0.9.0

Adaptive Layouts

An Adaptive Layout uses primary input sources, namely:

  • Data and its Metadata
  • Layout Instructions
  • Metadata Layout Components
  • Registered Layout Components

An Adaptive Layout uses those inputs and produces a composition of Adaptive Layout Components. Not all inputs are required, and the degree to which the inputs are used depends on the use case, described later in this document. Adaptive Layouts understand how to take data and map, or translate them, into meaningful component parameters. Adaptive Layouts also understand how to take changes from the components and store them back into the corresponding object adaptor. Some layouts are built into the core library and are used by default when no other layout is applicable. Some layouts can be created, stored and retrieved to augment the core with additional, registered layouts.

Adaptive Layout Components

These are the building blocks for creating user interfaces. They are simple units for building up more complex UI patterns, while maintaining some degree of generality, left to the implementation details. This slight abstraction allows for the Layout Component to be portable between UI implementation frameworks. For example, a Text Field Layout Component may suggest that it has a label, a description and a value, but it doesn't specify how the inputs are arranged out and rendered. It contains no direct influence over, say, the font style or spacing, or whether the field has an outline or not. The implementation may even have more complex features than the generic Layout Component definition requires.

Layout Components are also “dumb”, so to speak. They are unaware of where data comes from or where it needs to be stored. So, to produce something meaningful, a composite collection of components need to work together and a layer placed on top to handle the data synchronization. This is where Layouts and Metadata Components come in.

The following table is a complete list of Layout Components:

Layout ComponentDescription
AutocompleteComponent to display a list of options that may be selected or can be autocompleted by typing.
BoxA component that renders a flexible Box of content.
BreadcrumbA component that renders a Breadcrumb path with links
ButtonComponent to display a Button.
CalloutA layout container that displays content inside a popup.
ChartComponent to display data in a Chart.
CheckboxA component that displays a checkbox.
ChoiceGroupA component to display a selectable choice of options.
CodeEditorA component that renders a rich text editor.
CollapsibleA layout container that displays content that can be hidden by a collapsible control.
DatePickerA component that allows you to select a date from a calendar.
DateTimePickerA component that allows you to select a date and time.
DialogA layout container that displays content inside a popup, with a confirmation response.
DiffEditorA component that compares two objects.
DividerA component that displays a Divider line to separate content.
DropdownA component that displays a set of options that can be selected from a dropdown.
DropdownEditorA component that manages a list of options in a Dropdown picker.
EditableCalloutA component that calls out with an editable multiline text area.
EditableLabelA component that renders an label, which can be edited when clicked.
HiddenA component that hides content under screen breakpoint conditions.
IconA component that displays an icon.
ImageA component that displays an image.
LinkA component that renders a url link.
ListA layout container that renders a list of components.
ListEditorA component that allows the user to manage a list of text items.
MenuA component that renders a Menu to be displayed.
MessageA component that renders a message to be displayed.
ModalA layout container that displays content inside a popup.
NativeA component that displays a native HTML element.
NavA navigational component that displays a list of links.
PaperA component that allows contents to be displayed on a Paper like surface.
PickerA component that allows one or more items to be picked from a list.
ResponsiveA layout container that renders content in a grid format, with breakpoints defined for a variety of screen sizes.
SkeletonA component that displays a skeleton, or shape, of a component that may shimmer to indicate that an actual component is waiting to be loaded.
SliderA component that displays numeric values in a slider control.
SnackbarA component that renders a Snackbar to be displayed.
SpinButtonA component that renders a numeric field that an be incremented or decremented.
SpinnerA component that displays a spinner progress indicator.
StepperA component that displays a Stepper indicating a list of steps and the current one you are on.
TableA component that displays data in a table format.
TabsA layout container that renders a series of tabs.
TextFieldA component that renders a text field with a label and description.
TimeDurationA component that renders a time duration.
TimePickerA component that allows a time to be chosen.
TimezonePickerA component that allows a timezone to be chosen.
ToggleA component that renders a boolean value as a toggleable switch.
ToggleButtonsA component to display a selectable choice of options, presented as buttons that can be toggled on or off.
ToolbarA container component that arranges a series of buttons or other minor content in a horizontal bar.
TooltipA component that surrounds content with a tooltip.
TreeA component that renders data in a Tree structure.
TypographyA component that renders a text label.

Generating Adaptive Layouts

There are a variety of methods for building Adaptive Layouts. Some require very little effort, while others require varying degrees of programming. This range of flexibility resembles the patterns of Declarative vs Imperative design. We will visit each method of creating layouts, beginning with the most declarative way and move towards more imperative methods.

Method 1

Method 1

By simply defining objects and their metadata - objectType and propertyType definitions - we have already given the Adaptive Layout processor much of what it needs to know to leverage built-in components and parameter mappings to generate some simple layouts. For example, suppose we have an object containing:

obj = {
    “givenName”: “Robert”,
    “surname”: “Smith”,
    “registered”: true,
}

And supposed we also define an Object Type to handle those properties:

objectType = {
    “propertyTypes”: {
        “givenName”: {
            “dataType”: “string”,
            “label”: “Given Name”,
            “description”: “Your first name”
        },
        “surname”: {
            “dataType”: “string”,
            “label”: “Surname”,
            "description": “Your last name”
        },
	      “registered”: {
            “dataType”: “boolean”
        }
    }
}

This may not seem like much, but already, we have enough to render the object with some appropriate default components. The properties givenName and surname would use TextField components, while registered would use a Checkbox component. Using metadata this way allows you to use declarative efforts to create your layouts. By changing the metadata and adding in constraints and dataTypeParameters, you can influence the way a layout is created. In this method, we are not explicitly defining any real Layout designs.

Results

When we are finished, we may see something like:

Method 1 Results

Pros

Layouts are implicitly generated simply by declaring metadata. This eliminates code and boilerplates, necessary for influencing the final output. Great for simple designs, or for end-users with little to no time or programming experience.

Cons

You are limited to what can be added to metadata, and therefore layouts auto-generated in this way may seem cookie-cutter like in their final output.

Method 2

Method 2

This method piggy-backs the first Method, but introduces the ability to declare some Layout Parameters. These parameters are instructions that the Adaptive Layout processor uses to influence which components to select, and how to handle parameter mappings to individual Components. If we reuse the example from Method 1, we may decide to tweak the design slightly so that boolean dataTypes are represented by Switch components instead of Checkbox components, and TextFields should ignore descriptions. To do this, we may create some Layout Parameters, such as:

layoutParameters = {
    “preferredComponents”: [
        {
            “dataType”: “boolean”,
            “componentType”: “Switch”
        },
        {
            “dataType”: “string”,
            “componentType”: “TextField”,
            “componentProps”: {
                “showDescriptions”: false
            }
        }
  ]
}

Results

When we're finished, we may see something like:

Method 2 Results

Pros

This method still uses metadata for much of its rendering, but with some parameter declaration, we can produce much more flexible outputs than previously.

Cons

In addition to object metadata, we will have to actually create Adaptive Layouts to declare our Layout Parameters.

Method 3

Method 3

Now, we're going to have to start declaring our layouts much more directly. This method takes the Layouts that we created via Method 2 and enhances them with some explicit instructions on how to actually layout the data we have to work with. In addition, we no longer need to tether the layout to object data or metadata, if we don't really want to. We are free to add spontaneous boxes, headers, text labels or icons.

layout = {
        “componentType”: “Box”,
        “parameters”: {
            “contains”: [
                {
                    “componentType”: “Typography”,
                    “parameters”: {
                        “text”: “Register User Form”
                    }
                },
                {
                    “componentType”: “Box”,
                    “parameters”: {
                        “contains”: [
                            {
                                “componentType”: “TextField”,
                                “parameters”: {
                                    “label”: “Given Name”
                                }
                            },
                            {
                                “componentType”: “TextField”,
                                “parameters”: {
                                    “label”: “Surname”
                                }
                            },
                            {
                                “componentType”: “Switch”,
                                “parameters”: {
                                    “label”: “registered”
                                }
                            }
                        ]
                    }
                }
            ]
        }
}

Results

When we're finished, we may see something like:

Method 3 Results

Pros

The rendered output will be very customizable, while still maintaining the flexibility and portability offered by keeping the designs inside Adaptive Layouts.

Cons

More effort will be required, using the Adaptive Layout design tool to generate the layout instructions and any additional layout parameters. For a programmer with more experience, they may wish to simply use the underlying components directly inside an IDE.

Method 4

Method 4

At this point, we are breaking away from Adaptive Layouts and directly importing and using layouts that have been implemented by a technology, such as Javascript/ReactJS. In this use-case, you are a programmer and may be writing a full-blown application that contains data and components that are outside of Adaptive Layouts or their purpose, but still want to pull in some Adaptive Layout code for an easier integration with Adaptive Framework data. You may also want to massage the data going in and out of the components in order to store and present them in different ways.

Results

A complete application, independent of Adaptive Framework, but importing common layouts:

Method 4 Results

Pros

As a programmer, you get to work with tools and libraries that you may be more familiar with, while still extracting some of the work done by Adaptive Layouts. Entire apps can integrate parts of the framework without too much effort.

Cons

You must be an experienced programmer.

Method 5

Method 5

From here on out, we're not really talking about Adaptive Layouts at all, but more interested in the direct interfaces and APIs that can be used to integrate Adaptive Framework data. Perhaps, you import and use the Javascript bindings, or even hit the RESTful interfaces to access and use data. All of the UI is up to you and you may choose to use third-party component libraries to present the UI.

Results

The sky's the limit!

Pros

You have the ultimate flexibility here. Use what you need and discard the rest.

Cons

Some assembly required.

Metadata Components

In the previous section, the more declarative methods for creating Adaptive Layouts did some hand-waving to suggest the Layout processor that generated the layouts understood the best way to do so, given the data, metadata, instructions. This requires there be some default behavior when those instructions are not present. That's where Metadata Components come in. In general, there are three categories of built-ins. Not surprisingly, they are:

  • Data Type Components
  • Property Type Components
  • Object Type Components

The first set of Metadata Components, Data Type Components are fairly simple. They take a dataType and dataType parameter, along with any operational property, such as "editable", and return a Layout Component, such as a TextField, with its parameters appropriately mapped from the object and its object metadata. These Metadata Components map one-to-one with dataTypes:

  • anyURI
  • Base64Binary
  • Boolean
  • Date
  • DateTime
  • DayTimeDuration
  • DnsName
  • Double
  • Expression
  • HexBinary
  • Hybrid
  • Ia5String
  • Integer
  • IpAddress
  • List
  • Null
  • Object
  • ObjectId
  • ObjectPath
  • Password
  • Rfc822Name
  • String
  • Template
  • Time
  • X500Name
  • XpathExpression
  • YearMonthDuration

The next set of Metadata Components handle specific Property Types. These aren't as obvious, but some of the common ones are:

  • AdaptorDropdown
  • DataTypeDropdown
  • PropertyTypeDropdown
  • ObjectTypeDrodown
  • CustomVariables

Finally, some Metadata Components handle specific Object Types. For example, _AdaptiveObjectType_ objects are specially handled in order to display them in an easy-to-consume way.

Customization

Custom Adaptive Layouts

Adaptive Layouts are intended to be created by end-users and developers in order to provide layout instructions for the Object Types and Property Types that are unique to your data. This section describes the process of creating and maintaining custom Adaptive Layouts.

Custom Adaptive Components

There's a lot of flexibility and options that have been provided with the Adaptive Components provided out of the box. However, just like everything else in Adaptive Framework, these Adaptive Components are intended to be extended, so developers can create and add new Adaptive Components to be used and shared. This section provides steps to being creating your own custom Adaptive Components.