@aurodesignsystem/auro-library 5.12.2 → 5.13.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/CHANGELOG.md +29 -0
- package/package.json +1 -1
- package/scripts/runtime/Focusables/test/Focusables.test.js +75 -55
- package/scripts/runtime/dateUtilities/dateFormatter.mjs +228 -102
- package/scripts/runtime/dateUtilities/dateFormatter.test.js +284 -0
- package/scripts/runtime/dateUtilities/dateUtilities.mjs +40 -41
- package/scripts/runtime/dateUtilities/dateUtilities.test.js +80 -0
- package/scripts/runtime/floatingUI.mjs +152 -14
- package/scripts/runtime/floatingUI.test.js +267 -0
|
@@ -62,6 +62,36 @@ export default class AuroFloatingUI {
|
|
|
62
62
|
}
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
static openingQueue = [];
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Returns the currently active floating UI instance that should be considered "on top".
|
|
69
|
+
* Prefers any globally tracked expanded dropdown or floater, falling back to the last entry in the local opening queue.
|
|
70
|
+
*
|
|
71
|
+
* This getter first checks the global document references for a visible floating UI and returns it if found.
|
|
72
|
+
* If the global reference is stale or not visible, it clears those references and instead returns the most recently opened instance from `openingQueue`, or `null` if none exist.
|
|
73
|
+
*
|
|
74
|
+
* Side effect: clears stale global refs so callers don't need a separate cleanup step.
|
|
75
|
+
*/
|
|
76
|
+
static get topOpeningFloatingUI() {
|
|
77
|
+
const existedVisibleFloatingUI =
|
|
78
|
+
document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
|
|
79
|
+
if (
|
|
80
|
+
existedVisibleFloatingUI &&
|
|
81
|
+
existedVisibleFloatingUI.element.isPopoverVisible
|
|
82
|
+
) {
|
|
83
|
+
return existedVisibleFloatingUI;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// clear existedVisibleFloatingUI in case it's not flushed well when it hidden by other reasons (e.g. noToggle + click)
|
|
87
|
+
document.expandedAuroFormkitDropdown = null;
|
|
88
|
+
document.expandedAuroFloater = null;
|
|
89
|
+
|
|
90
|
+
return AuroFloatingUI.openingQueue.length > 0
|
|
91
|
+
? AuroFloatingUI.openingQueue[AuroFloatingUI.openingQueue.length - 1]
|
|
92
|
+
: null;
|
|
93
|
+
}
|
|
94
|
+
|
|
65
95
|
constructor(element, behavior) {
|
|
66
96
|
this.element = element;
|
|
67
97
|
this.behavior = behavior;
|
|
@@ -161,12 +191,16 @@ export default class AuroFloatingUI {
|
|
|
161
191
|
`(max-width: ${breakpoint})`,
|
|
162
192
|
).matches;
|
|
163
193
|
|
|
164
|
-
element.expanded = smallerThanBreakpoint;
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
194
|
+
this.element.expanded = smallerThanBreakpoint;
|
|
195
|
+
|
|
196
|
+
if (this.element.nested) {
|
|
197
|
+
return "cover";
|
|
198
|
+
}
|
|
199
|
+
return smallerThanBreakpoint || this.element.modal
|
|
200
|
+
? "fullscreen"
|
|
201
|
+
: "dialog";
|
|
168
202
|
}
|
|
169
|
-
return "
|
|
203
|
+
return "dialog";
|
|
170
204
|
case "dropdown":
|
|
171
205
|
case undefined:
|
|
172
206
|
case null:
|
|
@@ -265,17 +299,111 @@ export default class AuroFloatingUI {
|
|
|
265
299
|
lockScroll(lock = true) {
|
|
266
300
|
const element = this.element;
|
|
267
301
|
|
|
268
|
-
if (
|
|
269
|
-
|
|
270
|
-
|
|
302
|
+
if (!element?.bib) {
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
const dialog = (
|
|
307
|
+
element.bib?.shadowRoot ||
|
|
308
|
+
element.bib ||
|
|
309
|
+
element
|
|
310
|
+
).querySelector("dialog");
|
|
311
|
+
if (dialog) {
|
|
312
|
+
if (lock) {
|
|
313
|
+
dialog.setAttribute("aria-modal", "true");
|
|
314
|
+
} else {
|
|
315
|
+
dialog.removeAttribute("aria-modal");
|
|
271
316
|
}
|
|
317
|
+
}
|
|
272
318
|
|
|
273
|
-
|
|
319
|
+
if (lock) {
|
|
320
|
+
if (!this._scrollLocked) {
|
|
321
|
+
this._scrollLocked = true;
|
|
322
|
+
this._savedScrollY = window.scrollY;
|
|
323
|
+
this._savedScrollStyles = {
|
|
324
|
+
rootScrollbarGutter: document.documentElement.style.scrollbarGutter,
|
|
325
|
+
rootOverflow: document.documentElement.style.overflow,
|
|
326
|
+
bodyOverflow: document.body.style.overflow,
|
|
327
|
+
bodyPosition: document.body.style.position,
|
|
328
|
+
bodyTop: document.body.style.top,
|
|
329
|
+
bodyWidth: document.body.style.width,
|
|
330
|
+
bibTransform: element?.bib?.style.transform,
|
|
331
|
+
};
|
|
332
|
+
document.documentElement.style.scrollbarGutter = "stable";
|
|
333
|
+
document.documentElement.style.overflow = "hidden";
|
|
334
|
+
document.body.style.overflow = "hidden";
|
|
335
|
+
|
|
336
|
+
// position:fixed is the only way to block VoiceOver three-finger swipe,
|
|
337
|
+
// which bypasses both overflow:hidden and touchmove preventDefault.
|
|
338
|
+
document.body.style.position = "fixed";
|
|
339
|
+
document.body.style.top = `-${this._savedScrollY}px`;
|
|
340
|
+
document.body.style.width = "100%";
|
|
341
|
+
|
|
342
|
+
// Move `bib` by the amount the viewport is shifted to stay aligned in fullscreen.
|
|
343
|
+
if (element?.bib && window?.visualViewport?.offsetTop) {
|
|
344
|
+
element.bib.style.transform = `translateY(${window?.visualViewport?.offsetTop}px)`;
|
|
345
|
+
}
|
|
274
346
|
|
|
275
|
-
|
|
276
|
-
|
|
347
|
+
this.lockTouchScroll(true);
|
|
348
|
+
}
|
|
277
349
|
} else {
|
|
278
|
-
|
|
350
|
+
if (this._scrollLocked) {
|
|
351
|
+
document.documentElement.style.scrollbarGutter =
|
|
352
|
+
this._savedScrollStyles?.rootScrollbarGutter ?? "";
|
|
353
|
+
document.documentElement.style.overflow =
|
|
354
|
+
this._savedScrollStyles?.rootOverflow ?? "";
|
|
355
|
+
document.body.style.overflow =
|
|
356
|
+
this._savedScrollStyles?.bodyOverflow ?? "";
|
|
357
|
+
document.body.style.position =
|
|
358
|
+
this._savedScrollStyles?.bodyPosition ?? "";
|
|
359
|
+
document.body.style.top = this._savedScrollStyles?.bodyTop ?? "";
|
|
360
|
+
document.body.style.width = this._savedScrollStyles?.bodyWidth ?? "";
|
|
361
|
+
if (element?.bib) {
|
|
362
|
+
element.bib.style.transform =
|
|
363
|
+
this._savedScrollStyles?.bibTransform ?? "";
|
|
364
|
+
}
|
|
365
|
+
window.scrollTo(0, this._savedScrollY || 0);
|
|
366
|
+
this._savedScrollY = undefined;
|
|
367
|
+
this._savedScrollStyles = undefined;
|
|
368
|
+
this._scrollLocked = false;
|
|
369
|
+
|
|
370
|
+
this.lockTouchScroll(false);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
/**
|
|
376
|
+
* Locks page-level touch scroll while bib is open.
|
|
377
|
+
* Walks composedPath() so scrollable children inside the dialog still scroll.
|
|
378
|
+
* @private
|
|
379
|
+
*/
|
|
380
|
+
lockTouchScroll(lock = true) {
|
|
381
|
+
if (lock) {
|
|
382
|
+
if (this._boundTouchMoveHandler) {
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
this._boundTouchMoveHandler = (e) => {
|
|
386
|
+
const path = e.composedPath();
|
|
387
|
+
const insideScrollable = path.some(
|
|
388
|
+
(el) =>
|
|
389
|
+
el !== document &&
|
|
390
|
+
el !== document.documentElement &&
|
|
391
|
+
el !== document.body &&
|
|
392
|
+
(el.scrollHeight > el.clientHeight ||
|
|
393
|
+
el.scrollWidth > el.clientWidth),
|
|
394
|
+
);
|
|
395
|
+
if (!insideScrollable) {
|
|
396
|
+
e.preventDefault();
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
document.addEventListener("touchmove", this._boundTouchMoveHandler, {
|
|
400
|
+
passive: false,
|
|
401
|
+
});
|
|
402
|
+
} else if (this._boundTouchMoveHandler) {
|
|
403
|
+
document.removeEventListener("touchmove", this._boundTouchMoveHandler, {
|
|
404
|
+
passive: false,
|
|
405
|
+
});
|
|
406
|
+
this._boundTouchMoveHandler = undefined;
|
|
279
407
|
}
|
|
280
408
|
}
|
|
281
409
|
|
|
@@ -294,7 +422,7 @@ export default class AuroFloatingUI {
|
|
|
294
422
|
return;
|
|
295
423
|
}
|
|
296
424
|
|
|
297
|
-
if (value === "fullscreen") {
|
|
425
|
+
if (value === "fullscreen" || value === "dialog") {
|
|
298
426
|
element.isBibFullscreen = true;
|
|
299
427
|
// reset the prev position
|
|
300
428
|
element.bib.setAttribute("isfullscreen", "");
|
|
@@ -322,7 +450,7 @@ export default class AuroFloatingUI {
|
|
|
322
450
|
}
|
|
323
451
|
|
|
324
452
|
if (element.isPopoverVisible) {
|
|
325
|
-
this.lockScroll(
|
|
453
|
+
this.lockScroll(value === "fullscreen");
|
|
326
454
|
}
|
|
327
455
|
} else {
|
|
328
456
|
element.bib.style.position = "";
|
|
@@ -595,6 +723,12 @@ export default class AuroFloatingUI {
|
|
|
595
723
|
this.position();
|
|
596
724
|
},
|
|
597
725
|
);
|
|
726
|
+
|
|
727
|
+
const idx = AuroFloatingUI.openingQueue.indexOf(this);
|
|
728
|
+
if (idx > -1) {
|
|
729
|
+
AuroFloatingUI.openingQueue.splice(idx, 1);
|
|
730
|
+
}
|
|
731
|
+
AuroFloatingUI.openingQueue.push(this);
|
|
598
732
|
}
|
|
599
733
|
}
|
|
600
734
|
|
|
@@ -635,6 +769,10 @@ export default class AuroFloatingUI {
|
|
|
635
769
|
// Clearing it when hideBib is blocked (e.g. noToggle + click) corrupts
|
|
636
770
|
// the singleton state so other dropdowns can't detect this one is still open.
|
|
637
771
|
document.expandedAuroFloater = null;
|
|
772
|
+
const idx = AuroFloatingUI.openingQueue.indexOf(this);
|
|
773
|
+
if (idx > -1) {
|
|
774
|
+
AuroFloatingUI.openingQueue.splice(idx, 1);
|
|
775
|
+
}
|
|
638
776
|
}
|
|
639
777
|
|
|
640
778
|
/**
|
|
@@ -129,4 +129,271 @@ describe("AuroFloatingUI", () => {
|
|
|
129
129
|
|
|
130
130
|
expect(floatingUI.getPositioningStrategy()).to.equal("floating");
|
|
131
131
|
});
|
|
132
|
+
|
|
133
|
+
it("restores pre-existing inline scroll styles after lock/unlock", () => {
|
|
134
|
+
document.documentElement.style.scrollbarGutter = "auto";
|
|
135
|
+
document.documentElement.style.overflow = "clip";
|
|
136
|
+
document.body.style.overflow = "scroll";
|
|
137
|
+
document.body.style.position = "sticky";
|
|
138
|
+
document.body.style.top = "12px";
|
|
139
|
+
document.body.style.width = "75%";
|
|
140
|
+
const scrollToStub = sinon.stub(window, "scrollTo");
|
|
141
|
+
|
|
142
|
+
floatingUI.lockScroll(true);
|
|
143
|
+
|
|
144
|
+
expect(document.documentElement.style.scrollbarGutter).to.equal("stable");
|
|
145
|
+
expect(document.documentElement.style.overflow).to.equal("hidden");
|
|
146
|
+
expect(document.body.style.overflow).to.equal("hidden");
|
|
147
|
+
expect(document.body.style.position).to.equal("fixed");
|
|
148
|
+
expect(document.body.style.width).to.equal("100%");
|
|
149
|
+
|
|
150
|
+
floatingUI.lockScroll(false);
|
|
151
|
+
|
|
152
|
+
expect(document.documentElement.style.scrollbarGutter).to.equal("auto");
|
|
153
|
+
expect(document.documentElement.style.overflow).to.equal("clip");
|
|
154
|
+
expect(document.body.style.overflow).to.equal("scroll");
|
|
155
|
+
expect(document.body.style.position).to.equal("sticky");
|
|
156
|
+
expect(document.body.style.top).to.equal("12px");
|
|
157
|
+
expect(document.body.style.width).to.equal("75%");
|
|
158
|
+
expect(scrollToStub.calledOnceWithExactly(0, 0)).to.be.true;
|
|
159
|
+
expect(floatingUI._boundTouchMoveHandler).to.equal(undefined);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("prevents touch scroll when gesture is outside scrollable content", () => {
|
|
163
|
+
floatingUI.lockTouchScroll(true);
|
|
164
|
+
|
|
165
|
+
const preventDefault = sinon.spy();
|
|
166
|
+
floatingUI._boundTouchMoveHandler({
|
|
167
|
+
composedPath: () => [document.body],
|
|
168
|
+
preventDefault,
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
expect(preventDefault.calledOnce).to.be.true;
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it("allows touch scroll when gesture is inside scrollable content", () => {
|
|
175
|
+
floatingUI.lockTouchScroll(true);
|
|
176
|
+
|
|
177
|
+
const scrollable = document.createElement("div");
|
|
178
|
+
Object.defineProperty(scrollable, "scrollHeight", {
|
|
179
|
+
configurable: true,
|
|
180
|
+
value: 200,
|
|
181
|
+
});
|
|
182
|
+
Object.defineProperty(scrollable, "clientHeight", {
|
|
183
|
+
configurable: true,
|
|
184
|
+
value: 100,
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const preventDefault = sinon.spy();
|
|
188
|
+
floatingUI._boundTouchMoveHandler({
|
|
189
|
+
composedPath: () => [scrollable],
|
|
190
|
+
preventDefault,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
expect(preventDefault.called).to.be.false;
|
|
194
|
+
});
|
|
195
|
+
it("lockScroll sets _scrollLocked flag when locking", () => {
|
|
196
|
+
floatingUI.lockScroll(true);
|
|
197
|
+
expect(floatingUI._scrollLocked).to.be.true;
|
|
198
|
+
floatingUI.lockScroll(false);
|
|
199
|
+
expect(floatingUI._scrollLocked).to.be.false;
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("lockScroll saves scroll position when locking", () => {
|
|
203
|
+
const originalScrollY = window.scrollY;
|
|
204
|
+
floatingUI.lockScroll(true);
|
|
205
|
+
expect(floatingUI._savedScrollY).to.equal(originalScrollY);
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it("lockScroll restores scroll position when unlocking", () => {
|
|
209
|
+
floatingUI.lockScroll(true);
|
|
210
|
+
window.scrollTo(0, 500);
|
|
211
|
+
floatingUI.lockScroll(false);
|
|
212
|
+
// Note: scrollTo may not work in test environment, but the restoration logic is in place
|
|
213
|
+
expect(floatingUI._scrollLocked).to.be.false;
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it("lockTouchScroll creates event handler when locking", () => {
|
|
217
|
+
expect(floatingUI._boundTouchMoveHandler).to.be.undefined;
|
|
218
|
+
floatingUI.lockTouchScroll(true);
|
|
219
|
+
expect(floatingUI._boundTouchMoveHandler).to.be.a("function");
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
it("lockTouchScroll removes event handler when unlocking", () => {
|
|
223
|
+
floatingUI.lockTouchScroll(true);
|
|
224
|
+
floatingUI.lockTouchScroll(false);
|
|
225
|
+
expect(floatingUI._boundTouchMoveHandler).to.be.undefined;
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it("lockTouchScroll prevents default on non-scrollable elements", () => {
|
|
229
|
+
floatingUI.lockTouchScroll(true);
|
|
230
|
+
const nonScrollable = document.createElement("div");
|
|
231
|
+
const preventDefault = sinon.spy();
|
|
232
|
+
const touchEvent = {
|
|
233
|
+
composedPath: () => [nonScrollable],
|
|
234
|
+
preventDefault,
|
|
235
|
+
};
|
|
236
|
+
floatingUI._boundTouchMoveHandler(touchEvent);
|
|
237
|
+
expect(preventDefault.called).to.be.true;
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
it("lockTouchScroll allows touchmove on scrollable elements", () => {
|
|
241
|
+
floatingUI.lockTouchScroll(true);
|
|
242
|
+
const scrollable = document.createElement("div");
|
|
243
|
+
Object.defineProperty(scrollable, "scrollHeight", {
|
|
244
|
+
configurable: true,
|
|
245
|
+
value: 200,
|
|
246
|
+
});
|
|
247
|
+
Object.defineProperty(scrollable, "clientHeight", {
|
|
248
|
+
configurable: true,
|
|
249
|
+
value: 100,
|
|
250
|
+
});
|
|
251
|
+
const preventDefault = sinon.spy();
|
|
252
|
+
const touchEvent = {
|
|
253
|
+
composedPath: () => [scrollable],
|
|
254
|
+
preventDefault,
|
|
255
|
+
};
|
|
256
|
+
floatingUI._boundTouchMoveHandler(touchEvent);
|
|
257
|
+
expect(preventDefault.called).to.be.false;
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
it("configureBibStrategy sets isfullscreen attribute for fullscreen", () => {
|
|
261
|
+
host.bib = bib;
|
|
262
|
+
host.isPopoverVisible = false;
|
|
263
|
+
floatingUI.configureBibStrategy("fullscreen");
|
|
264
|
+
expect(bib.getAttribute("isfullscreen")).to.equal("");
|
|
265
|
+
expect(host.isBibFullscreen).to.be.true;
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
it("configureBibStrategy removes isfullscreen attribute for floating", () => {
|
|
269
|
+
host.bib = bib;
|
|
270
|
+
bib.setAttribute("isfullscreen", "");
|
|
271
|
+
host.isBibFullscreen = true;
|
|
272
|
+
floatingUI.configureBibStrategy("floating");
|
|
273
|
+
expect(bib.hasAttribute("isfullscreen")).to.be.false;
|
|
274
|
+
expect(host.isBibFullscreen).to.be.false;
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it("getPositioningStrategy returns 'dialog' for dialog behavior without breakpoint", () => {
|
|
278
|
+
floatingUI.behavior = "dialog";
|
|
279
|
+
host.floaterConfig = {};
|
|
280
|
+
const strategy = floatingUI.getPositioningStrategy();
|
|
281
|
+
expect(strategy).to.equal("dialog");
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it("getPositioningStrategy returns 'floating' for undefined behavior", () => {
|
|
285
|
+
floatingUI.behavior = undefined;
|
|
286
|
+
host.floaterConfig = {};
|
|
287
|
+
const strategy = floatingUI.getPositioningStrategy();
|
|
288
|
+
expect(strategy).to.equal("floating");
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it("getPositioningStrategy returns 'floating' when element is missing", () => {
|
|
292
|
+
floatingUI.element = null;
|
|
293
|
+
const strategy = floatingUI.getPositioningStrategy();
|
|
294
|
+
expect(strategy).to.equal("floating");
|
|
295
|
+
});
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
describe("AuroFloatingUI.openingQueue and topOpeningFloatingUI", () => {
|
|
299
|
+
let floatingUI1;
|
|
300
|
+
let floatingUI2;
|
|
301
|
+
let floatingUI3;
|
|
302
|
+
let host1;
|
|
303
|
+
let host2;
|
|
304
|
+
let host3;
|
|
305
|
+
let bib1;
|
|
306
|
+
let bib2;
|
|
307
|
+
let bib3;
|
|
308
|
+
|
|
309
|
+
beforeEach(() => {
|
|
310
|
+
AuroFloatingUI.openingQueue = [];
|
|
311
|
+
document.expandedAuroFormkitDropdown = null;
|
|
312
|
+
document.expandedAuroFloater = null;
|
|
313
|
+
|
|
314
|
+
host1 = document.createElement("div");
|
|
315
|
+
bib1 = document.createElement("div");
|
|
316
|
+
host1.bib = bib1;
|
|
317
|
+
host1.isPopoverVisible = false;
|
|
318
|
+
document.body.append(host1, bib1);
|
|
319
|
+
floatingUI1 = new AuroFloatingUI(host1, "dropdown");
|
|
320
|
+
|
|
321
|
+
host2 = document.createElement("div");
|
|
322
|
+
bib2 = document.createElement("div");
|
|
323
|
+
host2.bib = bib2;
|
|
324
|
+
host2.isPopoverVisible = false;
|
|
325
|
+
document.body.append(host2, bib2);
|
|
326
|
+
floatingUI2 = new AuroFloatingUI(host2, "dropdown");
|
|
327
|
+
|
|
328
|
+
host3 = document.createElement("div");
|
|
329
|
+
bib3 = document.createElement("div");
|
|
330
|
+
host3.bib = bib3;
|
|
331
|
+
host3.isPopoverVisible = false;
|
|
332
|
+
document.body.append(host3, bib3);
|
|
333
|
+
floatingUI3 = new AuroFloatingUI(host3, "dropdown");
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
afterEach(() => {
|
|
337
|
+
AuroFloatingUI.openingQueue = [];
|
|
338
|
+
document.expandedAuroFormkitDropdown = null;
|
|
339
|
+
document.expandedAuroFloater = null;
|
|
340
|
+
host1?.remove();
|
|
341
|
+
host2?.remove();
|
|
342
|
+
host3?.remove();
|
|
343
|
+
bib1?.remove();
|
|
344
|
+
bib2?.remove();
|
|
345
|
+
bib3?.remove();
|
|
346
|
+
sinon.restore();
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
it("can add instances to openingQueue", () => {
|
|
350
|
+
AuroFloatingUI.openingQueue.push(floatingUI1);
|
|
351
|
+
expect(AuroFloatingUI.openingQueue).to.include(floatingUI1);
|
|
352
|
+
expect(AuroFloatingUI.openingQueue.length).to.equal(1);
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
it("maintains insertion order in openingQueue", () => {
|
|
356
|
+
AuroFloatingUI.openingQueue.push(floatingUI1);
|
|
357
|
+
AuroFloatingUI.openingQueue.push(floatingUI2);
|
|
358
|
+
expect(AuroFloatingUI.openingQueue[0]).to.equal(floatingUI1);
|
|
359
|
+
expect(AuroFloatingUI.openingQueue[1]).to.equal(floatingUI2);
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
it("can remove instances from openingQueue", () => {
|
|
363
|
+
AuroFloatingUI.openingQueue.push(floatingUI1);
|
|
364
|
+
AuroFloatingUI.openingQueue.push(floatingUI2);
|
|
365
|
+
const index = AuroFloatingUI.openingQueue.indexOf(floatingUI1);
|
|
366
|
+
AuroFloatingUI.openingQueue.splice(index, 1);
|
|
367
|
+
expect(AuroFloatingUI.openingQueue).to.not.include(floatingUI1);
|
|
368
|
+
expect(AuroFloatingUI.openingQueue).to.include(floatingUI2);
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
it("topOpeningFloatingUI returns global reference when visible", () => {
|
|
372
|
+
document.expandedAuroFloater = floatingUI1;
|
|
373
|
+
floatingUI1.element.isPopoverVisible = true;
|
|
374
|
+
const topUI = AuroFloatingUI.topOpeningFloatingUI;
|
|
375
|
+
expect(topUI).to.equal(floatingUI1);
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
it("topOpeningFloatingUI returns queue last entry when global ref is stale", () => {
|
|
379
|
+
document.expandedAuroFloater = floatingUI1;
|
|
380
|
+
floatingUI1.element.isPopoverVisible = false;
|
|
381
|
+
AuroFloatingUI.openingQueue.push(floatingUI2);
|
|
382
|
+
floatingUI2.element.isPopoverVisible = true;
|
|
383
|
+
const topUI = AuroFloatingUI.topOpeningFloatingUI;
|
|
384
|
+
expect(topUI).to.equal(floatingUI2);
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
it("topOpeningFloatingUI returns last entry from queue", () => {
|
|
388
|
+
AuroFloatingUI.openingQueue.push(floatingUI1);
|
|
389
|
+
AuroFloatingUI.openingQueue.push(floatingUI2);
|
|
390
|
+
AuroFloatingUI.openingQueue.push(floatingUI3);
|
|
391
|
+
const topUI = AuroFloatingUI.topOpeningFloatingUI;
|
|
392
|
+
expect(topUI).to.equal(floatingUI3);
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
it("topOpeningFloatingUI returns null when queue is empty", () => {
|
|
396
|
+
const topUI = AuroFloatingUI.topOpeningFloatingUI;
|
|
397
|
+
expect(topUI).to.be.null;
|
|
398
|
+
});
|
|
132
399
|
});
|