sober
Version:
Sober is a library of UI components designed with reference to Material You.
169 lines (168 loc) • 4.91 kB
JavaScript
import { useElement, useProps } from './core/element.js';
const name = 's-search';
const props = useProps({
$placeholder: '',
disabled: false,
$value: '',
$maxLength: -1,
readOnly: false
});
const style = /*css*/ `
:host{
display: inline-flex;
vertical-align: middle;
min-height: 40px;
width: 220px;
border-radius: 20px;
font-size: .875rem;
position: relative;
background: var(--s-color-surface-container-low, ${"#F2F4F5" /* Theme.colorSurfaceContainerLow */});
color: var(--s-color-on-surface, ${"#191C1E" /* Theme.colorOnSurface */});
--search-outline-width: 1px;
--search-outline-color: var(--s-color-surface-variant, ${"#DCE4E8" /* Theme.colorSurfaceVariant */});
}
.wrapper{
display: grid;
position: relative;
border-radius: inherit;
overflow: hidden;
background: inherit;
min-height: inherit;
flex-grow: 1;
width: 100%;
box-shadow: 0 0 0 var(--search-outline-width) var(--search-outline-color);
}
:host(:focus-within) .wrapper{
position: absolute;
}
.container{
display: flex;
align-items: center;
position: relative;
min-height: inherit;
}
input{
border: none;
padding: 0 16px;
height: 100%;
width: 0;
flex-grow: 1;
background: none;
outline: none;
font-size: inherit;
color: inherit;
box-sizing: border-box;
line-height: 1;
font-family: inherit;
caret-color: var(--s-color-primary, ${"#006782" /* Theme.colorPrimary */});
}
input::placeholder{
color: var(--s-color-outline, ${"#70787D" /* Theme.colorOutline */});
}
input::selection{
background: var(--s-color-primary, ${"#006782" /* Theme.colorPrimary */});
color: var(--s-color-on-primary, ${"#ffffff" /* Theme.colorOnPrimary */});
}
::slotted([slot=dropdown]){
position: absolute;
pointer-events: none;
left: 0;
height: 0;
opacity: 0;
border-top: solid 1px var(--s-color-surface-variant, ${"#DCE4E8" /* Theme.colorSurfaceVariant */});
height: auto;
}
:host(:focus-within) ::slotted([slot=dropdown]){
pointer-events: auto;
position: relative;
opacity: 1;
}
::slotted([slot]){
flex-shrink: 0;
}
.clear{
display: none;
align-items: center;
justify-content: center;
height: 40px;
width: 40px;
border-radius: 50%;
}
svg,
::slotted(svg){
height: 24px;
width: 24px;
fill: var(--s-color-on-surface-variant, ${"#40484C" /* Theme.colorOnSurfaceVariant */});
}
.icon,
::slotted(:is(s-icon[slot=start], svg[slot=start])){
margin: 0 -8px 0 8px;
}
::slotted(:is(s-icon[slot=end], svg[slot=end])){
margin: 0 8px 0 -8px;
}
::slotted(s-icon-button[slot=start]){
margin-right: -16px;
}
.clear,
::slotted(s-icon-button[slot=end]){
margin-left: -16px;
}
`;
const template = /*html*/ `
<div class="wrapper" part="wrapper">
<div class="container" part="container">
<slot name="start">
<svg viewBox="0 -960 960 960" class="icon">
<path d="M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z"></path>
</svg>
</slot>
<input type="text">
<slot name="end">
<s-ripple class="clear">
<svg viewBox="0 -960 960 960">
<path d="m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z"></path>
</svg>
</s-ripple>
</slot>
</div>
<slot name="dropdown"></slot>
</div>
`;
export class Search extends useElement({
style, template, props,
setup(shadowRoot) {
const input = shadowRoot.querySelector('input');
const clear = shadowRoot.querySelector('.clear');
const dropdown = shadowRoot.querySelector('[name=dropdown]');
const onInput = () => clear.style.display = input.value === '' ? 'none' : 'flex';
dropdown.onmousedown = (e) => e.preventDefault();
input.onchange = () => this.dispatchEvent(new Event('change'));
clear.onclick = () => {
input.value = '';
onInput();
this.dispatchEvent(new Event('input'));
this.dispatchEvent(new Event('change'));
};
input.oninput = onInput;
return {
expose: {
get native() {
return input;
}
},
value: {
get: () => input.value,
set: (value) => {
input.value = value;
onInput();
}
},
placeholder: (placeholder) => input.placeholder = placeholder,
maxLength: (maxLength) => input.maxLength = maxLength,
readOnly: (readOnly) => input.readOnly = readOnly
};
}
}) {
}
Search.define(name);