UNPKG

sober

Version:

Sober is a library of UI components designed with reference to Material You.

169 lines (168 loc) 4.91 kB
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);