Skip to content

Components

Robin Schreiber edited this page Apr 20, 2023 · 6 revisions

Glossary

Let's take a look at the core abstractions when working with components in lively.next. When talking about the component system we have to differentiate between public (user facing) abstractions and internal abstractions.

User Facing

component

Components are the primary form of defining reusable UI elements that can be used to compose new UIs in lively.next. They are declarative definitions of the structure and appearance of morph hierarchies. Components can be defined as standalone or as a derivation from another existing component which enables reusability and avoid style duplications in the system. Components are created by calling the component() function with a nested object (representing the structure and style of the morph hierarchy also known as a spec) or a reference to another component followed by the spec object as the second parameter (now acting as a spec that defines which properties are to be overridden from the parent component). Finally we can also define the custom behaviour corresponding to a particular component in the form of view model classes. Once a morph is instantiate from a component, these view model classes are used to instantiate a view model which implements the custom behaviour of a morph in a separate object. Internally, components are reified as style policies that are wrapped by a Component Descriptor. Among other things this allows the system to keep track of derivations and dependencies between component definitions and morphs and keeping them in sync.

part

A part is an instance of a component, which can be created by calling part method with the corresponding component and overridden properties. Unlike a component it is an actual tangible morph instance with properties that are dictated by the component definition (structure and style). Just as the component() function part() takes a spec of overridden properties as a second optional parameter. The overridden properties work in the same way as they do when deriving a component from another one, except in this case they are isolated to the morph instance we create. This is especially useful for creating last minute custom adjustments to a morph that can not be reasonably served by a dedicated component. The part method can also be used within a component definition. In this context, it denotes that a part of the component being defined is actually constructed based on another component in the system. This opens up another possibility of reusing components in the system, by actually embedding derivations of them within other components.

master

Is the property on a morph that points to the style policy that is currently applied to it and its submorphs. This can also be overridden at runtime, however this rarely leads to the desired outcome as it radically resets the entire style of a morph and its submorphs in order to adhere to the new component definition (ignoring any of the overridden properties as part of the part() call).

View Model (viewModel)

Is an object that encapsulates state and behavior of the respective morph hierarchy it is attached to. View models are able to define bindings that listen for events in the morph hierarchy and in turn trigger handlers defined on the view model. They are also able to expose functions and properties through the root morph of the hierarchy they are bound to. This enables a uniform morphic interface from the outside while enabling the encapsulation of behavior into separate objects from the UI.

Internal

Component Scopes

Denotes the fractions of a submorph hierarchy that are managed by a component. When a component definition does not include any reused components (via an embedded part() call) the component scope comprises the entire submorph hierarchy. As soon as derived components are introduced into a component definition, the component scope stops at the point where the other derived component is introduced. Conceptually this a partitioning of a tree into different sub-trees, where the sub-trees are defined by the introduction of component derivations. If this sounds too complicated, dont worry. In practice you will not have to deal with component scopes directly.

Style Policy (policy, policy applicator)

Holds information (the concrete data structure for this is also referred to as a spec) about how a component or single morph should be styled. A style policy also knows about how to apply the style to a particular morph and its submorphs. Finally we are also able to create morphs from style policies by using them as a factory that produces morphs stylized in accordance to the policy.

Inline Policy

These are the product of overwriting a property when instantiating a part. They are referred to as inline since there is no top level component definition they correspond with. Instead they are more or less spontenous customized derivations of components that are only used in a particular part of a component definition. In principle, all inline policies could be replaced by top level/normal style policies however this rarely makes sense since not every style is a meaningful reusable entity.

Inline Master

Refers to the overriding (adjusting) of the master property of a morph as part of a derived component or within an inline policy. Precendence wise, overridden masters are sandwiched between the parent component props and the overridden props when it comes to the synthesization of style properties.

Property Synthesization

Refers to the process of computing the set of style properties for a particular morph inside a morph hierarchy that is being styled by a policy. When synthesization happens the entire derivation chain of a style policy is traversed, collecting the applicable style properties on the go and finally returning a set of properties that are to be applied to the morph in question. The properties are collected per policy and can be divided into three classes with the increasing precedence:

  1. The synthesized properties of the parent policy (if applicable, if this is a top level policy this is dropped).
  2. The synthesized properties of the inline master (if applicable, if there is not inline master for this morph, this is dropped).
  3. The set of locally defined overridden properties for this policy.

Note how in step 1. we recursively invoke the 3 steps outlined above for the parent policy. This is how the traversal of the derivation chain is implemented.

Component Descriptor

Is a data structure that keeps track of dependent components of a component, meta information about the location of the source code, module and the current style policy object. It is mainly intended to be used in tools that aid the user in crafting new components.

Clone this wiki locally