@peter.prib/renderengine 0.2.6 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/REFERENCE.md +180 -2
- package/dist/renderengine-workspace.umd.js +8704 -5310
- package/dist/renderengine.umd.js +5675 -3398
- package/examples/archimate.html +68 -66
- package/examples/data-model.html +223 -13
- package/package.json +1 -1
- package/src/bian.js +182 -0
- package/src/charting/DiagramEditor.js +5 -26
- package/src/charting/DiagramTypeRegistry.js +8 -2
- package/src/charting/ModelCheckDialog.js +63 -0
- package/src/charting/ModelChecker.js +26 -0
- package/src/charting/ViewTabStrip.js +94 -81
- package/src/charting/datamodel/BianLandscapeReader.js +185 -0
- package/src/charting/datamodel/BianSemanticApiReader.js +183 -0
- package/src/charting/datamodel/DataModel.js +356 -10
- package/src/charting/datamodel/DataModelChecker.js +92 -0
- package/src/charting/datamodel/DataModelCompared.js +127 -0
- package/src/charting/datamodel/DataModelFileFormat.js +33 -0
- package/src/charting/datamodel/DataModelPerspective.js +45 -0
- package/src/charting/datamodel/DataType.js +108 -0
- package/src/charting/datamodel/EnumerationType.js +51 -0
- package/src/charting/datamodel/ServiceDomain.js +177 -0
- package/src/charting/datamodel/ServiceLandscape.js +104 -0
- package/src/charting/datamodel/StructuredType.js +63 -0
- package/src/charting/datamodel/index.js +10 -0
- package/src/charting/diagramModel/MergeModelCommand.js +43 -37
- package/src/charting/diagramModel/OpenViewList.js +75 -0
- package/src/charting/diagramModel/ViewSetChecker.js +22 -34
- package/src/charting/diagrams/DataModelRelationshipStrategy.js +12 -4
- package/src/charting/diagrams/EdgeGeometry.js +578 -553
- package/src/charting/diagrams/GraphDiagram.js +11 -1
- package/src/charting/diagrams/NodeGeometry.js +169 -158
- package/src/charting/glyphs/PersonGlyph.js +24 -23
- package/src/index.js +2666 -2664
- package/src/workspace/EditorShell.js +166 -67
- package/src/workspace/PanelLayout.js +56 -0
- package/src/workspace/layout/TabsNode.js +205 -191
- package/src/workspace/parts/ArchimateCanvasPart.js +5 -7
- package/src/workspace/parts/DataModelPart.js +339 -29
- package/src/workspace/parts/DiagramEditorPart.js +2 -8
- package/src/workspace/parts/EditorPart.js +461 -407
- package/src/workspace/parts/ModelFile.js +216 -187
- package/src/workspace/parts/ModelsPart.js +483 -192
- package/src/workspace/storage/BackupFolder.js +145 -0
- package/src/workspace/storage/KeyValueStore.js +92 -0
- package/src/workspace/storage/ModelLibrary.js +65 -0
- package/src/workspace/workArea.js +417 -413
- package/src/yaml/YamlReader.js +372 -0
|
@@ -1,191 +1,205 @@
|
|
|
1
|
-
import { LayoutNode } from './LayoutNode.js';
|
|
2
|
-
import { el } from '../dom.js';
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* TabsNode — a tab strip over a stack of children, one visible at a time.
|
|
6
|
-
* This is what workbench's eight mutually exclusive tool-panels become, and
|
|
7
|
-
* what a WorkArea uses as its editor groups.
|
|
8
|
-
*
|
|
9
|
-
* Three deliberate behaviours:
|
|
10
|
-
* - **Lazy first mount.** A child is only mounted when its tab is first
|
|
11
|
-
* selected, so opening a workspace does not pay for eight panels nobody
|
|
12
|
-
* looked at. This is the case ContextBus's retained-value replay exists for:
|
|
13
|
-
* a part mounting on first activation still sees current selection.
|
|
14
|
-
* - **No unmount on switch.** Once mounted a child stays mounted and is merely
|
|
15
|
-
* hidden. Tearing down and rebuilding per switch is what makes a shell feel
|
|
16
|
-
* slow, and it would discard scroll position and unsaved input.
|
|
17
|
-
* - **Closing is optional and delegable.** `closable` adds a close control per
|
|
18
|
-
* tab (per-child `closable: false` opts one out — a pinned welcome tab, say).
|
|
19
|
-
* With no `ctx.onTabClose` the node closes the tab itself, so a plain layout
|
|
20
|
-
* gets working close buttons; with one, the handler owns it, which is how
|
|
21
|
-
* WorkArea keeps closing in its model instead of in the DOM.
|
|
22
|
-
*/
|
|
23
|
-
export class TabsNode extends LayoutNode {
|
|
24
|
-
static type = 'tabs';
|
|
25
|
-
|
|
26
|
-
constructor(spec = {}) {
|
|
27
|
-
super(spec);
|
|
28
|
-
this.active = Number.isInteger(spec.active) ? spec.active : 0;
|
|
29
|
-
/** Group identity — what "open beside THIS group" addresses. */
|
|
30
|
-
this.id = spec.id ?? null;
|
|
31
|
-
this.closable = spec.closable ?? false;
|
|
32
|
-
this._panes = [];
|
|
33
|
-
this._tabs = [];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
build(ctx) {
|
|
37
|
-
this.el.classList.add('ws-tabs');
|
|
38
|
-
this.el.append(
|
|
39
|
-
el({ cls: 'ws-tabstrip', attrs: { role: 'tablist' }, ref: n => { this.strip = n; } }),
|
|
40
|
-
el({ cls: 'ws-tabbody', ref: n => { this.body = n; } }),
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
// Capture phase: a part may stopPropagation on its own clicks, and
|
|
44
|
-
// "the group you last touched" has to hold even then, or the next
|
|
45
|
-
// thing you open lands somewhere you weren't looking.
|
|
46
|
-
if (this.id) {
|
|
47
|
-
this.el.addEventListener('pointerdown', () => ctx.onGroupFocus?.(this.id, this), true);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
this._panes = [];
|
|
51
|
-
this._tabs = [];
|
|
52
|
-
|
|
53
|
-
this.children.forEach((child, i) => {
|
|
54
|
-
const pane = el({ cls: 'ws-tabpane' });
|
|
55
|
-
this.body.appendChild(pane);
|
|
56
|
-
// Render before reading label(): a PartNode only resolves its part
|
|
57
|
-
// — and therefore its title — during render(). Building the tab
|
|
58
|
-
// first would label every tab with the raw part id.
|
|
59
|
-
child.render(pane, ctx);
|
|
60
|
-
this._panes.push(pane);
|
|
61
|
-
this._tabs.push(this.strip.appendChild(this._buildTab(child, i)));
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
if (this.children.length) this.select(Math.min(this.active, this.children.length - 1), true);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* One tab. A `<div role="tab">` rather than a `<button>` because a closable
|
|
69
|
-
* tab nests a close button, and a button inside a button is invalid markup
|
|
70
|
-
* that browsers reparent — so `tabindex`/`keydown` stand in for the button
|
|
71
|
-
* behaviour that is lost.
|
|
72
|
-
*/
|
|
73
|
-
_buildTab(child, i) {
|
|
74
|
-
const label = child.label?.() ?? child.spec?.title ?? `Tab ${i + 1}`;
|
|
75
|
-
const closable = this.closable && (child.spec?.closable ?? true);
|
|
76
|
-
return el({
|
|
77
|
-
cls: 'ws-tab',
|
|
78
|
-
attrs: { role: 'tab', tabindex: '0', title: label },
|
|
79
|
-
on: {
|
|
80
|
-
click: () => this.select(i),
|
|
81
|
-
keydown: (e) => {
|
|
82
|
-
if (e.key !== 'Enter' && e.key !== ' ') return;
|
|
83
|
-
e.preventDefault();
|
|
84
|
-
this.select(i);
|
|
85
|
-
},
|
|
86
|
-
// Middle-click closes, as it does in every editor and browser.
|
|
87
|
-
auxclick: (e) => { if (closable && e.button === 1) { e.preventDefault(); this.requestClose(i); } },
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
this.
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
this.
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
*
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
const
|
|
127
|
-
if (
|
|
128
|
-
this.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
child
|
|
140
|
-
this.
|
|
141
|
-
this.
|
|
142
|
-
this.
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
this.
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
1
|
+
import { LayoutNode } from './LayoutNode.js';
|
|
2
|
+
import { el } from '../dom.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* TabsNode — a tab strip over a stack of children, one visible at a time.
|
|
6
|
+
* This is what workbench's eight mutually exclusive tool-panels become, and
|
|
7
|
+
* what a WorkArea uses as its editor groups.
|
|
8
|
+
*
|
|
9
|
+
* Three deliberate behaviours:
|
|
10
|
+
* - **Lazy first mount.** A child is only mounted when its tab is first
|
|
11
|
+
* selected, so opening a workspace does not pay for eight panels nobody
|
|
12
|
+
* looked at. This is the case ContextBus's retained-value replay exists for:
|
|
13
|
+
* a part mounting on first activation still sees current selection.
|
|
14
|
+
* - **No unmount on switch.** Once mounted a child stays mounted and is merely
|
|
15
|
+
* hidden. Tearing down and rebuilding per switch is what makes a shell feel
|
|
16
|
+
* slow, and it would discard scroll position and unsaved input.
|
|
17
|
+
* - **Closing is optional and delegable.** `closable` adds a close control per
|
|
18
|
+
* tab (per-child `closable: false` opts one out — a pinned welcome tab, say).
|
|
19
|
+
* With no `ctx.onTabClose` the node closes the tab itself, so a plain layout
|
|
20
|
+
* gets working close buttons; with one, the handler owns it, which is how
|
|
21
|
+
* WorkArea keeps closing in its model instead of in the DOM.
|
|
22
|
+
*/
|
|
23
|
+
export class TabsNode extends LayoutNode {
|
|
24
|
+
static type = 'tabs';
|
|
25
|
+
|
|
26
|
+
constructor(spec = {}) {
|
|
27
|
+
super(spec);
|
|
28
|
+
this.active = Number.isInteger(spec.active) ? spec.active : 0;
|
|
29
|
+
/** Group identity — what "open beside THIS group" addresses. */
|
|
30
|
+
this.id = spec.id ?? null;
|
|
31
|
+
this.closable = spec.closable ?? false;
|
|
32
|
+
this._panes = [];
|
|
33
|
+
this._tabs = [];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
build(ctx) {
|
|
37
|
+
this.el.classList.add('ws-tabs');
|
|
38
|
+
this.el.append(
|
|
39
|
+
el({ cls: 'ws-tabstrip', attrs: { role: 'tablist' }, ref: n => { this.strip = n; } }),
|
|
40
|
+
el({ cls: 'ws-tabbody', ref: n => { this.body = n; } }),
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
// Capture phase: a part may stopPropagation on its own clicks, and
|
|
44
|
+
// "the group you last touched" has to hold even then, or the next
|
|
45
|
+
// thing you open lands somewhere you weren't looking.
|
|
46
|
+
if (this.id) {
|
|
47
|
+
this.el.addEventListener('pointerdown', () => ctx.onGroupFocus?.(this.id, this), true);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
this._panes = [];
|
|
51
|
+
this._tabs = [];
|
|
52
|
+
|
|
53
|
+
this.children.forEach((child, i) => {
|
|
54
|
+
const pane = el({ cls: 'ws-tabpane' });
|
|
55
|
+
this.body.appendChild(pane);
|
|
56
|
+
// Render before reading label(): a PartNode only resolves its part
|
|
57
|
+
// — and therefore its title — during render(). Building the tab
|
|
58
|
+
// first would label every tab with the raw part id.
|
|
59
|
+
child.render(pane, ctx);
|
|
60
|
+
this._panes.push(pane);
|
|
61
|
+
this._tabs.push(this.strip.appendChild(this._buildTab(child, i)));
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
if (this.children.length) this.select(Math.min(this.active, this.children.length - 1), true);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* One tab. A `<div role="tab">` rather than a `<button>` because a closable
|
|
69
|
+
* tab nests a close button, and a button inside a button is invalid markup
|
|
70
|
+
* that browsers reparent — so `tabindex`/`keydown` stand in for the button
|
|
71
|
+
* behaviour that is lost.
|
|
72
|
+
*/
|
|
73
|
+
_buildTab(child, i) {
|
|
74
|
+
const label = child.label?.() ?? child.spec?.title ?? `Tab ${i + 1}`;
|
|
75
|
+
const closable = this.closable && (child.spec?.closable ?? true);
|
|
76
|
+
return el({
|
|
77
|
+
cls: 'ws-tab',
|
|
78
|
+
attrs: { role: 'tab', tabindex: '0', title: label },
|
|
79
|
+
on: {
|
|
80
|
+
click: () => this.select(i),
|
|
81
|
+
keydown: (e) => {
|
|
82
|
+
if (e.key !== 'Enter' && e.key !== ' ') return;
|
|
83
|
+
e.preventDefault();
|
|
84
|
+
this.select(i);
|
|
85
|
+
},
|
|
86
|
+
// Middle-click closes, as it does in every editor and browser.
|
|
87
|
+
auxclick: (e) => { if (closable && e.button === 1) { e.preventDefault(); this.requestClose(i); } },
|
|
88
|
+
// Right-click: the shell's menu for what the tab holds, when it offers one.
|
|
89
|
+
contextmenu: (e) => this.requestMenu(i, e),
|
|
90
|
+
},
|
|
91
|
+
children: [
|
|
92
|
+
{ tag: 'span', cls: 'ws-tab-label', text: label },
|
|
93
|
+
closable && {
|
|
94
|
+
tag: 'button',
|
|
95
|
+
cls: 'ws-tabclose',
|
|
96
|
+
text: '×',
|
|
97
|
+
attrs: { type: 'button', tabindex: '-1', 'aria-label': `Close ${label}` },
|
|
98
|
+
// Without stopPropagation the tab's own click handler also
|
|
99
|
+
// fires and selects the tab we are closing.
|
|
100
|
+
on: { click: (e) => { e.stopPropagation(); this.requestClose(i); } },
|
|
101
|
+
},
|
|
102
|
+
].filter(Boolean),
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
select(index, silent = false) {
|
|
107
|
+
if (index < 0 || index >= this.children.length) return;
|
|
108
|
+
this.active = index;
|
|
109
|
+
this._tabs.forEach((t, i) => {
|
|
110
|
+
const on = i === index;
|
|
111
|
+
t.classList.toggle('ws-tab-active', on);
|
|
112
|
+
t.setAttribute('aria-selected', String(on));
|
|
113
|
+
});
|
|
114
|
+
this._panes.forEach((p, i) => { p.style.display = i === index ? '' : 'none'; });
|
|
115
|
+
// Mount on first reveal only — activate() is idempotent.
|
|
116
|
+
this.children[index].activate?.();
|
|
117
|
+
if (!silent) this._emitChange();
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* A tab was right-clicked: `ctx.onTabMenu` (the shell's menu for what it
|
|
122
|
+
* holds) gets it, with the event to place the menu by; without one, the
|
|
123
|
+
* browser's own menu shows.
|
|
124
|
+
*/
|
|
125
|
+
requestMenu(index, event) {
|
|
126
|
+
const child = this.children[index];
|
|
127
|
+
if (!child || !this.ctx?.onTabMenu) return;
|
|
128
|
+
const shown = this.ctx.onTabMenu({ tabs: this, index, partId: child.spec?.partId ?? null, node: child, event });
|
|
129
|
+
if (shown) event.preventDefault();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* A tab's close control was used. Hands off to `ctx.onTabClose` when the
|
|
134
|
+
* shell wants to own the decision (it may prompt about unsaved work, or
|
|
135
|
+
* rearrange the surrounding splits); otherwise closes it here.
|
|
136
|
+
*/
|
|
137
|
+
requestClose(index) {
|
|
138
|
+
const child = this.children[index];
|
|
139
|
+
if (!child) return;
|
|
140
|
+
const detail = { tabs: this, index, partId: child.spec?.partId ?? null, node: child };
|
|
141
|
+
if (this.ctx?.onTabClose) { this.ctx.onTabClose(detail); return; }
|
|
142
|
+
this.closeTab(index);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Remove a tab and its child. Selection moves to the neighbour rather than
|
|
147
|
+
* back to the first tab, which is what closing the tab you were reading
|
|
148
|
+
* should feel like.
|
|
149
|
+
*/
|
|
150
|
+
closeTab(index) {
|
|
151
|
+
const child = this.children[index];
|
|
152
|
+
if (!child) return null;
|
|
153
|
+
child.dispose();
|
|
154
|
+
this._panes[index]?.remove?.();
|
|
155
|
+
this._tabs[index]?.remove?.();
|
|
156
|
+
this.children.splice(index, 1);
|
|
157
|
+
this._panes.splice(index, 1);
|
|
158
|
+
this._tabs.splice(index, 1);
|
|
159
|
+
// Rebuilt so each tab's handlers close over its new index.
|
|
160
|
+
this._tabs.forEach((tab, i) => {
|
|
161
|
+
const fresh = this._buildTab(this.children[i], i);
|
|
162
|
+
tab.replaceWith(fresh);
|
|
163
|
+
this._tabs[i] = fresh;
|
|
164
|
+
});
|
|
165
|
+
if (this.children.length) {
|
|
166
|
+
this.select(Math.min(index, this.children.length - 1), true);
|
|
167
|
+
} else {
|
|
168
|
+
this.active = 0;
|
|
169
|
+
}
|
|
170
|
+
this._emitChange();
|
|
171
|
+
return child;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Show each tab's label as its child gives it now (a part's title that changed). */
|
|
175
|
+
refreshLabels() {
|
|
176
|
+
this._tabs.forEach((tab, i) => {
|
|
177
|
+
const fresh = this._buildTab(this.children[i], i);
|
|
178
|
+
fresh.classList.toggle('ws-tab-active', i === this.active);
|
|
179
|
+
fresh.setAttribute('aria-selected', String(i === this.active));
|
|
180
|
+
tab.replaceWith(fresh);
|
|
181
|
+
this._tabs[i] = fresh;
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** Activating the container activates only the visible child. */
|
|
186
|
+
activate() {
|
|
187
|
+
if (this.children.length) this.children[this.active]?.activate?.();
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
serialize() {
|
|
191
|
+
// Spread the spec first: `id` and `closable` are part of the group's
|
|
192
|
+
// identity, and a work area that lost group ids on save would reopen
|
|
193
|
+
// with every "open beside this group" pointing at nothing.
|
|
194
|
+
// The spec is spread rather than rebuilt field by field: `id` and
|
|
195
|
+
// `closable` are part of a group's identity, and a work area that lost
|
|
196
|
+
// group ids on save would come back with every "open beside this group"
|
|
197
|
+
// pointing at nothing.
|
|
198
|
+
return {
|
|
199
|
+
...this.spec,
|
|
200
|
+
type: TabsNode.type,
|
|
201
|
+
active: this.active,
|
|
202
|
+
children: this.children.map(c => c.serialize()),
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -6,7 +6,6 @@ import { ArchimateCanvasEditor, ArchimatePalette, typeTitle } from '../../charti
|
|
|
6
6
|
import { ArchimateNotation } from '../../archimate.js';
|
|
7
7
|
import { MenuBar } from '../../charting/MenuBar.js';
|
|
8
8
|
import { ToolbarText } from '../../charting/toolbar/index.js';
|
|
9
|
-
import { ViewTabStrip } from '../../charting/ViewTabStrip.js';
|
|
10
9
|
import { FormDialog } from '../../charting/FormDialog.js';
|
|
11
10
|
import { CsvImportDialog } from '../../charting/archimate/CsvImportDialog.js';
|
|
12
11
|
import { pickFile } from '../../charting/toolbar/pickFile.js';
|
|
@@ -189,13 +188,12 @@ export class ArchimateCanvasPart extends EditorPart {
|
|
|
189
188
|
elements.id = 'elements';
|
|
190
189
|
canvas.appendChild(elements);
|
|
191
190
|
|
|
192
|
-
const tabs =
|
|
193
|
-
document: doc,
|
|
194
|
-
onSelect: (id) => model.switchTo(id),
|
|
195
|
-
menuItems: (id) => this.viewMenu.items(id),
|
|
196
|
-
}).render(model.views(), model.currentViewId);
|
|
191
|
+
const tabs = this.viewTabs();
|
|
197
192
|
|
|
198
|
-
const { toolbar, side, main, aside } = new EditorShell({
|
|
193
|
+
const { toolbar, side, main, aside } = new EditorShell({
|
|
194
|
+
document: doc, sideWidth: '260px', aside: true, asideWidth: this.spec.analysis ? '260px' : '210px',
|
|
195
|
+
layout: this.layout, labels: { side: 'Model', aside: this.spec.analysis ? 'Palette and analysis' : 'Palette' },
|
|
196
|
+
}).mount(this.container);
|
|
199
197
|
Object.assign(aside.style, { padding: '6px', fontSize: '12px' });
|
|
200
198
|
// With `analysis`, the palette shares the right with the analysis of the selected element.
|
|
201
199
|
let paletteHost = aside, analysisHost = null;
|