@schukai/monster 3.115.4 → 3.116.1
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/CHANGELOG.md +19 -0
- package/package.json +1 -1
- package/source/components/datatable/stylesheet/dataset.mjs +1 -1
- package/source/components/datatable/stylesheet/datatable.mjs +1 -1
- package/source/components/form/field-set.mjs +2 -2
- package/source/components/form/login.mjs +97 -18
- package/source/components/host/overlay.mjs +4 -295
- package/source/components/layout/board.mjs +711 -0
- package/source/components/layout/overlay.mjs +320 -0
- package/source/components/layout/style/board.pcss +34 -0
- package/source/components/layout/style/tabs.pcss +2 -1
- package/source/components/layout/stylesheet/board.mjs +31 -0
- package/source/components/layout/stylesheet/tabs.mjs +1 -1
- package/source/components/style/skeleton.css +60 -20
- package/source/components/style/typography.css +2 -2
- package/source/components/stylesheet/skeleton.mjs +1 -1
- package/source/components/tree-menu/tree-menu.mjs +1 -1
- package/source/monster.mjs +3 -1
- package/source/types/version.mjs +1 -1
- package/test/cases/monster.mjs +1 -1
- package/test/web/test.html +2 -2
- package/test/web/tests.js +40 -36
- /package/source/components/{host → layout}/style/overlay.pcss +0 -0
- /package/source/components/{host → layout}/stylesheet/overlay.mjs +0 -0
@@ -414,10 +414,10 @@ function getTemplate() {
|
|
414
414
|
</div>
|
415
415
|
<div data-monster-role="container" part="container">
|
416
416
|
<div class="collapse-alignment" part="content">
|
417
|
-
<slot
|
417
|
+
<slot></slot>
|
418
418
|
</div>
|
419
419
|
<monster-collapse data-monster-role="collapse" part="collapse">
|
420
|
-
<slot name="extended"
|
420
|
+
<slot name="extended"></slot>
|
421
421
|
</monster-collapse>
|
422
422
|
</div>
|
423
423
|
</div>`;
|
@@ -1543,9 +1543,20 @@ function getTemplate() {
|
|
1543
1543
|
|
1544
1544
|
<monster-collapse data-monster-option-openByDefault="true"
|
1545
1545
|
data-monster-role="login-collapse"
|
1546
|
+
exportparts="control:collapse-login-control,
|
1547
|
+
container:collapse-login-container,
|
1548
|
+
deco:collapse-login-deco"
|
1546
1549
|
part="login-collapse"
|
1547
1550
|
>
|
1548
|
-
<monster-field-set
|
1551
|
+
<monster-field-set
|
1552
|
+
exportparts="
|
1553
|
+
control:field-set-login-control,
|
1554
|
+
header:field-set-login-header,
|
1555
|
+
title:field-set-login-title,
|
1556
|
+
container:field-set-login-container,
|
1557
|
+
content:field-set-login-content,
|
1558
|
+
collapse:field-set-login-collapse"
|
1559
|
+
part="login-field-set">
|
1549
1560
|
<slot name="login-header"></slot>
|
1550
1561
|
<label part="login-label" data-monster-replace="path:labels.username"></label>
|
1551
1562
|
<input type="text" name="username" autofocus autocomplete="off">
|
@@ -1555,6 +1566,13 @@ function getTemplate() {
|
|
1555
1566
|
<div data-monster-attributes="class path:classes.passwordInvalid"></div>
|
1556
1567
|
<monster-message-state-button id="loginButton"
|
1557
1568
|
part="login-button"
|
1569
|
+
exportparts="
|
1570
|
+
control:login-button-control,
|
1571
|
+
button:login-button-button,
|
1572
|
+
popper:login-button-popper,
|
1573
|
+
message:login-button-message,
|
1574
|
+
button-button:login-button-button,
|
1575
|
+
button-control:login-button-control"
|
1558
1576
|
data-monster-replace="path:labels.login"></monster-message-state-button>
|
1559
1577
|
<a href="#" data-monster-role="forgot-password-link" part="forgot-password-link"
|
1560
1578
|
data-monster-attributes="class path:features.forgotPassword | ?::hidden"
|
@@ -1564,19 +1582,37 @@ function getTemplate() {
|
|
1564
1582
|
|
1565
1583
|
|
1566
1584
|
</monster-collapse>
|
1567
|
-
<monster-collapse data-monster-role="forgot-password-collapse"
|
1568
|
-
|
1569
|
-
|
1585
|
+
<monster-collapse data-monster-role="forgot-password-collapse"
|
1586
|
+
exportparts="control:collapse-forgot-password-control,
|
1587
|
+
container:collapse-forgot-password-container,
|
1588
|
+
deco:collapse-forgot-password-deco"
|
1589
|
+
part="forgot-password-collapse">
|
1590
|
+
|
1591
|
+
<monster-field-set part="forgot-password-field-set"
|
1592
|
+
exportparts="
|
1593
|
+
control:field-set-forgot-password-control,
|
1594
|
+
header:field-set-forgot-password-header,
|
1595
|
+
title:field-set-forgot-password-title,
|
1596
|
+
container:field-set-forgot-password-container,
|
1597
|
+
content:field-set-forgot-password-content,
|
1598
|
+
collapse:field-set-forgot-password-collapse">
|
1570
1599
|
<slot name="forgot-password-header"></slot>
|
1571
1600
|
<label part="forgot-password-label" data-monster-replace="path:labels.mailAddress"></label>
|
1572
1601
|
<input type="email" name="email"
|
1573
1602
|
data-monster-attributes="accesskey path:accessKeys.username"
|
1574
1603
|
autocomplete="off">
|
1575
1604
|
<div data-monster-attributes="class path:classes.emailInvalid"></div>
|
1576
|
-
|
1577
|
-
|
1578
|
-
|
1579
|
-
|
1605
|
+
<monster-message-state-button id="requestLinkButton"
|
1606
|
+
part="request-link-button"
|
1607
|
+
exportparts="
|
1608
|
+
control:forgot-password-button-control,
|
1609
|
+
button:forgot-password-button-button,
|
1610
|
+
popper:forgot-password-button-popper,
|
1611
|
+
message:forgot-password-button-message,
|
1612
|
+
button-button:forgot-password-button-button,
|
1613
|
+
button-control:forgot-password-button-control"
|
1614
|
+
data-monster-attributes="accesskey path:accessKeys.password"
|
1615
|
+
data-monster-replace="path:labels.requestLink"></monster-message-state-button>
|
1580
1616
|
<a href="#"
|
1581
1617
|
data-monster-attributes="accesskey path:accessKeys.loginLink"
|
1582
1618
|
data-monster-role="login-link"
|
@@ -1586,18 +1622,38 @@ function getTemplate() {
|
|
1586
1622
|
</monster-field-set>
|
1587
1623
|
|
1588
1624
|
</monster-collapse>
|
1589
|
-
<monster-collapse data-monster-role="second-factor-collapse"
|
1590
|
-
|
1591
|
-
|
1625
|
+
<monster-collapse data-monster-role="second-factor-collapse"
|
1626
|
+
exportparts="control:collapse-second-factor-control,
|
1627
|
+
container:collapse-second-factor-container,
|
1628
|
+
deco:collapse-second-factor-deco"
|
1629
|
+
part="second-factor-collapse">
|
1630
|
+
|
1631
|
+
<monster-field-set part="second-factor-field-set"
|
1632
|
+
exportparts="
|
1633
|
+
control:field-set-second-factor-control,
|
1634
|
+
header:field-set-second-factor-header,
|
1635
|
+
title:field-set-second-factor-title,
|
1636
|
+
container:field-set-second-factor-container,
|
1637
|
+
content:field-set-second-factor-content,
|
1638
|
+
collapse:field-set-second-factor-collapse">
|
1592
1639
|
<slot name="second-factor-header"></slot>
|
1593
1640
|
<label part="second-factor-label" data-monster-replace="path:labels.secondFactor"></label>
|
1594
1641
|
<div>
|
1595
1642
|
<monster-digits data-monster-attributes="data-monster-option-digits path:digits"
|
1596
1643
|
id="secondFactorControl"></monster-digits>
|
1597
1644
|
</div>
|
1598
|
-
|
1599
|
-
|
1600
|
-
|
1645
|
+
<!-- SECOND FACTOR COLLAPSE -->
|
1646
|
+
<monster-message-state-button id="secondFactorButton"
|
1647
|
+
part="secondFactor-digits-button"
|
1648
|
+
exportparts="
|
1649
|
+
control:second-factor-button-control,
|
1650
|
+
button:second-factor-button-button,
|
1651
|
+
popper:second-factor-button-popper,
|
1652
|
+
message:second-factor-button-message,
|
1653
|
+
button-button:second-factor-button-button,
|
1654
|
+
button-control:second-factor-button-control"
|
1655
|
+
data-monster-replace="path:labels.sendSecondFactorDigits"></monster-message-state-button>
|
1656
|
+
|
1601
1657
|
<a href="#" data-monster-role="reset-login-process-link"
|
1602
1658
|
part="reset-login-process-link"
|
1603
1659
|
data-monster-replace="path:labels.resetLoginProcess"></a>
|
@@ -1605,9 +1661,20 @@ function getTemplate() {
|
|
1605
1661
|
</monster-field-set>
|
1606
1662
|
|
1607
1663
|
</monster-collapse>
|
1608
|
-
<monster-collapse data-monster-role="digits-collapse"
|
1609
|
-
|
1610
|
-
|
1664
|
+
<monster-collapse data-monster-role="digits-collapse"
|
1665
|
+
exportparts="control:collapse-digits-control,
|
1666
|
+
container:collapse-digits-container,
|
1667
|
+
deco:collapse-digits-deco"
|
1668
|
+
part="digits-collapse">
|
1669
|
+
|
1670
|
+
<monster-field-set part="digits-field-set"
|
1671
|
+
exportparts="
|
1672
|
+
control:field-set-digits-control,
|
1673
|
+
header:field-set-digits-header,
|
1674
|
+
title:field-set-digits-title,
|
1675
|
+
container:field-set-digits-container,
|
1676
|
+
content:field-set-digits-content,
|
1677
|
+
collapse:field-set-digits-collapse">
|
1611
1678
|
<slot name="digits-header"></slot>
|
1612
1679
|
<label part="digits-label" data-monster-replace="path:labels.digits"></label>
|
1613
1680
|
<div>
|
@@ -1616,6 +1683,13 @@ function getTemplate() {
|
|
1616
1683
|
</div>
|
1617
1684
|
<monster-message-state-button id="digitsButton"
|
1618
1685
|
part="digits-button"
|
1686
|
+
exportparts="
|
1687
|
+
control:digits-button-control,
|
1688
|
+
button:digits-button-button,
|
1689
|
+
popper:digits-button-popper,
|
1690
|
+
message:digits-button-message,
|
1691
|
+
button-button:digits-button-button,
|
1692
|
+
button-control:digits-button-control"
|
1619
1693
|
data-monster-replace="path:labels.sendDigits"></monster-message-state-button>
|
1620
1694
|
<a href="#" data-monster-role="reset-login-process-link"
|
1621
1695
|
part="reset-login-process-link"
|
@@ -1624,7 +1698,12 @@ function getTemplate() {
|
|
1624
1698
|
</monster-field-set>
|
1625
1699
|
|
1626
1700
|
</monster-collapse>
|
1627
|
-
<monster-collapse data-monster-role="logged-in-collapse"
|
1701
|
+
<monster-collapse data-monster-role="logged-in-collapse"
|
1702
|
+
exportparts="
|
1703
|
+
control:collapse-success-control,
|
1704
|
+
container:collapse-success-container,
|
1705
|
+
deco:collapse-success-deco"
|
1706
|
+
part="logged-in-collapse">
|
1628
1707
|
<div>
|
1629
1708
|
<slot name="logged-in-header"></slot>
|
1630
1709
|
<ul data-monster-insert="urls path:successUrls"></ul>
|
@@ -12,303 +12,12 @@
|
|
12
12
|
* SPDX-License-Identifier: AGPL-3.0
|
13
13
|
*/
|
14
14
|
|
15
|
-
import {
|
16
|
-
assembleMethodSymbol,
|
17
|
-
CustomElement,
|
18
|
-
registerCustomElement,
|
19
|
-
} from "../../dom/customelement.mjs";
|
20
|
-
import "../notify/notify.mjs";
|
21
|
-
import { OverlayStyleSheet } from "./stylesheet/overlay.mjs";
|
22
|
-
import { ATTRIBUTE_ROLE } from "../../dom/constants.mjs";
|
23
|
-
import {
|
24
|
-
findTargetElementFromEvent,
|
25
|
-
fireCustomEvent,
|
26
|
-
} from "../../dom/events.mjs";
|
27
|
-
import { instanceSymbol } from "../../constants.mjs";
|
28
|
-
|
15
|
+
import { Overlay as NewOverlay } from "../layout/overlay.mjs";
|
29
16
|
export { Overlay };
|
30
17
|
|
31
18
|
/**
|
32
|
-
* @
|
33
|
-
* @type {symbol}
|
34
|
-
*/
|
35
|
-
const overlayElementSymbol = Symbol("overlayElement");
|
36
|
-
|
37
|
-
/**
|
38
|
-
* @private
|
39
|
-
* @type {symbol}
|
40
|
-
*/
|
41
|
-
const overlayCloseElementSymbol = Symbol("overlayCloserElement");
|
42
|
-
|
43
|
-
/**
|
44
|
-
* @private
|
45
|
-
* @type {symbol}
|
46
|
-
*/
|
47
|
-
const overlayOpenElementSymbol = Symbol("overlayOpenElement");
|
48
|
-
|
49
|
-
/**
|
50
|
-
* @private
|
51
|
-
* @type {symbol}
|
52
|
-
*/
|
53
|
-
const closeEventHandlerSymbol = Symbol("closeEventHandler");
|
54
|
-
|
55
|
-
/**
|
56
|
-
* @private
|
57
|
-
* @type {symbol}
|
58
|
-
*/
|
59
|
-
const openEventHandlerSymbol = Symbol("openEventHandler");
|
60
|
-
|
61
|
-
/**
|
62
|
-
* @private
|
63
|
-
* @type {string}
|
64
|
-
*/
|
65
|
-
const ATTRIBUTE_VALUE_OVERLAY_OPEN = "overlay-open";
|
66
|
-
|
67
|
-
/**
|
68
|
-
* The Overlay component is used to show an overlay and a button to open the overlay.
|
69
|
-
*
|
19
|
+
* @since 1.10.0
|
70
20
|
* @copyright schukai GmbH
|
71
|
-
* @
|
72
|
-
* @fires monster-overlay-before-open
|
73
|
-
* @fires monster-overlay-open
|
74
|
-
* @fires monster-overlay-before-close
|
75
|
-
* @fires monster-overlay-closed
|
21
|
+
* @deprecated since 3.116.0 use Layout/Overlay instead
|
76
22
|
*/
|
77
|
-
class Overlay extends
|
78
|
-
/**
|
79
|
-
* This method is called by the `instanceof` operator.
|
80
|
-
* @return {symbol}
|
81
|
-
*/
|
82
|
-
static get [instanceSymbol]() {
|
83
|
-
return Symbol.for("@schukai/monster/components/host/overlay@@instance");
|
84
|
-
}
|
85
|
-
|
86
|
-
/**
|
87
|
-
* To set the options via the HTML tag, the attribute `data-monster-options` must be used.
|
88
|
-
* @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
|
89
|
-
*
|
90
|
-
* The individual configuration values can be found in the table.
|
91
|
-
*
|
92
|
-
* @property {Object} templates Template definitions
|
93
|
-
* @property {string} templates.main Main template
|
94
|
-
* @property {Object} container Container definitions
|
95
|
-
* @property {array} container Container definitions
|
96
|
-
* @property {string} container[].name Name of the container
|
97
|
-
* @property {string} container[].content Content of the container
|
98
|
-
* @property {string} container[].class Css class of the container
|
99
|
-
* @property {Object} classes Css classes
|
100
|
-
* @property {string} classes.body Css class to hide the body. This class is removed when the component is ready.
|
101
|
-
* @property {string} classes.overlay Css class to hide the overlay. This class is removed when the component is ready.
|
102
|
-
* @property {Object} features Feature definitions
|
103
|
-
* @property {boolean} features.escapeKey If true the overlay can be closed with the escape key
|
104
|
-
* @property {boolean} features.openButton If true the overlay can be opened with a button
|
105
|
-
*/
|
106
|
-
get defaults() {
|
107
|
-
return Object.assign({}, super.defaults, {
|
108
|
-
templates: {
|
109
|
-
main: getTemplate(),
|
110
|
-
},
|
111
|
-
overlay: [
|
112
|
-
{
|
113
|
-
name: "content",
|
114
|
-
content: "<slot></slot>",
|
115
|
-
class: "",
|
116
|
-
},
|
117
|
-
],
|
118
|
-
classes: {
|
119
|
-
body: "hidden",
|
120
|
-
overlay: "hide-empty",
|
121
|
-
},
|
122
|
-
features: {
|
123
|
-
escapeKey: true,
|
124
|
-
openButton: true,
|
125
|
-
},
|
126
|
-
});
|
127
|
-
}
|
128
|
-
|
129
|
-
/**
|
130
|
-
* @private
|
131
|
-
*/
|
132
|
-
connectedCallback() {
|
133
|
-
super.connectedCallback();
|
134
|
-
|
135
|
-
/**
|
136
|
-
* show the scroll bar always
|
137
|
-
* @type {string}
|
138
|
-
*/
|
139
|
-
document.documentElement.style.overflowY = "scroll";
|
140
|
-
|
141
|
-
const classNames = this.getOption("classes.body");
|
142
|
-
|
143
|
-
if (document.body.classList.contains(classNames)) {
|
144
|
-
document.body.classList.remove(classNames);
|
145
|
-
}
|
146
|
-
}
|
147
|
-
|
148
|
-
/**
|
149
|
-
*
|
150
|
-
* @return {Monster.Components.Host.Overlay}
|
151
|
-
*/
|
152
|
-
[assembleMethodSymbol]() {
|
153
|
-
super[assembleMethodSymbol]();
|
154
|
-
|
155
|
-
initControlReferences.call(this);
|
156
|
-
initEventHandler.call(this);
|
157
|
-
}
|
158
|
-
|
159
|
-
/**
|
160
|
-
*
|
161
|
-
* @return {Monster.Components.Host.Overlay}
|
162
|
-
*/
|
163
|
-
toggle() {
|
164
|
-
if (this[overlayElementSymbol].classList.contains("open")) {
|
165
|
-
this.close();
|
166
|
-
} else {
|
167
|
-
this.open();
|
168
|
-
}
|
169
|
-
return this;
|
170
|
-
}
|
171
|
-
|
172
|
-
/**
|
173
|
-
* @return {Monster.Components.Host.Overlay}
|
174
|
-
* @fires monster-overlay-before-open
|
175
|
-
* @fires monster-overlay-open
|
176
|
-
* @fires monster-overlay-before-close
|
177
|
-
* @fires monster-overlay-closed
|
178
|
-
*/
|
179
|
-
open() {
|
180
|
-
fireCustomEvent(this, "monster-overlay-before-open", {});
|
181
|
-
|
182
|
-
this[overlayElementSymbol].classList.remove("hide-empty");
|
183
|
-
|
184
|
-
setTimeout(() => {
|
185
|
-
this[overlayElementSymbol].classList.add("open");
|
186
|
-
setTimeout(() => {
|
187
|
-
fireCustomEvent(this, "monster-overlay-open", {});
|
188
|
-
}, 0);
|
189
|
-
}, 0);
|
190
|
-
|
191
|
-
return this;
|
192
|
-
}
|
193
|
-
|
194
|
-
/**
|
195
|
-
* @return {Monster.Components.Host.Overlay}
|
196
|
-
*/
|
197
|
-
close() {
|
198
|
-
fireCustomEvent(this, "monster-overlay-before-close", {});
|
199
|
-
setTimeout(() => {
|
200
|
-
this[overlayElementSymbol].classList.remove("open");
|
201
|
-
setTimeout(() => {
|
202
|
-
fireCustomEvent(this, "monster-overlay-closed", {});
|
203
|
-
}, 0);
|
204
|
-
}, 0);
|
205
|
-
return this;
|
206
|
-
}
|
207
|
-
|
208
|
-
/**
|
209
|
-
*
|
210
|
-
* @return {string}
|
211
|
-
*/
|
212
|
-
static getTag() {
|
213
|
-
return "monster-overlay";
|
214
|
-
}
|
215
|
-
|
216
|
-
/**
|
217
|
-
* @return {CSSStyleSheet[]}
|
218
|
-
*/
|
219
|
-
static getCSSStyleSheet() {
|
220
|
-
return [OverlayStyleSheet];
|
221
|
-
}
|
222
|
-
}
|
223
|
-
|
224
|
-
/**
|
225
|
-
* @private
|
226
|
-
* @return {Select}
|
227
|
-
* @throws {Error} no shadow-root is defined
|
228
|
-
*/
|
229
|
-
function initControlReferences() {
|
230
|
-
if (!this.shadowRoot) {
|
231
|
-
throw new Error("no shadow-root is defined");
|
232
|
-
}
|
233
|
-
|
234
|
-
this[overlayElementSymbol] = this.shadowRoot.getElementById("overlay");
|
235
|
-
this[overlayCloseElementSymbol] = this.shadowRoot.querySelector(
|
236
|
-
"[data-monster-role=overlay-close]",
|
237
|
-
);
|
238
|
-
this[overlayOpenElementSymbol] = this.shadowRoot.querySelector(
|
239
|
-
"[data-monster-role=overlay-open]",
|
240
|
-
);
|
241
|
-
}
|
242
|
-
|
243
|
-
/**
|
244
|
-
* @private
|
245
|
-
*/
|
246
|
-
function initEventHandler() {
|
247
|
-
/**
|
248
|
-
* @param {Event} event
|
249
|
-
*/
|
250
|
-
this[closeEventHandlerSymbol] = (event) => {
|
251
|
-
this.close();
|
252
|
-
};
|
253
|
-
|
254
|
-
this[overlayCloseElementSymbol].addEventListener(
|
255
|
-
"click",
|
256
|
-
this[closeEventHandlerSymbol],
|
257
|
-
);
|
258
|
-
|
259
|
-
/**
|
260
|
-
* @param {Event} event
|
261
|
-
*/
|
262
|
-
this[openEventHandlerSymbol] = (event) => {
|
263
|
-
const element = findTargetElementFromEvent(
|
264
|
-
event,
|
265
|
-
ATTRIBUTE_ROLE,
|
266
|
-
ATTRIBUTE_VALUE_OVERLAY_OPEN,
|
267
|
-
);
|
268
|
-
if (element) {
|
269
|
-
this.open();
|
270
|
-
}
|
271
|
-
};
|
272
|
-
|
273
|
-
this.addEventListener("click", this[openEventHandlerSymbol]);
|
274
|
-
|
275
|
-
if (this.getOption("features.escapeKey") === true) {
|
276
|
-
this.addEventListener("keydown", (event) => {
|
277
|
-
if (event.key === "Escape") {
|
278
|
-
const isNotCombinedKey = !(
|
279
|
-
event.ctrlKey ||
|
280
|
-
event.altKey ||
|
281
|
-
event.shiftKey
|
282
|
-
);
|
283
|
-
if (isNotCombinedKey) {
|
284
|
-
this.toggleOverlay();
|
285
|
-
}
|
286
|
-
}
|
287
|
-
});
|
288
|
-
}
|
289
|
-
|
290
|
-
return this;
|
291
|
-
}
|
292
|
-
|
293
|
-
/**
|
294
|
-
* @private
|
295
|
-
* @return {string}
|
296
|
-
*/
|
297
|
-
function getTemplate() {
|
298
|
-
// language=HTML
|
299
|
-
return `
|
300
|
-
<template id="host-overlay">
|
301
|
-
<div data-monster-replace="path:host-overlay.content"
|
302
|
-
data-monster-attributes="part path:host-overlay.name, data-monster-role path:host-container.overlay"></div>
|
303
|
-
</template>
|
304
|
-
|
305
|
-
<div data-monster-role="overlay-open" part="open"
|
306
|
-
data-monster-attributes="class path:features.openButton | if:visible:hidden"></div>
|
307
|
-
|
308
|
-
<div id="overlay" data-monster-role="overlay" part="overlay" data-monster-insert="host-overlay path:overlay"
|
309
|
-
data-monster-attributes="class path:classes.overlay">
|
310
|
-
<div data-monster-role="overlay-close" part="close"></div>
|
311
|
-
</div>`;
|
312
|
-
}
|
313
|
-
|
314
|
-
registerCustomElement(Overlay);
|
23
|
+
class Overlay extends NewOverlay {}
|