@aurodesignsystem-dev/auro-formkit 0.0.0-pr1452.0 → 0.0.0-pr1456.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/components/checkbox/demo/api.min.js +3 -2
- package/components/checkbox/demo/index.min.js +3 -2
- package/components/checkbox/dist/auro-checkbox-group.d.ts +6 -6
- package/components/checkbox/dist/auro-checkbox.d.ts +9 -8
- package/components/checkbox/dist/index.js +3 -2
- package/components/checkbox/dist/registered.js +3 -2
- package/components/combobox/demo/api.min.js +1436 -1434
- package/components/combobox/demo/index.min.js +1436 -1434
- package/components/combobox/dist/auro-combobox.d.ts +35 -35
- package/components/combobox/dist/index.js +8 -6
- package/components/combobox/dist/registered.js +8 -6
- package/components/counter/demo/api.min.js +2 -2
- package/components/counter/demo/index.min.js +2 -2
- package/components/counter/dist/auro-counter-group.d.ts +2 -2
- package/components/counter/dist/auro-counter.d.ts +10 -10
- package/components/counter/dist/index.js +2 -2
- package/components/counter/dist/registered.js +2 -2
- package/components/datepicker/demo/api.min.js +6 -6
- package/components/datepicker/demo/index.min.js +6 -6
- package/components/datepicker/dist/{src/auro-calendar-cell.d.ts → auro-calendar-cell.d.ts} +2 -2
- package/components/datepicker/dist/{src/auro-datepicker.d.ts → auro-datepicker.d.ts} +13 -13
- package/components/datepicker/dist/index.js +6 -6
- package/components/datepicker/dist/registered.js +6 -6
- package/components/datepicker/dist/{src/utilities.d.ts → utilities.d.ts} +4 -4
- package/components/datepicker/dist/{src/utilitiesCalendar.d.ts → utilitiesCalendar.d.ts} +3 -3
- package/components/datepicker/dist/{src/vendor → vendor}/wc-range-datepicker/range-datepicker-calendar.d.ts +2 -2
- package/components/datepicker/dist/{src/vendor → vendor}/wc-range-datepicker/range-datepicker.d.ts +1 -1
- package/components/dropdown/demo/api.min.js +1 -1
- package/components/dropdown/demo/index.min.js +1 -1
- package/components/dropdown/dist/auro-dropdown.d.ts +22 -22
- package/components/dropdown/dist/auro-dropdownBib.d.ts +3 -3
- package/components/dropdown/dist/dropdownBibKeyboardStrategy.d.ts +1 -1
- package/components/dropdown/dist/index.js +1 -1
- package/components/dropdown/dist/registered.js +1 -1
- package/components/form/demo/api.min.js +1527 -1524
- package/components/form/demo/index.min.js +1527 -1524
- package/components/input/demo/api.min.js +4 -4
- package/components/input/demo/index.min.js +4 -4
- package/components/input/dist/auro-input.d.ts +1 -1
- package/components/input/dist/base-input.d.ts +30 -29
- package/components/input/dist/index.js +4 -4
- package/components/input/dist/registered.js +4 -4
- package/components/menu/demo/api.md +2 -2
- package/components/menu/demo/api.min.js +1536 -1536
- package/components/menu/demo/index.min.js +1536 -1536
- package/components/menu/dist/auro-menu-utils.d.ts +1 -1
- package/components/menu/dist/auro-menu.context.d.ts +4 -3
- package/components/menu/dist/auro-menu.d.ts +4 -4
- package/components/menu/dist/auro-menuoption.d.ts +6 -6
- package/components/menu/dist/index.js +1565 -1565
- package/components/menu/dist/registered.js +1521 -1521
- package/components/radio/demo/api.min.js +1 -1
- package/components/radio/demo/index.min.js +1 -1
- package/components/radio/dist/auro-radio-group.d.ts +9 -9
- package/components/radio/dist/auro-radio.d.ts +8 -8
- package/components/radio/dist/index.js +1 -1
- package/components/radio/dist/registered.js +1 -1
- package/components/select/demo/api.min.js +1433 -1433
- package/components/select/demo/index.min.js +1433 -1433
- package/components/select/dist/auro-select.d.ts +11 -11
- package/components/select/dist/index.js +2 -2
- package/components/select/dist/registered.js +2 -2
- package/custom-elements.json +5 -2
- package/package.json +27 -41
- /package/components/datepicker/dist/{src/auro-calendar-month.d.ts → auro-calendar-month.d.ts} +0 -0
- /package/components/datepicker/dist/{src/auro-calendar.d.ts → auro-calendar.d.ts} +0 -0
- /package/components/datepicker/dist/{src/buttonVersion.d.ts → buttonVersion.d.ts} +0 -0
- /package/components/datepicker/dist/{src/datepickerKeyboardStrategy.d.ts → datepickerKeyboardStrategy.d.ts} +0 -0
- /package/components/datepicker/dist/{src/iconVersion.d.ts → iconVersion.d.ts} +0 -0
- /package/components/datepicker/dist/{src/index.d.ts → index.d.ts} +0 -0
- /package/components/datepicker/dist/{src/popoverVersion.d.ts → popoverVersion.d.ts} +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/classic/color-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/classic/style-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/color-calendar-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/color-cell-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/color-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/color-month-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/shapeSize-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/snowflake/color-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/snowflake/style-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/style-auro-calendar-cell-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/style-auro-calendar-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/style-auro-calendar-month-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/style-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/styles → styles}/tokens-css.d.ts +0 -0
- /package/components/datepicker/dist/{src/utilitiesCalendarRender.d.ts → utilitiesCalendarRender.d.ts} +0 -0
- /package/components/datepicker/dist/{src/vendor → vendor}/wc-range-datepicker/day.d.ts +0 -0
- /package/components/datepicker/dist/{src/vendor → vendor}/wc-range-datepicker/range-datepicker-cell.d.ts +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { css, LitElement, html } from 'lit';
|
|
2
|
-
import { createContext, ContextProvider
|
|
3
|
-
import { classMap } from 'lit/directives/class-map.js';
|
|
2
|
+
import { ContextConsumer, createContext, ContextProvider } from '@lit/context';
|
|
4
3
|
import { unsafeStatic, literal, html as html$1 } from 'lit/static-html.js';
|
|
4
|
+
import { classMap } from 'lit/directives/class-map.js';
|
|
5
5
|
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
6
6
|
|
|
7
7
|
var styleCss$1 = css`:focus:not(:focus-visible){outline:3px solid transparent}.body-default{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-weight:var(--wcss-body-weight, 450);letter-spacing:var(--wcss-body-letter-spacing, 0);font-size:var(--wcss-body-default-font-size, 1rem);line-height:var(--wcss-body-default-line-height, 1.5rem)}.body-lg{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-weight:var(--wcss-body-weight, 450);letter-spacing:var(--wcss-body-letter-spacing, 0);font-size:var(--wcss-body-lg-font-size, 1.125rem);line-height:var(--wcss-body-lg-line-height, 1.625rem)}.body-sm{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-weight:var(--wcss-body-weight, 450);letter-spacing:var(--wcss-body-letter-spacing, 0);font-size:var(--wcss-body-sm-font-size, 0.875rem);line-height:var(--wcss-body-sm-line-height, 1.25rem)}.body-xs{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-weight:var(--wcss-body-weight, 450);letter-spacing:var(--wcss-body-letter-spacing, 0);font-size:var(--wcss-body-xs-font-size, 0.75rem);line-height:var(--wcss-body-xs-line-height, 1rem)}.body-2xs{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-weight:var(--wcss-body-weight, 450);letter-spacing:var(--wcss-body-letter-spacing, 0);font-size:var(--wcss-body-2xs-font-size, 0.625rem);line-height:var(--wcss-body-2xs-line-height, 0.875rem)}.display-2xl{font-family:var(--wcss-display-2xl-family, "AS Circular"),var(--wcss-display-2xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-display-2xl-letter-spacing, 0);font-weight:var(--wcss-display-2xl-weight, 300);line-height:var(--wcss-display-2xl-line-height, 1.3);font-size:var(--wcss-display-2xl-font-size, clamp(3.5rem, 6vw, 5.375rem))}.display-xl{font-family:var(--wcss-display-xl-family, "AS Circular"),var(--wcss-display-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-display-xl-letter-spacing, 0);font-weight:var(--wcss-display-xl-weight, 300);line-height:var(--wcss-display-xl-line-height, 1.3);font-size:var(--wcss-display-xl-font-size, clamp(3rem, 5.3333333333vw, 4.5rem))}.display-lg{font-family:var(--wcss-display-lg-family, "AS Circular"),var(--wcss-display-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-display-lg-letter-spacing, 0);font-weight:var(--wcss-display-lg-weight, 300);line-height:var(--wcss-display-lg-line-height, 1.3);font-size:var(--wcss-display-lg-font-size, clamp(2.75rem, 4.6666666667vw, 4rem))}.display-md{font-family:var(--wcss-display-md-family, "AS Circular"),var(--wcss-display-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-display-md-letter-spacing, 0);font-weight:var(--wcss-display-md-weight, 300);line-height:var(--wcss-display-md-line-height, 1.3);font-size:var(--wcss-display-md-font-size, clamp(2.5rem, 4vw, 3.5rem))}.display-sm{font-family:var(--wcss-display-sm-family, "AS Circular"),var(--wcss-display-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-display-sm-letter-spacing, 0);font-weight:var(--wcss-display-sm-weight, 300);line-height:var(--wcss-display-sm-line-height, 1.3);font-size:var(--wcss-display-sm-font-size, clamp(2rem, 3.6666666667vw, 3rem))}.display-xs{font-family:var(--wcss-display-xs-family, "AS Circular"),var(--wcss-display-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-display-xs-letter-spacing, 0);font-weight:var(--wcss-display-xs-weight, 300);line-height:var(--wcss-display-xs-line-height, 1.3);font-size:var(--wcss-display-xs-font-size, clamp(1.75rem, 3vw, 2.375rem))}.heading-xl{font-family:var(--wcss-heading-xl-family, "AS Circular"),var(--wcss-heading-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-heading-xl-letter-spacing, 0);font-weight:var(--wcss-heading-xl-weight, 300);line-height:var(--wcss-heading-xl-line-height, 1.3);font-size:var(--wcss-heading-xl-font-size, clamp(2rem, 3vw, 2.5rem))}.heading-lg{font-family:var(--wcss-heading-lg-family, "AS Circular"),var(--wcss-heading-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-heading-lg-letter-spacing, 0);font-weight:var(--wcss-heading-lg-weight, 300);line-height:var(--wcss-heading-lg-line-height, 1.3);font-size:var(--wcss-heading-lg-font-size, clamp(1.75rem, 2.6666666667vw, 2.25rem))}.heading-md{font-family:var(--wcss-heading-md-family, "AS Circular"),var(--wcss-heading-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-heading-md-letter-spacing, 0);font-weight:var(--wcss-heading-md-weight, 300);line-height:var(--wcss-heading-md-line-height, 1.3);font-size:var(--wcss-heading-md-font-size, clamp(1.625rem, 2.3333333333vw, 1.75rem))}.heading-sm{font-family:var(--wcss-heading-sm-family, "AS Circular"),var(--wcss-heading-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-heading-sm-letter-spacing, 0);font-weight:var(--wcss-heading-sm-weight, 300);line-height:var(--wcss-heading-sm-line-height, 1.3);font-size:var(--wcss-heading-sm-font-size, clamp(1.375rem, 2vw, 1.5rem))}.heading-xs{font-family:var(--wcss-heading-xs-family, "AS Circular"),var(--wcss-heading-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-heading-xs-letter-spacing, 0);font-weight:var(--wcss-heading-xs-weight, 450);line-height:var(--wcss-heading-xs-line-height, 1.3);font-size:var(--wcss-heading-xs-font-size, clamp(1.25rem, 1.6666666667vw, 1.25rem))}.heading-2xs{font-family:var(--wcss-heading-2xs-family, "AS Circular"),var(--wcss-heading-2xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-heading-2xs-letter-spacing, 0);font-weight:var(--wcss-heading-2xs-weight, 450);line-height:var(--wcss-heading-2xs-line-height, 1.3);font-size:var(--wcss-heading-2xs-font-size, clamp(1.125rem, 1.5vw, 1.125rem))}.accent-2xl{font-family:var(--wcss-accent-2xl-family, "Good OT"),var(--wcss-accent-2xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-2xl-letter-spacing, 0.05em);font-weight:var(--wcss-accent-2xl-weight, 450);line-height:var(--wcss-accent-2xl-line-height, 1);font-size:var(--wcss-accent-2xl-font-size, clamp(2rem, 3.1666666667vw, 2.375rem));text-transform:uppercase}.accent-xl{font-family:var(--wcss-accent-xl-family, "Good OT"),var(--wcss-accent-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-xl-letter-spacing, 0.05em);font-weight:var(--wcss-accent-xl-weight, 450);line-height:var(--wcss-accent-xl-line-height, 1.3);font-size:var(--wcss-accent-xl-font-size, clamp(1.625rem, 2.3333333333vw, 2rem));text-transform:uppercase}.accent-lg{font-family:var(--wcss-accent-lg-family, "Good OT"),var(--wcss-accent-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-lg-letter-spacing, 0.05em);font-weight:var(--wcss-accent-lg-weight, 450);line-height:var(--wcss-accent-lg-line-height, 1.3);font-size:var(--wcss-accent-lg-font-size, clamp(1.5rem, 2.1666666667vw, 1.75rem));text-transform:uppercase}.accent-md{font-family:var(--wcss-accent-md-family, "Good OT"),var(--wcss-accent-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-md-letter-spacing, 0.05em);font-weight:var(--wcss-accent-md-weight, 500);line-height:var(--wcss-accent-md-line-height, 1.3);font-size:var(--wcss-accent-md-font-size, clamp(1.375rem, 1.8333333333vw, 1.5rem));text-transform:uppercase}.accent-sm{font-family:var(--wcss-accent-sm-family, "Good OT"),var(--wcss-accent-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-sm-letter-spacing, 0.05em);font-weight:var(--wcss-accent-sm-weight, 500);line-height:var(--wcss-accent-sm-line-height, 1.3);font-size:var(--wcss-accent-sm-font-size, clamp(1.125rem, 1.5vw, 1.25rem));text-transform:uppercase}.accent-xs{font-family:var(--wcss-accent-xs-family, "Good OT"),var(--wcss-accent-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-xs-letter-spacing, 0.1em);font-weight:var(--wcss-accent-xs-weight, 500);line-height:var(--wcss-accent-xs-line-height, 1.3);font-size:var(--wcss-accent-xs-font-size, clamp(1rem, 1.3333333333vw, 1rem));text-transform:uppercase}.accent-2xs{font-family:var(--wcss-accent-2xs-family, "Good OT"),var(--wcss-accent-2xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-2xs-letter-spacing, 0.1em);font-weight:var(--wcss-accent-2xs-weight, 450);line-height:var(--wcss-accent-2xs-line-height, 1.3);font-size:var(--wcss-accent-2xs-font-size, clamp(0.875rem, 1.1666666667vw, 0.875rem));text-transform:uppercase}:host{display:block;line-height:0;overflow-y:auto}:host .menuWrapper{box-sizing:border-box;display:flex;flex-direction:column;width:100%;margin:0;padding:0}:host ::slotted(hr){box-sizing:content-box !important;height:0 !important;overflow:visible !important;margin:var(--ds-size-100, 0.5rem) 0 !important;border-width:0 !important;border-top-width:1px !important;border-top-style:solid !important}:host [loadingplaceholder].empty{opacity:0;position:absolute}:host [loadingplaceholder] slot[name=loadingIcon]{vertical-align:middle;display:inline-block;margin-bottom:var(--ds-size-25, 0.125rem)}:host [loadingplaceholder] slot[name=loadingIcon]::slotted(*){margin-right:var(--ds-size-150, 0.75rem)}:host([root]) .menuWrapper.lg{padding:var(--ds-size-150, 0.75rem);gap:var(--ds-size-50, 0.25rem)}:host([root]) .menuWrapper.xl{padding:var(--ds-size-200, 1rem);gap:var(--ds-size-100, 0.5rem)}`;
|
|
@@ -114,1701 +114,1560 @@ class AuroElement extends LitElement {
|
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
-
/* eslint-disable */
|
|
117
|
+
var styleCss = css`.body-default{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-weight:var(--wcss-body-weight, 450);letter-spacing:var(--wcss-body-letter-spacing, 0);font-size:var(--wcss-body-default-font-size, 1rem);line-height:var(--wcss-body-default-line-height, 1.5rem)}.body-lg{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-weight:var(--wcss-body-weight, 450);letter-spacing:var(--wcss-body-letter-spacing, 0);font-size:var(--wcss-body-lg-font-size, 1.125rem);line-height:var(--wcss-body-lg-line-height, 1.625rem)}.body-sm{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-weight:var(--wcss-body-weight, 450);letter-spacing:var(--wcss-body-letter-spacing, 0);font-size:var(--wcss-body-sm-font-size, 0.875rem);line-height:var(--wcss-body-sm-line-height, 1.25rem)}.body-xs{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-weight:var(--wcss-body-weight, 450);letter-spacing:var(--wcss-body-letter-spacing, 0);font-size:var(--wcss-body-xs-font-size, 0.75rem);line-height:var(--wcss-body-xs-line-height, 1rem)}.body-2xs{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-weight:var(--wcss-body-weight, 450);letter-spacing:var(--wcss-body-letter-spacing, 0);font-size:var(--wcss-body-2xs-font-size, 0.625rem);line-height:var(--wcss-body-2xs-line-height, 0.875rem)}.display-2xl{font-family:var(--wcss-display-2xl-family, "AS Circular"),var(--wcss-display-2xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-display-2xl-letter-spacing, 0);font-weight:var(--wcss-display-2xl-weight, 300);line-height:var(--wcss-display-2xl-line-height, 1.3);font-size:var(--wcss-display-2xl-font-size, clamp(3.5rem, 6vw, 5.375rem))}.display-xl{font-family:var(--wcss-display-xl-family, "AS Circular"),var(--wcss-display-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-display-xl-letter-spacing, 0);font-weight:var(--wcss-display-xl-weight, 300);line-height:var(--wcss-display-xl-line-height, 1.3);font-size:var(--wcss-display-xl-font-size, clamp(3rem, 5.3333333333vw, 4.5rem))}.display-lg{font-family:var(--wcss-display-lg-family, "AS Circular"),var(--wcss-display-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-display-lg-letter-spacing, 0);font-weight:var(--wcss-display-lg-weight, 300);line-height:var(--wcss-display-lg-line-height, 1.3);font-size:var(--wcss-display-lg-font-size, clamp(2.75rem, 4.6666666667vw, 4rem))}.display-md{font-family:var(--wcss-display-md-family, "AS Circular"),var(--wcss-display-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-display-md-letter-spacing, 0);font-weight:var(--wcss-display-md-weight, 300);line-height:var(--wcss-display-md-line-height, 1.3);font-size:var(--wcss-display-md-font-size, clamp(2.5rem, 4vw, 3.5rem))}.display-sm{font-family:var(--wcss-display-sm-family, "AS Circular"),var(--wcss-display-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-display-sm-letter-spacing, 0);font-weight:var(--wcss-display-sm-weight, 300);line-height:var(--wcss-display-sm-line-height, 1.3);font-size:var(--wcss-display-sm-font-size, clamp(2rem, 3.6666666667vw, 3rem))}.display-xs{font-family:var(--wcss-display-xs-family, "AS Circular"),var(--wcss-display-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-display-xs-letter-spacing, 0);font-weight:var(--wcss-display-xs-weight, 300);line-height:var(--wcss-display-xs-line-height, 1.3);font-size:var(--wcss-display-xs-font-size, clamp(1.75rem, 3vw, 2.375rem))}.heading-xl{font-family:var(--wcss-heading-xl-family, "AS Circular"),var(--wcss-heading-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-heading-xl-letter-spacing, 0);font-weight:var(--wcss-heading-xl-weight, 300);line-height:var(--wcss-heading-xl-line-height, 1.3);font-size:var(--wcss-heading-xl-font-size, clamp(2rem, 3vw, 2.5rem))}.heading-lg{font-family:var(--wcss-heading-lg-family, "AS Circular"),var(--wcss-heading-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-heading-lg-letter-spacing, 0);font-weight:var(--wcss-heading-lg-weight, 300);line-height:var(--wcss-heading-lg-line-height, 1.3);font-size:var(--wcss-heading-lg-font-size, clamp(1.75rem, 2.6666666667vw, 2.25rem))}.heading-md{font-family:var(--wcss-heading-md-family, "AS Circular"),var(--wcss-heading-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-heading-md-letter-spacing, 0);font-weight:var(--wcss-heading-md-weight, 300);line-height:var(--wcss-heading-md-line-height, 1.3);font-size:var(--wcss-heading-md-font-size, clamp(1.625rem, 2.3333333333vw, 1.75rem))}.heading-sm{font-family:var(--wcss-heading-sm-family, "AS Circular"),var(--wcss-heading-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-heading-sm-letter-spacing, 0);font-weight:var(--wcss-heading-sm-weight, 300);line-height:var(--wcss-heading-sm-line-height, 1.3);font-size:var(--wcss-heading-sm-font-size, clamp(1.375rem, 2vw, 1.5rem))}.heading-xs{font-family:var(--wcss-heading-xs-family, "AS Circular"),var(--wcss-heading-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-heading-xs-letter-spacing, 0);font-weight:var(--wcss-heading-xs-weight, 450);line-height:var(--wcss-heading-xs-line-height, 1.3);font-size:var(--wcss-heading-xs-font-size, clamp(1.25rem, 1.6666666667vw, 1.25rem))}.heading-2xs{font-family:var(--wcss-heading-2xs-family, "AS Circular"),var(--wcss-heading-2xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-heading-2xs-letter-spacing, 0);font-weight:var(--wcss-heading-2xs-weight, 450);line-height:var(--wcss-heading-2xs-line-height, 1.3);font-size:var(--wcss-heading-2xs-font-size, clamp(1.125rem, 1.5vw, 1.125rem))}.accent-2xl{font-family:var(--wcss-accent-2xl-family, "Good OT"),var(--wcss-accent-2xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-2xl-letter-spacing, 0.05em);font-weight:var(--wcss-accent-2xl-weight, 450);line-height:var(--wcss-accent-2xl-line-height, 1);font-size:var(--wcss-accent-2xl-font-size, clamp(2rem, 3.1666666667vw, 2.375rem));text-transform:uppercase}.accent-xl{font-family:var(--wcss-accent-xl-family, "Good OT"),var(--wcss-accent-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-xl-letter-spacing, 0.05em);font-weight:var(--wcss-accent-xl-weight, 450);line-height:var(--wcss-accent-xl-line-height, 1.3);font-size:var(--wcss-accent-xl-font-size, clamp(1.625rem, 2.3333333333vw, 2rem));text-transform:uppercase}.accent-lg{font-family:var(--wcss-accent-lg-family, "Good OT"),var(--wcss-accent-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-lg-letter-spacing, 0.05em);font-weight:var(--wcss-accent-lg-weight, 450);line-height:var(--wcss-accent-lg-line-height, 1.3);font-size:var(--wcss-accent-lg-font-size, clamp(1.5rem, 2.1666666667vw, 1.75rem));text-transform:uppercase}.accent-md{font-family:var(--wcss-accent-md-family, "Good OT"),var(--wcss-accent-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-md-letter-spacing, 0.05em);font-weight:var(--wcss-accent-md-weight, 500);line-height:var(--wcss-accent-md-line-height, 1.3);font-size:var(--wcss-accent-md-font-size, clamp(1.375rem, 1.8333333333vw, 1.5rem));text-transform:uppercase}.accent-sm{font-family:var(--wcss-accent-sm-family, "Good OT"),var(--wcss-accent-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-sm-letter-spacing, 0.05em);font-weight:var(--wcss-accent-sm-weight, 500);line-height:var(--wcss-accent-sm-line-height, 1.3);font-size:var(--wcss-accent-sm-font-size, clamp(1.125rem, 1.5vw, 1.25rem));text-transform:uppercase}.accent-xs{font-family:var(--wcss-accent-xs-family, "Good OT"),var(--wcss-accent-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-xs-letter-spacing, 0.1em);font-weight:var(--wcss-accent-xs-weight, 500);line-height:var(--wcss-accent-xs-line-height, 1.3);font-size:var(--wcss-accent-xs-font-size, clamp(1rem, 1.3333333333vw, 1rem));text-transform:uppercase}.accent-2xs{font-family:var(--wcss-accent-2xs-family, "Good OT"),var(--wcss-accent-2xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-2xs-letter-spacing, 0.1em);font-weight:var(--wcss-accent-2xs-weight, 450);line-height:var(--wcss-accent-2xs-line-height, 1.3);font-size:var(--wcss-accent-2xs-font-size, clamp(0.875rem, 1.1666666667vw, 0.875rem));text-transform:uppercase}:host{cursor:pointer;user-select:none;text-overflow:ellipsis;max-width:100dvw}:host .wrapper{display:flex;align-items:center;height:var(--ds-size-400, 2rem);padding-right:var(--ds-size-200, 1rem);padding-left:calc(var(--ds-size-150, 0.75rem) + var(--ds-size-300, 1.5rem) + var(--ds-size-100, 0.5rem));border-radius:var(--ds-size-100, 0.5rem);-webkit-tap-highlight-color:transparent}:host .wrapper[class*=shape-box]{border-radius:unset}:host .wrapper[class*=shape-snowflake]{border-radius:unset;line-height:24px}:host .wrapper[class*=shape-pill]{border-radius:30px}:host .wrapper[class*=-lg]{padding-top:var(--ds-size-75, 0.375rem);padding-bottom:var(--ds-size-75, 0.375rem);padding-right:var(--ds-size-150, 0.75rem);line-height:26px}:host .wrapper[class*=-xl]{padding-top:var(--ds-size-100, 0.5rem);padding-bottom:var(--ds-size-100, 0.5rem);padding-right:var(--ds-size-200, 1rem);line-height:26px}:host slot{display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}:host [auro-icon]{--ds-auro-icon-size: var(--ds-size-300, 1.5rem);margin-right:var(--ds-size-150, 0.75rem);margin-left:var(--ds-size-100, 0.5rem)}:host ::slotted(.nestingSpacer){display:inline-block;width:var(--ds-size-300, 1.5rem)}[slot=displayValue]{display:none}:host([loadingplaceholder]) .wrapper{padding-left:calc(var(--ds-size-150, 0.75rem) + var(--ds-size-300, 1.5rem) + var(--ds-size-100, 0.5rem))}:host([selected]) .wrapper{padding-left:0}:host([nocheckmark]) .wrapper{padding-left:var(--ds-size-150, 0.75rem)}:host([nocheckmark]) .wrapper[class*=-lg]{padding-left:var(--ds-size-150, 0.75rem)}:host([nocheckmark]) .wrapper[class*=-xl]{padding-left:var(--ds-size-200, 1rem)}:host([hidden]){display:none}:host([static]){pointer-events:none}:host([disabled]:hover){cursor:auto}:host([disabled]){user-select:none;pointer-events:none}`;
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
var colorCss = css`:host .wrapper{background-color:var(--ds-auro-menuoption-container-color, transparent);box-shadow:inset 0 0 0 1px var(--ds-auro-menuoption-container-border-color, transparent);color:var(--ds-auro-menuoption-text-color)}:host svg{fill:var(--ds-auro-menuoption-icon-color)}:host([disabled]){--ds-auro-menuoption-container-color: var(--ds-basic-color-surface-default, #ffffff);--ds-auro-menuoption-text-color: var(--ds-basic-color-texticon-disabled, #d0d0d0);--ds-auro-menuoption-icon-color: var(--ds-basic-color-texticon-disabled, #d0d0d0)}:host(.active){--ds-auro-menuoption-container-color: var(--ds-basic-color-surface-accent1-muted, #ebfafd)}@media(hover: hover){:host(:hover){--ds-auro-menuoption-container-color: var(--ds-basic-color-surface-accent1-muted, #ebfafd)}}:host(:focus){--ds-auro-menuoption-container-color: var(--ds-basic-color-surface-default, #ffffff);--ds-auro-menuoption-container-border-color: var(--ds-basic-color-border-brand, #00274a)}:host([selected]){--ds-auro-menuoption-container-color: var(--ds-basic-color-surface-accent1-subtle, #b4eff9);--ds-auro-menuoption-text-color: var(--ds-basic-color-texticon-default, #2a2a2a);--ds-auro-menuoption-icon-color: var(--ds-basic-color-texticon-default, #2a2a2a)}:host([selected].active){--ds-auro-menuoption-container-color: var(--ds-basic-color-surface-accent1-muted, #ebfafd)}@media(hover: hover){:host([selected]:hover){--ds-auro-menuoption-container-color: var(--ds-basic-color-surface-accent1-muted, #ebfafd)}}:host([selected]:focus){--ds-auro-menuoption-container-color: var(--ds-basic-color-surface-accent1-subtle, #b4eff9);--ds-auro-menuoption-container-border-color: var(--ds-basic-color-border-brand, #00274a)}:host(:focus.active){--ds-auro-menuoption-container-color: var(--ds-basic-color-surface-accent1-muted, #ebfafd);--ds-auro-menuoption-container-border-color: var(--ds-basic-color-border-brand, #00274a)}@media(hover: hover){:host(:focus:hover){--ds-auro-menuoption-container-color: var(--ds-basic-color-surface-accent1-muted, #ebfafd);--ds-auro-menuoption-container-border-color: var(--ds-basic-color-border-brand, #00274a)}}:host([selected]:focus.active){--ds-auro-menuoption-container-color: var(--ds-basic-color-surface-accent1-muted, #ebfafd);--ds-auro-menuoption-container-border-color: var(--ds-basic-color-border-brand, #00274a)}@media(hover: hover){:host([selected]:focus:hover){--ds-auro-menuoption-container-color: var(--ds-basic-color-surface-accent1-muted, #ebfafd);--ds-auro-menuoption-container-border-color: var(--ds-basic-color-border-brand, #00274a)}}`;
|
|
120
120
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
*/
|
|
121
|
+
// Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
|
|
122
|
+
// See LICENSE in the project root for license information.
|
|
124
123
|
|
|
125
|
-
|
|
126
|
-
* Gets the list of registered menu options.
|
|
127
|
-
* @returns {AuroMenuOption[]}
|
|
128
|
-
*/
|
|
129
|
-
get menuOptions() {
|
|
130
|
-
return this._menuOptions;
|
|
131
|
-
}
|
|
124
|
+
// ---------------------------------------------------------------------
|
|
132
125
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
return this._menuOptions[this.highlightedIndex] || null;
|
|
139
|
-
}
|
|
126
|
+
/* eslint-disable line-comment-position, no-inline-comments, no-confusing-arrow, no-nested-ternary, implicit-arrow-linebreak */
|
|
127
|
+
|
|
128
|
+
class AuroLibraryRuntimeUtils {
|
|
129
|
+
|
|
130
|
+
/* eslint-disable jsdoc/require-param */
|
|
140
131
|
|
|
141
132
|
/**
|
|
142
|
-
*
|
|
143
|
-
* @
|
|
133
|
+
* This will register a new custom element with the browser.
|
|
134
|
+
* @param {String} name - The name of the custom element.
|
|
135
|
+
* @param {Object} componentClass - The class to register as a custom element.
|
|
136
|
+
* @returns {void}
|
|
144
137
|
*/
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
138
|
+
registerComponent(name, componentClass) {
|
|
139
|
+
if (!customElements.get(name)) {
|
|
140
|
+
customElements.define(name, class extends componentClass {});
|
|
141
|
+
}
|
|
148
142
|
}
|
|
149
143
|
|
|
150
144
|
/**
|
|
151
|
-
*
|
|
152
|
-
* @returns {
|
|
145
|
+
* Finds and returns the closest HTML Element based on a selector.
|
|
146
|
+
* @returns {void}
|
|
153
147
|
*/
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
148
|
+
closestElement(
|
|
149
|
+
selector, // selector like in .closest()
|
|
150
|
+
base = this, // extra functionality to skip a parent
|
|
151
|
+
__Closest = (el, found = el && el.closest(selector)) =>
|
|
152
|
+
!el || el === document || el === window
|
|
153
|
+
? null // standard .closest() returns null for non-found selectors also
|
|
154
|
+
: found
|
|
155
|
+
? found // found a selector INside this element
|
|
156
|
+
: __Closest(el.getRootNode().host) // recursion!! break out to parent DOM
|
|
157
|
+
) {
|
|
158
|
+
return __Closest(base);
|
|
157
159
|
}
|
|
160
|
+
/* eslint-enable jsdoc/require-param */
|
|
158
161
|
|
|
159
162
|
/**
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
* @
|
|
163
|
+
* If the element passed is registered with a different tag name than what is passed in, the tag name is added as an attribute to the element.
|
|
164
|
+
* @param {Object} elem - The element to check.
|
|
165
|
+
* @param {String} tagName - The name of the Auro component to check for or add as an attribute.
|
|
166
|
+
* @returns {void}
|
|
163
167
|
*/
|
|
164
|
-
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
if (Array.isArray(currentValue)) {
|
|
168
|
-
if (currentValue.length > 0) {
|
|
169
|
-
return JSON.stringify(currentValue);
|
|
170
|
-
}
|
|
171
|
-
return undefined;
|
|
172
|
-
}
|
|
168
|
+
handleComponentTagRename(elem, tagName) {
|
|
169
|
+
const tag = tagName.toLowerCase();
|
|
170
|
+
const elemTag = elem.tagName.toLowerCase();
|
|
173
171
|
|
|
174
|
-
if (
|
|
175
|
-
|
|
176
|
-
return currentValue;
|
|
177
|
-
}
|
|
178
|
-
return undefined;
|
|
172
|
+
if (elemTag !== tag) {
|
|
173
|
+
elem.setAttribute(tag, true);
|
|
179
174
|
}
|
|
180
|
-
|
|
181
|
-
// Future: handle other types here (e.g., number, object, etc.)
|
|
182
|
-
return undefined;
|
|
183
175
|
}
|
|
184
176
|
|
|
185
177
|
/**
|
|
186
|
-
*
|
|
187
|
-
* @
|
|
178
|
+
* Validates if an element is a specific Auro component.
|
|
179
|
+
* @param {Object} elem - The element to validate.
|
|
180
|
+
* @param {String} tagName - The name of the Auro component to check against.
|
|
181
|
+
* @returns {Boolean} - Returns true if the element is the specified Auro component.
|
|
188
182
|
*/
|
|
189
|
-
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
}
|
|
183
|
+
elementMatch(elem, tagName) {
|
|
184
|
+
const tag = tagName.toLowerCase();
|
|
185
|
+
const elemTag = elem.tagName.toLowerCase();
|
|
193
186
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
*/
|
|
187
|
+
return elemTag === tag || elem.hasAttribute(tag);
|
|
188
|
+
}
|
|
197
189
|
|
|
198
190
|
/**
|
|
199
|
-
*
|
|
200
|
-
* @
|
|
201
|
-
*
|
|
202
|
-
* @throws {Error} If the host is not provided.
|
|
191
|
+
* Gets the text content of a named slot.
|
|
192
|
+
* @returns {String}
|
|
193
|
+
* @private
|
|
203
194
|
*/
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
throw new Error("MenuService requires a host element.");
|
|
209
|
-
}
|
|
195
|
+
getSlotText(elem, name) {
|
|
196
|
+
const slot = elem.shadowRoot?.querySelector(`slot[name="${name}"]`);
|
|
197
|
+
const nodes = slot?.assignedNodes({ flatten: true }) || [];
|
|
198
|
+
const text = nodes.map(n => n.textContent?.trim()).join(' ').trim();
|
|
210
199
|
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
200
|
+
return text || null;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
214
203
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
this.shape = undefined;
|
|
218
|
-
this.noCheckmark = undefined;
|
|
219
|
-
this.disabled = undefined;
|
|
220
|
-
this.matchWord = undefined;
|
|
221
|
-
this.multiSelect = undefined;
|
|
222
|
-
this.allowDeselect = undefined;
|
|
223
|
-
this.selectAllMatchingOptions = undefined;
|
|
204
|
+
// Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
|
|
205
|
+
// See LICENSE in the project root for license information.
|
|
224
206
|
|
|
225
|
-
this.highlightedIndex = -1;
|
|
226
207
|
|
|
227
|
-
|
|
228
|
-
this._subscribers = [];
|
|
229
|
-
this.internalUpdateInProgress = false;
|
|
230
|
-
this.selectedOptions = [];
|
|
231
|
-
this._pendingValue = null;
|
|
232
|
-
this._pendingRetryScheduled = false;
|
|
233
|
-
this._pendingRetryCount = 0;
|
|
234
|
-
}
|
|
208
|
+
class AuroDependencyVersioning {
|
|
235
209
|
|
|
236
210
|
/**
|
|
237
|
-
*
|
|
211
|
+
* Generates a unique string to be used for child auro element naming.
|
|
212
|
+
* @private
|
|
213
|
+
* @param {string} baseName - Defines the first part of the unique element name.
|
|
214
|
+
* @param {string} version - Version of the component that will be appended to the baseName.
|
|
215
|
+
* @returns {string} - Unique string to be used for naming.
|
|
238
216
|
*/
|
|
217
|
+
generateElementName(baseName, version) {
|
|
218
|
+
let result = baseName;
|
|
219
|
+
|
|
220
|
+
result += '-';
|
|
221
|
+
result += version.replace(/[.]/g, '_');
|
|
222
|
+
|
|
223
|
+
return result;
|
|
224
|
+
}
|
|
239
225
|
|
|
240
226
|
/**
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
*
|
|
245
|
-
* You can read more about Lit reactive controllers here: https://lit.dev/docs/composition/controllers/
|
|
227
|
+
* Generates a unique string to be used for child auro element naming.
|
|
228
|
+
* @param {string} baseName - Defines the first part of the unique element name.
|
|
229
|
+
* @param {string} version - Version of the component that will be appended to the baseName.
|
|
230
|
+
* @returns {string} - Unique string to be used for naming.
|
|
246
231
|
*/
|
|
247
|
-
|
|
232
|
+
generateTag(baseName, version, tagClass) {
|
|
233
|
+
const elementName = this.generateElementName(baseName, version);
|
|
234
|
+
const tag = literal`${unsafeStatic(elementName)}`;
|
|
248
235
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
this.selectedOptions = [];
|
|
236
|
+
if (!customElements.get(elementName)) {
|
|
237
|
+
customElements.define(elementName, class extends tagClass {});
|
|
252
238
|
}
|
|
253
239
|
|
|
254
|
-
|
|
255
|
-
this.setProperties({
|
|
256
|
-
size: this.host.size,
|
|
257
|
-
shape: this.host.shape,
|
|
258
|
-
noCheckmark: this.host.noCheckmark,
|
|
259
|
-
disabled: this.host.disabled,
|
|
260
|
-
matchWord: this.host.matchWord,
|
|
261
|
-
multiSelect: this.host.multiSelect,
|
|
262
|
-
allowDeselect: this.host.allowDeselect,
|
|
263
|
-
selectAllMatchingOptions: this.host.selectAllMatchingOptions
|
|
264
|
-
});
|
|
240
|
+
return tag;
|
|
265
241
|
}
|
|
242
|
+
}
|
|
266
243
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
244
|
+
class p{registerComponent(t,a){customElements.get(t)||customElements.define(t,class extends a{});}closestElement(t,a=this,e=(a,s=a&&a.closest(t))=>a&&a!==document&&a!==window?s||e(a.getRootNode().host):null){return e(a)}handleComponentTagRename(t,a){const e=a.toLowerCase();t.tagName.toLowerCase()!==e&&t.setAttribute(e,true);}elementMatch(t,a){const e=a.toLowerCase();return t.tagName.toLowerCase()===e||t.hasAttribute(e)}getSlotText(t,a){const e=t.shadowRoot?.querySelector(`slot[name="${a}"]`);return (e?.assignedNodes({flatten:true})||[]).map(t=>t.textContent?.trim()).join(" ").trim()||null}}var u='<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-labelledby="error__desc" class="ico_squareLarge" data-deprecated="true" role="img" style="min-width:var(--auro-size-lg, var(--ds-size-300, 1.5rem));height:var(--auro-size-lg, var(--ds-size-300, 1.5rem));fill:currentColor" viewBox="0 0 24 24" part="svg"><title/><desc id="error__desc">Error alert indicator.</desc><path d="m13.047 5.599 6.786 11.586A1.207 1.207 0 0 1 18.786 19H5.214a1.207 1.207 0 0 1-1.047-1.815l6.786-11.586a1.214 1.214 0 0 1 2.094 0m-1.165.87a.23.23 0 0 0-.085.085L5.419 17.442a.232.232 0 0 0 .203.35h12.756a.234.234 0 0 0 .203-.35L12.203 6.554a.236.236 0 0 0-.321-.084M12 15.5a.75.75 0 1 1 0 1.5.75.75 0 0 1 0-1.5m-.024-6.22c.325 0 .589.261.589.583v4.434a.586.586 0 0 1-.589.583.586.586 0 0 1-.588-.583V9.863c0-.322.264-.583.588-.583"/></svg>';class m extends LitElement{static get properties(){return {hidden:{type:Boolean,reflect:true},hiddenVisually:{type:Boolean,reflect:true},hiddenAudible:{type:Boolean,reflect:true}}}hideAudible(t){return t?"true":"false"}}const g=new Map,f=(t,a={})=>{const e=a.responseParser||(t=>t.text());return g.has(t)||g.set(t,fetch(t).then(e)),g.get(t)};var w=css`:focus:not(:focus-visible){outline:3px solid transparent}.util_displayInline{display:inline}.util_displayInlineBlock{display:inline-block}.util_displayBlock,:host{display:block}.util_displayFlex{display:flex}.util_displayHidden,:host([hidden]:not(:focus):not(:active)){display:none}.util_displayHiddenVisually,:host([hiddenVisually]:not(:focus):not(:active)){position:absolute;overflow:hidden;clip:rect(1px,1px,1px,1px);width:1px;height:1px;padding:0;border:0}.ico_squareLarge{fill:currentColor;height:var(--auro-size-lg, var(--ds-size-300, 1.5rem))}.ico_squareSmall{fill:currentColor;height:.6rem}.ico_squareMed{fill:currentColor;height:var(--auro-size-md, var(--ds-size-200, 1rem))}.ico_squareSml{fill:currentColor;height:var(--auro-size-sm, var(--ds-size-150, .75rem))}:host{color:currentColor;vertical-align:middle;display:inline-block}svg{min-width:var(--ds-auro-icon-size, 1.5rem)!important;width:var(--ds-auro-icon-size, 1.5rem)!important;height:var(--ds-auro-icon-size, 1.5rem)!important}.componentWrapper{display:flex;line-height:var(--ds-auro-icon-size)}.svgWrapper{height:var(--ds-auro-icon-size);width:var(--ds-auro-icon-size)}.svgWrapper [part=svg]{display:flex}.labelWrapper{margin-left:var(--ds-size-50, .25rem)}.labelWrapper ::slotted(*){line-height:inherit!important}
|
|
245
|
+
`;class z extends m{constructor(){super(),this._initializeDefaults();}_initializeDefaults(){this.onDark=false,this.appearance="default";}static get properties(){return {...m.properties,onDark:{type:Boolean,reflect:true},appearance:{type:String,reflect:true},svg:{attribute:false,reflect:true}}}static get styles(){return w}async fetchIcon(t,a){let e="";e="logos"===t?await f(`${this.uri}/${t}/${a}.svg`):await f(`${this.uri}/icons/${t}/${a}.svg`);return (new DOMParser).parseFromString(e,"text/html").body.querySelector("svg")}async firstUpdated(){try{if(!this.customSvg){const t=await this.fetchIcon(this.category,this.name);if(t)this.svg=t;else if(!t){const t=(new DOMParser).parseFromString(u,"text/html");this.svg=t.body.firstChild;}}}catch(t){this.svg=void 0;}}}css`.util_displayInline{display:inline}.util_displayInlineBlock{display:inline-block}.util_displayBlock,:host{display:block}.util_displayFlex{display:flex}.util_displayHidden,:host([hidden]:not(:focus):not(:active)){display:none}.util_displayHiddenVisually,:host([hiddenVisually]:not(:focus):not(:active)){position:absolute;overflow:hidden;clip:rect(1px,1px,1px,1px);width:1px;height:1px;padding:0;border:0}:host{display:inline-block;--ds-auro-icon-size: 100%;width:100%;height:100%}:host .logo{color:var(--ds-auro-alaska-color)}:host([onDark]),:host([appearance=inverse]){--ds-auro-alaska-color: #FFF}
|
|
246
|
+
`;var y=css`:host{--ds-auro-icon-color: var(--ds-basic-color-texticon-default, #2a2a2a);--ds-auro-alaska-color: #02426D;--ds-auro-icon-size: var(--ds-size-300, 1.5rem)}
|
|
247
|
+
`;var x=css`:host{color:var(--ds-auro-icon-color)}:host([customColor]){color:inherit}:host(:not([onDark])[variant=accent1]),:host(:not([appearance=inverse])[variant=accent1]){--ds-auro-icon-color: var(--ds-basic-color-texticon-accent1, #265688)}:host(:not([onDark])[variant=disabled]),:host(:not([appearance=inverse])[variant=disabled]){--ds-auro-icon-color: var(--ds-basic-color-texticon-disabled, #d0d0d0)}:host(:not([onDark])[variant=muted]),:host(:not([appearance=inverse])[variant=muted]){--ds-auro-icon-color: var(--ds-basic-color-texticon-muted, #676767)}:host(:not([onDark])[variant=statusDefault]),:host(:not([appearance=inverse])[variant=statusDefault]){--ds-auro-icon-color: var(--ds-basic-color-status-default, #afb9c6)}:host(:not([onDark])[variant=statusInfo]),:host(:not([appearance=inverse])[variant=statusInfo]){--ds-auro-icon-color: var(--ds-basic-color-status-info, #01426a)}:host(:not([onDark])[variant=statusSuccess]),:host(:not([appearance=inverse])[variant=statusSuccess]){--ds-auro-icon-color: var(--ds-basic-color-status-success, #447a1f)}:host(:not([onDark])[variant=statusWarning]),:host(:not([appearance=inverse])[variant=statusWarning]){--ds-auro-icon-color: var(--ds-basic-color-status-warning, #fac200)}:host(:not([onDark])[variant=statusError]),:host(:not([appearance=inverse])[variant=statusError]){--ds-auro-icon-color: var(--ds-basic-color-status-error, #e31f26)}:host(:not([onDark])[variant=statusInfoSubtle]),:host(:not([appearance=inverse])[variant=statusInfoSubtle]){--ds-auro-icon-color: var(--ds-basic-color-status-info-subtle, #ebf3f9)}:host(:not([onDark])[variant=statusSuccessSubtle]),:host(:not([appearance=inverse])[variant=statusSuccessSubtle]){--ds-auro-icon-color: var(--ds-basic-color-status-success-subtle, #d6eac7)}:host(:not([onDark])[variant=statusWarningSubtle]),:host(:not([appearance=inverse])[variant=statusWarningSubtle]){--ds-auro-icon-color: var(--ds-basic-color-status-warning-subtle, #fff0b2)}:host(:not([onDark])[variant=statusErrorSubtle]),:host(:not([appearance=inverse])[variant=statusErrorSubtle]){--ds-auro-icon-color: var(--ds-basic-color-status-error-subtle, #fbc6c6)}:host(:not([onDark])[variant=fareBasicEconomy]),:host(:not([appearance=inverse])[variant=fareBasicEconomy]){--ds-auro-icon-color: var(--ds-basic-color-fare-basiceconomy, #97eaf8)}:host(:not([onDark])[variant=fareBusiness]),:host(:not([appearance=inverse])[variant=fareBusiness]){--ds-auro-icon-color: var(--ds-basic-color-fare-business, #01426a)}:host(:not([onDark])[variant=fareEconomy]),:host(:not([appearance=inverse])[variant=fareEconomy]){--ds-auro-icon-color: var(--ds-basic-color-fare-economy, #0074ca)}:host(:not([onDark])[variant=fareFirst]),:host(:not([appearance=inverse])[variant=fareFirst]){--ds-auro-icon-color: var(--ds-basic-color-fare-first, #00274a)}:host(:not([onDark])[variant=farePremiumEconomy]),:host(:not([appearance=inverse])[variant=farePremiumEconomy]){--ds-auro-icon-color: var(--ds-basic-color-fare-premiumeconomy, #005154)}:host(:not([onDark])[variant=tierOneWorldEmerald]),:host(:not([appearance=inverse])[variant=tierOneWorldEmerald]){--ds-auro-icon-color: var(--ds-basic-color-tier-program-oneworld-emerald, #139142)}:host(:not([onDark])[variant=tierOneWorldSapphire]),:host(:not([appearance=inverse])[variant=tierOneWorldSapphire]){--ds-auro-icon-color: var(--ds-basic-color-tier-program-oneworld-sapphire, #015daa)}:host(:not([onDark])[variant=tierOneWorldRuby]),:host(:not([appearance=inverse])[variant=tierOneWorldRuby]){--ds-auro-icon-color: var(--ds-basic-color-tier-program-oneworld-ruby, #a41d4a)}:host([onDark]),:host([appearance=inverse]){--ds-auro-icon-color: var(--ds-basic-color-texticon-inverse, #ffffff)}:host([onDark][variant=disabled]),:host([appearance=inverse][variant=disabled]){--ds-auro-icon-color: var(--ds-basic-color-texticon-inverse-disabled, #7e8894)}:host([onDark][variant=muted]),:host([appearance=inverse][variant=muted]){--ds-auro-icon-color: var(--ds-basic-color-texticon-inverse-muted, #ccd2db)}:host([onDark][variant=statusError]),:host([appearance=inverse][variant=statusError]){--ds-auro-icon-color: var(--ds-advanced-color-state-error-inverse, #f9a4a8)}
|
|
248
|
+
`;class _ extends z{constructor(){super(),this._initializeDefaults();}_initializeDefaults(){this.variant=void 0,this.uri="https://cdn.jsdelivr.net/npm/@alaskaairux/icons@latest/dist",this.runtimeUtils=new p;}static get properties(){return {...z.properties,ariaHidden:{type:String,reflect:true},category:{type:String,reflect:true},customColor:{type:Boolean,reflect:true},customSvg:{type:Boolean},label:{type:Boolean,reflect:true},name:{type:String,reflect:true},variant:{type:String,reflect:true}}}static get styles(){return [z.styles,y,w,x]}static register(t="auro-icon"){p.prototype.registerComponent(t,_);}connectedCallback(){super.connectedCallback(),this.runtimeUtils.handleComponentTagRename(this,"auro-icon");}exposeCssParts(){this.setAttribute("exportparts","svg:iconSvg");}async firstUpdated(){if(await super.firstUpdated(),this.hasAttribute("ariaHidden")&&this.svg){const t=this.svg.querySelector("desc");t&&(t.remove(),this.svg.removeAttribute("aria-labelledby"));}}render(){const t={labelWrapper:true,util_displayHiddenVisually:!this.label};return html`
|
|
249
|
+
<div class="componentWrapper">
|
|
250
|
+
<div
|
|
251
|
+
class="${classMap({svgWrapper:true})}"
|
|
252
|
+
title="${ifDefined(this.title||void 0)}">
|
|
253
|
+
<span aria-hidden="${ifDefined(this.ariaHidden||true)}" part="svg">
|
|
254
|
+
${this.customSvg?html`
|
|
255
|
+
<slot name="svg"></slot>
|
|
256
|
+
`:html`
|
|
257
|
+
${this.svg}
|
|
258
|
+
`}
|
|
259
|
+
</span>
|
|
260
|
+
</div>
|
|
277
261
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
setProperty(property, value) {
|
|
262
|
+
<div class="${classMap(t)}" part="label">
|
|
263
|
+
<slot></slot>
|
|
264
|
+
</div>
|
|
265
|
+
</div>
|
|
266
|
+
`}}
|
|
284
267
|
|
|
285
|
-
|
|
286
|
-
if (this.hasOwnProperty(property)) {
|
|
268
|
+
var iconVersion = '9.1.2';
|
|
287
269
|
|
|
288
|
-
|
|
289
|
-
const valueChanged = this[property] !== value;
|
|
270
|
+
var checkmarkIcon = {"svg":"<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" aria-labelledby=\"checkmark-sm__desc\" class=\"ico_squareLarge\" role=\"img\" style=\"min-width:var(--auro-size-lg, var(--ds-size-300, 1.5rem));height:var(--auro-size-lg, var(--ds-size-300, 1.5rem));fill:currentColor\" viewBox=\"0 0 24 24\" part=\"svg\"><title/><desc id=\"checkmark-sm__desc\">a small check mark.</desc><path d=\"M8.461 11.84a.625.625 0 1 0-.922.844l2.504 2.738c.247.27.674.27.922 0l5.496-6a.625.625 0 1 0-.922-.844l-5.035 5.496z\"/></svg>"};
|
|
290
271
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
this[property] = value;
|
|
294
|
-
this.notify({ property, value });
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
}
|
|
272
|
+
// Copyright (c) 2021 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
273
|
+
// See LICENSE in the project root for license information.
|
|
298
274
|
|
|
299
|
-
|
|
300
|
-
* Sets multiple properties on the instance.
|
|
301
|
-
* @param {Object} properties - Key-value pairs of properties to set.
|
|
302
|
-
*/
|
|
303
|
-
setProperties(properties) {
|
|
304
|
-
for (const [key, value] of Object.entries(properties)) {
|
|
305
|
-
this.setProperty(key, value);
|
|
306
|
-
}
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
* MENU OPTION HIGHLIGHTING
|
|
311
|
-
*/
|
|
275
|
+
// ---------------------------------------------------------------------
|
|
312
276
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
277
|
+
/**
|
|
278
|
+
* Converts value to an array.
|
|
279
|
+
* If the value is a JSON string representing an array, it will be parsed.
|
|
280
|
+
* If the value is already an array, it is returned.
|
|
281
|
+
* If the value is undefined, it returns undefined.
|
|
282
|
+
* @private
|
|
283
|
+
* @param {any} value - The value to be converted. Can be a string, array, or undefined.
|
|
284
|
+
* @returns {Array|undefined} - The converted array or undefined.
|
|
285
|
+
* @throws {Error} - Throws an error if the value is not an array, undefined,
|
|
286
|
+
* or if the value cannot be parsed into an array from a JSON string.
|
|
287
|
+
*/
|
|
288
|
+
function arrayConverter(value) {
|
|
289
|
+
// Allow undefined
|
|
290
|
+
if (value === undefined) {
|
|
291
|
+
return undefined;
|
|
318
292
|
}
|
|
319
293
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
highlightPrevious() {
|
|
324
|
-
this.moveHighlightedOption("previous");
|
|
294
|
+
// Return the value if it is already an array
|
|
295
|
+
if (Array.isArray(value)) {
|
|
296
|
+
return value;
|
|
325
297
|
}
|
|
326
298
|
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
*/
|
|
331
|
-
moveHighlightedOption(direction) {
|
|
299
|
+
try {
|
|
300
|
+
// If value is a JSON string, parse it
|
|
301
|
+
const parsed = typeof value === 'string' ? JSON.parse(value) : value;
|
|
332
302
|
|
|
333
|
-
//
|
|
334
|
-
|
|
303
|
+
// Check if the parsed value is an array
|
|
304
|
+
if (Array.isArray(parsed)) {
|
|
305
|
+
return parsed;
|
|
306
|
+
}
|
|
307
|
+
} catch (error) {
|
|
308
|
+
// If JSON parsing fails, continue to throw an error below
|
|
309
|
+
/* eslint-disable no-console */
|
|
310
|
+
console.error('JSON parsing failed:', error);
|
|
311
|
+
}
|
|
335
312
|
|
|
336
|
-
|
|
337
|
-
|
|
313
|
+
// Throw error if the input is not an array or undefined
|
|
314
|
+
throw new Error('Invalid value: Input must be an array or undefined');
|
|
315
|
+
}
|
|
338
316
|
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
317
|
+
/**
|
|
318
|
+
* Validates if an option can be interacted with.
|
|
319
|
+
* @private
|
|
320
|
+
* @param {HTMLElement} option - The option to check.
|
|
321
|
+
* @returns {boolean} True if option is interactive.
|
|
322
|
+
*/
|
|
323
|
+
function isOptionInteractive(option) {
|
|
324
|
+
return !option.hasAttribute('hidden') &&
|
|
325
|
+
!option.hasAttribute('disabled') &&
|
|
326
|
+
!option.hasAttribute('static');
|
|
327
|
+
}
|
|
347
328
|
|
|
348
|
-
|
|
349
|
-
|
|
329
|
+
/**
|
|
330
|
+
* Helper method to dispatch custom events.
|
|
331
|
+
* @param {HTMLElement} element - Element to dispatch event from.
|
|
332
|
+
* @param {string} eventName - Name of the event to dispatch.
|
|
333
|
+
* @param {Object} [detail] - Optional detail object to include with the event.
|
|
334
|
+
*/
|
|
335
|
+
function dispatchMenuEvent(element, eventName, detail = null) {
|
|
336
|
+
const eventConfig = {
|
|
337
|
+
bubbles: true,
|
|
338
|
+
cancelable: false,
|
|
339
|
+
composed: true
|
|
340
|
+
};
|
|
350
341
|
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
this.setHighlightedOption(newActiveOption);
|
|
342
|
+
if (detail !== null) {
|
|
343
|
+
eventConfig.detail = detail;
|
|
354
344
|
}
|
|
355
345
|
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
* @param {AuroMenuOption} option - The option to highlight.
|
|
359
|
-
*/
|
|
360
|
-
setHighlightedOption(option) {
|
|
361
|
-
|
|
362
|
-
if (!option) return;
|
|
346
|
+
element.dispatchEvent(new CustomEvent(eventName, eventConfig));
|
|
347
|
+
}
|
|
363
348
|
|
|
364
|
-
|
|
365
|
-
|
|
349
|
+
// Copyright (c) 2021 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
350
|
+
// See LICENSE in the project root for license information.
|
|
366
351
|
|
|
367
|
-
// Update highlighted index
|
|
368
|
-
this.highlightedIndex = index;
|
|
369
352
|
|
|
370
|
-
|
|
371
|
-
this.notify({ type: 'highlightChange', option, index: this.highlightedIndex });
|
|
353
|
+
let menuOptionIdCounter = 0;
|
|
372
354
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
355
|
+
/**
|
|
356
|
+
* The `auro-menuoption` element provides users a way to define a menu option.
|
|
357
|
+
* @customElement auro-menuoption
|
|
358
|
+
*
|
|
359
|
+
* @slot default - The default slot for the menu option text.
|
|
360
|
+
*
|
|
361
|
+
* @event auroMenuOption-mouseover - Notifies that this option has been hovered over.
|
|
362
|
+
*/
|
|
363
|
+
class AuroMenuOption extends AuroElement {
|
|
376
364
|
|
|
377
365
|
/**
|
|
378
|
-
*
|
|
379
|
-
* @param {
|
|
366
|
+
* This will register this element with the browser.
|
|
367
|
+
* @param {string} [name="auro-menuoption"] - The name of the element that you want to register.
|
|
368
|
+
*
|
|
369
|
+
* @example
|
|
370
|
+
* AuroMenuOption.register("custom-menuoption") // this will register this element to <custom-menuoption/>
|
|
371
|
+
*
|
|
380
372
|
*/
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
this.setHighlightedOption(option);
|
|
373
|
+
static register(name = "auro-menuoption") {
|
|
374
|
+
AuroLibraryRuntimeUtils.prototype.registerComponent(name, AuroMenuOption);
|
|
384
375
|
}
|
|
385
376
|
|
|
386
377
|
/**
|
|
387
|
-
*
|
|
378
|
+
* Returns whether the menu option is currently active and selectable.
|
|
379
|
+
* An option is considered active if it is not hidden, not disabled, and not static.
|
|
380
|
+
* @returns {boolean} True if the option is active, false otherwise.
|
|
388
381
|
*/
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
this.
|
|
392
|
-
|
|
382
|
+
get isActive() {
|
|
383
|
+
return !this.hasAttribute('hidden') &&
|
|
384
|
+
!this.disabled &&
|
|
385
|
+
!this.hasAttribute('static');
|
|
393
386
|
}
|
|
394
387
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
*/
|
|
388
|
+
constructor() {
|
|
389
|
+
super();
|
|
398
390
|
|
|
399
|
-
|
|
400
|
-
* Selects one or more options in a batch operation
|
|
401
|
-
* @param {AuroMenuOption|AuroMenuOption[]} options - Single option or array of options to select
|
|
402
|
-
*/
|
|
403
|
-
selectOptions(options) {
|
|
404
|
-
let optionsToSelect = Array.isArray(options) ? options : [options];
|
|
391
|
+
this.bindEvents();
|
|
405
392
|
|
|
406
|
-
|
|
407
|
-
|
|
393
|
+
/**
|
|
394
|
+
* @private
|
|
395
|
+
*/
|
|
396
|
+
this.shape = undefined;
|
|
408
397
|
|
|
409
|
-
|
|
398
|
+
/**
|
|
399
|
+
* @private
|
|
400
|
+
*/
|
|
401
|
+
this.size = undefined;
|
|
410
402
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
}
|
|
403
|
+
/**
|
|
404
|
+
* Generate unique names for dependency components.
|
|
405
|
+
*/
|
|
406
|
+
const versioning = new AuroDependencyVersioning();
|
|
407
|
+
this.iconTag = versioning.generateTag('auro-formkit-menuoption-icon', iconVersion, _);
|
|
417
408
|
|
|
418
|
-
this.
|
|
419
|
-
|
|
409
|
+
this.selected = false;
|
|
410
|
+
this.noCheckmark = false;
|
|
411
|
+
this.disabled = false;
|
|
412
|
+
this.noMatch = false;
|
|
420
413
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
deselectOptions(options) {
|
|
426
|
-
const optionsToDeselect = Array.isArray(options) ? options : [options];
|
|
414
|
+
/**
|
|
415
|
+
* @private
|
|
416
|
+
*/
|
|
417
|
+
this.runtimeUtils = new AuroLibraryRuntimeUtils();
|
|
427
418
|
|
|
428
|
-
|
|
419
|
+
// Initialize context-related properties
|
|
420
|
+
this.menuService = null;
|
|
421
|
+
this.unsubscribe = null;
|
|
429
422
|
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
423
|
+
/**
|
|
424
|
+
* @private
|
|
425
|
+
*/
|
|
426
|
+
this.handleMenuChange = this.handleMenuChange.bind(this);
|
|
427
|
+
}
|
|
433
428
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
option.selected = true;
|
|
438
|
-
});
|
|
439
|
-
this.dispatchChangeEvent('auroMenu-deselectPrevented', {
|
|
440
|
-
values: optionsToDeselect
|
|
441
|
-
});
|
|
442
|
-
return;
|
|
443
|
-
}
|
|
429
|
+
static get properties() {
|
|
430
|
+
return {
|
|
431
|
+
...super.properties,
|
|
444
432
|
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
433
|
+
/**
|
|
434
|
+
* When true, disables the menu option.
|
|
435
|
+
*/
|
|
436
|
+
disabled: {
|
|
437
|
+
type: Boolean,
|
|
438
|
+
reflect: true
|
|
439
|
+
},
|
|
448
440
|
|
|
449
|
-
|
|
450
|
-
|
|
441
|
+
/**
|
|
442
|
+
* @private
|
|
443
|
+
*/
|
|
444
|
+
event: {
|
|
445
|
+
type: String,
|
|
446
|
+
reflect: true
|
|
447
|
+
},
|
|
451
448
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
}
|
|
449
|
+
/**
|
|
450
|
+
* @private
|
|
451
|
+
*/
|
|
452
|
+
layout: {
|
|
453
|
+
type: String
|
|
454
|
+
},
|
|
459
455
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
456
|
+
/**
|
|
457
|
+
* Allows users to set a unique key for the menu option for specified option selection. If no key is provided, the value property will be used.
|
|
458
|
+
*/
|
|
459
|
+
key: {
|
|
460
|
+
type: String,
|
|
461
|
+
reflect: true
|
|
462
|
+
},
|
|
467
463
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
464
|
+
/**
|
|
465
|
+
* @private
|
|
466
|
+
*/
|
|
467
|
+
menuService: {
|
|
468
|
+
type: Object,
|
|
469
|
+
state: true
|
|
470
|
+
},
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* @private
|
|
474
|
+
*/
|
|
475
|
+
matchWord: {
|
|
476
|
+
type: String,
|
|
477
|
+
state: true
|
|
478
|
+
},
|
|
479
|
+
|
|
480
|
+
/**
|
|
481
|
+
* @private
|
|
482
|
+
*/
|
|
483
|
+
noCheckmark: {
|
|
484
|
+
type: Boolean,
|
|
485
|
+
reflect: true
|
|
486
|
+
},
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* When true, marks this option as the "no matching results" placeholder shown by combobox when the user's input does not match any available options. Enables distinct styling and prevents the option from being treated as a selectable match.
|
|
490
|
+
*/
|
|
491
|
+
noMatch: {
|
|
492
|
+
type: Boolean,
|
|
493
|
+
reflect: true,
|
|
494
|
+
attribute: 'nomatch'
|
|
495
|
+
},
|
|
496
|
+
|
|
497
|
+
/**
|
|
498
|
+
* Specifies that an option is selected.
|
|
499
|
+
*/
|
|
500
|
+
selected: {
|
|
501
|
+
type: Boolean,
|
|
502
|
+
reflect: true
|
|
503
|
+
},
|
|
504
|
+
|
|
505
|
+
/**
|
|
506
|
+
* Specifies the tab index of the menu option.
|
|
507
|
+
*/
|
|
508
|
+
tabIndex: {
|
|
509
|
+
type: Number,
|
|
510
|
+
reflect: true
|
|
511
|
+
},
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Specifies the value to be sent to a server.
|
|
515
|
+
*/
|
|
516
|
+
value: {
|
|
517
|
+
type: String,
|
|
518
|
+
reflect: true
|
|
519
|
+
},
|
|
520
|
+
};
|
|
478
521
|
}
|
|
479
522
|
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
value === null ||
|
|
488
|
-
(Array.isArray(value) && value.length === 0) ||
|
|
489
|
-
(typeof value === 'string' && value.trim() === '');
|
|
523
|
+
static get styles() {
|
|
524
|
+
return [
|
|
525
|
+
styleCss,
|
|
526
|
+
colorCss,
|
|
527
|
+
tokensCss
|
|
528
|
+
];
|
|
529
|
+
}
|
|
490
530
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
this.selectedOptions.forEach(opt => opt.selected = false);
|
|
494
|
-
this.selectedOptions = [];
|
|
495
|
-
return;
|
|
496
|
-
}
|
|
531
|
+
connectedCallback() {
|
|
532
|
+
super.connectedCallback();
|
|
497
533
|
|
|
498
|
-
//
|
|
499
|
-
//
|
|
500
|
-
|
|
501
|
-
this.queuePendingValue(value);
|
|
502
|
-
return;
|
|
503
|
-
}
|
|
534
|
+
// Add the tag name as an attribute if it is different than the component name
|
|
535
|
+
// Add this step soon as this node gets attached to the DOM to avoid racing condition with menu's value setting logic.
|
|
536
|
+
this.runtimeUtils.handleComponentTagRename(this, 'auro-menuoption');
|
|
504
537
|
|
|
505
|
-
//
|
|
506
|
-
|
|
538
|
+
// Set up context consumption in connectedCallback
|
|
539
|
+
this._contextConsumer = new ContextConsumer(this, {
|
|
540
|
+
context: MenuContext,
|
|
541
|
+
callback: this.attachTo.bind(this),
|
|
542
|
+
subscribe: true
|
|
543
|
+
});
|
|
507
544
|
|
|
508
|
-
//
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
545
|
+
// Establish the key property as early as possible.
|
|
546
|
+
// When a framework (e.g. Svelte) inserts the element into the DOM before
|
|
547
|
+
// setting its `value` property, both `getAttribute('value')` and
|
|
548
|
+
// `getAttribute('key')` return null here. Setting `this.key = null`
|
|
549
|
+
// would block the fallback in `updated()` that assigns key from the
|
|
550
|
+
// value property (the guard checked `=== undefined`). Only assign key
|
|
551
|
+
// if at least one source attribute is actually present so that the
|
|
552
|
+
// `updated()` fallback can run when the value property arrives later.
|
|
553
|
+
const valueAttr = this.getAttribute('value');
|
|
554
|
+
const keyAttr = this.getAttribute('key');
|
|
555
|
+
const resolvedKey = keyAttr !== null ? keyAttr : valueAttr;
|
|
556
|
+
if (resolvedKey !== null) {
|
|
557
|
+
this.key = resolvedKey;
|
|
513
558
|
}
|
|
559
|
+
}
|
|
514
560
|
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
}
|
|
561
|
+
firstUpdated() {
|
|
562
|
+
// Add the tag name as an attribute if it is different than the component name
|
|
563
|
+
this.runtimeUtils.handleComponentTagRename(this, 'auro-menuoption');
|
|
519
564
|
|
|
520
|
-
//
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
const isActive = option.isActive;
|
|
565
|
+
// Generate unique ID if not already set (required for aria-activedescendant)
|
|
566
|
+
if (!this.id) {
|
|
567
|
+
menuOptionIdCounter += 1;
|
|
568
|
+
this.id = `menuoption-${menuOptionIdCounter}`;
|
|
569
|
+
}
|
|
526
570
|
|
|
527
|
-
|
|
571
|
+
this.setAttribute('role', 'option');
|
|
572
|
+
this.setAttribute('aria-selected', 'false');
|
|
528
573
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
574
|
+
this.addEventListener('mouseover', () => {
|
|
575
|
+
this.dispatchEvent(new CustomEvent('auroMenuOption-mouseover', {
|
|
576
|
+
bubbles: true,
|
|
577
|
+
cancelable: false,
|
|
578
|
+
composed: true,
|
|
579
|
+
detail: this
|
|
580
|
+
}));
|
|
532
581
|
});
|
|
582
|
+
}
|
|
533
583
|
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
if (!optionsToSelect.length) {
|
|
537
|
-
const hasUnresolvedKeys = this._menuOptions.some((option) => option.isActive && option.key == null);
|
|
584
|
+
updated(changedProperties) {
|
|
585
|
+
super.updated(changedProperties);
|
|
538
586
|
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
return;
|
|
542
|
-
}
|
|
587
|
+
// Update aria-selected attribute if selected changed
|
|
588
|
+
if (changedProperties.has('selected')) {
|
|
543
589
|
|
|
544
|
-
|
|
590
|
+
// Update aria-selected attribute
|
|
591
|
+
this.setAttribute('aria-selected', this.selected.toString());
|
|
545
592
|
|
|
546
|
-
if
|
|
547
|
-
|
|
593
|
+
// Update menu service selection state if this isn't an internal update
|
|
594
|
+
if (this.internalUpdateInProgress !== true) {
|
|
595
|
+
this.menuService[this.selected ? 'selectOption' : 'deselectOption'](this);
|
|
548
596
|
}
|
|
597
|
+
}
|
|
549
598
|
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
if (validatedValues.length) {
|
|
556
|
-
this.dispatchChangeEvent('auroMenu-selectValueFailure', {
|
|
557
|
-
message: 'No matching options found for the provided value(s).',
|
|
558
|
-
values: validatedValues
|
|
559
|
-
});
|
|
599
|
+
if (changedProperties.has('disabled')) {
|
|
600
|
+
if (this.disabled) {
|
|
601
|
+
this.setAttribute('aria-disabled', 'true');
|
|
602
|
+
} else {
|
|
603
|
+
this.removeAttribute('aria-disabled');
|
|
560
604
|
}
|
|
605
|
+
}
|
|
561
606
|
|
|
562
|
-
|
|
607
|
+
if (changedProperties.has('active')) {
|
|
608
|
+
this.updateActiveClasses();
|
|
563
609
|
}
|
|
564
610
|
|
|
565
|
-
|
|
611
|
+
// Update text highlight if matchWord changed
|
|
612
|
+
if (changedProperties.has('matchWord')) {
|
|
613
|
+
this.updateTextHighlight();
|
|
614
|
+
}
|
|
566
615
|
|
|
567
|
-
if
|
|
568
|
-
|
|
616
|
+
// Set the key to be the passed value if no key is provided.
|
|
617
|
+
// Loose equality (== null) is intentional: it catches both null AND
|
|
618
|
+
// undefined. When a framework (e.g. Svelte, React) inserts the element
|
|
619
|
+
// before setting its value property, connectedCallback skips key
|
|
620
|
+
// assignment because both attributes are null at that point. The Lit
|
|
621
|
+
// property default for `key` is undefined (not null), so strict
|
|
622
|
+
// === null would miss the case and the fallback would never run.
|
|
623
|
+
if (changedProperties.has('value') && this.key == null) { // eslint-disable-line eqeqeq, no-eq-null
|
|
624
|
+
this.key = this.value;
|
|
569
625
|
}
|
|
626
|
+
}
|
|
570
627
|
|
|
571
|
-
|
|
572
|
-
this.
|
|
573
|
-
|
|
628
|
+
disconnectedCallback() {
|
|
629
|
+
if (this.menuService) {
|
|
630
|
+
this.menuService.unsubscribe(this.handleMenuChange);
|
|
631
|
+
this.menuService.removeMenuOption(this);
|
|
632
|
+
}
|
|
574
633
|
}
|
|
575
634
|
|
|
576
635
|
/**
|
|
577
|
-
*
|
|
578
|
-
*
|
|
636
|
+
* Sets up event listeners for user interaction with the menu option.
|
|
637
|
+
* This function enables click and mouse enter events to trigger selection and highlighting logic.
|
|
579
638
|
*/
|
|
580
|
-
|
|
581
|
-
this.
|
|
639
|
+
bindEvents() {
|
|
640
|
+
this.addEventListener('click', this.handleClick.bind(this));
|
|
641
|
+
this.addEventListener('mouseenter', this.handleMouseEnter.bind(this));
|
|
642
|
+
}
|
|
582
643
|
|
|
583
|
-
|
|
644
|
+
/**
|
|
645
|
+
* Attaches this menu option to a menu service and subscribes to its events.
|
|
646
|
+
* This method enables the option to participate in menu selection and highlighting logic.
|
|
647
|
+
* @param {Object} service - The menu service instance to attach to.
|
|
648
|
+
*/
|
|
649
|
+
attachTo(service) {
|
|
650
|
+
if (!service) {
|
|
584
651
|
return;
|
|
585
652
|
}
|
|
653
|
+
this.menuService = service;
|
|
654
|
+
this.menuService.addMenuOption(this);
|
|
655
|
+
this.menuService.subscribe(this.handleMenuChange);
|
|
656
|
+
}
|
|
586
657
|
|
|
587
|
-
|
|
588
|
-
|
|
658
|
+
/**
|
|
659
|
+
* Handles changes from the menu service and updates the option's state.
|
|
660
|
+
* This function synchronizes the option's properties and selection/highlight state with menu events.
|
|
661
|
+
* @param {Object} event - The event object from the menu service.
|
|
662
|
+
*/
|
|
663
|
+
handleMenuChange(event) {
|
|
589
664
|
|
|
590
|
-
|
|
591
|
-
|
|
665
|
+
// Ignore events without a type or property
|
|
666
|
+
if (!event || (!event.type && !event.property)) {
|
|
667
|
+
return;
|
|
668
|
+
}
|
|
592
669
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
670
|
+
// Update reactive properties based on event type
|
|
671
|
+
if (event.property && Object.keys(AuroMenuOption.properties).includes(event.property)) {
|
|
672
|
+
this[event.property] = event.value;
|
|
673
|
+
}
|
|
596
674
|
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
675
|
+
// Handle highlight changes
|
|
676
|
+
if (event.type === 'highlightChange') {
|
|
677
|
+
const isActive = event.option === this;
|
|
678
|
+
this.active = isActive;
|
|
679
|
+
this.updateActiveClasses();
|
|
680
|
+
}
|
|
601
681
|
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
this._pendingValue = null;
|
|
607
|
-
this._pendingRetryScheduled = false;
|
|
608
|
-
this._pendingRetryCount = 0;
|
|
682
|
+
if (event.type === 'stateChange') {
|
|
683
|
+
const isSelected = event.selectedOptions.includes(this);
|
|
684
|
+
this.setInternalSelected(isSelected);
|
|
685
|
+
}
|
|
609
686
|
}
|
|
610
687
|
|
|
611
688
|
/**
|
|
612
|
-
*
|
|
689
|
+
* Updates the internal selected state of the menu option bypassing 'updated' and triggers custom events if selected.
|
|
690
|
+
* This function ensures the option's selection state is synchronized with menu logic and notifies listeners.
|
|
691
|
+
* @param {boolean} isSelected - Whether the option should be marked as selected.
|
|
613
692
|
*/
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
this.selectedOptions = [];
|
|
693
|
+
setInternalSelected(isSelected) {
|
|
694
|
+
this.internalUpdateInProgress = true;
|
|
695
|
+
this.selected = isSelected;
|
|
618
696
|
|
|
619
|
-
//
|
|
620
|
-
if (
|
|
621
|
-
this.
|
|
697
|
+
// Fire custom event if selected
|
|
698
|
+
if (isSelected) {
|
|
699
|
+
this.handleCustomEvent();
|
|
622
700
|
}
|
|
701
|
+
|
|
702
|
+
setTimeout(() => {
|
|
703
|
+
this.internalUpdateInProgress = false;
|
|
704
|
+
}, 0);
|
|
623
705
|
}
|
|
624
706
|
|
|
625
707
|
/**
|
|
626
|
-
*
|
|
708
|
+
* Sets the selected state of the menu option.
|
|
709
|
+
* This function updates whether the option is currently selected.
|
|
710
|
+
* @param {boolean} isSelected - Whether the option should be marked as selected.
|
|
711
|
+
* @deprecated Simply modify the `selected` property directly instead.
|
|
627
712
|
*/
|
|
713
|
+
setSelected(isSelected) {
|
|
714
|
+
this.selected = isSelected;
|
|
715
|
+
}
|
|
628
716
|
|
|
629
717
|
/**
|
|
630
|
-
*
|
|
631
|
-
*
|
|
718
|
+
* Updates the active state and visual highlighting of the menu option.
|
|
719
|
+
* This function toggles the option's active status and applies or removes the active CSS class.
|
|
720
|
+
* @param {boolean} isActive - Whether the option should be marked as active.
|
|
721
|
+
* @deprecated Simply modify the `active` property directly instead.
|
|
632
722
|
*/
|
|
633
|
-
|
|
634
|
-
|
|
723
|
+
updateActive(isActive) {
|
|
724
|
+
|
|
725
|
+
// Set active state
|
|
726
|
+
this.active = isActive;
|
|
727
|
+
this.updateActiveClasses();
|
|
635
728
|
}
|
|
636
729
|
|
|
637
730
|
/**
|
|
638
|
-
*
|
|
639
|
-
*
|
|
731
|
+
* Updates the CSS class for the menu option based on its active state.
|
|
732
|
+
* This function adds or removes the 'active' class to visually indicate the option's active status.
|
|
733
|
+
* @private
|
|
640
734
|
*/
|
|
641
|
-
|
|
642
|
-
|
|
735
|
+
updateActiveClasses() {
|
|
736
|
+
// Update class based on active state
|
|
737
|
+
if (this.active) this.classList.add('active');
|
|
738
|
+
else this.classList.remove('active');
|
|
643
739
|
}
|
|
644
740
|
|
|
741
|
+
|
|
645
742
|
/**
|
|
646
|
-
*
|
|
743
|
+
* Updates the visual highlighting of text within the menu option based on the current match word.
|
|
744
|
+
* This function highlights matching text segments and manages nested spacers for display formatting.
|
|
745
|
+
* @private
|
|
647
746
|
*/
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
747
|
+
updateTextHighlight() {
|
|
748
|
+
|
|
749
|
+
// Regex for matchWord if needed
|
|
750
|
+
let regexWord = null;
|
|
751
|
+
|
|
752
|
+
if (this.matchWord && this.matchWord.length) {
|
|
753
|
+
const escapedWord = this.matchWord.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
754
|
+
regexWord = new RegExp(escapedWord, 'giu');
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
// Update text highlighting if matchWord changed
|
|
758
|
+
if (regexWord &&
|
|
759
|
+
this.isActive && !this.hasAttribute('persistent')) {
|
|
760
|
+
const nested = this.querySelectorAll('.nestingSpacer');
|
|
761
|
+
|
|
762
|
+
const displayValueEl = this.querySelector('[slot="displayValue"]');
|
|
763
|
+
if (displayValueEl) {
|
|
764
|
+
this.removeChild(displayValueEl);
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
// Create nested spacers
|
|
768
|
+
const nestingSpacerBundle = [...nested].map(() => this.nestingSpacer).join('');
|
|
769
|
+
|
|
770
|
+
// Update with spacers and matchWord
|
|
771
|
+
this.innerHTML = nestingSpacerBundle +
|
|
772
|
+
this.textContent.replace(
|
|
773
|
+
regexWord,
|
|
774
|
+
(match) => `<strong>${match}</strong>`
|
|
775
|
+
);
|
|
776
|
+
if (displayValueEl) {
|
|
777
|
+
this.append(displayValueEl);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
651
780
|
}
|
|
652
781
|
|
|
653
782
|
/**
|
|
654
|
-
*
|
|
655
|
-
*
|
|
656
|
-
* @
|
|
783
|
+
* Handles click events on the menu option, toggling its selected state.
|
|
784
|
+
* This function dispatches a click event and updates selection if the option is not disabled.
|
|
785
|
+
* @private
|
|
657
786
|
*/
|
|
658
|
-
|
|
659
|
-
this.
|
|
787
|
+
handleClick() {
|
|
788
|
+
if (!this.disabled) {
|
|
789
|
+
this.dispatchClickEvent();
|
|
790
|
+
this.selected = !this.selected;
|
|
791
|
+
}
|
|
660
792
|
}
|
|
661
793
|
|
|
662
794
|
/**
|
|
663
|
-
*
|
|
795
|
+
* Handles mouse enter events to highlight the menu option.
|
|
796
|
+
* This function updates the menu service to set this option as the currently highlighted item if not disabled.
|
|
797
|
+
* @private
|
|
664
798
|
*/
|
|
665
|
-
|
|
666
|
-
this.
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
...meta
|
|
670
|
-
});
|
|
799
|
+
handleMouseEnter() {
|
|
800
|
+
if (!this.disabled) {
|
|
801
|
+
this.menuService.setHighlightedOption(this);
|
|
802
|
+
}
|
|
671
803
|
}
|
|
672
804
|
|
|
673
805
|
/**
|
|
674
|
-
*
|
|
806
|
+
* Dispatches custom events defined for this menu option.
|
|
807
|
+
* This function notifies listeners when a custom event is triggered by the option.
|
|
808
|
+
* @private
|
|
675
809
|
*/
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
stringValue: this.stringValue,
|
|
682
|
-
keys: this.currentKeys,
|
|
683
|
-
options: this.selectedOptions,
|
|
684
|
-
label: this.currentLabel
|
|
685
|
-
};
|
|
686
|
-
|
|
687
|
-
// If only one option is selected, include its index
|
|
688
|
-
if (this.selectedOptions.length === 1) details.index = this._menuOptions.indexOf(this.selectedOptions[0]);
|
|
689
|
-
|
|
690
|
-
this.notify({
|
|
691
|
-
type: 'valueChange',
|
|
692
|
-
...meta,
|
|
693
|
-
...details
|
|
694
|
-
});
|
|
810
|
+
handleCustomEvent() {
|
|
811
|
+
if (this.event) {
|
|
812
|
+
dispatchMenuEvent(this, this.event, { option: this });
|
|
813
|
+
dispatchMenuEvent(this, 'auroMenu-customEventFired', { option: this });
|
|
814
|
+
}
|
|
695
815
|
}
|
|
696
816
|
|
|
697
817
|
/**
|
|
698
|
-
* Dispatches a
|
|
699
|
-
*
|
|
700
|
-
* @
|
|
818
|
+
* Dispatches a click event for this menu option.
|
|
819
|
+
* This function notifies listeners that the option has been clicked.
|
|
820
|
+
* @private
|
|
701
821
|
*/
|
|
702
|
-
|
|
703
|
-
this.
|
|
822
|
+
dispatchClickEvent() {
|
|
823
|
+
this.dispatchEvent(new CustomEvent('auroMenuOption-click', {
|
|
704
824
|
bubbles: true,
|
|
705
825
|
cancelable: false,
|
|
706
826
|
composed: true,
|
|
707
|
-
detail
|
|
827
|
+
detail: this
|
|
708
828
|
}));
|
|
709
829
|
}
|
|
710
830
|
|
|
711
831
|
/**
|
|
712
|
-
*
|
|
832
|
+
* Generates an HTML element containing an SVG icon based on the provided `svgContent`.
|
|
833
|
+
*
|
|
834
|
+
* @private
|
|
835
|
+
* @param {string} svgContent - The SVG content to be embedded.
|
|
836
|
+
* @returns {Element} The HTML element containing the SVG icon.
|
|
713
837
|
*/
|
|
838
|
+
generateIconHtml(svgContent) {
|
|
839
|
+
const dom = new DOMParser().parseFromString(svgContent, 'text/html');
|
|
840
|
+
const svg = dom.body.firstChild;
|
|
714
841
|
|
|
715
|
-
|
|
716
|
-
* Adds a menu option to the service's list.
|
|
717
|
-
* @param {AuroMenuOption} option - the option to track
|
|
718
|
-
*/
|
|
719
|
-
addMenuOption(option) {
|
|
720
|
-
this._menuOptions.push(option);
|
|
721
|
-
this.notify({ type: 'optionsChange', options: this._menuOptions });
|
|
842
|
+
svg.setAttribute('slot', 'svg');
|
|
722
843
|
|
|
723
|
-
|
|
724
|
-
this.queuePendingValue(this._pendingValue);
|
|
725
|
-
}
|
|
844
|
+
return html$1`<${this.iconTag} customColor customSvg>${svg}</${this.iconTag}>`;
|
|
726
845
|
}
|
|
727
846
|
|
|
728
847
|
/**
|
|
729
|
-
*
|
|
730
|
-
* @
|
|
848
|
+
* Logic to determine the layout of the component.
|
|
849
|
+
* @protected
|
|
850
|
+
* @returns {void}
|
|
731
851
|
*/
|
|
732
|
-
|
|
733
|
-
this._menuOptions = this._menuOptions.filter(opt => opt !== option);
|
|
734
|
-
this.notify({ type: 'optionsChange', options: this._menuOptions });
|
|
852
|
+
renderLayout() {
|
|
735
853
|
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
854
|
+
const fontClassMap = {
|
|
855
|
+
xs: 'body-sm',
|
|
856
|
+
sm: 'body-default',
|
|
857
|
+
md: 'body-default',
|
|
858
|
+
lg: 'body-lg',
|
|
859
|
+
xl: 'body-lg'
|
|
860
|
+
};
|
|
740
861
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
/**
|
|
746
|
-
* Normalizes a value or array of values into an array of strings for option selection.
|
|
747
|
-
* This function ensures that input values are consistently formatted for matching menu options.
|
|
748
|
-
*
|
|
749
|
-
* @param {string|number|Array<string|number>} value - The value(s) to normalize.
|
|
750
|
-
* @returns {Array<string>} An array of string values suitable for option matching.
|
|
751
|
-
* @throws {Error} If any value is not a string or number.
|
|
752
|
-
*/
|
|
753
|
-
_getNormalizedValues(value) {
|
|
754
|
-
let values = value;
|
|
862
|
+
const classes = classMap({
|
|
863
|
+
'wrapper': true,
|
|
864
|
+
[this.size ? fontClassMap[this.size] : 'body-sm']: true,
|
|
865
|
+
});
|
|
755
866
|
|
|
756
|
-
|
|
757
|
-
|
|
867
|
+
return html$1`
|
|
868
|
+
<div class="${classes}">
|
|
869
|
+
${this.selected && !this.noCheckmark
|
|
870
|
+
? this.generateIconHtml(checkmarkIcon.svg)
|
|
871
|
+
: undefined}
|
|
872
|
+
<slot></slot>
|
|
873
|
+
</div>
|
|
874
|
+
`;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
758
877
|
|
|
759
|
-
|
|
760
|
-
try {
|
|
878
|
+
/* eslint-disable */
|
|
761
879
|
|
|
762
|
-
|
|
763
|
-
// This will not handle complex cases but will cover basic usage
|
|
764
|
-
const parseValue = values.replace(/'([^']*?)'/g, '"$1"');
|
|
880
|
+
class MenuService {
|
|
765
881
|
|
|
766
|
-
|
|
767
|
-
|
|
882
|
+
/**
|
|
883
|
+
* PROPERTIES AND GETTERS
|
|
884
|
+
*/
|
|
768
885
|
|
|
769
|
-
|
|
770
|
-
|
|
886
|
+
/**
|
|
887
|
+
* Gets the list of registered menu options.
|
|
888
|
+
* @returns {AuroMenuOption[]}
|
|
889
|
+
*/
|
|
890
|
+
get menuOptions() {
|
|
891
|
+
return this._menuOptions;
|
|
892
|
+
}
|
|
771
893
|
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
894
|
+
/**
|
|
895
|
+
* Gets the currently highlighted option.
|
|
896
|
+
* @returns {AuroMenuOption|null}
|
|
897
|
+
*/
|
|
898
|
+
get highlightedOption() {
|
|
899
|
+
return this._menuOptions[this.highlightedIndex] || null;
|
|
900
|
+
}
|
|
775
901
|
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
902
|
+
/**
|
|
903
|
+
* Gets the current value(s) of the selected option(s).
|
|
904
|
+
* @returns {string|string[]|undefined}
|
|
905
|
+
*/
|
|
906
|
+
get currentValue() {
|
|
907
|
+
const values = (this.selectedOptions || []).map(option => option.value);
|
|
908
|
+
return this.multiSelect ? values : values[0];
|
|
909
|
+
}
|
|
780
910
|
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
911
|
+
/**
|
|
912
|
+
* Gets the label(s) of the currently selected option(s).
|
|
913
|
+
* @returns {string}
|
|
914
|
+
*/
|
|
915
|
+
get currentLabel() {
|
|
916
|
+
const labels = (this.selectedOptions || []).map(option => option.textContent);
|
|
917
|
+
return this.multiSelect ? labels.join(", ") : labels[0] || '';
|
|
918
|
+
}
|
|
785
919
|
|
|
786
|
-
|
|
787
|
-
|
|
920
|
+
/**
|
|
921
|
+
* Gets the string representation of the current value(s).
|
|
922
|
+
* For multi-select, this is a JSON stringified array.
|
|
923
|
+
* @returns {string|undefined}
|
|
924
|
+
*/
|
|
925
|
+
get stringValue() {
|
|
926
|
+
const { currentValue } = this;
|
|
788
927
|
|
|
789
|
-
|
|
790
|
-
if (
|
|
791
|
-
|
|
928
|
+
if (Array.isArray(currentValue)) {
|
|
929
|
+
if (currentValue.length > 0) {
|
|
930
|
+
return JSON.stringify(currentValue);
|
|
792
931
|
}
|
|
932
|
+
return undefined;
|
|
933
|
+
}
|
|
793
934
|
|
|
794
|
-
|
|
795
|
-
if (
|
|
796
|
-
|
|
935
|
+
if (typeof currentValue === 'string') {
|
|
936
|
+
if (currentValue.length > 0) {
|
|
937
|
+
return currentValue;
|
|
797
938
|
}
|
|
798
|
-
|
|
939
|
+
return undefined;
|
|
940
|
+
}
|
|
799
941
|
|
|
800
|
-
//
|
|
801
|
-
return
|
|
942
|
+
// Future: handle other types here (e.g., number, object, etc.)
|
|
943
|
+
return undefined;
|
|
802
944
|
}
|
|
803
945
|
|
|
804
946
|
/**
|
|
805
|
-
*
|
|
806
|
-
* @
|
|
807
|
-
* @param {AuroMenuOption[]} arr2 - Second array of options.
|
|
808
|
-
* @returns {boolean} True if arrays match, false otherwise.
|
|
947
|
+
* Gets the key(s) of the currently selected option(s).
|
|
948
|
+
* @returns {string|string[]|undefined}
|
|
809
949
|
*/
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
const set1 = new Set(arr1);
|
|
814
|
-
const set2 = new Set(arr2);
|
|
815
|
-
|
|
816
|
-
for (let item of set1) {
|
|
817
|
-
if (!set2.has(item)) {
|
|
818
|
-
return false;
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
|
|
822
|
-
return true;
|
|
950
|
+
get currentKeys() {
|
|
951
|
+
const keys = (this.selectedOptions || []).map(option => option.key);
|
|
952
|
+
return this.multiSelect ? keys : keys[0];
|
|
823
953
|
}
|
|
824
|
-
}
|
|
825
954
|
|
|
826
|
-
|
|
955
|
+
/**
|
|
956
|
+
* CONSTRUCTOR
|
|
957
|
+
*/
|
|
827
958
|
|
|
828
|
-
|
|
829
|
-
|
|
959
|
+
/**
|
|
960
|
+
* Creates a new MenuService instance.
|
|
961
|
+
* @param {Object} options - The options object.
|
|
962
|
+
* @param {AuroMenu} options.host - The host element that this service will control. Required.
|
|
963
|
+
* @throws {Error} If the host is not provided.
|
|
964
|
+
*/
|
|
965
|
+
constructor({ host } = {}) {
|
|
830
966
|
|
|
831
|
-
//
|
|
967
|
+
// Ensure a host was passed
|
|
968
|
+
if (!host) {
|
|
969
|
+
throw new Error("MenuService requires a host element.");
|
|
970
|
+
}
|
|
832
971
|
|
|
833
|
-
|
|
972
|
+
// Attach the service to the host
|
|
973
|
+
this.host = host;
|
|
974
|
+
this.host.addController(this);
|
|
834
975
|
|
|
835
|
-
|
|
976
|
+
// Set default properties
|
|
977
|
+
this.size = undefined;
|
|
978
|
+
this.shape = undefined;
|
|
979
|
+
this.noCheckmark = undefined;
|
|
980
|
+
this.disabled = undefined;
|
|
981
|
+
this.matchWord = undefined;
|
|
982
|
+
this.multiSelect = undefined;
|
|
983
|
+
this.allowDeselect = undefined;
|
|
984
|
+
this.selectAllMatchingOptions = undefined;
|
|
836
985
|
|
|
837
|
-
|
|
986
|
+
this.highlightedIndex = -1;
|
|
838
987
|
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
if (!customElements.get(name)) {
|
|
847
|
-
customElements.define(name, class extends componentClass {});
|
|
848
|
-
}
|
|
988
|
+
this._menuOptions = [];
|
|
989
|
+
this._subscribers = [];
|
|
990
|
+
this.internalUpdateInProgress = false;
|
|
991
|
+
this.selectedOptions = [];
|
|
992
|
+
this._pendingValue = null;
|
|
993
|
+
this._pendingRetryScheduled = false;
|
|
994
|
+
this._pendingRetryCount = 0;
|
|
849
995
|
}
|
|
850
996
|
|
|
851
997
|
/**
|
|
852
|
-
*
|
|
853
|
-
* @returns {void}
|
|
998
|
+
* PROPERTY SYNCING
|
|
854
999
|
*/
|
|
855
|
-
closestElement(
|
|
856
|
-
selector, // selector like in .closest()
|
|
857
|
-
base = this, // extra functionality to skip a parent
|
|
858
|
-
__Closest = (el, found = el && el.closest(selector)) =>
|
|
859
|
-
!el || el === document || el === window
|
|
860
|
-
? null // standard .closest() returns null for non-found selectors also
|
|
861
|
-
: found
|
|
862
|
-
? found // found a selector INside this element
|
|
863
|
-
: __Closest(el.getRootNode().host) // recursion!! break out to parent DOM
|
|
864
|
-
) {
|
|
865
|
-
return __Closest(base);
|
|
866
|
-
}
|
|
867
|
-
/* eslint-enable jsdoc/require-param */
|
|
868
1000
|
|
|
869
1001
|
/**
|
|
870
|
-
*
|
|
871
|
-
*
|
|
872
|
-
*
|
|
873
|
-
*
|
|
1002
|
+
* Handles host updates.
|
|
1003
|
+
* This is a lit reactive lifecycle method.
|
|
1004
|
+
* This comes from the Lit controller interface provided by adding this service as a controller to the host.
|
|
1005
|
+
* See constructor for `this.host.addController(this)`
|
|
1006
|
+
* You can read more about Lit reactive controllers here: https://lit.dev/docs/composition/controllers/
|
|
874
1007
|
*/
|
|
875
|
-
|
|
876
|
-
const tag = tagName.toLowerCase();
|
|
877
|
-
const elemTag = elem.tagName.toLowerCase();
|
|
1008
|
+
hostUpdated() {
|
|
878
1009
|
|
|
879
|
-
if
|
|
880
|
-
|
|
1010
|
+
// Reset selection if multiSelect mode changes
|
|
1011
|
+
if (this.host.multiSelect !== this.multiSelect) {
|
|
1012
|
+
this.selectedOptions = [];
|
|
881
1013
|
}
|
|
1014
|
+
|
|
1015
|
+
// Update properties on host update
|
|
1016
|
+
this.setProperties({
|
|
1017
|
+
size: this.host.size,
|
|
1018
|
+
shape: this.host.shape,
|
|
1019
|
+
noCheckmark: this.host.noCheckmark,
|
|
1020
|
+
disabled: this.host.disabled,
|
|
1021
|
+
matchWord: this.host.matchWord,
|
|
1022
|
+
multiSelect: this.host.multiSelect,
|
|
1023
|
+
allowDeselect: this.host.allowDeselect,
|
|
1024
|
+
selectAllMatchingOptions: this.host.selectAllMatchingOptions
|
|
1025
|
+
});
|
|
882
1026
|
}
|
|
883
1027
|
|
|
884
1028
|
/**
|
|
885
|
-
*
|
|
886
|
-
* @param {Object} elem - The element to validate.
|
|
887
|
-
* @param {String} tagName - The name of the Auro component to check against.
|
|
888
|
-
* @returns {Boolean} - Returns true if the element is the specified Auro component.
|
|
1029
|
+
* Handles host disconnection and memory cleanup.
|
|
889
1030
|
*/
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
1031
|
+
hostDisconnected() {
|
|
1032
|
+
this._subscribers = [];
|
|
1033
|
+
this._menuOptions = [];
|
|
1034
|
+
this._pendingValue = null;
|
|
1035
|
+
this._pendingRetryScheduled = false;
|
|
1036
|
+
this._pendingRetryCount = 0;
|
|
895
1037
|
}
|
|
896
1038
|
|
|
897
1039
|
/**
|
|
898
|
-
*
|
|
899
|
-
* @
|
|
900
|
-
* @
|
|
1040
|
+
* Sets a property value if it exists on the instance and the value has changed.
|
|
1041
|
+
* @param {string} property
|
|
1042
|
+
* @param {any} value
|
|
901
1043
|
*/
|
|
902
|
-
|
|
903
|
-
const slot = elem.shadowRoot?.querySelector(`slot[name="${name}"]`);
|
|
904
|
-
const nodes = slot?.assignedNodes({ flatten: true }) || [];
|
|
905
|
-
const text = nodes.map(n => n.textContent?.trim()).join(' ').trim();
|
|
906
|
-
|
|
907
|
-
return text || null;
|
|
908
|
-
}
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
// Copyright (c) 2021 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
912
|
-
// See LICENSE in the project root for license information.
|
|
913
|
-
|
|
914
|
-
// ---------------------------------------------------------------------
|
|
915
|
-
|
|
916
|
-
/**
|
|
917
|
-
* Converts value to an array.
|
|
918
|
-
* If the value is a JSON string representing an array, it will be parsed.
|
|
919
|
-
* If the value is already an array, it is returned.
|
|
920
|
-
* If the value is undefined, it returns undefined.
|
|
921
|
-
* @private
|
|
922
|
-
* @param {any} value - The value to be converted. Can be a string, array, or undefined.
|
|
923
|
-
* @returns {Array|undefined} - The converted array or undefined.
|
|
924
|
-
* @throws {Error} - Throws an error if the value is not an array, undefined,
|
|
925
|
-
* or if the value cannot be parsed into an array from a JSON string.
|
|
926
|
-
*/
|
|
927
|
-
function arrayConverter(value) {
|
|
928
|
-
// Allow undefined
|
|
929
|
-
if (value === undefined) {
|
|
930
|
-
return undefined;
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
// Return the value if it is already an array
|
|
934
|
-
if (Array.isArray(value)) {
|
|
935
|
-
return value;
|
|
936
|
-
}
|
|
937
|
-
|
|
938
|
-
try {
|
|
939
|
-
// If value is a JSON string, parse it
|
|
940
|
-
const parsed = typeof value === 'string' ? JSON.parse(value) : value;
|
|
941
|
-
|
|
942
|
-
// Check if the parsed value is an array
|
|
943
|
-
if (Array.isArray(parsed)) {
|
|
944
|
-
return parsed;
|
|
945
|
-
}
|
|
946
|
-
} catch (error) {
|
|
947
|
-
// If JSON parsing fails, continue to throw an error below
|
|
948
|
-
/* eslint-disable no-console */
|
|
949
|
-
console.error('JSON parsing failed:', error);
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
// Throw error if the input is not an array or undefined
|
|
953
|
-
throw new Error('Invalid value: Input must be an array or undefined');
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
/**
|
|
957
|
-
* Validates if an option can be interacted with.
|
|
958
|
-
* @private
|
|
959
|
-
* @param {HTMLElement} option - The option to check.
|
|
960
|
-
* @returns {boolean} True if option is interactive.
|
|
961
|
-
*/
|
|
962
|
-
function isOptionInteractive(option) {
|
|
963
|
-
return !option.hasAttribute('hidden') &&
|
|
964
|
-
!option.hasAttribute('disabled') &&
|
|
965
|
-
!option.hasAttribute('static');
|
|
966
|
-
}
|
|
967
|
-
|
|
968
|
-
/**
|
|
969
|
-
* Helper method to dispatch custom events.
|
|
970
|
-
* @param {HTMLElement} element - Element to dispatch event from.
|
|
971
|
-
* @param {string} eventName - Name of the event to dispatch.
|
|
972
|
-
* @param {Object} [detail] - Optional detail object to include with the event.
|
|
973
|
-
*/
|
|
974
|
-
function dispatchMenuEvent(element, eventName, detail = null) {
|
|
975
|
-
const eventConfig = {
|
|
976
|
-
bubbles: true,
|
|
977
|
-
cancelable: false,
|
|
978
|
-
composed: true
|
|
979
|
-
};
|
|
980
|
-
|
|
981
|
-
if (detail !== null) {
|
|
982
|
-
eventConfig.detail = detail;
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
element.dispatchEvent(new CustomEvent(eventName, eventConfig));
|
|
986
|
-
}
|
|
987
|
-
|
|
988
|
-
/* eslint-disable no-underscore-dangle */
|
|
989
|
-
// Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
990
|
-
// See LICENSE in the project root for license information.
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
/**
|
|
995
|
-
* The `auro-menu` element provides users a way to select from a list of options.
|
|
996
|
-
* @customElement auro-menu
|
|
997
|
-
*
|
|
998
|
-
* @event {CustomEvent<Element>} auroMenu-activatedOption - Notifies that a menuoption has been made `active`.
|
|
999
|
-
* @event {CustomEvent<any>} auroMenu-customEventFired - Notifies that a custom event has been fired.
|
|
1000
|
-
* @event {CustomEvent<{ loading: boolean; hasLoadingPlaceholder: boolean; }>} auroMenu-loadingChange - Notifies when the loading attribute is changed.
|
|
1001
|
-
* @event {CustomEvent<any>} auroMenu-selectValueFailure - Notifies that an attempt to select a menuoption by matching a value has failed.
|
|
1002
|
-
* @event {CustomEvent<{ values: HTMLElement[] }>} auroMenu-deselectPrevented - Notifies that deselection was prevented and includes the affected options in `detail.values`.
|
|
1003
|
-
* @event {CustomEvent<any>} auroMenu-selectValueReset - Notifies that the component value has been reset.
|
|
1004
|
-
* @event {CustomEvent<any>} auroMenu-selectedOption - Notifies that a new menuoption selection has been made.
|
|
1005
|
-
* @slot loadingText - Text to show while loading attribute is set
|
|
1006
|
-
* @slot loadingIcon - Icon to show while loading attribute is set
|
|
1007
|
-
* @slot - Slot for insertion of menu options.
|
|
1008
|
-
*/
|
|
1009
|
-
|
|
1010
|
-
/* eslint-disable max-lines */
|
|
1011
|
-
|
|
1012
|
-
class AuroMenu extends AuroElement {
|
|
1013
|
-
|
|
1014
|
-
constructor() {
|
|
1015
|
-
super();
|
|
1016
|
-
|
|
1017
|
-
// State properties (reactive)
|
|
1018
|
-
|
|
1019
|
-
/**
|
|
1020
|
-
* @private
|
|
1021
|
-
*/
|
|
1022
|
-
this.shape = "box";
|
|
1023
|
-
|
|
1024
|
-
/**
|
|
1025
|
-
* @private
|
|
1026
|
-
*/
|
|
1027
|
-
this.size = "sm";
|
|
1028
|
-
|
|
1029
|
-
// Value of the selected options
|
|
1030
|
-
this.value = undefined;
|
|
1031
|
-
// Currently selected option
|
|
1032
|
-
this.optionSelected = undefined;
|
|
1033
|
-
// String used for highlighting/filtering
|
|
1034
|
-
this.matchWord = undefined;
|
|
1035
|
-
// Hide the checkmark icon on selected options
|
|
1036
|
-
this.noCheckmark = false;
|
|
1037
|
-
// Currently active option
|
|
1038
|
-
this.optionActive = undefined;
|
|
1039
|
-
// Loading state
|
|
1040
|
-
this.loading = false;
|
|
1041
|
-
// Multi-select mode
|
|
1042
|
-
this.multiSelect = false;
|
|
1043
|
-
// Allow deselecting of menu options
|
|
1044
|
-
this.allowDeselect = false;
|
|
1045
|
-
// Select all matching options when setting value in multi-select mode
|
|
1046
|
-
this.selectAllMatchingOptions = false;
|
|
1047
|
-
|
|
1048
|
-
// Event Bindings
|
|
1049
|
-
|
|
1050
|
-
/**
|
|
1051
|
-
* @private
|
|
1052
|
-
*/
|
|
1053
|
-
this.handleSlotChange = this.handleSlotChange.bind(this);
|
|
1054
|
-
|
|
1055
|
-
// Instance properties (non-reactive)
|
|
1056
|
-
|
|
1057
|
-
/**
|
|
1058
|
-
* @private
|
|
1059
|
-
*/
|
|
1060
|
-
Object.assign(this, {
|
|
1061
|
-
// Root-level menu (true) or a nested submenu (false)
|
|
1062
|
-
rootMenu: true,
|
|
1063
|
-
// Currently focused/active menu item index
|
|
1064
|
-
_index: -1,
|
|
1065
|
-
// Nested menu spacer
|
|
1066
|
-
nestingSpacer: '<span class="nestingSpacer"></span>',
|
|
1067
|
-
// Loading indicator for slot elements
|
|
1068
|
-
loadingSlots: null,
|
|
1069
|
-
});
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
static get properties() {
|
|
1073
|
-
return {
|
|
1074
|
-
...super.properties,
|
|
1075
|
-
|
|
1076
|
-
/**
|
|
1077
|
-
* Allows deselecting an already selected option when clicked again in single-select mode.
|
|
1078
|
-
*/
|
|
1079
|
-
allowDeselect: {
|
|
1080
|
-
type: Boolean,
|
|
1081
|
-
reflect: true,
|
|
1082
|
-
},
|
|
1083
|
-
|
|
1084
|
-
/**
|
|
1085
|
-
* When true, the entire menu and all options are disabled.
|
|
1086
|
-
*/
|
|
1087
|
-
disabled: {
|
|
1088
|
-
type: Boolean,
|
|
1089
|
-
reflect: true
|
|
1090
|
-
},
|
|
1091
|
-
|
|
1092
|
-
/**
|
|
1093
|
-
* Indicates whether the menu has a loadingIcon or loadingText to render when in a loading state.
|
|
1094
|
-
*/
|
|
1095
|
-
hasLoadingPlaceholder: {
|
|
1096
|
-
type: Boolean
|
|
1097
|
-
},
|
|
1098
|
-
|
|
1099
|
-
/**
|
|
1100
|
-
* @private
|
|
1101
|
-
*/
|
|
1102
|
-
layout: {
|
|
1103
|
-
type: String
|
|
1104
|
-
},
|
|
1105
|
-
|
|
1106
|
-
/**
|
|
1107
|
-
* Indent level for submenus.
|
|
1108
|
-
* @private
|
|
1109
|
-
*/
|
|
1110
|
-
level: {
|
|
1111
|
-
type: Number,
|
|
1112
|
-
reflect: false,
|
|
1113
|
-
attribute: false
|
|
1114
|
-
},
|
|
1115
|
-
|
|
1116
|
-
/**
|
|
1117
|
-
* When true, displays a loading state using the loadingIcon and loadingText slots if provided.
|
|
1118
|
-
*/
|
|
1119
|
-
loading: {
|
|
1120
|
-
type: Boolean,
|
|
1121
|
-
reflect: true
|
|
1122
|
-
},
|
|
1123
|
-
|
|
1124
|
-
/**
|
|
1125
|
-
* Specifies a string used to highlight matched string parts in options.
|
|
1126
|
-
*/
|
|
1127
|
-
matchWord: {
|
|
1128
|
-
type: String,
|
|
1129
|
-
attribute: 'matchword'
|
|
1130
|
-
},
|
|
1131
|
-
|
|
1132
|
-
/**
|
|
1133
|
-
* When true, the selected option can be multiple options.
|
|
1134
|
-
*/
|
|
1135
|
-
multiSelect: {
|
|
1136
|
-
type: Boolean,
|
|
1137
|
-
reflect: true,
|
|
1138
|
-
attribute: 'multiselect'
|
|
1139
|
-
},
|
|
1140
|
-
|
|
1141
|
-
/**
|
|
1142
|
-
* When true, selected option will not show the checkmark.
|
|
1143
|
-
*/
|
|
1144
|
-
noCheckmark: {
|
|
1145
|
-
type: Boolean,
|
|
1146
|
-
reflect: true,
|
|
1147
|
-
attribute: 'nocheckmark'
|
|
1148
|
-
},
|
|
1149
|
-
|
|
1150
|
-
/**
|
|
1151
|
-
* Specifies the current active menuOption.
|
|
1152
|
-
*/
|
|
1153
|
-
optionActive: {
|
|
1154
|
-
type: Object,
|
|
1155
|
-
attribute: 'optionactive'
|
|
1156
|
-
},
|
|
1157
|
-
|
|
1158
|
-
/**
|
|
1159
|
-
* An array of currently selected menu options, type `HTMLElement` by default. In multi-select mode, `optionSelected` is an array of HTML elements.
|
|
1160
|
-
*/
|
|
1161
|
-
optionSelected: {
|
|
1162
|
-
// Allow HTMLElement, HTMLElement[] arrays and undefined
|
|
1163
|
-
type: Object
|
|
1164
|
-
},
|
|
1165
|
-
|
|
1166
|
-
/**
|
|
1167
|
-
* Available menu options.
|
|
1168
|
-
* @readonly
|
|
1169
|
-
*/
|
|
1170
|
-
options: {
|
|
1171
|
-
type: Array,
|
|
1172
|
-
reflect: false,
|
|
1173
|
-
attribute: false
|
|
1174
|
-
},
|
|
1175
|
-
|
|
1176
|
-
/**
|
|
1177
|
-
* Sets the size of the menu.
|
|
1178
|
-
* @type {'sm' | 'md'}
|
|
1179
|
-
* @default 'sm'
|
|
1180
|
-
*/
|
|
1181
|
-
size: {
|
|
1182
|
-
type: String,
|
|
1183
|
-
reflect: true
|
|
1184
|
-
},
|
|
1185
|
-
|
|
1186
|
-
/**
|
|
1187
|
-
* When true, selects all options that match the provided value/key when setting value and multiselect is enabled.
|
|
1188
|
-
*/
|
|
1189
|
-
selectAllMatchingOptions: {
|
|
1190
|
-
type: Boolean,
|
|
1191
|
-
reflect: true,
|
|
1192
|
-
},
|
|
1044
|
+
setProperty(property, value) {
|
|
1193
1045
|
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
* @type {'box' | 'round'}
|
|
1197
|
-
* @default 'box'
|
|
1198
|
-
*/
|
|
1199
|
-
shape: {
|
|
1200
|
-
type: String,
|
|
1201
|
-
reflect: true
|
|
1202
|
-
},
|
|
1046
|
+
// Only update if we are tracking the property in this service
|
|
1047
|
+
if (this.hasOwnProperty(property)) {
|
|
1203
1048
|
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1049
|
+
// Check if the value has changed
|
|
1050
|
+
const valueChanged = this[property] !== value;
|
|
1051
|
+
|
|
1052
|
+
// Update and notify if changed
|
|
1053
|
+
if (valueChanged) {
|
|
1054
|
+
this[property] = value;
|
|
1055
|
+
this.notify({ property, value });
|
|
1211
1056
|
}
|
|
1212
|
-
}
|
|
1057
|
+
}
|
|
1213
1058
|
}
|
|
1214
1059
|
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
]
|
|
1060
|
+
/**
|
|
1061
|
+
* Sets multiple properties on the instance.
|
|
1062
|
+
* @param {Object} properties - Key-value pairs of properties to set.
|
|
1063
|
+
*/
|
|
1064
|
+
setProperties(properties) {
|
|
1065
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
1066
|
+
this.setProperty(key, value);
|
|
1067
|
+
}
|
|
1221
1068
|
}
|
|
1222
1069
|
|
|
1223
1070
|
/**
|
|
1224
|
-
*
|
|
1225
|
-
* @returns {string} - Returns the label of the currently selected option(s).
|
|
1071
|
+
* MENU OPTION HIGHLIGHTING
|
|
1226
1072
|
*/
|
|
1227
|
-
get currentLabel() {
|
|
1228
|
-
return this.menuService.currentLabel;
|
|
1229
|
-
};
|
|
1230
1073
|
|
|
1231
1074
|
/**
|
|
1232
|
-
*
|
|
1233
|
-
* @returns {Array<HTMLElement>} - Returns the array of available menu options.
|
|
1234
|
-
* @deprecated Use `options` property instead.
|
|
1075
|
+
* Highlights the next active option in the menu.
|
|
1235
1076
|
*/
|
|
1236
|
-
|
|
1237
|
-
|
|
1077
|
+
highlightNext() {
|
|
1078
|
+
this.moveHighlightedOption("next");
|
|
1238
1079
|
}
|
|
1239
1080
|
|
|
1240
1081
|
/**
|
|
1241
|
-
*
|
|
1082
|
+
* Highlights the previous active option in the menu.
|
|
1242
1083
|
*/
|
|
1243
|
-
|
|
1244
|
-
|
|
1084
|
+
highlightPrevious() {
|
|
1085
|
+
this.moveHighlightedOption("previous");
|
|
1245
1086
|
}
|
|
1246
1087
|
|
|
1247
1088
|
/**
|
|
1248
|
-
*
|
|
1089
|
+
* Moves the highlighted option in the specified direction.
|
|
1090
|
+
* @param {string} direction - The direction to move the highlight ("next" or "previous").
|
|
1249
1091
|
*/
|
|
1250
|
-
|
|
1251
|
-
|
|
1092
|
+
moveHighlightedOption(direction) {
|
|
1093
|
+
|
|
1094
|
+
// Get the active options
|
|
1095
|
+
const activeOptions = this._menuOptions.filter(option => option.isActive);
|
|
1096
|
+
|
|
1097
|
+
// Get the currently active option
|
|
1098
|
+
const currentActiveOption = activeOptions[activeOptions.indexOf(this.highlightedOption)];
|
|
1099
|
+
|
|
1100
|
+
// Determine the new index based on the currently active option and direction
|
|
1101
|
+
let newIndex = currentActiveOption
|
|
1102
|
+
? direction === "previous"
|
|
1103
|
+
? activeOptions.indexOf(currentActiveOption) - 1
|
|
1104
|
+
: activeOptions.indexOf(currentActiveOption) + 1
|
|
1105
|
+
: direction === "previous"
|
|
1106
|
+
? activeOptions.length - 1
|
|
1107
|
+
: 0;
|
|
1108
|
+
|
|
1109
|
+
// Wrap around the index if needed
|
|
1110
|
+
newIndex = newIndex < 0 ? activeOptions.length - 1 : newIndex >= activeOptions.length ? 0 : newIndex;
|
|
1111
|
+
|
|
1112
|
+
// Get the new active option and set it as highlighted
|
|
1113
|
+
const newActiveOption = activeOptions[newIndex];
|
|
1114
|
+
this.setHighlightedOption(newActiveOption);
|
|
1252
1115
|
}
|
|
1253
1116
|
|
|
1254
1117
|
/**
|
|
1255
|
-
*
|
|
1256
|
-
* @param {
|
|
1257
|
-
*
|
|
1258
|
-
* @example
|
|
1259
|
-
* AuroMenu.register("custom-menu") // this will register this element to <custom-menu/>
|
|
1260
|
-
*
|
|
1118
|
+
* Sets the highlighted index to the specified option.
|
|
1119
|
+
* @param {AuroMenuOption} option - The option to highlight.
|
|
1261
1120
|
*/
|
|
1262
|
-
|
|
1263
|
-
|
|
1121
|
+
setHighlightedOption(option) {
|
|
1122
|
+
|
|
1123
|
+
if (!option) return;
|
|
1124
|
+
|
|
1125
|
+
// Get the index of the option to highlight
|
|
1126
|
+
const index = this._menuOptions.indexOf(option);
|
|
1127
|
+
|
|
1128
|
+
// Update highlighted index
|
|
1129
|
+
this.highlightedIndex = index;
|
|
1130
|
+
|
|
1131
|
+
// Notify subscribers of highlight change
|
|
1132
|
+
this.notify({ type: 'highlightChange', option, index: this.highlightedIndex });
|
|
1133
|
+
|
|
1134
|
+
// Dispatch the change event
|
|
1135
|
+
this.dispatchChangeEvent('auroMenu-activatedOption', option);
|
|
1264
1136
|
}
|
|
1265
1137
|
|
|
1266
1138
|
/**
|
|
1267
|
-
*
|
|
1268
|
-
*
|
|
1269
|
-
* @private
|
|
1270
|
-
* @returns {String|Array<String>}
|
|
1139
|
+
* Sets the highlighted option to the option at the specified index if it exists.
|
|
1140
|
+
* @param {number} index
|
|
1271
1141
|
*/
|
|
1272
|
-
|
|
1273
|
-
|
|
1142
|
+
setHighlightedIndex(index) {
|
|
1143
|
+
const option = this._menuOptions[index] || null;
|
|
1144
|
+
this.setHighlightedOption(option);
|
|
1274
1145
|
}
|
|
1275
1146
|
|
|
1276
1147
|
/**
|
|
1277
|
-
*
|
|
1278
|
-
* @private
|
|
1279
|
-
* @returns {Object}
|
|
1148
|
+
* Selects the currently highlighted option.
|
|
1280
1149
|
*/
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
noCheckmark: this.nocheckmark,
|
|
1286
|
-
disabled: this.disabled
|
|
1287
|
-
};
|
|
1150
|
+
selectHighlightedOption() {
|
|
1151
|
+
if (this.highlightedOption) {
|
|
1152
|
+
this.toggleOption(this.highlightedOption);
|
|
1153
|
+
}
|
|
1288
1154
|
}
|
|
1289
1155
|
|
|
1290
1156
|
/**
|
|
1291
|
-
*
|
|
1292
|
-
* Initializes the MenuService and subscribes to menu changes.
|
|
1293
|
-
* @protected
|
|
1157
|
+
* SELECTION AND DESELECTION METHODS
|
|
1294
1158
|
*/
|
|
1295
|
-
provideContext() {
|
|
1296
|
-
if (this.parentElement && this.parentElement.closest('auro-menu, [auro-menu]')) {
|
|
1297
|
-
this.rootMenu = false;
|
|
1298
|
-
this.menuService = this.parentElement.menuService;
|
|
1299
|
-
this._contextProvider = this.parentElement._contextProvider;
|
|
1300
|
-
return;
|
|
1301
|
-
}
|
|
1302
|
-
|
|
1303
|
-
this.menuService = new MenuService({host: this});
|
|
1304
|
-
this.menuService.setProperties(this.propertyValues);
|
|
1305
|
-
this.menuService.subscribe(this.handleMenuChange.bind(this));
|
|
1306
|
-
this._contextProvider = new ContextProvider(this, {
|
|
1307
|
-
context: MenuContext,
|
|
1308
|
-
initialValue: this.menuService
|
|
1309
|
-
});
|
|
1310
|
-
}
|
|
1311
1159
|
|
|
1312
1160
|
/**
|
|
1313
|
-
*
|
|
1314
|
-
* @param {
|
|
1161
|
+
* Selects one or more options in a batch operation
|
|
1162
|
+
* @param {AuroMenuOption|AuroMenuOption[]} options - Single option or array of options to select
|
|
1315
1163
|
*/
|
|
1316
|
-
|
|
1317
|
-
|
|
1164
|
+
selectOptions(options) {
|
|
1165
|
+
let optionsToSelect = Array.isArray(options) ? options : [options];
|
|
1166
|
+
|
|
1167
|
+
// Filter out options that are inactive
|
|
1168
|
+
optionsToSelect = optionsToSelect.filter(option => option.isActive);
|
|
1169
|
+
|
|
1170
|
+
if (!optionsToSelect.length) return;
|
|
1171
|
+
|
|
1172
|
+
if (this.multiSelect) {
|
|
1173
|
+
this.selectedOptions = [...(this.selectedOptions || []), ...optionsToSelect];
|
|
1174
|
+
} else {
|
|
1175
|
+
// In single select mode, only take the last option
|
|
1176
|
+
this.selectedOptions = [optionsToSelect[optionsToSelect.length - 1]];
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
this.stageUpdate();
|
|
1318
1180
|
}
|
|
1319
1181
|
|
|
1320
1182
|
/**
|
|
1321
|
-
*
|
|
1322
|
-
* @param {
|
|
1323
|
-
* @protected
|
|
1183
|
+
* Deselects one or more options in a batch operation
|
|
1184
|
+
* @param {AuroMenuOption|AuroMenuOption[]} options - Single option or array of options to deselect
|
|
1324
1185
|
*/
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
this.internalUpdateInProgress = true;
|
|
1328
|
-
this.value = value;
|
|
1186
|
+
deselectOptions(options) {
|
|
1187
|
+
const optionsToDeselect = Array.isArray(options) ? options : [options];
|
|
1329
1188
|
|
|
1330
|
-
|
|
1331
|
-
|
|
1189
|
+
if (!optionsToDeselect.length) return;
|
|
1190
|
+
|
|
1191
|
+
// Check if deselection should be prevented
|
|
1192
|
+
const shouldPreventDeselect = !this.allowDeselect && !this.multiSelect;
|
|
1193
|
+
const isOnlySelectedOption = this.selectedOptions.length === 1 && optionsToDeselect.includes(this.selectedOptions[0]);
|
|
1194
|
+
|
|
1195
|
+
// Prevent deselecting the only selected option if not allowed
|
|
1196
|
+
if (shouldPreventDeselect && isOnlySelectedOption) {
|
|
1197
|
+
optionsToDeselect.forEach(option => {
|
|
1198
|
+
option.selected = true;
|
|
1199
|
+
});
|
|
1200
|
+
this.dispatchChangeEvent('auroMenu-deselectPrevented', {
|
|
1201
|
+
values: optionsToDeselect
|
|
1332
1202
|
});
|
|
1203
|
+
return;
|
|
1333
1204
|
}
|
|
1205
|
+
|
|
1206
|
+
const optionsSet = new Set(optionsToDeselect);
|
|
1207
|
+
this.selectedOptions = (this.selectedOptions || [])
|
|
1208
|
+
.filter(opt => !optionsSet.has(opt));
|
|
1209
|
+
|
|
1210
|
+
this.stageUpdate();
|
|
1334
1211
|
}
|
|
1335
1212
|
|
|
1336
1213
|
/**
|
|
1337
|
-
*
|
|
1338
|
-
* @param {
|
|
1339
|
-
* @protected
|
|
1214
|
+
* Selects a single option.
|
|
1215
|
+
* @param {AuroMenuOption} option
|
|
1340
1216
|
*/
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
// New option is array value or first option with fallback to undefined for empty array in all cases
|
|
1345
|
-
const newOption = this.multiSelect && event.options.length ? event.options : event.options[0] || undefined;
|
|
1346
|
-
const newValue = event.stringValue;
|
|
1217
|
+
selectOption(option) {
|
|
1218
|
+
this.selectOptions(option);
|
|
1219
|
+
}
|
|
1347
1220
|
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1221
|
+
/**
|
|
1222
|
+
* Deselects a single option.
|
|
1223
|
+
* @param {AuroMenuOption} option
|
|
1224
|
+
*/
|
|
1225
|
+
deselectOption(option) {
|
|
1226
|
+
this.deselectOptions(option);
|
|
1227
|
+
}
|
|
1353
1228
|
|
|
1354
|
-
|
|
1355
|
-
|
|
1229
|
+
/**
|
|
1230
|
+
* Toggles the selection state of a single option.
|
|
1231
|
+
* @param {AuroMenuOption} option
|
|
1232
|
+
*/
|
|
1233
|
+
toggleOption(option) {
|
|
1234
|
+
if (option.selected) {
|
|
1235
|
+
this.deselectOption(option);
|
|
1236
|
+
} else {
|
|
1237
|
+
this.selectOption(option);
|
|
1356
1238
|
}
|
|
1239
|
+
}
|
|
1357
1240
|
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1241
|
+
/**
|
|
1242
|
+
* Selects options based on their value(s) when compared to a passed value or values.
|
|
1243
|
+
* Value or values are normalized to an array of strings that can be matched to option keys.
|
|
1244
|
+
* @param {string|number|Array<string|number>} value - The value(s) to select.
|
|
1245
|
+
*/
|
|
1246
|
+
selectByValue(value) {
|
|
1247
|
+
const isEmptyValue = value === undefined ||
|
|
1248
|
+
value === null ||
|
|
1249
|
+
(Array.isArray(value) && value.length === 0) ||
|
|
1250
|
+
(typeof value === 'string' && value.trim() === '');
|
|
1362
1251
|
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
this.
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
}
|
|
1369
|
-
}));
|
|
1252
|
+
// Early exit for invalid/empty values
|
|
1253
|
+
if (isEmptyValue) {
|
|
1254
|
+
this.selectedOptions.forEach(opt => opt.selected = false);
|
|
1255
|
+
this.selectedOptions = [];
|
|
1256
|
+
return;
|
|
1370
1257
|
}
|
|
1371
|
-
}
|
|
1372
1258
|
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
}
|
|
1259
|
+
// If an internal update cycle is still in progress, defer value application
|
|
1260
|
+
// rather than dropping it.
|
|
1261
|
+
if (this.internalUpdateInProgress || this.host.internalUpdateInProgress) {
|
|
1262
|
+
this.queuePendingValue(value);
|
|
1263
|
+
return;
|
|
1264
|
+
}
|
|
1380
1265
|
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
* @returns {HTMLElement|null}
|
|
1384
|
-
*/
|
|
1385
|
-
get selectedOption() {
|
|
1386
|
-
return this.menuService ? this.menuService.selectedOptions[0] : null;
|
|
1387
|
-
}
|
|
1266
|
+
// Normalize values to array of strings
|
|
1267
|
+
const normalizedValues = this._getNormalizedValues(value);
|
|
1388
1268
|
|
|
1389
|
-
|
|
1269
|
+
// Validate for single-select mode
|
|
1270
|
+
let validatedValues = normalizedValues;
|
|
1271
|
+
if (normalizedValues.length > 1 && !this.multiSelect) {
|
|
1272
|
+
console.warn("MenuService - Multiple values provided for single-select menu. Only the first value will be selected.");
|
|
1273
|
+
validatedValues = [normalizedValues[0]];
|
|
1274
|
+
}
|
|
1390
1275
|
|
|
1391
|
-
|
|
1392
|
-
|
|
1276
|
+
if (this._menuOptions.length === 0) {
|
|
1277
|
+
this.queuePendingValue(value);
|
|
1278
|
+
return;
|
|
1279
|
+
}
|
|
1393
1280
|
|
|
1394
|
-
|
|
1281
|
+
// Find matching options by comparing available options to validated values
|
|
1282
|
+
const trackedKeys = new Set();
|
|
1283
|
+
const optionsToSelect = this._menuOptions.filter(option => {
|
|
1284
|
+
const passesFilter = validatedValues.includes(option.key);
|
|
1285
|
+
const alreadyTracked = trackedKeys.has(option.key);
|
|
1286
|
+
const isActive = option.isActive;
|
|
1395
1287
|
|
|
1396
|
-
|
|
1397
|
-
this.addEventListener('auroMenuOption-click', this.handleMouseSelect);
|
|
1398
|
-
this.addEventListener('auroMenuOption-mouseover', this.handleOptionHover);
|
|
1399
|
-
this.addEventListener('slotchange', this.handleSlotChange);
|
|
1400
|
-
this.setTagAttribute("auro-menu");
|
|
1401
|
-
}
|
|
1288
|
+
trackedKeys.add(option.key);
|
|
1402
1289
|
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
this.removeEventListener('slotchange', this.handleSlotChange);
|
|
1290
|
+
// Include the option in the options to be selected if it passes the filter check and
|
|
1291
|
+
// either hasn't been tracked yet or selectAllMatchingOptions is true
|
|
1292
|
+
return isActive && passesFilter && (!alreadyTracked || (alreadyTracked && this.selectAllMatchingOptions));
|
|
1293
|
+
});
|
|
1408
1294
|
|
|
1409
|
-
|
|
1410
|
-
|
|
1295
|
+
// Handle no matches: clear existing selection, but do not dispatch an intermediate
|
|
1296
|
+
// undefined value that can overwrite the host value in parent components.
|
|
1297
|
+
if (!optionsToSelect.length) {
|
|
1298
|
+
const hasUnresolvedKeys = this._menuOptions.some((option) => option.isActive && option.key == null);
|
|
1411
1299
|
|
|
1412
|
-
|
|
1413
|
-
|
|
1300
|
+
if (hasUnresolvedKeys) {
|
|
1301
|
+
this.queuePendingValue(value);
|
|
1302
|
+
return;
|
|
1303
|
+
}
|
|
1414
1304
|
|
|
1415
|
-
|
|
1416
|
-
this.initializeMenu();
|
|
1417
|
-
}
|
|
1305
|
+
this.clearPendingValue();
|
|
1418
1306
|
|
|
1307
|
+
if (this.selectedOptions.length > 0) {
|
|
1308
|
+
this.selectedOptions = [];
|
|
1309
|
+
}
|
|
1419
1310
|
|
|
1420
|
-
|
|
1421
|
-
|
|
1311
|
+
// Always notify so the host resets any stale invalid value, even when
|
|
1312
|
+
// selectedOptions was already empty (e.g. double-clicking set-invalid).
|
|
1313
|
+
this.stageUpdate({ reason: 'no-match' });
|
|
1422
1314
|
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
this.menuService.selectByValue(this.value);
|
|
1431
|
-
}
|
|
1315
|
+
// Dispatch failure event if no matches found
|
|
1316
|
+
if (validatedValues.length) {
|
|
1317
|
+
this.dispatchChangeEvent('auroMenu-selectValueFailure', {
|
|
1318
|
+
message: 'No matching options found for the provided value(s).',
|
|
1319
|
+
values: validatedValues
|
|
1320
|
+
});
|
|
1321
|
+
}
|
|
1432
1322
|
|
|
1433
|
-
|
|
1434
|
-
if (changedProperties.has('loading')) {
|
|
1435
|
-
this.setLoadingState(this.loading);
|
|
1323
|
+
return;
|
|
1436
1324
|
}
|
|
1437
1325
|
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
this.removeAttribute('aria-multiselectable');
|
|
1443
|
-
}
|
|
1326
|
+
this.clearPendingValue();
|
|
1327
|
+
|
|
1328
|
+
if (this.optionsArraysMatch(optionsToSelect, this.selectedOptions)) {
|
|
1329
|
+
return;
|
|
1444
1330
|
}
|
|
1331
|
+
|
|
1332
|
+
// Apply programmatic selection as a single transaction and emit one final state.
|
|
1333
|
+
this.selectedOptions = optionsToSelect;
|
|
1334
|
+
this.stageUpdate();
|
|
1445
1335
|
}
|
|
1446
1336
|
|
|
1447
1337
|
/**
|
|
1448
|
-
*
|
|
1449
|
-
* @param {string}
|
|
1450
|
-
* @private
|
|
1338
|
+
* Queues a pending value and schedules a bounded retry.
|
|
1339
|
+
* @param {string|number|Array<string|number>} value - The value to retry.
|
|
1451
1340
|
*/
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1341
|
+
queuePendingValue(value) {
|
|
1342
|
+
this._pendingValue = value;
|
|
1343
|
+
|
|
1344
|
+
if (this._pendingRetryScheduled || this._pendingRetryCount >= 5) {
|
|
1345
|
+
return;
|
|
1455
1346
|
}
|
|
1347
|
+
|
|
1348
|
+
this._pendingRetryScheduled = true;
|
|
1349
|
+
this._pendingRetryCount += 1;
|
|
1350
|
+
|
|
1351
|
+
setTimeout(() => {
|
|
1352
|
+
this._pendingRetryScheduled = false;
|
|
1353
|
+
|
|
1354
|
+
if (this._pendingValue == null) {
|
|
1355
|
+
return;
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
const pendingValue = this._pendingValue;
|
|
1359
|
+
this.selectByValue(pendingValue);
|
|
1360
|
+
}, 0);
|
|
1456
1361
|
}
|
|
1457
1362
|
|
|
1458
1363
|
/**
|
|
1459
|
-
*
|
|
1460
|
-
* @param {boolean} isLoading - Whether the menu is loading.
|
|
1461
|
-
* @protected
|
|
1364
|
+
* Clears pending retry state.
|
|
1462
1365
|
*/
|
|
1463
|
-
|
|
1464
|
-
this.
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
hasLoadingPlaceholder: this.hasLoadingPlaceholder
|
|
1468
|
-
});
|
|
1366
|
+
clearPendingValue() {
|
|
1367
|
+
this._pendingValue = null;
|
|
1368
|
+
this._pendingRetryScheduled = false;
|
|
1369
|
+
this._pendingRetryCount = 0;
|
|
1469
1370
|
}
|
|
1470
1371
|
|
|
1471
|
-
// Init Methods
|
|
1472
|
-
|
|
1473
1372
|
/**
|
|
1474
|
-
*
|
|
1475
|
-
* @private
|
|
1373
|
+
* Resets the selected options to an empty array.
|
|
1476
1374
|
*/
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1375
|
+
reset() {
|
|
1376
|
+
const previousOptions = [...this.selectedOptions];
|
|
1377
|
+
previousOptions.forEach(opt => opt.selected = false);
|
|
1378
|
+
this.selectedOptions = [];
|
|
1481
1379
|
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1380
|
+
// Single update after clearing all
|
|
1381
|
+
if (previousOptions.length) {
|
|
1382
|
+
this.stageUpdate();
|
|
1485
1383
|
}
|
|
1486
|
-
|
|
1487
|
-
this.handleNestedMenus(this);
|
|
1488
1384
|
}
|
|
1489
1385
|
|
|
1490
1386
|
/**
|
|
1491
|
-
*
|
|
1492
|
-
* @protected
|
|
1387
|
+
* SUBSCRIPTION, NOTIFICATION AND EVENT DISPATCH METHODS
|
|
1493
1388
|
*/
|
|
1494
|
-
makeSelection() {
|
|
1495
|
-
this.menuService.selectHighlightedOption();
|
|
1496
|
-
}
|
|
1497
1389
|
|
|
1498
1390
|
/**
|
|
1499
|
-
*
|
|
1500
|
-
* @
|
|
1391
|
+
* Subscribes a callback to menu service events.
|
|
1392
|
+
* @param {Function} callback - The callback to invoke on events.
|
|
1501
1393
|
*/
|
|
1502
|
-
|
|
1503
|
-
this.
|
|
1504
|
-
this.value = undefined;
|
|
1505
|
-
this._index = -1;
|
|
1394
|
+
subscribe(callback) {
|
|
1395
|
+
this._subscribers.push(callback);
|
|
1506
1396
|
}
|
|
1507
1397
|
|
|
1508
1398
|
/**
|
|
1509
|
-
*
|
|
1510
|
-
*
|
|
1511
|
-
* @public
|
|
1399
|
+
* Remove a previously subscribed callback from menu service events.
|
|
1400
|
+
* @param {Function} callback
|
|
1512
1401
|
*/
|
|
1513
|
-
|
|
1514
|
-
this.
|
|
1515
|
-
|
|
1516
|
-
// Dispatch reset event
|
|
1517
|
-
dispatchMenuEvent(this, 'auroMenu-selectValueReset');
|
|
1402
|
+
unsubscribe(callback) {
|
|
1403
|
+
this._subscribers = this._subscribers.filter(cb => cb !== callback);
|
|
1518
1404
|
}
|
|
1519
1405
|
|
|
1520
1406
|
/**
|
|
1521
|
-
*
|
|
1522
|
-
* @private
|
|
1523
|
-
* @param {HTMLElement} menu - Root menu element.
|
|
1407
|
+
* Stages an update to notify subscribers of state and value changes.
|
|
1524
1408
|
*/
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
menu.setAttribute('role', 'group');
|
|
1530
|
-
menu.removeAttribute("root");
|
|
1531
|
-
if (!menu.hasAttribute('aria-label')) {
|
|
1532
|
-
menu.setAttribute('aria-label', 'submenu');
|
|
1533
|
-
}
|
|
1534
|
-
}
|
|
1409
|
+
stageUpdate(meta = {}) {
|
|
1410
|
+
this.notifyStateChange(meta);
|
|
1411
|
+
this.notifyValueChange(meta);
|
|
1412
|
+
}
|
|
1535
1413
|
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1414
|
+
/**
|
|
1415
|
+
* Notifies subscribers of a menu service event.
|
|
1416
|
+
* All notifications are sent to all subscribers.
|
|
1417
|
+
* @param {string} event - The event to send to subscribers.
|
|
1418
|
+
*/
|
|
1419
|
+
notify(event) {
|
|
1420
|
+
this._subscribers.forEach(callback => callback(event));
|
|
1541
1421
|
}
|
|
1542
1422
|
|
|
1543
1423
|
/**
|
|
1544
|
-
*
|
|
1545
|
-
* @param {'up'|'down'} direction - The direction to navigate.
|
|
1546
|
-
* @protected
|
|
1424
|
+
* Notifies subscribers of a state change (selected options has changed).
|
|
1547
1425
|
*/
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
}
|
|
1426
|
+
notifyStateChange(meta = {}) {
|
|
1427
|
+
this.notify({
|
|
1428
|
+
type: 'stateChange',
|
|
1429
|
+
selectedOptions: this.selectedOptions,
|
|
1430
|
+
...meta
|
|
1431
|
+
});
|
|
1554
1432
|
}
|
|
1555
1433
|
|
|
1556
1434
|
/**
|
|
1557
|
-
*
|
|
1558
|
-
* @private
|
|
1435
|
+
* Notifies subscribers of a value change (current value has changed).
|
|
1559
1436
|
*/
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1437
|
+
notifyValueChange(meta = {}) {
|
|
1438
|
+
|
|
1439
|
+
// Prepare details for the event
|
|
1440
|
+
const details = {
|
|
1441
|
+
value: this.currentValue,
|
|
1442
|
+
stringValue: this.stringValue,
|
|
1443
|
+
keys: this.currentKeys,
|
|
1444
|
+
options: this.selectedOptions,
|
|
1445
|
+
label: this.currentLabel
|
|
1446
|
+
};
|
|
1447
|
+
|
|
1448
|
+
// If only one option is selected, include its index
|
|
1449
|
+
if (this.selectedOptions.length === 1) details.index = this._menuOptions.indexOf(this.selectedOptions[0]);
|
|
1450
|
+
|
|
1451
|
+
this.notify({
|
|
1452
|
+
type: 'valueChange',
|
|
1453
|
+
...meta,
|
|
1454
|
+
...details
|
|
1455
|
+
});
|
|
1564
1456
|
}
|
|
1565
1457
|
|
|
1566
1458
|
/**
|
|
1567
|
-
*
|
|
1568
|
-
* @
|
|
1569
|
-
* @param {
|
|
1459
|
+
* Dispatches a custom event from the host element.
|
|
1460
|
+
* @param {string} eventName
|
|
1461
|
+
* @param {any} detail
|
|
1570
1462
|
*/
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1463
|
+
dispatchChangeEvent(eventName, detail) {
|
|
1464
|
+
this.host.dispatchEvent(new CustomEvent(eventName, {
|
|
1465
|
+
bubbles: true,
|
|
1466
|
+
cancelable: false,
|
|
1467
|
+
composed: true,
|
|
1468
|
+
detail
|
|
1469
|
+
}));
|
|
1575
1470
|
}
|
|
1576
1471
|
|
|
1577
1472
|
/**
|
|
1578
|
-
*
|
|
1579
|
-
* @param {any} source - The source that triggers this event.
|
|
1580
|
-
* @private
|
|
1473
|
+
* MENU OPTION MANAGEMENT METHODS
|
|
1581
1474
|
*/
|
|
1582
|
-
notifySelectionChange({value, stringValue, keys, options, reason} = {}) {
|
|
1583
|
-
dispatchMenuEvent(this, 'auroMenu-selectedOption', {
|
|
1584
|
-
value,
|
|
1585
|
-
stringValue,
|
|
1586
|
-
keys,
|
|
1587
|
-
options,
|
|
1588
|
-
reason
|
|
1589
|
-
});
|
|
1590
|
-
}
|
|
1591
1475
|
|
|
1592
1476
|
/**
|
|
1593
|
-
*
|
|
1594
|
-
* @
|
|
1595
|
-
* @param {HTMLElement} option - The option to check.
|
|
1596
|
-
* @returns {boolean}
|
|
1477
|
+
* Adds a menu option to the service's list.
|
|
1478
|
+
* @param {AuroMenuOption} option - the option to track
|
|
1597
1479
|
*/
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
}
|
|
1480
|
+
addMenuOption(option) {
|
|
1481
|
+
this._menuOptions.push(option);
|
|
1482
|
+
this.notify({ type: 'optionsChange', options: this._menuOptions });
|
|
1602
1483
|
|
|
1603
|
-
if (this.
|
|
1604
|
-
|
|
1605
|
-
return Array.isArray(this.optionSelected) && this.optionSelected.some((selectedOption) => selectedOption === option);
|
|
1484
|
+
if (this._pendingValue != null) {
|
|
1485
|
+
this.queuePendingValue(this._pendingValue);
|
|
1606
1486
|
}
|
|
1607
|
-
|
|
1608
|
-
return this.optionSelected === option;
|
|
1609
1487
|
}
|
|
1610
1488
|
|
|
1611
1489
|
/**
|
|
1612
|
-
*
|
|
1613
|
-
* @
|
|
1490
|
+
* Removes a menu option from the service's list.
|
|
1491
|
+
* @param {AuroMenuOption} option - the option to remove
|
|
1614
1492
|
*/
|
|
1615
|
-
|
|
1616
|
-
|
|
1493
|
+
removeMenuOption(option) {
|
|
1494
|
+
this._menuOptions = this._menuOptions.filter(opt => opt !== option);
|
|
1495
|
+
this.notify({ type: 'optionsChange', options: this._menuOptions });
|
|
1496
|
+
|
|
1497
|
+
if (this._menuOptions.length === 0) {
|
|
1498
|
+
this.clearPendingValue();
|
|
1499
|
+
}
|
|
1617
1500
|
}
|
|
1618
1501
|
|
|
1619
1502
|
/**
|
|
1620
|
-
*
|
|
1621
|
-
* @returns {Object} - Class map for the wrapper element.
|
|
1622
|
-
* @private
|
|
1503
|
+
* UTILITIES
|
|
1623
1504
|
*/
|
|
1624
|
-
get wrapperClasses() {
|
|
1625
|
-
return classMap({
|
|
1626
|
-
'menuWrapper': true,
|
|
1627
|
-
[this.size]: true,
|
|
1628
|
-
});
|
|
1629
|
-
}
|
|
1630
1505
|
|
|
1631
1506
|
/**
|
|
1632
|
-
*
|
|
1633
|
-
*
|
|
1634
|
-
*
|
|
1507
|
+
* Normalizes a value or array of values into an array of strings for option selection.
|
|
1508
|
+
* This function ensures that input values are consistently formatted for matching menu options.
|
|
1509
|
+
*
|
|
1510
|
+
* @param {string|number|Array<string|number>} value - The value(s) to normalize.
|
|
1511
|
+
* @returns {Array<string>} An array of string values suitable for option matching.
|
|
1512
|
+
* @throws {Error} If any value is not a string or number.
|
|
1635
1513
|
*/
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
return html`
|
|
1639
|
-
<div class="${this.wrapperClasses}">
|
|
1640
|
-
<auro-menuoption
|
|
1641
|
-
disabled
|
|
1642
|
-
loadingplaceholder
|
|
1643
|
-
class="${this.hasLoadingPlaceholder ? "" : "empty"}"
|
|
1644
|
-
>
|
|
1645
|
-
<div>
|
|
1646
|
-
<slot name="loadingIcon" class="body-lg"></slot>
|
|
1647
|
-
<slot name="loadingText"></slot>
|
|
1648
|
-
</div>
|
|
1649
|
-
</auro-menuoption>
|
|
1650
|
-
</div>
|
|
1651
|
-
`;
|
|
1652
|
-
}
|
|
1514
|
+
_getNormalizedValues(value) {
|
|
1515
|
+
let values = value;
|
|
1653
1516
|
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
<slot @slotchange=${this.handleSlotChange}></slot>
|
|
1657
|
-
</div>
|
|
1658
|
-
`;
|
|
1659
|
-
}
|
|
1660
|
-
}
|
|
1517
|
+
// Handle JSON string and single value string input
|
|
1518
|
+
if (!Array.isArray(values) && typeof values === 'string') {
|
|
1661
1519
|
|
|
1662
|
-
var styleCss = css`.body-default{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-weight:var(--wcss-body-weight, 450);letter-spacing:var(--wcss-body-letter-spacing, 0);font-size:var(--wcss-body-default-font-size, 1rem);line-height:var(--wcss-body-default-line-height, 1.5rem)}.body-lg{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-weight:var(--wcss-body-weight, 450);letter-spacing:var(--wcss-body-letter-spacing, 0);font-size:var(--wcss-body-lg-font-size, 1.125rem);line-height:var(--wcss-body-lg-line-height, 1.625rem)}.body-sm{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-weight:var(--wcss-body-weight, 450);letter-spacing:var(--wcss-body-letter-spacing, 0);font-size:var(--wcss-body-sm-font-size, 0.875rem);line-height:var(--wcss-body-sm-line-height, 1.25rem)}.body-xs{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-weight:var(--wcss-body-weight, 450);letter-spacing:var(--wcss-body-letter-spacing, 0);font-size:var(--wcss-body-xs-font-size, 0.75rem);line-height:var(--wcss-body-xs-line-height, 1rem)}.body-2xs{font-family:var(--wcss-body-family, "AS Circular"),system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;font-weight:var(--wcss-body-weight, 450);letter-spacing:var(--wcss-body-letter-spacing, 0);font-size:var(--wcss-body-2xs-font-size, 0.625rem);line-height:var(--wcss-body-2xs-line-height, 0.875rem)}.display-2xl{font-family:var(--wcss-display-2xl-family, "AS Circular"),var(--wcss-display-2xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-display-2xl-letter-spacing, 0);font-weight:var(--wcss-display-2xl-weight, 300);line-height:var(--wcss-display-2xl-line-height, 1.3);font-size:var(--wcss-display-2xl-font-size, clamp(3.5rem, 6vw, 5.375rem))}.display-xl{font-family:var(--wcss-display-xl-family, "AS Circular"),var(--wcss-display-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-display-xl-letter-spacing, 0);font-weight:var(--wcss-display-xl-weight, 300);line-height:var(--wcss-display-xl-line-height, 1.3);font-size:var(--wcss-display-xl-font-size, clamp(3rem, 5.3333333333vw, 4.5rem))}.display-lg{font-family:var(--wcss-display-lg-family, "AS Circular"),var(--wcss-display-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-display-lg-letter-spacing, 0);font-weight:var(--wcss-display-lg-weight, 300);line-height:var(--wcss-display-lg-line-height, 1.3);font-size:var(--wcss-display-lg-font-size, clamp(2.75rem, 4.6666666667vw, 4rem))}.display-md{font-family:var(--wcss-display-md-family, "AS Circular"),var(--wcss-display-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-display-md-letter-spacing, 0);font-weight:var(--wcss-display-md-weight, 300);line-height:var(--wcss-display-md-line-height, 1.3);font-size:var(--wcss-display-md-font-size, clamp(2.5rem, 4vw, 3.5rem))}.display-sm{font-family:var(--wcss-display-sm-family, "AS Circular"),var(--wcss-display-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-display-sm-letter-spacing, 0);font-weight:var(--wcss-display-sm-weight, 300);line-height:var(--wcss-display-sm-line-height, 1.3);font-size:var(--wcss-display-sm-font-size, clamp(2rem, 3.6666666667vw, 3rem))}.display-xs{font-family:var(--wcss-display-xs-family, "AS Circular"),var(--wcss-display-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-display-xs-letter-spacing, 0);font-weight:var(--wcss-display-xs-weight, 300);line-height:var(--wcss-display-xs-line-height, 1.3);font-size:var(--wcss-display-xs-font-size, clamp(1.75rem, 3vw, 2.375rem))}.heading-xl{font-family:var(--wcss-heading-xl-family, "AS Circular"),var(--wcss-heading-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-heading-xl-letter-spacing, 0);font-weight:var(--wcss-heading-xl-weight, 300);line-height:var(--wcss-heading-xl-line-height, 1.3);font-size:var(--wcss-heading-xl-font-size, clamp(2rem, 3vw, 2.5rem))}.heading-lg{font-family:var(--wcss-heading-lg-family, "AS Circular"),var(--wcss-heading-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-heading-lg-letter-spacing, 0);font-weight:var(--wcss-heading-lg-weight, 300);line-height:var(--wcss-heading-lg-line-height, 1.3);font-size:var(--wcss-heading-lg-font-size, clamp(1.75rem, 2.6666666667vw, 2.25rem))}.heading-md{font-family:var(--wcss-heading-md-family, "AS Circular"),var(--wcss-heading-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-heading-md-letter-spacing, 0);font-weight:var(--wcss-heading-md-weight, 300);line-height:var(--wcss-heading-md-line-height, 1.3);font-size:var(--wcss-heading-md-font-size, clamp(1.625rem, 2.3333333333vw, 1.75rem))}.heading-sm{font-family:var(--wcss-heading-sm-family, "AS Circular"),var(--wcss-heading-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-heading-sm-letter-spacing, 0);font-weight:var(--wcss-heading-sm-weight, 300);line-height:var(--wcss-heading-sm-line-height, 1.3);font-size:var(--wcss-heading-sm-font-size, clamp(1.375rem, 2vw, 1.5rem))}.heading-xs{font-family:var(--wcss-heading-xs-family, "AS Circular"),var(--wcss-heading-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-heading-xs-letter-spacing, 0);font-weight:var(--wcss-heading-xs-weight, 450);line-height:var(--wcss-heading-xs-line-height, 1.3);font-size:var(--wcss-heading-xs-font-size, clamp(1.25rem, 1.6666666667vw, 1.25rem))}.heading-2xs{font-family:var(--wcss-heading-2xs-family, "AS Circular"),var(--wcss-heading-2xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-heading-2xs-letter-spacing, 0);font-weight:var(--wcss-heading-2xs-weight, 450);line-height:var(--wcss-heading-2xs-line-height, 1.3);font-size:var(--wcss-heading-2xs-font-size, clamp(1.125rem, 1.5vw, 1.125rem))}.accent-2xl{font-family:var(--wcss-accent-2xl-family, "Good OT"),var(--wcss-accent-2xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-2xl-letter-spacing, 0.05em);font-weight:var(--wcss-accent-2xl-weight, 450);line-height:var(--wcss-accent-2xl-line-height, 1);font-size:var(--wcss-accent-2xl-font-size, clamp(2rem, 3.1666666667vw, 2.375rem));text-transform:uppercase}.accent-xl{font-family:var(--wcss-accent-xl-family, "Good OT"),var(--wcss-accent-xl-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-xl-letter-spacing, 0.05em);font-weight:var(--wcss-accent-xl-weight, 450);line-height:var(--wcss-accent-xl-line-height, 1.3);font-size:var(--wcss-accent-xl-font-size, clamp(1.625rem, 2.3333333333vw, 2rem));text-transform:uppercase}.accent-lg{font-family:var(--wcss-accent-lg-family, "Good OT"),var(--wcss-accent-lg-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-lg-letter-spacing, 0.05em);font-weight:var(--wcss-accent-lg-weight, 450);line-height:var(--wcss-accent-lg-line-height, 1.3);font-size:var(--wcss-accent-lg-font-size, clamp(1.5rem, 2.1666666667vw, 1.75rem));text-transform:uppercase}.accent-md{font-family:var(--wcss-accent-md-family, "Good OT"),var(--wcss-accent-md-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-md-letter-spacing, 0.05em);font-weight:var(--wcss-accent-md-weight, 500);line-height:var(--wcss-accent-md-line-height, 1.3);font-size:var(--wcss-accent-md-font-size, clamp(1.375rem, 1.8333333333vw, 1.5rem));text-transform:uppercase}.accent-sm{font-family:var(--wcss-accent-sm-family, "Good OT"),var(--wcss-accent-sm-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-sm-letter-spacing, 0.05em);font-weight:var(--wcss-accent-sm-weight, 500);line-height:var(--wcss-accent-sm-line-height, 1.3);font-size:var(--wcss-accent-sm-font-size, clamp(1.125rem, 1.5vw, 1.25rem));text-transform:uppercase}.accent-xs{font-family:var(--wcss-accent-xs-family, "Good OT"),var(--wcss-accent-xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-xs-letter-spacing, 0.1em);font-weight:var(--wcss-accent-xs-weight, 500);line-height:var(--wcss-accent-xs-line-height, 1.3);font-size:var(--wcss-accent-xs-font-size, clamp(1rem, 1.3333333333vw, 1rem));text-transform:uppercase}.accent-2xs{font-family:var(--wcss-accent-2xs-family, "Good OT"),var(--wcss-accent-2xs-family-fallback, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif);letter-spacing:var(--wcss-accent-2xs-letter-spacing, 0.1em);font-weight:var(--wcss-accent-2xs-weight, 450);line-height:var(--wcss-accent-2xs-line-height, 1.3);font-size:var(--wcss-accent-2xs-font-size, clamp(0.875rem, 1.1666666667vw, 0.875rem));text-transform:uppercase}:host{cursor:pointer;user-select:none;text-overflow:ellipsis;max-width:100dvw}:host .wrapper{display:flex;align-items:center;height:var(--ds-size-400, 2rem);padding-right:var(--ds-size-200, 1rem);padding-left:calc(var(--ds-size-150, 0.75rem) + var(--ds-size-300, 1.5rem) + var(--ds-size-100, 0.5rem));border-radius:var(--ds-size-100, 0.5rem);-webkit-tap-highlight-color:transparent}:host .wrapper[class*=shape-box]{border-radius:unset}:host .wrapper[class*=shape-snowflake]{border-radius:unset;line-height:24px}:host .wrapper[class*=shape-pill]{border-radius:30px}:host .wrapper[class*=-lg]{padding-top:var(--ds-size-75, 0.375rem);padding-bottom:var(--ds-size-75, 0.375rem);padding-right:var(--ds-size-150, 0.75rem);line-height:26px}:host .wrapper[class*=-xl]{padding-top:var(--ds-size-100, 0.5rem);padding-bottom:var(--ds-size-100, 0.5rem);padding-right:var(--ds-size-200, 1rem);line-height:26px}:host slot{display:block;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}:host [auro-icon]{--ds-auro-icon-size: var(--ds-size-300, 1.5rem);margin-right:var(--ds-size-150, 0.75rem);margin-left:var(--ds-size-100, 0.5rem)}:host ::slotted(.nestingSpacer){display:inline-block;width:var(--ds-size-300, 1.5rem)}[slot=displayValue]{display:none}:host([loadingplaceholder]) .wrapper{padding-left:calc(var(--ds-size-150, 0.75rem) + var(--ds-size-300, 1.5rem) + var(--ds-size-100, 0.5rem))}:host([selected]) .wrapper{padding-left:0}:host([nocheckmark]) .wrapper{padding-left:var(--ds-size-150, 0.75rem)}:host([nocheckmark]) .wrapper[class*=-lg]{padding-left:var(--ds-size-150, 0.75rem)}:host([nocheckmark]) .wrapper[class*=-xl]{padding-left:var(--ds-size-200, 1rem)}:host([hidden]){display:none}:host([static]){pointer-events:none}:host([disabled]:hover){cursor:auto}:host([disabled]){user-select:none;pointer-events:none}`;
|
|
1520
|
+
// Attempt to parse as JSON array
|
|
1521
|
+
try {
|
|
1663
1522
|
|
|
1664
|
-
|
|
1523
|
+
// Normalize single quotes to double quotes for JSON parsing
|
|
1524
|
+
// This will not handle complex cases but will cover basic usage
|
|
1525
|
+
const parseValue = values.replace(/'([^']*?)'/g, '"$1"');
|
|
1665
1526
|
|
|
1666
|
-
//
|
|
1667
|
-
|
|
1527
|
+
// Attempt parse
|
|
1528
|
+
const parsed = JSON.parse(parseValue);
|
|
1668
1529
|
|
|
1530
|
+
// Ensure parsed value is an array
|
|
1531
|
+
if (!Array.isArray(parsed)) throw new Error('Not an array');
|
|
1669
1532
|
|
|
1670
|
-
|
|
1533
|
+
// Set values to parsed array
|
|
1534
|
+
values = parsed;
|
|
1535
|
+
} catch (err) {
|
|
1671
1536
|
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
* @param {string} version - Version of the component that will be appended to the baseName.
|
|
1677
|
-
* @returns {string} - Unique string to be used for naming.
|
|
1678
|
-
*/
|
|
1679
|
-
generateElementName(baseName, version) {
|
|
1680
|
-
let result = baseName;
|
|
1537
|
+
// If parsing fails, treat as single value
|
|
1538
|
+
values = [value];
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1681
1541
|
|
|
1682
|
-
|
|
1683
|
-
|
|
1542
|
+
// Handle a single number being passed
|
|
1543
|
+
if (typeof values === 'number') {
|
|
1544
|
+
values = [String(values)];
|
|
1545
|
+
}
|
|
1684
1546
|
|
|
1685
|
-
|
|
1547
|
+
// Coerce each value to string and validate types
|
|
1548
|
+
values.forEach((val, index) => {
|
|
1549
|
+
|
|
1550
|
+
// Throw an error for invalid value types
|
|
1551
|
+
if (typeof val !== 'string' && typeof val !== 'number') {
|
|
1552
|
+
throw new Error('Value contains invalid value type. Supported types are string and number.');
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
// Convert numbers to strings for consistency
|
|
1556
|
+
if (typeof val === 'number') {
|
|
1557
|
+
values[index] = String(val);
|
|
1558
|
+
}
|
|
1559
|
+
});
|
|
1560
|
+
|
|
1561
|
+
// Return the resulting array of string values
|
|
1562
|
+
return values;
|
|
1686
1563
|
}
|
|
1687
1564
|
|
|
1688
1565
|
/**
|
|
1689
|
-
*
|
|
1690
|
-
* @param {
|
|
1691
|
-
* @param {
|
|
1692
|
-
* @returns {
|
|
1566
|
+
* Returns whether two arrays of options contain the same elements.
|
|
1567
|
+
* @param {AuroMenuOption[]} arr1 - First array of options.
|
|
1568
|
+
* @param {AuroMenuOption[]} arr2 - Second array of options.
|
|
1569
|
+
* @returns {boolean} True if arrays match, false otherwise.
|
|
1693
1570
|
*/
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
const tag = literal`${unsafeStatic(elementName)}`;
|
|
1571
|
+
optionsArraysMatch(arr1, arr2) {
|
|
1572
|
+
if (arr1.length !== arr2.length) return false;
|
|
1697
1573
|
|
|
1698
|
-
|
|
1699
|
-
|
|
1574
|
+
const set1 = new Set(arr1);
|
|
1575
|
+
const set2 = new Set(arr2);
|
|
1576
|
+
|
|
1577
|
+
for (let item of set1) {
|
|
1578
|
+
if (!set2.has(item)) {
|
|
1579
|
+
return false;
|
|
1580
|
+
}
|
|
1700
1581
|
}
|
|
1701
1582
|
|
|
1702
|
-
return
|
|
1583
|
+
return true;
|
|
1703
1584
|
}
|
|
1704
1585
|
}
|
|
1705
1586
|
|
|
1706
|
-
|
|
1707
|
-
`;class z extends m{constructor(){super(),this._initializeDefaults();}_initializeDefaults(){this.onDark=false,this.appearance="default";}static get properties(){return {...m.properties,onDark:{type:Boolean,reflect:true},appearance:{type:String,reflect:true},svg:{attribute:false,reflect:true}}}static get styles(){return w}async fetchIcon(t,a){let e="";e="logos"===t?await f(`${this.uri}/${t}/${a}.svg`):await f(`${this.uri}/icons/${t}/${a}.svg`);return (new DOMParser).parseFromString(e,"text/html").body.querySelector("svg")}async firstUpdated(){try{if(!this.customSvg){const t=await this.fetchIcon(this.category,this.name);if(t)this.svg=t;else if(!t){const t=(new DOMParser).parseFromString(u,"text/html");this.svg=t.body.firstChild;}}}catch(t){this.svg=void 0;}}}css`.util_displayInline{display:inline}.util_displayInlineBlock{display:inline-block}.util_displayBlock,:host{display:block}.util_displayFlex{display:flex}.util_displayHidden,:host([hidden]:not(:focus):not(:active)){display:none}.util_displayHiddenVisually,:host([hiddenVisually]:not(:focus):not(:active)){position:absolute;overflow:hidden;clip:rect(1px,1px,1px,1px);width:1px;height:1px;padding:0;border:0}:host{display:inline-block;--ds-auro-icon-size: 100%;width:100%;height:100%}:host .logo{color:var(--ds-auro-alaska-color)}:host([onDark]),:host([appearance=inverse]){--ds-auro-alaska-color: #FFF}
|
|
1708
|
-
`;var y=css`:host{--ds-auro-icon-color: var(--ds-basic-color-texticon-default, #2a2a2a);--ds-auro-alaska-color: #02426D;--ds-auro-icon-size: var(--ds-size-300, 1.5rem)}
|
|
1709
|
-
`;var x=css`:host{color:var(--ds-auro-icon-color)}:host([customColor]){color:inherit}:host(:not([onDark])[variant=accent1]),:host(:not([appearance=inverse])[variant=accent1]){--ds-auro-icon-color: var(--ds-basic-color-texticon-accent1, #265688)}:host(:not([onDark])[variant=disabled]),:host(:not([appearance=inverse])[variant=disabled]){--ds-auro-icon-color: var(--ds-basic-color-texticon-disabled, #d0d0d0)}:host(:not([onDark])[variant=muted]),:host(:not([appearance=inverse])[variant=muted]){--ds-auro-icon-color: var(--ds-basic-color-texticon-muted, #676767)}:host(:not([onDark])[variant=statusDefault]),:host(:not([appearance=inverse])[variant=statusDefault]){--ds-auro-icon-color: var(--ds-basic-color-status-default, #afb9c6)}:host(:not([onDark])[variant=statusInfo]),:host(:not([appearance=inverse])[variant=statusInfo]){--ds-auro-icon-color: var(--ds-basic-color-status-info, #01426a)}:host(:not([onDark])[variant=statusSuccess]),:host(:not([appearance=inverse])[variant=statusSuccess]){--ds-auro-icon-color: var(--ds-basic-color-status-success, #447a1f)}:host(:not([onDark])[variant=statusWarning]),:host(:not([appearance=inverse])[variant=statusWarning]){--ds-auro-icon-color: var(--ds-basic-color-status-warning, #fac200)}:host(:not([onDark])[variant=statusError]),:host(:not([appearance=inverse])[variant=statusError]){--ds-auro-icon-color: var(--ds-basic-color-status-error, #e31f26)}:host(:not([onDark])[variant=statusInfoSubtle]),:host(:not([appearance=inverse])[variant=statusInfoSubtle]){--ds-auro-icon-color: var(--ds-basic-color-status-info-subtle, #ebf3f9)}:host(:not([onDark])[variant=statusSuccessSubtle]),:host(:not([appearance=inverse])[variant=statusSuccessSubtle]){--ds-auro-icon-color: var(--ds-basic-color-status-success-subtle, #d6eac7)}:host(:not([onDark])[variant=statusWarningSubtle]),:host(:not([appearance=inverse])[variant=statusWarningSubtle]){--ds-auro-icon-color: var(--ds-basic-color-status-warning-subtle, #fff0b2)}:host(:not([onDark])[variant=statusErrorSubtle]),:host(:not([appearance=inverse])[variant=statusErrorSubtle]){--ds-auro-icon-color: var(--ds-basic-color-status-error-subtle, #fbc6c6)}:host(:not([onDark])[variant=fareBasicEconomy]),:host(:not([appearance=inverse])[variant=fareBasicEconomy]){--ds-auro-icon-color: var(--ds-basic-color-fare-basiceconomy, #97eaf8)}:host(:not([onDark])[variant=fareBusiness]),:host(:not([appearance=inverse])[variant=fareBusiness]){--ds-auro-icon-color: var(--ds-basic-color-fare-business, #01426a)}:host(:not([onDark])[variant=fareEconomy]),:host(:not([appearance=inverse])[variant=fareEconomy]){--ds-auro-icon-color: var(--ds-basic-color-fare-economy, #0074ca)}:host(:not([onDark])[variant=fareFirst]),:host(:not([appearance=inverse])[variant=fareFirst]){--ds-auro-icon-color: var(--ds-basic-color-fare-first, #00274a)}:host(:not([onDark])[variant=farePremiumEconomy]),:host(:not([appearance=inverse])[variant=farePremiumEconomy]){--ds-auro-icon-color: var(--ds-basic-color-fare-premiumeconomy, #005154)}:host(:not([onDark])[variant=tierOneWorldEmerald]),:host(:not([appearance=inverse])[variant=tierOneWorldEmerald]){--ds-auro-icon-color: var(--ds-basic-color-tier-program-oneworld-emerald, #139142)}:host(:not([onDark])[variant=tierOneWorldSapphire]),:host(:not([appearance=inverse])[variant=tierOneWorldSapphire]){--ds-auro-icon-color: var(--ds-basic-color-tier-program-oneworld-sapphire, #015daa)}:host(:not([onDark])[variant=tierOneWorldRuby]),:host(:not([appearance=inverse])[variant=tierOneWorldRuby]){--ds-auro-icon-color: var(--ds-basic-color-tier-program-oneworld-ruby, #a41d4a)}:host([onDark]),:host([appearance=inverse]){--ds-auro-icon-color: var(--ds-basic-color-texticon-inverse, #ffffff)}:host([onDark][variant=disabled]),:host([appearance=inverse][variant=disabled]){--ds-auro-icon-color: var(--ds-basic-color-texticon-inverse-disabled, #7e8894)}:host([onDark][variant=muted]),:host([appearance=inverse][variant=muted]){--ds-auro-icon-color: var(--ds-basic-color-texticon-inverse-muted, #ccd2db)}:host([onDark][variant=statusError]),:host([appearance=inverse][variant=statusError]){--ds-auro-icon-color: var(--ds-advanced-color-state-error-inverse, #f9a4a8)}
|
|
1710
|
-
`;class _ extends z{constructor(){super(),this._initializeDefaults();}_initializeDefaults(){this.variant=void 0,this.uri="https://cdn.jsdelivr.net/npm/@alaskaairux/icons@latest/dist",this.runtimeUtils=new p;}static get properties(){return {...z.properties,ariaHidden:{type:String,reflect:true},category:{type:String,reflect:true},customColor:{type:Boolean,reflect:true},customSvg:{type:Boolean},label:{type:Boolean,reflect:true},name:{type:String,reflect:true},variant:{type:String,reflect:true}}}static get styles(){return [z.styles,y,w,x]}static register(t="auro-icon"){p.prototype.registerComponent(t,_);}connectedCallback(){super.connectedCallback(),this.runtimeUtils.handleComponentTagRename(this,"auro-icon");}exposeCssParts(){this.setAttribute("exportparts","svg:iconSvg");}async firstUpdated(){if(await super.firstUpdated(),this.hasAttribute("ariaHidden")&&this.svg){const t=this.svg.querySelector("desc");t&&(t.remove(),this.svg.removeAttribute("aria-labelledby"));}}render(){const t={labelWrapper:true,util_displayHiddenVisually:!this.label};return html`
|
|
1711
|
-
<div class="componentWrapper">
|
|
1712
|
-
<div
|
|
1713
|
-
class="${classMap({svgWrapper:true})}"
|
|
1714
|
-
title="${ifDefined(this.title||void 0)}">
|
|
1715
|
-
<span aria-hidden="${ifDefined(this.ariaHidden||true)}" part="svg">
|
|
1716
|
-
${this.customSvg?html`
|
|
1717
|
-
<slot name="svg"></slot>
|
|
1718
|
-
`:html`
|
|
1719
|
-
${this.svg}
|
|
1720
|
-
`}
|
|
1721
|
-
</span>
|
|
1722
|
-
</div>
|
|
1723
|
-
|
|
1724
|
-
<div class="${classMap(t)}" part="label">
|
|
1725
|
-
<slot></slot>
|
|
1726
|
-
</div>
|
|
1727
|
-
</div>
|
|
1728
|
-
`}}
|
|
1729
|
-
|
|
1730
|
-
var iconVersion = '9.1.2';
|
|
1731
|
-
|
|
1732
|
-
var checkmarkIcon = {"svg":"<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" aria-labelledby=\"checkmark-sm__desc\" class=\"ico_squareLarge\" role=\"img\" style=\"min-width:var(--auro-size-lg, var(--ds-size-300, 1.5rem));height:var(--auro-size-lg, var(--ds-size-300, 1.5rem));fill:currentColor\" viewBox=\"0 0 24 24\" part=\"svg\"><title/><desc id=\"checkmark-sm__desc\">a small check mark.</desc><path d=\"M8.461 11.84a.625.625 0 1 0-.922.844l2.504 2.738c.247.27.674.27.922 0l5.496-6a.625.625 0 1 0-.922-.844l-5.035 5.496z\"/></svg>"};
|
|
1587
|
+
const MenuContext = createContext('menu-context');
|
|
1733
1588
|
|
|
1734
|
-
|
|
1589
|
+
/* eslint-disable no-underscore-dangle */
|
|
1590
|
+
// Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
1735
1591
|
// See LICENSE in the project root for license information.
|
|
1736
1592
|
|
|
1737
1593
|
|
|
1738
|
-
let menuOptionIdCounter = 0;
|
|
1739
1594
|
|
|
1740
1595
|
/**
|
|
1741
|
-
* The `auro-
|
|
1742
|
-
* @customElement auro-
|
|
1743
|
-
*
|
|
1744
|
-
* @slot default - The default slot for the menu option text.
|
|
1596
|
+
* The `auro-menu` element provides users a way to select from a list of options.
|
|
1597
|
+
* @customElement auro-menu
|
|
1745
1598
|
*
|
|
1746
|
-
* @event
|
|
1599
|
+
* @event {CustomEvent<Element>} auroMenu-activatedOption - Notifies that a menuoption has been made `active`.
|
|
1600
|
+
* @event {CustomEvent<any>} auroMenu-customEventFired - Notifies that a custom event has been fired.
|
|
1601
|
+
* @event {CustomEvent<{ loading: boolean; hasLoadingPlaceholder: boolean; }>} auroMenu-loadingChange - Notifies when the loading attribute is changed.
|
|
1602
|
+
* @event {CustomEvent<any>} auroMenu-selectValueFailure - Notifies that an attempt to select a menuoption by matching a value has failed.
|
|
1603
|
+
* @event {CustomEvent<{ values: HTMLElement[] }>} auroMenu-deselectPrevented - Notifies that deselection was prevented and includes the affected options in `detail.values`.
|
|
1604
|
+
* @event {CustomEvent<any>} auroMenu-selectValueReset - Notifies that the component value has been reset.
|
|
1605
|
+
* @event {CustomEvent<any>} auroMenu-selectedOption - Notifies that a new menuoption selection has been made.
|
|
1606
|
+
* @slot loadingText - Text to show while loading attribute is set
|
|
1607
|
+
* @slot loadingIcon - Icon to show while loading attribute is set
|
|
1608
|
+
* @slot - Slot for insertion of menu options.
|
|
1747
1609
|
*/
|
|
1748
|
-
class AuroMenuOption extends AuroElement {
|
|
1749
1610
|
|
|
1750
|
-
|
|
1751
|
-
* This will register this element with the browser.
|
|
1752
|
-
* @param {string} [name="auro-menuoption"] - The name of the element that you want to register.
|
|
1753
|
-
*
|
|
1754
|
-
* @example
|
|
1755
|
-
* AuroMenuOption.register("custom-menuoption") // this will register this element to <custom-menuoption/>
|
|
1756
|
-
*
|
|
1757
|
-
*/
|
|
1758
|
-
static register(name = "auro-menuoption") {
|
|
1759
|
-
AuroLibraryRuntimeUtils.prototype.registerComponent(name, AuroMenuOption);
|
|
1760
|
-
}
|
|
1611
|
+
/* eslint-disable max-lines */
|
|
1761
1612
|
|
|
1762
|
-
|
|
1763
|
-
* Returns whether the menu option is currently active and selectable.
|
|
1764
|
-
* An option is considered active if it is not hidden, not disabled, and not static.
|
|
1765
|
-
* @returns {boolean} True if the option is active, false otherwise.
|
|
1766
|
-
*/
|
|
1767
|
-
get isActive() {
|
|
1768
|
-
return !this.hasAttribute('hidden') &&
|
|
1769
|
-
!this.disabled &&
|
|
1770
|
-
!this.hasAttribute('static');
|
|
1771
|
-
}
|
|
1613
|
+
class AuroMenu extends AuroElement {
|
|
1772
1614
|
|
|
1773
1615
|
constructor() {
|
|
1774
1616
|
super();
|
|
1775
1617
|
|
|
1776
|
-
|
|
1618
|
+
// State properties (reactive)
|
|
1777
1619
|
|
|
1778
1620
|
/**
|
|
1779
1621
|
* @private
|
|
1780
1622
|
*/
|
|
1781
|
-
this.shape =
|
|
1623
|
+
this.shape = "box";
|
|
1782
1624
|
|
|
1783
1625
|
/**
|
|
1784
1626
|
* @private
|
|
1785
1627
|
*/
|
|
1786
|
-
this.size =
|
|
1787
|
-
|
|
1788
|
-
/**
|
|
1789
|
-
* Generate unique names for dependency components.
|
|
1790
|
-
*/
|
|
1791
|
-
const versioning = new AuroDependencyVersioning();
|
|
1792
|
-
this.iconTag = versioning.generateTag('auro-formkit-menuoption-icon', iconVersion, _);
|
|
1628
|
+
this.size = "sm";
|
|
1793
1629
|
|
|
1794
|
-
|
|
1630
|
+
// Value of the selected options
|
|
1631
|
+
this.value = undefined;
|
|
1632
|
+
// Currently selected option
|
|
1633
|
+
this.optionSelected = undefined;
|
|
1634
|
+
// String used for highlighting/filtering
|
|
1635
|
+
this.matchWord = undefined;
|
|
1636
|
+
// Hide the checkmark icon on selected options
|
|
1795
1637
|
this.noCheckmark = false;
|
|
1796
|
-
|
|
1797
|
-
this.
|
|
1638
|
+
// Currently active option
|
|
1639
|
+
this.optionActive = undefined;
|
|
1640
|
+
// Loading state
|
|
1641
|
+
this.loading = false;
|
|
1642
|
+
// Multi-select mode
|
|
1643
|
+
this.multiSelect = false;
|
|
1644
|
+
// Allow deselecting of menu options
|
|
1645
|
+
this.allowDeselect = false;
|
|
1646
|
+
// Select all matching options when setting value in multi-select mode
|
|
1647
|
+
this.selectAllMatchingOptions = false;
|
|
1648
|
+
|
|
1649
|
+
// Event Bindings
|
|
1798
1650
|
|
|
1799
1651
|
/**
|
|
1800
1652
|
* @private
|
|
1801
1653
|
*/
|
|
1802
|
-
this.
|
|
1654
|
+
this.handleSlotChange = this.handleSlotChange.bind(this);
|
|
1803
1655
|
|
|
1804
|
-
//
|
|
1805
|
-
this.menuService = null;
|
|
1806
|
-
this.unsubscribe = null;
|
|
1656
|
+
// Instance properties (non-reactive)
|
|
1807
1657
|
|
|
1808
1658
|
/**
|
|
1809
1659
|
* @private
|
|
1810
1660
|
*/
|
|
1811
|
-
|
|
1661
|
+
Object.assign(this, {
|
|
1662
|
+
// Root-level menu (true) or a nested submenu (false)
|
|
1663
|
+
rootMenu: true,
|
|
1664
|
+
// Currently focused/active menu item index
|
|
1665
|
+
_index: -1,
|
|
1666
|
+
// Nested menu spacer
|
|
1667
|
+
nestingSpacer: '<span class="nestingSpacer"></span>',
|
|
1668
|
+
// Loading indicator for slot elements
|
|
1669
|
+
loadingSlots: null,
|
|
1670
|
+
});
|
|
1812
1671
|
}
|
|
1813
1672
|
|
|
1814
1673
|
static get properties() {
|
|
@@ -1816,7 +1675,15 @@ class AuroMenuOption extends AuroElement {
|
|
|
1816
1675
|
...super.properties,
|
|
1817
1676
|
|
|
1818
1677
|
/**
|
|
1819
|
-
*
|
|
1678
|
+
* Allows deselecting an already selected option when clicked again in single-select mode.
|
|
1679
|
+
*/
|
|
1680
|
+
allowDeselect: {
|
|
1681
|
+
type: Boolean,
|
|
1682
|
+
reflect: true,
|
|
1683
|
+
},
|
|
1684
|
+
|
|
1685
|
+
/**
|
|
1686
|
+
* When true, the entire menu and all options are disabled.
|
|
1820
1687
|
*/
|
|
1821
1688
|
disabled: {
|
|
1822
1689
|
type: Boolean,
|
|
@@ -1824,11 +1691,10 @@ class AuroMenuOption extends AuroElement {
|
|
|
1824
1691
|
},
|
|
1825
1692
|
|
|
1826
1693
|
/**
|
|
1827
|
-
*
|
|
1694
|
+
* Indicates whether the menu has a loadingIcon or loadingText to render when in a loading state.
|
|
1828
1695
|
*/
|
|
1829
|
-
|
|
1830
|
-
type:
|
|
1831
|
-
reflect: true
|
|
1696
|
+
hasLoadingPlaceholder: {
|
|
1697
|
+
type: Boolean
|
|
1832
1698
|
},
|
|
1833
1699
|
|
|
1834
1700
|
/**
|
|
@@ -1839,394 +1705,528 @@ class AuroMenuOption extends AuroElement {
|
|
|
1839
1705
|
},
|
|
1840
1706
|
|
|
1841
1707
|
/**
|
|
1842
|
-
*
|
|
1708
|
+
* Indent level for submenus.
|
|
1709
|
+
* @private
|
|
1843
1710
|
*/
|
|
1844
|
-
|
|
1845
|
-
type:
|
|
1846
|
-
reflect:
|
|
1711
|
+
level: {
|
|
1712
|
+
type: Number,
|
|
1713
|
+
reflect: false,
|
|
1714
|
+
attribute: false
|
|
1847
1715
|
},
|
|
1848
1716
|
|
|
1849
1717
|
/**
|
|
1850
|
-
*
|
|
1718
|
+
* When true, displays a loading state using the loadingIcon and loadingText slots if provided.
|
|
1851
1719
|
*/
|
|
1852
|
-
|
|
1853
|
-
type:
|
|
1854
|
-
|
|
1720
|
+
loading: {
|
|
1721
|
+
type: Boolean,
|
|
1722
|
+
reflect: true
|
|
1855
1723
|
},
|
|
1856
1724
|
|
|
1857
1725
|
/**
|
|
1858
|
-
*
|
|
1726
|
+
* Specifies a string used to highlight matched string parts in options.
|
|
1859
1727
|
*/
|
|
1860
1728
|
matchWord: {
|
|
1861
1729
|
type: String,
|
|
1862
|
-
|
|
1730
|
+
attribute: 'matchword'
|
|
1863
1731
|
},
|
|
1864
1732
|
|
|
1865
1733
|
/**
|
|
1866
|
-
*
|
|
1734
|
+
* When true, the selected option can be multiple options.
|
|
1867
1735
|
*/
|
|
1868
|
-
|
|
1736
|
+
multiSelect: {
|
|
1869
1737
|
type: Boolean,
|
|
1870
|
-
reflect: true
|
|
1738
|
+
reflect: true,
|
|
1739
|
+
attribute: 'multiselect'
|
|
1871
1740
|
},
|
|
1872
1741
|
|
|
1873
1742
|
/**
|
|
1874
|
-
* When true,
|
|
1743
|
+
* When true, selected option will not show the checkmark.
|
|
1875
1744
|
*/
|
|
1876
|
-
|
|
1745
|
+
noCheckmark: {
|
|
1877
1746
|
type: Boolean,
|
|
1878
1747
|
reflect: true,
|
|
1879
|
-
attribute: '
|
|
1748
|
+
attribute: 'nocheckmark'
|
|
1880
1749
|
},
|
|
1881
1750
|
|
|
1882
1751
|
/**
|
|
1883
|
-
* Specifies
|
|
1752
|
+
* Specifies the current active menuOption.
|
|
1884
1753
|
*/
|
|
1885
|
-
|
|
1886
|
-
type:
|
|
1887
|
-
|
|
1754
|
+
optionActive: {
|
|
1755
|
+
type: Object,
|
|
1756
|
+
attribute: 'optionactive'
|
|
1888
1757
|
},
|
|
1889
1758
|
|
|
1890
1759
|
/**
|
|
1891
|
-
*
|
|
1760
|
+
* An array of currently selected menu options, type `HTMLElement` by default. In multi-select mode, `optionSelected` is an array of HTML elements.
|
|
1892
1761
|
*/
|
|
1893
|
-
|
|
1894
|
-
|
|
1762
|
+
optionSelected: {
|
|
1763
|
+
// Allow HTMLElement, HTMLElement[] arrays and undefined
|
|
1764
|
+
type: Object
|
|
1765
|
+
},
|
|
1766
|
+
|
|
1767
|
+
/**
|
|
1768
|
+
* Available menu options.
|
|
1769
|
+
* @readonly
|
|
1770
|
+
*/
|
|
1771
|
+
options: {
|
|
1772
|
+
type: Array,
|
|
1773
|
+
reflect: false,
|
|
1774
|
+
attribute: false
|
|
1775
|
+
},
|
|
1776
|
+
|
|
1777
|
+
/**
|
|
1778
|
+
* Sets the size of the menu.
|
|
1779
|
+
* @type {'sm' | 'md'}
|
|
1780
|
+
* @default 'sm'
|
|
1781
|
+
*/
|
|
1782
|
+
size: {
|
|
1783
|
+
type: String,
|
|
1895
1784
|
reflect: true
|
|
1896
1785
|
},
|
|
1897
1786
|
|
|
1898
1787
|
/**
|
|
1899
|
-
*
|
|
1788
|
+
* When true, selects all options that match the provided value/key when setting value and multiselect is enabled.
|
|
1900
1789
|
*/
|
|
1901
|
-
|
|
1790
|
+
selectAllMatchingOptions: {
|
|
1791
|
+
type: Boolean,
|
|
1792
|
+
reflect: true,
|
|
1793
|
+
},
|
|
1794
|
+
|
|
1795
|
+
/**
|
|
1796
|
+
* Sets the shape of the menu.
|
|
1797
|
+
* @type {'box' | 'round'}
|
|
1798
|
+
* @default 'box'
|
|
1799
|
+
*/
|
|
1800
|
+
shape: {
|
|
1902
1801
|
type: String,
|
|
1903
1802
|
reflect: true
|
|
1904
1803
|
},
|
|
1804
|
+
|
|
1805
|
+
/**
|
|
1806
|
+
* The value of the selected option. In multi-select mode, this is a JSON stringified array of selected option values.
|
|
1807
|
+
*/
|
|
1808
|
+
value: {
|
|
1809
|
+
type: String,
|
|
1810
|
+
reflect: true,
|
|
1811
|
+
attribute: 'value'
|
|
1812
|
+
}
|
|
1905
1813
|
};
|
|
1906
1814
|
}
|
|
1907
1815
|
|
|
1908
1816
|
static get styles() {
|
|
1909
1817
|
return [
|
|
1910
|
-
styleCss,
|
|
1911
|
-
colorCss,
|
|
1818
|
+
styleCss$1,
|
|
1819
|
+
colorCss$1,
|
|
1912
1820
|
tokensCss
|
|
1913
1821
|
];
|
|
1914
1822
|
}
|
|
1915
1823
|
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
this.
|
|
1824
|
+
/**
|
|
1825
|
+
* @readonly
|
|
1826
|
+
* @returns {string} - Returns the label of the currently selected option(s).
|
|
1827
|
+
*/
|
|
1828
|
+
get currentLabel() {
|
|
1829
|
+
return this.menuService.currentLabel;
|
|
1830
|
+
};
|
|
1831
|
+
|
|
1832
|
+
/**
|
|
1833
|
+
* @readonly
|
|
1834
|
+
* @returns {Array<HTMLElement>} - Returns the array of available menu options.
|
|
1835
|
+
* @deprecated Use `options` property instead.
|
|
1836
|
+
*/
|
|
1837
|
+
get items() {
|
|
1838
|
+
return this.options;
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1841
|
+
/**
|
|
1842
|
+
* @returns {number} - Returns the index of the currently active option.
|
|
1843
|
+
*/
|
|
1844
|
+
get index() {
|
|
1845
|
+
return this._index;
|
|
1846
|
+
}
|
|
1847
|
+
|
|
1848
|
+
/**
|
|
1849
|
+
* @param {number} value - Sets the index of the currently active option.
|
|
1850
|
+
*/
|
|
1851
|
+
set index(value) {
|
|
1852
|
+
this.menuService.setHighlightedIndex(value);
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
/**
|
|
1856
|
+
* This will register this element with the browser.
|
|
1857
|
+
* @param {string} [name="auro-menu"] - The name of the element that you want to register.
|
|
1858
|
+
*
|
|
1859
|
+
* @example
|
|
1860
|
+
* AuroMenu.register("custom-menu") // this will register this element to <custom-menu/>
|
|
1861
|
+
*
|
|
1862
|
+
*/
|
|
1863
|
+
static register(name = "auro-menu") {
|
|
1864
|
+
AuroLibraryRuntimeUtils.prototype.registerComponent(name, AuroMenu);
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
/**
|
|
1868
|
+
* Formatted value based on `multiSelect` state.
|
|
1869
|
+
* Default type is `String`, changing to `Array<String>` when `multiSelect` is true.
|
|
1870
|
+
* @private
|
|
1871
|
+
* @returns {String|Array<String>}
|
|
1872
|
+
*/
|
|
1873
|
+
get formattedValue() {
|
|
1874
|
+
return this.menuService.currentValue;
|
|
1875
|
+
}
|
|
1876
|
+
|
|
1877
|
+
/**
|
|
1878
|
+
* Gets the current property values for the menu service.
|
|
1879
|
+
* @private
|
|
1880
|
+
* @returns {Object}
|
|
1881
|
+
*/
|
|
1882
|
+
get propertyValues() {
|
|
1883
|
+
return {
|
|
1884
|
+
size: this.size,
|
|
1885
|
+
shape: this.shape,
|
|
1886
|
+
noCheckmark: this.nocheckmark,
|
|
1887
|
+
disabled: this.disabled
|
|
1888
|
+
};
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
/**
|
|
1892
|
+
* Provides the menu context to child components.
|
|
1893
|
+
* Initializes the MenuService and subscribes to menu changes.
|
|
1894
|
+
* @protected
|
|
1895
|
+
*/
|
|
1896
|
+
provideContext() {
|
|
1897
|
+
if (this.parentElement && this.parentElement.closest('auro-menu, [auro-menu]')) {
|
|
1898
|
+
this.rootMenu = false;
|
|
1899
|
+
this.menuService = this.parentElement.menuService;
|
|
1900
|
+
this._contextProvider = this.parentElement._contextProvider;
|
|
1901
|
+
return;
|
|
1902
|
+
}
|
|
1922
1903
|
|
|
1923
|
-
|
|
1924
|
-
this.
|
|
1904
|
+
this.menuService = new MenuService({host: this});
|
|
1905
|
+
this.menuService.setProperties(this.propertyValues);
|
|
1906
|
+
this.menuService.subscribe(this.handleMenuChange.bind(this));
|
|
1907
|
+
this._contextProvider = new ContextProvider(this, {
|
|
1925
1908
|
context: MenuContext,
|
|
1926
|
-
|
|
1927
|
-
subscribe: true
|
|
1909
|
+
initialValue: this.menuService
|
|
1928
1910
|
});
|
|
1911
|
+
}
|
|
1929
1912
|
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
// if at least one source attribute is actually present so that the
|
|
1937
|
-
// `updated()` fallback can run when the value property arrives later.
|
|
1938
|
-
const valueAttr = this.getAttribute('value');
|
|
1939
|
-
const keyAttr = this.getAttribute('key');
|
|
1940
|
-
const resolvedKey = keyAttr !== null ? keyAttr : valueAttr;
|
|
1941
|
-
if (resolvedKey !== null) {
|
|
1942
|
-
this.key = resolvedKey;
|
|
1943
|
-
}
|
|
1913
|
+
/**
|
|
1914
|
+
* Updates the currently active option in the menu.
|
|
1915
|
+
* @param {HTMLElement} option - The option to set as active.
|
|
1916
|
+
*/
|
|
1917
|
+
updateActiveOption(option) {
|
|
1918
|
+
this.menuService.setHighlightedOption(option);
|
|
1944
1919
|
}
|
|
1945
1920
|
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1921
|
+
/**
|
|
1922
|
+
* Sets the internal value and manages update state.
|
|
1923
|
+
* @param {String|Array<String>} value - The value to set.
|
|
1924
|
+
* @protected
|
|
1925
|
+
*/
|
|
1926
|
+
setInternalValue(value) {
|
|
1927
|
+
if (this.value !== value) {
|
|
1928
|
+
this.internalUpdateInProgress = true;
|
|
1929
|
+
this.value = value;
|
|
1949
1930
|
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
this.id = `menuoption-${menuOptionIdCounter}`;
|
|
1931
|
+
setTimeout(() => {
|
|
1932
|
+
this.internalUpdateInProgress = false;
|
|
1933
|
+
});
|
|
1954
1934
|
}
|
|
1955
|
-
|
|
1956
|
-
this.setAttribute('role', 'option');
|
|
1957
|
-
this.setAttribute('aria-selected', 'false');
|
|
1958
|
-
|
|
1959
|
-
this.addEventListener('mouseover', () => {
|
|
1960
|
-
this.dispatchEvent(new CustomEvent('auroMenuOption-mouseover', {
|
|
1961
|
-
bubbles: true,
|
|
1962
|
-
cancelable: false,
|
|
1963
|
-
composed: true,
|
|
1964
|
-
detail: this
|
|
1965
|
-
}));
|
|
1966
|
-
});
|
|
1967
1935
|
}
|
|
1968
1936
|
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
this.setAttribute('aria-selected', this.selected.toString());
|
|
1937
|
+
/**
|
|
1938
|
+
* Handles changes from the menu service and updates component state.
|
|
1939
|
+
* @param {Object} event - The event object from the menu service.
|
|
1940
|
+
* @protected
|
|
1941
|
+
*/
|
|
1942
|
+
handleMenuChange(event) {
|
|
1943
|
+
if (event.type === 'valueChange') {
|
|
1977
1944
|
|
|
1978
|
-
//
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
}
|
|
1982
|
-
}
|
|
1945
|
+
// New option is array value or first option with fallback to undefined for empty array in all cases
|
|
1946
|
+
const newOption = this.multiSelect && event.options.length ? event.options : event.options[0] || undefined;
|
|
1947
|
+
const newValue = event.stringValue;
|
|
1983
1948
|
|
|
1984
|
-
|
|
1985
|
-
if (this.
|
|
1986
|
-
this.
|
|
1987
|
-
|
|
1988
|
-
this.removeAttribute('aria-disabled');
|
|
1949
|
+
// Check if the option or value has actually changed
|
|
1950
|
+
if (this.optionSelected !== newOption || this.stringValue !== newValue) {
|
|
1951
|
+
this.optionSelected = newOption;
|
|
1952
|
+
this.setInternalValue(newValue);
|
|
1989
1953
|
}
|
|
1990
|
-
}
|
|
1991
|
-
|
|
1992
|
-
if (changedProperties.has('active')) {
|
|
1993
|
-
this.updateActiveClasses();
|
|
1994
|
-
}
|
|
1995
1954
|
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
this.updateTextHighlight();
|
|
1955
|
+
// Notify components of selection change
|
|
1956
|
+
this.notifySelectionChange(event);
|
|
1999
1957
|
}
|
|
2000
1958
|
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
// before setting its value property, connectedCallback skips key
|
|
2005
|
-
// assignment because both attributes are null at that point. The Lit
|
|
2006
|
-
// property default for `key` is undefined (not null), so strict
|
|
2007
|
-
// === null would miss the case and the fallback would never run.
|
|
2008
|
-
if (changedProperties.has('value') && this.key == null) { // eslint-disable-line eqeqeq, no-eq-null
|
|
2009
|
-
this.key = this.value;
|
|
1959
|
+
if (event.type === 'highlightChange') {
|
|
1960
|
+
this.optionActive = event.option;
|
|
1961
|
+
this._index = event.index;
|
|
2010
1962
|
}
|
|
2011
|
-
}
|
|
2012
1963
|
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
this.
|
|
2016
|
-
|
|
1964
|
+
if (event.type === 'optionsChange') {
|
|
1965
|
+
this.options = event.options;
|
|
1966
|
+
this.dispatchEvent(new CustomEvent('auroMenu-optionsChange', {
|
|
1967
|
+
detail: {
|
|
1968
|
+
options: event.options
|
|
1969
|
+
}
|
|
1970
|
+
}));
|
|
2017
1971
|
}
|
|
2018
1972
|
}
|
|
2019
1973
|
|
|
2020
1974
|
/**
|
|
2021
|
-
*
|
|
2022
|
-
*
|
|
1975
|
+
* Gets the currently selected options.
|
|
1976
|
+
* @returns {Array<HTMLElement>}
|
|
2023
1977
|
*/
|
|
2024
|
-
|
|
2025
|
-
this.
|
|
2026
|
-
this.addEventListener('mouseenter', this.handleMouseEnter.bind(this));
|
|
1978
|
+
get selectedOptions() {
|
|
1979
|
+
return this.menuService ? this.menuService.selectedOptions : [];
|
|
2027
1980
|
}
|
|
2028
1981
|
|
|
2029
1982
|
/**
|
|
2030
|
-
*
|
|
2031
|
-
*
|
|
2032
|
-
* @param {Object} service - The menu service instance to attach to.
|
|
1983
|
+
* Gets the first selected option, or null if none.
|
|
1984
|
+
* @returns {HTMLElement|null}
|
|
2033
1985
|
*/
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
return;
|
|
2037
|
-
}
|
|
2038
|
-
this.menuService = service;
|
|
2039
|
-
this.menuService.addMenuOption(this);
|
|
2040
|
-
this.menuService.subscribe(this.handleMenuChange);
|
|
1986
|
+
get selectedOption() {
|
|
1987
|
+
return this.menuService ? this.menuService.selectedOptions[0] : null;
|
|
2041
1988
|
}
|
|
2042
1989
|
|
|
2043
|
-
|
|
2044
|
-
* Handles changes from the menu service and updates the option's state.
|
|
2045
|
-
* This function synchronizes the option's properties and selection/highlight state with menu events.
|
|
2046
|
-
* @param {Object} event - The event object from the menu service.
|
|
2047
|
-
*/
|
|
2048
|
-
handleMenuChange(event) {
|
|
1990
|
+
// Lifecycle Methods
|
|
2049
1991
|
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
1992
|
+
connectedCallback() {
|
|
1993
|
+
super.connectedCallback();
|
|
1994
|
+
|
|
1995
|
+
this.provideContext();
|
|
1996
|
+
|
|
1997
|
+
// this.addEventListener('keydown', this.handleKeyDown);
|
|
1998
|
+
this.addEventListener('auroMenuOption-click', this.handleMouseSelect);
|
|
1999
|
+
this.addEventListener('auroMenuOption-mouseover', this.handleOptionHover);
|
|
2000
|
+
this.addEventListener('slotchange', this.handleSlotChange);
|
|
2001
|
+
this.setTagAttribute("auro-menu");
|
|
2002
|
+
}
|
|
2003
|
+
|
|
2004
|
+
disconnectedCallback() {
|
|
2005
|
+
// this.removeEventListener('keydown', this.handleKeyDown);
|
|
2006
|
+
this.removeEventListener('auroMenuOption-click', this.handleMouseSelect);
|
|
2007
|
+
this.removeEventListener('auroMenuOption-mouseover', this.handleOptionHover);
|
|
2008
|
+
this.removeEventListener('slotchange', this.handleSlotChange);
|
|
2009
|
+
|
|
2010
|
+
super.disconnectedCallback();
|
|
2011
|
+
}
|
|
2012
|
+
|
|
2013
|
+
firstUpdated() {
|
|
2014
|
+
AuroLibraryRuntimeUtils.prototype.handleComponentTagRename(this, 'auro-menu');
|
|
2015
|
+
|
|
2016
|
+
this.loadingSlots = this.querySelectorAll("[slot='loadingText'], [slot='loadingIcon']");
|
|
2017
|
+
this.initializeMenu();
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
|
|
2021
|
+
updated(changedProperties) {
|
|
2022
|
+
super.updated(changedProperties);
|
|
2023
|
+
|
|
2024
|
+
// Apply value selection synchronously so that static-HTML fixtures
|
|
2025
|
+
// resolve within a single update cycle. The refactored selectByValue
|
|
2026
|
+
// no longer calls reset() first, so the destructive intermediate-event
|
|
2027
|
+
// cascade that originally required deferral is eliminated. If option
|
|
2028
|
+
// keys are not yet resolved (framework mount-order race), selectByValue
|
|
2029
|
+
// queues a bounded retry automatically via queuePendingValue.
|
|
2030
|
+
if (changedProperties.has('value') && !this.internalUpdateInProgress) {
|
|
2031
|
+
this.menuService.selectByValue(this.value);
|
|
2053
2032
|
}
|
|
2054
2033
|
|
|
2055
|
-
//
|
|
2056
|
-
if (
|
|
2057
|
-
this
|
|
2034
|
+
// Handle loading state changes
|
|
2035
|
+
if (changedProperties.has('loading')) {
|
|
2036
|
+
this.setLoadingState(this.loading);
|
|
2058
2037
|
}
|
|
2059
2038
|
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2039
|
+
if (changedProperties.has('multiSelect') && this.rootMenu) {
|
|
2040
|
+
if (this.multiSelect) {
|
|
2041
|
+
this.setAttribute('aria-multiselectable', 'true');
|
|
2042
|
+
} else {
|
|
2043
|
+
this.removeAttribute('aria-multiselectable');
|
|
2044
|
+
}
|
|
2065
2045
|
}
|
|
2046
|
+
}
|
|
2066
2047
|
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2048
|
+
/**
|
|
2049
|
+
* Sets an attribute that matches the default tag name if the tag name is not the default.
|
|
2050
|
+
* @param {string} tagName - The tag name to set as an attribute.
|
|
2051
|
+
* @private
|
|
2052
|
+
*/
|
|
2053
|
+
setTagAttribute(tagName) {
|
|
2054
|
+
if (this.tagName.toLowerCase() !== tagName) {
|
|
2055
|
+
this.setAttribute(tagName, true);
|
|
2070
2056
|
}
|
|
2071
2057
|
}
|
|
2072
2058
|
|
|
2073
2059
|
/**
|
|
2074
|
-
*
|
|
2075
|
-
*
|
|
2076
|
-
* @
|
|
2060
|
+
* Sets the loading state and dispatches a loading change event.
|
|
2061
|
+
* @param {boolean} isLoading - Whether the menu is loading.
|
|
2062
|
+
* @protected
|
|
2063
|
+
*/
|
|
2064
|
+
setLoadingState(isLoading) {
|
|
2065
|
+
this.setAttribute("aria-busy", isLoading);
|
|
2066
|
+
dispatchMenuEvent(this, "auroMenu-loadingChange", {
|
|
2067
|
+
loading: isLoading,
|
|
2068
|
+
hasLoadingPlaceholder: this.hasLoadingPlaceholder
|
|
2069
|
+
});
|
|
2070
|
+
}
|
|
2071
|
+
|
|
2072
|
+
// Init Methods
|
|
2073
|
+
|
|
2074
|
+
/**
|
|
2075
|
+
* Initializes the menu's state and structure.
|
|
2076
|
+
* @private
|
|
2077
2077
|
*/
|
|
2078
|
-
|
|
2079
|
-
this.
|
|
2080
|
-
|
|
2078
|
+
initializeMenu() {
|
|
2079
|
+
if (this.rootMenu) {
|
|
2080
|
+
this.setAttribute('role', 'listbox');
|
|
2081
|
+
this.setAttribute('root', '');
|
|
2081
2082
|
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2083
|
+
if (this.multiSelect) {
|
|
2084
|
+
this.setAttribute('aria-multiselectable', 'true');
|
|
2085
|
+
}
|
|
2085
2086
|
}
|
|
2086
2087
|
|
|
2087
|
-
|
|
2088
|
-
this.internalUpdateInProgress = false;
|
|
2089
|
-
}, 0);
|
|
2088
|
+
this.handleNestedMenus(this);
|
|
2090
2089
|
}
|
|
2091
2090
|
|
|
2092
2091
|
/**
|
|
2093
|
-
*
|
|
2094
|
-
*
|
|
2095
|
-
* @param {boolean} isSelected - Whether the option should be marked as selected.
|
|
2096
|
-
* @deprecated Simply modify the `selected` property directly instead.
|
|
2092
|
+
* Selects the currently highlighted option.
|
|
2093
|
+
* @protected
|
|
2097
2094
|
*/
|
|
2098
|
-
|
|
2099
|
-
this.
|
|
2095
|
+
makeSelection() {
|
|
2096
|
+
this.menuService.selectHighlightedOption();
|
|
2100
2097
|
}
|
|
2101
2098
|
|
|
2102
2099
|
/**
|
|
2103
|
-
*
|
|
2104
|
-
*
|
|
2105
|
-
* @param {boolean} isActive - Whether the option should be marked as active.
|
|
2106
|
-
* @deprecated Simply modify the `active` property directly instead.
|
|
2100
|
+
* Resets all options to their default state.
|
|
2101
|
+
* @private
|
|
2107
2102
|
*/
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
this.
|
|
2112
|
-
this.updateActiveClasses();
|
|
2103
|
+
clearSelection() {
|
|
2104
|
+
this.optionSelected = undefined;
|
|
2105
|
+
this.value = undefined;
|
|
2106
|
+
this._index = -1;
|
|
2113
2107
|
}
|
|
2114
2108
|
|
|
2115
2109
|
/**
|
|
2116
|
-
*
|
|
2117
|
-
* This
|
|
2118
|
-
* @
|
|
2110
|
+
* Resets the menu to its initial state.
|
|
2111
|
+
* This is the only way to return value to undefined.
|
|
2112
|
+
* @public
|
|
2119
2113
|
*/
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
if (this.active) this.classList.add('active');
|
|
2123
|
-
else this.classList.remove('active');
|
|
2124
|
-
}
|
|
2114
|
+
reset() {
|
|
2115
|
+
this.menuService.reset();
|
|
2125
2116
|
|
|
2117
|
+
// Dispatch reset event
|
|
2118
|
+
dispatchMenuEvent(this, 'auroMenu-selectValueReset');
|
|
2119
|
+
}
|
|
2126
2120
|
|
|
2127
2121
|
/**
|
|
2128
|
-
*
|
|
2129
|
-
* This function highlights matching text segments and manages nested spacers for display formatting.
|
|
2122
|
+
* Handles nested menu structure.
|
|
2130
2123
|
* @private
|
|
2124
|
+
* @param {HTMLElement} menu - Root menu element.
|
|
2131
2125
|
*/
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
// Regex for matchWord if needed
|
|
2135
|
-
let regexWord = null;
|
|
2136
|
-
|
|
2137
|
-
if (this.matchWord && this.matchWord.length) {
|
|
2138
|
-
const escapedWord = this.matchWord.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
2139
|
-
regexWord = new RegExp(escapedWord, 'giu');
|
|
2140
|
-
}
|
|
2141
|
-
|
|
2142
|
-
// Update text highlighting if matchWord changed
|
|
2143
|
-
if (regexWord &&
|
|
2144
|
-
this.isActive && !this.hasAttribute('persistent')) {
|
|
2145
|
-
const nested = this.querySelectorAll('.nestingSpacer');
|
|
2146
|
-
|
|
2147
|
-
const displayValueEl = this.querySelector('[slot="displayValue"]');
|
|
2148
|
-
if (displayValueEl) {
|
|
2149
|
-
this.removeChild(displayValueEl);
|
|
2150
|
-
}
|
|
2151
|
-
|
|
2152
|
-
// Create nested spacers
|
|
2153
|
-
const nestingSpacerBundle = [...nested].map(() => this.nestingSpacer).join('');
|
|
2126
|
+
handleNestedMenus(menu) {
|
|
2127
|
+
menu.level = menu.parentElement.level >= 0 ? menu.parentElement.level + 1 : 0;
|
|
2154
2128
|
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
);
|
|
2161
|
-
if (displayValueEl) {
|
|
2162
|
-
this.append(displayValueEl);
|
|
2129
|
+
if (menu.level > 0) {
|
|
2130
|
+
menu.setAttribute('role', 'group');
|
|
2131
|
+
menu.removeAttribute("root");
|
|
2132
|
+
if (!menu.hasAttribute('aria-label')) {
|
|
2133
|
+
menu.setAttribute('aria-label', 'submenu');
|
|
2163
2134
|
}
|
|
2164
2135
|
}
|
|
2136
|
+
|
|
2137
|
+
const options = menu.querySelectorAll(':scope > auro-menuoption, :scope > [auro-menuoption]');
|
|
2138
|
+
options.forEach((option) => {
|
|
2139
|
+
const regex = new RegExp(this.nestingSpacer, "gu");
|
|
2140
|
+
option.innerHTML = this.nestingSpacer.repeat(menu.level) + option.innerHTML.replace(regex, '');
|
|
2141
|
+
});
|
|
2165
2142
|
}
|
|
2166
2143
|
|
|
2167
2144
|
/**
|
|
2168
|
-
*
|
|
2169
|
-
*
|
|
2170
|
-
* @
|
|
2145
|
+
* Navigates the menu options in the specified direction.
|
|
2146
|
+
* @param {'up'|'down'} direction - The direction to navigate.
|
|
2147
|
+
* @protected
|
|
2171
2148
|
*/
|
|
2172
|
-
|
|
2173
|
-
if (
|
|
2174
|
-
this.
|
|
2175
|
-
|
|
2149
|
+
navigateOptions(direction) {
|
|
2150
|
+
if (direction === 'up') {
|
|
2151
|
+
this.menuService.highlightPrevious();
|
|
2152
|
+
} else if (direction === 'down') {
|
|
2153
|
+
this.menuService.highlightNext();
|
|
2176
2154
|
}
|
|
2177
2155
|
}
|
|
2178
2156
|
|
|
2179
2157
|
/**
|
|
2180
|
-
* Handles
|
|
2181
|
-
* This function updates the menu service to set this option as the currently highlighted item if not disabled.
|
|
2158
|
+
* Handles slot change events.
|
|
2182
2159
|
* @private
|
|
2183
2160
|
*/
|
|
2184
|
-
|
|
2185
|
-
if (
|
|
2186
|
-
this.
|
|
2161
|
+
handleSlotChange() {
|
|
2162
|
+
if (this.rootMenu) {
|
|
2163
|
+
this.initializeMenu();
|
|
2187
2164
|
}
|
|
2188
2165
|
}
|
|
2189
2166
|
|
|
2190
2167
|
/**
|
|
2191
|
-
*
|
|
2192
|
-
* This function notifies listeners when a custom event is triggered by the option.
|
|
2168
|
+
* Handles custom events defined on options.
|
|
2193
2169
|
* @private
|
|
2170
|
+
* @param {HTMLElement} option - Option with custom event.
|
|
2194
2171
|
*/
|
|
2195
|
-
handleCustomEvent() {
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
}
|
|
2172
|
+
handleCustomEvent(option) {
|
|
2173
|
+
const eventName = option.getAttribute('event');
|
|
2174
|
+
dispatchMenuEvent(this, eventName);
|
|
2175
|
+
dispatchMenuEvent(this, 'auroMenu-customEventFired');
|
|
2200
2176
|
}
|
|
2201
2177
|
|
|
2202
2178
|
/**
|
|
2203
|
-
*
|
|
2204
|
-
*
|
|
2179
|
+
* Notifies selection change to parent components.
|
|
2180
|
+
* @param {any} source - The source that triggers this event.
|
|
2205
2181
|
* @private
|
|
2206
2182
|
*/
|
|
2207
|
-
|
|
2208
|
-
this
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2183
|
+
notifySelectionChange({value, stringValue, keys, options, reason} = {}) {
|
|
2184
|
+
dispatchMenuEvent(this, 'auroMenu-selectedOption', {
|
|
2185
|
+
value,
|
|
2186
|
+
stringValue,
|
|
2187
|
+
keys,
|
|
2188
|
+
options,
|
|
2189
|
+
reason
|
|
2190
|
+
});
|
|
2214
2191
|
}
|
|
2215
2192
|
|
|
2216
2193
|
/**
|
|
2217
|
-
*
|
|
2218
|
-
*
|
|
2194
|
+
* Checks if an option is currently selected.
|
|
2219
2195
|
* @private
|
|
2220
|
-
* @param {
|
|
2221
|
-
* @returns {
|
|
2196
|
+
* @param {HTMLElement} option - The option to check.
|
|
2197
|
+
* @returns {boolean}
|
|
2222
2198
|
*/
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2199
|
+
isOptionSelected(option) {
|
|
2200
|
+
if (!this.optionSelected) {
|
|
2201
|
+
return false;
|
|
2202
|
+
}
|
|
2226
2203
|
|
|
2227
|
-
|
|
2204
|
+
if (this.multiSelect) {
|
|
2205
|
+
// In multi-select mode, check if the option is in the selected array
|
|
2206
|
+
return Array.isArray(this.optionSelected) && this.optionSelected.some((selectedOption) => selectedOption === option);
|
|
2207
|
+
}
|
|
2228
2208
|
|
|
2229
|
-
return
|
|
2209
|
+
return this.optionSelected === option;
|
|
2210
|
+
}
|
|
2211
|
+
|
|
2212
|
+
/**
|
|
2213
|
+
* Getter for loading placeholder state.
|
|
2214
|
+
* @returns {boolean} - True if loading slots are present and non-empty.
|
|
2215
|
+
*/
|
|
2216
|
+
get hasLoadingPlaceholder() {
|
|
2217
|
+
return this.loadingSlots && this.loadingSlots.length > 0;
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
/**
|
|
2221
|
+
* Getter for wrapper classes based on size.
|
|
2222
|
+
* @returns {Object} - Class map for the wrapper element.
|
|
2223
|
+
* @private
|
|
2224
|
+
*/
|
|
2225
|
+
get wrapperClasses() {
|
|
2226
|
+
return classMap({
|
|
2227
|
+
'menuWrapper': true,
|
|
2228
|
+
[this.size]: true,
|
|
2229
|
+
});
|
|
2230
2230
|
}
|
|
2231
2231
|
|
|
2232
2232
|
/**
|
|
@@ -2235,26 +2235,26 @@ class AuroMenuOption extends AuroElement {
|
|
|
2235
2235
|
* @returns {void}
|
|
2236
2236
|
*/
|
|
2237
2237
|
renderLayout() {
|
|
2238
|
+
if (this.loading) {
|
|
2239
|
+
return html`
|
|
2240
|
+
<div class="${this.wrapperClasses}">
|
|
2241
|
+
<auro-menuoption
|
|
2242
|
+
disabled
|
|
2243
|
+
loadingplaceholder
|
|
2244
|
+
class="${this.hasLoadingPlaceholder ? "" : "empty"}"
|
|
2245
|
+
>
|
|
2246
|
+
<div>
|
|
2247
|
+
<slot name="loadingIcon" class="body-lg"></slot>
|
|
2248
|
+
<slot name="loadingText"></slot>
|
|
2249
|
+
</div>
|
|
2250
|
+
</auro-menuoption>
|
|
2251
|
+
</div>
|
|
2252
|
+
`;
|
|
2253
|
+
}
|
|
2238
2254
|
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
md: 'body-default',
|
|
2243
|
-
lg: 'body-lg',
|
|
2244
|
-
xl: 'body-lg'
|
|
2245
|
-
};
|
|
2246
|
-
|
|
2247
|
-
const classes = classMap({
|
|
2248
|
-
'wrapper': true,
|
|
2249
|
-
[this.size ? fontClassMap[this.size] : 'body-sm']: true,
|
|
2250
|
-
});
|
|
2251
|
-
|
|
2252
|
-
return html$1`
|
|
2253
|
-
<div class="${classes}">
|
|
2254
|
-
${this.selected && !this.noCheckmark
|
|
2255
|
-
? this.generateIconHtml(checkmarkIcon.svg)
|
|
2256
|
-
: undefined}
|
|
2257
|
-
<slot></slot>
|
|
2255
|
+
return html`
|
|
2256
|
+
<div class="${this.wrapperClasses}">
|
|
2257
|
+
<slot @slotchange=${this.handleSlotChange}></slot>
|
|
2258
2258
|
</div>
|
|
2259
2259
|
`;
|
|
2260
2260
|
}
|