Getting Started
Getting Started
We always start by creating a RootLayout
.
import { RootLayout } from 'ug-layout';
const root = RootLayout.create({
container: document.body // This can be any HTMLElement
});
Not that we have a root layout all we need to do is configure the renderable tree. For configuring renderables refer to the configuration section of the docs.
import { RootLayout, Layout, Row, View } from 'ug-layout';
const root = RootLayout.create({
container: document.body
});
root.load(
RootLayout.configure({
child: Layout.configure({
child: Row
})
})
)
The above will create a layout with a single row. We haven't configured any renderables
to occupy that row yet. This is where Views
come into play. Views are Renderables
that render a component that we create. We can use factories, classes, or already existing instances.
Read the configuration for the {@link View} Renderable for more information.
Let's create a basic component we want to render.
export class MyComponent {
// This hook gets fired when the component is initialized.
ugOnInit(container: ViewContainer): void {
container.mountHTML('<div>Hello World!</div>');
}
}
The ViewContainer
is an object that contains the component instance. It's the link
between your component and the layout framework. This seperation allows for the framework to be
transparent to the component. You only need to expose hooks on your component.
So no that our component is created lets hook it up.
import { RootLayout, Layout, Row, View } from 'ug-layout';
import { MyComponent } from './MyComponent';
const root = RootLayout.create({
container: document.body
});
root.load(
RootLayout.configure({
child: Layout.configure({
child: Row.configure({
children: [{
use: View.configure({
useClass: MyComponent
})
}, {
use: View.configure({
useClass: MyComponent
})
}]
})
})
})
)
So, from this example we have a layout with a row that will render two instances of MyComponet
. This all the configuration needed. This may seem a little verbose at first but this allows for any number of combinations of Renderables
. Since this framework is completely extensible we can create adapters into any frameworks rendering and component engine. For example ug-layout-angular
will render Angular 2 and Angular 1 components.
Views
Views
Views are Renderables that know how to render a specific component. This is where we can integrate it into different frameworks. Let's use the following as our base example. I would read the Getting Started guide before diving in here.
Component
import { ViewComponent } from 'ug-layout';
@ViewComponent()
export class MyComponent {
ugOnInit(container: ViewContainer): void {
container.mountHTML('<div>Hello World!</div>');
}
}
Layout
import { RootLayout, Layout, Row, View } from 'ug-layout';
import { MyComponent } from './MyComponent';
const root = RootLayout.create({
container: document.body
});
root.load(
RootLayout.configure({
child: Layout.configure({
child: Row.configure({
children: [{
use: View.configure({
useClass: MyComponent
})
}]
})
})
})
)
View Container
The view container is a special object that manages how the component integrates with the view. It invokes hooks on the component, contains notification observables, and APIs for interacting with the layout framework. In the above example we are setting the content of the view with our components template. The view container also manages when the component is 'ready' allowing for components to resolve asynchronously.
Async View Resolution
Views can have two async resolution phases. We can use a factory that returns a promise or we can use the ugOnResolve
hook and return a promise.
Factory
View.configure({
useFactory: async () => {
const data = await service.fetchData();
return myViewFactory(data); // Returns our component instance.
}
});
ugOnResolve Hook
@ViewComponent()
class MyComponent {
async ugOnResolve(): Promise<void> {
this.data = await this.getData();
}
ugOnInit(container: ViewContainer): void {
// This won't be invoked until the data is fetched.
container.mountHTML('<div>Hello World!</div>');
}
}
View.configure({
useClass: MyComponent
});
Component Lifecycle Hooks
These are hooks that get invoked during different points in the lifecycle of the view.
- ugOnResolve(container: ViewContainer) -> Invoked when the component is created, but before the
ugOnInit
hook. Can resolve async operations. - ugOnInit(container: ViewContainer) -> Invoked when the component is ready and resolved.
- ugOnAttach(container: ViewContainer) -> Invoked when the ViewContainer is attached to it's View Renderable.
- ugOnDetach() -> Invoked when the ViewContainer is detached from it's View Renderable. This is useful for component caching.
- ugOnResize(dimensions: { width: number, height: number }) -> Invoked when the dimensions of the container change.
- ugOnVisibilityChange(isVisible: boolean) -> Invoked whenever this view becomes visible or hidden.
- ugOnBeforeDestroy(event: BeforeDestroyEvent) -> Invoked whenever the view is about to be destroyed. The event for this hook is cancellable or can wait on an async operation. This is useful for confirming before closing or halting the closing all together. Note, this is only fired during some destroy events (ex: Tab closing), not every time the view is destroyed.
View Component
The ViewComponent
decorator is a special decorator used to define metadata for the view component. Many of the options for a view can be configured when configuring the view renderable as well.
@ViewComponent({
lazy: true,
cacheable: true
})
export class MyComponent {}
// These can be overriden upon each use of the component.
View.configure({
useClass: MyComponent,
lazy: false,
cacheable: false
});
View Configuration
A view config has the following properties:
lazy: boolean
-> The view container won't be initialized until the view is visible for the first time. This also won't create the component until it is first shown or intialize is explicitly invoked on the ViewContainer.cacheable: boolean
-> Whether the view container and it's component should NOT be destroyed when the View renderable is destroyed. This means you can use the same component instance across different layout configurations.resolution: ResolverStrategy
-> How the view should be resolved with the ViewManager. See the section onResolver Strategies
.token: any
-> The token to use to store this view with the {@link ViewManager}. If usinguseClass
the constructor will be used as the token. If using a factory atoken
must be provided. This token is used to resolve configuration for the component as well.useFactory: Function
-> Use a factory to generate the component.deps: any[]
-> Depenedencies to inject into the factory function. Only applies when usinguseFactory
option.useClass: Type<any>
-> A class that will be instantiated as the component.useValue: any
-> An already create component instance.ref: string
-> A reference identifier. This is used to identify specific component references programmatically.
Resolver Strategies
We can determine how a view gets resolved when it is created or asked for.
ResolverStrategy.TRANSIENT
-> Each time a view is requested to create a component, it will always create a new one.ResolverStrategy.SINGLETON
-> Each time a view is requested to create a component, it will either return an existing instance of that component or create one that will be the single instance for that component.ResolverStrategy.REF
-> Each time a view is requested to create a component, it will either return an existing instance of that component that matches the same ref identifier given or create one that will be registered under the given ref. Note,ref
must be provided or else an error will be thrown.
Custom View Renderables
A {@link View} can be extended like any {@link Renderable} and can be integrated into any framework. Checkout the ug-layout-angular
package for a View that renders Angular 1 and 2 components.
Serialization
Serialization
ugLayout supports serializing a layout's state as JSON that can be stored and read back into a layout. Usually each Renderable has a Serializer associated with it. Let's dive in to serialization basic usage.
Usage
We need to create a SerializerContainer from our root layout. We can use the RootSerializer class which is a SerializerContainer bootstrapped with all the built in Renderables registered.
const rootLayout = RootLayout.create({ container: document.body });
class MyComponent {}
rootLayout.load(
RootLayout.configure({
child: Layout.configure({
child: View.configure({ useClass: MyComponent })
})
})
);
Let's assume we have the root layout instance above. Now we can create out serializer.
import { RootSerializer } from 'ug-layout';
const serializer = RootSerializer.fromRoot(rootLayout);
const layoutJSON = serializer.serialize(rootLayout);
Not we can store this JSON into LocalStorage or any other storage. Now we'll load the root layout from the JSON.
rootLayout.load(serializer.deserialize(layoutJSON));
The deserialize
method returns a ConfiguredRenderable
which is the same as calling RootLayout.configure()
.
Creating Serializers
Each Renderable is not essential a 1 to 1 relation ship but in a lot of cases it is. For example the Layout
Renderable has a LayoutSerializer
which knows how to serialize and deserialize a Layout Renderable. A Stack
has a single StackSerializer
, but it also serializes and deserializes StackHeader
, StackTab
, and StackItemContainer
since they are only applicable to Stacks.
A serializer need to implement the Serializer
interface. Here is an example serializer.
import {
Serializer,
Serialized,
ConfiguredRenderable,
SerializerContainer
} from 'ug-layout';
import { MyRenderable } from './MyRenderable';
export interface SerializedMyRenderable extends Serialized {
someMessage: string;
}
export class MySerializer implements Serializer<MyRenderable, SerializeMyRenderable> {
serialize(renderable: MyRenderable): SerializedMyRenderable {
return {
name: 'MyRenderable',
someMessage: renderable.someMessage
};
}
deserialize(serialized: SerializedMyRenderable): ConfiguredRenderable<MyRenderable> {
return new ConfiguiredRenderable(MyRenderable, {
someMessage: serialized.someMessage
});
}
static register(container: SerializerContainer): void {
container.registerClass('MyRenderable', MyRenderable);
}
}
Builtin Renderables
Builtin Renderables
Here is a list of builtin renderables.
Row
A row renders a list of Renderables horizontally.
Column
A column renders a list of Renderables vertically.
Stack
A stack renders a list of Renderables as a tabbable interface. If the tab is configured with headers the tabs can be dropped onto other stacks.
Layout
A layout is a grouping that contains Renderables underneath it. Visually it does nothing, but it contains it's own DragHost
which restricts items from being dragged outside it's bounds. If you want keep a Stack item from being dragged out side a set of Renderables then you would use a Layout to contain it.
RootLayout
This is the root layout that is created and bootstraps all dependencies for child renderables.
View
Renders components and interfaces with a ViewContainer.
Configuring Renderables
Configuring Renderables
ugLayout uses the ConfiguredRenderable
class as a way to associate configuration between a Renderable and it's configuration. Most built in renderables contain static method named configure
. This method returns a ConfiguredRenderable
instance that contains the provided config and Renderable class.
Layout.configure({
child: Row
});
// Is equal to
new ConfiguredRenderable(Layout, {
child: Row
})
Anywhere something requires a RenderableArg
You can provide a Renderable, a ConfiguredRenderable
or an instance of a Renderable.
Resolving Renderables and Configuration
If you are creating Renderables from a RenderableArg
you can use the resolve
and resolveConfiguration
static methods on the ConfiguredRenderable
class to resolve them.
const layoutConfig = Layout.configure({ child: Row });
const layoutInstance = new Layout();
ConfiguredRenderable.resolve(layoutConfig); // => Layout
ConfiguredRenderable.resolve(Layout); // => Layout
ConfiguredRenderable.resolve(layoutInstance); // => Layout
ConfiguredRenderable.resolveConfiguration(layoutConfig); // => { child: Row }
References
References
Class Summary
Static Public Class Summary | ||
public |
Event fired before an item is destroyed. |
|
public |
An event that can be dispatched from the event bus. |
|
public |
An class that is thrown when a Cancellable is cancelled. |
|
public |
An event that can be cancelled. |
|
public |
|
|
public |
A control that triggers a tab to close. |
|
public |
|
|
public |
|
|
public |
A container that holds a Renderable class and a configuration to use when it is instanatiated. |
|
public |
Invokes a custom view hook on any views that receive this event. |
|
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public |
Custom eventing bus that abstracts common patterns between events. |
|
public |
An instance of a forward ref function. |
|
public |
A serializer that can be used for renderables that don't container any special logic or configuration. |
|
public |
A dependency injector for resolving dependencies. |
|
public |
|
|
public |
Serializes/deserializes a layout renderable. |
|
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public abstract |
The base renderable that all other renderables extend from. |
|
public |
A class that defines an area in pixels. |
|
public |
An injector created for renderables. |
|
public |
Renders the layout. |
|
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public |
A container for running and determining serializers. |
|
public |
|
|
public |
A Renderable that renders the Renderable items in a tabbable format. |
|
public |
Base stack control that all stack controls extend. |
|
public |
|
|
public |
|
|
public |
|
|
public |
A renderable that is a direct child of a stack. |
|
public |
|
|
public |
Renderable representing a stack tab. |
|
public |
|
|
public |
Fired when a tab is closed. |
|
public |
|
|
public |
Fired when a tab is dragged. |
|
public |
Event fired when a tab is selected. |
|
public |
|
|
public |
A token used for dependency injection. |
|
public |
|
|
public |
A renderable that renders a component. |
|
public |
A container that holds a 1 to 1 relationship with a component instance. |
|
public |
Responsible for creating view containers from view configurations. |
|
public |
Executes view hooks on a component instance. |
|
public |
This service wires up a class instance with custom behavior for dealing with communication between multiple views. |
|
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public |
|
Interface Summary
Static Public Interface Summary | ||
public |
|
|
public |
An event interface that is emitted from a Draggable. |
|
public |
An interface that signifies the renderable can handle drops. |
|
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public |
|
Function Summary
Static Public Function Summary | ||
public |
Inject(token: *): ParameterDecorator Marks a param to be injected with the registered provider registered with the token. |
|
public |
Injectable(config: InjectableConfigArgs): ClassDecorator Marks a dependency as injectable. |
|
public |
Lazy(): ParameterDecorator Marks a dependency as lazy. |
|
public |
MemoizeFrom(properties: ...string[]): MethodDecorator A decorator that memoizes a functions computation based on the current and previous value of other parameters. |
|
public |
ObserveViewHook(hook: string): PropertyDecorator Creates an Observable that emits when the provided hook is invoked. |
|
public |
Optional(): ParameterDecorator Marks a dependency as optional. |
|
public |
Self(): ParameterDecorator Will only check the injector creating the dependency. |
|
public |
ViewComponent(config: ViewComponentConfigArgs): ClassDecorator Registers view metadata with a component class. |
|
public |
ViewInsert(config: ViewInsertConfigArgs): PropertyDecorator Sets up a view insert method. |
|
public |
ViewLinkInit(injections: ...any[]): MethodDecorator Sets up an init method that is invoked at the time a view is linked by the ViewLinker. |
|
public |
ViewQuery(config: ViewQueryConfigArgs): MethodDecorator Sets up a view query with the decorated method as the callback to receive the query results. |
|
public |
ViewResolve(config: ViewResolveConfigArgs): PropertyDecorator Sets up a view resolve method. |
|
public |
clamp(val: *, min: *, max: *): * |
|
public |
defaults(dest: *, src: *): * |
|
public |
eq(value: *): * |
|
public |
forwardRef(fn: Function): ForwardRef A factory that creates a ForwardRef. |
|
public |
get(obj: *, path: *, defaultValue: *, comparer: *): * |
|
public |
getDefaultMetadata(): {"queries": *, "inits": *, "inserts": *, "resolves": *} |
|
public |
isBoolean(val: *): * |
|
public |
isFunction(val: *): * |
|
public |
isNumber(val: *): * |
|
public |
isObject(val: *): * |
|
public |
isObserver(val: *): * |
|
public |
isPromise(value: *): * |
|
public |
isString(val: *): * |
|
public |
isUndefined(val: *): * |
|
public |
negate(fn: *): * |
|
public |
|
|
public |
propEq(prop: *, value: *): * |
|
public |
|
Variable Summary
Static Public Variable Summary | ||
public |
Injection token for injecting the renderables configuration. |
|
public |
Injection token for injecting the container renderable. |
|
public |
ContextType: {"NONE": string, "LOAD": string} |
|
public |
|
|
public |
Injection token for the Document API. |
|
public |
Injection token for injecting an HTML element associated with the renderable. |
|
public |
|
|
public |
Key used to assign the injector to on Renderables. |
|
public |
|
|
public |
|
|
public |
|
|
public |
Layout: * A layout is a set of renderables scoped to a drag host. |
|
public |
LinkerMetatdataRef: docs/di.js~Token |
|
public |
|
|
public |
Injection token for injecting the patch method generated by snabbdom. |
|
public |
Injection token for the root configuration used to create a RootLayout |
|
public |
|
|
public |
Symbol that signifies that an XYItemContainer's ratio is unallocated. |
|
public |
|
|
public |
|
|
public |
|
|
public |
ViewComponentRef: docs/di.js~Token |
|
public |
uid: * |
Typedef Summary
Static Public Typedef Summary | ||
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public |
ProviderArg: Provider | Type<*> |
|
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public |
|
External Summary
Static Public External Summary | ||
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public |
|
|
public |
|