@schukai/monster 3.73.5 → 3.73.6

Sign up to get free protection for your applications and to get access to all the features.
package/CHANGELOG.md CHANGED
@@ -2,11 +2,19 @@
2
2
 
3
3
 
4
4
 
5
+ ## [3.73.6] - 2024-07-31
6
+
7
+ ### Bug Fixes
8
+
9
+ - repair url in tests [#230](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/230)
10
+ - improvement of the tree menu to avoid recursion. [#230](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/230)
11
+
12
+
5
13
  ## [3.73.5] - 2024-07-02
6
14
 
7
15
  ### Bug Fixes
8
16
 
9
- - originValues in the savebutton is now reset.
17
+ - originValues in the save button is now reset.
10
18
 
11
19
  ## [3.73.4] - 2024-07-02
12
20
 
package/package.json CHANGED
@@ -1 +1 @@
1
- {"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.6.7","@popperjs/core":"^2.11.8"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"3.73.5"}
1
+ {"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.6.7","@popperjs/core":"^2.11.8"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"3.73.6"}
@@ -12,33 +12,33 @@
12
12
  * SPDX-License-Identifier: AGPL-3.0
13
13
  */
14
14
 
15
- import {instanceSymbol, internalSymbol} from "../../constants.mjs";
16
- import {diff} from "../../data/diff.mjs";
17
- import {addAttributeToken} from "../../dom/attributes.mjs";
18
- import {ATTRIBUTE_ERRORMESSAGE} from "../../dom/constants.mjs";
15
+ import { instanceSymbol, internalSymbol } from "../../constants.mjs";
16
+ import { diff } from "../../data/diff.mjs";
17
+ import { addAttributeToken } from "../../dom/attributes.mjs";
18
+ import { ATTRIBUTE_ERRORMESSAGE } from "../../dom/constants.mjs";
19
19
  import {
20
- assembleMethodSymbol,
21
- CustomElement,
22
- attributeObserverSymbol,
23
- registerCustomElement,
20
+ assembleMethodSymbol,
21
+ CustomElement,
22
+ attributeObserverSymbol,
23
+ registerCustomElement,
24
24
  } from "../../dom/customelement.mjs";
25
- import {findElementWithSelectorUpwards} from "../../dom/util.mjs";
26
- import {isString, isArray} from "../../types/is.mjs";
27
- import {Observer} from "../../types/observer.mjs";
28
- import {TokenList} from "../../types/tokenlist.mjs";
29
- import {clone} from "../../util/clone.mjs";
30
- import {State} from "../form/types/state.mjs";
31
- import {ATTRIBUTE_DATASOURCE_SELECTOR} from "./constants.mjs";
32
- import {Datasource} from "./datasource.mjs";
33
- import {BadgeStyleSheet} from "../stylesheet/badge.mjs";
34
- import {SaveButtonStyleSheet} from "./stylesheet/save-button.mjs";
25
+ import { findElementWithSelectorUpwards } from "../../dom/util.mjs";
26
+ import { isString, isArray } from "../../types/is.mjs";
27
+ import { Observer } from "../../types/observer.mjs";
28
+ import { TokenList } from "../../types/tokenlist.mjs";
29
+ import { clone } from "../../util/clone.mjs";
30
+ import { State } from "../form/types/state.mjs";
31
+ import { ATTRIBUTE_DATASOURCE_SELECTOR } from "./constants.mjs";
32
+ import { Datasource } from "./datasource.mjs";
33
+ import { BadgeStyleSheet } from "../stylesheet/badge.mjs";
34
+ import { SaveButtonStyleSheet } from "./stylesheet/save-button.mjs";
35
35
 
36
36
  import {
37
- handleDataSourceChanges,
38
- datasourceLinkedElementSymbol,
37
+ handleDataSourceChanges,
38
+ datasourceLinkedElementSymbol,
39
39
  } from "./util.mjs";
40
40
 
41
- export {SaveButton};
41
+ export { SaveButton };
42
42
 
43
43
  /**
44
44
  * @private
@@ -59,185 +59,187 @@ const originValuesSymbol = Symbol("originValues");
59
59
  const badgeElementSymbol = Symbol("badgeElement");
60
60
 
61
61
  class SaveButton extends CustomElement {
62
- /**
63
- * This method is called by the `instanceof` operator.
64
- * @returns {symbol}
65
- */
66
- static get [instanceSymbol]() {
67
- return Symbol.for(
68
- "@schukai/monster/components/datasource/save-button@@instance",
69
- );
70
- }
71
-
72
- /**
73
- * To set the options via the html tag the attribute `data-monster-options` must be used.
74
- * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
75
- *
76
- * The individual configuration values can be found in the table.
77
- *
78
- * @property {Object} templates Template definitions
79
- * @property {string} templates.main Main template
80
- * @property {object} datasource The datasource
81
- * @property {string} datasource.selector The selector of the datasource
82
- * @property {string} labels.button The button label
83
- * @property {Object} classes The classes
84
- * @property {string} classes.bar The bar class
85
- * @property {string} classes.badge The badge class
86
- * @property {Array} ignoreChanges The ignore changes (regex)
87
- * @property {Array} data The data
88
- * @return {Object}
89
- */
90
- get defaults() {
91
- const obj = Object.assign({}, super.defaults, {
92
- templates: {
93
- main: getTemplate(),
94
- },
95
-
96
- labels: {
97
- button: "save",
98
- },
99
-
100
- classes: {
101
- bar: "monster-button-primary",
102
- badge: "monster-badge-secondary hidden",
103
- },
104
-
105
- datasource: {
106
- selector: null,
107
- },
108
-
109
- changes: "0",
110
-
111
- ignoreChanges: [],
112
-
113
- data: {},
114
-
115
- disabled: false,
116
- });
117
-
118
- updateOptionsFromArguments.call(this, obj);
119
- return obj;
120
- }
121
-
122
- /**
123
- *
124
- * @return {string}
125
- */
126
- static getTag() {
127
- return "monster-datasource-save-button";
128
- }
129
-
130
- /**
131
- * This method is responsible for assembling the component.
132
- *
133
- * It calls the parent's assemble method first, then initializes control references and event handlers.
134
- * If the `datasource.selector` option is provided and is a string, it searches for the corresponding
135
- * element in the DOM using that selector.
136
- *
137
- * If the selector matches exactly one element, it checks if the element is an instance of the `Datasource` class.
138
- *
139
- * If it is, the component's `datasourceLinkedElementSymbol` property is set to the element, and the component
140
- * attaches an observer to the datasource's changes.
141
- *
142
- * The observer is a function that calls the `handleDataSourceChanges` method in the context of the component.
143
- * Additionally, the component attaches an observer to itself, which also calls the `handleDataSourceChanges`
144
- * method in the component's context.
145
- */
146
- [assembleMethodSymbol]() {
147
- super[assembleMethodSymbol]();
148
- const self = this;
149
-
150
- initControlReferences.call(this);
151
- initEventHandler.call(this);
152
-
153
- const selector = this.getOption("datasource.selector");
154
-
155
- if (isString(selector)) {
156
- const element = findElementWithSelectorUpwards(this, selector);
157
- if (element === null) {
158
- throw new Error("the selector must match exactly one element");
159
- }
160
-
161
- if (!(element instanceof Datasource)) {
162
- throw new TypeError("the element must be a datasource");
163
- }
164
-
165
- this[datasourceLinkedElementSymbol] = element;
166
- element.datasource.attachObserver(
167
- new Observer(handleDataSourceChanges.bind(this)),
168
- );
169
-
170
- self[originValuesSymbol] = null;
171
-
172
- element.datasource.attachObserver(
173
- new Observer(function () {
174
- if (!self[originValuesSymbol]) {
175
- self[originValuesSymbol] = clone(self[datasourceLinkedElementSymbol].data);
176
- }
177
-
178
- const currentValues = this.getRealSubject();
179
- const ignoreChanges = self.getOption("ignoreChanges");
180
-
181
- const result = diff(self[originValuesSymbol], currentValues);
182
- if (isArray(ignoreChanges) && ignoreChanges.length > 0) {
183
- const itemsToRemove = [];
184
- for (const item of result) {
185
- for (const ignorePattern of ignoreChanges) {
186
- const p = new RegExp(ignorePattern);
187
- if (p.test(item.path)) {
188
- itemsToRemove.push(item);
189
- break;
190
- }
191
- }
192
- }
193
-
194
- for (const itemToRemove of itemsToRemove) {
195
- const index = result.indexOf(itemToRemove);
196
- if (index > -1) {
197
- result.splice(index, 1);
198
- }
199
- }
200
- }
201
-
202
- if (isArray(result) && result.length > 0) {
203
- self[stateButtonElementSymbol].setState("changed");
204
- self[stateButtonElementSymbol].setOption("disabled", false);
205
- self.setOption("changes", result.length);
206
- self.setOption(
207
- "classes.badge",
208
- new TokenList(self.getOption("classes.badge"))
209
- .remove("hidden")
210
- .toString(),
211
- );
212
- } else {
213
- self[stateButtonElementSymbol].removeState();
214
- self[stateButtonElementSymbol].setOption("disabled", true);
215
- self.setOption("changes", 0);
216
- self.setOption(
217
- "classes.badge",
218
- new TokenList(self.getOption("classes.badge"))
219
- .add("hidden")
220
- .toString(),
221
- );
222
- }
223
- }),
224
- );
225
- }
226
-
227
- this.attachObserver(
228
- new Observer(() => {
229
- handleDataSourceChanges.call(this);
230
- }),
231
- );
232
- }
233
-
234
- /**
235
- *
236
- * @return [CSSStyleSheet]
237
- */
238
- static getCSSStyleSheet() {
239
- return [SaveButtonStyleSheet, BadgeStyleSheet];
240
- }
62
+ /**
63
+ * This method is called by the `instanceof` operator.
64
+ * @returns {symbol}
65
+ */
66
+ static get [instanceSymbol]() {
67
+ return Symbol.for(
68
+ "@schukai/monster/components/datasource/save-button@@instance",
69
+ );
70
+ }
71
+
72
+ /**
73
+ * To set the options via the html tag the attribute `data-monster-options` must be used.
74
+ * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
75
+ *
76
+ * The individual configuration values can be found in the table.
77
+ *
78
+ * @property {Object} templates Template definitions
79
+ * @property {string} templates.main Main template
80
+ * @property {object} datasource The datasource
81
+ * @property {string} datasource.selector The selector of the datasource
82
+ * @property {string} labels.button The button label
83
+ * @property {Object} classes The classes
84
+ * @property {string} classes.bar The bar class
85
+ * @property {string} classes.badge The badge class
86
+ * @property {Array} ignoreChanges The ignore changes (regex)
87
+ * @property {Array} data The data
88
+ * @return {Object}
89
+ */
90
+ get defaults() {
91
+ const obj = Object.assign({}, super.defaults, {
92
+ templates: {
93
+ main: getTemplate(),
94
+ },
95
+
96
+ labels: {
97
+ button: "save",
98
+ },
99
+
100
+ classes: {
101
+ bar: "monster-button-primary",
102
+ badge: "monster-badge-secondary hidden",
103
+ },
104
+
105
+ datasource: {
106
+ selector: null,
107
+ },
108
+
109
+ changes: "0",
110
+
111
+ ignoreChanges: [],
112
+
113
+ data: {},
114
+
115
+ disabled: false,
116
+ });
117
+
118
+ updateOptionsFromArguments.call(this, obj);
119
+ return obj;
120
+ }
121
+
122
+ /**
123
+ *
124
+ * @return {string}
125
+ */
126
+ static getTag() {
127
+ return "monster-datasource-save-button";
128
+ }
129
+
130
+ /**
131
+ * This method is responsible for assembling the component.
132
+ *
133
+ * It calls the parent's assemble method first, then initializes control references and event handlers.
134
+ * If the `datasource.selector` option is provided and is a string, it searches for the corresponding
135
+ * element in the DOM using that selector.
136
+ *
137
+ * If the selector matches exactly one element, it checks if the element is an instance of the `Datasource` class.
138
+ *
139
+ * If it is, the component's `datasourceLinkedElementSymbol` property is set to the element, and the component
140
+ * attaches an observer to the datasource's changes.
141
+ *
142
+ * The observer is a function that calls the `handleDataSourceChanges` method in the context of the component.
143
+ * Additionally, the component attaches an observer to itself, which also calls the `handleDataSourceChanges`
144
+ * method in the component's context.
145
+ */
146
+ [assembleMethodSymbol]() {
147
+ super[assembleMethodSymbol]();
148
+ const self = this;
149
+
150
+ initControlReferences.call(this);
151
+ initEventHandler.call(this);
152
+
153
+ const selector = this.getOption("datasource.selector");
154
+
155
+ if (isString(selector)) {
156
+ const element = findElementWithSelectorUpwards(this, selector);
157
+ if (element === null) {
158
+ throw new Error("the selector must match exactly one element");
159
+ }
160
+
161
+ if (!(element instanceof Datasource)) {
162
+ throw new TypeError("the element must be a datasource");
163
+ }
164
+
165
+ this[datasourceLinkedElementSymbol] = element;
166
+ element.datasource.attachObserver(
167
+ new Observer(handleDataSourceChanges.bind(this)),
168
+ );
169
+
170
+ self[originValuesSymbol] = null;
171
+
172
+ element.datasource.attachObserver(
173
+ new Observer(function () {
174
+ if (!self[originValuesSymbol]) {
175
+ self[originValuesSymbol] = clone(
176
+ self[datasourceLinkedElementSymbol].data,
177
+ );
178
+ }
179
+
180
+ const currentValues = this.getRealSubject();
181
+ const ignoreChanges = self.getOption("ignoreChanges");
182
+
183
+ const result = diff(self[originValuesSymbol], currentValues);
184
+ if (isArray(ignoreChanges) && ignoreChanges.length > 0) {
185
+ const itemsToRemove = [];
186
+ for (const item of result) {
187
+ for (const ignorePattern of ignoreChanges) {
188
+ const p = new RegExp(ignorePattern);
189
+ if (p.test(item.path)) {
190
+ itemsToRemove.push(item);
191
+ break;
192
+ }
193
+ }
194
+ }
195
+
196
+ for (const itemToRemove of itemsToRemove) {
197
+ const index = result.indexOf(itemToRemove);
198
+ if (index > -1) {
199
+ result.splice(index, 1);
200
+ }
201
+ }
202
+ }
203
+
204
+ if (isArray(result) && result.length > 0) {
205
+ self[stateButtonElementSymbol].setState("changed");
206
+ self[stateButtonElementSymbol].setOption("disabled", false);
207
+ self.setOption("changes", result.length);
208
+ self.setOption(
209
+ "classes.badge",
210
+ new TokenList(self.getOption("classes.badge"))
211
+ .remove("hidden")
212
+ .toString(),
213
+ );
214
+ } else {
215
+ self[stateButtonElementSymbol].removeState();
216
+ self[stateButtonElementSymbol].setOption("disabled", true);
217
+ self.setOption("changes", 0);
218
+ self.setOption(
219
+ "classes.badge",
220
+ new TokenList(self.getOption("classes.badge"))
221
+ .add("hidden")
222
+ .toString(),
223
+ );
224
+ }
225
+ }),
226
+ );
227
+ }
228
+
229
+ this.attachObserver(
230
+ new Observer(() => {
231
+ handleDataSourceChanges.call(this);
232
+ }),
233
+ );
234
+ }
235
+
236
+ /**
237
+ *
238
+ * @return [CSSStyleSheet]
239
+ */
240
+ static getCSSStyleSheet() {
241
+ return [SaveButtonStyleSheet, BadgeStyleSheet];
242
+ }
241
243
  }
242
244
 
243
245
  /**
@@ -245,78 +247,78 @@ class SaveButton extends CustomElement {
245
247
  * @return {Monster.Components.Datatable.Form}
246
248
  */
247
249
  function initControlReferences() {
248
- if (!this.shadowRoot) {
249
- throw new Error("no shadow-root is defined");
250
- }
251
-
252
- this[stateButtonElementSymbol] = this.shadowRoot.querySelector(
253
- "[data-monster-role=state-button]",
254
- );
255
-
256
- this[badgeElementSymbol] = this.shadowRoot.querySelector(
257
- "[data-monster-role=badge]",
258
- );
259
-
260
- if (this[stateButtonElementSymbol]) {
261
- setTimeout(() => {
262
- const states = {
263
- changed: new State(
264
- "changed",
265
- '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-cloud-arrow-up" viewBox="0 0 16 16">\n' +
266
- ' <path fill-rule="evenodd" d="M7.646 5.146a.5.5 0 0 1 .708 0l2 2a.5.5 0 0 1-.708.708L8.5 6.707V10.5a.5.5 0 0 1-1 0V6.707L6.354 7.854a.5.5 0 1 1-.708-.708z"/>\n' +
267
- ' <path d="M4.406 3.342A5.53 5.53 0 0 1 8 2c2.69 0 4.923 2 5.166 4.579C14.758 6.804 16 8.137 16 9.773 16 11.569 14.502 13 12.687 13H3.781C1.708 13 0 11.366 0 9.318c0-1.763 1.266-3.223 2.942-3.593.143-.863.698-1.723 1.464-2.383m.653.757c-.757.653-1.153 1.44-1.153 2.056v.448l-.445.049C2.064 6.805 1 7.952 1 9.318 1 10.785 2.23 12 3.781 12h8.906C13.98 12 15 10.988 15 9.773c0-1.216-1.02-2.228-2.313-2.228h-.5v-.5C12.188 4.825 10.328 3 8 3a4.53 4.53 0 0 0-2.941 1.1z"/>\n' +
268
- "</svg>",
269
- ),
270
- };
271
-
272
- this[stateButtonElementSymbol].removeState();
273
- this[stateButtonElementSymbol].setOption("disabled", "disabled");
274
- this[stateButtonElementSymbol].setOption("states", states);
275
- this[stateButtonElementSymbol].setOption(
276
- "labels.button",
277
- this.getOption("labels.button"),
278
- );
279
- }, 1);
280
- }
281
-
282
- return this;
250
+ if (!this.shadowRoot) {
251
+ throw new Error("no shadow-root is defined");
252
+ }
253
+
254
+ this[stateButtonElementSymbol] = this.shadowRoot.querySelector(
255
+ "[data-monster-role=state-button]",
256
+ );
257
+
258
+ this[badgeElementSymbol] = this.shadowRoot.querySelector(
259
+ "[data-monster-role=badge]",
260
+ );
261
+
262
+ if (this[stateButtonElementSymbol]) {
263
+ setTimeout(() => {
264
+ const states = {
265
+ changed: new State(
266
+ "changed",
267
+ '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-cloud-arrow-up" viewBox="0 0 16 16">\n' +
268
+ ' <path fill-rule="evenodd" d="M7.646 5.146a.5.5 0 0 1 .708 0l2 2a.5.5 0 0 1-.708.708L8.5 6.707V10.5a.5.5 0 0 1-1 0V6.707L6.354 7.854a.5.5 0 1 1-.708-.708z"/>\n' +
269
+ ' <path d="M4.406 3.342A5.53 5.53 0 0 1 8 2c2.69 0 4.923 2 5.166 4.579C14.758 6.804 16 8.137 16 9.773 16 11.569 14.502 13 12.687 13H3.781C1.708 13 0 11.366 0 9.318c0-1.763 1.266-3.223 2.942-3.593.143-.863.698-1.723 1.464-2.383m.653.757c-.757.653-1.153 1.44-1.153 2.056v.448l-.445.049C2.064 6.805 1 7.952 1 9.318 1 10.785 2.23 12 3.781 12h8.906C13.98 12 15 10.988 15 9.773c0-1.216-1.02-2.228-2.313-2.228h-.5v-.5C12.188 4.825 10.328 3 8 3a4.53 4.53 0 0 0-2.941 1.1z"/>\n' +
270
+ "</svg>",
271
+ ),
272
+ };
273
+
274
+ this[stateButtonElementSymbol].removeState();
275
+ this[stateButtonElementSymbol].setOption("disabled", "disabled");
276
+ this[stateButtonElementSymbol].setOption("states", states);
277
+ this[stateButtonElementSymbol].setOption(
278
+ "labels.button",
279
+ this.getOption("labels.button"),
280
+ );
281
+ }, 1);
282
+ }
283
+
284
+ return this;
283
285
  }
284
286
 
285
287
  /**
286
288
  * @private
287
289
  */
288
290
  function initEventHandler() {
289
- setTimeout(() => {
290
- this[stateButtonElementSymbol].setOption("actions.click", () => {
291
- this[datasourceLinkedElementSymbol]
292
- .write()
293
- .then(() => {
294
- this[originValuesSymbol] = null;
295
- this[stateButtonElementSymbol].removeState();
296
- this[stateButtonElementSymbol].setOption("disabled", true);
297
- this.setOption("changes", 0);
298
- this.setOption(
299
- "classes.badge",
300
- new TokenList(this.getOption("classes.badge"))
301
- .add("hidden")
302
- .toString(),
303
- );
304
- })
305
- .catch((error) => {
306
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error.toString());
307
- });
308
- });
309
- }, 1);
291
+ setTimeout(() => {
292
+ this[stateButtonElementSymbol].setOption("actions.click", () => {
293
+ this[datasourceLinkedElementSymbol]
294
+ .write()
295
+ .then(() => {
296
+ this[originValuesSymbol] = null;
297
+ this[stateButtonElementSymbol].removeState();
298
+ this[stateButtonElementSymbol].setOption("disabled", true);
299
+ this.setOption("changes", 0);
300
+ this.setOption(
301
+ "classes.badge",
302
+ new TokenList(this.getOption("classes.badge"))
303
+ .add("hidden")
304
+ .toString(),
305
+ );
306
+ })
307
+ .catch((error) => {
308
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, error.toString());
309
+ });
310
+ });
311
+ }, 1);
310
312
  }
311
313
 
312
314
  /**
313
315
  * @param {Object} options
314
316
  */
315
317
  function updateOptionsFromArguments(options) {
316
- const selector = this.getAttribute(ATTRIBUTE_DATASOURCE_SELECTOR);
317
- if (selector) {
318
- options.datasource.selector = selector;
319
- }
318
+ const selector = this.getAttribute(ATTRIBUTE_DATASOURCE_SELECTOR);
319
+ if (selector) {
320
+ options.datasource.selector = selector;
321
+ }
320
322
  }
321
323
 
322
324
  /**
@@ -324,8 +326,8 @@ function updateOptionsFromArguments(options) {
324
326
  * @return {string}
325
327
  */
326
328
  function getTemplate() {
327
- // language=HTML
328
- return `
329
+ // language=HTML
330
+ return `
329
331
  <div data-monster-role="control" part="control"
330
332
  data-monster-attributes="disabled path:disabled | if:true">
331
333
  <monster-state-button data-monster-role="state-button">save</monster-state-button>
@@ -51,7 +51,6 @@ export const buttonElementSymbol = Symbol("buttonElement");
51
51
  * @copyright schukai GmbH
52
52
  * @summary A beautiful button that can make your life easier and also looks good.
53
53
  * @fires monster-button-clicked this event is triggered when the button is clicked. It contains the field {button} with the button instance.
54
- *
55
54
  */
56
55
  class Button extends CustomControl {
57
56
  /**