@schukai/monster 4.145.2 → 4.146.0
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/package.json +1 -1
- package/source/components/form/choice-cards.mjs +13 -2
- package/source/components/form/control-bar-spacer.mjs +3 -0
- package/source/components/form/control-bar.mjs +19 -2
- package/source/components/layout/style/tabs.pcss +13 -0
- package/source/components/layout/stylesheet/tabs.mjs +1 -1
- package/source/components/layout/tabs.mjs +808 -30
- package/test/cases/components/form/select.mjs +46 -0
- package/test/cases/components/layout/tabs.mjs +872 -463
|
@@ -35,7 +35,11 @@ import {
|
|
|
35
35
|
findTargetElementFromEvent,
|
|
36
36
|
fireCustomEvent,
|
|
37
37
|
} from "../../dom/events.mjs";
|
|
38
|
-
import {
|
|
38
|
+
import {
|
|
39
|
+
findElementWithSelectorUpwards,
|
|
40
|
+
getDocument,
|
|
41
|
+
getWindow,
|
|
42
|
+
} from "../../dom/util.mjs";
|
|
39
43
|
import { random } from "../../math/random.mjs";
|
|
40
44
|
import { getGlobal } from "../../types/global.mjs";
|
|
41
45
|
import { ID } from "../../types/id.mjs";
|
|
@@ -60,6 +64,7 @@ import {
|
|
|
60
64
|
setEventListenersModifiers,
|
|
61
65
|
} from "../form/util/popper.mjs";
|
|
62
66
|
import { getLocaleOfDocument } from "../../dom/locale.mjs";
|
|
67
|
+
import { generateComponentConfigKey } from "../host/util.mjs";
|
|
63
68
|
|
|
64
69
|
export { Tabs };
|
|
65
70
|
|
|
@@ -86,6 +91,12 @@ const controlElementSymbol = Symbol("controlElement");
|
|
|
86
91
|
* @type {symbol}
|
|
87
92
|
*/
|
|
88
93
|
const navElementSymbol = Symbol("navElement");
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* @private
|
|
97
|
+
* @type {symbol}
|
|
98
|
+
*/
|
|
99
|
+
const measurementNavElementSymbol = Symbol("measurementNavElement");
|
|
89
100
|
/**
|
|
90
101
|
* @private
|
|
91
102
|
* @type {symbol}
|
|
@@ -103,6 +114,30 @@ const changeTabEventHandler = Symbol("changeTabEventHandler");
|
|
|
103
114
|
*/
|
|
104
115
|
const removeTabEventHandler = Symbol("removeTabEventHandler");
|
|
105
116
|
|
|
117
|
+
/**
|
|
118
|
+
* @private
|
|
119
|
+
* @type {symbol}
|
|
120
|
+
*/
|
|
121
|
+
const dragStartEventHandler = Symbol("dragStartEventHandler");
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* @private
|
|
125
|
+
* @type {symbol}
|
|
126
|
+
*/
|
|
127
|
+
const dragOverEventHandler = Symbol("dragOverEventHandler");
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* @private
|
|
131
|
+
* @type {symbol}
|
|
132
|
+
*/
|
|
133
|
+
const dropEventHandler = Symbol("dropEventHandler");
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* @private
|
|
137
|
+
* @type {symbol}
|
|
138
|
+
*/
|
|
139
|
+
const dragEndEventHandler = Symbol("dragEndEventHandler");
|
|
140
|
+
|
|
106
141
|
/**
|
|
107
142
|
* @private
|
|
108
143
|
* @type {symbol}
|
|
@@ -154,6 +189,42 @@ const resizeObserverSymbol = Symbol("resizeObserver");
|
|
|
154
189
|
*/
|
|
155
190
|
const activeReferenceSymbol = Symbol("activeReference");
|
|
156
191
|
|
|
192
|
+
/**
|
|
193
|
+
* local symbol
|
|
194
|
+
* @private
|
|
195
|
+
* @type {symbol}
|
|
196
|
+
*/
|
|
197
|
+
const draggingReferenceSymbol = Symbol("draggingReference");
|
|
198
|
+
|
|
199
|
+
/**
|
|
200
|
+
* local symbol
|
|
201
|
+
* @private
|
|
202
|
+
* @type {symbol}
|
|
203
|
+
*/
|
|
204
|
+
const suppressOrderConfigSaveSymbol = Symbol("suppressOrderConfigSave");
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* @private
|
|
208
|
+
* @type {symbol}
|
|
209
|
+
*/
|
|
210
|
+
const rearrangeFrameSymbol = Symbol("rearrangeFrame");
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* @private
|
|
214
|
+
* @type {symbol}
|
|
215
|
+
*/
|
|
216
|
+
const buttonCollectionsSignatureSymbol = Symbol("buttonCollectionsSignature");
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* @private
|
|
220
|
+
* @type {symbol}
|
|
221
|
+
*/
|
|
222
|
+
const layoutSignatureHistorySymbol = Symbol("layoutSignatureHistory");
|
|
223
|
+
|
|
224
|
+
const LAYOUT_SWITCH_HYSTERESIS = 16;
|
|
225
|
+
const LAYOUT_OSCILLATION_HISTORY_LIMIT = 4;
|
|
226
|
+
const LAYOUT_OSCILLATION_TIME_WINDOW_MS = 1000;
|
|
227
|
+
|
|
157
228
|
/**
|
|
158
229
|
* A Tabs Control
|
|
159
230
|
*
|
|
@@ -197,6 +268,11 @@ class Tabs extends CustomElement {
|
|
|
197
268
|
* @property {string} features.removeBehavior Remove behavior, auto, next, previous and none
|
|
198
269
|
* @property {boolean} features.openFirst Open the first tab when no active tab is set
|
|
199
270
|
* @property {boolean} features.deriveLabelFromContent=true Generate labels from panel text when no `data-monster-button-label` is set
|
|
271
|
+
* @property {Object} features.order Tab ordering features
|
|
272
|
+
* @property {boolean} features.order.drag=true Allow tab headers to be reordered by drag and drop
|
|
273
|
+
* @property {boolean} features.order.persist=false Persist reordered tabs through the host config manager
|
|
274
|
+
* @property {Object} config Host configuration options
|
|
275
|
+
* @property {string} config.instanceKey Stable config identity for persisted tab order
|
|
200
276
|
*
|
|
201
277
|
* Tab panels can use `data-monster-name` as stable public identity, while
|
|
202
278
|
* DOM ids remain the internal button reference. `data-monster-tab-available`
|
|
@@ -250,6 +326,14 @@ class Tabs extends CustomElement {
|
|
|
250
326
|
removeBehavior: "auto",
|
|
251
327
|
openFirst: true,
|
|
252
328
|
deriveLabelFromContent: true,
|
|
329
|
+
order: {
|
|
330
|
+
drag: true,
|
|
331
|
+
persist: false,
|
|
332
|
+
},
|
|
333
|
+
},
|
|
334
|
+
|
|
335
|
+
config: {
|
|
336
|
+
instanceKey: null,
|
|
253
337
|
},
|
|
254
338
|
|
|
255
339
|
classes: {
|
|
@@ -305,11 +389,22 @@ class Tabs extends CustomElement {
|
|
|
305
389
|
attachTabChangeObserver.call(this);
|
|
306
390
|
|
|
307
391
|
// setup structure
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
392
|
+
const initTabs =
|
|
393
|
+
isTabOrderPersistenceEnabled.call(this) === true
|
|
394
|
+
? initTabOrderFromHostConfig
|
|
395
|
+
.call(this)
|
|
396
|
+
.then(() => initTabButtons.call(this))
|
|
397
|
+
: initTabButtons.call(this);
|
|
398
|
+
|
|
399
|
+
initTabs
|
|
400
|
+
.then(() => {
|
|
401
|
+
initPopperSwitch.call(this);
|
|
402
|
+
initPopper.call(this);
|
|
403
|
+
attachResizeObserver.call(this);
|
|
404
|
+
})
|
|
405
|
+
.catch((e) => {
|
|
406
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, e.message);
|
|
407
|
+
});
|
|
313
408
|
}
|
|
314
409
|
|
|
315
410
|
/**
|
|
@@ -553,6 +648,26 @@ class Tabs extends CustomElement {
|
|
|
553
648
|
|
|
554
649
|
this[popperInstanceSymbol]?.destroy();
|
|
555
650
|
this[tabListMutationObserverSymbol]?.disconnect();
|
|
651
|
+
this[resizeObserverSymbol]?.disconnect();
|
|
652
|
+
this[navElementSymbol]?.removeEventListener(
|
|
653
|
+
"dragstart",
|
|
654
|
+
this[dragStartEventHandler],
|
|
655
|
+
);
|
|
656
|
+
this[navElementSymbol]?.removeEventListener(
|
|
657
|
+
"dragover",
|
|
658
|
+
this[dragOverEventHandler],
|
|
659
|
+
);
|
|
660
|
+
this[navElementSymbol]?.removeEventListener("drop", this[dropEventHandler]);
|
|
661
|
+
this[navElementSymbol]?.removeEventListener(
|
|
662
|
+
"dragend",
|
|
663
|
+
this[dragEndEventHandler],
|
|
664
|
+
);
|
|
665
|
+
if (this[rearrangeFrameSymbol] !== undefined) {
|
|
666
|
+
getWindow().cancelAnimationFrame(this[rearrangeFrameSymbol]);
|
|
667
|
+
delete this[rearrangeFrameSymbol];
|
|
668
|
+
}
|
|
669
|
+
this[measurementNavElementSymbol]?.remove();
|
|
670
|
+
delete this[measurementNavElementSymbol];
|
|
556
671
|
}
|
|
557
672
|
}
|
|
558
673
|
|
|
@@ -1233,6 +1348,93 @@ function initEventHandler() {
|
|
|
1233
1348
|
this[navElementSymbol].addEventListener("touch", this[changeTabEventHandler]);
|
|
1234
1349
|
this[navElementSymbol].addEventListener("click", this[changeTabEventHandler]);
|
|
1235
1350
|
|
|
1351
|
+
this[dragStartEventHandler] = (event) => {
|
|
1352
|
+
if (isTabDragEnabled.call(this) !== true) {
|
|
1353
|
+
return;
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
const button = findTargetElementFromEvent(event, ATTRIBUTE_ROLE, "button");
|
|
1357
|
+
if (!(button instanceof HTMLButtonElement) || button.disabled === true) {
|
|
1358
|
+
return;
|
|
1359
|
+
}
|
|
1360
|
+
|
|
1361
|
+
const reference = button.getAttribute(`${ATTRIBUTE_PREFIX}tab-reference`);
|
|
1362
|
+
if (!reference) {
|
|
1363
|
+
return;
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
this[draggingReferenceSymbol] = reference;
|
|
1367
|
+
button.setAttribute("data-monster-dragging", "true");
|
|
1368
|
+
event.dataTransfer?.setData("text/plain", reference);
|
|
1369
|
+
if (event.dataTransfer) {
|
|
1370
|
+
event.dataTransfer.effectAllowed = "move";
|
|
1371
|
+
}
|
|
1372
|
+
};
|
|
1373
|
+
|
|
1374
|
+
this[dragOverEventHandler] = (event) => {
|
|
1375
|
+
if (isTabDragEnabled.call(this) !== true) {
|
|
1376
|
+
return;
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
const button = findTargetElementFromEvent(event, ATTRIBUTE_ROLE, "button");
|
|
1380
|
+
if (
|
|
1381
|
+
!(button instanceof HTMLButtonElement) ||
|
|
1382
|
+
button.disabled === true ||
|
|
1383
|
+
!this[draggingReferenceSymbol]
|
|
1384
|
+
) {
|
|
1385
|
+
return;
|
|
1386
|
+
}
|
|
1387
|
+
|
|
1388
|
+
event.preventDefault();
|
|
1389
|
+
if (event.dataTransfer) {
|
|
1390
|
+
event.dataTransfer.dropEffect = "move";
|
|
1391
|
+
}
|
|
1392
|
+
};
|
|
1393
|
+
|
|
1394
|
+
this[dropEventHandler] = (event) => {
|
|
1395
|
+
if (isTabDragEnabled.call(this) !== true) {
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
|
|
1399
|
+
const button = findTargetElementFromEvent(event, ATTRIBUTE_ROLE, "button");
|
|
1400
|
+
if (!(button instanceof HTMLButtonElement) || button.disabled === true) {
|
|
1401
|
+
return;
|
|
1402
|
+
}
|
|
1403
|
+
|
|
1404
|
+
const sourceReference = this[draggingReferenceSymbol];
|
|
1405
|
+
const targetReference = button.getAttribute(
|
|
1406
|
+
`${ATTRIBUTE_PREFIX}tab-reference`,
|
|
1407
|
+
);
|
|
1408
|
+
if (
|
|
1409
|
+
!sourceReference ||
|
|
1410
|
+
!targetReference ||
|
|
1411
|
+
sourceReference === targetReference
|
|
1412
|
+
) {
|
|
1413
|
+
return;
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
event.preventDefault();
|
|
1417
|
+
reorderTabPanels.call(this, sourceReference, targetReference);
|
|
1418
|
+
clearDraggingButton.call(this);
|
|
1419
|
+
delete this[draggingReferenceSymbol];
|
|
1420
|
+
};
|
|
1421
|
+
|
|
1422
|
+
this[dragEndEventHandler] = () => {
|
|
1423
|
+
clearDraggingButton.call(this);
|
|
1424
|
+
delete this[draggingReferenceSymbol];
|
|
1425
|
+
};
|
|
1426
|
+
|
|
1427
|
+
this[navElementSymbol].addEventListener(
|
|
1428
|
+
"dragstart",
|
|
1429
|
+
this[dragStartEventHandler],
|
|
1430
|
+
);
|
|
1431
|
+
this[navElementSymbol].addEventListener(
|
|
1432
|
+
"dragover",
|
|
1433
|
+
this[dragOverEventHandler],
|
|
1434
|
+
);
|
|
1435
|
+
this[navElementSymbol].addEventListener("drop", this[dropEventHandler]);
|
|
1436
|
+
this[navElementSymbol].addEventListener("dragend", this[dragEndEventHandler]);
|
|
1437
|
+
|
|
1236
1438
|
return this;
|
|
1237
1439
|
}
|
|
1238
1440
|
|
|
@@ -1327,6 +1529,8 @@ function initTabButtons() {
|
|
|
1327
1529
|
throw new Error("no shadow-root is defined");
|
|
1328
1530
|
}
|
|
1329
1531
|
|
|
1532
|
+
resetLayoutSignatureHistory.call(this);
|
|
1533
|
+
|
|
1330
1534
|
let activeReference;
|
|
1331
1535
|
let invalidActive = false;
|
|
1332
1536
|
const previousActiveReference = this[activeReferenceSymbol] || null;
|
|
@@ -1399,6 +1603,7 @@ function initTabButtons() {
|
|
|
1399
1603
|
state,
|
|
1400
1604
|
class: classes,
|
|
1401
1605
|
disabled,
|
|
1606
|
+
draggable: isTabDragEnabled.call(this) === true && disabled !== true,
|
|
1402
1607
|
title: disabled === true ? disabledReason : null,
|
|
1403
1608
|
"aria-label": disabled === true ? disabledReason : null,
|
|
1404
1609
|
remove,
|
|
@@ -1408,8 +1613,11 @@ function initTabButtons() {
|
|
|
1408
1613
|
});
|
|
1409
1614
|
}
|
|
1410
1615
|
|
|
1411
|
-
|
|
1616
|
+
const { standardButtons, popperButtons } =
|
|
1617
|
+
splitButtonsByCurrentPopperReferences.call(this, buttons);
|
|
1618
|
+
setButtonCollections.call(this, standardButtons, popperButtons);
|
|
1412
1619
|
this.setOption("marker", random());
|
|
1620
|
+
this[dimensionsSymbol].setVia("data.calculated", false);
|
|
1413
1621
|
|
|
1414
1622
|
return adjustButtonVisibility.call(this).then(() => {
|
|
1415
1623
|
if (
|
|
@@ -1491,7 +1699,9 @@ function adjustButtonVisibility() {
|
|
|
1491
1699
|
const runIfRendered = () => {
|
|
1492
1700
|
if (resolved === true) return;
|
|
1493
1701
|
|
|
1494
|
-
const defCount =
|
|
1702
|
+
const defCount =
|
|
1703
|
+
self.getOption("buttons.standard").length +
|
|
1704
|
+
self.getOption("buttons.popper").length;
|
|
1495
1705
|
const domCount = self[navElementSymbol].querySelectorAll(
|
|
1496
1706
|
'button[data-monster-role="button"][data-monster-tab-reference]',
|
|
1497
1707
|
).length;
|
|
@@ -1529,7 +1739,7 @@ function getDimValue(value) {
|
|
|
1529
1739
|
return 0;
|
|
1530
1740
|
}
|
|
1531
1741
|
|
|
1532
|
-
const valueAsInt =
|
|
1742
|
+
const valueAsInt = parseFloat(value);
|
|
1533
1743
|
|
|
1534
1744
|
if (isNaN(valueAsInt)) {
|
|
1535
1745
|
return 0;
|
|
@@ -1554,7 +1764,7 @@ function calcBoxWidth(node) {
|
|
|
1554
1764
|
getDimValue(bounding["width"]) +
|
|
1555
1765
|
getDimValue(dim["border-right-width"]) +
|
|
1556
1766
|
getDimValue(dim["margin-right"]) +
|
|
1557
|
-
getDimValue(dim["padding-
|
|
1767
|
+
getDimValue(dim["padding-right"])
|
|
1558
1768
|
);
|
|
1559
1769
|
}
|
|
1560
1770
|
|
|
@@ -1563,10 +1773,13 @@ function calcBoxWidth(node) {
|
|
|
1563
1773
|
* @return {Object}
|
|
1564
1774
|
*/
|
|
1565
1775
|
function rearrangeButtons() {
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1776
|
+
if (this[rearrangeFrameSymbol] !== undefined) {
|
|
1777
|
+
return;
|
|
1778
|
+
}
|
|
1779
|
+
|
|
1780
|
+
this[rearrangeFrameSymbol] = getWindow().requestAnimationFrame(() => {
|
|
1781
|
+
delete this[rearrangeFrameSymbol];
|
|
1782
|
+
|
|
1570
1783
|
const space = this[dimensionsSymbol].getVia("data.space");
|
|
1571
1784
|
|
|
1572
1785
|
if (space <= 0) {
|
|
@@ -1576,16 +1789,30 @@ function rearrangeButtons() {
|
|
|
1576
1789
|
const buttons = this.getOption("buttons.standard").concat(
|
|
1577
1790
|
this.getOption("buttons.popper"),
|
|
1578
1791
|
);
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1792
|
+
const widths = buttons.map((button) =>
|
|
1793
|
+
resolveButtonWidth.call(this, button?.reference),
|
|
1794
|
+
);
|
|
1795
|
+
const switchWidth = resolveSwitchWidth.call(this);
|
|
1796
|
+
const switchCurrentlyVisible =
|
|
1797
|
+
this[switchElementSymbol] instanceof HTMLElement &&
|
|
1798
|
+
!this[switchElementSymbol].classList.contains("hidden");
|
|
1799
|
+
const { standardButtons, popperButtons } = resolveOverflowButtonLayout({
|
|
1800
|
+
buttons,
|
|
1801
|
+
widths,
|
|
1802
|
+
space,
|
|
1803
|
+
switchWidth,
|
|
1804
|
+
switchCurrentlyVisible,
|
|
1805
|
+
});
|
|
1583
1806
|
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1807
|
+
if (
|
|
1808
|
+
shouldSuppressOscillatingTabLayout.call(
|
|
1809
|
+
this,
|
|
1810
|
+
space,
|
|
1811
|
+
standardButtons,
|
|
1812
|
+
popperButtons,
|
|
1813
|
+
)
|
|
1814
|
+
) {
|
|
1815
|
+
return;
|
|
1589
1816
|
}
|
|
1590
1817
|
|
|
1591
1818
|
setButtonCollections.call(this, standardButtons, popperButtons);
|
|
@@ -1594,6 +1821,74 @@ function rearrangeButtons() {
|
|
|
1594
1821
|
});
|
|
1595
1822
|
}
|
|
1596
1823
|
|
|
1824
|
+
/**
|
|
1825
|
+
* @private
|
|
1826
|
+
* @param {Object} options
|
|
1827
|
+
* @param {Object[]} options.buttons
|
|
1828
|
+
* @param {number[]} options.widths
|
|
1829
|
+
* @param {number} options.space
|
|
1830
|
+
* @param {number} options.switchWidth
|
|
1831
|
+
* @param {boolean} options.switchCurrentlyVisible
|
|
1832
|
+
* @return {{standardButtons: Object[], popperButtons: Object[]}}
|
|
1833
|
+
*/
|
|
1834
|
+
function resolveOverflowButtonLayout({
|
|
1835
|
+
buttons,
|
|
1836
|
+
widths,
|
|
1837
|
+
space,
|
|
1838
|
+
switchWidth,
|
|
1839
|
+
switchCurrentlyVisible,
|
|
1840
|
+
}) {
|
|
1841
|
+
let layout;
|
|
1842
|
+
if (switchCurrentlyVisible) {
|
|
1843
|
+
layout = fitButtonsIntoSpace(
|
|
1844
|
+
buttons,
|
|
1845
|
+
widths,
|
|
1846
|
+
space - switchWidth - LAYOUT_SWITCH_HYSTERESIS,
|
|
1847
|
+
);
|
|
1848
|
+
if (layout.popperButtons.length === 0) {
|
|
1849
|
+
layout = fitButtonsIntoSpace(buttons, widths, space);
|
|
1850
|
+
}
|
|
1851
|
+
return layout;
|
|
1852
|
+
}
|
|
1853
|
+
|
|
1854
|
+
layout = fitButtonsIntoSpace(
|
|
1855
|
+
buttons,
|
|
1856
|
+
widths,
|
|
1857
|
+
space - LAYOUT_SWITCH_HYSTERESIS,
|
|
1858
|
+
);
|
|
1859
|
+
if (layout.popperButtons.length > 0) {
|
|
1860
|
+
return fitButtonsIntoSpace(buttons, widths, space - switchWidth);
|
|
1861
|
+
}
|
|
1862
|
+
|
|
1863
|
+
return fitButtonsIntoSpace(buttons, widths, space);
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
/**
|
|
1867
|
+
* @private
|
|
1868
|
+
* @param {Object[]} buttons
|
|
1869
|
+
* @param {number[]} widths
|
|
1870
|
+
* @param {number} availableSpace
|
|
1871
|
+
* @return {{standardButtons: Object[], popperButtons: Object[]}}
|
|
1872
|
+
*/
|
|
1873
|
+
function fitButtonsIntoSpace(buttons, widths, availableSpace) {
|
|
1874
|
+
let sum = 0;
|
|
1875
|
+
const standardButtons = [];
|
|
1876
|
+
const popperButtons = [];
|
|
1877
|
+
const boundedSpace = Math.max(0, availableSpace);
|
|
1878
|
+
|
|
1879
|
+
for (const [index, button] of buttons.entries()) {
|
|
1880
|
+
const width = widths[index];
|
|
1881
|
+
if (popperButtons.length > 0 || sum + width > boundedSpace) {
|
|
1882
|
+
popperButtons.push(clone(button));
|
|
1883
|
+
} else {
|
|
1884
|
+
sum += width;
|
|
1885
|
+
standardButtons.push(clone(button));
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
|
|
1889
|
+
return { standardButtons, popperButtons };
|
|
1890
|
+
}
|
|
1891
|
+
|
|
1597
1892
|
/**
|
|
1598
1893
|
* @private
|
|
1599
1894
|
*/
|
|
@@ -1625,11 +1920,135 @@ function resolveButtonWidth(ref) {
|
|
|
1625
1920
|
return 0;
|
|
1626
1921
|
}
|
|
1627
1922
|
|
|
1628
|
-
width =
|
|
1629
|
-
|
|
1923
|
+
width = measureButtonWidth.call(this, element);
|
|
1924
|
+
if (width > 0) {
|
|
1925
|
+
this[dimensionsSymbol].setVia(`data.button.${ref}`, width);
|
|
1926
|
+
}
|
|
1630
1927
|
return width;
|
|
1631
1928
|
}
|
|
1632
1929
|
|
|
1930
|
+
/**
|
|
1931
|
+
* @private
|
|
1932
|
+
* @param {boolean} force
|
|
1933
|
+
* @return {number}
|
|
1934
|
+
*/
|
|
1935
|
+
function resolveSwitchWidth(force = false) {
|
|
1936
|
+
let width = this[dimensionsSymbol].getVia("data.switchWidth", 0);
|
|
1937
|
+
if (force !== true && width > 0) {
|
|
1938
|
+
return width;
|
|
1939
|
+
}
|
|
1940
|
+
|
|
1941
|
+
if (!(this[switchElementSymbol] instanceof HTMLElement)) {
|
|
1942
|
+
return 0;
|
|
1943
|
+
}
|
|
1944
|
+
|
|
1945
|
+
width = measureElementWidthInNavigation.call(
|
|
1946
|
+
this,
|
|
1947
|
+
this[switchElementSymbol],
|
|
1948
|
+
{
|
|
1949
|
+
removeHiddenClass: true,
|
|
1950
|
+
},
|
|
1951
|
+
);
|
|
1952
|
+
this[dimensionsSymbol].setVia("data.switchWidth", width);
|
|
1953
|
+
return width;
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
/**
|
|
1957
|
+
* @private
|
|
1958
|
+
* @param {HTMLButtonElement} element
|
|
1959
|
+
* @return {number}
|
|
1960
|
+
*/
|
|
1961
|
+
function measureButtonWidth(element) {
|
|
1962
|
+
if (
|
|
1963
|
+
element.closest(`[${ATTRIBUTE_ROLE}=popper-nav]`) instanceof HTMLElement
|
|
1964
|
+
) {
|
|
1965
|
+
return measureButtonWidthInNavigation.call(this, element);
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
const width = calcBoxWidth.call(this, element);
|
|
1969
|
+
if (width > 0) {
|
|
1970
|
+
return width;
|
|
1971
|
+
}
|
|
1972
|
+
|
|
1973
|
+
return measureButtonWidthInNavigation.call(this, element);
|
|
1974
|
+
}
|
|
1975
|
+
|
|
1976
|
+
/**
|
|
1977
|
+
* @private
|
|
1978
|
+
* @param {HTMLButtonElement} element
|
|
1979
|
+
* @return {number}
|
|
1980
|
+
*/
|
|
1981
|
+
function measureButtonWidthInNavigation(element) {
|
|
1982
|
+
return measureElementWidthInNavigation.call(this, element);
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
/**
|
|
1986
|
+
* @private
|
|
1987
|
+
* @param {HTMLElement} element
|
|
1988
|
+
* @param {{removeHiddenClass?: boolean}} options
|
|
1989
|
+
* @return {number}
|
|
1990
|
+
*/
|
|
1991
|
+
function measureElementWidthInNavigation(element, options = {}) {
|
|
1992
|
+
const measurementNav = ensureMeasurementNav.call(this);
|
|
1993
|
+
const cloneElement = element.cloneNode(true);
|
|
1994
|
+
prepareMeasurementElement(cloneElement, options);
|
|
1995
|
+
|
|
1996
|
+
measurementNav.appendChild(cloneElement);
|
|
1997
|
+
const width = calcBoxWidth.call(this, cloneElement);
|
|
1998
|
+
cloneElement.remove();
|
|
1999
|
+
|
|
2000
|
+
return width;
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
/**
|
|
2004
|
+
* @private
|
|
2005
|
+
* @param {HTMLElement} element
|
|
2006
|
+
* @param {{removeHiddenClass?: boolean}} options
|
|
2007
|
+
* @return {void}
|
|
2008
|
+
*/
|
|
2009
|
+
function prepareMeasurementElement(element, options = {}) {
|
|
2010
|
+
element.setAttribute("aria-hidden", "true");
|
|
2011
|
+
element.setAttribute("tabindex", "-1");
|
|
2012
|
+
element.removeAttribute("data-monster-tab-reference");
|
|
2013
|
+
element.removeAttribute("id");
|
|
2014
|
+
element.dataset.monsterMeasurement = "true";
|
|
2015
|
+
|
|
2016
|
+
if (options.removeHiddenClass === true) {
|
|
2017
|
+
element.classList.remove("hidden");
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
element.style.position = "";
|
|
2021
|
+
element.style.visibility = "";
|
|
2022
|
+
element.style.pointerEvents = "";
|
|
2023
|
+
element.style.inset = "";
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
/**
|
|
2027
|
+
* @private
|
|
2028
|
+
* @return {HTMLElement}
|
|
2029
|
+
*/
|
|
2030
|
+
function ensureMeasurementNav() {
|
|
2031
|
+
if (this[measurementNavElementSymbol] instanceof HTMLElement) {
|
|
2032
|
+
return this[measurementNavElementSymbol];
|
|
2033
|
+
}
|
|
2034
|
+
|
|
2035
|
+
const nav = getDocument().createElement("nav");
|
|
2036
|
+
nav.setAttribute(ATTRIBUTE_ROLE, "nav");
|
|
2037
|
+
nav.setAttribute("aria-hidden", "true");
|
|
2038
|
+
nav.dataset.monsterMeasurement = "true";
|
|
2039
|
+
nav.style.position = "absolute";
|
|
2040
|
+
nav.style.visibility = "hidden";
|
|
2041
|
+
nav.style.pointerEvents = "none";
|
|
2042
|
+
nav.style.inset = "0 auto auto 0";
|
|
2043
|
+
nav.style.width = "max-content";
|
|
2044
|
+
nav.style.height = "auto";
|
|
2045
|
+
nav.style.overflow = "visible";
|
|
2046
|
+
|
|
2047
|
+
this[controlElementSymbol].appendChild(nav);
|
|
2048
|
+
this[measurementNavElementSymbol] = nav;
|
|
2049
|
+
return nav;
|
|
2050
|
+
}
|
|
2051
|
+
|
|
1633
2052
|
/**
|
|
1634
2053
|
* Keep the main navigation and popper navigation models in sync with one update.
|
|
1635
2054
|
*
|
|
@@ -1641,12 +2060,302 @@ function resolveButtonWidth(ref) {
|
|
|
1641
2060
|
* @param {Object[]} popperButtons
|
|
1642
2061
|
*/
|
|
1643
2062
|
function setButtonCollections(standardButtons, popperButtons) {
|
|
2063
|
+
const signature = getButtonCollectionsSignature(
|
|
2064
|
+
standardButtons,
|
|
2065
|
+
popperButtons,
|
|
2066
|
+
);
|
|
2067
|
+
if (this[buttonCollectionsSignatureSymbol] === signature) {
|
|
2068
|
+
return;
|
|
2069
|
+
}
|
|
2070
|
+
|
|
2071
|
+
const currentSignature = getButtonCollectionsSignature(
|
|
2072
|
+
this.getOption("buttons.standard", []),
|
|
2073
|
+
this.getOption("buttons.popper", []),
|
|
2074
|
+
);
|
|
2075
|
+
if (currentSignature === signature) {
|
|
2076
|
+
this[buttonCollectionsSignatureSymbol] = signature;
|
|
2077
|
+
return;
|
|
2078
|
+
}
|
|
2079
|
+
|
|
2080
|
+
this[buttonCollectionsSignatureSymbol] = signature;
|
|
1644
2081
|
this.setOption("buttons", {
|
|
1645
2082
|
standard: clone(standardButtons),
|
|
1646
2083
|
popper: clone(popperButtons),
|
|
1647
2084
|
});
|
|
1648
2085
|
}
|
|
1649
2086
|
|
|
2087
|
+
/**
|
|
2088
|
+
* @private
|
|
2089
|
+
* @param {Object[]} standardButtons
|
|
2090
|
+
* @param {Object[]} popperButtons
|
|
2091
|
+
* @return {string}
|
|
2092
|
+
*/
|
|
2093
|
+
function getButtonCollectionsSignature(standardButtons, popperButtons) {
|
|
2094
|
+
return JSON.stringify({
|
|
2095
|
+
standard: standardButtons.map(getButtonSignature),
|
|
2096
|
+
popper: popperButtons.map(getButtonSignature),
|
|
2097
|
+
});
|
|
2098
|
+
}
|
|
2099
|
+
|
|
2100
|
+
/**
|
|
2101
|
+
* @private
|
|
2102
|
+
* @param {Object} button
|
|
2103
|
+
* @return {Object}
|
|
2104
|
+
*/
|
|
2105
|
+
function getButtonSignature(button) {
|
|
2106
|
+
return {
|
|
2107
|
+
reference: button?.reference,
|
|
2108
|
+
name: button?.name,
|
|
2109
|
+
tab: button?.tab,
|
|
2110
|
+
label: button?.label,
|
|
2111
|
+
error: button?.error,
|
|
2112
|
+
state: button?.state,
|
|
2113
|
+
class: button?.class,
|
|
2114
|
+
disabled: button?.disabled,
|
|
2115
|
+
draggable: button?.draggable,
|
|
2116
|
+
title: button?.title,
|
|
2117
|
+
"aria-label": button?.["aria-label"],
|
|
2118
|
+
remove: button?.remove,
|
|
2119
|
+
kind: button?.kind,
|
|
2120
|
+
priority: button?.priority,
|
|
2121
|
+
group: button?.group,
|
|
2122
|
+
};
|
|
2123
|
+
}
|
|
2124
|
+
|
|
2125
|
+
/**
|
|
2126
|
+
* @private
|
|
2127
|
+
* @param {Object[]} buttons
|
|
2128
|
+
* @return {{standardButtons: Object[], popperButtons: Object[]}}
|
|
2129
|
+
*/
|
|
2130
|
+
function splitButtonsByCurrentPopperReferences(buttons) {
|
|
2131
|
+
const popperReferences = new Set(
|
|
2132
|
+
this.getOption("buttons.popper", []).map((button) => button.reference),
|
|
2133
|
+
);
|
|
2134
|
+
const standardButtons = [];
|
|
2135
|
+
const popperButtons = [];
|
|
2136
|
+
for (const button of buttons) {
|
|
2137
|
+
if (popperReferences.has(button.reference)) {
|
|
2138
|
+
popperButtons.push(button);
|
|
2139
|
+
} else {
|
|
2140
|
+
standardButtons.push(button);
|
|
2141
|
+
}
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2144
|
+
return { standardButtons, popperButtons };
|
|
2145
|
+
}
|
|
2146
|
+
|
|
2147
|
+
/**
|
|
2148
|
+
* @private
|
|
2149
|
+
* @return {boolean}
|
|
2150
|
+
*/
|
|
2151
|
+
function isTabDragEnabled() {
|
|
2152
|
+
return this.getOption("features.order.drag") !== false;
|
|
2153
|
+
}
|
|
2154
|
+
|
|
2155
|
+
/**
|
|
2156
|
+
* @private
|
|
2157
|
+
* @return {boolean}
|
|
2158
|
+
*/
|
|
2159
|
+
function isTabOrderPersistenceEnabled() {
|
|
2160
|
+
return this.getOption("features.order.persist") === true;
|
|
2161
|
+
}
|
|
2162
|
+
|
|
2163
|
+
/**
|
|
2164
|
+
* @private
|
|
2165
|
+
* @return {boolean}
|
|
2166
|
+
*/
|
|
2167
|
+
function hasConfigIdentity() {
|
|
2168
|
+
return (
|
|
2169
|
+
(isString(this.id) && this.id.trim() !== "") ||
|
|
2170
|
+
(isString(this.getOption("config.instanceKey")) &&
|
|
2171
|
+
this.getOption("config.instanceKey").trim() !== "")
|
|
2172
|
+
);
|
|
2173
|
+
}
|
|
2174
|
+
|
|
2175
|
+
/**
|
|
2176
|
+
* @private
|
|
2177
|
+
* @return {string}
|
|
2178
|
+
*/
|
|
2179
|
+
function getTabOrderConfigKey() {
|
|
2180
|
+
return generateComponentConfigKey("tabs", this?.id, "tab_order", {
|
|
2181
|
+
instanceKey: this.getOption("config.instanceKey"),
|
|
2182
|
+
});
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
/**
|
|
2186
|
+
* @private
|
|
2187
|
+
* @return {HTMLElement|null}
|
|
2188
|
+
*/
|
|
2189
|
+
function getHostElement() {
|
|
2190
|
+
return findElementWithSelectorUpwards(this, "monster-host");
|
|
2191
|
+
}
|
|
2192
|
+
|
|
2193
|
+
/**
|
|
2194
|
+
* @private
|
|
2195
|
+
* @return {string[]}
|
|
2196
|
+
*/
|
|
2197
|
+
function getCurrentTabOrder() {
|
|
2198
|
+
return getAllTabPanels
|
|
2199
|
+
.call(this)
|
|
2200
|
+
.map((node) => getTabPublicReference(node))
|
|
2201
|
+
.filter((reference) => isString(reference) && reference.trim() !== "");
|
|
2202
|
+
}
|
|
2203
|
+
|
|
2204
|
+
/**
|
|
2205
|
+
* @private
|
|
2206
|
+
* @return {Promise}
|
|
2207
|
+
*/
|
|
2208
|
+
function initTabOrderFromHostConfig() {
|
|
2209
|
+
if (isTabOrderPersistenceEnabled.call(this) !== true) {
|
|
2210
|
+
return Promise.resolve();
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
const host = getHostElement.call(this);
|
|
2214
|
+
if (!(host && hasConfigIdentity.call(this))) {
|
|
2215
|
+
return Promise.resolve();
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
const configKey = getTabOrderConfigKey.call(this);
|
|
2219
|
+
return host
|
|
2220
|
+
.hasConfig(configKey)
|
|
2221
|
+
.then((hasConfig) => {
|
|
2222
|
+
if (hasConfig !== true) {
|
|
2223
|
+
return null;
|
|
2224
|
+
}
|
|
2225
|
+
return host.getConfig(configKey);
|
|
2226
|
+
})
|
|
2227
|
+
.then((order) => {
|
|
2228
|
+
if (!isArray(order)) {
|
|
2229
|
+
return;
|
|
2230
|
+
}
|
|
2231
|
+
this[suppressOrderConfigSaveSymbol] = true;
|
|
2232
|
+
applyTabOrder.call(this, order);
|
|
2233
|
+
this[suppressOrderConfigSaveSymbol] = false;
|
|
2234
|
+
})
|
|
2235
|
+
.catch((error) => {
|
|
2236
|
+
this[suppressOrderConfigSaveSymbol] = false;
|
|
2237
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, String(error));
|
|
2238
|
+
});
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2241
|
+
/**
|
|
2242
|
+
* @private
|
|
2243
|
+
* @param {string[]} order
|
|
2244
|
+
* @return {void}
|
|
2245
|
+
*/
|
|
2246
|
+
function applyTabOrder(order) {
|
|
2247
|
+
const panels = getAllTabPanels.call(this);
|
|
2248
|
+
const panelsByReference = new Map();
|
|
2249
|
+
for (const panel of panels) {
|
|
2250
|
+
panelsByReference.set(getTabReference(panel), panel);
|
|
2251
|
+
const name = getTabName(panel);
|
|
2252
|
+
if (name) {
|
|
2253
|
+
panelsByReference.set(name, panel);
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
|
|
2257
|
+
const appended = new Set();
|
|
2258
|
+
for (const reference of order) {
|
|
2259
|
+
const panel = panelsByReference.get(reference);
|
|
2260
|
+
if (panel instanceof HTMLElement && appended.has(panel) !== true) {
|
|
2261
|
+
this.appendChild(panel);
|
|
2262
|
+
appended.add(panel);
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
|
|
2266
|
+
for (const panel of panels) {
|
|
2267
|
+
if (appended.has(panel) !== true) {
|
|
2268
|
+
this.appendChild(panel);
|
|
2269
|
+
}
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
|
|
2273
|
+
/**
|
|
2274
|
+
* @private
|
|
2275
|
+
* @return {void}
|
|
2276
|
+
*/
|
|
2277
|
+
function saveTabOrderConfig() {
|
|
2278
|
+
if (
|
|
2279
|
+
isTabOrderPersistenceEnabled.call(this) !== true ||
|
|
2280
|
+
this[suppressOrderConfigSaveSymbol] === true
|
|
2281
|
+
) {
|
|
2282
|
+
return;
|
|
2283
|
+
}
|
|
2284
|
+
|
|
2285
|
+
const host = getHostElement.call(this);
|
|
2286
|
+
if (!(host && hasConfigIdentity.call(this))) {
|
|
2287
|
+
return;
|
|
2288
|
+
}
|
|
2289
|
+
|
|
2290
|
+
try {
|
|
2291
|
+
host.setConfig(
|
|
2292
|
+
getTabOrderConfigKey.call(this),
|
|
2293
|
+
getCurrentTabOrder.call(this),
|
|
2294
|
+
);
|
|
2295
|
+
} catch (error) {
|
|
2296
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, String(error));
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
|
|
2300
|
+
/**
|
|
2301
|
+
* @private
|
|
2302
|
+
* @param {string} sourceReference
|
|
2303
|
+
* @param {string} targetReference
|
|
2304
|
+
* @return {void}
|
|
2305
|
+
*/
|
|
2306
|
+
function reorderTabPanels(sourceReference, targetReference) {
|
|
2307
|
+
const sourcePanel = findTabPanel.call(this, sourceReference, {
|
|
2308
|
+
availableOnly: true,
|
|
2309
|
+
});
|
|
2310
|
+
const targetPanel = findTabPanel.call(this, targetReference, {
|
|
2311
|
+
availableOnly: true,
|
|
2312
|
+
});
|
|
2313
|
+
|
|
2314
|
+
if (
|
|
2315
|
+
!(sourcePanel instanceof HTMLElement) ||
|
|
2316
|
+
!(targetPanel instanceof HTMLElement) ||
|
|
2317
|
+
sourcePanel === targetPanel
|
|
2318
|
+
) {
|
|
2319
|
+
return;
|
|
2320
|
+
}
|
|
2321
|
+
|
|
2322
|
+
const panels = getAllTabPanels.call(this);
|
|
2323
|
+
const sourceIndex = panels.indexOf(sourcePanel);
|
|
2324
|
+
const targetIndex = panels.indexOf(targetPanel);
|
|
2325
|
+
|
|
2326
|
+
if (sourceIndex < targetIndex) {
|
|
2327
|
+
targetPanel.after(sourcePanel);
|
|
2328
|
+
} else {
|
|
2329
|
+
targetPanel.before(sourcePanel);
|
|
2330
|
+
}
|
|
2331
|
+
|
|
2332
|
+
this[dimensionsSymbol].setVia("data.calculated", false);
|
|
2333
|
+
initTabButtons
|
|
2334
|
+
.call(this)
|
|
2335
|
+
.then(() => {
|
|
2336
|
+
saveTabOrderConfig.call(this);
|
|
2337
|
+
fireCustomEvent(this, "monster-tab-order-changed", {
|
|
2338
|
+
order: getCurrentTabOrder.call(this),
|
|
2339
|
+
source: getTabEventDetail(sourcePanel),
|
|
2340
|
+
target: getTabEventDetail(targetPanel),
|
|
2341
|
+
});
|
|
2342
|
+
})
|
|
2343
|
+
.catch((error) => {
|
|
2344
|
+
addAttributeToken(this, ATTRIBUTE_ERRORMESSAGE, String(error));
|
|
2345
|
+
});
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2348
|
+
/**
|
|
2349
|
+
* @private
|
|
2350
|
+
* @return {void}
|
|
2351
|
+
*/
|
|
2352
|
+
function clearDraggingButton() {
|
|
2353
|
+
const buttons = this.shadowRoot.querySelectorAll("[data-monster-dragging]");
|
|
2354
|
+
for (const button of buttons) {
|
|
2355
|
+
button.removeAttribute("data-monster-dragging");
|
|
2356
|
+
}
|
|
2357
|
+
}
|
|
2358
|
+
|
|
1650
2359
|
/**
|
|
1651
2360
|
* @private
|
|
1652
2361
|
* @return {Object}
|
|
@@ -1676,10 +2385,10 @@ function calculateNavigationButtonsDimensions() {
|
|
|
1676
2385
|
const element = findButtonElement.call(this, ref);
|
|
1677
2386
|
if (!(element instanceof HTMLButtonElement)) continue;
|
|
1678
2387
|
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
2388
|
+
const width = measureButtonWidth.call(this, element);
|
|
2389
|
+
if (width > 0) {
|
|
2390
|
+
this[dimensionsSymbol].setVia(`data.button.${ref}`, width);
|
|
2391
|
+
}
|
|
1683
2392
|
button["class"] = new TokenList(button["class"])
|
|
1684
2393
|
.remove("invisible")
|
|
1685
2394
|
.toString();
|
|
@@ -1692,13 +2401,81 @@ function calculateNavigationButtonsDimensions() {
|
|
|
1692
2401
|
slot.classList.remove("invisible");
|
|
1693
2402
|
}
|
|
1694
2403
|
|
|
1695
|
-
|
|
2404
|
+
const { standardButtons, popperButtons } =
|
|
2405
|
+
splitButtonsByCurrentPopperReferences.call(this, buttons);
|
|
2406
|
+
|
|
2407
|
+
resolveSwitchWidth.call(this, true);
|
|
2408
|
+
setButtonCollections.call(this, standardButtons, popperButtons);
|
|
1696
2409
|
|
|
1697
2410
|
getWindow().requestAnimationFrame(() => {
|
|
1698
2411
|
this[dimensionsSymbol].setVia("data.calculated", true);
|
|
1699
2412
|
});
|
|
1700
2413
|
}
|
|
1701
2414
|
|
|
2415
|
+
/**
|
|
2416
|
+
* @private
|
|
2417
|
+
* @param {number} space
|
|
2418
|
+
* @param {Object[]} standardButtons
|
|
2419
|
+
* @param {Object[]} popperButtons
|
|
2420
|
+
* @return {boolean}
|
|
2421
|
+
*/
|
|
2422
|
+
function shouldSuppressOscillatingTabLayout(
|
|
2423
|
+
space,
|
|
2424
|
+
standardButtons,
|
|
2425
|
+
popperButtons,
|
|
2426
|
+
) {
|
|
2427
|
+
const signature = [
|
|
2428
|
+
Math.round(space),
|
|
2429
|
+
standardButtons.map((button) => button.reference).join(","),
|
|
2430
|
+
popperButtons.map((button) => button.reference).join(","),
|
|
2431
|
+
].join("|");
|
|
2432
|
+
|
|
2433
|
+
const history = this[layoutSignatureHistorySymbol] || [];
|
|
2434
|
+
history.push({
|
|
2435
|
+
signature,
|
|
2436
|
+
time: performanceNow(),
|
|
2437
|
+
});
|
|
2438
|
+
while (history.length > LAYOUT_OSCILLATION_HISTORY_LIMIT) {
|
|
2439
|
+
history.shift();
|
|
2440
|
+
}
|
|
2441
|
+
this[layoutSignatureHistorySymbol] = history;
|
|
2442
|
+
|
|
2443
|
+
if (history.length < LAYOUT_OSCILLATION_HISTORY_LIMIT) {
|
|
2444
|
+
return false;
|
|
2445
|
+
}
|
|
2446
|
+
|
|
2447
|
+
const [first, second, third, fourth] = history;
|
|
2448
|
+
if (fourth.time - first.time > LAYOUT_OSCILLATION_TIME_WINDOW_MS) {
|
|
2449
|
+
return false;
|
|
2450
|
+
}
|
|
2451
|
+
|
|
2452
|
+
return (
|
|
2453
|
+
first.signature !== second.signature &&
|
|
2454
|
+
first.signature === third.signature &&
|
|
2455
|
+
second.signature === fourth.signature
|
|
2456
|
+
);
|
|
2457
|
+
}
|
|
2458
|
+
|
|
2459
|
+
/**
|
|
2460
|
+
* @private
|
|
2461
|
+
* @return {void}
|
|
2462
|
+
*/
|
|
2463
|
+
function resetLayoutSignatureHistory() {
|
|
2464
|
+
delete this[layoutSignatureHistorySymbol];
|
|
2465
|
+
}
|
|
2466
|
+
|
|
2467
|
+
/**
|
|
2468
|
+
* @private
|
|
2469
|
+
* @return {number}
|
|
2470
|
+
*/
|
|
2471
|
+
function performanceNow() {
|
|
2472
|
+
const globalObject = getGlobal();
|
|
2473
|
+
if (globalObject?.performance?.now instanceof Function) {
|
|
2474
|
+
return globalObject.performance.now();
|
|
2475
|
+
}
|
|
2476
|
+
return Date.now();
|
|
2477
|
+
}
|
|
2478
|
+
|
|
1702
2479
|
/**
|
|
1703
2480
|
* @private
|
|
1704
2481
|
* @param {string} ref
|
|
@@ -1899,6 +2676,7 @@ function getTemplate() {
|
|
|
1899
2676
|
data-monster-attributes="
|
|
1900
2677
|
class path:classes.button,
|
|
1901
2678
|
data-monster-state path:buttons.state,
|
|
2679
|
+
draggable path:buttons.draggable | if:true,
|
|
1902
2680
|
disabled path:buttons.disabled | if:true,
|
|
1903
2681
|
title path:buttons.title,
|
|
1904
2682
|
aria-label path:buttons.aria-label,
|