@schukai/monster 3.85.0 → 3.85.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 CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
 
4
4
 
5
+ ## [3.85.1] - 2024-11-12
6
+
7
+ ### Bug Fixes
8
+
9
+ - update the copy component [#259](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/259)
10
+
11
+
12
+
5
13
  ## [3.85.0] - 2024-11-05
6
14
 
7
15
  ### Add Features
package/package.json CHANGED
@@ -1 +1 @@
1
- {"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.6.12","@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.85.0"}
1
+ {"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.6.12","@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.85.1"}
@@ -8,30 +8,34 @@
8
8
  * For those who do not wish to adhere to the AGPLv3, a commercial license is available.
9
9
  * Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms.
10
10
  * For more information about purchasing a commercial license, please contact schukai GmbH.
11
+ *
12
+ * SPDX-License-Identifier: AGPL-3.0
11
13
  */
12
14
 
13
- import { instanceSymbol } from "../../constants.mjs";
15
+ import {instanceSymbol} from "../../constants.mjs";
14
16
  import {
15
- addAttributeToken,
16
- removeAttributeToken,
17
+ addAttributeToken,
18
+ removeAttributeToken,
17
19
  } from "../../dom/attributes.mjs";
18
20
  import {
19
- ATTRIBUTE_ERRORMESSAGE,
20
- ATTRIBUTE_ROLE,
21
+ ATTRIBUTE_ERRORMESSAGE,
22
+ ATTRIBUTE_ROLE,
21
23
  } from "../../dom/constants.mjs";
22
- import { CustomElement, getSlottedElements } from "../../dom/customelement.mjs";
24
+ import {CustomElement, getSlottedElements} from "../../dom/customelement.mjs";
23
25
  import {
24
- assembleMethodSymbol,
25
- registerCustomElement,
26
+ assembleMethodSymbol,
27
+ registerCustomElement,
26
28
  } from "../../dom/customelement.mjs";
27
- import { getDocument } from "../../dom/util.mjs";
28
- import { STYLE_DISPLAY_MODE_BLOCK } from "../form/constants.mjs";
29
- import { CopyStyleSheet } from "./stylesheet/copy.mjs";
30
- import { fireCustomEvent } from "../../dom/events.mjs";
31
- import { positionPopper } from "../form/util/floating-ui.mjs";
32
- import { DeadMansSwitch } from "../../util/deadmansswitch.mjs";
29
+ import {getDocument} from "../../dom/util.mjs";
30
+ import {isString} from "../../types/is.mjs";
31
+ import {validateString} from "../../types/validate.mjs";
32
+ import {STYLE_DISPLAY_MODE_BLOCK} from "../form/constants.mjs";
33
+ import {CopyStyleSheet} from "./stylesheet/copy.mjs";
34
+ import {fireCustomEvent} from "../../dom/events.mjs";
35
+ import {positionPopper} from "../form/util/floating-ui.mjs";
36
+ import {DeadMansSwitch} from "../../util/deadmansswitch.mjs";
33
37
 
34
- export { Copy };
38
+ export {Copy};
35
39
 
36
40
  /**
37
41
  * @private
@@ -39,6 +43,12 @@ export { Copy };
39
43
  */
40
44
  const timerCallbackSymbol = Symbol("timerCallback");
41
45
 
46
+ /**
47
+ * @private
48
+ * @type {symbol}
49
+ */
50
+ const timerDelaySymbol = Symbol("timerDelay");
51
+
42
52
  /**
43
53
  * @private
44
54
  * @type {symbol}
@@ -83,248 +93,265 @@ const resizeObserverSymbol = Symbol("resizeObserver");
83
93
  * @summary A beautiful Copy that can make your life easier and also looks good.
84
94
  */
85
95
  class Copy extends CustomElement {
86
- /**
87
- * This method is called by the `instanceof` operator.
88
- * @return {symbol}
89
- */
90
- static get [instanceSymbol]() {
91
- return Symbol.for("@schukai/monster/components/content/copy@@instance");
92
- }
93
-
94
- /**
95
- *
96
- * @return {Components.Content.Copy
97
- * @fires monster-copy-clicked This event is fired when the copy button is clicked.
98
- * @fires monster-copy-success This event is fired when the copy action is successful.
99
- * @fires monster-copy-error This event is fired when the copy action fails.
100
- */
101
- [assembleMethodSymbol]() {
102
- super[assembleMethodSymbol]();
103
- initControlReferences.call(this);
104
- initEventHandler.call(this);
105
- return this;
106
- }
107
-
108
- /**
109
- * This method is called when the element is connected to the dom.
110
- *
111
- * @return {void}
112
- */
113
- connectedCallback() {
114
- super.connectedCallback();
115
-
116
- const document = getDocument();
117
-
118
- for (const [, type] of Object.entries(["click", "touch"])) {
119
- // close on outside ui-events
120
- document.addEventListener(type, this[closeEventHandler]);
121
- }
122
-
123
- updatePopper.call(this);
124
- attachResizeObserver.call(this);
125
- }
126
-
127
- /**
128
- * This method is called when the element is disconnected from the dom.
129
- *
130
- * @return {void}
131
- */
132
- disconnectedCallback() {
133
- super.disconnectedCallback();
134
-
135
- // close on outside ui-events
136
- for (const [, type] of Object.entries(["click", "touch"])) {
137
- document.removeEventListener(type, this[closeEventHandler]);
138
- }
139
-
140
- disconnectResizeObserver.call(this);
141
- }
142
-
143
- /**
144
- * To set the options via the HTML Tag, the attribute `data-monster-options` must be used.
145
- * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
146
- *
147
- * The individual configuration values can be found in the table.
148
- *
149
- * @property {Object} templates Template definitions
150
- * @property {string} templates.main Main template
151
- * @property {Object} actions Callbacks
152
- * @property {string} actions.click="throw Error" Callback when clicked
153
- * @property {Object} features Features
154
- * @property {boolean} features.stripTags=true Strip tags from the copied text
155
- * @property {boolean} features.preventOpenEventSent=false Prevent open event from being sent
156
- * @property {Object} popper Popper configuration
157
- * @property {string} popper.placement="top" Popper placement
158
- * @property {string[]} popper.middleware=["autoPlacement", "shift", "offset:15", "arrow"] Popper middleware
159
- * @property {boolean} disabled=false Disabled state
160
- */
161
- get defaults() {
162
- return Object.assign({}, super.defaults, {
163
- templates: {
164
- main: getTemplate(),
165
- },
166
- disabled: false,
167
- features: {
168
- stripTags: true,
169
- preventOpenEventSent: false,
170
- },
171
- popper: {
172
- placement: "top",
173
- middleware: ["autoPlacement", "shift", "offset:15", "arrow"],
174
- },
175
- });
176
- }
177
-
178
- /**
179
- * @return {string}
180
- */
181
- static getTag() {
182
- return "monster-copy";
183
- }
184
-
185
- /**
186
- * @return {CSSStyleSheet[]}
187
- */
188
- static getCSSStyleSheet() {
189
- return [CopyStyleSheet];
190
- }
191
-
192
- /**
193
- * With this method, you can show the popper.
194
- *
195
- * @return {Copy}
196
- */
197
- showDialog() {
198
- show.call(this);
199
- return this;
200
- }
201
-
202
- /**
203
- * With this method, you can hide the popper.
204
- *
205
- * @return {Copy}
206
- */
207
- hideDialog() {
208
- hide.call(this);
209
- return this;
210
- }
211
-
212
- /**
213
- * With this method, you can toggle the popper.
214
- *
215
- * @return {Copy}
216
- */
217
- toggleDialog() {
218
- if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) {
219
- this.hideDialog();
220
- } else {
221
- this.showDialog();
222
- }
223
- return this;
224
- }
96
+ /**
97
+ * This method is called by the `instanceof` operator.
98
+ * @return {symbol}
99
+ */
100
+ static get [instanceSymbol]() {
101
+ return Symbol.for("@schukai/monster/components/content/copy@@instance");
102
+ }
103
+
104
+ /**
105
+ *
106
+ * @return {Components.Content.Copy
107
+ * @fires monster-copy-clicked This event is fired when the copy button is clicked.
108
+ * @fires monster-copy-success This event is fired when the copy action is successful.
109
+ * @fires monster-copy-error This event is fired when the copy action fails.
110
+ */
111
+ [assembleMethodSymbol]() {
112
+ super[assembleMethodSymbol]();
113
+ initControlReferences.call(this);
114
+ initEventHandler.call(this);
115
+ return this;
116
+ }
117
+
118
+ /**
119
+ * This method is called when the element is connected to the dom.
120
+ *
121
+ * @return {void}
122
+ */
123
+ connectedCallback() {
124
+ super.connectedCallback();
125
+
126
+ const document = getDocument();
127
+
128
+ for (const [, type] of Object.entries(["click", "touch"])) {
129
+ // close on outside ui-events
130
+ document.addEventListener(type, this[closeEventHandler]);
131
+ }
132
+
133
+ updatePopper.call(this);
134
+ attachResizeObserver.call(this);
135
+ }
136
+
137
+ /**
138
+ * This method is called when the element is disconnected from the dom.
139
+ *
140
+ * @return {void}
141
+ */
142
+ disconnectedCallback() {
143
+ super.disconnectedCallback();
144
+
145
+ // close on outside ui-events
146
+ for (const [, type] of Object.entries(["click", "touch"])) {
147
+ document.removeEventListener(type, this[closeEventHandler]);
148
+ }
149
+
150
+ disconnectResizeObserver.call(this);
151
+ }
152
+
153
+ /**
154
+ * To set the options via the HTML Tag, the attribute `data-monster-options` must be used.
155
+ * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
156
+ *
157
+ * The individual configuration values can be found in the table.
158
+ *
159
+ * @property {Object} templates Template definitions
160
+ * @property {string} templates.main Main template
161
+ * @property {Object} actions Callbacks
162
+ * @property {string} actions.click="throw Error" Callback when clicked
163
+ * @property {Object} features Features
164
+ * @property {boolean} features.stripTags=true Strip tags from the copied text
165
+ * @property {boolean} features.preventOpenEventSent=false Prevent open event from being sent
166
+ * @property {Object} popper Popper configuration
167
+ * @property {string} popper.placement="top" Popper placement
168
+ * @property {string[]} popper.middleware=["autoPlacement", "shift", "offset:15", "arrow"] Popper middleware
169
+ * @property {boolean} disabled=false Disabled state
170
+ */
171
+ get defaults() {
172
+ return Object.assign({}, super.defaults, {
173
+ templates: {
174
+ main: getTemplate(),
175
+ },
176
+ disabled: false,
177
+ features: {
178
+ stripTags: true,
179
+ preventOpenEventSent: false,
180
+ },
181
+ popper: {
182
+ placement: "top",
183
+ middleware: ["autoPlacement", "offset:-1", "arrow"],
184
+ },
185
+ });
186
+ }
187
+
188
+ /**
189
+ * @return {string}
190
+ */
191
+ static getTag() {
192
+ return "monster-copy";
193
+ }
194
+
195
+ /**
196
+ * @return {CSSStyleSheet[]}
197
+ */
198
+ static getCSSStyleSheet() {
199
+ return [CopyStyleSheet];
200
+ }
201
+
202
+ /**
203
+ * With this method, you can show the popper.
204
+ *
205
+ * @return {Copy}
206
+ */
207
+ showDialog() {
208
+ if (this[timerDelaySymbol] instanceof DeadMansSwitch) {
209
+ try {
210
+ this[timerDelaySymbol].defuse();
211
+ } catch (e) {
212
+ }
213
+ }
214
+
215
+ this[timerDelaySymbol] = new DeadMansSwitch(500, () => {
216
+ show.call(this);
217
+ });
218
+
219
+ return this;
220
+ }
221
+
222
+ /**
223
+ * With this method, you can hide the popper.
224
+ *
225
+ * @return {Copy}
226
+ */
227
+ hideDialog() {
228
+ if (this[timerDelaySymbol] instanceof DeadMansSwitch) {
229
+ try {
230
+ this[timerDelaySymbol].defuse();
231
+ } catch (e) {
232
+ }
233
+ }
234
+
235
+ hide.call(this);
236
+ return this;
237
+ }
238
+
239
+ /**
240
+ * With this method, you can toggle the popper.
241
+ *
242
+ * @return {Copy}
243
+ */
244
+ toggleDialog() {
245
+ if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) {
246
+ this.hideDialog();
247
+ } else {
248
+ this.showDialog();
249
+ }
250
+ return this;
251
+ }
225
252
  }
226
253
 
227
254
  /**
228
255
  * @private
229
256
  */
230
257
  function attachResizeObserver() {
231
- // against flickering
232
- this[resizeObserverSymbol] = new ResizeObserver((entries) => {
233
- if (this[timerCallbackSymbol] instanceof DeadMansSwitch) {
234
- try {
235
- this[timerCallbackSymbol].touch();
236
- return;
237
- } catch (e) {
238
- delete this[timerCallbackSymbol];
239
- }
240
- }
241
-
242
- this[timerCallbackSymbol] = new DeadMansSwitch(200, () => {
243
- updatePopper.call(this);
244
- });
245
- });
246
-
247
- this[resizeObserverSymbol].observe(this.parentElement);
258
+ // against flickering
259
+ this[resizeObserverSymbol] = new ResizeObserver((entries) => {
260
+ if (this[timerCallbackSymbol] instanceof DeadMansSwitch) {
261
+ try {
262
+ this[timerCallbackSymbol].touch();
263
+ return;
264
+ } catch (e) {
265
+ delete this[timerCallbackSymbol];
266
+ }
267
+ }
268
+
269
+ this[timerCallbackSymbol] = new DeadMansSwitch(200, () => {
270
+ updatePopper.call(this);
271
+ });
272
+ });
273
+
274
+ this[resizeObserverSymbol].observe(this.parentElement);
248
275
  }
249
276
 
250
277
  /**
251
278
  * @private
252
279
  */
253
280
  function disconnectResizeObserver() {
254
- if (this[resizeObserverSymbol] instanceof ResizeObserver) {
255
- this[resizeObserverSymbol].disconnect();
256
- }
281
+ if (this[resizeObserverSymbol] instanceof ResizeObserver) {
282
+ this[resizeObserverSymbol].disconnect();
283
+ }
257
284
  }
258
285
 
259
286
  /**
260
287
  * @private
261
288
  */
262
289
  function hide() {
263
- const self = this;
290
+ const self = this;
264
291
 
265
- fireCustomEvent(self, "monster-popper-hide", {
266
- self,
267
- });
292
+ fireCustomEvent(self, "monster-popper-hide", {
293
+ self,
294
+ });
268
295
 
269
- self[popperElementSymbol].style.display = "none";
270
- removeAttributeToken(self[controlElementSymbol], "class", "open");
296
+ self[popperElementSymbol].style.display = "none";
297
+ removeAttributeToken(self[controlElementSymbol], "class", "open");
271
298
 
272
- setTimeout(() => {
273
- fireCustomEvent(self, "monster-popper-hidden", {
274
- self,
275
- });
276
- }, 0);
299
+ setTimeout(() => {
300
+ fireCustomEvent(self, "monster-popper-hidden", {
301
+ self,
302
+ });
303
+ }, 0);
277
304
  }
278
305
 
279
306
  /**
280
307
  * @private
281
308
  */
282
309
  function show() {
283
- const self = this;
310
+ const self = this;
284
311
 
285
- if (self.getOption("disabled", false) === true) {
286
- return;
287
- }
312
+ if (self.getOption("disabled", false) === true) {
313
+ return;
314
+ }
288
315
 
289
- if (self[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) {
290
- return;
291
- }
316
+ if (self[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) {
317
+ return;
318
+ }
292
319
 
293
- fireCustomEvent(self, "monster-popper-open", {
294
- self,
295
- });
320
+ fireCustomEvent(self, "monster-popper-open", {
321
+ self,
322
+ });
296
323
 
297
- self[popperElementSymbol].style.visibility = "hidden";
298
- self[popperElementSymbol].style.display = STYLE_DISPLAY_MODE_BLOCK;
324
+ self[popperElementSymbol].style.visibility = "hidden";
325
+ self[popperElementSymbol].style.display = STYLE_DISPLAY_MODE_BLOCK;
299
326
 
300
- addAttributeToken(self[controlElementSymbol], "class", "open");
301
- updatePopper.call(self);
327
+ addAttributeToken(self[controlElementSymbol], "class", "open");
328
+ updatePopper.call(self);
302
329
 
303
- setTimeout(() => {
304
- fireCustomEvent(self, "monster-popper-opened", {
305
- self,
306
- });
307
- }, 0);
330
+ setTimeout(() => {
331
+ fireCustomEvent(self, "monster-popper-opened", {
332
+ self,
333
+ });
334
+ }, 0);
308
335
  }
309
336
 
310
337
  /**
311
338
  * @private
312
339
  */
313
340
  function updatePopper() {
314
- if (this[popperElementSymbol].style.display !== STYLE_DISPLAY_MODE_BLOCK) {
315
- return;
316
- }
317
-
318
- if (this.getOption("disabled", false) === true) {
319
- return;
320
- }
321
-
322
- positionPopper.call(
323
- this,
324
- this[controlElementSymbol],
325
- this[popperElementSymbol],
326
- this.getOption("popper", {}),
327
- );
341
+ if (this[popperElementSymbol].style.display !== STYLE_DISPLAY_MODE_BLOCK) {
342
+ return;
343
+ }
344
+
345
+ if (this.getOption("disabled", false) === true) {
346
+ return;
347
+ }
348
+
349
+ positionPopper.call(
350
+ this,
351
+ this[controlElementSymbol],
352
+ this[popperElementSymbol],
353
+ this.getOption("popper", {}),
354
+ );
328
355
  }
329
356
 
330
357
  /**
@@ -332,92 +359,126 @@ function updatePopper() {
332
359
  * @return {initEventHandler}
333
360
  */
334
361
  function initEventHandler() {
335
- const self = this;
336
-
337
- this[closeEventHandler] = (event) => {
338
- const path = event.composedPath();
339
-
340
- for (const [, element] of Object.entries(path)) {
341
- if (element === this) {
342
- return;
343
- }
344
- }
345
- hide.call(this);
346
- };
347
-
348
- const type = "click";
349
-
350
- this[controlElementSymbol].addEventListener("mouseenter", (event) => {
351
- if (this.getOption("features.preventOpenEventSent") === true) {
352
- event.preventDefault();
353
- }
354
- this.showDialog();
355
- });
356
-
357
- this[controlElementSymbol].addEventListener("focus", (event) => {
358
- if (this.getOption("features.preventOpenEventSent") === true) {
359
- event.preventDefault();
360
- }
361
- this.showDialog();
362
- });
363
- this[controlElementSymbol].addEventListener("blur", (event) => {
364
- if (this.getOption("features.preventOpenEventSent") === true) {
365
- event.preventDefault();
366
- }
367
- this.hideDialog();
368
- });
369
-
370
- this[copyButtonElementSymbol].addEventListener(type, function (event) {
371
- fireCustomEvent(self, "monster-copy-clicked", {
372
- element: self,
373
- });
374
-
375
- const nodes = getSlottedElements.call(self, ":scope");
376
-
377
- let text = "";
378
- for (const node of nodes) {
379
- if (self.getOption("features.stripTags")) {
380
- text += node.textContent;
381
- } else {
382
- text += node.outerHTML;
383
- }
384
- }
385
-
386
- navigator.clipboard
387
- .writeText(text)
388
- .then(function () {
389
- self[copyButtonElementSymbol]
390
- .querySelector("use")
391
- .setAttribute("href", "#copy-success");
392
- setTimeout(() => {
393
- self[copyButtonElementSymbol]
394
- .querySelector("use")
395
- .setAttribute("href", "#copy");
396
- }, 2000);
397
-
398
- fireCustomEvent(self, "monster-copy-success", {
399
- element: self,
400
- });
401
- })
402
- .catch(function (e) {
403
- self[copyButtonElementSymbol]
404
- .querySelector("use")
405
- .setAttribute("href", "#copy-error");
406
- setTimeout(() => {
407
- self[copyButtonElementSymbol]
408
- .querySelector("use")
409
- .setAttribute("href", "#copy");
410
- }, 2000);
411
-
412
- fireCustomEvent(self, "monster-copy-error", {
413
- element: self,
414
- });
415
-
416
- addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, "" + e);
417
- });
418
- });
419
-
420
- return this;
362
+ const self = this;
363
+
364
+ this[closeEventHandler] = (event) => {
365
+ const path = event.composedPath();
366
+
367
+ for (const [, element] of Object.entries(path)) {
368
+ if (element === this) {
369
+ return;
370
+ }
371
+ }
372
+ hide.call(this);
373
+ };
374
+
375
+ const type = "click";
376
+
377
+ this[controlElementSymbol].addEventListener("mouseenter", (event) => {
378
+ if (this.getOption("features.preventOpenEventSent") === true) {
379
+ event.preventDefault();
380
+ }
381
+ this.showDialog();
382
+ });
383
+
384
+ this[controlElementSymbol].addEventListener("mouseleave", (event) => {
385
+ if (this.getOption("features.preventOpenEventSent") === true) {
386
+ event.preventDefault();
387
+ }
388
+ this.hideDialog();
389
+ });
390
+
391
+ this[controlElementSymbol].addEventListener("focus", (event) => {
392
+ if (this.getOption("features.preventOpenEventSent") === true) {
393
+ event.preventDefault();
394
+ }
395
+ this.showDialog();
396
+ });
397
+ this[controlElementSymbol].addEventListener("blur", (event) => {
398
+ if (this.getOption("features.preventOpenEventSent") === true) {
399
+ event.preventDefault();
400
+ }
401
+ this.hideDialog();
402
+ });
403
+
404
+ this[copyButtonElementSymbol].addEventListener(type, function (event) {
405
+ fireCustomEvent(self, "monster-copy-clicked", {
406
+ element: self,
407
+ });
408
+
409
+ const text = getSlottedCopyContent.call(self);
410
+
411
+ navigator.clipboard
412
+ .writeText(text)
413
+ .then(function () {
414
+ self[copyButtonElementSymbol]
415
+ .querySelector("use")
416
+ .setAttribute("href", "#copy-success");
417
+ setTimeout(() => {
418
+ self[copyButtonElementSymbol]
419
+ .querySelector("use")
420
+ .setAttribute("href", "#copy");
421
+ }, 2000);
422
+
423
+ fireCustomEvent(self, "monster-copy-success", {
424
+ element: self,
425
+ });
426
+ })
427
+ .catch(function (e) {
428
+ self[copyButtonElementSymbol]
429
+ .querySelector("use")
430
+ .setAttribute("href", "#copy-error");
431
+ setTimeout(() => {
432
+ self[copyButtonElementSymbol]
433
+ .querySelector("use")
434
+ .setAttribute("href", "#copy");
435
+ }, 2000);
436
+
437
+ fireCustomEvent(self, "monster-copy-error", {
438
+ element: self,
439
+ });
440
+
441
+ addAttributeToken(self, ATTRIBUTE_ERRORMESSAGE, "" + e);
442
+ });
443
+ });
444
+
445
+ return this;
446
+ }
447
+
448
+ /**
449
+ * @private
450
+ * @returns {Set<any>|string}
451
+ */
452
+ function getSlottedCopyContent() {
453
+ const self = this;
454
+ const result = new Set();
455
+
456
+ if (!(this.shadowRoot instanceof ShadowRoot)) {
457
+ return result;
458
+ }
459
+
460
+ const slots = this.shadowRoot.querySelectorAll("slot");
461
+
462
+ let text = "";
463
+ for (const [, slot] of Object.entries(slots)) {
464
+ slot.assignedNodes().forEach(function (node) {
465
+ if (
466
+ node instanceof HTMLElement ||
467
+ node instanceof SVGElement ||
468
+ node instanceof MathMLElement
469
+ ) {
470
+ if (self.getOption("features.stripTags")) {
471
+ text += node.textContent.trim();
472
+ } else {
473
+ text += node.outerHTML.trim();
474
+ }
475
+ } else {
476
+ text += node.textContent.trim();
477
+ }
478
+ });
479
+ }
480
+
481
+ return text;
421
482
  }
422
483
 
423
484
  /**
@@ -425,17 +486,17 @@ function initEventHandler() {
425
486
  * @return {void}
426
487
  */
427
488
  function initControlReferences() {
428
- this[controlElementSymbol] = this.shadowRoot.querySelector(
429
- `[${ATTRIBUTE_ROLE}="control"]`,
430
- );
489
+ this[controlElementSymbol] = this.shadowRoot.querySelector(
490
+ `[${ATTRIBUTE_ROLE}="control"]`,
491
+ );
431
492
 
432
- this[copyButtonElementSymbol] = this.shadowRoot.querySelector(
433
- `[${ATTRIBUTE_ROLE}="button"]`,
434
- );
493
+ this[copyButtonElementSymbol] = this.shadowRoot.querySelector(
494
+ `[${ATTRIBUTE_ROLE}="button"]`,
495
+ );
435
496
 
436
- this[popperElementSymbol] = this.shadowRoot.querySelector(
437
- `[${ATTRIBUTE_ROLE}="popper"]`,
438
- );
497
+ this[popperElementSymbol] = this.shadowRoot.querySelector(
498
+ `[${ATTRIBUTE_ROLE}="popper"]`,
499
+ );
439
500
  }
440
501
 
441
502
  /**
@@ -443,14 +504,15 @@ function initControlReferences() {
443
504
  * @return {string}
444
505
  */
445
506
  function getTemplate() {
446
- // language=HTML
447
- return `
507
+ // language=HTML
508
+ return `
448
509
  <div data-monster-role="control" part="control">
449
510
  <slot></slot>
450
511
  <div data-monster-role="popper" part="popper" tabindex="-1" class="monster-color-primary-1">
451
512
  <div data-monster-role="arrow"></div>
452
513
  <button data-monster-role="button" part="button">
453
- <svg data-monster-role="icon-map"><defs>
514
+ <svg data-monster-role="icon-map">
515
+ <defs>
454
516
  <g id="copy">
455
517
  <path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1z"/>
456
518
  <path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0z"/>
@@ -471,7 +533,11 @@ function getTemplate() {
471
533
  </g>
472
534
 
473
535
  </defs>
474
- </svg><svg data-monster-role="icon" xmlns="http://www.w3.org/2000/svg" width="25" height="25" viewBox="0 0 16 16"><use href="#copy"></use></svg>
536
+ </svg>
537
+ <svg data-monster-role="icon" xmlns="http://www.w3.org/2000/svg" width="25" height="25"
538
+ viewBox="0 0 16 16">
539
+ <use href="#copy"></use>
540
+ </svg>
475
541
  </button>
476
542
  </div>
477
543
  </div>`;
@@ -63,11 +63,23 @@ class DeadMansSwitch extends Base {
63
63
  }
64
64
 
65
65
  clearTimeout(this[internalSymbol]["timer"]);
66
-
67
66
  initCallback.call(this);
68
67
 
69
68
  return this;
70
69
  }
70
+
71
+ /**
72
+ * @throws {Error} has already run
73
+ * @returns {DeadMansSwitch}
74
+ */
75
+ defuse() {
76
+ if (this[internalSymbol]["isAlreadyRun"] === true) {
77
+ throw new Error("has already run");
78
+ }
79
+
80
+ clearTimeout(this[internalSymbol]["timer"]);
81
+ return this;
82
+ }
71
83
  }
72
84
 
73
85
  /**