@lion/ui 0.1.2 → 0.1.4
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/combobox/src/LionCombobox.js +34 -65
- package/components/combobox/src/utils/makeMatchingTextBold.js +68 -0
- package/components/combobox/test/lion-combobox.test.js +166 -1
- package/custom-elements.json +256 -0
- package/dist-types/components/combobox/src/LionCombobox.d.ts +13 -0
- package/dist-types/components/combobox/src/LionCombobox.d.ts.map +1 -1
- package/dist-types/components/combobox/src/utils/makeMatchingTextBold.d.ts +10 -0
- package/dist-types/components/combobox/src/utils/makeMatchingTextBold.d.ts.map +1 -0
- package/dist-types/components/combobox/test/lion-combobox.test.d.ts +1 -0
- package/dist-types/components/combobox/test/lion-combobox.test.d.ts.map +1 -1
- package/dist-types/exports/combobox.d.ts +1 -0
- package/dist-types/exports/types/core.d.ts +2 -0
- package/dist-types/exports/types/core.d.ts.map +1 -1
- package/dist-types/tsconfig.tsbuildinfo +1 -1
- package/docs/components/checkbox-group/overview.md +2 -2
- package/docs/components/collapsible/overview.md +1 -1
- package/docs/components/combobox/overview.md +1 -1
- package/docs/components/combobox/use-cases.md +40 -16
- package/docs/components/dialog/overview.md +1 -1
- package/docs/components/fieldset/overview.md +5 -5
- package/docs/components/form/overview.md +3 -3
- package/docs/components/icon/use-cases.md +1 -1
- package/docs/components/input/overview.md +1 -1
- package/docs/components/input-amount/overview.md +3 -3
- package/docs/components/input-date/overview.md +3 -3
- package/docs/components/input-datepicker/overview.md +5 -5
- package/docs/components/input-email/overview.md +2 -2
- package/docs/components/input-iban/overview.md +2 -2
- package/docs/components/input-range/overview.md +2 -2
- package/docs/components/input-stepper/overview.md +1 -1
- package/docs/components/input-tel/overview.md +1 -1
- package/docs/components/input-tel/use-cases.md +6 -6
- package/docs/components/input-tel-dropdown/overview.md +1 -1
- package/docs/components/listbox/src/listboxData.js +66 -0
- package/docs/components/radio-group/overview.md +3 -3
- package/docs/components/select-rich/use-cases.md +1 -1
- package/docs/components/tabs/examples.md +1 -1
- package/docs/fundamentals/index.md +4 -4
- package/docs/fundamentals/node-tools/providence-analytics/LocalConfiguration.md +1 -1
- package/docs/fundamentals/node-tools/providence-analytics/QueryResult.md +1 -1
- package/docs/fundamentals/node-tools/providence-analytics/analyzer.md +1 -1
- package/docs/fundamentals/node-tools/providence-analytics/dashboard.md +1 -1
- package/docs/fundamentals/node-tools/providence-analytics/overview.md +3 -3
- package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
- package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
- package/docs/fundamentals/systems/core/overview.md +1 -1
- package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
- package/docs/fundamentals/systems/form/model-value.md +1 -1
- package/docs/fundamentals/systems/form/overview.md +28 -28
- package/docs/fundamentals/systems/form/validate.md +1 -1
- package/docs/fundamentals/systems/localize/overview.md +4 -4
- package/docs/fundamentals/systems/overlays/configuration.md +2 -2
- package/docs/fundamentals/systems/overlays/overview.md +5 -5
- package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
- package/docs/fundamentals/tools/helpers/overview.md +1 -1
- package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
- package/docs/guides/how-to/create-a-custom-field.md +5 -5
- package/docs/guides/how-to/extend-a-native-input.md +2 -2
- package/docs/guides/index.md +8 -8
- package/docs/guides/principles/index.md +5 -5
- package/docs/guides/principles/styling.md +1 -1
- package/exports/combobox.js +4 -0
- package/exports/types/core.ts +2 -0
- package/package.json +8 -1
|
@@ -1,62 +1,11 @@
|
|
|
1
|
-
import { html, css } from 'lit';
|
|
2
1
|
import { browserDetection } from '@lion/ui/core.js';
|
|
3
|
-
import { OverlayMixin, withDropdownConfig } from '@lion/ui/overlays.js';
|
|
4
2
|
import { LionListbox } from '@lion/ui/listbox.js';
|
|
3
|
+
import { OverlayMixin, withDropdownConfig } from '@lion/ui/overlays.js';
|
|
4
|
+
import { css, html } from 'lit';
|
|
5
|
+
import { makeMatchingTextBold, unmakeMatchingTextBold } from './utils/makeMatchingTextBold.js';
|
|
5
6
|
|
|
6
|
-
const matchReverseFns = new WeakMap();
|
|
7
7
|
const matchA11ySpanReverseFns = new WeakMap();
|
|
8
8
|
|
|
9
|
-
/**
|
|
10
|
-
* @param {Node} root
|
|
11
|
-
* @param {string} matchingString
|
|
12
|
-
* @param {Node} option
|
|
13
|
-
*/
|
|
14
|
-
function makeMatchingTextBold(root, matchingString, option) {
|
|
15
|
-
Array.from(root.childNodes).forEach(childNode => {
|
|
16
|
-
if (childNode.nodeName === '#text') {
|
|
17
|
-
// check for match based on nodeValue
|
|
18
|
-
|
|
19
|
-
const re = new RegExp(`^(.*)(${matchingString})(.*)$`, 'i');
|
|
20
|
-
// @ts-ignore
|
|
21
|
-
const match = childNode.nodeValue.match(re);
|
|
22
|
-
|
|
23
|
-
if (match) {
|
|
24
|
-
// 1. textContent before match
|
|
25
|
-
|
|
26
|
-
const textBefore = document.createTextNode(match[1]);
|
|
27
|
-
root.appendChild(textBefore);
|
|
28
|
-
|
|
29
|
-
// 2. matched part
|
|
30
|
-
const boldElement = document.createElement('b');
|
|
31
|
-
// eslint-disable-next-line prefer-destructuring
|
|
32
|
-
boldElement.textContent = match[2];
|
|
33
|
-
root.appendChild(boldElement);
|
|
34
|
-
|
|
35
|
-
// 3. textContent after match
|
|
36
|
-
|
|
37
|
-
const textAfter = document.createTextNode(match[3]);
|
|
38
|
-
root.appendChild(textAfter);
|
|
39
|
-
root.removeChild(childNode);
|
|
40
|
-
|
|
41
|
-
matchReverseFns.set(option, () => {
|
|
42
|
-
root.appendChild(childNode);
|
|
43
|
-
if (root.contains(textBefore) && textBefore.parentNode !== null) {
|
|
44
|
-
textBefore.parentNode.removeChild(textBefore);
|
|
45
|
-
}
|
|
46
|
-
if (root.contains(boldElement) && boldElement.parentNode !== null) {
|
|
47
|
-
boldElement.parentNode.removeChild(boldElement);
|
|
48
|
-
}
|
|
49
|
-
if (root.contains(textAfter) && textAfter.parentNode !== null) {
|
|
50
|
-
textAfter.parentNode.removeChild(textAfter);
|
|
51
|
-
}
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
} else {
|
|
55
|
-
makeMatchingTextBold(childNode, matchingString, option);
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
|
|
60
9
|
// TODO: make ListboxOverlayMixin that is shared between SelectRich and Combobox
|
|
61
10
|
// TODO: extract option matching based on 'typed character cache' and share that logic
|
|
62
11
|
// on Listbox or ListNavigationWithActiveDescendantMixin
|
|
@@ -304,7 +253,6 @@ export class LionCombobox extends OverlayMixin(LionListbox) {
|
|
|
304
253
|
* @type {'begin'|'all'}
|
|
305
254
|
*/
|
|
306
255
|
this.matchMode = 'all';
|
|
307
|
-
|
|
308
256
|
/**
|
|
309
257
|
* When true, the listbox is open and textbox goes from a value to empty, all options are shown.
|
|
310
258
|
* By default, the listbox closes on empty, similar to wai-aria example and <datalist>
|
|
@@ -642,14 +590,27 @@ export class LionCombobox extends OverlayMixin(LionListbox) {
|
|
|
642
590
|
* @param {string} matchingString
|
|
643
591
|
* @protected
|
|
644
592
|
*/
|
|
645
|
-
// eslint-disable-next-line class-methods-use-this
|
|
646
593
|
_onFilterMatch(option, matchingString) {
|
|
647
|
-
|
|
594
|
+
this._highlightMatchedOption(option, matchingString);
|
|
595
|
+
|
|
596
|
+
// Alternatively, an extension can add an animation here
|
|
597
|
+
option.style.display = '';
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
/**
|
|
601
|
+
* @overridable
|
|
602
|
+
* @param {Element} option
|
|
603
|
+
* @param {string} matchingString
|
|
604
|
+
* @protected
|
|
605
|
+
*/
|
|
606
|
+
// eslint-disable-next-line class-methods-use-this
|
|
607
|
+
_highlightMatchedOption(option, matchingString) {
|
|
608
|
+
makeMatchingTextBold(option, matchingString);
|
|
648
609
|
|
|
649
610
|
// For Safari, we need to add a label to the element
|
|
650
611
|
if (option.textContent) {
|
|
651
612
|
const a11ySpan = document.createElement('span');
|
|
652
|
-
a11ySpan.setAttribute('aria-label', option.textContent);
|
|
613
|
+
a11ySpan.setAttribute('aria-label', option.textContent.replace(/\s+/g, ' '));
|
|
653
614
|
Array.from(option.childNodes).forEach(childNode => {
|
|
654
615
|
a11ySpan.appendChild(childNode);
|
|
655
616
|
});
|
|
@@ -664,8 +625,6 @@ export class LionCombobox extends OverlayMixin(LionListbox) {
|
|
|
664
625
|
}
|
|
665
626
|
});
|
|
666
627
|
}
|
|
667
|
-
// Alternatively, an extension can add an animation here
|
|
668
|
-
option.style.display = '';
|
|
669
628
|
}
|
|
670
629
|
|
|
671
630
|
/**
|
|
@@ -677,14 +636,24 @@ export class LionCombobox extends OverlayMixin(LionListbox) {
|
|
|
677
636
|
*/
|
|
678
637
|
// eslint-disable-next-line no-unused-vars, class-methods-use-this
|
|
679
638
|
_onFilterUnmatch(option, curValue, prevValue) {
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
639
|
+
this._unhighlightMatchedOption(option);
|
|
640
|
+
|
|
641
|
+
// Alternatively, an extension can add an animation here
|
|
642
|
+
option.style.display = 'none';
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
/**
|
|
646
|
+
* @overridable
|
|
647
|
+
* @param {Element} option
|
|
648
|
+
* @protected
|
|
649
|
+
*/
|
|
650
|
+
// eslint-disable-next-line class-methods-use-this
|
|
651
|
+
_unhighlightMatchedOption(option) {
|
|
652
|
+
unmakeMatchingTextBold(option);
|
|
653
|
+
|
|
683
654
|
if (matchA11ySpanReverseFns.has(option)) {
|
|
684
655
|
matchA11ySpanReverseFns.get(option)();
|
|
685
656
|
}
|
|
686
|
-
// Alternatively, an extension can add an animation here
|
|
687
|
-
option.style.display = 'none';
|
|
688
657
|
}
|
|
689
658
|
/* eslint-enable no-param-reassign */
|
|
690
659
|
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
const matchReverseFns = new WeakMap();
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @param {Node} root
|
|
5
|
+
* @param {string} matchingString
|
|
6
|
+
*/
|
|
7
|
+
export function makeMatchingTextBold(root, matchingString) {
|
|
8
|
+
Array.from(root.childNodes).forEach(childNode => {
|
|
9
|
+
if (childNode.nodeName === '#text') {
|
|
10
|
+
// check for match based on nodeValue
|
|
11
|
+
|
|
12
|
+
const re = new RegExp(`^(.*?)(${matchingString})(.*)$`, 'i');
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
const match = childNode.nodeValue.match(re);
|
|
15
|
+
|
|
16
|
+
if (match) {
|
|
17
|
+
// 1. textContent before match
|
|
18
|
+
const textBefore = document.createTextNode(match[1]);
|
|
19
|
+
root.appendChild(textBefore);
|
|
20
|
+
|
|
21
|
+
// 2. matched part
|
|
22
|
+
const boldElement = document.createElement('b');
|
|
23
|
+
// eslint-disable-next-line prefer-destructuring
|
|
24
|
+
boldElement.textContent = match[2];
|
|
25
|
+
root.appendChild(boldElement);
|
|
26
|
+
|
|
27
|
+
// 3. textContent after match
|
|
28
|
+
const textAfter = document.createTextNode(match[3]);
|
|
29
|
+
root.appendChild(textAfter);
|
|
30
|
+
|
|
31
|
+
root.removeChild(childNode);
|
|
32
|
+
|
|
33
|
+
matchReverseFns.set(root, () => {
|
|
34
|
+
root.appendChild(childNode);
|
|
35
|
+
if (root.contains(textBefore) && textBefore.parentNode !== null) {
|
|
36
|
+
textBefore.parentNode.removeChild(textBefore);
|
|
37
|
+
}
|
|
38
|
+
if (root.contains(boldElement) && boldElement.parentNode !== null) {
|
|
39
|
+
boldElement.parentNode.removeChild(boldElement);
|
|
40
|
+
}
|
|
41
|
+
if (root.contains(textAfter) && textAfter.parentNode !== null) {
|
|
42
|
+
textAfter.parentNode.removeChild(textAfter);
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
} else {
|
|
47
|
+
makeMatchingTextBold(childNode, matchingString);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* @param {Node} root
|
|
54
|
+
*/
|
|
55
|
+
export function unmakeMatchingTextBold(root) {
|
|
56
|
+
if (matchReverseFns.has(root)) {
|
|
57
|
+
matchReverseFns.get(root)();
|
|
58
|
+
}
|
|
59
|
+
Array.from(root.childNodes).forEach(childNode => {
|
|
60
|
+
if (childNode.nodeName === '#text') {
|
|
61
|
+
if (matchReverseFns.has(childNode)) {
|
|
62
|
+
matchReverseFns.get(childNode)();
|
|
63
|
+
}
|
|
64
|
+
} else {
|
|
65
|
+
unmakeMatchingTextBold(childNode);
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
@@ -13,6 +13,7 @@ import { LionCombobox } from '@lion/ui/combobox.js';
|
|
|
13
13
|
* @typedef {import('../types/SelectionDisplay.js').SelectionDisplay} SelectionDisplay
|
|
14
14
|
* @typedef {import('../../listbox/types/ListboxMixinTypes.js').ListboxHost} ListboxHost
|
|
15
15
|
* @typedef {import('../../form-core/types/FormControlMixinTypes.js').FormControlHost} FormControlHost
|
|
16
|
+
* @typedef {import('@lion/ui/listbox.js').LionOption} LionOption
|
|
16
17
|
*/
|
|
17
18
|
|
|
18
19
|
/**
|
|
@@ -1632,7 +1633,7 @@ describe('lion-combobox', () => {
|
|
|
1632
1633
|
});
|
|
1633
1634
|
});
|
|
1634
1635
|
|
|
1635
|
-
it('highlights matching
|
|
1636
|
+
it('highlights first occcurence of matching option', async () => {
|
|
1636
1637
|
const el = /** @type {LionCombobox} */ (
|
|
1637
1638
|
await fixture(html`
|
|
1638
1639
|
<lion-combobox name="foo" match-mode="all">
|
|
@@ -1645,6 +1646,16 @@ describe('lion-combobox', () => {
|
|
|
1645
1646
|
);
|
|
1646
1647
|
const options = el.formElements;
|
|
1647
1648
|
|
|
1649
|
+
mimicUserTyping(/** @type {LionCombobox} */ (el), 'c');
|
|
1650
|
+
|
|
1651
|
+
await el.updateComplete;
|
|
1652
|
+
expect(options[0]).lightDom.to.equal(`<span aria-label="Artichoke">Arti<b>c</b>hoke</span>`);
|
|
1653
|
+
expect(options[1]).lightDom.to.equal(`<span aria-label="Chard"><b>C</b>hard</span>`);
|
|
1654
|
+
expect(options[2]).lightDom.to.equal(`<span aria-label="Chicory"><b>C</b>hicory</span>`);
|
|
1655
|
+
expect(options[3]).lightDom.to.equal(
|
|
1656
|
+
`<span aria-label="Victoria Plum">Vi<b>c</b>toria Plum</span>`,
|
|
1657
|
+
);
|
|
1658
|
+
|
|
1648
1659
|
mimicUserTyping(/** @type {LionCombobox} */ (el), 'ch');
|
|
1649
1660
|
|
|
1650
1661
|
await el.updateComplete;
|
|
@@ -1662,6 +1673,48 @@ describe('lion-combobox', () => {
|
|
|
1662
1673
|
expect(options[3]).lightDom.to.equal(`Victoria Plum`);
|
|
1663
1674
|
});
|
|
1664
1675
|
|
|
1676
|
+
it('highlights matching complex options', async () => {
|
|
1677
|
+
const el = /** @type {LionCombobox} */ (
|
|
1678
|
+
await fixture(html`
|
|
1679
|
+
<lion-combobox name="foo" match-mode="all">
|
|
1680
|
+
<lion-option .choiceValue="${'Artichoke'}">
|
|
1681
|
+
<div>Artichoke</div>
|
|
1682
|
+
<small>Cardoon</small>
|
|
1683
|
+
</lion-option>
|
|
1684
|
+
<lion-option .choiceValue="${'Chard'}">
|
|
1685
|
+
<div>Chard</div>
|
|
1686
|
+
<small>Beet</small>
|
|
1687
|
+
</lion-option>
|
|
1688
|
+
<lion-option .choiceValue="${'Chicory'}">
|
|
1689
|
+
<div>Chicory</div>
|
|
1690
|
+
<small>Chicory</small>
|
|
1691
|
+
</lion-option>
|
|
1692
|
+
<lion-option .choiceValue="${'Victoria Plum'}">
|
|
1693
|
+
<div>Victoria Plum</div>
|
|
1694
|
+
<small>Prunus domestica</small>
|
|
1695
|
+
</lion-option>
|
|
1696
|
+
</lion-combobox>
|
|
1697
|
+
`)
|
|
1698
|
+
);
|
|
1699
|
+
const options = el.formElements;
|
|
1700
|
+
|
|
1701
|
+
mimicUserTyping(/** @type {LionCombobox} */ (el), 'ch');
|
|
1702
|
+
|
|
1703
|
+
await el.updateComplete;
|
|
1704
|
+
expect(options[0]).lightDom.to.equal(
|
|
1705
|
+
`<span aria-label=" Artichoke Cardoon "><div>Arti<b>ch</b>oke</div><small>Cardoon</small>`,
|
|
1706
|
+
);
|
|
1707
|
+
expect(options[1]).lightDom.to.equal(
|
|
1708
|
+
`<span aria-label=" Chard Beet "><div><b>Ch</b>ard</div><small>Beet</small>`,
|
|
1709
|
+
);
|
|
1710
|
+
expect(options[2]).lightDom.to.equal(
|
|
1711
|
+
`<span aria-label=" Chicory Chicory "><div><b>Ch</b>icory</div><small><b>Ch</b>icory</small>`,
|
|
1712
|
+
);
|
|
1713
|
+
expect(options[3]).lightDom.to.equal(
|
|
1714
|
+
`<div>Victoria Plum</div><small>Prunus domestica</small>`,
|
|
1715
|
+
);
|
|
1716
|
+
});
|
|
1717
|
+
|
|
1665
1718
|
it('synchronizes textbox when autocomplete is "inline" or "both"', async () => {
|
|
1666
1719
|
const el = /** @type {LionCombobox} */ (
|
|
1667
1720
|
await fixture(html`
|
|
@@ -1999,6 +2052,98 @@ describe('lion-combobox', () => {
|
|
|
1999
2052
|
await performChecks();
|
|
2000
2053
|
});
|
|
2001
2054
|
});
|
|
2055
|
+
|
|
2056
|
+
it('allows to override "_onFilterMatch" and "_onFilterUmatch"', async () => {
|
|
2057
|
+
class X extends LionCombobox {
|
|
2058
|
+
/**
|
|
2059
|
+
* @overridable
|
|
2060
|
+
* @param {LionOption & {__originalInnerHTML?:string}} option
|
|
2061
|
+
* @param {string} matchingString
|
|
2062
|
+
* @protected
|
|
2063
|
+
*/
|
|
2064
|
+
_onFilterMatch(option, matchingString) {
|
|
2065
|
+
Array.from(option.children).forEach(child => {
|
|
2066
|
+
if (child.hasAttribute('data-key')) {
|
|
2067
|
+
this._highlightMatchedOption(child, matchingString);
|
|
2068
|
+
}
|
|
2069
|
+
});
|
|
2070
|
+
// Alternatively, an extension can add an animation here
|
|
2071
|
+
// option.style.display = '';
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
/**
|
|
2075
|
+
* @overridable
|
|
2076
|
+
* @param {LionOption & {__originalInnerHTML?:string}} option
|
|
2077
|
+
* @param {string} [curValue]
|
|
2078
|
+
* @param {string} [prevValue]
|
|
2079
|
+
* @protected
|
|
2080
|
+
*/
|
|
2081
|
+
// eslint-disable-next-line no-unused-vars
|
|
2082
|
+
_onFilterUnmatch(option, curValue, prevValue) {
|
|
2083
|
+
Array.from(option.children).forEach(child => {
|
|
2084
|
+
if (child.hasAttribute('data-key')) {
|
|
2085
|
+
this._unhighlightMatchedOption(child);
|
|
2086
|
+
}
|
|
2087
|
+
});
|
|
2088
|
+
// Alternatively, an extension can add an animation here
|
|
2089
|
+
// option.style.display = 'none';
|
|
2090
|
+
}
|
|
2091
|
+
}
|
|
2092
|
+
const tagName = defineCE(X);
|
|
2093
|
+
const tag = unsafeStatic(tagName);
|
|
2094
|
+
|
|
2095
|
+
const el = /** @type {LionCombobox} */ (
|
|
2096
|
+
await fixture(html`
|
|
2097
|
+
<${tag} name="foo" autocomplete="both">
|
|
2098
|
+
<lion-option .choiceValue="${'Artichoke'}">
|
|
2099
|
+
<div data-key>Artichoke</div>
|
|
2100
|
+
<small>Cardoon</small>
|
|
2101
|
+
</lion-option>
|
|
2102
|
+
<lion-option .choiceValue="${'Chard'}">
|
|
2103
|
+
<div data-key>Chard</div>
|
|
2104
|
+
<small>Beet</small>
|
|
2105
|
+
</lion-option>
|
|
2106
|
+
<lion-option .choiceValue="${'Chicory'}">
|
|
2107
|
+
<div data-key>Chicory</div>
|
|
2108
|
+
<small>Chicory</small>
|
|
2109
|
+
</lion-option>
|
|
2110
|
+
<lion-option .choiceValue="${'Victoria Plum'}">
|
|
2111
|
+
<div data-key>Victoria Plum</div>
|
|
2112
|
+
<small>Prunus domestica</small>
|
|
2113
|
+
</lion-option>
|
|
2114
|
+
</${tag}>
|
|
2115
|
+
`)
|
|
2116
|
+
);
|
|
2117
|
+
const options = el.formElements;
|
|
2118
|
+
|
|
2119
|
+
mimicUserTyping(/** @type {LionCombobox} */ (el), 'ch');
|
|
2120
|
+
|
|
2121
|
+
await el.updateComplete;
|
|
2122
|
+
expect(options[0]).lightDom.to.equal(
|
|
2123
|
+
`<div data-key><span aria-label="Artichoke">Arti<b>ch</b>oke</span></div><small>Cardoon</small>`,
|
|
2124
|
+
);
|
|
2125
|
+
expect(options[1]).lightDom.to.equal(
|
|
2126
|
+
`<div data-key><span aria-label="Chard"><b>Ch</b>ard</div></span><small>Beet</small>`,
|
|
2127
|
+
);
|
|
2128
|
+
expect(options[2]).lightDom.to.equal(
|
|
2129
|
+
`<div data-key><span aria-label="Chicory"><b>Ch</b>icory</span></div><small>Chicory</small>`,
|
|
2130
|
+
);
|
|
2131
|
+
expect(options[3]).lightDom.to.equal(
|
|
2132
|
+
`<div data-key>Victoria Plum</div><small>Prunus domestica</small>`,
|
|
2133
|
+
);
|
|
2134
|
+
|
|
2135
|
+
mimicUserTyping(/** @type {LionCombobox} */ (el), 'D');
|
|
2136
|
+
|
|
2137
|
+
await el.updateComplete;
|
|
2138
|
+
expect(options[0]).lightDom.to.equal(`<div data-key>Artichoke</div><small>Cardoon</small>`);
|
|
2139
|
+
expect(options[1]).lightDom.to.equal(
|
|
2140
|
+
`<div data-key><span aria-label="Chard">Char<b>d</b></div></span><small>Beet</small>`,
|
|
2141
|
+
);
|
|
2142
|
+
expect(options[2]).lightDom.to.equal(`<div data-key>Chicory</div><small>Chicory</small>`);
|
|
2143
|
+
expect(options[3]).lightDom.to.equal(
|
|
2144
|
+
`<div data-key>Victoria Plum</div><small>Prunus domestica</small>`,
|
|
2145
|
+
);
|
|
2146
|
+
});
|
|
2002
2147
|
});
|
|
2003
2148
|
|
|
2004
2149
|
describe('Active index behavior', () => {
|
|
@@ -2278,6 +2423,26 @@ describe('lion-combobox', () => {
|
|
|
2278
2423
|
expect(labelledElement).to.not.be.null;
|
|
2279
2424
|
expect(labelledElement.innerText).to.equal('Artichoke');
|
|
2280
2425
|
});
|
|
2426
|
+
|
|
2427
|
+
it('adds aria-label to highlighted complex options', async () => {
|
|
2428
|
+
const el = /** @type {LionCombobox} */ (
|
|
2429
|
+
await fixture(html`
|
|
2430
|
+
<lion-combobox name="foo" match-mode="all">
|
|
2431
|
+
<lion-option .choiceValue="${'Artichoke'}">
|
|
2432
|
+
<div>Artichoke</div>
|
|
2433
|
+
<small>Cardoon</small>
|
|
2434
|
+
</lion-option>
|
|
2435
|
+
</lion-combobox>
|
|
2436
|
+
`)
|
|
2437
|
+
);
|
|
2438
|
+
const options = el.formElements;
|
|
2439
|
+
|
|
2440
|
+
mimicUserTyping(/** @type {LionCombobox} */ (el), 'choke');
|
|
2441
|
+
await el.updateComplete;
|
|
2442
|
+
const labelledElement = options[0].querySelector('span[aria-label=" Artichoke Cardoon "]');
|
|
2443
|
+
expect(labelledElement).to.not.be.null;
|
|
2444
|
+
expect(labelledElement.innerText).to.equal('Artichoke\nCardoon');
|
|
2445
|
+
});
|
|
2281
2446
|
});
|
|
2282
2447
|
});
|
|
2283
2448
|
|