@aurodesignsystem-dev/auro-formkit 0.0.0-pr624.16 → 0.0.0-pr624.17
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/components/counter/demo/api.min.js +320 -61
- package/components/counter/demo/index.min.js +320 -61
- package/components/counter/dist/auro-counter-group.d.ts +16 -8
- package/components/counter/dist/index.js +320 -61
- package/components/counter/dist/registered.js +320 -61
- package/package.json +2 -2
|
@@ -9073,7 +9073,266 @@ class AuroElement extends i$2 {
|
|
|
9073
9073
|
}
|
|
9074
9074
|
}
|
|
9075
9075
|
|
|
9076
|
-
|
|
9076
|
+
// Selectors for focusable elements
|
|
9077
|
+
const FOCUSABLE_SELECTORS = [
|
|
9078
|
+
'a[href]',
|
|
9079
|
+
'button:not([disabled])',
|
|
9080
|
+
'textarea:not([disabled])',
|
|
9081
|
+
'input:not([disabled])',
|
|
9082
|
+
'select:not([disabled])',
|
|
9083
|
+
'[role="tab"]:not([disabled])',
|
|
9084
|
+
'[role="link"]:not([disabled])',
|
|
9085
|
+
'[role="button"]:not([disabled])',
|
|
9086
|
+
'[tabindex]:not([tabindex="-1"])',
|
|
9087
|
+
'[contenteditable]:not([contenteditable="false"])'
|
|
9088
|
+
];
|
|
9089
|
+
|
|
9090
|
+
// List of custom components that are known to be focusable
|
|
9091
|
+
const FOCUSABLE_COMPONENTS = [
|
|
9092
|
+
'auro-checkbox',
|
|
9093
|
+
'auro-radio',
|
|
9094
|
+
'auro-dropdown',
|
|
9095
|
+
'auro-button',
|
|
9096
|
+
'auro-combobox',
|
|
9097
|
+
'auro-input',
|
|
9098
|
+
'auro-counter',
|
|
9099
|
+
'auro-menu',
|
|
9100
|
+
'auro-select',
|
|
9101
|
+
'auro-datepicker',
|
|
9102
|
+
'auro-hyperlink',
|
|
9103
|
+
'auro-accordion',
|
|
9104
|
+
];
|
|
9105
|
+
|
|
9106
|
+
/**
|
|
9107
|
+
* Determines if a given element is a custom focusable component.
|
|
9108
|
+
* Returns true if the element matches a known focusable component and is not disabled.
|
|
9109
|
+
*
|
|
9110
|
+
* @param {HTMLElement} element The element to check for focusability.
|
|
9111
|
+
* @returns {boolean} True if the element is a focusable custom component, false otherwise.
|
|
9112
|
+
*/
|
|
9113
|
+
function isFocusableComponent(element) {
|
|
9114
|
+
const componentName = element.tagName.toLowerCase();
|
|
9115
|
+
|
|
9116
|
+
// Guard Clause: Element is a focusable component
|
|
9117
|
+
if (!FOCUSABLE_COMPONENTS.includes(componentName)) return false;
|
|
9118
|
+
|
|
9119
|
+
// Guard Clause: Element is not disabled
|
|
9120
|
+
if (element.hasAttribute('disabled')) return false;
|
|
9121
|
+
|
|
9122
|
+
// Guard Clause: The element is a hyperlink and has no href attribute
|
|
9123
|
+
if (componentName.match("hyperlink") && !element.hasAttribute('href')) return false;
|
|
9124
|
+
|
|
9125
|
+
// If all guard clauses pass, the element is a focusable component
|
|
9126
|
+
return true;
|
|
9127
|
+
}
|
|
9128
|
+
|
|
9129
|
+
/**
|
|
9130
|
+
* Retrieves all focusable elements within the container in DOM order, including those in shadow DOM and slots.
|
|
9131
|
+
* Returns a unique, ordered array of elements that can receive focus.
|
|
9132
|
+
*
|
|
9133
|
+
* @param {HTMLElement} container The container to search within
|
|
9134
|
+
* @returns {Array<HTMLElement>} An array of focusable elements within the container.
|
|
9135
|
+
*/
|
|
9136
|
+
function getFocusableElements(container) {
|
|
9137
|
+
// Get elements in DOM order by walking the tree
|
|
9138
|
+
const orderedFocusableElements = [];
|
|
9139
|
+
|
|
9140
|
+
// Define a recursive function to collect focusable elements in DOM order
|
|
9141
|
+
const collectFocusableElements = (root) => {
|
|
9142
|
+
// Check if current element is focusable
|
|
9143
|
+
if (root.nodeType === Node.ELEMENT_NODE) {
|
|
9144
|
+
// Check if this is a custom component that is focusable
|
|
9145
|
+
const isComponentFocusable = isFocusableComponent(root);
|
|
9146
|
+
|
|
9147
|
+
if (isComponentFocusable) {
|
|
9148
|
+
// Add the component itself as a focusable element and don't traverse its shadow DOM
|
|
9149
|
+
orderedFocusableElements.push(root);
|
|
9150
|
+
return; // Skip traversing inside this component
|
|
9151
|
+
}
|
|
9152
|
+
|
|
9153
|
+
// Check if the element itself matches any selector
|
|
9154
|
+
for (const selector of FOCUSABLE_SELECTORS) {
|
|
9155
|
+
if (root.matches?.(selector)) {
|
|
9156
|
+
orderedFocusableElements.push(root);
|
|
9157
|
+
break; // Once we know it's focusable, no need to check other selectors
|
|
9158
|
+
}
|
|
9159
|
+
}
|
|
9160
|
+
|
|
9161
|
+
// Process shadow DOM only for non-Auro components
|
|
9162
|
+
if (root.shadowRoot) {
|
|
9163
|
+
// Process shadow DOM children in order
|
|
9164
|
+
if (root.shadowRoot.children) {
|
|
9165
|
+
Array.from(root.shadowRoot.children).forEach(child => {
|
|
9166
|
+
collectFocusableElements(child);
|
|
9167
|
+
});
|
|
9168
|
+
}
|
|
9169
|
+
}
|
|
9170
|
+
|
|
9171
|
+
// Process slots and their assigned nodes in order
|
|
9172
|
+
if (root.tagName === 'SLOT') {
|
|
9173
|
+
const assignedNodes = root.assignedNodes({ flatten: true });
|
|
9174
|
+
for (const node of assignedNodes) {
|
|
9175
|
+
collectFocusableElements(node);
|
|
9176
|
+
}
|
|
9177
|
+
} else {
|
|
9178
|
+
// Process light DOM children in order
|
|
9179
|
+
if (root.children) {
|
|
9180
|
+
Array.from(root.children).forEach(child => {
|
|
9181
|
+
collectFocusableElements(child);
|
|
9182
|
+
});
|
|
9183
|
+
}
|
|
9184
|
+
}
|
|
9185
|
+
}
|
|
9186
|
+
};
|
|
9187
|
+
|
|
9188
|
+
// Start the traversal from the container
|
|
9189
|
+
collectFocusableElements(container);
|
|
9190
|
+
|
|
9191
|
+
// Remove duplicates that might have been collected through different paths
|
|
9192
|
+
// while preserving order
|
|
9193
|
+
const uniqueElements = [];
|
|
9194
|
+
const seen = new Set();
|
|
9195
|
+
|
|
9196
|
+
for (const element of orderedFocusableElements) {
|
|
9197
|
+
if (!seen.has(element)) {
|
|
9198
|
+
seen.add(element);
|
|
9199
|
+
uniqueElements.push(element);
|
|
9200
|
+
}
|
|
9201
|
+
}
|
|
9202
|
+
|
|
9203
|
+
return uniqueElements;
|
|
9204
|
+
}
|
|
9205
|
+
|
|
9206
|
+
/**
|
|
9207
|
+
* FocusTrap manages keyboard focus within a specified container element, ensuring that focus does not leave the container when tabbing.
|
|
9208
|
+
* It is commonly used for modal dialogs or overlays to improve accessibility by trapping focus within interactive UI components.
|
|
9209
|
+
*/
|
|
9210
|
+
class FocusTrap {
|
|
9211
|
+
/**
|
|
9212
|
+
* Creates a new FocusTrap instance for the given container element.
|
|
9213
|
+
* Initializes event listeners and prepares the container for focus management.
|
|
9214
|
+
*
|
|
9215
|
+
* @param {HTMLElement} container The DOM element to trap focus within.
|
|
9216
|
+
* @throws {Error} If the provided container is not a valid HTMLElement.
|
|
9217
|
+
*/
|
|
9218
|
+
constructor(container) {
|
|
9219
|
+
if (!container || !(container instanceof HTMLElement)) {
|
|
9220
|
+
throw new Error("FocusTrap requires a valid HTMLElement.");
|
|
9221
|
+
}
|
|
9222
|
+
|
|
9223
|
+
this.container = container;
|
|
9224
|
+
this.tabDirection = 'forward'; // or 'backward'
|
|
9225
|
+
|
|
9226
|
+
this._init();
|
|
9227
|
+
}
|
|
9228
|
+
|
|
9229
|
+
/**
|
|
9230
|
+
* Initializes the focus trap by setting up event listeners and attributes on the container.
|
|
9231
|
+
* Prepares the container for focus management, including support for shadow DOM and inert attributes.
|
|
9232
|
+
*
|
|
9233
|
+
* @private
|
|
9234
|
+
*/
|
|
9235
|
+
_init() {
|
|
9236
|
+
|
|
9237
|
+
// Add inert attribute to prevent focusing programmatically as well (if supported)
|
|
9238
|
+
if ('inert' in HTMLElement.prototype) {
|
|
9239
|
+
this.container.inert = false; // Ensure the container isn't inert
|
|
9240
|
+
this.container.setAttribute('data-focus-trap-container', true); // Mark for identification
|
|
9241
|
+
}
|
|
9242
|
+
|
|
9243
|
+
// Track tab direction
|
|
9244
|
+
this.container.addEventListener('keydown', this._onKeydown);
|
|
9245
|
+
}
|
|
9246
|
+
|
|
9247
|
+
/**
|
|
9248
|
+
* Handles keydown events to manage tab navigation within the container.
|
|
9249
|
+
* Ensures that focus wraps around when reaching the first or last focusable element.
|
|
9250
|
+
*
|
|
9251
|
+
* @param {KeyboardEvent} e The keyboard event triggered by user interaction.
|
|
9252
|
+
* @private
|
|
9253
|
+
*/
|
|
9254
|
+
_onKeydown = (e) => {
|
|
9255
|
+
|
|
9256
|
+
if (e.key === 'Tab') {
|
|
9257
|
+
|
|
9258
|
+
// Set the tab direction based on the key pressed
|
|
9259
|
+
this.tabDirection = e.shiftKey ? 'backward' : 'forward';
|
|
9260
|
+
|
|
9261
|
+
// Get the active element(s) in the document and shadow root
|
|
9262
|
+
// This will include the active element in the shadow DOM if it exists
|
|
9263
|
+
// Active element may be inside the shadow DOM depending on delegatesFocus, so we need to check both
|
|
9264
|
+
const actives = [
|
|
9265
|
+
document.activeElement,
|
|
9266
|
+
...document.activeElement.shadowRoot && [document.activeElement.shadowRoot.activeElement] || []
|
|
9267
|
+
];
|
|
9268
|
+
|
|
9269
|
+
// Update the focusable elements
|
|
9270
|
+
const focusables = this._getFocusableElements();
|
|
9271
|
+
|
|
9272
|
+
// If we're at either end of the focusable elements, wrap around to the other end
|
|
9273
|
+
const focusIndex =
|
|
9274
|
+
(actives.includes(focusables[0]) || actives.includes(this.container)) && this.tabDirection === 'backward'
|
|
9275
|
+
? focusables.length - 1
|
|
9276
|
+
: actives.includes(focusables[focusables.length - 1]) && this.tabDirection === 'forward'
|
|
9277
|
+
? 0
|
|
9278
|
+
: null;
|
|
9279
|
+
|
|
9280
|
+
if (focusIndex !== null) {
|
|
9281
|
+
focusables[focusIndex].focus();
|
|
9282
|
+
e.preventDefault(); // Prevent default tab behavior
|
|
9283
|
+
e.stopPropagation(); // Stop the event from bubbling up
|
|
9284
|
+
}
|
|
9285
|
+
}
|
|
9286
|
+
};
|
|
9287
|
+
|
|
9288
|
+
/**
|
|
9289
|
+
* Retrieves all focusable elements within the container in DOM order, including those in shadow DOM and slots.
|
|
9290
|
+
* Returns a unique, ordered array of elements that can receive focus.
|
|
9291
|
+
*
|
|
9292
|
+
* @returns {Array<HTMLElement>} An array of focusable elements within the container.
|
|
9293
|
+
* @private
|
|
9294
|
+
*/
|
|
9295
|
+
_getFocusableElements() {
|
|
9296
|
+
// Use the imported utility function to get focusable elements
|
|
9297
|
+
const elements = getFocusableElements(this.container);
|
|
9298
|
+
|
|
9299
|
+
// Filter out any elements with the 'focus-bookend' class
|
|
9300
|
+
return elements;
|
|
9301
|
+
}
|
|
9302
|
+
|
|
9303
|
+
/**
|
|
9304
|
+
* Moves focus to the first focusable element within the container.
|
|
9305
|
+
* Useful for setting initial focus when activating the focus trap.
|
|
9306
|
+
*/
|
|
9307
|
+
focusFirstElement() {
|
|
9308
|
+
const focusables = this._getFocusableElements();
|
|
9309
|
+
if (focusables.length) focusables[0].focus();
|
|
9310
|
+
}
|
|
9311
|
+
|
|
9312
|
+
/**
|
|
9313
|
+
* Moves focus to the last focusable element within the container.
|
|
9314
|
+
* Useful for setting focus when deactivating or cycling focus in reverse.
|
|
9315
|
+
*/
|
|
9316
|
+
focusLastElement() {
|
|
9317
|
+
const focusables = this._getFocusableElements();
|
|
9318
|
+
if (focusables.length) focusables[focusables.length - 1].focus();
|
|
9319
|
+
}
|
|
9320
|
+
|
|
9321
|
+
/**
|
|
9322
|
+
* Removes event listeners and attributes added by the focus trap.
|
|
9323
|
+
* Call this method to clean up when the focus trap is no longer needed.
|
|
9324
|
+
*/
|
|
9325
|
+
disconnect() {
|
|
9326
|
+
|
|
9327
|
+
if (this.container.hasAttribute('data-focus-trap-container')) {
|
|
9328
|
+
this.container.removeAttribute('data-focus-trap-container');
|
|
9329
|
+
}
|
|
9330
|
+
|
|
9331
|
+
this.container.removeEventListener('keydown', this._onKeydown);
|
|
9332
|
+
}
|
|
9333
|
+
}
|
|
9334
|
+
|
|
9335
|
+
/* eslint-disable lit/no-invalid-html, lit/binding-positions, max-lines, prefer-destructuring, no-underscore-dangle, arrow-parens, no-confusing-arrow, curly, no-unused-expressions */
|
|
9077
9336
|
|
|
9078
9337
|
|
|
9079
9338
|
/**
|
|
@@ -9132,6 +9391,11 @@ class AuroCounterGroup extends AuroElement {
|
|
|
9132
9391
|
*/
|
|
9133
9392
|
this.validation = new AuroFormValidation();
|
|
9134
9393
|
|
|
9394
|
+
// Bind callback methods since we can't use arrow functions in class properties
|
|
9395
|
+
|
|
9396
|
+
/** @private */
|
|
9397
|
+
this.handleDropdownToggle = this.handleDropdownToggle.bind(this);
|
|
9398
|
+
|
|
9135
9399
|
/**
|
|
9136
9400
|
* Generate unique names for dependency components.
|
|
9137
9401
|
* @private
|
|
@@ -9309,51 +9573,6 @@ class AuroCounterGroup extends AuroElement {
|
|
|
9309
9573
|
};
|
|
9310
9574
|
}
|
|
9311
9575
|
|
|
9312
|
-
/**
|
|
9313
|
-
* Traps keyboard tab interactions within dropdown when open.
|
|
9314
|
-
* @private
|
|
9315
|
-
* @param {KeyboardEvent} event - The keyboard event.
|
|
9316
|
-
* @param {NodeList} counters - The list of counter elements.
|
|
9317
|
-
*/
|
|
9318
|
-
trapKeyboard(event, counters) {
|
|
9319
|
-
if (!this.dropdown.isPopoverVisible) {
|
|
9320
|
-
return;
|
|
9321
|
-
}
|
|
9322
|
-
|
|
9323
|
-
event.stopPropagation();
|
|
9324
|
-
event.preventDefault();
|
|
9325
|
-
|
|
9326
|
-
const firstFocusable = counters[0];
|
|
9327
|
-
const lastFocusable = counters[counters.length - 1];
|
|
9328
|
-
|
|
9329
|
-
if (event.key === 'Enter') {
|
|
9330
|
-
firstFocusable.focus();
|
|
9331
|
-
}
|
|
9332
|
-
|
|
9333
|
-
if (event.key === 'Escape') {
|
|
9334
|
-
this.dropdown.hide();
|
|
9335
|
-
}
|
|
9336
|
-
|
|
9337
|
-
if (event.key === 'Tab' && this.dropdown && event.target.offsetParent === this.dropdown.bib) {
|
|
9338
|
-
this.dropdown.noHideOnThisFocusLoss = true;
|
|
9339
|
-
|
|
9340
|
-
const currentIndex = Array.from(counters).indexOf(document.activeElement);
|
|
9341
|
-
|
|
9342
|
-
if (event.shiftKey) {
|
|
9343
|
-
if (currentIndex === 0) {
|
|
9344
|
-
lastFocusable.focus();
|
|
9345
|
-
} else {
|
|
9346
|
-
counters[currentIndex - 1].focus();
|
|
9347
|
-
}
|
|
9348
|
-
} else if (currentIndex === counters.length - 1) {
|
|
9349
|
-
firstFocusable.focus();
|
|
9350
|
-
} else {
|
|
9351
|
-
counters[currentIndex + 1].focus();
|
|
9352
|
-
}
|
|
9353
|
-
|
|
9354
|
-
}
|
|
9355
|
-
}
|
|
9356
|
-
|
|
9357
9576
|
/**
|
|
9358
9577
|
* Dynamically disables increment/decrement buttons on a counter based on group value.
|
|
9359
9578
|
* This method checks the total aggregated value against the group's min and max properties.
|
|
@@ -9387,6 +9606,52 @@ class AuroCounterGroup extends AuroElement {
|
|
|
9387
9606
|
});
|
|
9388
9607
|
}
|
|
9389
9608
|
|
|
9609
|
+
/**
|
|
9610
|
+
* Performs state updates that should happen when the dropdown is toggled.
|
|
9611
|
+
* @returns {void}
|
|
9612
|
+
* @private
|
|
9613
|
+
*/
|
|
9614
|
+
handleDropdownToggle() {
|
|
9615
|
+
|
|
9616
|
+
// Check if the dropdown is open
|
|
9617
|
+
const dropdownIsOpen = this.dropdown.isPopoverVisible;
|
|
9618
|
+
|
|
9619
|
+
// Adds and removes the focus trap based on the dropdown state
|
|
9620
|
+
this.updateFocusTrap(dropdownIsOpen);
|
|
9621
|
+
|
|
9622
|
+
// Tasks to perform if the dropdown is closed
|
|
9623
|
+
if (!dropdownIsOpen) {
|
|
9624
|
+
|
|
9625
|
+
// Shift focus to the dropdown trigger
|
|
9626
|
+
this.dropdown.trigger.focus();
|
|
9627
|
+
}
|
|
9628
|
+
}
|
|
9629
|
+
|
|
9630
|
+
/**
|
|
9631
|
+
* Updates the focus trap based on whether the dropdown is open or closed.
|
|
9632
|
+
* If the dropdown is open, it creates a new focus trap and focuses the first element
|
|
9633
|
+
* If the dropdown is closed, it disconnects the focus trap if it exists to prevent memory leaks and disable focus trapping.
|
|
9634
|
+
* @param {boolean} dropdownIsOpen - Indicates whether the dropdown is currently open.
|
|
9635
|
+
* @returns {void}
|
|
9636
|
+
* @private
|
|
9637
|
+
*/
|
|
9638
|
+
updateFocusTrap(dropdownIsOpen) {
|
|
9639
|
+
|
|
9640
|
+
// If the dropdown is open, create a focus trap and focus the first element
|
|
9641
|
+
if (dropdownIsOpen) {
|
|
9642
|
+
this.dropdownFocusTrap = new FocusTrap(this.dropdown.bibContent);
|
|
9643
|
+
this.dropdownFocusTrap.focusFirstElement();
|
|
9644
|
+
return;
|
|
9645
|
+
}
|
|
9646
|
+
|
|
9647
|
+
// Guard Clause: Ensure there is a focus trap currently active before continuing
|
|
9648
|
+
if (!this.dropdownFocusTrap) return;
|
|
9649
|
+
|
|
9650
|
+
// If the dropdown is not open, disconnect the focus trap if it exists
|
|
9651
|
+
this.dropdownFocusTrap.disconnect();
|
|
9652
|
+
this.dropdownFocusTrap = undefined;
|
|
9653
|
+
}
|
|
9654
|
+
|
|
9390
9655
|
/**
|
|
9391
9656
|
* Configures the dropdown counters by selecting all `auro-counter` elements,
|
|
9392
9657
|
* appending them to the `auro-counter-wrapper` element within the shadow DOM,
|
|
@@ -9395,28 +9660,14 @@ class AuroCounterGroup extends AuroElement {
|
|
|
9395
9660
|
*/
|
|
9396
9661
|
configureDropdownCounters() {
|
|
9397
9662
|
this.dropdown = this.shadowRoot.querySelector(this.dropdownTag._$litStatic$);
|
|
9398
|
-
this.dropdown.addEventListener('keydown', (event) => this.trapKeyboard(event, this.counters, 'dropdown'));
|
|
9399
|
-
// notify dropdown to reconfigure as the trigger text is updated
|
|
9400
9663
|
this.dropdown.requestUpdate();
|
|
9401
9664
|
|
|
9402
|
-
this.addEventListener(
|
|
9403
|
-
if (!this.dropdown.isPopoverVisible) {
|
|
9404
|
-
this.dropdown.focus();
|
|
9405
|
-
}
|
|
9406
|
-
});
|
|
9665
|
+
this.dropdown.addEventListener("auroDropdown-toggled", this.handleDropdownToggle);
|
|
9407
9666
|
|
|
9408
9667
|
const counterWrapper = this.shadowRoot.querySelector('auro-counter-wrapper');
|
|
9409
9668
|
const counterSlot = counterWrapper.querySelector('slot');
|
|
9410
9669
|
this.counters = counterSlot.assignedElements().filter(el => el.tagName.toLowerCase() === 'auro-counter' || el.hasAttribute('auro-counter'));
|
|
9411
9670
|
|
|
9412
|
-
if (this.keydownHandler) {
|
|
9413
|
-
counterWrapper.removeEventListener('keydown', this.keydownHandler);
|
|
9414
|
-
}
|
|
9415
|
-
this.keydownHandler = (keydownEvent) => {
|
|
9416
|
-
this.trapKeyboard(keydownEvent, this.counters);
|
|
9417
|
-
};
|
|
9418
|
-
counterWrapper.addEventListener('keydown', this.keydownHandler);
|
|
9419
|
-
|
|
9420
9671
|
this.counters.forEach((counter) => {
|
|
9421
9672
|
counter.addEventListener("input", () => this.updateValue());
|
|
9422
9673
|
});
|
|
@@ -9558,6 +9809,13 @@ class AuroCounterGroup extends AuroElement {
|
|
|
9558
9809
|
this.updateValueText();
|
|
9559
9810
|
}
|
|
9560
9811
|
|
|
9812
|
+
disconnectedCallback() {
|
|
9813
|
+
super.disconnectedCallback();
|
|
9814
|
+
|
|
9815
|
+
// Remove the event listener for dropdown toggling
|
|
9816
|
+
this.removeEventListener("auroDropdown-toggled", this.handleDropdownToggle);
|
|
9817
|
+
}
|
|
9818
|
+
|
|
9561
9819
|
/**
|
|
9562
9820
|
* Registers the custom element with the browser.
|
|
9563
9821
|
* @param {string} [name="auro-counter-group"] - Custom element name to register.
|
|
@@ -9576,6 +9834,7 @@ class AuroCounterGroup extends AuroElement {
|
|
|
9576
9834
|
renderCounterDropdown() {
|
|
9577
9835
|
return u`
|
|
9578
9836
|
<${this.dropdownTag}
|
|
9837
|
+
noHideOnThisFocusLoss
|
|
9579
9838
|
chevron common fluid
|
|
9580
9839
|
part="dropdown"
|
|
9581
9840
|
?autoPlacement="${this.autoPlacement}"
|