Layout
Now let's use another component with which you can define more complex layouts without using flexbox
or any other HTML structures like before. We will use a component called Layout
and we will extend
this.
What are we learning here?
- How to use a
Layout
component
A Layout need an outer element with specified height
An Layout
component will always adapt its dimensions to the outer element. A Layout
is not
suitable for loading into an empty stage that has no height. In addition, a Layout
cannot
adapt to the content of its own stages.
Let's start with a simple skeleton:
src/apps/demo/layout-component/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 | import { Application } from "@codecoupler/cc-ui";
import LayoutComponent from "./layout.js";
export default class extends Application {
static defaults = {
"@codecoupler": {
panel: {
panelSize: "1165 630",
headerTitle: "Test Layout Features",
}
}
};
async start() {
await this.stage.load(LayoutComponent);
}
}
|
We load the new application in our system.js file (just by replacing the previous one):
src/system.js
| import { Component } from "@codecoupler/cc-ui";
import TestApp from "./demo/apps/layout-component";
export default class extends Component {
async boot() {
await this.stage.load(TestApp);
}
}
|
Ok, we have an empty application window. Not very spectacular. Let's start building a layout.
Now we pass options to the component starting with one property root
to define stages. The
structure is very similar to the options of the `Flexbox' component, but there are significant
differences in the details.
In the following step we define first only one stage and load the application component
WidgetBasics
into this to demonstrate how to modify an application component to look like a canvas
or widget component.
We want to load the application component in our first stage without the title and borders. So we
will set the panel to the status "fullsize".To set this option we use so called namespaced options.
These options will be evaluated by the underlying base classes. In our example the options described
by { "@codecoupler": { application: {} } }
will be processed by the base class Application
which
is be extended by WidgetBasics
.
Each component intended to be extended has its own options in many cases. In order not to conflict
with the options of the final class, namespaces are used. Best practice is to use the top level with
the vendor name prefixed with an @-sign. In the level below, the name of the base class is used.
As we will use this option many times we will put it in an own variable:
src/apps/demo/layout-component/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 | import { Application, Layout } from "@codecoupler/cc-ui";
import WidgetBasics from "../widget-basics";
export default class extends Application {
static defaults = {
"@codecoupler": {
panel: {
panelSize: "1165 630",
headerTitle: "Test Layout Features",
}
}
};
async start() {
await this.stage.load(Layout, {
root: { id: "first", type: "stage" }
});
let options = "@codecoupler": { application: { panel: { setStatus: "fullsize" } } };
await this.getStage("first").load(WidgetBasics, options);
}
}
|
Still not very spectacular, so lets replace the first stage with the type row
and split this row
into two parts. Sublayouts in a row will be defined in the array content
. Every part is now an own
stage in which we can load a component.
Furthermore, we combine two awaits into one. The components can be loaded in parallel instead of
sequentially.
src/apps/demo/layout-component/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 | import { Application, Layout } from "@codecoupler/cc-ui";
import WidgetBasics from "../widget-basics";
import SingleRoot from "../single-root";
export default class extends Application {
static defaults = {
"@codecoupler": {
panel: {
panelSize: "1165 630",
headerTitle: "Test Layout Features",
}
}
};
async start() {
await this.stage.load(Layout, {
root: {
type: "row",
content: [
{ id: "first", type: "stage" },
{ id: "second", type: "stage" }
]
}
});
let options = "@codecoupler": { application: { panel: { setStatus: "fullsize" } } };
await Promise.all([
this.getStage("first").load(WidgetBasics, options),
this.getStage("second").load(SingleRoot, options)
]);
}
}
|
Now let's go one step further to illustrate how you can use the types row
and column
, how to use
size
and how they can be nested:
src/apps/demo/layout-component/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 | import { Application, Layout } from "@codecoupler/cc-ui";
import WidgetBasics from "../widget-basics";
import SingleRoot from "../single-root";
import WidgetBasicsVue from "../widget-basics-vue";
export default class extends Application {
static defaults = {
"@codecoupler": {
panel: {
panelSize: "1165 630",
headerTitle: "Test Layout Features",
}
}
};
async start() {
await this.stage.load(Layout, {
root: {
type: "row",
content: [
{ id: "first", type: "stage", size: "60%" },
{
type: "column",
content: [
{ id: "second", type: "stage" },
{ id: "third", type: "stage", size: "60%" }
]
}
]
}
});
let options = {
"@codecoupler": { application: { panel: { setStatus: "fullsize" } } }
};
await Promise.all([
this.getStage("first").load(WidgetBasics, options),
this.getStage("second").load(SingleRoot, options),
this.getStage("third").load(WidgetBasicsVue, options)
]);
}
}
|
Ok, now we have created a basic layout which we could have also done with a flexbox layout. Now
let's add the following property resizable: true
to show borders between the stages and and make
them resizable:
src/apps/demo/layout-component/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 | import { Application, Layout } from "@codecoupler/cc-ui";
import WidgetBasics from "../widget-basics";
import SingleRoot from "../single-root";
import WidgetBasicsVue from "../widget-basics-vue";
export default class extends Application {
static defaults = {
"@codecoupler": {
panel: {
panelSize: "1165 630",
headerTitle: "Test Layout Features",
}
}
};
async start() {
await this.stage.load(Layout, {
resizable: true,
root: {
type: "row",
content: [
{ id: "first", type: "stage", size: "60%" },
{
type: "column",
content: [
{ id: "second", type: "stage" },
{ id: "third", type: "stage", size: "60%" }
]
}
]
}
});
let options = {
"@codecoupler": { application: { panel: { setStatus: "fullsize" } } }
};
await Promise.all([
this.getStage("first").load(WidgetBasics, options),
this.getStage("second").load(SingleRoot, options),
this.getStage("third").load(WidgetBasicsVue, options)
]);
}
}
|
Info
resizable: true
is just a shortcut for dimensions: { borderWidth: 5, borderGrabWidth: 15 }
.
You can set of course only borderWidth
to have just borders that are not resizable.
Resizing the stages is nice, but what about draging them around and rearange them? Let's insert a
new property reordable: true
.
src/apps/demo/layout-component/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 | import { Application, Layout } from "@codecoupler/cc-ui";
import WidgetBasics from "../widget-basics";
import SingleRoot from "../single-root";
import WidgetBasicsVue from "../widget-basics-vue";
export default class extends Application {
static defaults = {
"@codecoupler": {
panel: {
panelSize: "1165 630",
headerTitle: "Test Layout Features",
}
}
};
async start() {
await this.stage.load(Layout, {
reordable: true,
resizable: true,
root: {
type: "row",
content: [
{ id: "first", type: "stage", size: "60%" },
{
type: "column",
content: [
{ id: "second", type: "stage" },
{ id: "third", type: "stage", size: "60%" }
]
}
]
}
});
let options = {
"@codecoupler": { application: { panel: { setStatus: "fullsize" } } }
};
await Promise.all([
this.getStage("first").load(WidgetBasics, options),
this.getStage("second").load(SingleRoot, options),
this.getStage("third").load(WidgetBasicsVue, options)
]);
}
}
|
Info
reordable: true
is just a shortcut for header: { show: true }
Now you can drag the areas around, rearange the layout and even maximize single areas. Let's set an
title for every tab:
src/apps/demo/layout-component/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 | import { Application, Layout } from "@codecoupler/cc-ui";
import WidgetBasics from "../widget-basics";
import SingleRoot from "../single-root";
import WidgetBasicsVue from "../widget-basics-vue";
export default class extends Application {
static defaults = {
"@codecoupler": {
panel: {
panelSize: "1165 630",
headerTitle: "Test Layout Features",
}
}
};
async start() {
await this.stage.load(Layout, {
reordable: true,
resizable: true,
root: {
type: "row",
content: [
{ id: "first", type: "stage", size: "60%", title: "Basics" },
{
type: "column",
content: [
{ id: "second", type: "stage", title: "Single Root" },
{ id: "third", type: "stage", size: "60%", title: "Vue" }
]
}
]
}
});
let options = {
"@codecoupler": { application: { panel: { setStatus: "fullsize" } } }
};
await Promise.all([
this.getStage("first").load(WidgetBasics, options),
this.getStage("second").load(SingleRoot, options),
this.getStage("third").load(WidgetBasicsVue, options)
]);
}
}
|
Let's demonstrate one last type. Beside row
and column
you can define a stack
:
src/apps/demo/layout-component/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50 | import { Application, Layout } from "@codecoupler/cc-ui";
import WidgetBasics from "../widget-basics";
import SingleRoot from "../single-root";
import WidgetBasicsVue from "../widget-basics-vue";
import UnusableLayout from "../canvas-vs-widget-layout";
export default class extends Application {
static defaults = {
"@codecoupler": {
panel: {
panelSize: "1165 630",
headerTitle: "Test Layout Features",
}
}
};
async start() {
await this.stage.load(Layout, {
reordable: true,
resizable: true,
root: {
type: "row",
content: [
{ id: "first", type: "stage", size: "60%", title: "Basics" },
{
type: "column",
content: [
{ id: "second", type: "stage", title: "Single Root" },
{
type: "stack",
size: "60%",
content: [
{ id: "third", type: "stage", title: "Vue" },
{ id: "fourth", type: "stage", title: "No Height" }
]
}
]
}
]
}
});
let options = {
"@codecoupler": { application: { panel: { setStatus: "fullsize" } } }
};
await Promise.all([
this.getStage("first").load(WidgetBasics, options),
this.getStage("second").load(SingleRoot, options),
this.getStage("third").load(WidgetBasicsVue, options),
this.getStage("fourth").load(UnusableLayout, options)
]);
}
}
|
Ok. Now we're taking it to the extreme, using all the other components we created earlier and
putting them all in the layout:
src/apps/demo/layout-component/index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73 | import { Application, Layout } from "@codecoupler/cc-ui";
import WidgetBasics from "../widget-basics";
import SingleRoot from "../single-root";
import WidgetBasicsVue from "../widget-basics-vue";
import UnusableLayout from "../canvas-vs-widget-layout";
import UnusableScroll from "../canvas-vs-widget-scroll";
import StageLevels from "../stage-levels";
import StagesFlexbox from "../stages-flexbox";
import SimpleBox from "../simple-box";
export default class extends Application {
static defaults = {
"@codecoupler": {
panel: {
panelSize: "1165 630",
headerTitle: "Test Layout Features",
}
}
};
async start() {
await this.stage.load(Layout, {
reordable: true,
resizable: true,
root: {
type: "row",
content: [
{
type: "stack",
size: "60%",
content: [
{ id: "first", type: "stage", title: "Basics" },
{ id: "sixth", type: "stage", title: "Layers" },
{ id: "seventh", type: "stage", title: "Flexbox" },
{ id: "eighth", type: "stage", title: "Box" }
]
},
{
type: "column",
content: [
{
type: "stack",
content: [
{ id: "second", type: "stage", title: "Single Root" },
{ id: "fifth", type: "stage", title: "No Scroll" }
]
},
{
type: "stack",
size: "60%",
content: [
{ id: "third", type: "stage", title: "Vue" },
{ id: "fourth", type: "stage", title: "No Height" }
]
}
]
}
]
}
});
let options = {
"@codecoupler": { panel: { setStatus: "fullsize" } }
};
await Promise.all([
this.getStage("first").load(WidgetBasics, options),
this.getStage("second").load(SingleRoot, options),
this.getStage("third").load(WidgetBasicsVue, options),
this.getStage("fourth").load(UnusableLayout, options),
this.getStage("fifth").load(UnusableScroll, options),
this.getStage("sixth").load(StageLevels, options),
this.getStage("seventh").load(StagesFlexbox, options),
this.getStage("eighth").load(SimpleBox, options)
]);
}
}
|