@openvcs/sdk 0.2.17-nightly.20260407.3 → 0.2.18-beta.8
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/lib/runtime/modal.d.ts +28 -1
- package/lib/runtime/modal.js +59 -1
- package/lib/types/modal.d.ts +34 -1
- package/package.json +1 -1
- package/src/lib/runtime/modal.ts +94 -5
- package/src/lib/types/modal.ts +39 -0
- package/test/modal.test.ts +71 -2
package/lib/runtime/modal.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ModalButtonVariant, ModalContentAlign, ModalInputKind, ModalListRowDefinition, ModalSelectOptionDefinition, PluginModalDefinition } from '../types/modal.js';
|
|
1
|
+
import type { ModalButtonVariant, ModalContentAlign, ModalInputKind, ModalListRowDefinition, ModalSelectOptionDefinition, PluginModalContentItem, PluginModalDefinition } from '../types/modal.js';
|
|
2
2
|
/** Describes the options accepted by `ModalBuilder.button()`. */
|
|
3
3
|
export interface ModalBuilderButtonOptions {
|
|
4
4
|
/** Stores the optional tooltip text. */
|
|
@@ -50,6 +50,27 @@ export interface ModalBuilderListOptions {
|
|
|
50
50
|
/** Stores the list rows. */
|
|
51
51
|
items: ModalListRowDefinition[];
|
|
52
52
|
}
|
|
53
|
+
/** Describes the options accepted by `ModalBuilder.horizontalBox()`. */
|
|
54
|
+
export interface ModalBuilderHorizontalBoxOptions {
|
|
55
|
+
/** Stores the spacing between children. */
|
|
56
|
+
gap?: string;
|
|
57
|
+
/** Stores the alignment hint for the main axis. */
|
|
58
|
+
align?: ModalContentAlign;
|
|
59
|
+
/** Stores whether children may wrap. */
|
|
60
|
+
wrap?: boolean;
|
|
61
|
+
}
|
|
62
|
+
/** Describes the options accepted by `ModalBuilder.verticalBox()`. */
|
|
63
|
+
export interface ModalBuilderVerticalBoxOptions {
|
|
64
|
+
/** Stores the spacing between children. */
|
|
65
|
+
gap?: string;
|
|
66
|
+
}
|
|
67
|
+
/** Describes the options accepted by `ModalBuilder.grid()`. */
|
|
68
|
+
export interface ModalBuilderGridOptions {
|
|
69
|
+
/** Stores the CSS grid column template. */
|
|
70
|
+
columns: string;
|
|
71
|
+
/** Stores the spacing between cells. */
|
|
72
|
+
gap?: string;
|
|
73
|
+
}
|
|
53
74
|
/** Builds a structured modal definition with a fluent class API. */
|
|
54
75
|
export declare class ModalBuilder {
|
|
55
76
|
private readonly definition;
|
|
@@ -59,6 +80,12 @@ export declare class ModalBuilder {
|
|
|
59
80
|
text(content: string, options?: ModalBuilderTextOptions): this;
|
|
60
81
|
/** Adds a separator to the modal body. */
|
|
61
82
|
separator(): this;
|
|
83
|
+
/** Adds a horizontal box to the modal body. */
|
|
84
|
+
horizontalBox(content: PluginModalContentItem[], options?: ModalBuilderHorizontalBoxOptions): this;
|
|
85
|
+
/** Adds a vertical box to the modal body. */
|
|
86
|
+
verticalBox(content: PluginModalContentItem[], options?: ModalBuilderVerticalBoxOptions): this;
|
|
87
|
+
/** Adds a grid container to the modal body. */
|
|
88
|
+
grid(content: PluginModalContentItem[], options: ModalBuilderGridOptions): this;
|
|
62
89
|
/** Adds a button to the modal body. */
|
|
63
90
|
button(id: string, content: string, options?: ModalBuilderButtonOptions): this;
|
|
64
91
|
/** Adds a text input to the modal body. */
|
package/lib/runtime/modal.js
CHANGED
|
@@ -28,6 +28,36 @@ class ModalBuilder {
|
|
|
28
28
|
this.definition.content.push({ type: 'separator' });
|
|
29
29
|
return this;
|
|
30
30
|
}
|
|
31
|
+
/** Adds a horizontal box to the modal body. */
|
|
32
|
+
horizontalBox(content, options = {}) {
|
|
33
|
+
this.definition.content.push({
|
|
34
|
+
type: 'horizontal-box',
|
|
35
|
+
content: cloneContent(content),
|
|
36
|
+
...(options.gap ? { gap: options.gap } : {}),
|
|
37
|
+
...(options.align ? { align: options.align } : {}),
|
|
38
|
+
...(options.wrap !== undefined ? { wrap: options.wrap } : {}),
|
|
39
|
+
});
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
/** Adds a vertical box to the modal body. */
|
|
43
|
+
verticalBox(content, options = {}) {
|
|
44
|
+
this.definition.content.push({
|
|
45
|
+
type: 'vertical-box',
|
|
46
|
+
content: cloneContent(content),
|
|
47
|
+
...(options.gap ? { gap: options.gap } : {}),
|
|
48
|
+
});
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
/** Adds a grid container to the modal body. */
|
|
52
|
+
grid(content, options) {
|
|
53
|
+
this.definition.content.push({
|
|
54
|
+
type: 'grid',
|
|
55
|
+
content: cloneContent(content),
|
|
56
|
+
columns: String(options.columns || '').trim(),
|
|
57
|
+
...(options.gap ? { gap: options.gap } : {}),
|
|
58
|
+
});
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
31
61
|
/** Adds a button to the modal body. */
|
|
32
62
|
button(id, content, options = {}) {
|
|
33
63
|
this.definition.content.push({
|
|
@@ -83,7 +113,7 @@ class ModalBuilder {
|
|
|
83
113
|
build() {
|
|
84
114
|
return {
|
|
85
115
|
title: this.definition.title,
|
|
86
|
-
content: this.definition.content
|
|
116
|
+
content: cloneContent(this.definition.content),
|
|
87
117
|
};
|
|
88
118
|
}
|
|
89
119
|
/** Returns the serialized modal payload for a host request. */
|
|
@@ -92,3 +122,31 @@ class ModalBuilder {
|
|
|
92
122
|
}
|
|
93
123
|
}
|
|
94
124
|
exports.ModalBuilder = ModalBuilder;
|
|
125
|
+
/** Clones modal content recursively so nested containers stay isolated. */
|
|
126
|
+
function cloneContent(content) {
|
|
127
|
+
return Array.isArray(content) ? content.map((item) => cloneItem(item)) : [];
|
|
128
|
+
}
|
|
129
|
+
/** Clones one modal content item recursively. */
|
|
130
|
+
function cloneItem(item) {
|
|
131
|
+
if (!item || typeof item !== 'object')
|
|
132
|
+
return item;
|
|
133
|
+
if (item.type === 'horizontal-box') {
|
|
134
|
+
return {
|
|
135
|
+
...item,
|
|
136
|
+
content: cloneContent(item.content),
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
if (item.type === 'vertical-box') {
|
|
140
|
+
return {
|
|
141
|
+
...item,
|
|
142
|
+
content: cloneContent(item.content),
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
if (item.type === 'grid') {
|
|
146
|
+
return {
|
|
147
|
+
...item,
|
|
148
|
+
content: cloneContent(item.content),
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
return { ...item };
|
|
152
|
+
}
|
package/lib/types/modal.d.ts
CHANGED
|
@@ -35,6 +35,39 @@ export interface ModalSeparatorDefinition {
|
|
|
35
35
|
/** Always stores `separator`. */
|
|
36
36
|
type: 'separator';
|
|
37
37
|
}
|
|
38
|
+
/** Describes one horizontal box rendered inside a modal. */
|
|
39
|
+
export interface ModalHorizontalBoxDefinition {
|
|
40
|
+
/** Always stores `horizontal-box`. */
|
|
41
|
+
type: 'horizontal-box';
|
|
42
|
+
/** Stores the ordered child content. */
|
|
43
|
+
content: PluginModalContentItem[];
|
|
44
|
+
/** Stores the optional spacing between children. */
|
|
45
|
+
gap?: string;
|
|
46
|
+
/** Stores the alignment hint along the main axis. */
|
|
47
|
+
align?: ModalContentAlign;
|
|
48
|
+
/** Stores whether children may wrap onto multiple rows. */
|
|
49
|
+
wrap?: boolean;
|
|
50
|
+
}
|
|
51
|
+
/** Describes one vertical box rendered inside a modal. */
|
|
52
|
+
export interface ModalVerticalBoxDefinition {
|
|
53
|
+
/** Always stores `vertical-box`. */
|
|
54
|
+
type: 'vertical-box';
|
|
55
|
+
/** Stores the ordered child content. */
|
|
56
|
+
content: PluginModalContentItem[];
|
|
57
|
+
/** Stores the optional spacing between children. */
|
|
58
|
+
gap?: string;
|
|
59
|
+
}
|
|
60
|
+
/** Describes one grid rendered inside a modal. */
|
|
61
|
+
export interface ModalGridDefinition {
|
|
62
|
+
/** Always stores `grid`. */
|
|
63
|
+
type: 'grid';
|
|
64
|
+
/** Stores the ordered child content. */
|
|
65
|
+
content: PluginModalContentItem[];
|
|
66
|
+
/** Stores the CSS grid column template. */
|
|
67
|
+
columns: string;
|
|
68
|
+
/** Stores the optional spacing between cells. */
|
|
69
|
+
gap?: string;
|
|
70
|
+
}
|
|
38
71
|
/** Describes one button rendered inside a modal body. */
|
|
39
72
|
export interface ModalButtonItemDefinition extends ModalButtonDefinition {
|
|
40
73
|
/** Always stores `button`. */
|
|
@@ -119,7 +152,7 @@ export interface ModalListDefinition {
|
|
|
119
152
|
items: ModalListRowDefinition[];
|
|
120
153
|
}
|
|
121
154
|
/** Describes one plugin modal content item. */
|
|
122
|
-
export type PluginModalContentItem = ModalTextDefinition | ModalSeparatorDefinition | ModalButtonItemDefinition | ModalInputDefinition | ModalSelectDefinition | ModalListDefinition;
|
|
155
|
+
export type PluginModalContentItem = ModalTextDefinition | ModalSeparatorDefinition | ModalHorizontalBoxDefinition | ModalVerticalBoxDefinition | ModalGridDefinition | ModalButtonItemDefinition | ModalInputDefinition | ModalSelectDefinition | ModalListDefinition;
|
|
123
156
|
/** Describes the structured payload used to render a plugin modal. */
|
|
124
157
|
export interface PluginModalDefinition {
|
|
125
158
|
/** Stores the modal title. */
|
package/package.json
CHANGED
package/src/lib/runtime/modal.ts
CHANGED
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
3
3
|
|
|
4
4
|
import type {
|
|
5
|
-
ModalButtonDefinition,
|
|
6
5
|
ModalButtonVariant,
|
|
7
6
|
ModalContentAlign,
|
|
8
|
-
|
|
7
|
+
ModalGridDefinition,
|
|
9
8
|
ModalInputKind,
|
|
10
|
-
|
|
9
|
+
ModalHorizontalBoxDefinition,
|
|
11
10
|
ModalListRowDefinition,
|
|
12
|
-
|
|
11
|
+
ModalVerticalBoxDefinition,
|
|
13
12
|
ModalSelectOptionDefinition,
|
|
14
13
|
PluginModalContentItem,
|
|
15
14
|
PluginModalDefinition,
|
|
@@ -71,6 +70,30 @@ export interface ModalBuilderListOptions {
|
|
|
71
70
|
items: ModalListRowDefinition[];
|
|
72
71
|
}
|
|
73
72
|
|
|
73
|
+
/** Describes the options accepted by `ModalBuilder.horizontalBox()`. */
|
|
74
|
+
export interface ModalBuilderHorizontalBoxOptions {
|
|
75
|
+
/** Stores the spacing between children. */
|
|
76
|
+
gap?: string;
|
|
77
|
+
/** Stores the alignment hint for the main axis. */
|
|
78
|
+
align?: ModalContentAlign;
|
|
79
|
+
/** Stores whether children may wrap. */
|
|
80
|
+
wrap?: boolean;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** Describes the options accepted by `ModalBuilder.verticalBox()`. */
|
|
84
|
+
export interface ModalBuilderVerticalBoxOptions {
|
|
85
|
+
/** Stores the spacing between children. */
|
|
86
|
+
gap?: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Describes the options accepted by `ModalBuilder.grid()`. */
|
|
90
|
+
export interface ModalBuilderGridOptions {
|
|
91
|
+
/** Stores the CSS grid column template. */
|
|
92
|
+
columns: string;
|
|
93
|
+
/** Stores the spacing between cells. */
|
|
94
|
+
gap?: string;
|
|
95
|
+
}
|
|
96
|
+
|
|
74
97
|
/** Builds a structured modal definition with a fluent class API. */
|
|
75
98
|
export class ModalBuilder {
|
|
76
99
|
private readonly definition: PluginModalDefinition;
|
|
@@ -100,6 +123,39 @@ export class ModalBuilder {
|
|
|
100
123
|
return this;
|
|
101
124
|
}
|
|
102
125
|
|
|
126
|
+
/** Adds a horizontal box to the modal body. */
|
|
127
|
+
horizontalBox(content: PluginModalContentItem[], options: ModalBuilderHorizontalBoxOptions = {}): this {
|
|
128
|
+
this.definition.content.push({
|
|
129
|
+
type: 'horizontal-box',
|
|
130
|
+
content: cloneContent(content),
|
|
131
|
+
...(options.gap ? { gap: options.gap } : {}),
|
|
132
|
+
...(options.align ? { align: options.align } : {}),
|
|
133
|
+
...(options.wrap !== undefined ? { wrap: options.wrap } : {}),
|
|
134
|
+
} as ModalHorizontalBoxDefinition);
|
|
135
|
+
return this;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Adds a vertical box to the modal body. */
|
|
139
|
+
verticalBox(content: PluginModalContentItem[], options: ModalBuilderVerticalBoxOptions = {}): this {
|
|
140
|
+
this.definition.content.push({
|
|
141
|
+
type: 'vertical-box',
|
|
142
|
+
content: cloneContent(content),
|
|
143
|
+
...(options.gap ? { gap: options.gap } : {}),
|
|
144
|
+
} as ModalVerticalBoxDefinition);
|
|
145
|
+
return this;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** Adds a grid container to the modal body. */
|
|
149
|
+
grid(content: PluginModalContentItem[], options: ModalBuilderGridOptions): this {
|
|
150
|
+
this.definition.content.push({
|
|
151
|
+
type: 'grid',
|
|
152
|
+
content: cloneContent(content),
|
|
153
|
+
columns: String(options.columns || '').trim(),
|
|
154
|
+
...(options.gap ? { gap: options.gap } : {}),
|
|
155
|
+
} as ModalGridDefinition);
|
|
156
|
+
return this;
|
|
157
|
+
}
|
|
158
|
+
|
|
103
159
|
/** Adds a button to the modal body. */
|
|
104
160
|
button(id: string, content: string, options: ModalBuilderButtonOptions = {}): this {
|
|
105
161
|
this.definition.content.push({
|
|
@@ -159,7 +215,7 @@ export class ModalBuilder {
|
|
|
159
215
|
build(): PluginModalDefinition {
|
|
160
216
|
return {
|
|
161
217
|
title: this.definition.title,
|
|
162
|
-
content: this.definition.content
|
|
218
|
+
content: cloneContent(this.definition.content),
|
|
163
219
|
};
|
|
164
220
|
}
|
|
165
221
|
|
|
@@ -168,3 +224,36 @@ export class ModalBuilder {
|
|
|
168
224
|
return this.build();
|
|
169
225
|
}
|
|
170
226
|
}
|
|
227
|
+
|
|
228
|
+
/** Clones modal content recursively so nested containers stay isolated. */
|
|
229
|
+
function cloneContent(content: PluginModalContentItem[]): PluginModalContentItem[] {
|
|
230
|
+
return Array.isArray(content) ? content.map((item) => cloneItem(item)) : [];
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** Clones one modal content item recursively. */
|
|
234
|
+
function cloneItem(item: PluginModalContentItem): PluginModalContentItem {
|
|
235
|
+
if (!item || typeof item !== 'object') return item;
|
|
236
|
+
|
|
237
|
+
if (item.type === 'horizontal-box') {
|
|
238
|
+
return {
|
|
239
|
+
...item,
|
|
240
|
+
content: cloneContent(item.content),
|
|
241
|
+
} as ModalHorizontalBoxDefinition;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
if (item.type === 'vertical-box') {
|
|
245
|
+
return {
|
|
246
|
+
...item,
|
|
247
|
+
content: cloneContent(item.content),
|
|
248
|
+
} as ModalVerticalBoxDefinition;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
if (item.type === 'grid') {
|
|
252
|
+
return {
|
|
253
|
+
...item,
|
|
254
|
+
content: cloneContent(item.content),
|
|
255
|
+
} as ModalGridDefinition;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
return { ...item };
|
|
259
|
+
}
|
package/src/lib/types/modal.ts
CHANGED
|
@@ -44,6 +44,42 @@ export interface ModalSeparatorDefinition {
|
|
|
44
44
|
type: 'separator';
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/** Describes one horizontal box rendered inside a modal. */
|
|
48
|
+
export interface ModalHorizontalBoxDefinition {
|
|
49
|
+
/** Always stores `horizontal-box`. */
|
|
50
|
+
type: 'horizontal-box';
|
|
51
|
+
/** Stores the ordered child content. */
|
|
52
|
+
content: PluginModalContentItem[];
|
|
53
|
+
/** Stores the optional spacing between children. */
|
|
54
|
+
gap?: string;
|
|
55
|
+
/** Stores the alignment hint along the main axis. */
|
|
56
|
+
align?: ModalContentAlign;
|
|
57
|
+
/** Stores whether children may wrap onto multiple rows. */
|
|
58
|
+
wrap?: boolean;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Describes one vertical box rendered inside a modal. */
|
|
62
|
+
export interface ModalVerticalBoxDefinition {
|
|
63
|
+
/** Always stores `vertical-box`. */
|
|
64
|
+
type: 'vertical-box';
|
|
65
|
+
/** Stores the ordered child content. */
|
|
66
|
+
content: PluginModalContentItem[];
|
|
67
|
+
/** Stores the optional spacing between children. */
|
|
68
|
+
gap?: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** Describes one grid rendered inside a modal. */
|
|
72
|
+
export interface ModalGridDefinition {
|
|
73
|
+
/** Always stores `grid`. */
|
|
74
|
+
type: 'grid';
|
|
75
|
+
/** Stores the ordered child content. */
|
|
76
|
+
content: PluginModalContentItem[];
|
|
77
|
+
/** Stores the CSS grid column template. */
|
|
78
|
+
columns: string;
|
|
79
|
+
/** Stores the optional spacing between cells. */
|
|
80
|
+
gap?: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
47
83
|
/** Describes one button rendered inside a modal body. */
|
|
48
84
|
export interface ModalButtonItemDefinition extends ModalButtonDefinition {
|
|
49
85
|
/** Always stores `button`. */
|
|
@@ -138,6 +174,9 @@ export interface ModalListDefinition {
|
|
|
138
174
|
export type PluginModalContentItem =
|
|
139
175
|
| ModalTextDefinition
|
|
140
176
|
| ModalSeparatorDefinition
|
|
177
|
+
| ModalHorizontalBoxDefinition
|
|
178
|
+
| ModalVerticalBoxDefinition
|
|
179
|
+
| ModalGridDefinition
|
|
141
180
|
| ModalButtonItemDefinition
|
|
142
181
|
| ModalInputDefinition
|
|
143
182
|
| ModalSelectDefinition
|
package/test/modal.test.ts
CHANGED
|
@@ -10,14 +10,83 @@ describe('ModalBuilder', () => {
|
|
|
10
10
|
it('builds a structured modal definition', () => {
|
|
11
11
|
const modal = new ModalBuilder('Manage Submodules')
|
|
12
12
|
.text('Hello, World!')
|
|
13
|
-
.
|
|
13
|
+
.verticalBox([
|
|
14
|
+
{
|
|
15
|
+
type: 'input',
|
|
16
|
+
id: 'path',
|
|
17
|
+
label: 'Submodule Path',
|
|
18
|
+
placeholder: 'libs/example',
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
type: 'grid',
|
|
22
|
+
columns: 'minmax(0, 1fr) minmax(0, 1fr)',
|
|
23
|
+
content: [
|
|
24
|
+
{
|
|
25
|
+
type: 'input',
|
|
26
|
+
id: 'name',
|
|
27
|
+
label: 'Submodule Name',
|
|
28
|
+
placeholder: 'example',
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
type: 'input',
|
|
32
|
+
id: 'branch',
|
|
33
|
+
label: 'Branch (optional)',
|
|
34
|
+
placeholder: 'main',
|
|
35
|
+
},
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
])
|
|
39
|
+
.horizontalBox(
|
|
40
|
+
[
|
|
41
|
+
{ type: 'button', id: 'new-button', content: 'Test button, push me!', align: 'centered' },
|
|
42
|
+
{ type: 'button', id: 'secondary-button', content: 'Refresh' },
|
|
43
|
+
],
|
|
44
|
+
{ align: 'centered', wrap: true },
|
|
45
|
+
)
|
|
14
46
|
.build();
|
|
15
47
|
|
|
16
48
|
assert.deepStrictEqual(modal, {
|
|
17
49
|
title: 'Manage Submodules',
|
|
18
50
|
content: [
|
|
19
51
|
{ type: 'text', content: 'Hello, World!' },
|
|
20
|
-
{
|
|
52
|
+
{
|
|
53
|
+
type: 'vertical-box',
|
|
54
|
+
content: [
|
|
55
|
+
{
|
|
56
|
+
type: 'input',
|
|
57
|
+
id: 'path',
|
|
58
|
+
label: 'Submodule Path',
|
|
59
|
+
placeholder: 'libs/example',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
type: 'grid',
|
|
63
|
+
columns: 'minmax(0, 1fr) minmax(0, 1fr)',
|
|
64
|
+
content: [
|
|
65
|
+
{
|
|
66
|
+
type: 'input',
|
|
67
|
+
id: 'name',
|
|
68
|
+
label: 'Submodule Name',
|
|
69
|
+
placeholder: 'example',
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
type: 'input',
|
|
73
|
+
id: 'branch',
|
|
74
|
+
label: 'Branch (optional)',
|
|
75
|
+
placeholder: 'main',
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
type: 'horizontal-box',
|
|
83
|
+
align: 'centered',
|
|
84
|
+
wrap: true,
|
|
85
|
+
content: [
|
|
86
|
+
{ type: 'button', id: 'new-button', content: 'Test button, push me!', align: 'centered' },
|
|
87
|
+
{ type: 'button', id: 'secondary-button', content: 'Refresh' },
|
|
88
|
+
],
|
|
89
|
+
},
|
|
21
90
|
],
|
|
22
91
|
});
|
|
23
92
|
});
|