@aurodesignsystem-dev/auro-formkit 0.0.0-pr593.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/CHANGELOG.md +5 -0
- package/LICENSE +201 -0
- package/NOTICE +2 -0
- package/README.md +314 -0
- package/components/bibtemplate/dist/auro-bibtemplate.d.ts +39 -0
- package/components/bibtemplate/dist/headerVersion.d.ts +2 -0
- package/components/bibtemplate/dist/iconVersion.d.ts +2 -0
- package/components/bibtemplate/dist/index.d.ts +2 -0
- package/components/bibtemplate/dist/index.js +709 -0
- package/components/bibtemplate/dist/registered.js +709 -0
- package/components/bibtemplate/dist/styles/color-css.d.ts +2 -0
- package/components/bibtemplate/dist/styles/style-css.d.ts +2 -0
- package/components/bibtemplate/dist/styles/tokens-css.d.ts +2 -0
- package/components/checkbox/README.md +142 -0
- package/components/checkbox/demo/api.html +55 -0
- package/components/checkbox/demo/api.js +17 -0
- package/components/checkbox/demo/api.md +401 -0
- package/components/checkbox/demo/api.min.js +1833 -0
- package/components/checkbox/demo/index.html +51 -0
- package/components/checkbox/demo/index.js +8 -0
- package/components/checkbox/demo/index.md +327 -0
- package/components/checkbox/demo/index.min.js +1808 -0
- package/components/checkbox/demo/readme.html +50 -0
- package/components/checkbox/demo/readme.md +142 -0
- package/components/checkbox/dist/auro-checkbox-group.d.ts +166 -0
- package/components/checkbox/dist/auro-checkbox.d.ts +129 -0
- package/components/checkbox/dist/helptextVersion.d.ts +2 -0
- package/components/checkbox/dist/index.d.ts +3 -0
- package/components/checkbox/dist/index.js +1757 -0
- package/components/checkbox/dist/registered.js +1758 -0
- package/components/checkbox/dist/styles/auro-checkbox-css.d.ts +2 -0
- package/components/checkbox/dist/styles/auro-checkbox-group-css.d.ts +2 -0
- package/components/checkbox/dist/styles/color-css.d.ts +2 -0
- package/components/checkbox/dist/styles/colorGroup-css.d.ts +2 -0
- package/components/checkbox/dist/styles/tokens-css.d.ts +2 -0
- package/components/combobox/README.md +152 -0
- package/components/combobox/demo/api.html +57 -0
- package/components/combobox/demo/api.js +36 -0
- package/components/combobox/demo/api.md +1209 -0
- package/components/combobox/demo/api.min.js +15117 -0
- package/components/combobox/demo/index.html +56 -0
- package/components/combobox/demo/index.js +26 -0
- package/components/combobox/demo/index.md +621 -0
- package/components/combobox/demo/index.min.js +14971 -0
- package/components/combobox/demo/readme.html +50 -0
- package/components/combobox/demo/readme.md +152 -0
- package/components/combobox/dist/auro-combobox.d.ts +384 -0
- package/components/combobox/dist/bibtemplateVersion.d.ts +2 -0
- package/components/combobox/dist/dropdownVersion.d.ts +2 -0
- package/components/combobox/dist/index.d.ts +2 -0
- package/components/combobox/dist/index.js +13554 -0
- package/components/combobox/dist/inputVersion.d.ts +2 -0
- package/components/combobox/dist/registered.js +13556 -0
- package/components/combobox/dist/styles/style-css.d.ts +2 -0
- package/components/counter/README.md +146 -0
- package/components/counter/demo/api.html +54 -0
- package/components/counter/demo/api.js +20 -0
- package/components/counter/demo/api.md +584 -0
- package/components/counter/demo/api.min.js +7111 -0
- package/components/counter/demo/index.html +54 -0
- package/components/counter/demo/index.js +21 -0
- package/components/counter/demo/index.md +244 -0
- package/components/counter/demo/index.min.js +7075 -0
- package/components/counter/demo/readme.html +50 -0
- package/components/counter/demo/readme.md +146 -0
- package/components/counter/dist/auro-counter-button.d.ts +12 -0
- package/components/counter/dist/auro-counter-group.d.ts +235 -0
- package/components/counter/dist/auro-counter-wrapper.d.ts +22 -0
- package/components/counter/dist/auro-counter.d.ts +97 -0
- package/components/counter/dist/bibtemplateVersion.d.ts +2 -0
- package/components/counter/dist/dropdownVersion.d.ts +2 -0
- package/components/counter/dist/iconVersion.d.ts +2 -0
- package/components/counter/dist/index.d.ts +3 -0
- package/components/counter/dist/index.js +7018 -0
- package/components/counter/dist/registered.js +7019 -0
- package/components/counter/dist/styles/color-css.d.ts +2 -0
- package/components/counter/dist/styles/counter-button-color-css.d.ts +2 -0
- package/components/counter/dist/styles/counter-button-css.d.ts +2 -0
- package/components/counter/dist/styles/counter-group-css.d.ts +2 -0
- package/components/counter/dist/styles/counter-wrapper-color-css.d.ts +2 -0
- package/components/counter/dist/styles/counter-wrapper-css.d.ts +2 -0
- package/components/counter/dist/styles/style-css.d.ts +2 -0
- package/components/counter/dist/styles/tokens-css.d.ts +2 -0
- package/components/datepicker/README.md +140 -0
- package/components/datepicker/demo/api.html +57 -0
- package/components/datepicker/demo/api.js +35 -0
- package/components/datepicker/demo/api.md +1479 -0
- package/components/datepicker/demo/api.min.js +24534 -0
- package/components/datepicker/demo/index.html +56 -0
- package/components/datepicker/demo/index.js +19 -0
- package/components/datepicker/demo/index.md +112 -0
- package/components/datepicker/demo/index.min.js +24255 -0
- package/components/datepicker/demo/readme.html +50 -0
- package/components/datepicker/demo/readme.md +140 -0
- package/components/datepicker/dist/auro-calendar-cell.d.ts +163 -0
- package/components/datepicker/dist/auro-calendar-month.d.ts +20 -0
- package/components/datepicker/dist/auro-calendar.d.ts +133 -0
- package/components/datepicker/dist/auro-datepicker.d.ts +466 -0
- package/components/datepicker/dist/bibtemplateVersion.d.ts +2 -0
- package/components/datepicker/dist/buttonVersion.d.ts +2 -0
- package/components/datepicker/dist/dropdownVersion.d.ts +2 -0
- package/components/datepicker/dist/index.d.ts +2 -0
- package/components/datepicker/dist/index.js +24185 -0
- package/components/datepicker/dist/inputVersion.d.ts +2 -0
- package/components/datepicker/dist/popoverVersion.d.ts +2 -0
- package/components/datepicker/dist/registered.js +24185 -0
- package/components/datepicker/dist/styles/color-calendar-css.d.ts +2 -0
- package/components/datepicker/dist/styles/color-cell-css.d.ts +2 -0
- package/components/datepicker/dist/styles/color-css.d.ts +2 -0
- package/components/datepicker/dist/styles/color-month-css.d.ts +2 -0
- package/components/datepicker/dist/styles/style-auro-calendar-cell-css.d.ts +2 -0
- package/components/datepicker/dist/styles/style-auro-calendar-css.d.ts +2 -0
- package/components/datepicker/dist/styles/style-auro-calendar-month-css.d.ts +2 -0
- package/components/datepicker/dist/styles/style-css.d.ts +2 -0
- package/components/datepicker/dist/styles/tokens-css.d.ts +2 -0
- package/components/datepicker/dist/utilities.d.ts +78 -0
- package/components/datepicker/dist/utilitiesCalendar.d.ts +38 -0
- package/components/datepicker/dist/utilitiesCalendarRender.d.ts +50 -0
- package/components/datepicker/dist/vendor/wc-range-datepicker/day.d.ts +5 -0
- package/components/datepicker/dist/vendor/wc-range-datepicker/range-datepicker-calendar.d.ts +60 -0
- package/components/datepicker/dist/vendor/wc-range-datepicker/range-datepicker-cell.d.ts +1 -0
- package/components/datepicker/dist/vendor/wc-range-datepicker/range-datepicker.d.ts +57 -0
- package/components/dropdown/README.md +144 -0
- package/components/dropdown/demo/api.html +57 -0
- package/components/dropdown/demo/api.js +21 -0
- package/components/dropdown/demo/api.md +1434 -0
- package/components/dropdown/demo/api.min.js +3826 -0
- package/components/dropdown/demo/index.html +55 -0
- package/components/dropdown/demo/index.js +19 -0
- package/components/dropdown/demo/index.md +510 -0
- package/components/dropdown/demo/index.min.js +3789 -0
- package/components/dropdown/demo/readme.html +50 -0
- package/components/dropdown/demo/readme.md +144 -0
- package/components/dropdown/dist/auro-dropdown.d.ts +406 -0
- package/components/dropdown/dist/auro-dropdownBib.d.ts +46 -0
- package/components/dropdown/dist/dropdownVersion.d.ts +2 -0
- package/components/dropdown/dist/helptextVersion.d.ts +2 -0
- package/components/dropdown/dist/iconVersion.d.ts +2 -0
- package/components/dropdown/dist/index.d.ts +2 -0
- package/components/dropdown/dist/index.js +3734 -0
- package/components/dropdown/dist/registered.js +3734 -0
- package/components/dropdown/dist/styles/bibColors-css.d.ts +2 -0
- package/components/dropdown/dist/styles/bibStyles-css.d.ts +2 -0
- package/components/dropdown/dist/styles/color-css.d.ts +2 -0
- package/components/dropdown/dist/styles/style-css.d.ts +2 -0
- package/components/dropdown/dist/styles/tokens-css.d.ts +2 -0
- package/components/form/README.md +142 -0
- package/components/form/demo/api.html +49 -0
- package/components/form/demo/api.js +3 -0
- package/components/form/demo/api.md +51 -0
- package/components/form/demo/api.min.js +638 -0
- package/components/form/demo/autocomplete.html +15 -0
- package/components/form/demo/index.html +50 -0
- package/components/form/demo/index.js +4 -0
- package/components/form/demo/index.md +403 -0
- package/components/form/demo/index.min.js +639 -0
- package/components/form/demo/readme.html +50 -0
- package/components/form/demo/readme.md +142 -0
- package/components/form/demo/registerDemoDeps.js +23 -0
- package/components/form/demo/working.html +118 -0
- package/components/form/dist/auro-form.d.ts +223 -0
- package/components/form/dist/index.d.ts +2 -0
- package/components/form/dist/index.js +614 -0
- package/components/form/dist/registered.d.ts +1 -0
- package/components/form/dist/registered.js +614 -0
- package/components/form/dist/styles/style-css.d.ts +2 -0
- package/components/helptext/dist/auro-helptext.d.ts +61 -0
- package/components/helptext/dist/index.d.ts +2 -0
- package/components/helptext/dist/index.js +209 -0
- package/components/helptext/dist/registered.js +209 -0
- package/components/helptext/dist/styles/color-css.d.ts +2 -0
- package/components/helptext/dist/styles/style-css.d.ts +2 -0
- package/components/helptext/dist/styles/tokens-css.d.ts +2 -0
- package/components/input/README.md +135 -0
- package/components/input/demo/api.html +42 -0
- package/components/input/demo/api.js +29 -0
- package/components/input/demo/api.md +1252 -0
- package/components/input/demo/api.min.js +7238 -0
- package/components/input/demo/index.html +43 -0
- package/components/input/demo/index.js +20 -0
- package/components/input/demo/index.md +202 -0
- package/components/input/demo/index.min.js +7157 -0
- package/components/input/demo/readme.html +50 -0
- package/components/input/demo/readme.md +135 -0
- package/components/input/dist/auro-input.d.ts +31 -0
- package/components/input/dist/base-input.d.ts +512 -0
- package/components/input/dist/buttonVersion.d.ts +2 -0
- package/components/input/dist/helptextVersion.d.ts +2 -0
- package/components/input/dist/i18n.d.ts +18 -0
- package/components/input/dist/iconVersion.d.ts +2 -0
- package/components/input/dist/index.d.ts +2 -0
- package/components/input/dist/index.js +7063 -0
- package/components/input/dist/registered.js +7063 -0
- package/components/input/dist/styles/borders-css.d.ts +2 -0
- package/components/input/dist/styles/color-css.d.ts +2 -0
- package/components/input/dist/styles/input-css.d.ts +2 -0
- package/components/input/dist/styles/label-css.d.ts +2 -0
- package/components/input/dist/styles/mixins-css.d.ts +2 -0
- package/components/input/dist/styles/notificationIcons-css.d.ts +2 -0
- package/components/input/dist/styles/style-css.d.ts +2 -0
- package/components/input/dist/styles/tokens-css.d.ts +2 -0
- package/components/input/dist/utilities.d.ts +25 -0
- package/components/menu/README.md +145 -0
- package/components/menu/demo/api.html +55 -0
- package/components/menu/demo/api.js +27 -0
- package/components/menu/demo/api.md +954 -0
- package/components/menu/demo/api.min.js +1538 -0
- package/components/menu/demo/index.html +52 -0
- package/components/menu/demo/index.js +28 -0
- package/components/menu/demo/index.md +61 -0
- package/components/menu/demo/index.min.js +1484 -0
- package/components/menu/demo/readme.html +50 -0
- package/components/menu/demo/readme.md +145 -0
- package/components/menu/dist/auro-menu-utils.d.ts +42 -0
- package/components/menu/dist/auro-menu.d.ts +205 -0
- package/components/menu/dist/auro-menuoption.d.ts +63 -0
- package/components/menu/dist/dropdownVersion.d.ts +2 -0
- package/components/menu/dist/iconVersion.d.ts +2 -0
- package/components/menu/dist/index.d.ts +4 -0
- package/components/menu/dist/index.js +1426 -0
- package/components/menu/dist/registered.js +1427 -0
- package/components/menu/dist/styles/color-menu-css.d.ts +2 -0
- package/components/menu/dist/styles/color-menuoption-css.d.ts +2 -0
- package/components/menu/dist/styles/style-menu-css.d.ts +2 -0
- package/components/menu/dist/styles/style-menuoption-css.d.ts +2 -0
- package/components/menu/dist/styles/tokens-css.d.ts +2 -0
- package/components/radio/README.md +137 -0
- package/components/radio/demo/api.html +53 -0
- package/components/radio/demo/api.js +19 -0
- package/components/radio/demo/api.md +562 -0
- package/components/radio/demo/api.min.js +1944 -0
- package/components/radio/demo/index.html +50 -0
- package/components/radio/demo/index.js +8 -0
- package/components/radio/demo/index.md +150 -0
- package/components/radio/demo/index.min.js +1901 -0
- package/components/radio/demo/readme.html +50 -0
- package/components/radio/demo/readme.md +137 -0
- package/components/radio/dist/auro-radio-group.d.ts +194 -0
- package/components/radio/dist/auro-radio.d.ts +144 -0
- package/components/radio/dist/helptextVersion.d.ts +2 -0
- package/components/radio/dist/index.d.ts +3 -0
- package/components/radio/dist/index.js +1850 -0
- package/components/radio/dist/registered.js +1851 -0
- package/components/radio/dist/styles/auro-radio-group-css.d.ts +2 -0
- package/components/radio/dist/styles/color-css.d.ts +2 -0
- package/components/radio/dist/styles/groupColor-css.d.ts +2 -0
- package/components/radio/dist/styles/style-css.d.ts +2 -0
- package/components/radio/dist/styles/tokens-css.d.ts +2 -0
- package/components/select/README.md +144 -0
- package/components/select/demo/api.html +71 -0
- package/components/select/demo/api.js +35 -0
- package/components/select/demo/api.md +1313 -0
- package/components/select/demo/api.min.js +7763 -0
- package/components/select/demo/index.html +66 -0
- package/components/select/demo/index.js +9 -0
- package/components/select/demo/index.md +815 -0
- package/components/select/demo/index.min.js +7651 -0
- package/components/select/demo/readme.html +50 -0
- package/components/select/demo/readme.md +144 -0
- package/components/select/dist/auro-select.d.ts +359 -0
- package/components/select/dist/bibtemplateVersion.d.ts +2 -0
- package/components/select/dist/dropdownVersion.d.ts +2 -0
- package/components/select/dist/index.d.ts +2 -0
- package/components/select/dist/index.js +6300 -0
- package/components/select/dist/registered.js +6300 -0
- package/components/select/dist/styles/style-css.d.ts +2 -0
- package/package.json +217 -0
- package/packages/build-tools/src/postinstall.mjs +12 -0
|
@@ -0,0 +1,1426 @@
|
|
|
1
|
+
import { css, LitElement, html } from 'lit';
|
|
2
|
+
import { unsafeStatic, literal, html as html$1 } from 'lit/static-html.js';
|
|
3
|
+
import { classMap } from 'lit/directives/class-map.js';
|
|
4
|
+
import { ifDefined } from 'lit/directives/if-defined.js';
|
|
5
|
+
|
|
6
|
+
var styleCss$2 = css`:focus:not(:focus-visible){outline:3px solid transparent}:host{display:inline-block;width:100%;margin:0;padding:0;vertical-align:middle}:host ::slotted(auro-menuoption),:host ::slotted([auro-menuoption]),:host auro-menuoption[loadingplaceholder]{padding-left:calc(var(--ds-size-150, 0.75rem) + 24px + var(--ds-size-100, 0.5rem))}:host ::slotted([selected]){padding-left: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([nocheckmark]) ::slotted(auro-menuoption),:host([nocheckmark]) auro-menuoption[loadingplaceholder]{padding-left:var(--ds-size-200, 1rem)}:host([root]){overflow-y:auto}[loadingplaceholder].empty{opacity:0;position:absolute}[loadingplaceholder] slot[name=loadingIcon]{vertical-align:middle;line-height:1;display:inline-block}[loadingplaceholder] slot[name=loadingIcon]::slotted(*){margin-right:var(--ds-size-150, 0.75rem)}`;
|
|
7
|
+
|
|
8
|
+
var colorCss$2 = css`:host ::slotted(hr){border-top-color:var(--ds-auro-menu-divider-color)}[loadingplaceholder] slot[name=loadingIcon]{color:var(--ds-auro-menu-loader-color)}[loadingplaceholder] slot[name=loadingText]{color:var(--ds-auro-menu-loader-text-color)}`;
|
|
9
|
+
|
|
10
|
+
var tokensCss$1 = css`:host{--ds-auro-menu-divider-color: var(--ds-basic-color-border-divider, rgba(0, 0, 0, 0.15));--ds-auro-menu-loader-color: var(--ds-basic-color-brand-primary, #01426a);--ds-auro-menu-loader-text-color: var(--ds-basic-color-texticon-default, #2a2a2a);--ds-auro-menuoption-container-color: transparent;--ds-auro-menuoption-icon-color: transparent;--ds-auro-menuoption-text-color: var(--ds-basic-color-texticon-default, #2a2a2a)}`;
|
|
11
|
+
|
|
12
|
+
// Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
|
|
13
|
+
// See LICENSE in the project root for license information.
|
|
14
|
+
|
|
15
|
+
// ---------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
/* eslint-disable line-comment-position, no-inline-comments, no-confusing-arrow, no-nested-ternary, implicit-arrow-linebreak */
|
|
18
|
+
|
|
19
|
+
class AuroLibraryRuntimeUtils {
|
|
20
|
+
|
|
21
|
+
/* eslint-disable jsdoc/require-param */
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* This will register a new custom element with the browser.
|
|
25
|
+
* @param {String} name - The name of the custom element.
|
|
26
|
+
* @param {Object} componentClass - The class to register as a custom element.
|
|
27
|
+
* @returns {void}
|
|
28
|
+
*/
|
|
29
|
+
registerComponent(name, componentClass) {
|
|
30
|
+
if (!customElements.get(name)) {
|
|
31
|
+
customElements.define(name, class extends componentClass {});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Finds and returns the closest HTML Element based on a selector.
|
|
37
|
+
* @returns {void}
|
|
38
|
+
*/
|
|
39
|
+
closestElement(
|
|
40
|
+
selector, // selector like in .closest()
|
|
41
|
+
base = this, // extra functionality to skip a parent
|
|
42
|
+
__Closest = (el, found = el && el.closest(selector)) =>
|
|
43
|
+
!el || el === document || el === window
|
|
44
|
+
? null // standard .closest() returns null for non-found selectors also
|
|
45
|
+
: found
|
|
46
|
+
? found // found a selector INside this element
|
|
47
|
+
: __Closest(el.getRootNode().host) // recursion!! break out to parent DOM
|
|
48
|
+
) {
|
|
49
|
+
return __Closest(base);
|
|
50
|
+
}
|
|
51
|
+
/* eslint-enable jsdoc/require-param */
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 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.
|
|
55
|
+
* @param {Object} elem - The element to check.
|
|
56
|
+
* @param {String} tagName - The name of the Auro component to check for or add as an attribute.
|
|
57
|
+
* @returns {void}
|
|
58
|
+
*/
|
|
59
|
+
handleComponentTagRename(elem, tagName) {
|
|
60
|
+
const tag = tagName.toLowerCase();
|
|
61
|
+
const elemTag = elem.tagName.toLowerCase();
|
|
62
|
+
|
|
63
|
+
if (elemTag !== tag) {
|
|
64
|
+
elem.setAttribute(tag, true);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Validates if an element is a specific Auro component.
|
|
70
|
+
* @param {Object} elem - The element to validate.
|
|
71
|
+
* @param {String} tagName - The name of the Auro component to check against.
|
|
72
|
+
* @returns {Boolean} - Returns true if the element is the specified Auro component.
|
|
73
|
+
*/
|
|
74
|
+
elementMatch(elem, tagName) {
|
|
75
|
+
const tag = tagName.toLowerCase();
|
|
76
|
+
const elemTag = elem.tagName.toLowerCase();
|
|
77
|
+
|
|
78
|
+
return elemTag === tag || elem.hasAttribute(tag);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// Copyright (c) 2021 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
83
|
+
// See LICENSE in the project root for license information.
|
|
84
|
+
|
|
85
|
+
// ---------------------------------------------------------------------
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Converts value to an array.
|
|
89
|
+
* If the value is a JSON string representing an array, it will be parsed.
|
|
90
|
+
* If the value is already an array, it is returned.
|
|
91
|
+
* If the value is undefined, it returns undefined.
|
|
92
|
+
* @private
|
|
93
|
+
* @param {any} value - The value to be converted. Can be a string, array, or undefined.
|
|
94
|
+
* @returns {Array|undefined} - The converted array or undefined.
|
|
95
|
+
* @throws {Error} - Throws an error if the value is not an array, undefined,
|
|
96
|
+
* or if the value cannot be parsed into an array from a JSON string.
|
|
97
|
+
*/
|
|
98
|
+
function arrayConverter(value) {
|
|
99
|
+
// Allow undefined
|
|
100
|
+
if (value === undefined) {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// Return the value if it is already an array
|
|
105
|
+
if (Array.isArray(value)) {
|
|
106
|
+
return value;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
try {
|
|
110
|
+
// If value is a JSON string, parse it
|
|
111
|
+
const parsed = typeof value === 'string' ? JSON.parse(value) : value;
|
|
112
|
+
|
|
113
|
+
// Check if the parsed value is an array
|
|
114
|
+
if (Array.isArray(parsed)) {
|
|
115
|
+
return parsed;
|
|
116
|
+
}
|
|
117
|
+
} catch (error) {
|
|
118
|
+
// If JSON parsing fails, continue to throw an error below
|
|
119
|
+
/* eslint-disable no-console */
|
|
120
|
+
console.error('JSON parsing failed:', error);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// Throw error if the input is not an array or undefined
|
|
124
|
+
throw new Error('Invalid value: Input must be an array or undefined');
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Compare two arrays for equality.
|
|
129
|
+
* @private
|
|
130
|
+
* @param {Array} arr1 - First array to compare.
|
|
131
|
+
* @param {Array} arr2 - Second array to compare.
|
|
132
|
+
* @returns {boolean} True if arrays are equal.
|
|
133
|
+
*/
|
|
134
|
+
function arraysAreEqual(arr1, arr2) {
|
|
135
|
+
// If both arrays undefined, they are equal (true)
|
|
136
|
+
if (arr1 === undefined || arr2 === undefined) {
|
|
137
|
+
return arr1 === arr2;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// If arrays have different lengths, they are not equal
|
|
141
|
+
if (arr1.length !== arr2.length) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// If every item at each index is the same, return true
|
|
146
|
+
for (let index = 0; index < arr1.length; index += 1) {
|
|
147
|
+
if (arr1[index] !== arr2[index]) {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Compares array for changes.
|
|
156
|
+
* @private
|
|
157
|
+
* @param {Array|any} newVal - New value to compare.
|
|
158
|
+
* @param {Array|any} oldVal - Old value to compare.
|
|
159
|
+
* @returns {boolean} True if arrays have changed.
|
|
160
|
+
*/
|
|
161
|
+
function arrayOrUndefinedHasChanged(newVal, oldVal) {
|
|
162
|
+
try {
|
|
163
|
+
// Check if values are undefined or arrays
|
|
164
|
+
const isArrayOrUndefined = (val) => val === undefined || Array.isArray(val);
|
|
165
|
+
|
|
166
|
+
// If non-array or non-undefined, throw error
|
|
167
|
+
if (!isArrayOrUndefined(newVal) || !isArrayOrUndefined(oldVal)) {
|
|
168
|
+
const invalidValue = isArrayOrUndefined(newVal) ? oldVal : newVal;
|
|
169
|
+
throw new Error(`Value must be an array or undefined, received ${typeof invalidValue}`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Return true if arrays have changed, false if they are the same
|
|
173
|
+
return !arraysAreEqual(newVal, oldVal);
|
|
174
|
+
} catch (error) {
|
|
175
|
+
/* eslint-disable no-console */
|
|
176
|
+
console.error(error);
|
|
177
|
+
// If validation fails, it has changed
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Validates if an option can be interacted with.
|
|
184
|
+
* @private
|
|
185
|
+
* @param {HTMLElement} option - The option to check.
|
|
186
|
+
* @returns {boolean} True if option is interactive.
|
|
187
|
+
*/
|
|
188
|
+
function isOptionInteractive(option) {
|
|
189
|
+
return !option.hasAttribute('hidden') &&
|
|
190
|
+
!option.hasAttribute('disabled') &&
|
|
191
|
+
!option.hasAttribute('static');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Helper method to dispatch custom events.
|
|
196
|
+
* @param {HTMLElement} element - Element to dispatch event from.
|
|
197
|
+
* @param {string} eventName - Name of the event to dispatch.
|
|
198
|
+
* @param {Object} [detail] - Optional detail object to include with the event.
|
|
199
|
+
*/
|
|
200
|
+
function dispatchMenuEvent(element, eventName, detail = null) {
|
|
201
|
+
const eventConfig = {
|
|
202
|
+
bubbles: true,
|
|
203
|
+
cancelable: false,
|
|
204
|
+
composed: true
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
if (detail !== null) {
|
|
208
|
+
eventConfig.detail = detail;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
element.dispatchEvent(new CustomEvent(eventName, eventConfig));
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Copyright (c) 2021 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
215
|
+
// See LICENSE in the project root for license information.
|
|
216
|
+
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
// See https://git.io/JJ6SJ for "How to document your components using JSDoc"
|
|
220
|
+
/**
|
|
221
|
+
* The auro-menu element provides users a way to select from a list of options.
|
|
222
|
+
* @attr {Array<HTMLElement>|undefined} optionSelected - An array of currently selected menu options. In single-select mode, the array will contain only one HTMLElement. `undefined` when no options are selected.
|
|
223
|
+
* @attr {object} optionactive - Specifies the current active menuOption.
|
|
224
|
+
* @attr {string} matchword - Specifies a string used to highlight matched string parts in options.
|
|
225
|
+
* @attr {boolean} disabled - When true, the entire menu and all options are disabled;
|
|
226
|
+
* @attr {boolean} nocheckmark - When true, selected option will not show the checkmark.
|
|
227
|
+
* @attr {boolean} loading - When true, displays a loading state using the loadingIcon and loadingText slots if provided.
|
|
228
|
+
* @attr {boolean} multiselect - When true, the selected option can be multiple options.
|
|
229
|
+
* @attr {Array<string>|undefined} value - Value selected for the menu. `undefined` when no selection has been made, otherwise an array of strings. In single-select mode, the array will contain only one value.
|
|
230
|
+
* @prop {boolean} hasLoadingPlaceholder - Indicates whether the menu has a loadingIcon or loadingText to render when in a loading state.
|
|
231
|
+
* @event {CustomEvent<Element>} auroMenu-activatedOption - Notifies that a menuoption has been made `active`.
|
|
232
|
+
* @event {CustomEvent<any>} auroMenu-customEventFired - Notifies that a custom event has been fired.
|
|
233
|
+
* @event {CustomEvent<{ loading: boolean; hasLoadingPlaceholder: boolean; }>} auroMenu-loadingChange - Notifies when the loading attribute is changed.
|
|
234
|
+
* @event {CustomEvent<any>} auroMenu-selectValueFailure - Notifies that an attempt to select a menuoption by matching a value has failed.
|
|
235
|
+
* @event {CustomEvent<any>} auroMenu-selectValueReset - Notifies that the component value has been reset.
|
|
236
|
+
* @event {CustomEvent<any>} auroMenu-selectedOption - Notifies that a new menuoption selection has been made.
|
|
237
|
+
* @slot loadingText - Text to show while loading attribute is set
|
|
238
|
+
* @slot loadingIcon - Icon to show while loading attribute is set
|
|
239
|
+
* @slot - Slot for insertion of menu options.
|
|
240
|
+
*/
|
|
241
|
+
|
|
242
|
+
/* eslint-disable no-magic-numbers, max-lines */
|
|
243
|
+
|
|
244
|
+
class AuroMenu extends LitElement {
|
|
245
|
+
constructor() {
|
|
246
|
+
super();
|
|
247
|
+
|
|
248
|
+
// State properties (reactive)
|
|
249
|
+
|
|
250
|
+
// Value of the selected options
|
|
251
|
+
this.value = undefined;
|
|
252
|
+
// Currently selected option
|
|
253
|
+
this.optionSelected = undefined;
|
|
254
|
+
// String used for highlighting/filtering
|
|
255
|
+
this.matchWord = undefined;
|
|
256
|
+
// Hide the checkmark icon on selected options
|
|
257
|
+
this.noCheckmark = false;
|
|
258
|
+
// Currently active option
|
|
259
|
+
this.optionActive = undefined;
|
|
260
|
+
// Loading state
|
|
261
|
+
this.loading = false;
|
|
262
|
+
// Multi-select mode
|
|
263
|
+
this.multiSelect = false;
|
|
264
|
+
|
|
265
|
+
// Event Bindings
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* @private
|
|
269
|
+
*/
|
|
270
|
+
this.handleKeyDown = this.handleKeyDown.bind(this);
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* @private
|
|
274
|
+
*/
|
|
275
|
+
this.handleMouseSelect = this.handleMouseSelect.bind(this);
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* @private
|
|
279
|
+
*/
|
|
280
|
+
this.handleOptionHover = this.handleOptionHover.bind(this);
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* @private
|
|
284
|
+
*/
|
|
285
|
+
this.handleSlotChange = this.handleSlotChange.bind(this);
|
|
286
|
+
|
|
287
|
+
// Instance properties (non-reactive)
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* @private
|
|
291
|
+
*/
|
|
292
|
+
Object.assign(this, {
|
|
293
|
+
// Root-level menu (true) or a nested submenu (false)
|
|
294
|
+
rootMenu: true,
|
|
295
|
+
// Currently focused/active menu item index
|
|
296
|
+
index: -1,
|
|
297
|
+
// Nested menu spacer
|
|
298
|
+
nestingSpacer: '<span class="nestingSpacer"></span>',
|
|
299
|
+
// Loading indicator for slot elements
|
|
300
|
+
loadingSlots: null,
|
|
301
|
+
// Store for menu items
|
|
302
|
+
items: [],
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
static get properties() {
|
|
307
|
+
return {
|
|
308
|
+
noCheckmark: {
|
|
309
|
+
type: Boolean,
|
|
310
|
+
reflect: true,
|
|
311
|
+
attribute: 'nocheckmark'
|
|
312
|
+
},
|
|
313
|
+
disabled: {
|
|
314
|
+
type: Boolean,
|
|
315
|
+
reflect: true
|
|
316
|
+
},
|
|
317
|
+
loading: {
|
|
318
|
+
type: Boolean,
|
|
319
|
+
reflect: true
|
|
320
|
+
},
|
|
321
|
+
optionSelected: {
|
|
322
|
+
// Allow HTMLElement[] arrays and undefined
|
|
323
|
+
converter: arrayConverter,
|
|
324
|
+
hasChanged: arrayOrUndefinedHasChanged
|
|
325
|
+
},
|
|
326
|
+
optionActive: {
|
|
327
|
+
type: Object,
|
|
328
|
+
attribute: 'optionactive'
|
|
329
|
+
},
|
|
330
|
+
matchWord: {
|
|
331
|
+
type: String,
|
|
332
|
+
attribute: 'matchword'
|
|
333
|
+
},
|
|
334
|
+
multiSelect: {
|
|
335
|
+
type: Boolean,
|
|
336
|
+
reflect: true,
|
|
337
|
+
attribute: 'multiselect'
|
|
338
|
+
},
|
|
339
|
+
value: {
|
|
340
|
+
// Allow string[] arrays and undefined
|
|
341
|
+
type: Object,
|
|
342
|
+
converter: arrayConverter,
|
|
343
|
+
hasChanged: arrayOrUndefinedHasChanged
|
|
344
|
+
}
|
|
345
|
+
};
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
static get styles() {
|
|
349
|
+
return [
|
|
350
|
+
styleCss$2,
|
|
351
|
+
colorCss$2,
|
|
352
|
+
tokensCss$1
|
|
353
|
+
];
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* This will register this element with the browser.
|
|
358
|
+
* @param {string} [name="auro-menu"] - The name of element that you want to register to.
|
|
359
|
+
*
|
|
360
|
+
* @example
|
|
361
|
+
* AuroMenu.register("custom-menu") // this will register this element to <custom-menu/>
|
|
362
|
+
*
|
|
363
|
+
*/
|
|
364
|
+
static register(name = "auro-menu") {
|
|
365
|
+
AuroLibraryRuntimeUtils.prototype.registerComponent(name, AuroMenu);
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// Lifecycle Methods
|
|
369
|
+
|
|
370
|
+
connectedCallback() {
|
|
371
|
+
super.connectedCallback();
|
|
372
|
+
|
|
373
|
+
this.addEventListener('keydown', this.handleKeyDown);
|
|
374
|
+
this.addEventListener('mousedown', this.handleMouseSelect);
|
|
375
|
+
this.addEventListener('auroMenuOption-mouseover', this.handleOptionHover);
|
|
376
|
+
this.addEventListener('slotchange', this.handleSlotChange);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
disconnectedCallback() {
|
|
380
|
+
this.removeEventListener('keydown', this.handleKeyDown);
|
|
381
|
+
this.removeEventListener('mousedown', this.handleMouseSelect);
|
|
382
|
+
this.removeEventListener('auroMenuOption-mouseover', this.handleOptionHover);
|
|
383
|
+
this.removeEventListener('slotchange', this.handleSlotChange);
|
|
384
|
+
|
|
385
|
+
super.disconnectedCallback();
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
firstUpdated() {
|
|
389
|
+
AuroLibraryRuntimeUtils.prototype.handleComponentTagRename(this, 'auro-menu');
|
|
390
|
+
|
|
391
|
+
this.loadingSlots = this.querySelectorAll("[slot='loadingText'], [slot='loadingIcon']");
|
|
392
|
+
this.initializeMenu();
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
updated(changedProperties) {
|
|
396
|
+
if (changedProperties.has('value')) {
|
|
397
|
+
// Handle null/undefined case
|
|
398
|
+
if (this.value === undefined || this.value === null) {
|
|
399
|
+
this.optionSelected = undefined;
|
|
400
|
+
// Reset index tracking
|
|
401
|
+
this.index = -1;
|
|
402
|
+
} else {
|
|
403
|
+
// Convert single values to arrays
|
|
404
|
+
const valueArray = Array.isArray(this.value) ? this.value : [this.value];
|
|
405
|
+
|
|
406
|
+
// Find all matching options
|
|
407
|
+
const matchingOptions = this.items.filter((item) => valueArray.includes(item.value));
|
|
408
|
+
|
|
409
|
+
if (matchingOptions.length > 0) {
|
|
410
|
+
if (this.multiSelect) {
|
|
411
|
+
// For multiselect, keep all matching options
|
|
412
|
+
this.optionSelected = matchingOptions;
|
|
413
|
+
} else {
|
|
414
|
+
// For single select, only use the first match
|
|
415
|
+
this.optionSelected = [matchingOptions[0]];
|
|
416
|
+
this.index = this.items.indexOf(matchingOptions[0]);
|
|
417
|
+
}
|
|
418
|
+
} else {
|
|
419
|
+
// No matches found - trigger failure event
|
|
420
|
+
dispatchMenuEvent(this, 'auroMenu-selectValueFailure');
|
|
421
|
+
this.optionSelected = undefined;
|
|
422
|
+
this.index = -1;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
// Update UI state
|
|
427
|
+
this.updateItemsState(new Map([
|
|
428
|
+
[
|
|
429
|
+
'optionSelected',
|
|
430
|
+
true
|
|
431
|
+
]
|
|
432
|
+
]));
|
|
433
|
+
|
|
434
|
+
// Notify of changes
|
|
435
|
+
if (this.optionSelected !== undefined) {
|
|
436
|
+
this.notifySelectionChange();
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Process all other UI updates
|
|
441
|
+
this.updateItemsState(changedProperties);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Updates the UI state and appearance of menu items based on changed properties.
|
|
446
|
+
* @private
|
|
447
|
+
* @param {Map<string, boolean>} changedProperties - LitElement's changed properties map.
|
|
448
|
+
*/
|
|
449
|
+
updateItemsState(changedProperties) {
|
|
450
|
+
if (!this.items) {
|
|
451
|
+
return;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Handle noCheckmark propagation to all menus and options
|
|
455
|
+
if (changedProperties.has('noCheckmark') && this.noCheckmark) {
|
|
456
|
+
// Update both menus and options
|
|
457
|
+
this.querySelectorAll('auro-menu, [auro-menu], auro-menuoption, [auro-menuoption]').forEach((element) => element.setAttribute('noCheckmark', ''));
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
// Regex for matchWord if needed
|
|
461
|
+
let regexWord = null;
|
|
462
|
+
|
|
463
|
+
if (changedProperties.has('matchWord') && this.matchWord && this.matchWord.length) {
|
|
464
|
+
const escapedWord = this.matchWord.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
465
|
+
regexWord = new RegExp(escapedWord, 'giu');
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
// Handle direct item updates
|
|
469
|
+
this.items.forEach((option) => {
|
|
470
|
+
// Update selection if option or value changed
|
|
471
|
+
if (changedProperties.has('optionSelected') || changedProperties.has('value')) {
|
|
472
|
+
const isSelected = this.isOptionSelected(option);
|
|
473
|
+
option.setAttribute('aria-selected', isSelected ? 'true' : 'false');
|
|
474
|
+
|
|
475
|
+
// Add/remove selected attribute based on state
|
|
476
|
+
if (isSelected) {
|
|
477
|
+
option.setAttribute('selected', '');
|
|
478
|
+
} else {
|
|
479
|
+
option.removeAttribute('selected');
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
// Update text highlighting if matchWord changed
|
|
484
|
+
if (changedProperties.has('matchWord') && regexWord &&
|
|
485
|
+
isOptionInteractive(option) && !option.hasAttribute('persistent')) {
|
|
486
|
+
const nested = option.querySelectorAll('.nestingSpacer');
|
|
487
|
+
// Create nested spacers
|
|
488
|
+
const nestingSpacerBundle = [...nested].map(() => this.nestingSpacer).join('');
|
|
489
|
+
|
|
490
|
+
// Update with spacers and matchWord
|
|
491
|
+
option.innerHTML = nestingSpacerBundle +
|
|
492
|
+
option.textContent.replace(
|
|
493
|
+
regexWord,
|
|
494
|
+
(match) => `<strong>${match}</strong>`
|
|
495
|
+
);
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// Update disabled state
|
|
499
|
+
if (changedProperties.has('disabled')) {
|
|
500
|
+
option.disabled = this.disabled;
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
|
|
504
|
+
// Handle loading state changes
|
|
505
|
+
if (changedProperties.has('loading')) {
|
|
506
|
+
this.setAttribute("aria-busy", this.loading);
|
|
507
|
+
dispatchMenuEvent(this, "auroMenu-loadingChange", {
|
|
508
|
+
loading: this.loading,
|
|
509
|
+
hasLoadingPlaceholder: this.hasLoadingPlaceholder
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
// Init Methods
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Initializes the menu's state and structure.
|
|
518
|
+
* @private
|
|
519
|
+
*/
|
|
520
|
+
initializeMenu() {
|
|
521
|
+
this.initItems();
|
|
522
|
+
if (this.rootMenu) {
|
|
523
|
+
this.setAttribute('role', 'listbox');
|
|
524
|
+
this.setAttribute('root', '');
|
|
525
|
+
this.handleNestedMenus(this);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Initializes menu items and their attributes.
|
|
531
|
+
* @private
|
|
532
|
+
*/
|
|
533
|
+
initItems() {
|
|
534
|
+
this.items = Array.from(this.querySelectorAll('auro-menuoption, [auro-menuoption]'));
|
|
535
|
+
if (this.noCheckmark) {
|
|
536
|
+
this.updateItemsState(new Map([
|
|
537
|
+
[
|
|
538
|
+
'noCheckmark',
|
|
539
|
+
true
|
|
540
|
+
]
|
|
541
|
+
]));
|
|
542
|
+
}
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
// Logic Methods
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Updates menu state when an option is selected.
|
|
549
|
+
* @private
|
|
550
|
+
* @param {HTMLElement} option - The option element to select.
|
|
551
|
+
*/
|
|
552
|
+
handleSelectState(option) {
|
|
553
|
+
if (this.multiSelect) {
|
|
554
|
+
const currentValue = this.value || [];
|
|
555
|
+
const currentSelected = this.optionSelected || [];
|
|
556
|
+
|
|
557
|
+
if (!currentValue.includes(option.value)) {
|
|
558
|
+
this.value = [
|
|
559
|
+
...currentValue,
|
|
560
|
+
option.value
|
|
561
|
+
];
|
|
562
|
+
}
|
|
563
|
+
if (!currentSelected.includes(option)) {
|
|
564
|
+
this.optionSelected = [
|
|
565
|
+
...currentSelected,
|
|
566
|
+
option
|
|
567
|
+
];
|
|
568
|
+
}
|
|
569
|
+
} else {
|
|
570
|
+
// Single select - use arrays with single values
|
|
571
|
+
this.value = [option.value];
|
|
572
|
+
this.optionSelected = [option];
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
this.index = this.items.indexOf(option);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Deselects a menu option and updates related state.
|
|
580
|
+
* @private
|
|
581
|
+
* @param {HTMLElement} option - The menuoption to be deselected.
|
|
582
|
+
*/
|
|
583
|
+
handleDeselectState(option) {
|
|
584
|
+
if (this.multiSelect && Array.isArray(this.value)) {
|
|
585
|
+
// Remove this option from array
|
|
586
|
+
this.value = this.value.filter((val) => val !== option.value);
|
|
587
|
+
|
|
588
|
+
// If array is empty after removal, set back to undefined
|
|
589
|
+
if (this.value.length === 0) {
|
|
590
|
+
this.value = undefined;
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
this.optionSelected = this.optionSelected.filter((val) => val !== option);
|
|
594
|
+
if (this.optionSelected.length === 0) {
|
|
595
|
+
this.optionSelected = undefined;
|
|
596
|
+
}
|
|
597
|
+
} else {
|
|
598
|
+
// For single-select: Back to undefined when deselected
|
|
599
|
+
this.value = undefined;
|
|
600
|
+
this.optionSelected = undefined;
|
|
601
|
+
}
|
|
602
|
+
|
|
603
|
+
// Update the index tracking
|
|
604
|
+
this.index = this.items.indexOf(option);
|
|
605
|
+
|
|
606
|
+
// Update UI to reflect changes
|
|
607
|
+
this.updateItemsState(new Map([
|
|
608
|
+
[
|
|
609
|
+
'optionSelected',
|
|
610
|
+
true
|
|
611
|
+
]
|
|
612
|
+
]));
|
|
613
|
+
|
|
614
|
+
// Notify of selection change
|
|
615
|
+
this.notifySelectionChange();
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Resets all options to their default state.
|
|
620
|
+
* @private
|
|
621
|
+
*/
|
|
622
|
+
clearSelection() {
|
|
623
|
+
this.optionSelected = undefined;
|
|
624
|
+
this.value = undefined;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* Resets the menu to its initial state.
|
|
629
|
+
* This is the only way to return value to undefined.
|
|
630
|
+
* @public
|
|
631
|
+
*/
|
|
632
|
+
reset() {
|
|
633
|
+
// Reset to undefined - initial state
|
|
634
|
+
this.value = undefined;
|
|
635
|
+
this.optionSelected = undefined;
|
|
636
|
+
this.index = -1;
|
|
637
|
+
|
|
638
|
+
// Reset UI state
|
|
639
|
+
this.updateItemsState(new Map([
|
|
640
|
+
[
|
|
641
|
+
'optionSelected',
|
|
642
|
+
true
|
|
643
|
+
]
|
|
644
|
+
]));
|
|
645
|
+
|
|
646
|
+
// Dispatch reset event
|
|
647
|
+
dispatchMenuEvent(this, 'auroMenu-selectValueReset');
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/**
|
|
651
|
+
* Handles nested menu structure.
|
|
652
|
+
* @private
|
|
653
|
+
* @param {HTMLElement} menu - Root menu element.
|
|
654
|
+
*/
|
|
655
|
+
handleNestedMenus(menu) {
|
|
656
|
+
const nestedMenus = menu.querySelectorAll('auro-menu, [auro-menu]');
|
|
657
|
+
|
|
658
|
+
nestedMenus.forEach((nestedMenu) => {
|
|
659
|
+
// role="listbox" only allows "role=group" for children.
|
|
660
|
+
nestedMenu.setAttribute('role', 'group');
|
|
661
|
+
if (!nestedMenu.hasAttribute('aria-label')) {
|
|
662
|
+
nestedMenu.setAttribute('aria-label', 'submenu');
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
const options = nestedMenu.querySelectorAll(':scope > auro-menuoption, :scope > [auro-menuoption]');
|
|
666
|
+
options.forEach((option) => {
|
|
667
|
+
option.innerHTML = this.nestingSpacer + option.innerHTML;
|
|
668
|
+
});
|
|
669
|
+
|
|
670
|
+
this.handleNestedMenus(nestedMenu);
|
|
671
|
+
});
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
// Event Handlers
|
|
675
|
+
|
|
676
|
+
/**
|
|
677
|
+
* Handles keyboard navigation.
|
|
678
|
+
* @private
|
|
679
|
+
* @param {KeyboardEvent} event - Event object from the browser.
|
|
680
|
+
*/
|
|
681
|
+
handleKeyDown(event) {
|
|
682
|
+
event.preventDefault();
|
|
683
|
+
switch (event.key) {
|
|
684
|
+
case "ArrowDown":
|
|
685
|
+
this.navigateOptions('down');
|
|
686
|
+
break;
|
|
687
|
+
case "ArrowUp":
|
|
688
|
+
this.navigateOptions('up');
|
|
689
|
+
break;
|
|
690
|
+
case "Enter":
|
|
691
|
+
this.makeSelection();
|
|
692
|
+
break;
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* Makes a selection based on the current index or clicked option.
|
|
698
|
+
* @private
|
|
699
|
+
*/
|
|
700
|
+
makeSelection() {
|
|
701
|
+
if (!this.items) {
|
|
702
|
+
this.initItems();
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
// Get currently selected menu option based on index
|
|
706
|
+
const option = this.items[this.index];
|
|
707
|
+
|
|
708
|
+
// Return early if option is not interactive
|
|
709
|
+
if (!option || !isOptionInteractive(option)) {
|
|
710
|
+
return;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
// Handle custom events first
|
|
714
|
+
if (option.hasAttribute('event')) {
|
|
715
|
+
this.handleCustomEvent(option);
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
|
|
719
|
+
if (this.multiSelect) {
|
|
720
|
+
// In multiselect, toggle individual selections
|
|
721
|
+
this.toggleOption(option);
|
|
722
|
+
// In single select, only handle selection of new options
|
|
723
|
+
} else if (!this.isOptionSelected(option)) {
|
|
724
|
+
this.clearSelection();
|
|
725
|
+
this.handleSelectState(option);
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
this.notifySelectionChange();
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* Toggle the selection state of the menuoption.
|
|
733
|
+
* @private
|
|
734
|
+
* @param {HTMLElement} option - The menuoption to toggle.
|
|
735
|
+
*/
|
|
736
|
+
toggleOption(option) {
|
|
737
|
+
const isCurrentlySelected = this.isOptionSelected(option);
|
|
738
|
+
|
|
739
|
+
if (isCurrentlySelected) {
|
|
740
|
+
this.handleDeselectState(option);
|
|
741
|
+
} else if (option.value === undefined || option.value === '') {
|
|
742
|
+
dispatchMenuEvent(this, 'auroMenu-selectValueFailure');
|
|
743
|
+
} else {
|
|
744
|
+
this.handleSelectState(option);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* Handles option selection via mouse.
|
|
750
|
+
* @private
|
|
751
|
+
* @param {MouseEvent} event - Event object from the browser.
|
|
752
|
+
*/
|
|
753
|
+
handleMouseSelect(event) {
|
|
754
|
+
if (event.target === this) {
|
|
755
|
+
return;
|
|
756
|
+
}
|
|
757
|
+
|
|
758
|
+
const option = event.target.closest('auro-menuoption, [auro-menuoption]');
|
|
759
|
+
if (option) {
|
|
760
|
+
this.index = this.items.indexOf(option);
|
|
761
|
+
this.makeSelection();
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
/**
|
|
766
|
+
* Handles option hover events.
|
|
767
|
+
* @private
|
|
768
|
+
* @param {CustomEvent} event - Event object from the browser.
|
|
769
|
+
*/
|
|
770
|
+
handleOptionHover(event) {
|
|
771
|
+
const option = event.target;
|
|
772
|
+
this.index = this.items.indexOf(option);
|
|
773
|
+
this.updateActiveOption(this.index);
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
/**
|
|
777
|
+
* Handles slot change events.
|
|
778
|
+
* @private
|
|
779
|
+
*/
|
|
780
|
+
handleSlotChange() {
|
|
781
|
+
if (this.parentElement && this.parentElement.closest('auro-menu, [auro-menu]')) {
|
|
782
|
+
this.rootMenu = false;
|
|
783
|
+
}
|
|
784
|
+
|
|
785
|
+
if (this.rootMenu) {
|
|
786
|
+
this.initializeMenu();
|
|
787
|
+
} else if (this.noCheckmark) {
|
|
788
|
+
this.updateItemsState(new Map([
|
|
789
|
+
[
|
|
790
|
+
'noCheckmark',
|
|
791
|
+
true
|
|
792
|
+
]
|
|
793
|
+
]));
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
/**
|
|
798
|
+
* Navigates through options using keyboard.
|
|
799
|
+
* @private
|
|
800
|
+
* @param {string} direction - 'up' or 'down'.
|
|
801
|
+
*/
|
|
802
|
+
navigateOptions(direction) {
|
|
803
|
+
// Return early if no items exist
|
|
804
|
+
if (!this.items || !this.items.length) {
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
let newIndex = this.index;
|
|
809
|
+
const increment = direction === 'down' ? 1 : -1;
|
|
810
|
+
const maxIterations = this.items.length;
|
|
811
|
+
let iterations = 0;
|
|
812
|
+
let foundInteractiveOption = false;
|
|
813
|
+
|
|
814
|
+
do {
|
|
815
|
+
newIndex = (newIndex + increment + this.items.length) % this.items.length;
|
|
816
|
+
iterations += 1;
|
|
817
|
+
|
|
818
|
+
// Check if current option is interactive
|
|
819
|
+
const currentOption = this.items[newIndex];
|
|
820
|
+
if (isOptionInteractive(currentOption)) {
|
|
821
|
+
foundInteractiveOption = true;
|
|
822
|
+
break;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// Break if all options were checked
|
|
826
|
+
if (iterations >= maxIterations) {
|
|
827
|
+
break;
|
|
828
|
+
}
|
|
829
|
+
} while (iterations < maxIterations);
|
|
830
|
+
|
|
831
|
+
// Handle the results of the search
|
|
832
|
+
if (foundInteractiveOption) {
|
|
833
|
+
// Update only if an interactive option was found
|
|
834
|
+
this.index = newIndex;
|
|
835
|
+
this.updateActiveOption(this.index);
|
|
836
|
+
} else {
|
|
837
|
+
// All options are disabled or non-interactive
|
|
838
|
+
// Keep the current index unchanged
|
|
839
|
+
dispatchMenuEvent(this, 'auroMenu-navigateFailure', {
|
|
840
|
+
reason: 'No interactive options available',
|
|
841
|
+
direction,
|
|
842
|
+
currentIndex: this.index
|
|
843
|
+
});
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
/**
|
|
848
|
+
* Updates the active option state and dispatches events.
|
|
849
|
+
* @private
|
|
850
|
+
* @param {number} index - Index of the option to make active.
|
|
851
|
+
*/
|
|
852
|
+
updateActiveOption(index) {
|
|
853
|
+
if (!this.items || !this.items[index]) {
|
|
854
|
+
return;
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
this.items.forEach((item) => item.classList.remove('active'));
|
|
858
|
+
this.items[index].classList.add('active');
|
|
859
|
+
this.optionActive = this.items[index];
|
|
860
|
+
this.index = index;
|
|
861
|
+
|
|
862
|
+
dispatchMenuEvent(this, 'auroMenu-activatedOption', this.items[index]);
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
/**
|
|
866
|
+
* Handles custom events defined on options.
|
|
867
|
+
* @private
|
|
868
|
+
* @param {HTMLElement} option - Option with custom event.
|
|
869
|
+
*/
|
|
870
|
+
handleCustomEvent(option) {
|
|
871
|
+
const eventName = option.getAttribute('event');
|
|
872
|
+
dispatchMenuEvent(this, eventName);
|
|
873
|
+
dispatchMenuEvent(this, 'auroMenu-customEventFired');
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
/**
|
|
877
|
+
* Notifies selection change to parent components.
|
|
878
|
+
* @private
|
|
879
|
+
*/
|
|
880
|
+
notifySelectionChange() {
|
|
881
|
+
dispatchMenuEvent(this, 'auroMenu-selectedOption');
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
/**
|
|
885
|
+
* Checks if an option is currently selected.
|
|
886
|
+
* @private
|
|
887
|
+
* @param {HTMLElement} option - The option to check.
|
|
888
|
+
* @returns {boolean}
|
|
889
|
+
*/
|
|
890
|
+
isOptionSelected(option) {
|
|
891
|
+
if (!this.optionSelected) {
|
|
892
|
+
return false;
|
|
893
|
+
}
|
|
894
|
+
// Always treat as array for both single and multi-select
|
|
895
|
+
return Array.isArray(this.optionSelected) && this.optionSelected.includes(option);
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
/**
|
|
899
|
+
* Getter for loading placeholder state.
|
|
900
|
+
* @returns {boolean} - True if loading slots are present and non-empty.
|
|
901
|
+
*/
|
|
902
|
+
get hasLoadingPlaceholder() {
|
|
903
|
+
return this.loadingSlots && this.loadingSlots.length > 0;
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
/**
|
|
907
|
+
* Renders the component.
|
|
908
|
+
* @returns {boolean} - True if loading slots are present and non-empty.
|
|
909
|
+
*/
|
|
910
|
+
render() {
|
|
911
|
+
if (this.loading) {
|
|
912
|
+
return html`
|
|
913
|
+
<auro-menuoption disabled loadingplaceholder class="${this.hasLoadingPlaceholder ? '' : 'empty'}">
|
|
914
|
+
<div>
|
|
915
|
+
<slot name="loadingIcon"></slot>
|
|
916
|
+
<slot name="loadingText"></slot>
|
|
917
|
+
</div>
|
|
918
|
+
</auro-menuoption>
|
|
919
|
+
`;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
return html`<slot @slotchange=${this.handleSlotChange}></slot>`;
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
var styleCss$1 = css`:host{display:flex;align-items:center;padding:var(--ds-size-50, 0.25rem) var(--ds-size-200, 1rem) var(--ds-size-50, 0.25rem) 0;cursor:pointer;user-select:none;-webkit-tap-highlight-color:transparent}: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)}:host ::slotted(strong){font-weight:700}:host([hidden]){display:none}:host([static]){pointer-events:none}:host([disabled]:hover){cursor:auto}:host([disabled]){user-select:none;pointer-events:none}`;
|
|
927
|
+
|
|
928
|
+
var colorCss$1 = css`:host{background-color:var(--ds-auro-menuoption-container-color);color:var(--ds-auro-menuoption-text-color)}:host svg{fill:var(--ds-auro-menuoption-icon-color)}:host([disabled]){--ds-auro-menuoption-text-color: var(--ds-basic-color-texticon-disabled, #d0d0d0)}:host(:hover),:host(.active){--ds-auro-menuoption-container-color: var(--ds-basic-color-surface-neutral-subtle, #f7f7f7)}:host([selected]){--ds-auro-menuoption-container-color: var(--ds-advanced-color-state-selected, #01426a);--ds-auro-menuoption-text-color: var(--ds-basic-color-texticon-inverse, #ffffff);--ds-auro-menuoption-icon-color: var(--ds-basic-color-texticon-inverse, #ffffff)}:host([selected]):host(:hover),:host([selected]):host(.active){--ds-auro-menuoption-container-color: var(--ds-advanced-color-state-selected-hover, #00274a)}`;
|
|
929
|
+
|
|
930
|
+
// Copyright (c) Alaska Air. All right reserved. Licensed under the Apache-2.0 license
|
|
931
|
+
// See LICENSE in the project root for license information.
|
|
932
|
+
|
|
933
|
+
|
|
934
|
+
class AuroDependencyVersioning {
|
|
935
|
+
|
|
936
|
+
/**
|
|
937
|
+
* Generates a unique string to be used for child auro element naming.
|
|
938
|
+
* @private
|
|
939
|
+
* @param {string} baseName - Defines the first part of the unique element name.
|
|
940
|
+
* @param {string} version - Version of the component that will be appended to the baseName.
|
|
941
|
+
* @returns {string} - Unique string to be used for naming.
|
|
942
|
+
*/
|
|
943
|
+
generateElementName(baseName, version) {
|
|
944
|
+
let result = baseName;
|
|
945
|
+
|
|
946
|
+
result += '-';
|
|
947
|
+
result += version.replace(/[.]/g, '_');
|
|
948
|
+
|
|
949
|
+
return result;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
/**
|
|
953
|
+
* Generates a unique string to be used for child auro element naming.
|
|
954
|
+
* @param {string} baseName - Defines the first part of the unique element name.
|
|
955
|
+
* @param {string} version - Version of the component that will be appended to the baseName.
|
|
956
|
+
* @returns {string} - Unique string to be used for naming.
|
|
957
|
+
*/
|
|
958
|
+
generateTag(baseName, version, tagClass) {
|
|
959
|
+
const elementName = this.generateElementName(baseName, version);
|
|
960
|
+
const tag = literal`${unsafeStatic(elementName)}`;
|
|
961
|
+
|
|
962
|
+
if (!customElements.get(elementName)) {
|
|
963
|
+
customElements.define(elementName, class extends tagClass {});
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
return tag;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
// Copyright (c) 2020 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
971
|
+
// See LICENSE in the project root for license information.
|
|
972
|
+
|
|
973
|
+
|
|
974
|
+
/**
|
|
975
|
+
* @attr {Boolean} hidden - If present, the component will be hidden both visually and from screen readers
|
|
976
|
+
* @attr {Boolean} hiddenVisually - If present, the component will be hidden visually, but still read by screen readers
|
|
977
|
+
* @attr {Boolean} hiddenAudible - If present, the component will be hidden from screen readers, but seen visually
|
|
978
|
+
*/
|
|
979
|
+
|
|
980
|
+
class AuroElement extends LitElement {
|
|
981
|
+
|
|
982
|
+
// function to define props used within the scope of this component
|
|
983
|
+
static get properties() {
|
|
984
|
+
return {
|
|
985
|
+
hidden: { type: Boolean,
|
|
986
|
+
reflect: true },
|
|
987
|
+
hiddenVisually: { type: Boolean,
|
|
988
|
+
reflect: true },
|
|
989
|
+
hiddenAudible: { type: Boolean,
|
|
990
|
+
reflect: true },
|
|
991
|
+
};
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
/**
|
|
995
|
+
* @private Function that determines state of aria-hidden
|
|
996
|
+
*/
|
|
997
|
+
hideAudible(value) {
|
|
998
|
+
if (value) {
|
|
999
|
+
return 'true'
|
|
1000
|
+
}
|
|
1001
|
+
|
|
1002
|
+
return 'false'
|
|
1003
|
+
}
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
var error = {"svg":"<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>"};
|
|
1007
|
+
|
|
1008
|
+
/* eslint-disable no-underscore-dangle, jsdoc/no-undefined-types, jsdoc/require-param-description */
|
|
1009
|
+
|
|
1010
|
+
const _fetchMap = new Map();
|
|
1011
|
+
|
|
1012
|
+
/**
|
|
1013
|
+
* A callback to parse Response body.
|
|
1014
|
+
*
|
|
1015
|
+
* @callback ResponseParser
|
|
1016
|
+
* @param {Fetch.Response} response
|
|
1017
|
+
* @returns {Promise}
|
|
1018
|
+
*/
|
|
1019
|
+
|
|
1020
|
+
/**
|
|
1021
|
+
* A minimal in-memory map to de-duplicate Fetch API media requests.
|
|
1022
|
+
*
|
|
1023
|
+
* @param {String} uri
|
|
1024
|
+
* @param {Object} [options={}]
|
|
1025
|
+
* @param {ResponseParser} [options.responseParser=(response) => response.text()]
|
|
1026
|
+
* @returns {Promise}
|
|
1027
|
+
*/
|
|
1028
|
+
const cacheFetch = (uri, options = {}) => {
|
|
1029
|
+
const responseParser = options.responseParser || ((response) => response.text());
|
|
1030
|
+
if (!_fetchMap.has(uri)) {
|
|
1031
|
+
_fetchMap.set(uri, fetch(uri).then(responseParser));
|
|
1032
|
+
}
|
|
1033
|
+
return _fetchMap.get(uri);
|
|
1034
|
+
};
|
|
1035
|
+
|
|
1036
|
+
var styleCss = 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, 0.75rem))}:host{color:currentColor;vertical-align:middle;line-height:1;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}.svgWrapper{height:var(--ds-auro-icon-size);width:var(--ds-auro-icon-size)}.labelWrapper{margin-left:var(--ds-size-50, 0.25rem);line-height:1.8}`;
|
|
1037
|
+
|
|
1038
|
+
// Copyright (c) 2020 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
1039
|
+
// See LICENSE in the project root for license information.
|
|
1040
|
+
|
|
1041
|
+
|
|
1042
|
+
// See https://git.io/JJ6SJ for "How to document your components using JSDoc"
|
|
1043
|
+
/**
|
|
1044
|
+
* @slot - Hidden from visibility, used for a11y if icon description is needed
|
|
1045
|
+
*/
|
|
1046
|
+
|
|
1047
|
+
// build the component class
|
|
1048
|
+
class BaseIcon extends AuroElement {
|
|
1049
|
+
constructor() {
|
|
1050
|
+
super();
|
|
1051
|
+
this.onDark = false;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
// function to define props used within the scope of this component
|
|
1055
|
+
static get properties() {
|
|
1056
|
+
return {
|
|
1057
|
+
...super.properties,
|
|
1058
|
+
|
|
1059
|
+
/**
|
|
1060
|
+
* Set value for on-dark version of auro-icon.
|
|
1061
|
+
*/
|
|
1062
|
+
onDark: {
|
|
1063
|
+
type: Boolean,
|
|
1064
|
+
reflect: true
|
|
1065
|
+
},
|
|
1066
|
+
|
|
1067
|
+
/**
|
|
1068
|
+
* @private
|
|
1069
|
+
*/
|
|
1070
|
+
svg: {
|
|
1071
|
+
attribute: false,
|
|
1072
|
+
reflect: true
|
|
1073
|
+
}
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
|
|
1077
|
+
static get styles() {
|
|
1078
|
+
return css`
|
|
1079
|
+
${styleCss}
|
|
1080
|
+
`;
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
/**
|
|
1084
|
+
* Async function to fetch requested icon from npm CDN.
|
|
1085
|
+
* @private
|
|
1086
|
+
* @param {string} category - Icon category.
|
|
1087
|
+
* @param {string} name - Icon name.
|
|
1088
|
+
* @returns {SVGElement} DOM - Ready HTML to be appended.
|
|
1089
|
+
*/
|
|
1090
|
+
async fetchIcon(category, name) {
|
|
1091
|
+
let iconHTML = '';
|
|
1092
|
+
|
|
1093
|
+
if (category === 'logos') {
|
|
1094
|
+
iconHTML = await cacheFetch(`${this.uri}/${category}/${name}.svg`);
|
|
1095
|
+
} else {
|
|
1096
|
+
iconHTML = await cacheFetch(`${this.uri}/icons/${category}/${name}.svg`);
|
|
1097
|
+
}
|
|
1098
|
+
|
|
1099
|
+
const dom = new DOMParser().parseFromString(iconHTML, 'text/html');
|
|
1100
|
+
|
|
1101
|
+
return dom.body.querySelector('svg');
|
|
1102
|
+
}
|
|
1103
|
+
|
|
1104
|
+
// lifecycle function
|
|
1105
|
+
async firstUpdated() {
|
|
1106
|
+
if (!this.customSvg) {
|
|
1107
|
+
const svg = await this.fetchIcon(this.category, this.name);
|
|
1108
|
+
|
|
1109
|
+
if (svg) {
|
|
1110
|
+
this.svg = svg;
|
|
1111
|
+
} else if (!svg) {
|
|
1112
|
+
const penDOM = new DOMParser().parseFromString(error.svg, 'text/html');
|
|
1113
|
+
|
|
1114
|
+
this.svg = penDOM.body.firstChild;
|
|
1115
|
+
}
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
}
|
|
1119
|
+
|
|
1120
|
+
var tokensCss = 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)}`;
|
|
1121
|
+
|
|
1122
|
+
var colorCss = css`:host{color:var(--ds-auro-icon-color)}:host([customColor]){color:inherit}:host(:not([onDark])[variant=accent1]){--ds-auro-icon-color:var(--ds-basic-color-texticon-accent1, #265688)}:host(:not([onDark])[variant=disabled]){--ds-auro-icon-color:var(--ds-basic-color-texticon-disabled, #d0d0d0)}:host(:not([onDark])[variant=muted]){--ds-auro-icon-color:var(--ds-basic-color-texticon-muted, #676767)}:host(:not([onDark])[variant=statusDefault]){--ds-auro-icon-color:var(--ds-basic-color-status-default, #afb9c6)}:host(:not([onDark])[variant=statusInfo]){--ds-auro-icon-color:var(--ds-basic-color-status-info, #01426a)}:host(:not([onDark])[variant=statusSuccess]){--ds-auro-icon-color:var(--ds-basic-color-status-success, #447a1f)}:host(:not([onDark])[variant=statusWarning]){--ds-auro-icon-color:var(--ds-basic-color-status-warning, #fac200)}:host(:not([onDark])[variant=statusError]){--ds-auro-icon-color:var(--ds-basic-color-status-error, #e31f26)}:host(:not([onDark])[variant=statusInfoSubtle]){--ds-auro-icon-color:var(--ds-basic-color-status-info-subtle, #ebf3f9)}:host(:not([onDark])[variant=statusSuccessSubtle]){--ds-auro-icon-color:var(--ds-basic-color-status-success-subtle, #d6eac7)}:host(:not([onDark])[variant=statusWarningSubtle]){--ds-auro-icon-color:var(--ds-basic-color-status-warning-subtle, #fff0b2)}:host(:not([onDark])[variant=statusErrorSubtle]){--ds-auro-icon-color:var(--ds-basic-color-status-error-subtle, #fbc6c6)}:host(:not([onDark])[variant=fareBasicEconomy]){--ds-auro-icon-color:var(--ds-basic-color-fare-basiceconomy, #97eaf8)}:host(:not([onDark])[variant=fareBusiness]){--ds-auro-icon-color:var(--ds-basic-color-fare-business, #01426a)}:host(:not([onDark])[variant=fareEconomy]){--ds-auro-icon-color:var(--ds-basic-color-fare-economy, #0074ca)}:host(:not([onDark])[variant=fareFirst]){--ds-auro-icon-color:var(--ds-basic-color-fare-first, #00274a)}:host(:not([onDark])[variant=farePremiumEconomy]){--ds-auro-icon-color:var(--ds-basic-color-fare-premiumeconomy, #005154)}:host(:not([onDark])[variant=tierOneWorldEmerald]){--ds-auro-icon-color:var(--ds-basic-color-tier-program-oneworld-emerald, #139142)}:host(:not([onDark])[variant=tierOneWorldSapphire]){--ds-auro-icon-color:var(--ds-basic-color-tier-program-oneworld-sapphire, #015daa)}:host(:not([onDark])[variant=tierOneWorldRuby]){--ds-auro-icon-color:var(--ds-basic-color-tier-program-oneworld-ruby, #a41d4a)}:host([onDark]){--ds-auro-icon-color:var(--ds-basic-color-texticon-inverse, #ffffff)}:host([onDark][variant=disabled]){--ds-auro-icon-color:var(--ds-basic-color-texticon-inverse-disabled, #7e8894)}:host([onDark][variant=muted]){--ds-auro-icon-color:var(--ds-basic-color-texticon-inverse-muted, #ccd2db)}`;
|
|
1123
|
+
|
|
1124
|
+
// Copyright (c) 2025 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
1125
|
+
// See LICENSE in the project root for license information.
|
|
1126
|
+
|
|
1127
|
+
|
|
1128
|
+
class AuroIcon extends BaseIcon {
|
|
1129
|
+
constructor() {
|
|
1130
|
+
super();
|
|
1131
|
+
|
|
1132
|
+
this.variant = undefined;
|
|
1133
|
+
this.privateDefaults();
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
/**
|
|
1137
|
+
* Internal Defaults.
|
|
1138
|
+
* @private
|
|
1139
|
+
* @returns {void}
|
|
1140
|
+
*/
|
|
1141
|
+
privateDefaults() {
|
|
1142
|
+
this.uri = 'https://cdn.jsdelivr.net/npm/@alaskaairux/icons@latest/dist';
|
|
1143
|
+
this.runtimeUtils = new AuroLibraryRuntimeUtils();
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
// function to define props used within the scope of this component
|
|
1147
|
+
static get properties() {
|
|
1148
|
+
return {
|
|
1149
|
+
...super.properties,
|
|
1150
|
+
|
|
1151
|
+
/**
|
|
1152
|
+
* Set aria-hidden value. Default is `true`. Option is `false`.
|
|
1153
|
+
*/
|
|
1154
|
+
ariaHidden: {
|
|
1155
|
+
type: String,
|
|
1156
|
+
reflect: true
|
|
1157
|
+
},
|
|
1158
|
+
|
|
1159
|
+
/**
|
|
1160
|
+
* The category of the icon you are looking for. See https://auro.alaskaair.com/icons/usage.
|
|
1161
|
+
*/
|
|
1162
|
+
category: {
|
|
1163
|
+
type: String,
|
|
1164
|
+
reflect: true
|
|
1165
|
+
},
|
|
1166
|
+
|
|
1167
|
+
/**
|
|
1168
|
+
* Allows custom color to be set.
|
|
1169
|
+
*/
|
|
1170
|
+
customColor: {
|
|
1171
|
+
type: Boolean
|
|
1172
|
+
},
|
|
1173
|
+
|
|
1174
|
+
/**
|
|
1175
|
+
* When true, auro-icon will render a custom SVG inside the default slot.
|
|
1176
|
+
*/
|
|
1177
|
+
customSvg: {
|
|
1178
|
+
type: Boolean
|
|
1179
|
+
},
|
|
1180
|
+
|
|
1181
|
+
/**
|
|
1182
|
+
* Exposes content in slot as icon label.
|
|
1183
|
+
*/
|
|
1184
|
+
label: {
|
|
1185
|
+
type: Boolean,
|
|
1186
|
+
reflect: true
|
|
1187
|
+
},
|
|
1188
|
+
|
|
1189
|
+
/**
|
|
1190
|
+
* The name of the icon you are looking for without the file extension. See https://auro.alaskaair.com/icons/usage.
|
|
1191
|
+
*/
|
|
1192
|
+
name: {
|
|
1193
|
+
type: String,
|
|
1194
|
+
reflect: true
|
|
1195
|
+
},
|
|
1196
|
+
|
|
1197
|
+
/**
|
|
1198
|
+
* The style of the icon. The accepted variants are `accent1`, `disabled`, `muted`, `statusDefault`, `statusInfo`, `statusSuccess`, `statusWarning`, `statusError`, `statusInfoSubtle`, `statusSuccessSubtle`, `statusWarningSubtle`, `statusErrorSubtle`, `fareBasicEconomy`, `fareBusiness`, `fareEconomy`, `fareFirst`, `farePremiumEconomy`, `tierOneWorldEmerald`, `tierOneWorldSapphire`, `tierOneWorldRuby`.
|
|
1199
|
+
*/
|
|
1200
|
+
variant: {
|
|
1201
|
+
type: String,
|
|
1202
|
+
reflect: true
|
|
1203
|
+
}
|
|
1204
|
+
};
|
|
1205
|
+
}
|
|
1206
|
+
|
|
1207
|
+
static get styles() {
|
|
1208
|
+
return [
|
|
1209
|
+
super.styles,
|
|
1210
|
+
css`${tokensCss}`,
|
|
1211
|
+
css`${styleCss}`,
|
|
1212
|
+
css`${colorCss}`
|
|
1213
|
+
];
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
/**
|
|
1217
|
+
* This will register this element with the browser.
|
|
1218
|
+
* @param {string} [name="auro-icon"] - The name of element that you want to register to.
|
|
1219
|
+
*
|
|
1220
|
+
* @example
|
|
1221
|
+
* AuroIcon.register("custom-icon") // this will register this element to <custom-icon/>
|
|
1222
|
+
*
|
|
1223
|
+
*/
|
|
1224
|
+
static register(name = "auro-icon") {
|
|
1225
|
+
AuroLibraryRuntimeUtils.prototype.registerComponent(name, AuroIcon);
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
connectedCallback() {
|
|
1229
|
+
super.connectedCallback();
|
|
1230
|
+
|
|
1231
|
+
// Add the tag name as an attribute if it is different than the component name
|
|
1232
|
+
this.runtimeUtils.handleComponentTagRename(this, 'auro-icon');
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
/**
|
|
1236
|
+
* @private
|
|
1237
|
+
* @returns {void} Exposes CSS parts for styling from parent components.
|
|
1238
|
+
*/
|
|
1239
|
+
exposeCssParts() {
|
|
1240
|
+
this.setAttribute('exportparts', 'svg:iconSvg');
|
|
1241
|
+
}
|
|
1242
|
+
|
|
1243
|
+
async firstUpdated() {
|
|
1244
|
+
await super.firstUpdated();
|
|
1245
|
+
|
|
1246
|
+
// Removes the SVG description for screenreader if ariaHidden is set to true
|
|
1247
|
+
if (!this.hasAttribute('ariaHidden') && this.svg) {
|
|
1248
|
+
const svgDesc = this.svg.querySelector('desc');
|
|
1249
|
+
|
|
1250
|
+
if (svgDesc) {
|
|
1251
|
+
svgDesc.remove();
|
|
1252
|
+
this.svg.removeAttribute('aria-labelledby');
|
|
1253
|
+
}
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
// function that renders the HTML and CSS into the scope of the component
|
|
1258
|
+
render() {
|
|
1259
|
+
const labelClasses = {
|
|
1260
|
+
'labelWrapper': true,
|
|
1261
|
+
'util_displayHiddenVisually': !this.label
|
|
1262
|
+
};
|
|
1263
|
+
|
|
1264
|
+
const svgClasses = {
|
|
1265
|
+
'svgWrapper': true,
|
|
1266
|
+
};
|
|
1267
|
+
|
|
1268
|
+
return html`
|
|
1269
|
+
<div class="componentWrapper">
|
|
1270
|
+
<div
|
|
1271
|
+
class="${classMap(svgClasses)}"
|
|
1272
|
+
title="${ifDefined(this.title || undefined)}">
|
|
1273
|
+
<span aria-hidden="${ifDefined(this.ariaHidden || true)}" part="svg">
|
|
1274
|
+
${this.customSvg ? html`
|
|
1275
|
+
<slot name="svg"></slot>
|
|
1276
|
+
` : html`
|
|
1277
|
+
${this.svg}
|
|
1278
|
+
`
|
|
1279
|
+
}
|
|
1280
|
+
</span>
|
|
1281
|
+
</div>
|
|
1282
|
+
|
|
1283
|
+
<div class="${classMap(labelClasses)}">
|
|
1284
|
+
<slot></slot>
|
|
1285
|
+
</div>
|
|
1286
|
+
</div>
|
|
1287
|
+
`;
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
var iconVersion = '8.0.2';
|
|
1292
|
+
|
|
1293
|
+
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>"};
|
|
1294
|
+
|
|
1295
|
+
// Copyright (c) 2021 Alaska Airlines. All right reserved. Licensed under the Apache-2.0 license
|
|
1296
|
+
// See LICENSE in the project root for license information.
|
|
1297
|
+
|
|
1298
|
+
|
|
1299
|
+
/**
|
|
1300
|
+
* The auro-menu element provides users a way to define a menu option.
|
|
1301
|
+
*
|
|
1302
|
+
* @attr {String} value - Specifies the value to be sent to a server.
|
|
1303
|
+
* @attr {String} noCheckmark - When true, selected option will not show the checkmark.
|
|
1304
|
+
* @attr {Boolean} disabled - When true specifies that the menuoption is disabled.
|
|
1305
|
+
* @attr {Boolean} selected - Specifies that an option is selected.
|
|
1306
|
+
* @event auroMenuOption-mouseover - Notifies that this option has been hovered over.
|
|
1307
|
+
* @slot - Specifies text for an option, but is not the value.
|
|
1308
|
+
*/
|
|
1309
|
+
class AuroMenuOption extends LitElement {
|
|
1310
|
+
constructor() {
|
|
1311
|
+
super();
|
|
1312
|
+
|
|
1313
|
+
/**
|
|
1314
|
+
* Generate unique names for dependency components.
|
|
1315
|
+
*/
|
|
1316
|
+
const versioning = new AuroDependencyVersioning();
|
|
1317
|
+
this.iconTag = versioning.generateTag('auro-formkit-menuoption-icon', iconVersion, AuroIcon);
|
|
1318
|
+
|
|
1319
|
+
this.selected = false;
|
|
1320
|
+
this.nocheckmark = false;
|
|
1321
|
+
this.disabled = false;
|
|
1322
|
+
|
|
1323
|
+
/**
|
|
1324
|
+
* @private
|
|
1325
|
+
*/
|
|
1326
|
+
this.tabIndex = -1;
|
|
1327
|
+
|
|
1328
|
+
/**
|
|
1329
|
+
* @private
|
|
1330
|
+
*/
|
|
1331
|
+
this.runtimeUtils = new AuroLibraryRuntimeUtils();
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
static get properties() {
|
|
1335
|
+
return {
|
|
1336
|
+
nocheckmark: {
|
|
1337
|
+
type: Boolean,
|
|
1338
|
+
reflect: true
|
|
1339
|
+
},
|
|
1340
|
+
selected: {
|
|
1341
|
+
type: Boolean,
|
|
1342
|
+
reflect: true
|
|
1343
|
+
},
|
|
1344
|
+
disabled: {
|
|
1345
|
+
type: Boolean,
|
|
1346
|
+
reflect: true
|
|
1347
|
+
},
|
|
1348
|
+
value: {
|
|
1349
|
+
type: String
|
|
1350
|
+
},
|
|
1351
|
+
tabIndex: {
|
|
1352
|
+
type: Number,
|
|
1353
|
+
reflect: true
|
|
1354
|
+
}
|
|
1355
|
+
};
|
|
1356
|
+
}
|
|
1357
|
+
|
|
1358
|
+
static get styles() {
|
|
1359
|
+
return [
|
|
1360
|
+
styleCss$1,
|
|
1361
|
+
colorCss$1,
|
|
1362
|
+
tokensCss$1
|
|
1363
|
+
];
|
|
1364
|
+
}
|
|
1365
|
+
|
|
1366
|
+
/**
|
|
1367
|
+
* This will register this element with the browser.
|
|
1368
|
+
* @param {string} [name="auro-menuoption"] - The name of element that you want to register to.
|
|
1369
|
+
*
|
|
1370
|
+
* @example
|
|
1371
|
+
* AuroMenuOption.register("custom-menuoption") // this will register this element to <custom-menuoption/>
|
|
1372
|
+
*
|
|
1373
|
+
*/
|
|
1374
|
+
static register(name = "auro-menuoption") {
|
|
1375
|
+
AuroLibraryRuntimeUtils.prototype.registerComponent(name, AuroMenuOption);
|
|
1376
|
+
}
|
|
1377
|
+
|
|
1378
|
+
firstUpdated() {
|
|
1379
|
+
// Add the tag name as an attribute if it is different than the component name
|
|
1380
|
+
this.runtimeUtils.handleComponentTagRename(this, 'auro-menuoption');
|
|
1381
|
+
|
|
1382
|
+
this.setAttribute('role', 'option');
|
|
1383
|
+
this.setAttribute('aria-selected', 'false');
|
|
1384
|
+
|
|
1385
|
+
this.addEventListener('mouseover', () => {
|
|
1386
|
+
this.dispatchEvent(new CustomEvent('auroMenuOption-mouseover', {
|
|
1387
|
+
bubbles: true,
|
|
1388
|
+
cancelable: false,
|
|
1389
|
+
composed: true,
|
|
1390
|
+
detail: this
|
|
1391
|
+
}));
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
// observer for selected property changes
|
|
1396
|
+
updated(changedProperties) {
|
|
1397
|
+
if (changedProperties.has('selected')) {
|
|
1398
|
+
this.setAttribute('aria-selected', this.selected.toString());
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
|
|
1402
|
+
/**
|
|
1403
|
+
* Generates an HTML element containing an SVG icon based on the provided `svgContent`.
|
|
1404
|
+
*
|
|
1405
|
+
* @private
|
|
1406
|
+
* @param {string} svgContent - The SVG content to be embedded.
|
|
1407
|
+
* @returns {Element} The HTML element containing the SVG icon.
|
|
1408
|
+
*/
|
|
1409
|
+
generateIconHtml(svgContent) {
|
|
1410
|
+
const dom = new DOMParser().parseFromString(svgContent, 'text/html');
|
|
1411
|
+
const svg = dom.body.firstChild;
|
|
1412
|
+
|
|
1413
|
+
svg.setAttribute('slot', 'svg');
|
|
1414
|
+
|
|
1415
|
+
return html$1`<${this.iconTag} customColor customSvg slot="icon">${svg}</${this.iconTag}>`;
|
|
1416
|
+
}
|
|
1417
|
+
|
|
1418
|
+
render() {
|
|
1419
|
+
return html$1`
|
|
1420
|
+
${this.selected && !this.nocheckmark ? this.generateIconHtml(checkmarkIcon.svg) : undefined}
|
|
1421
|
+
<slot></slot>
|
|
1422
|
+
`;
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
|
|
1426
|
+
export { AuroMenu, AuroMenuOption, arrayConverter, arrayOrUndefinedHasChanged, dispatchMenuEvent, isOptionInteractive };
|