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