@aurodesignsystem-dev/auro-library 0.0.0-pr187.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.
Files changed (43) hide show
  1. package/.husky/commit-msg +4 -0
  2. package/.husky/pre-commit +4 -0
  3. package/.tool-versions +1 -0
  4. package/CHANGELOG.md +664 -0
  5. package/LICENSE +201 -0
  6. package/README.md +235 -0
  7. package/bin/generateDocs.mjs +210 -0
  8. package/bin/generateDocs_index.mjs +210 -0
  9. package/package.json +92 -0
  10. package/scripts/build/generateDocs.mjs +24 -0
  11. package/scripts/build/generateReadme.mjs +60 -0
  12. package/scripts/build/generateWcaComponent.mjs +43 -0
  13. package/scripts/build/postCss.mjs +66 -0
  14. package/scripts/build/postinstall.mjs +31 -0
  15. package/scripts/build/pre-commit.mjs +17 -0
  16. package/scripts/build/prepWcaCompatibleCode.mjs +19 -0
  17. package/scripts/build/processors/defaultDocsProcessor.mjs +83 -0
  18. package/scripts/build/processors/defaultDotGithubSync.mjs +83 -0
  19. package/scripts/build/staticStyles-template.js +2 -0
  20. package/scripts/build/syncGithubFiles.mjs +25 -0
  21. package/scripts/build/versionWriter.js +26 -0
  22. package/scripts/runtime/FocusTrap/FocusTrap.mjs +194 -0
  23. package/scripts/runtime/FocusTrap/index.mjs +1 -0
  24. package/scripts/runtime/FocusTrap/test/FocusTrap.test.js +168 -0
  25. package/scripts/runtime/Focusables/Focusables.mjs +157 -0
  26. package/scripts/runtime/Focusables/index.mjs +1 -0
  27. package/scripts/runtime/Focusables/test/Focusables.test.js +165 -0
  28. package/scripts/runtime/dateUtilities/baseDateUtilities.mjs +58 -0
  29. package/scripts/runtime/dateUtilities/dateConstraints.mjs +11 -0
  30. package/scripts/runtime/dateUtilities/dateFormatter.mjs +104 -0
  31. package/scripts/runtime/dateUtilities/dateUtilities.mjs +218 -0
  32. package/scripts/runtime/dateUtilities/index.mjs +26 -0
  33. package/scripts/runtime/dependencyTagVersioning.mjs +42 -0
  34. package/scripts/runtime/floatingUI.mjs +646 -0
  35. package/scripts/test-plugin/iterateWithA11Check.mjs +82 -0
  36. package/scripts/utils/auroFileHandler.mjs +70 -0
  37. package/scripts/utils/auroLibraryUtils.mjs +206 -0
  38. package/scripts/utils/auroTemplateFiller.mjs +178 -0
  39. package/scripts/utils/logger.mjs +73 -0
  40. package/scripts/utils/runtimeUtils.mjs +70 -0
  41. package/scripts/utils/sharedFileProcessorUtils.mjs +270 -0
  42. package/shellScripts/README.md +58 -0
  43. package/shellScripts/automation.sh +104 -0
@@ -0,0 +1,646 @@
1
+ /* eslint-disable line-comment-position, no-inline-comments */
2
+
3
+ import { autoUpdate, computePosition, offset, autoPlacement, flip } from '@floating-ui/dom';
4
+
5
+
6
+ const MAX_CONFIGURATION_COUNT = 10;
7
+
8
+ export default class AuroFloatingUI {
9
+
10
+ /**
11
+ * @private
12
+ */
13
+ static isMousePressed = false;
14
+
15
+ /**
16
+ * @private
17
+ */
18
+ static isMousePressHandlerInitialized = false;
19
+
20
+ /**
21
+ * @private
22
+ */
23
+ static setupMousePressChecker() {
24
+ if (!AuroFloatingUI.isMousePressHandlerInitialized && window && window.addEventListener) {
25
+ AuroFloatingUI.isMousePressHandlerInitialized = true;
26
+
27
+ // Track timeout for isMousePressed reset to avoid race conditions
28
+ if (!AuroFloatingUI._mousePressedTimeout) {
29
+ AuroFloatingUI._mousePressedTimeout = null;
30
+ }
31
+ const mouseEventGlobalHandler = (event) => {
32
+ const isPressed = event.type === 'mousedown';
33
+ if (isPressed) {
34
+ // Clear any pending timeout to prevent race condition
35
+ if (AuroFloatingUI._mousePressedTimeout !== null) {
36
+ clearTimeout(AuroFloatingUI._mousePressedTimeout);
37
+ AuroFloatingUI._mousePressedTimeout = null;
38
+ }
39
+ if (!AuroFloatingUI.isMousePressed) {
40
+ AuroFloatingUI.isMousePressed = true;
41
+ }
42
+ } else if (AuroFloatingUI.isMousePressed && !isPressed) {
43
+ // Schedule reset and track timeout ID
44
+ AuroFloatingUI._mousePressedTimeout = setTimeout(() => {
45
+ AuroFloatingUI.isMousePressed = false;
46
+ AuroFloatingUI._mousePressedTimeout = null;
47
+ }, 0);
48
+ }
49
+ };
50
+
51
+ window.addEventListener('mousedown', mouseEventGlobalHandler);
52
+ window.addEventListener('mouseup', mouseEventGlobalHandler);
53
+ }
54
+ }
55
+
56
+ constructor(element, behavior) {
57
+ this.element = element;
58
+ this.behavior = behavior;
59
+
60
+ // Store event listener references for cleanup
61
+ this.focusHandler = null;
62
+ this.clickHandler = null;
63
+ this.keyDownHandler = null;
64
+
65
+ /**
66
+ * @private
67
+ */
68
+ this.configureTrial = 0;
69
+
70
+ /**
71
+ * @private
72
+ */
73
+ this.eventPrefix = undefined;
74
+
75
+ /**
76
+ * @private
77
+ */
78
+ this.id = undefined;
79
+
80
+ /**
81
+ * @private
82
+ */
83
+ this.showing = false;
84
+
85
+ /**
86
+ * @private
87
+ */
88
+ this.strategy = undefined;
89
+ }
90
+
91
+ /**
92
+ * Mirrors the size of the bibSizer element to the bib content.
93
+ * Copies the width, height, max-width, and max-height styles from the bibSizer element to the bib content container.
94
+ * This ensures that the bib content has the same dimensions as the sizer element.
95
+ */
96
+ mirrorSize() {
97
+ // mirror the boxsize from bibSizer
98
+ if (this.element.bibSizer && this.element.matchWidth) {
99
+ const sizerStyle = window.getComputedStyle(this.element.bibSizer);
100
+ const bibContent = this.element.bib.shadowRoot.querySelector(".container");
101
+ if (sizerStyle.width !== '0px') {
102
+ bibContent.style.width = sizerStyle.width;
103
+ }
104
+ if (sizerStyle.height !== '0px') {
105
+ bibContent.style.height = sizerStyle.height;
106
+ }
107
+ bibContent.style.maxWidth = sizerStyle.maxWidth;
108
+ bibContent.style.maxHeight = sizerStyle.maxHeight;
109
+ }
110
+ }
111
+
112
+ /**
113
+ * @private
114
+ * Determines the positioning strategy based on the current viewport size and mobile breakpoint.
115
+ *
116
+ * This method checks if the current viewport width is less than or equal to the specified mobile fullscreen breakpoint
117
+ * defined in the bib element. If it is, the strategy is set to 'fullscreen'; otherwise, it defaults to 'floating'.
118
+ *
119
+ * @returns {String} The positioning strategy, one of 'fullscreen', 'floating', 'cover'.
120
+ */
121
+ getPositioningStrategy() {
122
+ const breakpoint = this.element.bib.mobileFullscreenBreakpoint || this.element.floaterConfig?.fullscreenBreakpoint;
123
+ switch (this.behavior) {
124
+ case "tooltip":
125
+ return "floating";
126
+ case "dialog":
127
+ case "drawer":
128
+ if (breakpoint) {
129
+ const smallerThanBreakpoint = window.matchMedia(`(max-width: ${breakpoint})`).matches;
130
+
131
+ this.element.expanded = smallerThanBreakpoint;
132
+ }
133
+ if (this.element.nested) {
134
+ return "cover";
135
+ }
136
+ return 'fullscreen';
137
+ case "dropdown":
138
+ case undefined:
139
+ case null:
140
+ if (breakpoint) {
141
+ const smallerThanBreakpoint = window.matchMedia(`(max-width: ${breakpoint})`).matches;
142
+ if (smallerThanBreakpoint) {
143
+ return 'fullscreen';
144
+ }
145
+ }
146
+ return "floating";
147
+ default:
148
+ return this.behavior;
149
+ }
150
+ }
151
+
152
+ /**
153
+ * @private
154
+ * Positions the bib element based on the current configuration and positioning strategy.
155
+ *
156
+ * This method determines the appropriate positioning strategy (fullscreen or not) and configures the bib accordingly.
157
+ * It also sets up middleware for the floater configuration, computes the position of the bib relative to the trigger element,
158
+ * and applies the calculated position to the bib's style.
159
+ */
160
+ position() {
161
+ const strategy = this.getPositioningStrategy();
162
+ this.configureBibStrategy(strategy);
163
+
164
+ if (strategy === 'floating') {
165
+ this.mirrorSize();
166
+ // Define the middlware for the floater configuration
167
+ const middleware = [
168
+ offset(this.element.floaterConfig?.offset || 0),
169
+ ...this.element.floaterConfig?.flip ? [flip()] : [], // Add flip middleware if flip is enabled.
170
+ ...this.element.floaterConfig?.autoPlacement ? [autoPlacement()] : [], // Add autoPlacement middleware if autoPlacement is enabled.
171
+ ];
172
+
173
+ // Compute the position of the bib
174
+ computePosition(this.element.trigger, this.element.bib, {
175
+ strategy: this.element.floaterConfig?.strategy || 'fixed',
176
+ placement: this.element.floaterConfig?.placement,
177
+ middleware: middleware || []
178
+ }).then(({ x, y }) => { // eslint-disable-line id-length
179
+ Object.assign(this.element.bib.style, {
180
+ left: `${x}px`,
181
+ top: `${y}px`,
182
+ });
183
+ });
184
+ } else if (strategy === 'cover') {
185
+ // Compute the position of the bib
186
+ computePosition(this.element.parentNode, this.element.bib, {
187
+ placement: 'bottom-start'
188
+ }).then(({ x, y }) => { // eslint-disable-line id-length
189
+ Object.assign(this.element.bib.style, {
190
+ left: `${x}px`,
191
+ top: `${y - this.element.parentNode.offsetHeight}px`,
192
+ width: `${this.element.parentNode.offsetWidth}px`,
193
+ height: `${this.element.parentNode.offsetHeight}px`
194
+ });
195
+ });
196
+ }
197
+ }
198
+
199
+ /**
200
+ * @private
201
+ * Controls whether to lock the scrolling for the document's body.
202
+ * @param {Boolean} lock - If true, locks the body's scrolling functionlity; otherwise, unlock.
203
+ */
204
+ lockScroll(lock = true) {
205
+ if (lock) {
206
+ document.body.style.overflow = 'hidden'; // hide body's scrollbar
207
+
208
+ // Move `bib` by the amount the viewport is shifted to stay aligned in fullscreen.
209
+ this.element.bib.style.transform = `translateY(${visualViewport.offsetTop}px)`;
210
+ } else {
211
+ document.body.style.overflow = '';
212
+ }
213
+ }
214
+
215
+ /**
216
+ * @private
217
+ * Configures the bib element's display strategy.
218
+ *
219
+ * Sets the bib to fullscreen or floating mode based on the provided strategy.
220
+ * Dispatches a 'strategy-change' event if the strategy changes.
221
+ *
222
+ * @param {string} strategy - The positioning strategy ('fullscreen' or 'floating').
223
+ */
224
+ configureBibStrategy(value) {
225
+ if (value === 'fullscreen') {
226
+ this.element.isBibFullscreen = true;
227
+ // reset the prev position
228
+ this.element.bib.setAttribute('isfullscreen', "");
229
+ this.element.bib.style.position = 'fixed';
230
+ this.element.bib.style.top = "0px";
231
+ this.element.bib.style.left = "0px";
232
+ this.element.bib.style.width = '';
233
+ this.element.bib.style.height = '';
234
+ this.element.style.contain = '';
235
+
236
+ // reset the size that was mirroring `size` css-part
237
+ const bibContent = this.element.bib.shadowRoot.querySelector(".container");
238
+ if (bibContent) {
239
+ bibContent.style.width = '';
240
+ bibContent.style.height = '';
241
+ bibContent.style.maxWidth = '';
242
+ bibContent.style.maxHeight = `${window.visualViewport.height}px`;
243
+ this.configureTrial = 0;
244
+ } else if (this.configureTrial < MAX_CONFIGURATION_COUNT) {
245
+ this.configureTrial += 1;
246
+
247
+ setTimeout(() => {
248
+ this.configureBibStrategy(value);
249
+ }, 0);
250
+ }
251
+
252
+ if (this.element.isPopoverVisible) {
253
+ this.lockScroll(true);
254
+ }
255
+ } else {
256
+ this.element.bib.style.position = '';
257
+ this.element.bib.removeAttribute('isfullscreen');
258
+ this.element.isBibFullscreen = false;
259
+ this.element.style.contain = 'layout';
260
+ }
261
+
262
+ const isChanged = this.strategy && this.strategy !== value;
263
+ this.strategy = value;
264
+ if (isChanged) {
265
+ const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-strategy-change` : 'strategy-change', {
266
+ detail: {
267
+ value,
268
+ },
269
+ composed: true
270
+ });
271
+
272
+ this.element.dispatchEvent(event);
273
+ }
274
+ }
275
+
276
+ updateState() {
277
+ const isVisible = this.element.isPopoverVisible;
278
+ if (!isVisible) {
279
+ this.cleanupHideHandlers();
280
+ try {
281
+ this.element.cleanup?.();
282
+ } catch (error) {
283
+ // Do nothing
284
+ }
285
+ }
286
+ }
287
+
288
+ /**
289
+ * @private
290
+ * getting called on 'blur' in trigger or `focusin` in document
291
+ *
292
+ * Hides the bib if focus moves outside of the trigger or bib, unless a 'noHideOnThisFocusLoss' flag is set.
293
+ * This method checks if the currently active element is still within the trigger or bib.
294
+ * If not, and if the bib isn't in fullscreen mode with focus lost, it hides the bib.
295
+ */
296
+ handleFocusLoss() {
297
+ // if mouse is being pressed, skip and let click event to handle the action
298
+ if (AuroFloatingUI.isMousePressed) {
299
+ return;
300
+ }
301
+
302
+ if (this.element.noHideOnThisFocusLoss ||
303
+ this.element.hasAttribute('noHideOnThisFocusLoss')) {
304
+ return;
305
+ }
306
+
307
+ const { activeElement } = document;
308
+ // if focus is still inside of trigger or bib, do not close
309
+ if (this.element.contains(activeElement) || this.element.bib?.contains(activeElement)) {
310
+ return;
311
+ }
312
+
313
+ // if fullscreen bib is in fullscreen mode, do not close
314
+ if (this.element.bib.hasAttribute('isfullscreen')) {
315
+ return;
316
+ }
317
+
318
+ this.hideBib("keydown");
319
+ }
320
+
321
+ setupHideHandlers() {
322
+ // Define handlers & store references
323
+ this.focusHandler = () => this.handleFocusLoss();
324
+
325
+ this.clickHandler = (evt) => {
326
+ if ((!evt.composedPath().includes(this.element.trigger) &&
327
+ !evt.composedPath().includes(this.element.bib)) ||
328
+ (this.element.bib.backdrop && evt.composedPath().includes(this.element.bib.backdrop))) {
329
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
330
+
331
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI.element.isPopoverVisible) {
332
+ // if something else is open, close that
333
+ existedVisibleFloatingUI.hideBib();
334
+ document.expandedAuroFormkitDropdown = null;
335
+ document.expandedAuroFloater = this;
336
+ } else {
337
+ this.hideBib("click");
338
+ }
339
+ }
340
+ };
341
+
342
+ // ESC key handler
343
+ this.keyDownHandler = (evt) => {
344
+ if (evt.key === 'Escape' && this.element.isPopoverVisible) {
345
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
346
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this && existedVisibleFloatingUI.element.isPopoverVisible) {
347
+ // if something else is open, let it handle itself
348
+ return;
349
+ }
350
+ this.hideBib("keydown");
351
+ }
352
+ };
353
+
354
+ if (this.behavior !== 'drawer' && this.behavior !== 'dialog') {
355
+ // Add event listeners using the stored references
356
+ document.addEventListener('focusin', this.focusHandler);
357
+ }
358
+
359
+ document.addEventListener('keydown', this.keyDownHandler);
360
+
361
+ // send this task to the end of queue to prevent conflicting
362
+ // it conflicts if showBib gets call from a button that's not this.element.trigger
363
+ setTimeout(() => {
364
+ window.addEventListener('click', this.clickHandler);
365
+ }, 0);
366
+ }
367
+
368
+ cleanupHideHandlers() {
369
+ // Remove event listeners if they exist
370
+
371
+ if (this.focusHandler) {
372
+ document.removeEventListener('focusin', this.focusHandler);
373
+ this.focusHandler = null;
374
+ }
375
+
376
+ if (this.clickHandler) {
377
+ window.removeEventListener('click', this.clickHandler);
378
+ this.clickHandler = null;
379
+ }
380
+
381
+ if (this.keyDownHandler) {
382
+ document.removeEventListener('keydown', this.keyDownHandler);
383
+ this.keyDownHandler = null;
384
+ }
385
+ }
386
+
387
+ handleUpdate(changedProperties) {
388
+ if (changedProperties.has('isPopoverVisible')) {
389
+ this.updateState();
390
+ }
391
+ }
392
+
393
+ updateCurrentExpandedDropdown() {
394
+ // Close any other dropdown that is already open
395
+ const existedVisibleFloatingUI = document.expandedAuroFormkitDropdown || document.expandedAuroFloater;
396
+ if (existedVisibleFloatingUI && existedVisibleFloatingUI !== this &&
397
+ existedVisibleFloatingUI.element.isPopoverVisible &&
398
+ document.expandedAuroFloater.eventPrefix === this.eventPrefix) {
399
+ document.expandedAuroFloater.hideBib();
400
+ }
401
+
402
+ document.expandedAuroFloater = this;
403
+ }
404
+
405
+ showBib() {
406
+ if (!this.element.disabled && !this.showing) {
407
+ this.updateCurrentExpandedDropdown();
408
+ this.element.triggerChevron?.setAttribute('data-expanded', true);
409
+
410
+ // prevent double showing: isPopovervisible gets first and showBib gets called later
411
+ if (!this.showing) {
412
+ if (!this.element.modal) {
413
+ this.setupHideHandlers();
414
+ }
415
+ this.showing = true;
416
+ this.element.isPopoverVisible = true;
417
+ this.position();
418
+ this.dispatchEventDropdownToggle();
419
+ }
420
+
421
+ // Setup auto update to handle resize and scroll
422
+ this.element.cleanup = autoUpdate(this.element.trigger || this.element.parentNode, this.element.bib, () => {
423
+ this.position();
424
+ });
425
+ }
426
+ }
427
+
428
+ /**
429
+ * Hides the floating UI element.
430
+ * @param {String} eventType - The event type that triggered the hiding action.
431
+ */
432
+ hideBib(eventType = "unknown") {
433
+ if (!this.element.disabled && !this.element.noToggle) {
434
+ this.lockScroll(false);
435
+ this.element.triggerChevron?.removeAttribute('data-expanded');
436
+
437
+ if (this.element.isPopoverVisible) {
438
+ this.element.isPopoverVisible = false;
439
+ }
440
+ if (this.showing) {
441
+ this.cleanupHideHandlers();
442
+ this.showing = false;
443
+ this.dispatchEventDropdownToggle(eventType);
444
+ }
445
+ }
446
+ document.expandedAuroFloater = null;
447
+ }
448
+
449
+ /**
450
+ * @private
451
+ * @returns {void} Dispatches event with an object showing the state of the dropdown.
452
+ * @param {String} eventType - The event type that triggered the toggle action.
453
+ */
454
+ dispatchEventDropdownToggle(eventType) {
455
+ const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-toggled` : 'toggled', {
456
+ detail: {
457
+ expanded: this.showing,
458
+ eventType: eventType || "unknown",
459
+ },
460
+ composed: true
461
+ });
462
+
463
+ this.element.dispatchEvent(event);
464
+ }
465
+
466
+ handleClick() {
467
+ if (this.element.isPopoverVisible) {
468
+ this.hideBib("click");
469
+ } else {
470
+ this.showBib();
471
+ }
472
+
473
+ const event = new CustomEvent(this.eventPrefix ? `${this.eventPrefix}-triggerClick` : "triggerClick", {
474
+ composed: true,
475
+ detail: {
476
+ expanded: this.element.isPopoverVisible
477
+ }
478
+ });
479
+
480
+ this.element.dispatchEvent(event);
481
+ }
482
+
483
+ handleEvent(event) {
484
+ if (!this.element.disableEventShow) {
485
+ switch (event.type) {
486
+ case 'keydown':
487
+ // Support both Enter and Space keys for accessibility
488
+ // Space is included as it's expected behavior for interactive elements
489
+
490
+ const origin = event.composedPath()[0];
491
+ if (event.key === 'Enter' || event.key === ' ' && (!origin || origin.tagName !== "INPUT")) {
492
+
493
+ event.preventDefault();
494
+ this.handleClick();
495
+ }
496
+ break;
497
+ case 'mouseenter':
498
+ if (this.element.hoverToggle) {
499
+ this.showBib();
500
+ }
501
+ break;
502
+ case 'mouseleave':
503
+ if (this.element.hoverToggle) {
504
+ this.hideBib("mouseleave");
505
+ }
506
+ break;
507
+ case 'focus':
508
+ if (this.element.focusShow) {
509
+
510
+ /*
511
+ This needs to better handle clicking that gives focus -
512
+ currently it shows and then immediately hides the bib
513
+ */
514
+ this.showBib();
515
+ }
516
+ break;
517
+ case 'blur':
518
+ // send this task 100ms later queue to
519
+ // wait a frame in case focus moves within the floating element/bib
520
+ setTimeout(() => this.handleFocusLoss(), 0);
521
+ break;
522
+ case 'click':
523
+ if (document.activeElement === document.body) {
524
+ event.currentTarget.focus();
525
+ }
526
+ this.handleClick();
527
+ break;
528
+ default:
529
+ // Do nothing
530
+ }
531
+ }
532
+ }
533
+
534
+ /**
535
+ * Manages the tabIndex of the trigger element based on its focusability.
536
+ *
537
+ * If the trigger element or any of its children are inherently focusable, the tabIndex of the component is set to -1.
538
+ * This prevents the component itself from being focusable when the trigger element already handles focus.
539
+ */
540
+ handleTriggerTabIndex() {
541
+ const focusableElementSelectors = [
542
+ 'a',
543
+ 'button',
544
+ 'input:not([type="hidden"])',
545
+ 'select',
546
+ 'textarea',
547
+ '[tabindex]:not([tabindex="-1"])',
548
+ 'auro-button',
549
+ 'auro-input',
550
+ 'auro-hyperlink'
551
+ ];
552
+
553
+ const triggerNode = this.element.querySelectorAll('[slot="trigger"]')[0];
554
+ if (!triggerNode) {
555
+ return;
556
+ }
557
+ const triggerNodeTagName = triggerNode.tagName.toLowerCase();
558
+
559
+ focusableElementSelectors.forEach((selector) => {
560
+ // Check if the trigger node element is focusable
561
+ if (triggerNodeTagName === selector) {
562
+ this.element.tabIndex = -1;
563
+ return;
564
+ }
565
+
566
+ // Check if any child is focusable
567
+ if (triggerNode.querySelector(selector)) {
568
+ this.element.tabIndex = -1;
569
+ }
570
+ });
571
+ }
572
+
573
+ /**
574
+ *
575
+ * @param {*} eventPrefix
576
+ */
577
+ regenerateBibId() {
578
+ this.id = this.element.getAttribute('id');
579
+ if (!this.id) {
580
+ this.id = window.crypto.randomUUID();
581
+ this.element.setAttribute('id', this.id);
582
+ }
583
+
584
+ this.element.bib.setAttribute("id", `${this.id}-floater-bib`);
585
+ }
586
+
587
+ configure(elem, eventPrefix) {
588
+ AuroFloatingUI.setupMousePressChecker();
589
+
590
+ this.eventPrefix = eventPrefix;
591
+ if (this.element !== elem) {
592
+ this.element = elem;
593
+ }
594
+
595
+ if (this.behavior !== this.element.behavior) {
596
+ this.behavior = this.element.behavior;
597
+ }
598
+
599
+ if (this.element.trigger) {
600
+ this.disconnect();
601
+ }
602
+ this.element.trigger = this.element.triggerElement || this.element.shadowRoot.querySelector('#trigger') || this.element.trigger;
603
+ this.element.bib = this.element.shadowRoot.querySelector('#bib') || this.element.bib;
604
+ this.element.bibSizer = this.element.shadowRoot.querySelector('#bibSizer');
605
+ this.element.triggerChevron = this.element.shadowRoot.querySelector('#showStateIcon');
606
+
607
+
608
+ if (this.element.floaterConfig) {
609
+ this.element.hoverToggle = this.element.floaterConfig.hoverToggle;
610
+ }
611
+
612
+ this.regenerateBibId();
613
+ this.handleTriggerTabIndex();
614
+
615
+ this.handleEvent = this.handleEvent.bind(this);
616
+ if (this.element.trigger) {
617
+ this.element.trigger.addEventListener('keydown', this.handleEvent);
618
+ this.element.trigger.addEventListener('click', this.handleEvent);
619
+ this.element.trigger.addEventListener('mouseenter', this.handleEvent);
620
+ this.element.trigger.addEventListener('mouseleave', this.handleEvent);
621
+ this.element.trigger.addEventListener('focus', this.handleEvent);
622
+ this.element.trigger.addEventListener('blur', this.handleEvent);
623
+ }
624
+ }
625
+
626
+ disconnect() {
627
+ this.cleanupHideHandlers();
628
+ if (this.element) {
629
+ this.element.cleanup?.();
630
+
631
+ if (this.element.bib) {
632
+ this.element.shadowRoot.append(this.element.bib);
633
+ }
634
+
635
+ // Remove event & keyboard listeners
636
+ if (this.element?.trigger) {
637
+ this.element.trigger.removeEventListener('keydown', this.handleEvent);
638
+ this.element.trigger.removeEventListener('click', this.handleEvent);
639
+ this.element.trigger.removeEventListener('mouseenter', this.handleEvent);
640
+ this.element.trigger.removeEventListener('mouseleave', this.handleEvent);
641
+ this.element.trigger.removeEventListener('focus', this.handleEvent);
642
+ this.element.trigger.removeEventListener('blur', this.handleEvent);
643
+ }
644
+ }
645
+ }
646
+ }