@schukai/monster 3.92.0 → 3.92.2

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.
@@ -12,55 +12,55 @@
12
12
  * SPDX-License-Identifier: AGPL-3.0
13
13
  */
14
14
 
15
- import { instanceSymbol } from "../../constants.mjs";
16
- import { createPopper } from "@popperjs/core";
17
- import { extend } from "../../data/extend.mjs";
18
- import { Pathfinder } from "../../data/pathfinder.mjs";
15
+ import {instanceSymbol} from "../../constants.mjs";
16
+ import {createPopper} from "@popperjs/core";
17
+ import {extend} from "../../data/extend.mjs";
18
+ import {Pathfinder} from "../../data/pathfinder.mjs";
19
19
  import {
20
- addAttributeToken,
21
- addToObjectLink,
22
- hasObjectLink,
20
+ addAttributeToken,
21
+ addToObjectLink,
22
+ hasObjectLink,
23
23
  } from "../../dom/attributes.mjs";
24
24
  import {
25
- ATTRIBUTE_ERRORMESSAGE,
26
- ATTRIBUTE_PREFIX,
27
- ATTRIBUTE_ROLE,
25
+ ATTRIBUTE_ERRORMESSAGE,
26
+ ATTRIBUTE_PREFIX,
27
+ ATTRIBUTE_ROLE,
28
28
  } from "../../dom/constants.mjs";
29
29
  import {
30
- assembleMethodSymbol,
31
- CustomElement,
32
- getSlottedElements,
33
- registerCustomElement,
30
+ assembleMethodSymbol,
31
+ CustomElement,
32
+ getSlottedElements,
33
+ registerCustomElement,
34
34
  } from "../../dom/customelement.mjs";
35
35
  import {
36
- findTargetElementFromEvent,
37
- fireCustomEvent,
36
+ findTargetElementFromEvent,
37
+ fireCustomEvent,
38
38
  } from "../../dom/events.mjs";
39
- import { getDocument } from "../../dom/util.mjs";
40
- import { random } from "../../math/random.mjs";
41
- import { getGlobal } from "../../types/global.mjs";
42
- import { ID } from "../../types/id.mjs";
43
- import { isArray, isString } from "../../types/is.mjs";
44
- import { TokenList } from "../../types/tokenlist.mjs";
45
- import { clone } from "../../util/clone.mjs";
46
- import { DeadMansSwitch } from "../../util/deadmansswitch.mjs";
47
- import { Processing } from "../../util/processing.mjs";
39
+ import {getDocument} from "../../dom/util.mjs";
40
+ import {random} from "../../math/random.mjs";
41
+ import {getGlobal} from "../../types/global.mjs";
42
+ import {ID} from "../../types/id.mjs";
43
+ import {isArray, isString} from "../../types/is.mjs";
44
+ import {TokenList} from "../../types/tokenlist.mjs";
45
+ import {clone} from "../../util/clone.mjs";
46
+ import {DeadMansSwitch} from "../../util/deadmansswitch.mjs";
47
+ import {Processing} from "../../util/processing.mjs";
48
48
  import {
49
- ATTRIBUTE_BUTTON_LABEL,
50
- ATTRIBUTE_FORM_RELOAD,
51
- ATTRIBUTE_FORM_URL,
52
- STYLE_DISPLAY_MODE_BLOCK,
49
+ ATTRIBUTE_BUTTON_LABEL,
50
+ ATTRIBUTE_FORM_RELOAD,
51
+ ATTRIBUTE_FORM_URL,
52
+ STYLE_DISPLAY_MODE_BLOCK,
53
53
  } from "../form/constants.mjs";
54
54
 
55
- import { TabsStyleSheet } from "./stylesheet/tabs.mjs";
56
- import { loadAndAssignContent } from "../form/util/fetch.mjs";
57
- import { ThemeStyleSheet } from "../stylesheet/theme.mjs";
55
+ import {TabsStyleSheet} from "./stylesheet/tabs.mjs";
56
+ import {loadAndAssignContent} from "../form/util/fetch.mjs";
57
+ import {ThemeStyleSheet} from "../stylesheet/theme.mjs";
58
58
  import {
59
- popperInstanceSymbol,
60
- setEventListenersModifiers,
59
+ popperInstanceSymbol,
60
+ setEventListenersModifiers,
61
61
  } from "../form/util/popper.mjs";
62
62
 
63
- export { Tabs };
63
+ export {Tabs};
64
64
 
65
65
  /**
66
66
  * @private
@@ -156,360 +156,361 @@ const resizeObserverSymbol = Symbol("resizeObserver");
156
156
  * @summary This CustomControl creates a tab element with a variety of options.
157
157
  */
158
158
  class Tabs extends CustomElement {
159
- /**
160
- * This method is called by the `instanceof` operator.
161
- * @return {symbol}
162
- */
163
- static get [instanceSymbol]() {
164
- return Symbol.for("@schukai/monster/components/layout/tabs");
165
- }
166
-
167
- /**
168
- * To set the options via the HTML tag, the attribute `data-monster-options` must be used.
169
- * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
170
- *
171
- * The individual configuration values can be found in the table.
172
- *
173
- * @property {Object} templates Template definitions
174
- * @property {string} templates.main Main template
175
- * @property {Object} labels
176
- * @property {string} labels.new-tab-label="New Tab"
177
- * @property {Object} features
178
- * @property {number} features.openDelay=500 Open delay in milliseconds
179
- * @property {string} features.removeBehavior="auto" Remove behavior, auto (default), next, previous and none
180
- * @property {Object} fetch Fetch [see Using Fetch mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)
181
- * @property {String} fetch.redirect=error
182
- * @property {String} fetch.method=GET
183
- * @property {String} fetch.mode=same-origin
184
- * @property {String} fetch.credentials=same-origin
185
- * @property {Object} fetch.headers={"accept":"text/html"}}
186
- * @property {Object} popper [PopperJS Options](https://popper.js.org/docs/v2/)
187
- * @property {string} popper.placement=bottom PopperJS placement
188
- * @property {Object[]} modifiers={name:offset} PopperJS placement
189
- */
190
- get defaults() {
191
- return Object.assign({}, super.defaults, {
192
- templates: {
193
- main: getTemplate(),
194
- },
195
- labels: {
196
- "new-tab-label": "New Tab",
197
- },
198
- buttons: {
199
- standard: [],
200
- popper: [],
201
- },
202
- fetch: {
203
- redirect: "error",
204
- method: "GET",
205
- mode: "same-origin",
206
- credentials: "same-origin",
207
- headers: {
208
- accept: "text/html",
209
- },
210
- },
211
-
212
- features: {
213
- openDelay: null,
214
- removeBehavior: "auto",
215
- },
216
-
217
- classes: {
218
- button: "monster-theme-primary-1",
219
- popper: "monster-theme-primary-1",
220
- navigation: "monster-theme-primary-1",
221
- },
222
-
223
- popper: {
224
- placement: "bottom",
225
- modifiers: [
226
- {
227
- name: "offset",
228
- options: {
229
- offset: [0, 2],
230
- },
231
- },
232
-
233
- {
234
- name: "eventListeners",
235
- enabled: false,
236
- },
237
- ],
238
- },
239
- });
240
- }
241
-
242
- /**
243
- * This method is called internal and should not be called directly.
244
- */
245
- [assembleMethodSymbol]() {
246
- super[assembleMethodSymbol]();
247
-
248
- initControlReferences.call(this);
249
-
250
- this[dimensionsSymbol] = new Pathfinder({ data: {} });
251
-
252
- initEventHandler.call(this);
253
-
254
- // setup structure
255
- initTabButtons.call(this).then(() => {
256
- initPopperSwitch.call(this);
257
- initPopper.call(this);
258
- attachResizeObserver.call(this);
259
- attachTabChangeObserver.call(this);
260
- });
261
- }
262
-
263
- /**
264
- * This method is called internal and should not be called directly.
265
- *
266
- * @return {CSSStyleSheet[]}
267
- */
268
- static getCSSStyleSheet() {
269
- return [TabsStyleSheet];
270
- }
271
-
272
- /**
273
- * This method is called internal and should not be called directly.
274
- *
275
- * @return {string}
276
- */
277
- static getTag() {
278
- return "monster-tabs";
279
- }
280
-
281
- /**
282
- * A function that activates a tab based on the provided name.
283
- *
284
- * The tabs have to be named with the `data-monster-name` attribute.
285
- *
286
- * @param {type} idOrName - the name or id of the tab to activate
287
- * @return {Tabs} - The current instance
288
- */
289
- activeTab(idOrName) {
290
- let found = false;
291
-
292
- getSlottedElements.call(this).forEach((node) => {
293
- if (found === true) {
294
- return;
295
- }
296
-
297
- if (node.getAttribute("data-monster-name") === idOrName) {
298
- this.shadowRoot
299
- .querySelector(
300
- `[data-monster-tab-reference="${node.getAttribute("id")}"]`,
301
- )
302
- .click();
303
- found = true;
304
- }
305
-
306
- if (node.getAttribute("id") === idOrName) {
307
- this.shadowRoot
308
- .querySelector(
309
- `[data-monster-tab-reference="${node.getAttribute("id")}"]`,
310
- )
311
- .click();
312
- found = true;
313
- }
314
- });
315
-
316
- return this;
317
- }
318
-
319
- /**
320
- * A function that returns the name or id of the currently active tab.
321
- *
322
- * The tabs have to be named with the `data-monster-name` attribute.
323
- *
324
- * @return {string|null}
325
- */
326
- getActiveTab() {
327
- const nodes = getSlottedElements.call(this);
328
- for (const node of nodes) {
329
- if (node.matches(".active") === true) {
330
- if (node.hasAttribute("data-monster-name")) {
331
- return node.getAttribute("data-monster-name");
332
- }
333
-
334
- return node.getAttribute("id");
335
- }
336
- }
337
- return null;
338
- }
339
-
340
- /**
341
- * This method is called by the dom and should not be called directly.
342
- *
343
- * @return {void}
344
- */
345
- connectedCallback() {
346
- super.connectedCallback();
347
-
348
- const document = getDocument();
349
-
350
- for (const [, type] of Object.entries(["click", "touch"])) {
351
- // close on outside ui-events
352
- document.addEventListener(type, this[closeEventHandler]);
353
- }
354
- }
355
-
356
- /**
357
- * This method is called by the dom and should not be called directly.
358
- *
359
- * @return {void}
360
- */
361
- disconnectedCallback() {
362
- super.disconnectedCallback();
363
-
364
- const document = getDocument();
365
-
366
- // close on outside ui-events
367
- for (const [, type] of Object.entries(["click", "touch"])) {
368
- document.removeEventListener(type, this[closeEventHandler]);
369
- }
370
- }
159
+ /**
160
+ * This method is called by the `instanceof` operator.
161
+ * @return {symbol}
162
+ */
163
+ static get [instanceSymbol]() {
164
+ return Symbol.for("@schukai/monster/components/layout/tabs");
165
+ }
166
+
167
+ /**
168
+ * To set the options via the HTML tag, the attribute `data-monster-options` must be used.
169
+ * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
170
+ *
171
+ * The individual configuration values can be found in the table.
172
+ *
173
+ * @property {Object} templates Template definitions
174
+ * @property {string} templates.main Main template
175
+ * @property {Object} labels
176
+ * @property {string} labels.new-tab-label="New Tab"
177
+ * @property {Object} features
178
+ * @property {number} features.openDelay=500 Open delay in milliseconds
179
+ * @property {string} features.removeBehavior="auto" Remove behavior, auto (default), next, previous and none
180
+ * @property {Object} fetch Fetch [see Using Fetch mozilla.org](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch)
181
+ * @property {String} fetch.redirect=error
182
+ * @property {String} fetch.method=GET
183
+ * @property {String} fetch.mode=same-origin
184
+ * @property {String} fetch.credentials=same-origin
185
+ * @property {Object} fetch.headers={"accept":"text/html"}}
186
+ * @property {Object} popper [PopperJS Options](https://popper.js.org/docs/v2/)
187
+ * @property {string} popper.placement=bottom PopperJS placement
188
+ * @property {Object[]} modifiers={name:offset} PopperJS placement
189
+ */
190
+ get defaults() {
191
+ return Object.assign({}, super.defaults, {
192
+ templates: {
193
+ main: getTemplate(),
194
+ },
195
+ labels: {
196
+ "new-tab-label": "New Tab",
197
+ },
198
+ buttons: {
199
+ standard: [],
200
+ popper: [],
201
+ },
202
+ fetch: {
203
+ redirect: "error",
204
+ method: "GET",
205
+ mode: "same-origin",
206
+ credentials: "same-origin",
207
+ headers: {
208
+ accept: "text/html",
209
+ },
210
+ },
211
+
212
+ features: {
213
+ openDelay: null,
214
+ removeBehavior: "auto",
215
+ },
216
+
217
+ classes: {
218
+ button: "monster-theme-primary-1",
219
+ popper: "monster-theme-primary-1",
220
+ navigation: "monster-theme-primary-1",
221
+ },
222
+
223
+ popper: {
224
+ placement: "bottom",
225
+ modifiers: [
226
+ {
227
+ name: "offset",
228
+ options: {
229
+ offset: [0, 2],
230
+ },
231
+ },
232
+
233
+ {
234
+ name: "eventListeners",
235
+ enabled: false,
236
+ },
237
+ ],
238
+ },
239
+ });
240
+ }
241
+
242
+ /**
243
+ * This method is called internal and should not be called directly.
244
+ */
245
+ [assembleMethodSymbol]() {
246
+ super[assembleMethodSymbol]();
247
+
248
+ initControlReferences.call(this);
249
+
250
+ this[dimensionsSymbol] = new Pathfinder({data: {}});
251
+
252
+ initEventHandler.call(this);
253
+
254
+ // setup structure
255
+ initTabButtons.call(this).then(() => {
256
+ initPopperSwitch.call(this);
257
+ initPopper.call(this);
258
+ attachResizeObserver.call(this);
259
+ attachTabChangeObserver.call(this);
260
+ });
261
+ }
262
+
263
+ /**
264
+ * This method is called internal and should not be called directly.
265
+ *
266
+ * @return {CSSStyleSheet[]}
267
+ */
268
+ static getCSSStyleSheet() {
269
+ return [TabsStyleSheet];
270
+ }
271
+
272
+ /**
273
+ * This method is called internal and should not be called directly.
274
+ *
275
+ * @return {string}
276
+ */
277
+ static getTag() {
278
+ return "monster-tabs";
279
+ }
280
+
281
+ /**
282
+ * A function that activates a tab based on the provided name.
283
+ *
284
+ * The tabs have to be named with the `data-monster-name` attribute.
285
+ *
286
+ * @param {type} idOrName - the name or id of the tab to activate
287
+ * @return {Tabs} - The current instance
288
+ */
289
+ activeTab(idOrName) {
290
+ let found = false;
291
+
292
+ getSlottedElements.call(this).forEach((node) => {
293
+ if (found === true) {
294
+ return;
295
+ }
296
+
297
+ if (node.getAttribute("data-monster-name") === idOrName) {
298
+ this.shadowRoot
299
+ .querySelector(
300
+ `[data-monster-tab-reference="${node.getAttribute("id")}"]`,
301
+ )
302
+ .click();
303
+ found = true;
304
+ }
305
+
306
+ if (node.getAttribute("id") === idOrName) {
307
+ this.shadowRoot
308
+ .querySelector(
309
+ `[data-monster-tab-reference="${node.getAttribute("id")}"]`,
310
+ )
311
+ .click();
312
+ found = true;
313
+ }
314
+ });
315
+
316
+ return this;
317
+ }
318
+
319
+ /**
320
+ * A function that returns the name or id of the currently active tab.
321
+ *
322
+ * The tabs have to be named with the `data-monster-name` attribute.
323
+ *
324
+ * @return {string|null}
325
+ */
326
+ getActiveTab() {
327
+ const nodes = getSlottedElements.call(this);
328
+ for (const node of nodes) {
329
+ if (node.matches(".active") === true) {
330
+ if (node.hasAttribute("data-monster-name")) {
331
+ return node.getAttribute("data-monster-name");
332
+ }
333
+
334
+ return node.getAttribute("id");
335
+ }
336
+ }
337
+ return null;
338
+ }
339
+
340
+ /**
341
+ * This method is called by the dom and should not be called directly.
342
+ *
343
+ * @return {void}
344
+ */
345
+ connectedCallback() {
346
+ super.connectedCallback();
347
+
348
+ const document = getDocument();
349
+
350
+ for (const [, type] of Object.entries(["click", "touch"])) {
351
+ // close on outside ui-events
352
+ document.addEventListener(type, this[closeEventHandler]);
353
+ }
354
+ }
355
+
356
+ /**
357
+ * This method is called by the dom and should not be called directly.
358
+ *
359
+ * @return {void}
360
+ */
361
+ disconnectedCallback() {
362
+ super.disconnectedCallback();
363
+
364
+ const document = getDocument();
365
+
366
+ // close on outside ui-events
367
+ for (const [, type] of Object.entries(["click", "touch"])) {
368
+ document.removeEventListener(type, this[closeEventHandler]);
369
+ }
370
+ }
371
371
  }
372
372
 
373
373
  /**
374
374
  * @private
375
375
  */
376
376
  function initPopperSwitch() {
377
- const nodes = getSlottedElements.call(this, `[${ATTRIBUTE_ROLE}="switch"]`); // null ↦ only unnamed slots
378
- let switchButton;
379
- if (nodes.size === 0) {
380
- switchButton = document.createElement("button");
381
- switchButton.setAttribute(ATTRIBUTE_ROLE, "switch");
382
- switchButton.setAttribute("part", "switch");
383
- switchButton.classList.add("hidden");
384
- const classList = this.getOption("classes.button");
385
- if (classList) {
386
- switchButton.classList.add(classList);
387
- }
388
- switchButton.innerHTML =
389
- '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"><path d="M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"/></svg>';
390
- this[navElementSymbol].prepend(switchButton);
391
- } else {
392
- switchButton = nodes.next();
393
- }
394
-
395
- /**
396
- * @param {Event} event
397
- */
398
- this[popperSwitchEventHandler] = (event) => {
399
- const element = findTargetElementFromEvent(event, ATTRIBUTE_ROLE, "switch");
400
-
401
- if (element instanceof HTMLButtonElement) {
402
- togglePopper.call(this);
403
- }
404
- };
405
-
406
- for (const type of ["click", "touch"]) {
407
- switchButton.addEventListener(type, this[popperSwitchEventHandler]);
408
- }
409
-
410
- this[switchElementSymbol] = switchButton;
377
+ const nodes = getSlottedElements.call(this, `[${ATTRIBUTE_ROLE}="switch"]`); // null ↦ only unnamed slots
378
+ let switchButton;
379
+ if (nodes.size === 0) {
380
+ switchButton = document.createElement("button");
381
+ switchButton.setAttribute(ATTRIBUTE_ROLE, "switch");
382
+ switchButton.setAttribute("part", "switch");
383
+ switchButton.classList.add("hidden");
384
+ const classList = this.getOption("classes.button");
385
+ if (classList) {
386
+ switchButton.classList.add(classList);
387
+ }
388
+ switchButton.innerHTML =
389
+ '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"><path d="M9.5 13a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0zm0-5a1.5 1.5 0 1 1-3 0 1.5 1.5 0 0 1 3 0z"/></svg>';
390
+ this[navElementSymbol].prepend(switchButton);
391
+ } else {
392
+ switchButton = nodes.next();
393
+ }
394
+
395
+ /**
396
+ * @param {Event} event
397
+ */
398
+ this[popperSwitchEventHandler] = (event) => {
399
+ const element = findTargetElementFromEvent(event, ATTRIBUTE_ROLE, "switch");
400
+
401
+ if (element instanceof HTMLButtonElement) {
402
+ togglePopper.call(this);
403
+ }
404
+ };
405
+
406
+ for (const type of ["click", "touch"]) {
407
+ switchButton.addEventListener(type, this[popperSwitchEventHandler]);
408
+ }
409
+
410
+ this[switchElementSymbol] = switchButton;
411
411
  }
412
412
 
413
413
  /**
414
414
  * @private
415
415
  */
416
416
  function hidePopper() {
417
- if (!this[popperInstanceSymbol]) {
418
- return;
419
- }
417
+ if (!this[popperInstanceSymbol]) {
418
+ return;
419
+ }
420
420
 
421
- this[popperElementSymbol].style.display = "none";
422
- // performance https://popper.js.org/docs/v2/tutorial/#performance
423
- setEventListenersModifiers.call(this, false);
421
+ this[popperElementSymbol].style.display = "none";
422
+ // performance https://popper.js.org/docs/v2/tutorial/#performance
423
+ setEventListenersModifiers.call(this, false);
424
424
  }
425
425
 
426
426
  /**
427
427
  * @private
428
428
  */
429
429
  function showPopper() {
430
- if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) {
431
- return;
432
- }
433
-
434
- this[popperElementSymbol].style.visibility = "hidden";
435
- this[popperElementSymbol].style.display = STYLE_DISPLAY_MODE_BLOCK;
436
- // performance https://popper.js.org/docs/v2/tutorial/#performance
437
- setEventListenersModifiers.call(this, true);
438
-
439
- this[popperInstanceSymbol].update();
440
-
441
- new Processing(() => {
442
- this[popperElementSymbol].style.removeProperty("visibility");
443
- })
444
- .run(undefined)
445
- .then(() => {})
446
- .catch((e) => {
447
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
448
- });
430
+ if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) {
431
+ return;
432
+ }
433
+
434
+ this[popperElementSymbol].style.visibility = "hidden";
435
+ this[popperElementSymbol].style.display = STYLE_DISPLAY_MODE_BLOCK;
436
+ // performance https://popper.js.org/docs/v2/tutorial/#performance
437
+ setEventListenersModifiers.call(this, true);
438
+
439
+ this[popperInstanceSymbol].update();
440
+
441
+ new Processing(() => {
442
+ this[popperElementSymbol].style.removeProperty("visibility");
443
+ })
444
+ .run(undefined)
445
+ .then(() => {
446
+ })
447
+ .catch((e) => {
448
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
449
+ });
449
450
  }
450
451
 
451
452
  /**
452
453
  * @private
453
454
  */
454
455
  function togglePopper() {
455
- if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) {
456
- hidePopper.call(this);
457
- } else {
458
- showPopper.call(this);
459
- }
456
+ if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) {
457
+ hidePopper.call(this);
458
+ } else {
459
+ showPopper.call(this);
460
+ }
460
461
  }
461
462
 
462
463
  /**
463
464
  * @private
464
465
  */
465
466
  function attachResizeObserver() {
466
- // against flickering
467
- this[resizeObserverSymbol] = new ResizeObserver((entries) => {
468
- if (this[timerCallbackSymbol] instanceof DeadMansSwitch) {
469
- try {
470
- this[timerCallbackSymbol].touch();
471
- return;
472
- } catch (e) {
473
- delete this[timerCallbackSymbol];
474
- }
475
- }
476
-
477
- this[timerCallbackSymbol] = new DeadMansSwitch(200, () => {
478
- this[dimensionsSymbol].setVia("data.calculated", false);
479
- checkAndRearrangeButtons.call(this);
480
- });
481
- });
482
-
483
- this[resizeObserverSymbol].observe(this[navElementSymbol]);
467
+ // against flickering
468
+ this[resizeObserverSymbol] = new ResizeObserver((entries) => {
469
+ if (this[timerCallbackSymbol] instanceof DeadMansSwitch) {
470
+ try {
471
+ this[timerCallbackSymbol].touch();
472
+ return;
473
+ } catch (e) {
474
+ delete this[timerCallbackSymbol];
475
+ }
476
+ }
477
+
478
+ this[timerCallbackSymbol] = new DeadMansSwitch(200, () => {
479
+ this[dimensionsSymbol].setVia("data.calculated", false);
480
+ checkAndRearrangeButtons.call(this);
481
+ });
482
+ });
483
+
484
+ this[resizeObserverSymbol].observe(this[navElementSymbol]);
484
485
  }
485
486
 
486
487
  /**
487
488
  * @private
488
489
  */
489
490
  function attachTabChangeObserver() {
490
- // against flickering
491
- new MutationObserver((mutations) => {
492
- let runUpdate = false;
493
-
494
- for (const mutation of mutations) {
495
- if (mutation.type === "childList") {
496
- if (
497
- mutation.addedNodes.length > 0 ||
498
- mutation.removedNodes.length > 0
499
- ) {
500
- runUpdate = true;
501
- break;
502
- }
503
- }
504
- }
505
-
506
- if (runUpdate === true) {
507
- this[dimensionsSymbol].setVia("data.calculated", false);
508
- initTabButtons.call(this);
509
- }
510
- }).observe(this, {
511
- childList: true,
512
- });
491
+ // against flickering
492
+ new MutationObserver((mutations) => {
493
+ let runUpdate = false;
494
+
495
+ for (const mutation of mutations) {
496
+ if (mutation.type === "childList") {
497
+ if (
498
+ mutation.addedNodes.length > 0 ||
499
+ mutation.removedNodes.length > 0
500
+ ) {
501
+ runUpdate = true;
502
+ break;
503
+ }
504
+ }
505
+ }
506
+
507
+ if (runUpdate === true) {
508
+ this[dimensionsSymbol].setVia("data.calculated", false);
509
+ initTabButtons.call(this);
510
+ }
511
+ }).observe(this, {
512
+ childList: true,
513
+ });
513
514
  }
514
515
 
515
516
  /**
@@ -518,41 +519,41 @@ function attachTabChangeObserver() {
518
519
  * @external "external:createPopper"
519
520
  */
520
521
  function initPopper() {
521
- const self = this;
522
-
523
- const options = extend({}, self.getOption("popper"));
524
-
525
- self[popperInstanceSymbol] = createPopper(
526
- self[switchElementSymbol],
527
- self[popperElementSymbol],
528
- options,
529
- );
530
-
531
- const observer1 = new MutationObserver(function (mutations) {
532
- let runUpdate = false;
533
- for (const mutation of mutations) {
534
- if (mutation.type === "childList") {
535
- if (
536
- mutation.addedNodes.length > 0 ||
537
- mutation.removedNodes.length > 0
538
- ) {
539
- runUpdate = true;
540
- break;
541
- }
542
- }
543
- }
544
-
545
- if (runUpdate === true) {
546
- self[popperInstanceSymbol].update();
547
- }
548
- });
549
-
550
- observer1.observe(self[popperNavElementSymbol], {
551
- childList: true,
552
- subtree: true,
553
- });
554
-
555
- return self;
522
+ const self = this;
523
+
524
+ const options = extend({}, self.getOption("popper"));
525
+
526
+ self[popperInstanceSymbol] = createPopper(
527
+ self[switchElementSymbol],
528
+ self[popperElementSymbol],
529
+ options,
530
+ );
531
+
532
+ const observer1 = new MutationObserver(function (mutations) {
533
+ let runUpdate = false;
534
+ for (const mutation of mutations) {
535
+ if (mutation.type === "childList") {
536
+ if (
537
+ mutation.addedNodes.length > 0 ||
538
+ mutation.removedNodes.length > 0
539
+ ) {
540
+ runUpdate = true;
541
+ break;
542
+ }
543
+ }
544
+ }
545
+
546
+ if (runUpdate === true) {
547
+ self[popperInstanceSymbol].update();
548
+ }
549
+ });
550
+
551
+ observer1.observe(self[popperNavElementSymbol], {
552
+ childList: true,
553
+ subtree: true,
554
+ });
555
+
556
+ return self;
556
557
  }
557
558
 
558
559
  /**
@@ -560,202 +561,229 @@ function initPopper() {
560
561
  * @param {HTMLElement} element
561
562
  */
562
563
  function show(element) {
563
- if (!this.shadowRoot) {
564
- throw new Error("no shadow-root is defined");
565
- }
566
-
567
- const reference = element.getAttribute(`${ATTRIBUTE_PREFIX}tab-reference`);
568
-
569
- const nodes = getSlottedElements.call(this);
570
- for (const node of nodes) {
571
- const id = node.getAttribute("id");
572
-
573
- if (id === reference) {
574
- node.classList.add("active");
575
-
576
- const openDelay = parseInt(this.getOption("features.openDelay"), 10);
577
-
578
- if (!isNaN(openDelay) && openDelay > 0) {
579
- node.style.visibility = "hidden";
580
-
581
- setTimeout(() => {
582
- node.style.visibility = "visible";
583
- }, openDelay);
584
- }
585
-
586
- // get all data- from button and filter out data-monster-attributes and data-monster-insert
587
- const data = {};
588
- const mask = [
589
- "data-monster-attributes",
590
- "data-monster-insert-reference",
591
- "data-monster-state",
592
- "data-monster-button-label",
593
- "data-monster-objectlink",
594
- "data-monster-role",
595
- ];
596
-
597
- for (const [, attr] of Object.entries(node.attributes)) {
598
- if (attr.name.startsWith("data-") && mask.indexOf(attr.name) === -1) {
599
- data[attr.name] = attr.value;
600
- }
601
- }
602
-
603
- if (node.hasAttribute(ATTRIBUTE_FORM_URL)) {
604
- const url = node.getAttribute(ATTRIBUTE_FORM_URL);
605
-
606
- if (
607
- !node.hasAttribute(ATTRIBUTE_FORM_RELOAD) ||
608
- node.getAttribute(ATTRIBUTE_FORM_RELOAD).toLowerCase() === "onshow"
609
- ) {
610
- node.removeAttribute(ATTRIBUTE_FORM_URL);
611
- }
612
-
613
- const options = this.getOption("fetch", {});
614
- const filter = undefined;
615
- loadAndAssignContent(node, url, options, filter)
616
- .then(() => {
617
- fireCustomEvent(this, "monster-tab-changed", {
618
- reference,
619
- });
620
- })
621
- .catch((e) => {
622
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
623
- });
624
- } else {
625
- fireCustomEvent(this, "monster-tab-changed", {
626
- reference,
627
- data,
628
- });
629
- }
630
- } else {
631
- node.classList.remove("active");
632
- }
633
- }
634
-
635
- const standardButtons = this.getOption("buttons.standard");
636
- for (const index in standardButtons) {
637
- const button = standardButtons[index];
638
- const state = button["reference"] === reference ? "active" : "inactive";
639
- this.setOption(`buttons.standard.${index}.state`, state);
640
- }
641
-
642
- const popperButton = this.getOption("buttons.popper");
643
- for (const index in popperButton) {
644
- const button = popperButton[index];
645
- const state = button["reference"] === reference ? "active" : "inactive";
646
- this.setOption(`buttons.popper.${index}.state`, state);
647
- }
648
-
649
- hidePopper.call(this);
564
+ if (!this.shadowRoot) {
565
+ throw new Error("no shadow-root is defined");
566
+ }
567
+
568
+ const reference = element.getAttribute(`${ATTRIBUTE_PREFIX}tab-reference`);
569
+
570
+ const nodes = getSlottedElements.call(this);
571
+ for (const node of nodes) {
572
+ const id = node.getAttribute("id");
573
+
574
+ if (id === reference) {
575
+ node.classList.add("active");
576
+
577
+ const openDelay = parseInt(this.getOption("features.openDelay"), 10);
578
+
579
+ if (!isNaN(openDelay) && openDelay > 0) {
580
+ node.style.visibility = "hidden";
581
+
582
+ setTimeout(() => {
583
+ node.style.visibility = "visible";
584
+ }, openDelay);
585
+ }
586
+
587
+ // get all data- from button and filter out data-monster-attributes and data-monster-insert
588
+ const data = {};
589
+ const mask = [
590
+ "data-monster-attributes",
591
+ "data-monster-insert-reference",
592
+ "data-monster-state",
593
+ "data-monster-button-label",
594
+ "data-monster-objectlink",
595
+ "data-monster-role",
596
+ ];
597
+
598
+ for (const [, attr] of Object.entries(node.attributes)) {
599
+ if (attr.name.startsWith("data-") && mask.indexOf(attr.name) === -1) {
600
+ data[attr.name] = attr.value;
601
+ }
602
+ }
603
+
604
+ if (node.hasAttribute(ATTRIBUTE_FORM_URL)) {
605
+ const url = node.getAttribute(ATTRIBUTE_FORM_URL);
606
+
607
+ if (
608
+ !node.hasAttribute(ATTRIBUTE_FORM_RELOAD) ||
609
+ node.getAttribute(ATTRIBUTE_FORM_RELOAD).toLowerCase() === "onshow"
610
+ ) {
611
+ node.removeAttribute(ATTRIBUTE_FORM_URL);
612
+ }
613
+
614
+ const options = this.getOption("fetch", {});
615
+ const filter = undefined;
616
+ loadAndAssignContent(node, url, options, filter)
617
+ .then(() => {
618
+ fireCustomEvent(this, "monster-tab-changed", {
619
+ reference,
620
+ });
621
+ })
622
+ .catch((e) => {
623
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
624
+ });
625
+ } else {
626
+ fireCustomEvent(this, "monster-tab-changed", {
627
+ reference,
628
+ data,
629
+ });
630
+ }
631
+ } else {
632
+ node.classList.remove("active");
633
+ }
634
+ }
635
+
636
+ const standardButtons = this.getOption("buttons.standard");
637
+ for (const index in standardButtons) {
638
+ const button = standardButtons[index];
639
+ const state = button["reference"] === reference ? "active" : "inactive";
640
+ this.setOption(`buttons.standard.${index}.state`, state);
641
+ }
642
+
643
+ const popperButton = this.getOption("buttons.popper");
644
+ for (const index in popperButton) {
645
+ const button = popperButton[index];
646
+ const state = button["reference"] === reference ? "active" : "inactive";
647
+ this.setOption(`buttons.popper.${index}.state`, state);
648
+ }
649
+
650
+ hidePopper.call(this);
650
651
  }
651
652
 
652
653
  /**
653
654
  * @private
654
655
  */
655
656
  function initEventHandler() {
656
- if (!this.shadowRoot) {
657
- throw new Error("no shadow-root is defined");
658
- }
659
-
660
- /**
661
- * @param {Event} event
662
- */
663
- this[changeTabEventHandler] = (event) => {
664
- const element = findTargetElementFromEvent(event, ATTRIBUTE_ROLE, "button");
665
-
666
- if (element instanceof HTMLButtonElement && element.disabled !== true) {
667
- show.call(this, element);
668
- }
669
- };
670
-
671
- /**
672
- * @param {Event} event
673
- * @fires monster-tab-remove
674
- */
675
- this[removeTabEventHandler] = (event) => {
676
- const element = findTargetElementFromEvent(
677
- event,
678
- ATTRIBUTE_ROLE,
679
- "remove-tab",
680
- );
681
-
682
- if (element instanceof HTMLElement) {
683
- const button = findTargetElementFromEvent(
684
- event,
685
- ATTRIBUTE_ROLE,
686
- "button",
687
- );
688
-
689
- if (button instanceof HTMLButtonElement && button.disabled !== true) {
690
- const reference = button.getAttribute(
691
- `${ATTRIBUTE_PREFIX}tab-reference`,
692
- );
693
-
694
- const previous = button.previousElementSibling;
695
- const next = button.nextElementSibling;
696
-
697
- if (reference) {
698
- const container = this.querySelector(`[id=${reference}]`);
699
- if (container instanceof HTMLElement) {
700
- container.remove();
701
- initTabButtons.call(this);
702
- fireCustomEvent(this, "monster-tab-remove", {
703
- reference,
704
- });
705
- }
706
- }
707
-
708
- switch (this.getOption("features.removeBehavior")) {
709
- case "auto":
710
- if (next instanceof HTMLButtonElement) {
711
- next.click();
712
- } else {
713
- // get previous button
714
- if (previous instanceof HTMLButtonElement) {
715
- previous.click();
716
- }
717
- }
718
- break;
719
- case "next":
720
- if (next instanceof HTMLButtonElement) {
721
- next.click();
722
- }
723
- break;
724
- case "previous":
725
- if (previous instanceof HTMLButtonElement) {
726
- previous.click();
727
- }
728
- break;
729
-
730
- default: // and "none"
731
- break;
732
- }
733
- }
734
- }
735
- };
736
-
737
- this[navElementSymbol].addEventListener("touch", this[changeTabEventHandler]);
738
- this[navElementSymbol].addEventListener("click", this[changeTabEventHandler]);
739
-
740
- this[navElementSymbol].addEventListener("touch", this[removeTabEventHandler]);
741
- this[navElementSymbol].addEventListener("click", this[removeTabEventHandler]);
742
-
743
- /**
744
- * @param {Event} event
745
- */
746
- this[closeEventHandler] = (event) => {
747
- const path = event.composedPath();
748
-
749
- for (const [, element] of Object.entries(path)) {
750
- if (element === this) {
751
- return;
752
- }
753
- }
754
-
755
- hidePopper.call(this);
756
- };
757
-
758
- return this;
657
+ const self = this;
658
+
659
+ if (!this.shadowRoot) {
660
+ throw new Error("no shadow-root is defined");
661
+ }
662
+
663
+ /**
664
+ * @param {Event} event
665
+ * @fires monster-tab-remove
666
+ */
667
+ this[removeTabEventHandler] = (event) => {
668
+
669
+ const element = findTargetElementFromEvent(
670
+ event,
671
+ ATTRIBUTE_ROLE,
672
+ "remove-tab",
673
+ );
674
+
675
+ if (element instanceof HTMLElement) {
676
+ const button = findTargetElementFromEvent(
677
+ event,
678
+ ATTRIBUTE_ROLE,
679
+ "button",
680
+ );
681
+
682
+ if (button instanceof HTMLButtonElement && button.disabled !== true) {
683
+ const reference = button.getAttribute(
684
+ `${ATTRIBUTE_PREFIX}tab-reference`,
685
+ );
686
+
687
+ let doChange = false;
688
+ let nextName = null
689
+ let previousName = null;
690
+
691
+ const btn = this.getOption("buttons")
692
+ for (let i = 0; i < btn.standard.length; i++) {
693
+ if (btn.standard[i].reference === reference) {
694
+ if (btn.standard[i].state === "active") {
695
+ doChange = i
696
+ if (i < btn.standard.length - 1) {
697
+ nextName = btn.standard[i + 1]?.reference
698
+ }
699
+ if (i > 0) {
700
+ previousName = btn.standard[i - 1]?.reference
701
+ }
702
+ }
703
+ break;
704
+ }
705
+ }
706
+
707
+ if (reference) {
708
+ const container = this.querySelector(`[id=${reference}]`);
709
+ if (container instanceof HTMLElement) {
710
+
711
+ if (doChange) {
712
+
713
+ switch (this.getOption("features.removeBehavior")) {
714
+ case "auto":
715
+ if (nextName !== null) {
716
+ self.activeTab(nextName);
717
+ } else {
718
+ if (previousName !== null) {
719
+ self.activeTab(previousName);
720
+ }
721
+ }
722
+ break;
723
+ case "next":
724
+ if (nextName !== null) {
725
+ self.activeTab(nextName);
726
+ }
727
+ break;
728
+ case "previous":
729
+ if (previousName !== null) {
730
+ self.activeTab(previousName);
731
+ }
732
+ break;
733
+
734
+ default: // and "none"
735
+ break;
736
+ }
737
+ }
738
+
739
+ container.remove();
740
+ initTabButtons.call(this);
741
+ fireCustomEvent(this, "monster-tab-remove", {
742
+ reference,
743
+ });
744
+ }
745
+ }
746
+
747
+ }
748
+ }
749
+ };
750
+
751
+ /**
752
+ * @param {Event} event
753
+ */
754
+ this[changeTabEventHandler] = (event) => {
755
+
756
+ const element = findTargetElementFromEvent(event, ATTRIBUTE_ROLE, "button");
757
+
758
+ if (element instanceof HTMLButtonElement && element.disabled !== true) {
759
+ show.call(this, element);
760
+ }
761
+ };
762
+
763
+ /**
764
+ * @param {Event} event
765
+ */
766
+ this[closeEventHandler] = (event) => {
767
+ const path = event.composedPath();
768
+
769
+ for (const [, element] of Object.entries(path)) {
770
+ if (element === this) {
771
+ return;
772
+ }
773
+ }
774
+
775
+ hidePopper.call(this);
776
+ };
777
+
778
+
779
+ // the order is important, because the remove must be before the change
780
+ this[navElementSymbol].addEventListener("touch", this[removeTabEventHandler]);
781
+ this[navElementSymbol].addEventListener("click", this[removeTabEventHandler]);
782
+
783
+ this[navElementSymbol].addEventListener("touch", this[changeTabEventHandler]);
784
+ this[navElementSymbol].addEventListener("click", this[changeTabEventHandler]);
785
+
786
+ return this;
759
787
  }
760
788
 
761
789
  /**
@@ -763,37 +791,37 @@ function initEventHandler() {
763
791
  * @param observedNode
764
792
  */
765
793
  function attachTabMutationObserver(observedNode) {
766
- const self = this;
767
-
768
- if (hasObjectLink(observedNode, mutationObserverSymbol)) {
769
- return;
770
- }
771
-
772
- /**
773
- * this construct monitors a node whether it is disabled or modified
774
- * @type {MutationObserver}
775
- */
776
- const observer = new MutationObserver(function (mutations) {
777
- if (isArray(mutations)) {
778
- const mutation = mutations.pop();
779
- if (mutation instanceof MutationRecord) {
780
- initTabButtons.call(self);
781
- }
782
- }
783
- });
784
-
785
- observer.observe(observedNode, {
786
- childList: false,
787
- attributes: true,
788
- subtree: false,
789
- attributeFilter: [
790
- "disabled",
791
- ATTRIBUTE_BUTTON_LABEL,
792
- `${ATTRIBUTE_PREFIX}button-icon`,
793
- ],
794
- });
795
-
796
- addToObjectLink(observedNode, mutationObserverSymbol, observer);
794
+ const self = this;
795
+
796
+ if (hasObjectLink(observedNode, mutationObserverSymbol)) {
797
+ return;
798
+ }
799
+
800
+ /**
801
+ * this construct monitors a node whether it is disabled or modified
802
+ * @type {MutationObserver}
803
+ */
804
+ const observer = new MutationObserver(function (mutations) {
805
+ if (isArray(mutations)) {
806
+ const mutation = mutations.pop();
807
+ if (mutation instanceof MutationRecord) {
808
+ initTabButtons.call(self);
809
+ }
810
+ }
811
+ });
812
+
813
+ observer.observe(observedNode, {
814
+ childList: false,
815
+ attributes: true,
816
+ subtree: false,
817
+ attributeFilter: [
818
+ "disabled",
819
+ ATTRIBUTE_BUTTON_LABEL,
820
+ `${ATTRIBUTE_PREFIX}button-icon`,
821
+ ],
822
+ });
823
+
824
+ addToObjectLink(observedNode, mutationObserverSymbol, observer);
797
825
  }
798
826
 
799
827
  /**
@@ -802,22 +830,22 @@ function attachTabMutationObserver(observedNode) {
802
830
  * @throws {Error} no shadow-root is defined
803
831
  */
804
832
  function initControlReferences() {
805
- if (!this.shadowRoot) {
806
- throw new Error("no shadow-root is defined");
807
- }
808
-
809
- this[controlElementSymbol] = this.shadowRoot.querySelector(
810
- `[${ATTRIBUTE_ROLE}=control]`,
811
- );
812
- this[navElementSymbol] = this.shadowRoot.querySelector(
813
- `nav[${ATTRIBUTE_ROLE}=nav]`,
814
- );
815
- this[popperElementSymbol] = this.shadowRoot.querySelector(
816
- `[${ATTRIBUTE_ROLE}=popper]`,
817
- );
818
- this[popperNavElementSymbol] = this.shadowRoot.querySelector(
819
- `[${ATTRIBUTE_ROLE}=popper-nav]`,
820
- );
833
+ if (!this.shadowRoot) {
834
+ throw new Error("no shadow-root is defined");
835
+ }
836
+
837
+ this[controlElementSymbol] = this.shadowRoot.querySelector(
838
+ `[${ATTRIBUTE_ROLE}=control]`,
839
+ );
840
+ this[navElementSymbol] = this.shadowRoot.querySelector(
841
+ `nav[${ATTRIBUTE_ROLE}=nav]`,
842
+ );
843
+ this[popperElementSymbol] = this.shadowRoot.querySelector(
844
+ `[${ATTRIBUTE_ROLE}=popper]`,
845
+ );
846
+ this[popperNavElementSymbol] = this.shadowRoot.querySelector(
847
+ `[${ATTRIBUTE_ROLE}=popper-nav]`,
848
+ );
821
849
  }
822
850
 
823
851
  /**
@@ -827,101 +855,102 @@ function initControlReferences() {
827
855
  *
828
856
  */
829
857
  function initTabButtons() {
830
- if (!this.shadowRoot) {
831
- throw new Error("no shadow-root is defined");
832
- }
833
-
834
- let activeReference;
835
-
836
- const dimensionsCalculated = this[dimensionsSymbol].getVia(
837
- "data.calculated",
838
- false,
839
- );
840
-
841
- const buttons = [];
842
- const nodes = getSlottedElements.call(this, undefined, null); // null ↦ only unnamed slots
843
-
844
- for (const node of nodes) {
845
- if (!(node instanceof HTMLElement)) continue;
846
- let label = getButtonLabel.call(this, node);
847
-
848
- let reference;
849
- if (node.hasAttribute("id")) {
850
- reference = node.getAttribute("id");
851
- }
852
-
853
- let disabled;
854
- if (node.hasAttribute("disabled") || node.disabled === true) {
855
- disabled = true;
856
- }
857
-
858
- if (!reference) {
859
- reference = new ID("tab").toString();
860
- node.setAttribute("id", reference);
861
- }
862
-
863
- if (node.hasAttribute(`${ATTRIBUTE_PREFIX}button-icon`)) {
864
- label = `<span part="label">${label}</span><img part="icon" alt="this is an icon" src="${node.getAttribute(
865
- `${ATTRIBUTE_PREFIX}button-icon`,
866
- )}">`;
867
- }
868
-
869
- let remove = false;
870
- if (node.hasAttribute(`${ATTRIBUTE_PREFIX}removable`)) {
871
- remove = true;
872
- }
873
-
874
- if (node.matches(".active") === true && disabled !== true) {
875
- node.classList.remove("active");
876
- activeReference = reference;
877
- }
878
-
879
- const state = "";
880
- const classes = dimensionsCalculated ? "" : "invisible";
881
-
882
- buttons.push({
883
- reference,
884
- label,
885
- state,
886
- class: classes,
887
- disabled,
888
- remove,
889
- });
890
-
891
- attachTabMutationObserver.call(this, node);
892
- }
893
-
894
- this.setOption("buttons.standard", clone(buttons));
895
- this.setOption("buttons.popper", []);
896
- this.setOption("marker", random());
897
-
898
- return adjustButtonVisibility.call(this).then(() => {
899
- if (activeReference) {
900
- return new Processing(() => {
901
- const button = this.shadowRoot.querySelector(
902
- `[${ATTRIBUTE_PREFIX}tab-reference="${activeReference}"]`,
903
- );
904
- if (button instanceof HTMLButtonElement && button.disabled !== true) {
905
- show.call(this, button);
906
- }
907
- })
908
- .run(undefined)
909
- .then(() => {})
910
- .catch((e) => {
911
- addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
912
- });
913
- }
914
-
915
- return Promise.resolve();
916
- });
858
+ if (!this.shadowRoot) {
859
+ throw new Error("no shadow-root is defined");
860
+ }
861
+
862
+ let activeReference;
863
+
864
+ const dimensionsCalculated = this[dimensionsSymbol].getVia(
865
+ "data.calculated",
866
+ false,
867
+ );
868
+
869
+ const buttons = [];
870
+ const nodes = getSlottedElements.call(this, undefined, null); // null ↦ only unnamed slots
871
+
872
+ for (const node of nodes) {
873
+ if (!(node instanceof HTMLElement)) continue;
874
+ let label = getButtonLabel.call(this, node);
875
+
876
+ let reference;
877
+ if (node.hasAttribute("id")) {
878
+ reference = node.getAttribute("id");
879
+ }
880
+
881
+ let disabled;
882
+ if (node.hasAttribute("disabled") || node.disabled === true) {
883
+ disabled = true;
884
+ }
885
+
886
+ if (!reference) {
887
+ reference = new ID("tab").toString();
888
+ node.setAttribute("id", reference);
889
+ }
890
+
891
+ if (node.hasAttribute(`${ATTRIBUTE_PREFIX}button-icon`)) {
892
+ label = `<span part="label">${label}</span><img part="icon" alt="this is an icon" src="${node.getAttribute(
893
+ `${ATTRIBUTE_PREFIX}button-icon`,
894
+ )}">`;
895
+ }
896
+
897
+ let remove = false;
898
+ if (node.hasAttribute(`${ATTRIBUTE_PREFIX}removable`)) {
899
+ remove = true;
900
+ }
901
+
902
+ if (node.matches(".active") === true && disabled !== true) {
903
+ node.classList.remove("active");
904
+ activeReference = reference;
905
+ }
906
+
907
+ const state = "";
908
+ const classes = dimensionsCalculated ? "" : "invisible";
909
+
910
+ buttons.push({
911
+ reference,
912
+ label,
913
+ state,
914
+ class: classes,
915
+ disabled,
916
+ remove,
917
+ });
918
+
919
+ attachTabMutationObserver.call(this, node);
920
+ }
921
+
922
+ this.setOption("buttons.standard", clone(buttons));
923
+ this.setOption("buttons.popper", []);
924
+ this.setOption("marker", random());
925
+
926
+ return adjustButtonVisibility.call(this).then(() => {
927
+ if (activeReference) {
928
+ return new Processing(() => {
929
+ const button = this.shadowRoot.querySelector(
930
+ `[${ATTRIBUTE_PREFIX}tab-reference="${activeReference}"]`,
931
+ );
932
+ if (button instanceof HTMLButtonElement && button.disabled !== true) {
933
+ show.call(this, button);
934
+ }
935
+ })
936
+ .run(undefined)
937
+ .then(() => {
938
+ })
939
+ .catch((e) => {
940
+ addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
941
+ });
942
+ }
943
+
944
+ return Promise.resolve();
945
+ });
917
946
  }
918
947
 
919
948
  function checkAndRearrangeButtons() {
920
- if (this[dimensionsSymbol].getVia("data.calculated", false) !== true) {
921
- calculateNavigationButtonsDimensions.call(this);
922
- }
949
+ if (this[dimensionsSymbol].getVia("data.calculated", false) !== true) {
950
+ calculateNavigationButtonsDimensions.call(this);
951
+ }
923
952
 
924
- rearrangeButtons.call(this);
953
+ rearrangeButtons.call(this);
925
954
  }
926
955
 
927
956
  /**
@@ -929,29 +958,29 @@ function checkAndRearrangeButtons() {
929
958
  * @return {Promise<unknown>}
930
959
  */
931
960
  function adjustButtonVisibility() {
932
- const self = this;
961
+ const self = this;
933
962
 
934
- return new Promise((resolve) => {
935
- const observer = new MutationObserver(function (mutations) {
936
- const defCount = self.getOption("buttons.standard").length;
937
- const domCount = self[navElementSymbol].querySelectorAll(
938
- 'button[data-monster-role="button"]',
939
- ).length;
963
+ return new Promise((resolve) => {
964
+ const observer = new MutationObserver(function (mutations) {
965
+ const defCount = self.getOption("buttons.standard").length;
966
+ const domCount = self[navElementSymbol].querySelectorAll(
967
+ 'button[data-monster-role="button"]',
968
+ ).length;
940
969
 
941
- // in drawing
942
- if (defCount !== domCount) return;
970
+ // in drawing
971
+ if (defCount !== domCount) return;
943
972
 
944
- observer.disconnect();
973
+ observer.disconnect();
945
974
 
946
- checkAndRearrangeButtons.call(self);
975
+ checkAndRearrangeButtons.call(self);
947
976
 
948
- resolve();
949
- });
977
+ resolve();
978
+ });
950
979
 
951
- observer.observe(self[navElementSymbol], {
952
- attributes: true,
953
- });
954
- });
980
+ observer.observe(self[navElementSymbol], {
981
+ attributes: true,
982
+ });
983
+ });
955
984
  }
956
985
 
957
986
  /**
@@ -960,17 +989,17 @@ function adjustButtonVisibility() {
960
989
  * @return {number}
961
990
  */
962
991
  function getDimValue(value) {
963
- if ([undefined, null].indexOf(value) !== -1) {
964
- return 0;
965
- }
992
+ if ([undefined, null].indexOf(value) !== -1) {
993
+ return 0;
994
+ }
966
995
 
967
- const valueAsInt = parseInt(value, 10);
996
+ const valueAsInt = parseInt(value, 10);
968
997
 
969
- if (isNaN(valueAsInt)) {
970
- return 0;
971
- }
998
+ if (isNaN(valueAsInt)) {
999
+ return 0;
1000
+ }
972
1001
 
973
- return valueAsInt;
1002
+ return valueAsInt;
974
1003
  }
975
1004
 
976
1005
  /**
@@ -979,18 +1008,18 @@ function getDimValue(value) {
979
1008
  * @return {number}
980
1009
  */
981
1010
  function calcBoxWidth(node) {
982
- const dim = getGlobal("window").getComputedStyle(node);
983
- const bounding = node.getBoundingClientRect();
984
-
985
- return (
986
- getDimValue(dim["border-left-width"]) +
987
- getDimValue(dim["padding-left"]) +
988
- getDimValue(dim["margin-left"]) +
989
- getDimValue(bounding["width"]) +
990
- getDimValue(dim["border-right-width"]) +
991
- getDimValue(dim["margin-right"]) +
992
- getDimValue(dim["padding-left"])
993
- );
1011
+ const dim = getGlobal("window").getComputedStyle(node);
1012
+ const bounding = node.getBoundingClientRect();
1013
+
1014
+ return (
1015
+ getDimValue(dim["border-left-width"]) +
1016
+ getDimValue(dim["padding-left"]) +
1017
+ getDimValue(dim["margin-left"]) +
1018
+ getDimValue(bounding["width"]) +
1019
+ getDimValue(dim["border-right-width"]) +
1020
+ getDimValue(dim["margin-right"]) +
1021
+ getDimValue(dim["padding-left"])
1022
+ );
994
1023
  }
995
1024
 
996
1025
  /**
@@ -998,35 +1027,35 @@ function calcBoxWidth(node) {
998
1027
  * @return {Object}
999
1028
  */
1000
1029
  function rearrangeButtons() {
1001
- const standardButtons = [];
1002
- const popperButtons = [];
1003
-
1004
- let sum = 0;
1005
- const space = this[dimensionsSymbol].getVia("data.space");
1006
-
1007
- const buttons = this.getOption("buttons.standard");
1008
- for (const [, button] of buttons.entries()) {
1009
- const ref = button?.reference;
1010
-
1011
- sum += this[dimensionsSymbol].getVia(`data.button.${ref}`);
1012
-
1013
- if (sum > space) {
1014
- popperButtons.push(clone(button));
1015
- } else {
1016
- standardButtons.push(clone(button));
1017
- }
1018
- }
1019
-
1020
- this.setOption("buttons.standard", standardButtons);
1021
- this.setOption("buttons.popper", popperButtons);
1022
-
1023
- if (this[switchElementSymbol]) {
1024
- if (popperButtons.length > 0) {
1025
- this[switchElementSymbol].classList.remove("hidden");
1026
- } else {
1027
- this[switchElementSymbol].classList.add("hidden");
1028
- }
1029
- }
1030
+ const standardButtons = [];
1031
+ const popperButtons = [];
1032
+
1033
+ let sum = 0;
1034
+ const space = this[dimensionsSymbol].getVia("data.space");
1035
+
1036
+ const buttons = this.getOption("buttons.standard");
1037
+ for (const [, button] of buttons.entries()) {
1038
+ const ref = button?.reference;
1039
+
1040
+ sum += this[dimensionsSymbol].getVia(`data.button.${ref}`);
1041
+
1042
+ if (sum > space) {
1043
+ popperButtons.push(clone(button));
1044
+ } else {
1045
+ standardButtons.push(clone(button));
1046
+ }
1047
+ }
1048
+
1049
+ this.setOption("buttons.standard", standardButtons);
1050
+ this.setOption("buttons.popper", popperButtons);
1051
+
1052
+ if (this[switchElementSymbol]) {
1053
+ if (popperButtons.length > 0) {
1054
+ this[switchElementSymbol].classList.remove("hidden");
1055
+ } else {
1056
+ this[switchElementSymbol].classList.add("hidden");
1057
+ }
1058
+ }
1030
1059
  }
1031
1060
 
1032
1061
  /**
@@ -1034,50 +1063,50 @@ function rearrangeButtons() {
1034
1063
  * @return {Object}
1035
1064
  */
1036
1065
  function calculateNavigationButtonsDimensions() {
1037
- const width = this[navElementSymbol].getBoundingClientRect().width;
1038
-
1039
- let startEndWidth = 0;
1040
-
1041
- getSlottedElements.call(this, undefined, "start").forEach((node) => {
1042
- startEndWidth += calcBoxWidth.call(this, node);
1043
- });
1044
-
1045
- getSlottedElements.call(this, undefined, "end").forEach((node) => {
1046
- startEndWidth += calcBoxWidth.call(this, node);
1047
- });
1048
-
1049
- this[dimensionsSymbol].setVia("data.space", width - startEndWidth - 2);
1050
- this[dimensionsSymbol].setVia("data.visible", !(width === 0));
1051
-
1052
- const buttons = this.getOption("buttons.standard").concat(
1053
- this.getOption("buttons.popper"),
1054
- );
1055
-
1056
- for (const [i, button] of buttons.entries()) {
1057
- const ref = button?.reference;
1058
- const element = this[navElementSymbol].querySelector(
1059
- `:scope > [${ATTRIBUTE_PREFIX}tab-reference="${ref}"]`,
1060
- );
1061
- if (!(element instanceof HTMLButtonElement)) continue;
1062
-
1063
- this[dimensionsSymbol].setVia(
1064
- `data.button.${ref}`,
1065
- calcBoxWidth.call(this, element),
1066
- );
1067
- button["class"] = new TokenList(button["class"])
1068
- .remove("invisible")
1069
- .toString();
1070
- }
1071
-
1072
- const slots = this[controlElementSymbol].querySelectorAll(
1073
- `nav[${ATTRIBUTE_PREFIX}role=nav] > slot.invisible, slot[${ATTRIBUTE_PREFIX}role=slot].invisible`,
1074
- );
1075
- for (const [, slot] of slots.entries()) {
1076
- slot.classList.remove("invisible");
1077
- }
1078
-
1079
- this[dimensionsSymbol].setVia("data.calculated", true);
1080
- this.setOption("buttons.standard", clone(buttons));
1066
+ const width = this[navElementSymbol].getBoundingClientRect().width;
1067
+
1068
+ let startEndWidth = 0;
1069
+
1070
+ getSlottedElements.call(this, undefined, "start").forEach((node) => {
1071
+ startEndWidth += calcBoxWidth.call(this, node);
1072
+ });
1073
+
1074
+ getSlottedElements.call(this, undefined, "end").forEach((node) => {
1075
+ startEndWidth += calcBoxWidth.call(this, node);
1076
+ });
1077
+
1078
+ this[dimensionsSymbol].setVia("data.space", width - startEndWidth - 2);
1079
+ this[dimensionsSymbol].setVia("data.visible", !(width === 0));
1080
+
1081
+ const buttons = this.getOption("buttons.standard").concat(
1082
+ this.getOption("buttons.popper"),
1083
+ );
1084
+
1085
+ for (const [i, button] of buttons.entries()) {
1086
+ const ref = button?.reference;
1087
+ const element = this[navElementSymbol].querySelector(
1088
+ `:scope > [${ATTRIBUTE_PREFIX}tab-reference="${ref}"]`,
1089
+ );
1090
+ if (!(element instanceof HTMLButtonElement)) continue;
1091
+
1092
+ this[dimensionsSymbol].setVia(
1093
+ `data.button.${ref}`,
1094
+ calcBoxWidth.call(this, element),
1095
+ );
1096
+ button["class"] = new TokenList(button["class"])
1097
+ .remove("invisible")
1098
+ .toString();
1099
+ }
1100
+
1101
+ const slots = this[controlElementSymbol].querySelectorAll(
1102
+ `nav[${ATTRIBUTE_PREFIX}role=nav] > slot.invisible, slot[${ATTRIBUTE_PREFIX}role=slot].invisible`,
1103
+ );
1104
+ for (const [, slot] of slots.entries()) {
1105
+ slot.classList.remove("invisible");
1106
+ }
1107
+
1108
+ this[dimensionsSymbol].setVia("data.calculated", true);
1109
+ this.setOption("buttons.standard", clone(buttons));
1081
1110
  }
1082
1111
 
1083
1112
  /**
@@ -1086,34 +1115,34 @@ function calculateNavigationButtonsDimensions() {
1086
1115
  * @return {string}
1087
1116
  */
1088
1117
  function getButtonLabel(node) {
1089
- let label;
1090
- let setLabel = false;
1091
- if (node.hasAttribute(ATTRIBUTE_BUTTON_LABEL)) {
1092
- label = node.getAttribute(ATTRIBUTE_BUTTON_LABEL);
1093
- } else {
1094
- label = node.innerText;
1095
- setLabel = true;
1096
- }
1097
-
1098
- if (!isString(label)) {
1099
- label = "";
1100
- }
1101
-
1102
- label = label.trim();
1103
-
1104
- if (label === "") {
1105
- label = this.getOption("labels.new-tab-label", "New Tab");
1106
- }
1107
-
1108
- if (label.length > 100) {
1109
- label = `${label.substring(0, 99)}…`;
1110
- }
1111
-
1112
- if (setLabel === true) {
1113
- node.setAttribute(ATTRIBUTE_BUTTON_LABEL, label);
1114
- }
1115
-
1116
- return label;
1118
+ let label;
1119
+ let setLabel = false;
1120
+ if (node.hasAttribute(ATTRIBUTE_BUTTON_LABEL)) {
1121
+ label = node.getAttribute(ATTRIBUTE_BUTTON_LABEL);
1122
+ } else {
1123
+ label = node.innerText;
1124
+ setLabel = true;
1125
+ }
1126
+
1127
+ if (!isString(label)) {
1128
+ label = "";
1129
+ }
1130
+
1131
+ label = label.trim();
1132
+
1133
+ if (label === "") {
1134
+ label = this.getOption("labels.new-tab-label", "New Tab");
1135
+ }
1136
+
1137
+ if (label.length > 100) {
1138
+ label = `${label.substring(0, 99)}…`;
1139
+ }
1140
+
1141
+ if (setLabel === true) {
1142
+ node.setAttribute(ATTRIBUTE_BUTTON_LABEL, label);
1143
+ }
1144
+
1145
+ return label;
1117
1146
  }
1118
1147
 
1119
1148
  /**
@@ -1121,8 +1150,8 @@ function getButtonLabel(node) {
1121
1150
  * @return {string}
1122
1151
  */
1123
1152
  function getTemplate() {
1124
- // language=HTML
1125
- return `
1153
+ // language=HTML
1154
+ return `
1126
1155
  <template id="buttons">
1127
1156
  <button part="button"
1128
1157
  data-monster-role="button"