Files
dees-catalog/ts_web/elements/dees-input-quantityselector.ts

187 lines
5.5 KiB
TypeScript
Raw Normal View History

import { customElement, property, html, type TemplateResult, css, cssManager } from '@design.estate/dees-element';
2023-08-07 19:13:29 +02:00
import * as domtools from '@design.estate/dees-domtools';
import { DeesInputBase } from './dees-input-base.js';
import { demoFunc } from './dees-input-quantityselector.demo.js';
2020-09-13 16:24:48 +00:00
2021-03-06 15:48:02 +00:00
declare global {
interface HTMLElementTagNameMap {
'dees-input-quantityselector': DeesInputQuantitySelector;
}
}
2020-09-13 16:24:48 +00:00
@customElement('dees-input-quantityselector')
export class DeesInputQuantitySelector extends DeesInputBase<DeesInputQuantitySelector> {
public static demo = demoFunc;
2020-09-13 16:24:48 +00:00
2021-08-20 00:25:14 +02:00
// INSTANCE
2020-09-13 16:24:48 +00:00
@property({
type: Number
})
public value: number = 1;
2021-08-26 21:30:35 +02:00
2021-08-25 13:51:55 +02:00
public static styles = [
...DeesInputBase.baseStyles,
cssManager.defaultStyles,
css`
2020-09-13 16:24:48 +00:00
:host {
width: auto;
2020-09-13 16:24:48 +00:00
user-select: none;
}
.quantity-container {
2025-06-27 16:29:19 +00:00
transition: all 0.15s ease;
2020-09-13 16:24:48 +00:00
font-size: 14px;
2025-06-27 16:29:19 +00:00
display: inline-flex;
align-items: center;
background: transparent;
height: 40px;
padding: 0;
min-width: 120px;
color: ${cssManager.bdTheme('hsl(0 0% 9%)', 'hsl(0 0% 95%)')};
border: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
border-radius: 6px;
overflow: hidden;
2020-12-09 23:05:13 +00:00
}
.quantity-container.disabled {
2025-06-27 16:29:19 +00:00
background: ${cssManager.bdTheme('hsl(0 0% 95.1%)', 'hsl(0 0% 14.9%)')};
border-color: ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
opacity: 0.5;
pointer-events: none;
}
2020-12-09 23:05:13 +00:00
2025-06-27 16:29:19 +00:00
.quantity-container:hover:not(.disabled) {
border-color: ${cssManager.bdTheme('hsl(0 0% 79.8%)', 'hsl(0 0% 20.9%)')};
2020-09-13 16:24:48 +00:00
}
2025-06-27 16:29:19 +00:00
.quantity-container:focus-within {
border-color: ${cssManager.bdTheme('hsl(222.2 47.4% 51.2%)', 'hsl(217.2 91.2% 59.8%)')};
box-shadow: 0 0 0 3px ${cssManager.bdTheme('hsl(222.2 47.4% 51.2% / 0.1)', 'hsl(217.2 91.2% 59.8% / 0.1)')};
2020-09-13 16:24:48 +00:00
}
.selector {
2025-06-27 16:29:19 +00:00
flex: 0 0 40px;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
font-weight: 500;
cursor: pointer;
transition: all 0.15s ease;
color: ${cssManager.bdTheme('hsl(215.4 16.3% 56.9%)', 'hsl(215 20.2% 55.1%)')};
position: relative;
2020-09-13 16:24:48 +00:00
}
.selector:hover {
2025-06-27 16:29:19 +00:00
background: ${cssManager.bdTheme('hsl(0 0% 95.1%)', 'hsl(0 0% 14.9%)')};
color: ${cssManager.bdTheme('hsl(0 0% 9%)', 'hsl(0 0% 95%)')};
}
.selector:active {
background: ${cssManager.bdTheme('hsl(0 0% 91%)', 'hsl(0 0% 11%)')};
}
.selector.minus {
border-right: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
}
.selector.plus {
border-left: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
2020-09-13 16:24:48 +00:00
}
.quantity {
2025-06-27 16:29:19 +00:00
flex: 1;
2020-09-13 16:24:48 +00:00
text-align: center;
2025-06-27 16:29:19 +00:00
font-weight: 500;
font-variant-numeric: tabular-nums;
letter-spacing: -0.006em;
}
/* Keyboard navigation focus styles */
.selector:focus {
outline: none;
background: ${cssManager.bdTheme('hsl(210 40% 96.1%)', 'hsl(215 20.2% 16.8%)')};
z-index: 1;
}
/* Min value state */
.quantity-container[data-min="true"] .selector.minus {
opacity: 0.3;
cursor: not-allowed;
}
.quantity-container[data-min="true"] .selector.minus:hover {
background: transparent;
color: ${cssManager.bdTheme('hsl(215.4 16.3% 56.9%)', 'hsl(215 20.2% 55.1%)')};
2020-09-13 16:24:48 +00:00
}
`,
];
2020-09-13 16:24:48 +00:00
public render(): TemplateResult {
return html`
<div class="input-wrapper">
2025-06-27 16:29:19 +00:00
${this.label ? html`<dees-label .label=${this.label} .description=${this.description} .required=${this.required}></dees-label>` : ''}
<div
class="quantity-container ${this.disabled ? 'disabled' : ''}"
data-min="${this.value <= 0}"
>
<div
class="selector minus"
@click="${() => {this.decrease();}}"
tabindex="${this.disabled ? '-1' : '0'}"
@keydown="${(e: KeyboardEvent) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
this.decrease();
}
}}"
role="button"
aria-label="Decrease quantity"
></div>
<div class="quantity" aria-live="polite" aria-atomic="true">${this.value}</div>
<div
class="selector plus"
@click="${() => {this.increase();}}"
tabindex="${this.disabled ? '-1' : '0'}"
@keydown="${(e: KeyboardEvent) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
this.increase();
}
}}"
role="button"
aria-label="Increase quantity"
>+</div>
</div>
2020-09-13 16:24:48 +00:00
</div>
`;
}
public increase() {
if (!this.disabled) {
this.value++;
this.changeSubject.next(this);
}
2020-09-13 16:24:48 +00:00
}
public decrease() {
if (!this.disabled && this.value > 0) {
2020-09-13 16:24:48 +00:00
this.value--;
this.changeSubject.next(this);
2020-09-13 16:24:48 +00:00
}
}
public getValue(): number {
return this.value;
}
public setValue(value: number): void {
this.value = value;
2020-09-13 16:24:48 +00:00
}
}