@aurodesignsystem-dev/auro-formkit 0.0.0-pr1497.0 → 0.0.0-pr1497.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/css-only.html +57 -0
- package/components/checkbox/demo/css-only.md +146 -0
- 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/demo/pages.json +1 -1
- package/components/checkbox/demo/styles.min.css +1 -1
- package/components/checkbox/demo/why-checkbox.html +57 -0
- package/components/checkbox/demo/why-checkbox.md +86 -0
- package/components/checkbox/dist/index.js +1 -1
- package/components/checkbox/dist/registered.js +1 -1
- package/components/combobox/demo/css-only.html +57 -0
- package/components/combobox/demo/css-only.md +209 -0
- package/components/combobox/demo/customize.min.js +250 -16
- package/components/combobox/demo/getting-started.min.js +250 -16
- package/components/combobox/demo/index.min.js +250 -16
- package/components/combobox/demo/pages.json +1 -1
- package/components/combobox/demo/styles.min.css +1 -1
- package/components/combobox/demo/why-combobox.html +57 -0
- package/components/combobox/demo/why-combobox.md +113 -0
- package/components/combobox/dist/index.js +250 -16
- package/components/combobox/dist/registered.js +250 -16
- package/components/counter/demo/css-only.html +57 -0
- package/components/counter/demo/css-only.md +184 -0
- package/components/counter/demo/customize.min.js +249 -15
- package/components/counter/demo/index.min.js +249 -15
- package/components/counter/demo/keyboard-behavior.md +1 -0
- package/components/counter/demo/pages.json +1 -1
- package/components/counter/demo/styles.min.css +1 -1
- package/components/counter/demo/why-counter.html +57 -0
- package/components/counter/demo/why-counter.md +108 -0
- package/components/counter/dist/index.js +10 -2
- package/components/counter/dist/registered.js +10 -2
- package/components/datepicker/demo/accessibility.md +54 -3
- package/components/datepicker/demo/api.md +63 -53
- package/components/datepicker/demo/css-only.html +57 -0
- package/components/datepicker/demo/css-only.md +151 -0
- package/components/datepicker/demo/customize.html +2 -0
- package/components/datepicker/demo/customize.js +19 -0
- package/components/datepicker/demo/customize.md +56 -0
- package/components/datepicker/demo/customize.min.js +36147 -0
- package/components/datepicker/demo/design.md +3 -1
- package/components/datepicker/demo/index.js +5 -1
- package/components/datepicker/demo/index.md +104 -15
- package/components/datepicker/demo/index.min.js +2485 -261
- package/components/datepicker/demo/keyboard-behavior.md +201 -2
- package/components/datepicker/demo/pages.json +1 -1
- package/components/datepicker/demo/styles.min.css +1 -1
- package/components/datepicker/demo/voiceover.md +21 -12
- package/components/datepicker/demo/why-datepicker.html +57 -0
- package/components/datepicker/demo/why-datepicker.md +133 -0
- package/components/datepicker/dist/index.js +2348 -211
- package/components/datepicker/dist/registered.js +2348 -211
- package/components/datepicker/dist/src/auro-calendar-cell.d.ts +113 -13
- package/components/datepicker/dist/src/auro-calendar-month.d.ts +38 -1
- package/components/datepicker/dist/src/auro-calendar.d.ts +258 -0
- package/components/datepicker/dist/src/auro-datepicker.d.ts +141 -41
- 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/css-only.html +57 -0
- package/components/dropdown/demo/css-only.md +219 -0
- package/components/dropdown/demo/customize.md +3 -0
- package/components/dropdown/demo/customize.min.js +239 -13
- package/components/dropdown/demo/getting-started.min.js +239 -13
- package/components/dropdown/demo/index.min.js +239 -13
- package/components/dropdown/demo/keyboard-behavior.md +1 -0
- package/components/dropdown/demo/pages.json +1 -1
- package/components/dropdown/demo/styles.min.css +1 -1
- package/components/dropdown/demo/why-dropdown.html +57 -0
- package/components/dropdown/demo/why-dropdown.md +97 -0
- package/components/dropdown/dist/auro-dropdown.d.ts +34 -1
- package/components/dropdown/dist/index.js +239 -13
- package/components/dropdown/dist/registered.js +239 -13
- package/components/form/demo/css-only.html +57 -0
- package/components/form/demo/css-only.md +156 -0
- package/components/form/demo/customize.min.js +3098 -259
- package/components/form/demo/getting-started.min.js +3098 -259
- package/components/form/demo/index.min.js +3098 -259
- package/components/form/demo/pages.json +1 -1
- package/components/form/demo/registerDemoDeps.min.js +3098 -259
- package/components/form/demo/styles.min.css +1 -1
- package/components/form/demo/why-form.html +57 -0
- package/components/form/demo/why-form.md +101 -0
- package/components/input/demo/css-only.html +57 -0
- package/components/input/demo/css-only.md +199 -0
- 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/demo/pages.json +1 -1
- package/components/input/demo/styles.min.css +1 -1
- package/components/input/demo/why-input.html +57 -0
- package/components/input/demo/why-input.md +121 -0
- package/components/input/dist/index.js +1 -1
- package/components/input/dist/registered.js +1 -1
- package/components/menu/demo/css-only.html +57 -0
- package/components/menu/demo/css-only.md +166 -0
- package/components/menu/demo/pages.json +1 -1
- package/components/menu/demo/styles.min.css +1 -1
- package/components/menu/demo/why-menu.html +57 -0
- package/components/menu/demo/why-menu.md +104 -0
- package/components/radio/demo/css-only.html +57 -0
- package/components/radio/demo/css-only.md +151 -0
- package/components/radio/demo/customize.min.js +1764 -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 +1783 -0
- package/components/radio/demo/index.min.js +1 -1
- package/components/radio/demo/pages.json +1 -1
- package/components/radio/demo/styles.min.css +1 -1
- package/components/radio/demo/why-radio.html +57 -0
- package/components/radio/demo/why-radio.md +92 -0
- package/components/radio/dist/index.js +1 -1
- package/components/radio/dist/registered.js +1 -1
- package/components/select/demo/css-only.html +57 -0
- package/components/select/demo/css-only.md +203 -0
- package/components/select/demo/customize.min.js +249 -15
- package/components/select/demo/getting-started.min.js +249 -15
- package/components/select/demo/index.min.js +249 -15
- package/components/select/demo/keyboard-behavior.md +1 -0
- package/components/select/demo/pages.json +1 -1
- package/components/select/demo/styles.min.css +1 -1
- package/components/select/demo/why-select.html +57 -0
- package/components/select/demo/why-select.md +128 -0
- package/components/select/dist/index.js +249 -15
- package/components/select/dist/registered.js +249 -15
- package/custom-elements.json +2700 -1621
- package/package.json +8 -8
|
@@ -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 = '202606081833';
|
|
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,45 @@ 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
|
+
}
|
|
4597
|
+
}
|
|
4598
|
+
|
|
4599
|
+
// Handle desktopModal toggled while the dropdown is already open.
|
|
4600
|
+
// Re-initialize focus trapping and page inert state to match the new mode.
|
|
4601
|
+
if (changedProperties.has('desktopModal') && this.isPopoverVisible && !this.isBibFullscreen) {
|
|
4602
|
+
this.updateFocusTrap();
|
|
4603
|
+
if (this.desktopModal) {
|
|
4604
|
+
this._setPageInert();
|
|
4605
|
+
} else {
|
|
4606
|
+
this._clearPageInert();
|
|
4607
|
+
}
|
|
4564
4608
|
}
|
|
4565
4609
|
}
|
|
4566
4610
|
|
|
@@ -4570,8 +4614,14 @@ class AuroDropdown extends AuroElement {
|
|
|
4570
4614
|
* @param {CustomEvent} event - The custom event that contains the dropdown toggle information.
|
|
4571
4615
|
*/
|
|
4572
4616
|
handleDropdownToggle(event) {
|
|
4573
|
-
this.updateFocusTrap();
|
|
4574
4617
|
this.isPopoverVisible = event.detail.expanded;
|
|
4618
|
+
|
|
4619
|
+
// Tear down FocusTrap when closing. Creation happens in updated()
|
|
4620
|
+
// after the dialog is open so getFocusableElements can find content.
|
|
4621
|
+
if (!this.isPopoverVisible) {
|
|
4622
|
+
this.updateFocusTrap();
|
|
4623
|
+
}
|
|
4624
|
+
|
|
4575
4625
|
const eventType = event.detail.eventType || "unknown";
|
|
4576
4626
|
if (!this.isPopoverVisible && this.hasFocus && eventType === "keydown") {
|
|
4577
4627
|
this.trigger.focus();
|
|
@@ -4670,19 +4720,194 @@ class AuroDropdown extends AuroElement {
|
|
|
4670
4720
|
* @private
|
|
4671
4721
|
*/
|
|
4672
4722
|
updateFocusTrap() {
|
|
4723
|
+
// Always clean up existing handlers/traps before setting up new ones
|
|
4724
|
+
// to prevent duplicate listeners on repeated calls.
|
|
4725
|
+
if (this._bibTabHandler) {
|
|
4726
|
+
this.removeEventListener('keydown', this._bibTabHandler);
|
|
4727
|
+
this._bibTabHandler = undefined;
|
|
4728
|
+
}
|
|
4729
|
+
|
|
4730
|
+
if (this.focusTrap) {
|
|
4731
|
+
this.focusTrap.disconnect();
|
|
4732
|
+
this.focusTrap = undefined;
|
|
4733
|
+
}
|
|
4734
|
+
|
|
4673
4735
|
if (this.isPopoverVisible) {
|
|
4674
4736
|
if (!this.isBibFullscreen) {
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4737
|
+
if (this.desktopModal) {
|
|
4738
|
+
// Desktop modal: trap focus only within the bib content.
|
|
4739
|
+
// Can't use FocusTrap on the bib element because keydown events
|
|
4740
|
+
// from slotted content bubble through the dropdown host (light DOM),
|
|
4741
|
+
// not through the bib (shadow projection target). Using FocusTrap
|
|
4742
|
+
// on the dropdown would include the trigger in the tab cycle.
|
|
4743
|
+
// Instead, listen for Tab on the dropdown and manually wrap focus
|
|
4744
|
+
// within the bib's focusable elements.
|
|
4745
|
+
this._bibTabHandler = (event) => {
|
|
4746
|
+
if (event.key !== 'Tab') {
|
|
4747
|
+
return;
|
|
4748
|
+
}
|
|
4749
|
+
|
|
4750
|
+
// Collect focusable elements from the bib content.
|
|
4751
|
+
const focusables = getFocusableElements(this.bibContent);
|
|
4752
|
+
|
|
4753
|
+
// Fallback: try from slotted content directly
|
|
4754
|
+
if (!focusables.length) {
|
|
4755
|
+
const slot = this.shadowRoot.querySelector('.slotContent slot');
|
|
4756
|
+
const assignedNodes = slot ? slot.assignedNodes({ flatten: true }) : [];
|
|
4757
|
+
|
|
4758
|
+
for (const node of assignedNodes) {
|
|
4759
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
4760
|
+
focusables.push(...getFocusableElements(node));
|
|
4761
|
+
}
|
|
4762
|
+
}
|
|
4763
|
+
}
|
|
4764
|
+
|
|
4765
|
+
if (!focusables.length) {
|
|
4766
|
+
return;
|
|
4767
|
+
}
|
|
4768
|
+
|
|
4769
|
+
event.preventDefault();
|
|
4770
|
+
|
|
4771
|
+
const direction = event.shiftKey ? -1 : 1; // eslint-disable-line no-magic-numbers
|
|
4772
|
+
|
|
4773
|
+
// Walk the active element chain through shadow roots
|
|
4774
|
+
const actives = this._getActiveElements();
|
|
4775
|
+
|
|
4776
|
+
let idx = focusables.findIndex((el) => actives.includes(el));
|
|
4777
|
+
|
|
4778
|
+
if (idx === -1) { // eslint-disable-line no-magic-numbers
|
|
4779
|
+
// Focus is not on a known element — move to first/last
|
|
4780
|
+
idx = direction === 1 ? -1 : focusables.length; // eslint-disable-line no-magic-numbers
|
|
4781
|
+
}
|
|
4782
|
+
|
|
4783
|
+
// Try each element in order, skipping any that can't receive focus
|
|
4784
|
+
// (e.g. hidden elements, elements in collapsed sections)
|
|
4785
|
+
for (let index = 0; index < focusables.length; index++) { // eslint-disable-line no-plusplus
|
|
4786
|
+
let nextIdx = idx + direction;
|
|
4787
|
+
|
|
4788
|
+
// Wrap around
|
|
4789
|
+
if (nextIdx < 0) {
|
|
4790
|
+
nextIdx = focusables.length - 1;
|
|
4791
|
+
} else if (nextIdx >= focusables.length) {
|
|
4792
|
+
nextIdx = 0;
|
|
4793
|
+
}
|
|
4794
|
+
|
|
4795
|
+
focusables[nextIdx].focus();
|
|
4796
|
+
|
|
4797
|
+
// Verify focus actually moved to the target
|
|
4798
|
+
const newActives = this._getActiveElements();
|
|
4799
|
+
|
|
4800
|
+
if (newActives.includes(focusables[nextIdx])) {
|
|
4801
|
+
return;
|
|
4802
|
+
}
|
|
4803
|
+
|
|
4804
|
+
// Focus didn't stick — skip this element and try the next
|
|
4805
|
+
idx = nextIdx;
|
|
4806
|
+
}
|
|
4807
|
+
};
|
|
4808
|
+
this.addEventListener('keydown', this._bibTabHandler);
|
|
4809
|
+
|
|
4810
|
+
// Move initial focus into the bib content, matching FocusTrap behavior
|
|
4811
|
+
requestAnimationFrame(() => {
|
|
4812
|
+
const focusables = getFocusableElements(this.bibContent);
|
|
4813
|
+
if (focusables.length) {
|
|
4814
|
+
focusables[0].focus();
|
|
4815
|
+
}
|
|
4816
|
+
});
|
|
4817
|
+
} else {
|
|
4818
|
+
// Normal desktop: use FocusTrap on the bib element
|
|
4819
|
+
this.focusTrap = new FocusTrap(this.bibContent);
|
|
4820
|
+
this.focusTrap.focusFirstElement();
|
|
4821
|
+
}
|
|
4678
4822
|
}
|
|
4679
4823
|
// Fullscreen: showModal() provides native focus trapping
|
|
4824
|
+
}
|
|
4825
|
+
}
|
|
4826
|
+
|
|
4827
|
+
/**
|
|
4828
|
+
* Returns the chain of active (focused) elements through shadow roots.
|
|
4829
|
+
* @private
|
|
4830
|
+
* @returns {Array<HTMLElement>}
|
|
4831
|
+
*/
|
|
4832
|
+
_getActiveElements() {
|
|
4833
|
+
let { activeElement } = document;
|
|
4834
|
+
const actives = [activeElement];
|
|
4835
|
+
|
|
4836
|
+
while (activeElement?.shadowRoot?.activeElement) {
|
|
4837
|
+
activeElement = activeElement.shadowRoot.activeElement;
|
|
4838
|
+
actives.push(activeElement);
|
|
4839
|
+
}
|
|
4840
|
+
|
|
4841
|
+
return actives;
|
|
4842
|
+
}
|
|
4843
|
+
|
|
4844
|
+
/**
|
|
4845
|
+
* Sets `inert` on sibling elements of the dropdown's top-level host
|
|
4846
|
+
* so that content outside the dropdown is not interactive while the modal is open.
|
|
4847
|
+
* Walks up through shadow DOM boundaries to find the outermost host element
|
|
4848
|
+
* in the light DOM, then sets `inert` on siblings at each ancestor level
|
|
4849
|
+
* to ensure all page content outside the host subtree is inert.
|
|
4850
|
+
* @private
|
|
4851
|
+
*/
|
|
4852
|
+
_setPageInert() {
|
|
4853
|
+
if (this._inertSiblings) {
|
|
4680
4854
|
return;
|
|
4681
4855
|
}
|
|
4682
4856
|
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4857
|
+
this._inertSiblings = [];
|
|
4858
|
+
|
|
4859
|
+
// Walk up through shadow DOM boundaries to find the topmost host
|
|
4860
|
+
// element in the light DOM. For example, if this dropdown is inside
|
|
4861
|
+
// auro-datepicker's shadow DOM, we walk up to the datepicker element
|
|
4862
|
+
// so we set inert on its siblings — not on the datepicker itself.
|
|
4863
|
+
let host = this;
|
|
4864
|
+
while (host.getRootNode() instanceof ShadowRoot) {
|
|
4865
|
+
host = host.getRootNode().host;
|
|
4866
|
+
}
|
|
4867
|
+
|
|
4868
|
+
// Walk up the ancestor chain, inerting siblings at each level
|
|
4869
|
+
// to ensure the entire page outside the host subtree is inert.
|
|
4870
|
+
// Uses a reference counter (data-auro-inert-count) so multiple
|
|
4871
|
+
// simultaneous modal dropdowns share inert state safely.
|
|
4872
|
+
let current = host;
|
|
4873
|
+
while (current.parentElement) {
|
|
4874
|
+
const parent = current.parentElement;
|
|
4875
|
+
for (const sibling of parent.children) {
|
|
4876
|
+
if (sibling !== current) {
|
|
4877
|
+
const count = parseInt(sibling.dataset.auroInertCount || '0', 10);
|
|
4878
|
+
if (count === 0) {
|
|
4879
|
+
sibling.dataset.auroInertWas = sibling.inert ? 'true' : 'false';
|
|
4880
|
+
}
|
|
4881
|
+
sibling.dataset.auroInertCount = String(count + 1);
|
|
4882
|
+
sibling.inert = true;
|
|
4883
|
+
this._inertSiblings.push(sibling);
|
|
4884
|
+
}
|
|
4885
|
+
}
|
|
4886
|
+
current = parent;
|
|
4887
|
+
}
|
|
4888
|
+
}
|
|
4889
|
+
|
|
4890
|
+
/**
|
|
4891
|
+
* Restores `inert` state on siblings that were tracked by `_setPageInert`.
|
|
4892
|
+
* Uses reference counting so inert is only cleared when the last modal
|
|
4893
|
+
* dropdown releases a given element. Preserves the original inert state
|
|
4894
|
+
* so externally-inerted elements are not inadvertently re-enabled.
|
|
4895
|
+
* @private
|
|
4896
|
+
*/
|
|
4897
|
+
_clearPageInert() {
|
|
4898
|
+
if (this._inertSiblings) {
|
|
4899
|
+
for (const sibling of this._inertSiblings) {
|
|
4900
|
+
const count = parseInt(sibling.dataset.auroInertCount || '1', 10) - 1;
|
|
4901
|
+
if (count <= 0) {
|
|
4902
|
+
const wasInert = sibling.dataset.auroInertWas === 'true';
|
|
4903
|
+
delete sibling.dataset.auroInertCount;
|
|
4904
|
+
delete sibling.dataset.auroInertWas;
|
|
4905
|
+
sibling.inert = wasInert;
|
|
4906
|
+
} else {
|
|
4907
|
+
sibling.dataset.auroInertCount = String(count);
|
|
4908
|
+
}
|
|
4909
|
+
}
|
|
4910
|
+
this._inertSiblings = undefined;
|
|
4686
4911
|
}
|
|
4687
4912
|
}
|
|
4688
4913
|
|
|
@@ -4921,6 +5146,7 @@ class AuroDropdown extends AuroElement {
|
|
|
4921
5146
|
shape="${this.shape}"
|
|
4922
5147
|
?data-show="${this.isPopoverVisible}"
|
|
4923
5148
|
?isfullscreen="${this.isBibFullscreen}"
|
|
5149
|
+
?desktopmodal="${this.desktopModal}"
|
|
4924
5150
|
.dialogLabel="${this.bibDialogLabel}"
|
|
4925
5151
|
${ref(this.bibElement)}
|
|
4926
5152
|
>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
|
|
3
|
+
See LICENSE in the project root for license information.
|
|
4
|
+
|
|
5
|
+
HTML in this document is standardized and NOT to be edited.
|
|
6
|
+
All demo code should be added/edited in ./demo/css-only.md
|
|
7
|
+
|
|
8
|
+
With the exception of adding custom elements if needed for the demo.
|
|
9
|
+
|
|
10
|
+
----------------------- DO NOT EDIT -----------------------------
|
|
11
|
+
|
|
12
|
+
-->
|
|
13
|
+
|
|
14
|
+
<!DOCTYPE html>
|
|
15
|
+
<html lang="en">
|
|
16
|
+
<head>
|
|
17
|
+
<meta charset="UTF-8" />
|
|
18
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
19
|
+
<title>Auro Web Component Demo | auro-form | CSS only</title>
|
|
20
|
+
|
|
21
|
+
<!-- highlight.js Stylesheet -->
|
|
22
|
+
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@11.9.0/build/styles/github.min.css"/>
|
|
23
|
+
|
|
24
|
+
<!-- Legacy reference is still needed to support auro-form's use of legacy token values at this time -->
|
|
25
|
+
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/@aurodesignsystem/design-tokens@latest/dist/legacy/auro-classic/CSSCustomProperties.css"/>
|
|
26
|
+
|
|
27
|
+
<!-- Design Token Alaska Theme -->
|
|
28
|
+
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/@aurodesignsystem/design-tokens@latest/dist/themes/alaska/CSSCustomProperties--alaska.min.css"/>
|
|
29
|
+
|
|
30
|
+
<!-- Webcore Stylesheet Alaska Theme -->
|
|
31
|
+
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/@aurodesignsystem/webcorestylesheets@latest/dist/bundled/themes/alaska.global.min.css" />
|
|
32
|
+
|
|
33
|
+
<!-- Demo Specific Styles -->
|
|
34
|
+
<link rel="stylesheet" type="text/css" href="./styles.min.css" />
|
|
35
|
+
<style>
|
|
36
|
+
table {
|
|
37
|
+
--ds-color-container-secondary-default: transparent;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
tr:not(:last-of-type) {
|
|
41
|
+
border-bottom: 1px solid var(--ds-color-border-tertiary-default);
|
|
42
|
+
}
|
|
43
|
+
</style>
|
|
44
|
+
</head>
|
|
45
|
+
<body class="auro-markdown">
|
|
46
|
+
<main></main>
|
|
47
|
+
|
|
48
|
+
<script type="module">
|
|
49
|
+
import { renderPage } from './demo-support.min.js';
|
|
50
|
+
await renderPage('./css-only.md');
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<!-- If additional elements are needed for the demo, add them here. -->
|
|
54
|
+
<script src="https://cdn.jsdelivr.net/npm/@aurodesignsystem/auro-header@latest/+esm" type="module"></script>
|
|
55
|
+
<script src="https://cdn.jsdelivr.net/npm/@aurodesignsystem/auro-hyperlink@latest/+esm" type="module"></script>
|
|
56
|
+
</body>
|
|
57
|
+
</html>
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
<auro-header level="1">CSS only with native form</auro-header>
|
|
2
|
+
<p>For situations where the <code><auro-form></code> web component cannot be used, a native HTML <code><form></code> element can be styled with the Auro Design System tokens to approximate the layout and spacing used by <code>auro-form</code>. Unlike <auro-hyperlink href="https://auro.alaskaair.com/components/auro/hyperlink/css-only" target="_blank">auro-hyperlink</auro-hyperlink>, <auro-hyperlink href="https://alaskaairlines.github.io/WebCoreStyleSheets/" target="_blank">Web Core Style Sheets</auro-hyperlink> does not provide a prebuilt <code>.form</code> class. The native <code><form></code> element provides the structural container and browser-native constraint validation, but it does not provide the cross-field coordination that <code>auro-form</code> adds.</p>
|
|
3
|
+
<auro-header level="2">Styling a native form</auro-header>
|
|
4
|
+
<p>The native form can be laid out using the Auro design tokens published by <auro-hyperlink href="https://alaskaairlines.github.io/WebCoreStyleSheets/" target="_blank">@aurodesignsystem/design-tokens</auro-hyperlink>. The pattern below replicates the spacing and rhythm used by <code>auro-form</code>.</p>
|
|
5
|
+
<pre><code>@import "./node_modules/@aurodesignsystem/design-tokens/dist/tokens/CSSCustomProperties.css";
|
|
6
|
+
|
|
7
|
+
.form {
|
|
8
|
+
display: flex;
|
|
9
|
+
flex-direction: column;
|
|
10
|
+
gap: var(--ds-size-300, 1.5rem);
|
|
11
|
+
padding: var(--ds-size-400, 2rem);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.form fieldset {
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-direction: column;
|
|
17
|
+
gap: var(--ds-size-200, 1rem);
|
|
18
|
+
border: 0;
|
|
19
|
+
padding: 0;
|
|
20
|
+
margin: 0;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.form legend {
|
|
24
|
+
padding: 0;
|
|
25
|
+
margin-bottom: var(--ds-size-100, 0.5rem);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.form .actions {
|
|
29
|
+
display: flex;
|
|
30
|
+
gap: var(--ds-size-200, 1rem);
|
|
31
|
+
margin-top: var(--ds-size-200, 1rem);
|
|
32
|
+
}</code></pre>
|
|
33
|
+
<auro-header level="3">Basic form</auro-header>
|
|
34
|
+
<p>Apply the <code>.form</code> class to a native <code><form></code> element and rely on the browser's built-in submit and reset behavior:</p>
|
|
35
|
+
<pre><code><form class="form" action="/subscribe" method="post">
|
|
36
|
+
<label>
|
|
37
|
+
Email
|
|
38
|
+
<input type="email" name="email" required />
|
|
39
|
+
</label>
|
|
40
|
+
<div class="actions">
|
|
41
|
+
<button type="submit">Submit</button>
|
|
42
|
+
<button type="reset">Reset</button>
|
|
43
|
+
</div>
|
|
44
|
+
</form></code></pre>
|
|
45
|
+
<auro-header level="3">Form with grouped fields</auro-header>
|
|
46
|
+
<p>Use a <code><fieldset></code> and <code><legend></code> to give grouped fields an accessible name:</p>
|
|
47
|
+
<pre><code><form class="form">
|
|
48
|
+
<fieldset>
|
|
49
|
+
<legend>Contact information</legend>
|
|
50
|
+
<label>First name <input type="text" name="firstName" required /></label>
|
|
51
|
+
<label>Last name <input type="text" name="lastName" required /></label>
|
|
52
|
+
<label>Email <input type="email" name="email" required /></label>
|
|
53
|
+
</fieldset>
|
|
54
|
+
<div class="actions">
|
|
55
|
+
<button type="submit">Submit</button>
|
|
56
|
+
<button type="reset">Reset</button>
|
|
57
|
+
</div>
|
|
58
|
+
</form></code></pre>
|
|
59
|
+
<auro-header level="2">What you lose without auro-form</auro-header>
|
|
60
|
+
<p>While the CSS above replicates the <strong>visual layout</strong> of <code>auro-form</code>, the following functionality built into the <code>auro-form</code> web component is <strong>not available</strong> when using a plain HTML <code><form></code>:</p>
|
|
61
|
+
<auro-header level="3">Child element registration</auro-header>
|
|
62
|
+
<p><code>auro-form</code> automatically discovers and registers its named Auro form-element children (<code>auro-input</code>, <code>auro-select</code>, <code>auro-datepicker</code>, <code>auro-combobox</code>, <code>auro-checkbox-group</code>, <code>auro-radio-group</code>, <code>auro-counter-group</code>) on slot change and via a <code>MutationObserver</code>, so dynamically added or removed fields are tracked without manual wiring. A native <code><form></code> only exposes built-in form-associated elements through <code>form.elements</code> — custom elements and dynamically inserted controls require custom registration logic.</p>
|
|
63
|
+
<auro-header level="3">Aggregated value snapshot</auro-header>
|
|
64
|
+
<p><code>auro-form</code> exposes a <code>value</code> getter that returns a single key-value object of every named child's current value, including array values from range datepickers and grouped controls. With a native <code><form></code>, you must either use <code>FormData</code> (which does not understand custom elements) or query each control individually and assemble the values yourself.</p>
|
|
65
|
+
<auro-header level="3">Aggregated validity state</auro-header>
|
|
66
|
+
<p><code>auro-form</code> exposes a single <code>validity</code> getter that returns <code>'valid'</code>, <code>'invalid'</code>, or <code>null</code> based on the validity of every required and interacted-with child. Native forms expose <code>form.checkValidity()</code> and <code>form.reportValidity()</code>, but those only consider built-in form-associated elements and do not include custom elements like <code>auro-input</code> or <code>auro-datepicker</code>.</p>
|
|
67
|
+
<auro-header level="3">Initial-state tracking</auro-header>
|
|
68
|
+
<p><code>auro-form</code> tracks an <code>isInitialState</code> flag that is <code>true</code> until any child has been interacted with or had its value changed. Native forms have no equivalent — you must implement change tracking yourself to know whether the form is in a pristine state.</p>
|
|
69
|
+
<auro-header level="3">auroFormElement-validated event aggregation</auro-header>
|
|
70
|
+
<p><code>auro-form</code> listens for <code>auroFormElement-validated</code> events from every registered child and updates its aggregated validity state in response. A native <code><form></code> does not listen to or interpret these events, so per-field validation reported by Auro components is not rolled up into a single form-level validity result.</p>
|
|
71
|
+
<auro-header level="3">Submit coordination</auro-header>
|
|
72
|
+
<p><code>auro-form</code> intercepts clicks on child submit buttons (<code><button type="submit"></code> or <code><auro-button type="submit"></code>), forces validation on every registered child, waits for validation to settle, and only then fires a <code>submit</code> event with <code>detail.value</code> containing the full form snapshot. A native <code><form></code> submit fires before custom-element validation can complete and does not surface a structured value object.</p>
|
|
73
|
+
<auro-header level="3">Reset coordination</auro-header>
|
|
74
|
+
<p><code>auro-form</code> intercepts clicks on child reset buttons, calls <code>reset()</code> on every registered child, reinitializes its state, and fires a <code>reset</code> event with <code>detail.previousValue</code> containing the values captured before the reset. A native <code><form></code> reset only restores default values on built-in form controls and does not call any custom reset method on web components.</p>
|
|
75
|
+
<auro-header level="3">Submit and reset button disabling</auro-header>
|
|
76
|
+
<p><code>auro-form</code> automatically disables submit buttons while the form is in its initial state or invalid, and disables reset buttons while the form is in its initial state. With a native <code><form></code>, you must wire up your own change listeners to toggle the <code>disabled</code> attribute on action buttons.</p>
|
|
77
|
+
<auro-header level="3">Enter-to-submit handling</auro-header>
|
|
78
|
+
<p><code>auro-form</code> listens for the Enter key on its registered children and triggers a coordinated submit, while skipping textarea-style fields so they can accept newlines. A native <code><form></code> submits on Enter only when the focused control is a form-associated element the browser recognizes, which excludes most custom elements.</p>
|
|
79
|
+
<auro-header level="3">Mixed Auro and native child support</auro-header>
|
|
80
|
+
<p><code>auro-form</code> recognizes its named Auro children and coordinates them as a single form, while still allowing native elements to live alongside them in markup. A native <code><form></code> treats Auro custom elements as opaque DOM nodes and provides no cross-field coordination between them.</p>
|
|
81
|
+
<auro-header level="3">Multi-brand theming</auro-header>
|
|
82
|
+
<p><code>auro-form</code> consumes Auro design tokens through its component logic, so it automatically picks up brand-specific theming when token packages are swapped. A CSS-only form is tied to whichever tokens were imported at author time and will not respond to runtime theme switching the way the web component does.</p>
|
|
83
|
+
<auro-header level="2">Summary</auro-header>
|
|
84
|
+
<table>
|
|
85
|
+
<thead>
|
|
86
|
+
<tr>
|
|
87
|
+
<th>Feature</th>
|
|
88
|
+
<th>Native <code><form></code> with Auro tokens</th>
|
|
89
|
+
<th><code>auro-form</code></th>
|
|
90
|
+
</tr>
|
|
91
|
+
</thead>
|
|
92
|
+
<tbody>
|
|
93
|
+
<tr>
|
|
94
|
+
<td>Design-system-aligned layout</td>
|
|
95
|
+
<td>Manual (author-written CSS)</td>
|
|
96
|
+
<td>Built-in</td>
|
|
97
|
+
</tr>
|
|
98
|
+
<tr>
|
|
99
|
+
<td>Child element registration</td>
|
|
100
|
+
<td>Built-ins only via <code>form.elements</code></td>
|
|
101
|
+
<td>Automatic, including dynamic children</td>
|
|
102
|
+
</tr>
|
|
103
|
+
<tr>
|
|
104
|
+
<td>Aggregated value snapshot</td>
|
|
105
|
+
<td>Manual or <code>FormData</code> (no custom elements)</td>
|
|
106
|
+
<td>Single <code>value</code> getter</td>
|
|
107
|
+
</tr>
|
|
108
|
+
<tr>
|
|
109
|
+
<td>Aggregated validity state</td>
|
|
110
|
+
<td>Built-ins only via <code>checkValidity()</code></td>
|
|
111
|
+
<td>Single <code>validity</code> getter across all children</td>
|
|
112
|
+
</tr>
|
|
113
|
+
<tr>
|
|
114
|
+
<td>Initial-state tracking</td>
|
|
115
|
+
<td>Manual</td>
|
|
116
|
+
<td><code>isInitialState</code> getter</td>
|
|
117
|
+
</tr>
|
|
118
|
+
<tr>
|
|
119
|
+
<td><code>auroFormElement-validated</code> aggregation</td>
|
|
120
|
+
<td>Not supported</td>
|
|
121
|
+
<td>Built-in</td>
|
|
122
|
+
</tr>
|
|
123
|
+
<tr>
|
|
124
|
+
<td>Submit coordination</td>
|
|
125
|
+
<td>Native submit fires before custom-element validation</td>
|
|
126
|
+
<td>Forces validation, then fires <code>submit</code> with full value</td>
|
|
127
|
+
</tr>
|
|
128
|
+
<tr>
|
|
129
|
+
<td>Reset coordination</td>
|
|
130
|
+
<td>Resets built-ins only</td>
|
|
131
|
+
<td>Calls <code>reset()</code> on every child; emits previous value</td>
|
|
132
|
+
</tr>
|
|
133
|
+
<tr>
|
|
134
|
+
<td>Submit/reset button disabling</td>
|
|
135
|
+
<td>Manual</td>
|
|
136
|
+
<td>Automatic based on state and validity</td>
|
|
137
|
+
</tr>
|
|
138
|
+
<tr>
|
|
139
|
+
<td>Enter-to-submit on custom elements</td>
|
|
140
|
+
<td>Not supported</td>
|
|
141
|
+
<td>Built-in (skips textarea)</td>
|
|
142
|
+
</tr>
|
|
143
|
+
<tr>
|
|
144
|
+
<td>Mixed Auro and native children</td>
|
|
145
|
+
<td>Native treats Auro elements as opaque</td>
|
|
146
|
+
<td>Coordinated as a single form</td>
|
|
147
|
+
</tr>
|
|
148
|
+
<tr>
|
|
149
|
+
<td>Multi-brand theming</td>
|
|
150
|
+
<td>Static (import-time tokens)</td>
|
|
151
|
+
<td>Full (design tokens + component logic)</td>
|
|
152
|
+
</tr>
|
|
153
|
+
</tbody>
|
|
154
|
+
</table>
|
|
155
|
+
<auro-header level="2">Recommendation</auro-header>
|
|
156
|
+
<p>Use <code>auro-form</code> whenever possible. Fall back to a CSS-styled native <code><form></code> only in environments where custom elements are not supported or when integrating with third-party systems that require plain HTML — and be prepared to reimplement child registration, aggregated value and validity, submit and reset coordination, and action-button state management yourself.</p>
|