chore(combobox): demo google search and whatsapp
This commit is contained in:
parent
143cdb5ac6
commit
dd1ac63284
10 changed files with 636 additions and 71 deletions
|
|
@ -5,13 +5,22 @@ import { html } from 'lit-html';
|
|||
import './md-combobox/md-combobox.js';
|
||||
import './gh-combobox/gh-combobox.js';
|
||||
import './wa-combobox/wa-combobox.js';
|
||||
import './lm-option/lm-option.js';
|
||||
import './google-combobox/google-combobox.js';
|
||||
|
||||
export default {
|
||||
title: 'Forms/Combobox/Extensions',
|
||||
};
|
||||
```
|
||||
|
||||
Below several extensions can be found. They illustrate that complex UI components can be created
|
||||
easily from an extended Lion component, just by:
|
||||
|
||||
- **configuring**: setting properties or providing conditions via methods
|
||||
- **enhancing**: adding extra html/styles/logic without changing behavior of the extended element
|
||||
- **overriding**: replace html/styles/logic of the extended element with your own
|
||||
|
||||
## Material Design
|
||||
|
||||
```js preview-story
|
||||
export const MaterialDesign = () => html`
|
||||
<md-combobox name="combo" label="Default">
|
||||
|
|
@ -24,6 +33,8 @@ export const MaterialDesign = () => html`
|
|||
`;
|
||||
```
|
||||
|
||||
## Github
|
||||
|
||||
```js preview-story
|
||||
export const Github = () => html`
|
||||
<gh-combobox name="combo" label="Switch branches/tags">
|
||||
|
|
@ -36,6 +47,8 @@ export const Github = () => html`
|
|||
`;
|
||||
```
|
||||
|
||||
## Whatsapp
|
||||
|
||||
```js preview-story
|
||||
export const Whatsapp = () => html`
|
||||
<wa-combobox name="combo" label="Filter chats">
|
||||
|
|
@ -81,44 +94,66 @@ export const Whatsapp = () => html`
|
|||
`;
|
||||
```
|
||||
|
||||
**Whatsapp example shows:**
|
||||
|
||||
- advanced styling
|
||||
- how to match/highlight text on multiple rows of the option (not just choiceValue)
|
||||
- how to animate options
|
||||
|
||||
## Google Search
|
||||
|
||||
```js preview-story
|
||||
export const LinkMixinBox = () => html`
|
||||
<lion-combobox name="combo" label="Default">
|
||||
<lm-option
|
||||
href="https://www.google.com/search?query=apple"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
.choiceValue=${'Apple'}
|
||||
>Apple</lm-option
|
||||
>
|
||||
<lm-option
|
||||
href="https://www.google.com/search?query=Artichoke"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
.choiceValue=${'Artichoke'}
|
||||
>Artichoke</lm-option
|
||||
>
|
||||
<lm-option
|
||||
href="https://www.google.com/search?query=Asparagus"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
.choiceValue=${'Asparagus'}
|
||||
>Asparagus</lm-option
|
||||
>
|
||||
<lm-option
|
||||
href="https://www.google.com/search?query=Banana"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
.choiceValue=${'Banana'}
|
||||
>Banana</lm-option
|
||||
>
|
||||
<lm-option
|
||||
href="https://www.google.com/search?query=Beets"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
.choiceValue=${'Beets'}
|
||||
>Beets</lm-option
|
||||
>
|
||||
</lion-combobox>
|
||||
`;
|
||||
export const GoogleSearch = () => {
|
||||
const appleLogoUrl = new URL('./google-combobox/assets/appleLogo.png', import.meta.url).href;
|
||||
return html`
|
||||
<google-combobox name="combo" label="Google Search">
|
||||
<google-option
|
||||
href="https://www.google.com/search?query=apple"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
.choiceValue=${'Apple'}
|
||||
.imageUrl=${appleLogoUrl}
|
||||
>Apple</google-option
|
||||
>
|
||||
<google-option
|
||||
href="https://www.google.com/search?query=Artichoke"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
.choiceValue=${'Artichoke'}
|
||||
>Artichoke</google-option
|
||||
>
|
||||
<google-option
|
||||
href="https://www.google.com/search?query=Asparagus"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
.choiceValue=${'Asparagus'}
|
||||
>Asparagus</google-option
|
||||
>
|
||||
<google-option
|
||||
href="https://www.google.com/search?query=Banana"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
.choiceValue=${'Banana'}
|
||||
>Banana</google-option
|
||||
>
|
||||
<google-option
|
||||
href="https://www.google.com/search?query=Beets"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
.choiceValue=${'Beets'}
|
||||
>Beets</google-option
|
||||
>
|
||||
</google-combobox>
|
||||
<div style="height:200px;"></div>
|
||||
`;
|
||||
};
|
||||
```
|
||||
|
||||
**Google Search example shows:**
|
||||
|
||||
- advanced styling
|
||||
- how to use options that are links
|
||||
- create exact user experience of Google Search, by:
|
||||
- using autocomplete 'list' as a fundament (we don't want inline completion in textbox)
|
||||
- enhancing `_showOverlayCondition`: open on focus
|
||||
- enhancing `_syncToTextboxCondition`: always sync to textbox when navigating by keyboard (this needs to be enabled, since it's not provided in the "autocomplete=list" preset)
|
||||
|
|
|
|||
BIN
packages/combobox/docs/google-combobox/assets/appleLogo.png
Normal file
BIN
packages/combobox/docs/google-combobox/assets/appleLogo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
|
|
@ -0,0 +1,9 @@
|
|||
import { html } from '@lion/core';
|
||||
|
||||
export default html`
|
||||
<svg focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path
|
||||
d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"
|
||||
></path>
|
||||
</svg>
|
||||
`;
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
import { html } from '@lion/core';
|
||||
|
||||
export default html`
|
||||
<svg focusable="false" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path
|
||||
d="M15.5 14h-.79l-.28-.27A6.471 6.471 0 0 0 16 9.5 6.5 6.5 0 1 0 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"
|
||||
></path>
|
||||
</svg>
|
||||
`;
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
import { html } from '@lion/core';
|
||||
|
||||
export default html`
|
||||
<svg class="HPVvwb" focusable="false" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path
|
||||
d="m12 15c1.66 0 3-1.31 3-2.97v-7.02c0-1.66-1.34-3.01-3-3.01s-3 1.34-3 3.01v7.02c0 1.66 1.34 2.97 3 2.97z"
|
||||
fill="#4285f4"
|
||||
></path>
|
||||
<path d="m11 18.08h2v3.92h-2z" fill="#34a853"></path>
|
||||
<path
|
||||
d="m7.05 16.87c-1.27-1.33-2.05-2.83-2.05-4.87h2c0 1.45 0.56 2.42 1.47 3.38v0.32l-1.15 1.18z"
|
||||
fill="#f4b400"
|
||||
></path>
|
||||
<path
|
||||
d="m12 16.93a4.97 5.25 0 0 1 -3.54 -1.55l-1.41 1.49c1.26 1.34 3.02 2.13 4.95 2.13 3.87 0 6.99-2.92 6.99-7h-1.99c0 2.92-2.24 4.93-5 4.93z"
|
||||
fill="#ea4335"
|
||||
></path>
|
||||
</svg>
|
||||
`;
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 5.8 KiB |
460
packages/combobox/docs/google-combobox/google-combobox.js
Normal file
460
packages/combobox/docs/google-combobox/google-combobox.js
Normal file
|
|
@ -0,0 +1,460 @@
|
|||
import { css, html } from '@lion/core';
|
||||
import { LionOption } from '@lion/listbox';
|
||||
import { renderLitAsNode } from '@lion/helpers';
|
||||
import { LionCombobox } from '../../src/LionCombobox.js';
|
||||
import { LinkMixin } from '../LinkMixin.js';
|
||||
import googleSearchIcon from './assets/google-search-icon.js';
|
||||
import googleVoiceSearchIcon from './assets/google-voice-search-icon.js';
|
||||
import googleClearIcon from './assets/google-clear-icon.js';
|
||||
|
||||
const googleSearchLogoUrl = new URL('./assets/googlelogo_color_272x92dp.png', import.meta.url).href;
|
||||
|
||||
export class GoogleOption extends LinkMixin(LionOption) {
|
||||
static get properties() {
|
||||
return {
|
||||
imageUrl: {
|
||||
type: String,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
static get styles() {
|
||||
return [
|
||||
super.styles,
|
||||
css`
|
||||
:host {
|
||||
position: relative;
|
||||
padding: 8px 16px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
background: none;
|
||||
}
|
||||
|
||||
:host:hover,
|
||||
:host([active]) {
|
||||
background: #eee !important;
|
||||
}
|
||||
|
||||
:host([checked]) {
|
||||
background: none;
|
||||
}
|
||||
|
||||
/* :host([active]) {
|
||||
color: #1867c0 !important;
|
||||
caret-color: #1867c0 !important;
|
||||
} */
|
||||
|
||||
:host {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
:host ::slotted(.google-option__highlight) {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.google-option__icon {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
margin-right: 12px;
|
||||
fill: var(--icon-color);
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @configure
|
||||
* @param {string} currentValue
|
||||
*/
|
||||
onFilterMatch(currentValue) {
|
||||
const { innerHTML } = this;
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
this.__originalInnerHTML = innerHTML;
|
||||
const newInnerHTML = innerHTML.replace(
|
||||
new RegExp(`(${currentValue})`, 'i'),
|
||||
`<span class="google-option__highlight">$1</span>`,
|
||||
);
|
||||
// For Safari, we need to add a label to the element
|
||||
this.setAttribute('aria-label', this.textContent);
|
||||
this.innerHTML = newInnerHTML;
|
||||
// Alternatively, an extension can add an animation here
|
||||
this.style.display = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* @configure LionCombobox
|
||||
*/
|
||||
onFilterUnmatch() {
|
||||
this.removeAttribute('aria-label');
|
||||
if (this.__originalInnerHTML) {
|
||||
this.innerHTML = this.__originalInnerHTML;
|
||||
}
|
||||
this.style.display = 'none';
|
||||
}
|
||||
|
||||
render() {
|
||||
return html`
|
||||
${!this.imageUrl
|
||||
? html` <div class="google-option__icon">${googleSearchIcon}</div>`
|
||||
: html` <img class="google-option__icon" src="${this.imageUrl}" />`}
|
||||
${super.render()}
|
||||
`;
|
||||
}
|
||||
}
|
||||
customElements.define('google-option', GoogleOption);
|
||||
|
||||
export class GoogleCombobox extends LionCombobox {
|
||||
static get styles() {
|
||||
return [
|
||||
super.styles,
|
||||
css`
|
||||
/** @configure FormControlMixin */
|
||||
|
||||
/* =======================
|
||||
block | .form-field
|
||||
======================= */
|
||||
|
||||
:host {
|
||||
font-family: arial, sans-serif;
|
||||
}
|
||||
|
||||
.form-field__label {
|
||||
margin-top: 36px;
|
||||
margin-bottom: 24px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* ==============================
|
||||
element | .input-group
|
||||
============================== */
|
||||
|
||||
.input-group {
|
||||
margin-bottom: 16px;
|
||||
max-width: 582px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
.input-group__container {
|
||||
position: relative;
|
||||
background: #fff;
|
||||
display: flex;
|
||||
border: 1px solid #dfe1e5;
|
||||
box-shadow: none;
|
||||
border-radius: 24px;
|
||||
height: 44px;
|
||||
}
|
||||
|
||||
.input-group__container:hover,
|
||||
:host([opened]) .input-group__container {
|
||||
border-color: rgba(223, 225, 229, 0);
|
||||
box-shadow: 0 1px 6px rgba(32, 33, 36, 0.28);
|
||||
}
|
||||
|
||||
:host([opened]) .input-group__container {
|
||||
border-bottom-right-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
}
|
||||
|
||||
:host([opened]) .input-group__container::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
background: white;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 10px;
|
||||
bottom: -10px;
|
||||
}
|
||||
|
||||
:host([opened]) .input-group__container::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
background: #eee;
|
||||
left: 16px;
|
||||
right: 16px;
|
||||
height: 1px;
|
||||
bottom: 0;
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
.input-group__prefix,
|
||||
.input-group__suffix {
|
||||
display: block;
|
||||
fill: var(--icon-color);
|
||||
display: flex;
|
||||
place-items: center;
|
||||
}
|
||||
|
||||
.input-group__input {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.input-group__input ::slotted([slot='input']) {
|
||||
border: transparent;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/** @configure LionCombobox */
|
||||
|
||||
/* =======================
|
||||
block | .form-field
|
||||
======================= */
|
||||
|
||||
#overlay-content-node-wrapper {
|
||||
box-shadow: 0 4px 6px rgba(32, 33, 36, 0.28);
|
||||
border-radius: 0 0 24px 24px;
|
||||
margin-top: -2px;
|
||||
padding-top: 6px;
|
||||
background: white;
|
||||
}
|
||||
|
||||
* > ::slotted([slot='listbox']) {
|
||||
margin-bottom: 8px;
|
||||
background: none;
|
||||
}
|
||||
|
||||
:host {
|
||||
--icon-color: #9aa0a6;
|
||||
}
|
||||
|
||||
/** @enhance LionCombobox */
|
||||
|
||||
/* ===================================
|
||||
block | .google-search-clear-btn
|
||||
=================================== */
|
||||
|
||||
.google-search-clear-btn {
|
||||
position: relative;
|
||||
height: 100%;
|
||||
align-items: center;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.google-search-clear-btn::after {
|
||||
border-left: 1px solid #dfe1e5;
|
||||
height: 65%;
|
||||
right: 0;
|
||||
content: '';
|
||||
margin-right: 10px;
|
||||
margin-left: 8px;
|
||||
}
|
||||
|
||||
:host([filled]) .google-search-clear-btn {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
* > ::slotted([slot='suffix']),
|
||||
* > ::slotted([slot='clear-btn']) {
|
||||
font: inherit;
|
||||
margin: 0;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
padding: 0;
|
||||
color: inherit;
|
||||
background-color: transparent;
|
||||
text-align: left;
|
||||
white-space: normal;
|
||||
overflow: visible;
|
||||
|
||||
user-select: none;
|
||||
-moz-user-select: none;
|
||||
-webkit-user-select: none;
|
||||
-ms-user-select: none;
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
|
||||
width: 25px;
|
||||
height: 25px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
* > ::slotted([slot='suffix']) {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
* > ::slotted([slot='prefix']) {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
margin-left: 12px;
|
||||
margin-right: 16px;
|
||||
}
|
||||
|
||||
/* =============================
|
||||
block | .google-search-btns
|
||||
============================ */
|
||||
|
||||
.google-search-btns {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.google-search-btns__input-button {
|
||||
background-image: -webkit-linear-gradient(top, #f8f9fa, #f8f9fa);
|
||||
background-color: #f8f9fa;
|
||||
border: 1px solid #f8f9fa;
|
||||
border-radius: 4px;
|
||||
color: #3c4043;
|
||||
font-family: arial, sans-serif;
|
||||
font-size: 14px;
|
||||
margin: 11px 4px;
|
||||
padding: 0 16px;
|
||||
line-height: 27px;
|
||||
height: 36px;
|
||||
min-width: 54px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.google-search-btns__input-button:hover {
|
||||
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
|
||||
background-image: -webkit-linear-gradient(top, #f8f8f8, #f1f1f1);
|
||||
background-color: #f8f8f8;
|
||||
border: 1px solid #c6c6c6;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
.google-search-btns__input-button:focus {
|
||||
border: 1px solid #4d90fe;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
/* ===============================
|
||||
block | .google-search-report
|
||||
============================== */
|
||||
|
||||
.google-search-report {
|
||||
display: flex;
|
||||
align-content: right;
|
||||
color: #70757a;
|
||||
font-style: italic;
|
||||
font-size: 8pt;
|
||||
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
|
||||
margin-bottom: 8px;
|
||||
justify-content: flex-end;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.google-search-report a {
|
||||
color: inherit;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @enhance LionCombobox - add google search buttons
|
||||
*/
|
||||
_overlayListboxTemplate() {
|
||||
return html`
|
||||
<div id="overlay-content-node-wrapper" role="dialog">
|
||||
<slot name="listbox"></slot>
|
||||
${this._googleSearchBtnsTemplate()}
|
||||
<div class="google-search-report"><a href="#">Report inappropriate predictions</a></div>
|
||||
</div>
|
||||
<slot id="options-outlet"></slot>
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @enhance FormControlMixin add clear-btn
|
||||
*/
|
||||
_inputGroupSuffixTemplate() {
|
||||
return html`
|
||||
<div class="input-group__suffix">
|
||||
<div class="google-search-clear-btn">
|
||||
<slot name="clear-btn"></slot>
|
||||
</div>
|
||||
<slot name="suffix"></slot>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
_googleSearchBtnsTemplate() {
|
||||
return html` <div class="google-search-btns">
|
||||
<input
|
||||
type="submit"
|
||||
class="google-search-btns__input-button"
|
||||
value="Google Search"
|
||||
aria-label="Google Search"
|
||||
/>
|
||||
<input
|
||||
type="submit"
|
||||
class="google-search-btns__input-button"
|
||||
value="I'm Feeling Lucky"
|
||||
aria-label="I'm Feeling Lucky"
|
||||
/>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @enhance FormControlMixin - add google search buttons
|
||||
*/
|
||||
_groupTwoTemplate() {
|
||||
return html`${super._groupTwoTemplate()} ${!this.opened ? this._googleSearchBtnsTemplate() : ''} `;
|
||||
}
|
||||
|
||||
get slots() {
|
||||
return {
|
||||
...super.slots,
|
||||
label: () => renderLitAsNode(html` <img alt="Google Search" src="${googleSearchLogoUrl}" />`),
|
||||
prefix: () => renderLitAsNode(html` <span>${googleSearchIcon}</span> `),
|
||||
suffix: () =>
|
||||
renderLitAsNode(
|
||||
html` <button aria-label="Search by voice">${googleVoiceSearchIcon}</button> `,
|
||||
),
|
||||
'clear-btn': () =>
|
||||
renderLitAsNode(
|
||||
html`
|
||||
<button @click="${this.__clearText}" aria-label="Clear text">${googleClearIcon}</button>
|
||||
`,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @configure OverlayMixin
|
||||
*/
|
||||
get _overlayReferenceNode() {
|
||||
return /** @type {ShadowRoot} */ (this.shadowRoot).querySelector('.input-group');
|
||||
}
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
/** @configure LionCombobox */
|
||||
this.autocomplete = 'list';
|
||||
/** @configure LionCombobox */
|
||||
this.showAllOnEmpty = true;
|
||||
|
||||
this.__resetFocus = this.__resetFocus.bind(this);
|
||||
this.__clearText = this.__clearText.bind(this);
|
||||
}
|
||||
|
||||
firstUpdated(changedProperties) {
|
||||
super.firstUpdated(changedProperties);
|
||||
|
||||
this._overlayContentNode.addEventListener('mouseenter', this.__resetFocus);
|
||||
}
|
||||
|
||||
/**
|
||||
* @override LionCombobox - always sync textbox when selected value changes
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
_syncToTextboxCondition() {
|
||||
return true;
|
||||
}
|
||||
|
||||
_showOverlayCondition(options) {
|
||||
return this.focused || super.showOverlayCondition(options);
|
||||
}
|
||||
|
||||
__resetFocus() {
|
||||
this.activeIndex = -1;
|
||||
this.checkedIndex = -1;
|
||||
}
|
||||
|
||||
__clearText() {
|
||||
this._inputNode.value = '';
|
||||
}
|
||||
}
|
||||
customElements.define('google-combobox', GoogleCombobox);
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
import { LionOption } from '@lion/listbox';
|
||||
import { LinkMixin } from '../LinkMixin.js';
|
||||
|
||||
export class LmOption extends LinkMixin(LionOption) {}
|
||||
|
||||
customElements.define('lm-option', LmOption);
|
||||
|
|
@ -167,9 +167,9 @@ class WaOption extends LionOption {
|
|||
:host([is-user-text-read]) .wa-option__content-row2-text-inner-icon {
|
||||
color: lightblue;
|
||||
}
|
||||
/*
|
||||
.wa-option__content-row2-menu {
|
||||
} */
|
||||
.wa-selected {
|
||||
color: #009688;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
|
@ -178,13 +178,7 @@ class WaOption extends LionOption {
|
|||
return html`<div class="wa-option">
|
||||
<div class="wa-option__image">
|
||||
<div class="wa-option__image-inner">
|
||||
<img
|
||||
src="${this.image}"
|
||||
alt=""
|
||||
draggable="false"
|
||||
class="_2goTk _1Jdop _3Whw5"
|
||||
style="visibility: visible;"
|
||||
/>
|
||||
<img src="${this.image}" alt="" draggable="false" style="visibility: visible;" />
|
||||
${this.image
|
||||
? ''
|
||||
: html`<div class="wa-option__image-inner-inner">
|
||||
|
|
@ -213,11 +207,9 @@ class WaOption extends LionOption {
|
|||
<div class="wa-option__content">
|
||||
<div class="wa-option__content-row1">
|
||||
<div class="wa-option__content-row1-title">
|
||||
<span class="_357i8">
|
||||
<span dir="auto" title="${this.title}" class="_3ko75 _5h6Y_ _3Whw5">
|
||||
${this.title}
|
||||
</span>
|
||||
<div class="_3XFan"></div>
|
||||
<span>
|
||||
<span dir="auto" title="${this.title}"> ${this.title} </span>
|
||||
<div></div>
|
||||
</span>
|
||||
</div>
|
||||
<div class="wa-option__content-row1-time">${this.time}</div>
|
||||
|
|
@ -226,7 +218,7 @@ class WaOption extends LionOption {
|
|||
<div class="wa-option__content-row2-text">
|
||||
<span class="wa-option__content-row2-text-inner" title="${this.text}">
|
||||
<div class="wa-option__content-row2-text-inner-icon">
|
||||
<span data-testid="status-dblcheck" data-icon="status-dblcheck" class="">
|
||||
<span>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 18 18"
|
||||
|
|
@ -240,7 +232,7 @@ class WaOption extends LionOption {
|
|||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
<span dir="ltr" class="_3ko75 _5h6Y_ _3Whw5">${this.text}</span></span
|
||||
<span dir="ltr">${this.text}</span></span
|
||||
>
|
||||
</div>
|
||||
<div class="wa-option__content-row2-menu"><span></span><span></span><span></span></div>
|
||||
|
|
@ -255,11 +247,23 @@ class WaOption extends LionOption {
|
|||
*/
|
||||
onFilterMatch(matchingString) {
|
||||
this.__originalTitle = this.title;
|
||||
const newInnerHTML = this.title.replace(new RegExp(`(${matchingString})`, 'i'), `<b>$1</b>`);
|
||||
this.__originalText = this.text;
|
||||
const newTitle = this.__originalTitle.replace(
|
||||
new RegExp(`(${matchingString})`, 'i'),
|
||||
`<b class="wa-selected">$1</b>`,
|
||||
);
|
||||
const newText = this.__originalText.replace(
|
||||
new RegExp(`(${matchingString})`, 'i'),
|
||||
`<b class="wa-selected">$1</b>`,
|
||||
);
|
||||
|
||||
const helperNode = document.createElement('div');
|
||||
// For Safari, we need to add a label to the element
|
||||
helperNode.innerHTML = `<span aria-label="${this.title}">${newInnerHTML}</span>`;
|
||||
helperNode.innerHTML = `<span aria-label="${this.title}">${newTitle}</span>`;
|
||||
[this.title] = helperNode.children;
|
||||
helperNode.innerHTML = `<span aria-label="${this.text}">${newText}</span>`;
|
||||
[this.text] = helperNode.children;
|
||||
// Show animation
|
||||
this.style.cssText = `
|
||||
max-height: 500px;
|
||||
opacity: 1;
|
||||
|
|
@ -276,6 +280,9 @@ class WaOption extends LionOption {
|
|||
if (this.__originalTitle) {
|
||||
this.title = this.__originalTitle;
|
||||
}
|
||||
if (this.__originalText) {
|
||||
this.text = this.__originalText;
|
||||
}
|
||||
this.style.cssText = `
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
|
|
@ -363,6 +370,38 @@ class WaCombobox extends LionCombobox {
|
|||
this.showAllOnEmpty = true;
|
||||
/** @configure LionCombobox */
|
||||
this.rotateKeyboardNavigation = false;
|
||||
/** @configure LionCombobox */
|
||||
this.autocomplete = 'list';
|
||||
}
|
||||
|
||||
/**
|
||||
* @override LionCombobox - also match option.text
|
||||
* @param {LionOption} option
|
||||
* @param {string} textboxValue current ._inputNode value
|
||||
*/
|
||||
matchCondition(option, textboxValue) {
|
||||
let idx = -1;
|
||||
if (typeof option.choiceValue === 'string' && typeof textboxValue === 'string') {
|
||||
idx = option.choiceValue.toLowerCase().indexOf(textboxValue.toLowerCase());
|
||||
// enhance LionCombobox: also match option.text
|
||||
const text = option.__originalText || option.text;
|
||||
if (idx === -1 && typeof text === 'string') {
|
||||
idx = text.toLowerCase().indexOf(textboxValue.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
if (this.matchMode === 'all') {
|
||||
return idx > -1; // matches part of word
|
||||
}
|
||||
return idx === 0; // matches beginning of value
|
||||
}
|
||||
|
||||
/**
|
||||
* @override LionCombobox - always sync textbox when selected value changes
|
||||
*/
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
_syncToTextboxCondition() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
customElements.define('wa-combobox', WaCombobox);
|
||||
|
|
|
|||
|
|
@ -841,10 +841,10 @@ describe('lion-combobox', () => {
|
|||
await performChecks('both', 0, 'Artichoke');
|
||||
|
||||
el.multipleChoice = true;
|
||||
// await performChecks('none', [0, 1], 'Chard');
|
||||
// await performChecks('list', [0, 1], 'Chard');
|
||||
// await performChecks('inline', [0, 1], 'Chard');
|
||||
// await performChecks('both', [0, 1], 'Chard');
|
||||
await performChecks('none', [0, 1], '');
|
||||
await performChecks('list', [0, 1], '');
|
||||
await performChecks('inline', [0, 1], '');
|
||||
await performChecks('both', [0, 1], '');
|
||||
});
|
||||
|
||||
it('does inline autocompletion when adding chars', async () => {
|
||||
|
|
@ -913,10 +913,10 @@ describe('lion-combobox', () => {
|
|||
mimicUserTyping(el, 'ch');
|
||||
await el.updateComplete;
|
||||
expect(el._inputNode.value).to.equal('Chard');
|
||||
expect(el._inputNode.selectionStart).to.equal('ch'.length);
|
||||
expect(el._inputNode.selectionStart).to.equal('Ch'.length);
|
||||
expect(el._inputNode.selectionEnd).to.equal('Chard'.length);
|
||||
|
||||
// Autocompletion happened. When we go backwards ('Char'), we should not
|
||||
// Autocompletion happened. When we go backwards ('Ch[ard]' => 'Ch'), we should not
|
||||
// autocomplete to 'Chard' anymore.
|
||||
await mimicUserTypingAdvanced(el, ['Backspace']);
|
||||
await el.updateComplete;
|
||||
|
|
|
|||
Loading…
Reference in a new issue