@aurodesignsystem-dev/auro-formkit 0.0.0-pr1474.4 → 0.0.0-pr1475.1
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/bibtemplate/dist/auro-bibtemplate.d.ts +7 -0
- package/components/bibtemplate/dist/index.js +9 -1
- package/components/bibtemplate/dist/registered.js +9 -1
- package/components/checkbox/demo/customize.html +2 -1
- package/components/checkbox/demo/customize.min.js +1 -1
- package/components/checkbox/demo/getting-started.min.js +1 -1
- package/components/checkbox/demo/index.min.js +1 -1
- package/components/checkbox/dist/index.js +1 -1
- package/components/checkbox/dist/registered.js +1 -1
- package/components/combobox/demo/customize.html +2 -1
- package/components/combobox/demo/customize.md +130 -106
- package/components/combobox/demo/customize.min.js +209 -16
- package/components/combobox/demo/getting-started.min.js +209 -16
- package/components/combobox/demo/index.min.js +209 -16
- package/components/combobox/dist/index.js +209 -16
- package/components/combobox/dist/registered.js +209 -16
- package/components/counter/demo/customize.min.js +208 -15
- package/components/counter/demo/index.min.js +208 -15
- package/components/counter/demo/keyboard-behavior.md +1 -0
- package/components/counter/dist/index.js +10 -2
- package/components/counter/dist/registered.js +10 -2
- package/components/datepicker/demo/accessibility.md +51 -3
- package/components/datepicker/demo/api.md +9 -0
- package/components/datepicker/demo/customize.html +2 -0
- package/components/datepicker/demo/customize.js +19 -0
- package/components/datepicker/demo/customize.md +72 -8
- package/components/datepicker/demo/customize.min.js +25690 -0
- package/components/datepicker/demo/design.md +3 -1
- package/components/datepicker/demo/index.js +2 -1
- package/components/datepicker/demo/index.md +81 -1
- package/components/datepicker/demo/index.min.js +1223 -101
- package/components/datepicker/demo/keyboard-behavior.md +201 -2
- package/components/datepicker/demo/voiceover.md +19 -12
- package/components/datepicker/dist/index.js +1155 -104
- package/components/datepicker/dist/registered.js +1155 -104
- package/components/datepicker/dist/src/auro-calendar-cell.d.ts +59 -0
- package/components/datepicker/dist/src/auro-calendar-month.d.ts +28 -0
- package/components/datepicker/dist/src/auro-calendar.d.ts +84 -0
- package/components/datepicker/dist/src/auro-datepicker.d.ts +80 -0
- package/components/datepicker/dist/src/datepickerKeyboardStrategy.d.ts +5 -3
- package/components/dropdown/demo/accessibility.md +11 -0
- package/components/dropdown/demo/api.md +1 -0
- package/components/dropdown/demo/customize.md +3 -0
- package/components/dropdown/demo/customize.min.js +198 -13
- package/components/dropdown/demo/getting-started.min.js +198 -13
- package/components/dropdown/demo/index.min.js +198 -13
- package/components/dropdown/demo/keyboard-behavior.md +1 -0
- package/components/dropdown/dist/auro-dropdown.d.ts +30 -1
- package/components/dropdown/dist/index.js +198 -13
- package/components/dropdown/dist/registered.js +198 -13
- package/components/form/demo/customize.html +6 -6
- package/components/form/demo/customize.js +0 -17
- package/components/form/demo/customize.md +51 -125
- package/components/form/demo/customize.min.js +1776 -327
- package/components/form/demo/getting-started.min.js +1776 -291
- package/components/form/demo/index.min.js +1776 -291
- package/components/form/demo/registerDemoDeps.min.js +1769 -139
- package/components/form/dist/auro-form.d.ts +5 -45
- package/components/form/dist/index.js +7 -152
- package/components/form/dist/registered.js +7 -152
- package/components/input/demo/customize.html +2 -1
- package/components/input/demo/customize.min.js +1 -1
- package/components/input/demo/getting-started.min.js +1 -1
- package/components/input/demo/index.min.js +1 -1
- package/components/input/dist/index.js +1 -1
- package/components/input/dist/registered.js +1 -1
- package/components/radio/demo/customize.min.js +2186 -0
- package/components/radio/demo/demo-support.min.js +55807 -0
- package/components/radio/demo/getting-started.js +1 -1
- package/components/radio/demo/getting-started.md +1 -1
- package/components/radio/demo/getting-started.min.js +2205 -0
- package/components/radio/demo/index.min.js +1 -1
- package/components/radio/dist/index.js +1 -1
- package/components/radio/dist/registered.js +1 -1
- package/components/select/demo/customize.html +2 -2
- package/components/select/demo/customize.min.js +208 -15
- package/components/select/demo/getting-started.min.js +208 -15
- package/components/select/demo/index.min.js +208 -15
- package/components/select/demo/keyboard-behavior.md +1 -0
- package/components/select/dist/index.js +208 -15
- package/components/select/dist/registered.js +208 -15
- package/custom-elements.json +2826 -2214
- package/package.json +2 -2
|
@@ -3338,7 +3338,7 @@ function applyKeyboardStrategy(component, strategy, options = {}) {
|
|
|
3338
3338
|
});
|
|
3339
3339
|
}
|
|
3340
3340
|
|
|
3341
|
-
var styleCss$2 = i$2`:host{position:fixed;z-index:var(--depth-tooltip, 400);display:none;isolation:isolate}:host dialog{width:auto;max-width:none;height:auto;max-height:none;padding:0;border:none;margin:0;outline:none;transform:translateZ(0)}:host dialog::backdrop{background:transparent}:host(:not([isfullscreen])) dialog{position:relative;inset:unset}:host(:not([isfullscreen])) .container.shape-box{border-radius:unset}:host(:not([isfullscreen])) .container[class*=shape-pill],:host(:not([isfullscreen])) .container[class*=shape-snowflake]{border-radius:30px}:host(:not([isfullscreen])) .container[class*=shape-rounded]{border-radius:16px}:host(:not([matchWidth])) .container{min-width:fit-content}:host([isfullscreen]){position:fixed;top:0;left:0}:host([isfullscreen]) .container{width:100dvw;max-width:none;height:100dvh;max-height:none;border-radius:unset;margin-top:0;box-shadow:unset;overscroll-behavior:contain}:host([isfullscreen]) .container::backdrop{background:var(--ds-color-background-primary, #fff)}:host(:popover-open){position:fixed;overflow:visible;padding:0;border:none;margin:0;background:transparent;inset:unset;outline:none}:host([data-show]){display:flex}:host([common]:not([isfullscreen])) .container,:host([rounded]:not([isfullscreen])) .container{border-radius:var(--ds-border-radius, 0.375rem)}:host([common][isfullscreen]) .container,:host([rounded][isfullscreen]) .container{border-radius:unset;box-shadow:unset}.container{display:inline-block;overflow:auto;box-sizing:border-box;border-radius:var(--ds-border-radius, 0.375rem);margin:var(--ds-size-50, 0.25rem) 0}.util_displayHiddenVisually{position:absolute;overflow:hidden;width:1px;height:1px;padding:0;border:0;margin:-1px;clip-path:inset(50%);white-space:nowrap}`;
|
|
3341
|
+
var styleCss$2 = i$2`:host{position:fixed;z-index:var(--depth-tooltip, 400);display:none;isolation:isolate}:host dialog{width:auto;max-width:none;height:auto;max-height:none;padding:0;border:none;margin:0;outline:none;transform:translateZ(0)}:host dialog::backdrop{background:transparent}:host(:not([isfullscreen])) dialog{position:relative;inset:unset}:host(:not([isfullscreen])) .container.shape-box{border-radius:unset}:host(:not([isfullscreen])) .container[class*=shape-pill],:host(:not([isfullscreen])) .container[class*=shape-snowflake]{border-radius:30px}:host(:not([isfullscreen])) .container[class*=shape-rounded]{border-radius:16px}:host([desktopmodal]:popover-open)::backdrop{background:transparent}:host(:not([matchWidth])) .container{min-width:fit-content}:host([isfullscreen]){position:fixed;top:0;left:0}:host([isfullscreen]) .container{width:100dvw;max-width:none;height:100dvh;max-height:none;border-radius:unset;margin-top:0;box-shadow:unset;overscroll-behavior:contain}:host([isfullscreen]) .container::backdrop{background:var(--ds-color-background-primary, #fff)}:host(:popover-open){position:fixed;overflow:visible;padding:0;border:none;margin:0;background:transparent;inset:unset;outline:none}:host([data-show]){display:flex}:host([common]:not([isfullscreen])) .container,:host([rounded]:not([isfullscreen])) .container{border-radius:var(--ds-border-radius, 0.375rem)}:host([common][isfullscreen]) .container,:host([rounded][isfullscreen]) .container{border-radius:unset;box-shadow:unset}.container{display:inline-block;overflow:auto;box-sizing:border-box;border-radius:var(--ds-border-radius, 0.375rem);margin:var(--ds-size-50, 0.25rem) 0}.util_displayHiddenVisually{position:absolute;overflow:hidden;width:1px;height:1px;padding:0;border:0;margin:-1px;clip-path:inset(50%);white-space:nowrap}`;
|
|
3342
3342
|
|
|
3343
3343
|
var colorCss$2 = i$2`.container{background-color:var(--ds-auro-dropdownbib-container-color);box-shadow:var(--ds-auro-dropdownbib-boxshadow-color);color:var(--ds-auro-dropdownbib-text-color)}`;
|
|
3344
3344
|
|
|
@@ -3969,7 +3969,7 @@ class AuroHelpText extends i {
|
|
|
3969
3969
|
}
|
|
3970
3970
|
}
|
|
3971
3971
|
|
|
3972
|
-
var formkitVersion = '
|
|
3972
|
+
var formkitVersion = '202605182202';
|
|
3973
3973
|
|
|
3974
3974
|
class AuroElement extends i {
|
|
3975
3975
|
static get properties() {
|
|
@@ -4149,6 +4149,7 @@ class AuroDropdown extends AuroElement {
|
|
|
4149
4149
|
_intializeDefaults() {
|
|
4150
4150
|
this.appearance = 'default';
|
|
4151
4151
|
this.chevron = false;
|
|
4152
|
+
this.desktopModal = false;
|
|
4152
4153
|
this.disabled = false;
|
|
4153
4154
|
this.disableKeyboardHandling = false;
|
|
4154
4155
|
this.error = false;
|
|
@@ -4329,6 +4330,14 @@ class AuroDropdown extends AuroElement {
|
|
|
4329
4330
|
reflect: true
|
|
4330
4331
|
},
|
|
4331
4332
|
|
|
4333
|
+
/**
|
|
4334
|
+
* If declared, the dropdown will behave as a modal dialog when in a desktop viewport size.
|
|
4335
|
+
*/
|
|
4336
|
+
desktopModal: {
|
|
4337
|
+
type: Boolean,
|
|
4338
|
+
reflect: true
|
|
4339
|
+
},
|
|
4340
|
+
|
|
4332
4341
|
/**
|
|
4333
4342
|
* If declared, the dropdown will only show by calling the API .show() public method.
|
|
4334
4343
|
*/
|
|
@@ -4616,6 +4625,15 @@ class AuroDropdown extends AuroElement {
|
|
|
4616
4625
|
|
|
4617
4626
|
disconnectedCallback() {
|
|
4618
4627
|
super.disconnectedCallback();
|
|
4628
|
+
this._clearPageInert();
|
|
4629
|
+
if (this._bibTabHandler) {
|
|
4630
|
+
this.removeEventListener('keydown', this._bibTabHandler);
|
|
4631
|
+
this._bibTabHandler = undefined;
|
|
4632
|
+
}
|
|
4633
|
+
if (this.focusTrap) {
|
|
4634
|
+
this.focusTrap.disconnect();
|
|
4635
|
+
this.focusTrap = undefined;
|
|
4636
|
+
}
|
|
4619
4637
|
if (this.floater) {
|
|
4620
4638
|
this.floater.hideBib('disconnect');
|
|
4621
4639
|
this.floater.disconnect();
|
|
@@ -4643,19 +4661,34 @@ class AuroDropdown extends AuroElement {
|
|
|
4643
4661
|
if (this.isPopoverVisible) {
|
|
4644
4662
|
// Fullscreen: use showModal() for native accessibility (inert outside, focus trap)
|
|
4645
4663
|
// Desktop: use show() for Floating UI positioning + FocusTrap for focus management
|
|
4646
|
-
|
|
4647
|
-
this.
|
|
4664
|
+
this.bibElement.value.open(this.isBibFullscreen);
|
|
4665
|
+
this.updateFocusTrap();
|
|
4666
|
+
|
|
4667
|
+
// Desktop modal: make siblings inert so content outside is not interactive
|
|
4668
|
+
if (this.desktopModal && !this.isBibFullscreen) {
|
|
4669
|
+
this._setPageInert();
|
|
4670
|
+
}
|
|
4648
4671
|
} else {
|
|
4649
4672
|
this.bibElement.value.close();
|
|
4673
|
+
this._clearPageInert();
|
|
4650
4674
|
}
|
|
4651
4675
|
}
|
|
4652
4676
|
|
|
4653
4677
|
// When fullscreen strategy changes while open, re-open dialog with correct mode
|
|
4654
4678
|
// (e.g. resizing from desktop → mobile while dropdown is open)
|
|
4655
4679
|
if (changedProperties.has('isBibFullscreen') && this.isPopoverVisible && this.bibElement.value) {
|
|
4656
|
-
const useModal = this.isBibFullscreen;
|
|
4657
4680
|
this.bibElement.value.close();
|
|
4658
|
-
this.bibElement.value.open(
|
|
4681
|
+
this.bibElement.value.open(this.isBibFullscreen);
|
|
4682
|
+
|
|
4683
|
+
// Re-initialize focus management for the new strategy
|
|
4684
|
+
this.updateFocusTrap();
|
|
4685
|
+
|
|
4686
|
+
// Toggle inert: desktop modal needs it, fullscreen showModal() handles it natively
|
|
4687
|
+
if (this.desktopModal && !this.isBibFullscreen) {
|
|
4688
|
+
this._setPageInert();
|
|
4689
|
+
} else {
|
|
4690
|
+
this._clearPageInert();
|
|
4691
|
+
}
|
|
4659
4692
|
}
|
|
4660
4693
|
}
|
|
4661
4694
|
|
|
@@ -4665,8 +4698,14 @@ class AuroDropdown extends AuroElement {
|
|
|
4665
4698
|
* @param {CustomEvent} event - The custom event that contains the dropdown toggle information.
|
|
4666
4699
|
*/
|
|
4667
4700
|
handleDropdownToggle(event) {
|
|
4668
|
-
this.updateFocusTrap();
|
|
4669
4701
|
this.isPopoverVisible = event.detail.expanded;
|
|
4702
|
+
|
|
4703
|
+
// Tear down FocusTrap when closing. Creation happens in updated()
|
|
4704
|
+
// after the dialog is open so getFocusableElements can find content.
|
|
4705
|
+
if (!this.isPopoverVisible) {
|
|
4706
|
+
this.updateFocusTrap();
|
|
4707
|
+
}
|
|
4708
|
+
|
|
4670
4709
|
const eventType = event.detail.eventType || "unknown";
|
|
4671
4710
|
if (!this.isPopoverVisible && this.hasFocus && eventType === "keydown") {
|
|
4672
4711
|
this.trigger.focus();
|
|
@@ -4765,19 +4804,164 @@ class AuroDropdown extends AuroElement {
|
|
|
4765
4804
|
* @private
|
|
4766
4805
|
*/
|
|
4767
4806
|
updateFocusTrap() {
|
|
4807
|
+
// Always clean up existing handlers/traps before setting up new ones
|
|
4808
|
+
// to prevent duplicate listeners on repeated calls.
|
|
4809
|
+
if (this._bibTabHandler) {
|
|
4810
|
+
this.removeEventListener('keydown', this._bibTabHandler);
|
|
4811
|
+
this._bibTabHandler = undefined;
|
|
4812
|
+
}
|
|
4813
|
+
|
|
4814
|
+
if (this.focusTrap) {
|
|
4815
|
+
this.focusTrap.disconnect();
|
|
4816
|
+
this.focusTrap = undefined;
|
|
4817
|
+
}
|
|
4818
|
+
|
|
4768
4819
|
if (this.isPopoverVisible) {
|
|
4769
4820
|
if (!this.isBibFullscreen) {
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4821
|
+
if (this.desktopModal) {
|
|
4822
|
+
// Desktop modal: trap focus only within the bib content.
|
|
4823
|
+
// Can't use FocusTrap on the bib element because keydown events
|
|
4824
|
+
// from slotted content bubble through the dropdown host (light DOM),
|
|
4825
|
+
// not through the bib (shadow projection target). Using FocusTrap
|
|
4826
|
+
// on the dropdown would include the trigger in the tab cycle.
|
|
4827
|
+
// Instead, listen for Tab on the dropdown and manually wrap focus
|
|
4828
|
+
// within the bib's focusable elements.
|
|
4829
|
+
this._bibTabHandler = (event) => {
|
|
4830
|
+
if (event.key !== 'Tab') {
|
|
4831
|
+
return;
|
|
4832
|
+
}
|
|
4833
|
+
|
|
4834
|
+
// Collect focusable elements from the bib content.
|
|
4835
|
+
const focusables = getFocusableElements(this.bibContent);
|
|
4836
|
+
|
|
4837
|
+
// Fallback: try from slotted content directly
|
|
4838
|
+
if (!focusables.length) {
|
|
4839
|
+
const slot = this.shadowRoot.querySelector('.slotContent slot');
|
|
4840
|
+
const assignedNodes = slot ? slot.assignedNodes({ flatten: true }) : [];
|
|
4841
|
+
|
|
4842
|
+
for (const node of assignedNodes) {
|
|
4843
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
4844
|
+
focusables.push(...getFocusableElements(node));
|
|
4845
|
+
}
|
|
4846
|
+
}
|
|
4847
|
+
}
|
|
4848
|
+
|
|
4849
|
+
if (!focusables.length) {
|
|
4850
|
+
return;
|
|
4851
|
+
}
|
|
4852
|
+
|
|
4853
|
+
event.preventDefault();
|
|
4854
|
+
|
|
4855
|
+
const direction = event.shiftKey ? -1 : 1; // eslint-disable-line no-magic-numbers
|
|
4856
|
+
|
|
4857
|
+
// Walk the active element chain through shadow roots
|
|
4858
|
+
const actives = this._getActiveElements();
|
|
4859
|
+
|
|
4860
|
+
let idx = focusables.findIndex((el) => actives.includes(el));
|
|
4861
|
+
|
|
4862
|
+
if (idx === -1) { // eslint-disable-line no-magic-numbers
|
|
4863
|
+
// Focus is not on a known element — move to first/last
|
|
4864
|
+
idx = direction === 1 ? -1 : focusables.length; // eslint-disable-line no-magic-numbers
|
|
4865
|
+
}
|
|
4866
|
+
|
|
4867
|
+
// Try each element in order, skipping any that can't receive focus
|
|
4868
|
+
// (e.g. hidden elements, elements in collapsed sections)
|
|
4869
|
+
for (let index = 0; index < focusables.length; index++) { // eslint-disable-line no-plusplus
|
|
4870
|
+
let nextIdx = idx + direction;
|
|
4871
|
+
|
|
4872
|
+
// Wrap around
|
|
4873
|
+
if (nextIdx < 0) {
|
|
4874
|
+
nextIdx = focusables.length - 1;
|
|
4875
|
+
} else if (nextIdx >= focusables.length) {
|
|
4876
|
+
nextIdx = 0;
|
|
4877
|
+
}
|
|
4878
|
+
|
|
4879
|
+
focusables[nextIdx].focus();
|
|
4880
|
+
|
|
4881
|
+
// Verify focus actually moved to the target
|
|
4882
|
+
const newActives = this._getActiveElements();
|
|
4883
|
+
|
|
4884
|
+
if (newActives.includes(focusables[nextIdx])) {
|
|
4885
|
+
return;
|
|
4886
|
+
}
|
|
4887
|
+
|
|
4888
|
+
// Focus didn't stick — skip this element and try the next
|
|
4889
|
+
idx = nextIdx;
|
|
4890
|
+
}
|
|
4891
|
+
};
|
|
4892
|
+
this.addEventListener('keydown', this._bibTabHandler);
|
|
4893
|
+
} else {
|
|
4894
|
+
// Normal desktop: use FocusTrap on the bib element
|
|
4895
|
+
this.focusTrap = new FocusTrap(this.bibContent);
|
|
4896
|
+
this.focusTrap.focusFirstElement();
|
|
4897
|
+
}
|
|
4773
4898
|
}
|
|
4774
4899
|
// Fullscreen: showModal() provides native focus trapping
|
|
4900
|
+
}
|
|
4901
|
+
}
|
|
4902
|
+
|
|
4903
|
+
/**
|
|
4904
|
+
* Returns the chain of active (focused) elements through shadow roots.
|
|
4905
|
+
* @private
|
|
4906
|
+
* @returns {Array<HTMLElement>}
|
|
4907
|
+
*/
|
|
4908
|
+
_getActiveElements() {
|
|
4909
|
+
let { activeElement } = document;
|
|
4910
|
+
const actives = [activeElement];
|
|
4911
|
+
|
|
4912
|
+
while (activeElement?.shadowRoot?.activeElement) {
|
|
4913
|
+
activeElement = activeElement.shadowRoot.activeElement;
|
|
4914
|
+
actives.push(activeElement);
|
|
4915
|
+
}
|
|
4916
|
+
|
|
4917
|
+
return actives;
|
|
4918
|
+
}
|
|
4919
|
+
|
|
4920
|
+
/**
|
|
4921
|
+
* Sets `inert` on sibling elements of the dropdown's top-level host
|
|
4922
|
+
* so that content outside the dropdown is not interactive while the modal is open.
|
|
4923
|
+
* Walks up through shadow DOM boundaries to find the outermost host element
|
|
4924
|
+
* in the light DOM, then sets `inert` on that element's siblings.
|
|
4925
|
+
* @private
|
|
4926
|
+
*/
|
|
4927
|
+
_setPageInert() {
|
|
4928
|
+
if (this._inertSiblings) {
|
|
4775
4929
|
return;
|
|
4776
4930
|
}
|
|
4777
4931
|
|
|
4778
|
-
|
|
4779
|
-
|
|
4780
|
-
|
|
4932
|
+
this._inertSiblings = [];
|
|
4933
|
+
|
|
4934
|
+
// Walk up through shadow DOM boundaries to find the topmost host
|
|
4935
|
+
// element in the light DOM. For example, if this dropdown is inside
|
|
4936
|
+
// auro-datepicker's shadow DOM, we walk up to the datepicker element
|
|
4937
|
+
// so we set inert on its siblings — not on the datepicker itself.
|
|
4938
|
+
let host = this;
|
|
4939
|
+
while (host.getRootNode() instanceof ShadowRoot) {
|
|
4940
|
+
host = host.getRootNode().host;
|
|
4941
|
+
}
|
|
4942
|
+
|
|
4943
|
+
const parent = host.parentElement;
|
|
4944
|
+
|
|
4945
|
+
if (parent) {
|
|
4946
|
+
for (const sibling of parent.children) {
|
|
4947
|
+
if (sibling !== host && !sibling.inert) {
|
|
4948
|
+
sibling.inert = true;
|
|
4949
|
+
this._inertSiblings.push(sibling);
|
|
4950
|
+
}
|
|
4951
|
+
}
|
|
4952
|
+
}
|
|
4953
|
+
}
|
|
4954
|
+
|
|
4955
|
+
/**
|
|
4956
|
+
* Restores `inert` state on siblings that were made inert by `_setPageInert`.
|
|
4957
|
+
* @private
|
|
4958
|
+
*/
|
|
4959
|
+
_clearPageInert() {
|
|
4960
|
+
if (this._inertSiblings) {
|
|
4961
|
+
for (const sibling of this._inertSiblings) {
|
|
4962
|
+
sibling.inert = false;
|
|
4963
|
+
}
|
|
4964
|
+
this._inertSiblings = undefined;
|
|
4781
4965
|
}
|
|
4782
4966
|
}
|
|
4783
4967
|
|
|
@@ -5016,6 +5200,7 @@ class AuroDropdown extends AuroElement {
|
|
|
5016
5200
|
shape="${this.shape}"
|
|
5017
5201
|
?data-show="${this.isPopoverVisible}"
|
|
5018
5202
|
?isfullscreen="${this.isBibFullscreen}"
|
|
5203
|
+
?desktopmodal="${this.desktopModal}"
|
|
5019
5204
|
.dialogLabel="${this.bibDialogLabel}"
|
|
5020
5205
|
${n$2(this.bibElement)}
|
|
5021
5206
|
>
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
<p>The trigger is a focusable element and participates in the standard tab order, responding to <code>Tab</code> and <code>Shift+Tab</code> key events per <auro-hyperlink href="https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/tabindex">native browser behavior</auro-hyperlink>, i.e., these keys step through the browser tabindex sequence.</p>
|
|
6
6
|
<p>When the component is <code>disabled</code> it is removed from the <code>tabindex</code> sequence. VoiceOver's virtual cursor <em>(swipe navigation)</em> can still encounter the component, but standard keyboard <code>Tab</code> navigation skips it.</p>
|
|
7
7
|
<p>When the bib is collapsed, the bib content is excluded from the tab sequence. When <strong>expanded</strong>, focusable elements within the bib content are included in the natural tab order. In fullscreen mode, focus is trapped within the bib, and the tab sequence cycles through the bib content focusable elements until the bib is closed or the viewport no longer meets the fullscreen condition and is rendered as a popover.</p>
|
|
8
|
+
<p>When the <code>desktopModal</code> attribute is set, focus is also trapped within the bib on desktop viewports. All sibling elements on the page are marked <code>inert</code>, preventing interaction with content outside the dropdown until it is closed.</p>
|
|
8
9
|
<!-- AURO-GENERATED-CONTENT:END -->
|
|
9
10
|
<auro-header level="3" id="keyEvents">Key Events</auro-header>
|
|
10
11
|
<!-- AURO-GENERATED-CONTENT:START (FILE:src=./../docs/partials/keyEvents.md) -->
|
|
@@ -44,6 +44,13 @@ export class AuroDropdown extends AuroElement {
|
|
|
44
44
|
type: BooleanConstructor;
|
|
45
45
|
reflect: boolean;
|
|
46
46
|
};
|
|
47
|
+
/**
|
|
48
|
+
* If declared, the dropdown will behave as a modal dialog when in a desktop viewport size.
|
|
49
|
+
*/
|
|
50
|
+
desktopModal: {
|
|
51
|
+
type: BooleanConstructor;
|
|
52
|
+
reflect: boolean;
|
|
53
|
+
};
|
|
47
54
|
/**
|
|
48
55
|
* If declared, the dropdown will only show by calling the API .show() public method.
|
|
49
56
|
*/
|
|
@@ -285,6 +292,7 @@ export class AuroDropdown extends AuroElement {
|
|
|
285
292
|
private _intializeDefaults;
|
|
286
293
|
appearance: string | undefined;
|
|
287
294
|
chevron: boolean | undefined;
|
|
295
|
+
desktopModal: boolean | undefined;
|
|
288
296
|
disabled: boolean | undefined;
|
|
289
297
|
disableKeyboardHandling: boolean | undefined;
|
|
290
298
|
error: boolean | undefined;
|
|
@@ -373,6 +381,8 @@ export class AuroDropdown extends AuroElement {
|
|
|
373
381
|
* @returns {string}
|
|
374
382
|
*/
|
|
375
383
|
private get focusableEntityQuery();
|
|
384
|
+
_bibTabHandler: ((event: any) => void) | undefined;
|
|
385
|
+
focusTrap: any;
|
|
376
386
|
updated(changedProperties: any): void;
|
|
377
387
|
firstUpdated(): void;
|
|
378
388
|
dropdownId: any;
|
|
@@ -400,7 +410,26 @@ export class AuroDropdown extends AuroElement {
|
|
|
400
410
|
* @private
|
|
401
411
|
*/
|
|
402
412
|
private updateFocusTrap;
|
|
403
|
-
|
|
413
|
+
/**
|
|
414
|
+
* Returns the chain of active (focused) elements through shadow roots.
|
|
415
|
+
* @private
|
|
416
|
+
* @returns {Array<HTMLElement>}
|
|
417
|
+
*/
|
|
418
|
+
private _getActiveElements;
|
|
419
|
+
/**
|
|
420
|
+
* Sets `inert` on sibling elements of the dropdown's top-level host
|
|
421
|
+
* so that content outside the dropdown is not interactive while the modal is open.
|
|
422
|
+
* Walks up through shadow DOM boundaries to find the outermost host element
|
|
423
|
+
* in the light DOM, then sets `inert` on that element's siblings.
|
|
424
|
+
* @private
|
|
425
|
+
*/
|
|
426
|
+
private _setPageInert;
|
|
427
|
+
_inertSiblings: any[] | undefined;
|
|
428
|
+
/**
|
|
429
|
+
* Restores `inert` state on siblings that were made inert by `_setPageInert`.
|
|
430
|
+
* @private
|
|
431
|
+
*/
|
|
432
|
+
private _clearPageInert;
|
|
404
433
|
/**
|
|
405
434
|
* Function to support @focusout event.
|
|
406
435
|
* @private
|
|
@@ -3243,7 +3243,7 @@ function applyKeyboardStrategy(component, strategy, options = {}) {
|
|
|
3243
3243
|
});
|
|
3244
3244
|
}
|
|
3245
3245
|
|
|
3246
|
-
var styleCss$2 = css`:host{position:fixed;z-index:var(--depth-tooltip, 400);display:none;isolation:isolate}:host dialog{width:auto;max-width:none;height:auto;max-height:none;padding:0;border:none;margin:0;outline:none;transform:translateZ(0)}:host dialog::backdrop{background:transparent}:host(:not([isfullscreen])) dialog{position:relative;inset:unset}:host(:not([isfullscreen])) .container.shape-box{border-radius:unset}:host(:not([isfullscreen])) .container[class*=shape-pill],:host(:not([isfullscreen])) .container[class*=shape-snowflake]{border-radius:30px}:host(:not([isfullscreen])) .container[class*=shape-rounded]{border-radius:16px}:host(:not([matchWidth])) .container{min-width:fit-content}:host([isfullscreen]){position:fixed;top:0;left:0}:host([isfullscreen]) .container{width:100dvw;max-width:none;height:100dvh;max-height:none;border-radius:unset;margin-top:0;box-shadow:unset;overscroll-behavior:contain}:host([isfullscreen]) .container::backdrop{background:var(--ds-color-background-primary, #fff)}:host(:popover-open){position:fixed;overflow:visible;padding:0;border:none;margin:0;background:transparent;inset:unset;outline:none}:host([data-show]){display:flex}:host([common]:not([isfullscreen])) .container,:host([rounded]:not([isfullscreen])) .container{border-radius:var(--ds-border-radius, 0.375rem)}:host([common][isfullscreen]) .container,:host([rounded][isfullscreen]) .container{border-radius:unset;box-shadow:unset}.container{display:inline-block;overflow:auto;box-sizing:border-box;border-radius:var(--ds-border-radius, 0.375rem);margin:var(--ds-size-50, 0.25rem) 0}.util_displayHiddenVisually{position:absolute;overflow:hidden;width:1px;height:1px;padding:0;border:0;margin:-1px;clip-path:inset(50%);white-space:nowrap}`;
|
|
3246
|
+
var styleCss$2 = css`:host{position:fixed;z-index:var(--depth-tooltip, 400);display:none;isolation:isolate}:host dialog{width:auto;max-width:none;height:auto;max-height:none;padding:0;border:none;margin:0;outline:none;transform:translateZ(0)}:host dialog::backdrop{background:transparent}:host(:not([isfullscreen])) dialog{position:relative;inset:unset}:host(:not([isfullscreen])) .container.shape-box{border-radius:unset}:host(:not([isfullscreen])) .container[class*=shape-pill],:host(:not([isfullscreen])) .container[class*=shape-snowflake]{border-radius:30px}:host(:not([isfullscreen])) .container[class*=shape-rounded]{border-radius:16px}:host([desktopmodal]:popover-open)::backdrop{background:transparent}:host(:not([matchWidth])) .container{min-width:fit-content}:host([isfullscreen]){position:fixed;top:0;left:0}:host([isfullscreen]) .container{width:100dvw;max-width:none;height:100dvh;max-height:none;border-radius:unset;margin-top:0;box-shadow:unset;overscroll-behavior:contain}:host([isfullscreen]) .container::backdrop{background:var(--ds-color-background-primary, #fff)}:host(:popover-open){position:fixed;overflow:visible;padding:0;border:none;margin:0;background:transparent;inset:unset;outline:none}:host([data-show]){display:flex}:host([common]:not([isfullscreen])) .container,:host([rounded]:not([isfullscreen])) .container{border-radius:var(--ds-border-radius, 0.375rem)}:host([common][isfullscreen]) .container,:host([rounded][isfullscreen]) .container{border-radius:unset;box-shadow:unset}.container{display:inline-block;overflow:auto;box-sizing:border-box;border-radius:var(--ds-border-radius, 0.375rem);margin:var(--ds-size-50, 0.25rem) 0}.util_displayHiddenVisually{position:absolute;overflow:hidden;width:1px;height:1px;padding:0;border:0;margin:-1px;clip-path:inset(50%);white-space:nowrap}`;
|
|
3247
3247
|
|
|
3248
3248
|
var colorCss$2 = css`.container{background-color:var(--ds-auro-dropdownbib-container-color);box-shadow:var(--ds-auro-dropdownbib-boxshadow-color);color:var(--ds-auro-dropdownbib-text-color)}`;
|
|
3249
3249
|
|
|
@@ -3874,7 +3874,7 @@ class AuroHelpText extends LitElement {
|
|
|
3874
3874
|
}
|
|
3875
3875
|
}
|
|
3876
3876
|
|
|
3877
|
-
var formkitVersion = '
|
|
3877
|
+
var formkitVersion = '202605182202';
|
|
3878
3878
|
|
|
3879
3879
|
class AuroElement extends LitElement {
|
|
3880
3880
|
static get properties() {
|
|
@@ -4054,6 +4054,7 @@ class AuroDropdown extends AuroElement {
|
|
|
4054
4054
|
_intializeDefaults() {
|
|
4055
4055
|
this.appearance = 'default';
|
|
4056
4056
|
this.chevron = false;
|
|
4057
|
+
this.desktopModal = false;
|
|
4057
4058
|
this.disabled = false;
|
|
4058
4059
|
this.disableKeyboardHandling = false;
|
|
4059
4060
|
this.error = false;
|
|
@@ -4234,6 +4235,14 @@ class AuroDropdown extends AuroElement {
|
|
|
4234
4235
|
reflect: true
|
|
4235
4236
|
},
|
|
4236
4237
|
|
|
4238
|
+
/**
|
|
4239
|
+
* If declared, the dropdown will behave as a modal dialog when in a desktop viewport size.
|
|
4240
|
+
*/
|
|
4241
|
+
desktopModal: {
|
|
4242
|
+
type: Boolean,
|
|
4243
|
+
reflect: true
|
|
4244
|
+
},
|
|
4245
|
+
|
|
4237
4246
|
/**
|
|
4238
4247
|
* If declared, the dropdown will only show by calling the API .show() public method.
|
|
4239
4248
|
*/
|
|
@@ -4521,6 +4530,15 @@ class AuroDropdown extends AuroElement {
|
|
|
4521
4530
|
|
|
4522
4531
|
disconnectedCallback() {
|
|
4523
4532
|
super.disconnectedCallback();
|
|
4533
|
+
this._clearPageInert();
|
|
4534
|
+
if (this._bibTabHandler) {
|
|
4535
|
+
this.removeEventListener('keydown', this._bibTabHandler);
|
|
4536
|
+
this._bibTabHandler = undefined;
|
|
4537
|
+
}
|
|
4538
|
+
if (this.focusTrap) {
|
|
4539
|
+
this.focusTrap.disconnect();
|
|
4540
|
+
this.focusTrap = undefined;
|
|
4541
|
+
}
|
|
4524
4542
|
if (this.floater) {
|
|
4525
4543
|
this.floater.hideBib('disconnect');
|
|
4526
4544
|
this.floater.disconnect();
|
|
@@ -4548,19 +4566,34 @@ class AuroDropdown extends AuroElement {
|
|
|
4548
4566
|
if (this.isPopoverVisible) {
|
|
4549
4567
|
// Fullscreen: use showModal() for native accessibility (inert outside, focus trap)
|
|
4550
4568
|
// Desktop: use show() for Floating UI positioning + FocusTrap for focus management
|
|
4551
|
-
|
|
4552
|
-
this.
|
|
4569
|
+
this.bibElement.value.open(this.isBibFullscreen);
|
|
4570
|
+
this.updateFocusTrap();
|
|
4571
|
+
|
|
4572
|
+
// Desktop modal: make siblings inert so content outside is not interactive
|
|
4573
|
+
if (this.desktopModal && !this.isBibFullscreen) {
|
|
4574
|
+
this._setPageInert();
|
|
4575
|
+
}
|
|
4553
4576
|
} else {
|
|
4554
4577
|
this.bibElement.value.close();
|
|
4578
|
+
this._clearPageInert();
|
|
4555
4579
|
}
|
|
4556
4580
|
}
|
|
4557
4581
|
|
|
4558
4582
|
// When fullscreen strategy changes while open, re-open dialog with correct mode
|
|
4559
4583
|
// (e.g. resizing from desktop → mobile while dropdown is open)
|
|
4560
4584
|
if (changedProperties.has('isBibFullscreen') && this.isPopoverVisible && this.bibElement.value) {
|
|
4561
|
-
const useModal = this.isBibFullscreen;
|
|
4562
4585
|
this.bibElement.value.close();
|
|
4563
|
-
this.bibElement.value.open(
|
|
4586
|
+
this.bibElement.value.open(this.isBibFullscreen);
|
|
4587
|
+
|
|
4588
|
+
// Re-initialize focus management for the new strategy
|
|
4589
|
+
this.updateFocusTrap();
|
|
4590
|
+
|
|
4591
|
+
// Toggle inert: desktop modal needs it, fullscreen showModal() handles it natively
|
|
4592
|
+
if (this.desktopModal && !this.isBibFullscreen) {
|
|
4593
|
+
this._setPageInert();
|
|
4594
|
+
} else {
|
|
4595
|
+
this._clearPageInert();
|
|
4596
|
+
}
|
|
4564
4597
|
}
|
|
4565
4598
|
}
|
|
4566
4599
|
|
|
@@ -4570,8 +4603,14 @@ class AuroDropdown extends AuroElement {
|
|
|
4570
4603
|
* @param {CustomEvent} event - The custom event that contains the dropdown toggle information.
|
|
4571
4604
|
*/
|
|
4572
4605
|
handleDropdownToggle(event) {
|
|
4573
|
-
this.updateFocusTrap();
|
|
4574
4606
|
this.isPopoverVisible = event.detail.expanded;
|
|
4607
|
+
|
|
4608
|
+
// Tear down FocusTrap when closing. Creation happens in updated()
|
|
4609
|
+
// after the dialog is open so getFocusableElements can find content.
|
|
4610
|
+
if (!this.isPopoverVisible) {
|
|
4611
|
+
this.updateFocusTrap();
|
|
4612
|
+
}
|
|
4613
|
+
|
|
4575
4614
|
const eventType = event.detail.eventType || "unknown";
|
|
4576
4615
|
if (!this.isPopoverVisible && this.hasFocus && eventType === "keydown") {
|
|
4577
4616
|
this.trigger.focus();
|
|
@@ -4670,19 +4709,164 @@ class AuroDropdown extends AuroElement {
|
|
|
4670
4709
|
* @private
|
|
4671
4710
|
*/
|
|
4672
4711
|
updateFocusTrap() {
|
|
4712
|
+
// Always clean up existing handlers/traps before setting up new ones
|
|
4713
|
+
// to prevent duplicate listeners on repeated calls.
|
|
4714
|
+
if (this._bibTabHandler) {
|
|
4715
|
+
this.removeEventListener('keydown', this._bibTabHandler);
|
|
4716
|
+
this._bibTabHandler = undefined;
|
|
4717
|
+
}
|
|
4718
|
+
|
|
4719
|
+
if (this.focusTrap) {
|
|
4720
|
+
this.focusTrap.disconnect();
|
|
4721
|
+
this.focusTrap = undefined;
|
|
4722
|
+
}
|
|
4723
|
+
|
|
4673
4724
|
if (this.isPopoverVisible) {
|
|
4674
4725
|
if (!this.isBibFullscreen) {
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4726
|
+
if (this.desktopModal) {
|
|
4727
|
+
// Desktop modal: trap focus only within the bib content.
|
|
4728
|
+
// Can't use FocusTrap on the bib element because keydown events
|
|
4729
|
+
// from slotted content bubble through the dropdown host (light DOM),
|
|
4730
|
+
// not through the bib (shadow projection target). Using FocusTrap
|
|
4731
|
+
// on the dropdown would include the trigger in the tab cycle.
|
|
4732
|
+
// Instead, listen for Tab on the dropdown and manually wrap focus
|
|
4733
|
+
// within the bib's focusable elements.
|
|
4734
|
+
this._bibTabHandler = (event) => {
|
|
4735
|
+
if (event.key !== 'Tab') {
|
|
4736
|
+
return;
|
|
4737
|
+
}
|
|
4738
|
+
|
|
4739
|
+
// Collect focusable elements from the bib content.
|
|
4740
|
+
const focusables = getFocusableElements(this.bibContent);
|
|
4741
|
+
|
|
4742
|
+
// Fallback: try from slotted content directly
|
|
4743
|
+
if (!focusables.length) {
|
|
4744
|
+
const slot = this.shadowRoot.querySelector('.slotContent slot');
|
|
4745
|
+
const assignedNodes = slot ? slot.assignedNodes({ flatten: true }) : [];
|
|
4746
|
+
|
|
4747
|
+
for (const node of assignedNodes) {
|
|
4748
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
4749
|
+
focusables.push(...getFocusableElements(node));
|
|
4750
|
+
}
|
|
4751
|
+
}
|
|
4752
|
+
}
|
|
4753
|
+
|
|
4754
|
+
if (!focusables.length) {
|
|
4755
|
+
return;
|
|
4756
|
+
}
|
|
4757
|
+
|
|
4758
|
+
event.preventDefault();
|
|
4759
|
+
|
|
4760
|
+
const direction = event.shiftKey ? -1 : 1; // eslint-disable-line no-magic-numbers
|
|
4761
|
+
|
|
4762
|
+
// Walk the active element chain through shadow roots
|
|
4763
|
+
const actives = this._getActiveElements();
|
|
4764
|
+
|
|
4765
|
+
let idx = focusables.findIndex((el) => actives.includes(el));
|
|
4766
|
+
|
|
4767
|
+
if (idx === -1) { // eslint-disable-line no-magic-numbers
|
|
4768
|
+
// Focus is not on a known element — move to first/last
|
|
4769
|
+
idx = direction === 1 ? -1 : focusables.length; // eslint-disable-line no-magic-numbers
|
|
4770
|
+
}
|
|
4771
|
+
|
|
4772
|
+
// Try each element in order, skipping any that can't receive focus
|
|
4773
|
+
// (e.g. hidden elements, elements in collapsed sections)
|
|
4774
|
+
for (let index = 0; index < focusables.length; index++) { // eslint-disable-line no-plusplus
|
|
4775
|
+
let nextIdx = idx + direction;
|
|
4776
|
+
|
|
4777
|
+
// Wrap around
|
|
4778
|
+
if (nextIdx < 0) {
|
|
4779
|
+
nextIdx = focusables.length - 1;
|
|
4780
|
+
} else if (nextIdx >= focusables.length) {
|
|
4781
|
+
nextIdx = 0;
|
|
4782
|
+
}
|
|
4783
|
+
|
|
4784
|
+
focusables[nextIdx].focus();
|
|
4785
|
+
|
|
4786
|
+
// Verify focus actually moved to the target
|
|
4787
|
+
const newActives = this._getActiveElements();
|
|
4788
|
+
|
|
4789
|
+
if (newActives.includes(focusables[nextIdx])) {
|
|
4790
|
+
return;
|
|
4791
|
+
}
|
|
4792
|
+
|
|
4793
|
+
// Focus didn't stick — skip this element and try the next
|
|
4794
|
+
idx = nextIdx;
|
|
4795
|
+
}
|
|
4796
|
+
};
|
|
4797
|
+
this.addEventListener('keydown', this._bibTabHandler);
|
|
4798
|
+
} else {
|
|
4799
|
+
// Normal desktop: use FocusTrap on the bib element
|
|
4800
|
+
this.focusTrap = new FocusTrap(this.bibContent);
|
|
4801
|
+
this.focusTrap.focusFirstElement();
|
|
4802
|
+
}
|
|
4678
4803
|
}
|
|
4679
4804
|
// Fullscreen: showModal() provides native focus trapping
|
|
4805
|
+
}
|
|
4806
|
+
}
|
|
4807
|
+
|
|
4808
|
+
/**
|
|
4809
|
+
* Returns the chain of active (focused) elements through shadow roots.
|
|
4810
|
+
* @private
|
|
4811
|
+
* @returns {Array<HTMLElement>}
|
|
4812
|
+
*/
|
|
4813
|
+
_getActiveElements() {
|
|
4814
|
+
let { activeElement } = document;
|
|
4815
|
+
const actives = [activeElement];
|
|
4816
|
+
|
|
4817
|
+
while (activeElement?.shadowRoot?.activeElement) {
|
|
4818
|
+
activeElement = activeElement.shadowRoot.activeElement;
|
|
4819
|
+
actives.push(activeElement);
|
|
4820
|
+
}
|
|
4821
|
+
|
|
4822
|
+
return actives;
|
|
4823
|
+
}
|
|
4824
|
+
|
|
4825
|
+
/**
|
|
4826
|
+
* Sets `inert` on sibling elements of the dropdown's top-level host
|
|
4827
|
+
* so that content outside the dropdown is not interactive while the modal is open.
|
|
4828
|
+
* Walks up through shadow DOM boundaries to find the outermost host element
|
|
4829
|
+
* in the light DOM, then sets `inert` on that element's siblings.
|
|
4830
|
+
* @private
|
|
4831
|
+
*/
|
|
4832
|
+
_setPageInert() {
|
|
4833
|
+
if (this._inertSiblings) {
|
|
4680
4834
|
return;
|
|
4681
4835
|
}
|
|
4682
4836
|
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4837
|
+
this._inertSiblings = [];
|
|
4838
|
+
|
|
4839
|
+
// Walk up through shadow DOM boundaries to find the topmost host
|
|
4840
|
+
// element in the light DOM. For example, if this dropdown is inside
|
|
4841
|
+
// auro-datepicker's shadow DOM, we walk up to the datepicker element
|
|
4842
|
+
// so we set inert on its siblings — not on the datepicker itself.
|
|
4843
|
+
let host = this;
|
|
4844
|
+
while (host.getRootNode() instanceof ShadowRoot) {
|
|
4845
|
+
host = host.getRootNode().host;
|
|
4846
|
+
}
|
|
4847
|
+
|
|
4848
|
+
const parent = host.parentElement;
|
|
4849
|
+
|
|
4850
|
+
if (parent) {
|
|
4851
|
+
for (const sibling of parent.children) {
|
|
4852
|
+
if (sibling !== host && !sibling.inert) {
|
|
4853
|
+
sibling.inert = true;
|
|
4854
|
+
this._inertSiblings.push(sibling);
|
|
4855
|
+
}
|
|
4856
|
+
}
|
|
4857
|
+
}
|
|
4858
|
+
}
|
|
4859
|
+
|
|
4860
|
+
/**
|
|
4861
|
+
* Restores `inert` state on siblings that were made inert by `_setPageInert`.
|
|
4862
|
+
* @private
|
|
4863
|
+
*/
|
|
4864
|
+
_clearPageInert() {
|
|
4865
|
+
if (this._inertSiblings) {
|
|
4866
|
+
for (const sibling of this._inertSiblings) {
|
|
4867
|
+
sibling.inert = false;
|
|
4868
|
+
}
|
|
4869
|
+
this._inertSiblings = undefined;
|
|
4686
4870
|
}
|
|
4687
4871
|
}
|
|
4688
4872
|
|
|
@@ -4921,6 +5105,7 @@ class AuroDropdown extends AuroElement {
|
|
|
4921
5105
|
shape="${this.shape}"
|
|
4922
5106
|
?data-show="${this.isPopoverVisible}"
|
|
4923
5107
|
?isfullscreen="${this.isBibFullscreen}"
|
|
5108
|
+
?desktopmodal="${this.desktopModal}"
|
|
4924
5109
|
.dialogLabel="${this.bibDialogLabel}"
|
|
4925
5110
|
${ref(this.bibElement)}
|
|
4926
5111
|
>
|