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

216 lines
5.7 KiB
TypeScript
Raw Normal View History

2021-08-25 13:51:55 +02:00
import {
customElement,
2023-08-07 20:02:18 +02:00
type TemplateResult,
2021-08-25 13:51:55 +02:00
property,
html,
2021-08-26 21:30:35 +02:00
css,
2023-08-07 20:02:18 +02:00
cssManager,
2023-08-07 19:13:29 +02:00
} from '@design.estate/dees-element';
import { DeesInputBase } from './dees-input-base.js';
import { demoFunc } from './dees-input-checkbox.demo.js';
2025-06-27 17:32:01 +00:00
import { cssGeistFontFamily } from './00fonts.js';
2020-09-13 16:24:48 +00:00
2021-03-06 15:48:02 +00:00
declare global {
interface HTMLElementTagNameMap {
'dees-input-checkbox': DeesInputCheckbox;
}
}
2020-09-13 16:24:48 +00:00
@customElement('dees-input-checkbox')
export class DeesInputCheckbox extends DeesInputBase<DeesInputCheckbox> {
2021-08-20 00:25:14 +02:00
// STATIC
public static demo = demoFunc;
2021-08-25 13:51:55 +02:00
2021-08-20 00:25:14 +02:00
// INSTANCE
2020-09-13 16:24:48 +00:00
2021-08-25 13:51:55 +02:00
@property({
type: Boolean,
})
2020-09-13 16:24:48 +00:00
public value: boolean = false;
2021-08-20 00:25:14 +02:00
constructor() {
super();
this.labelPosition = 'right'; // Checkboxes default to label on the right
}
2021-08-26 21:30:35 +02:00
public static styles = [
...DeesInputBase.baseStyles,
cssManager.defaultStyles,
css`
2020-09-13 16:24:48 +00:00
* {
box-sizing: border-box;
}
:host {
position: relative;
2023-12-26 21:21:18 +01:00
cursor: default;
2025-06-27 17:32:01 +00:00
font-family: ${cssGeistFontFamily};
2020-09-13 16:24:48 +00:00
}
.maincontainer {
2025-06-27 16:20:06 +00:00
display: inline-flex;
align-items: flex-start;
gap: 8px;
2025-06-26 15:08:14 +00:00
cursor: pointer;
user-select: none;
2025-06-27 16:20:06 +00:00
transition: all 0.15s ease;
2020-09-13 16:24:48 +00:00
}
2025-06-27 16:20:06 +00:00
.checkbox {
position: relative;
height: 18px;
width: 18px;
flex-shrink: 0;
border-radius: 4px;
border: 1px solid ${cssManager.bdTheme('hsl(0 0% 89.8%)', 'hsl(0 0% 14.9%)')};
background: ${cssManager.bdTheme('hsl(0 0% 100%)', 'hsl(0 0% 3.9%)')};
transition: all 0.15s ease;
margin-top: 1px;
2020-09-13 16:24:48 +00:00
}
2025-06-26 15:08:14 +00:00
.maincontainer:hover .checkbox {
2025-06-27 16:20:06 +00:00
border-color: ${cssManager.bdTheme('hsl(0 0% 79.8%)', 'hsl(0 0% 20.9%)')};
2020-09-13 16:24:48 +00:00
}
.checkbox.selected {
2025-06-27 16:20:06 +00:00
background: ${cssManager.bdTheme('hsl(222.2 47.4% 51.2%)', 'hsl(217.2 91.2% 59.8%)')};
border-color: ${cssManager.bdTheme('hsl(222.2 47.4% 51.2%)', 'hsl(217.2 91.2% 59.8%)')};
2020-09-13 16:24:48 +00:00
}
2025-06-27 16:20:06 +00:00
.checkbox:focus-visible {
outline: none;
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)')};
2021-08-26 21:30:35 +02:00
}
2025-06-27 16:20:06 +00:00
/* Checkmark using Lucide icon style */
2021-08-27 13:38:08 +02:00
.checkbox .checkmark {
2020-09-13 16:24:48 +00:00
position: absolute;
2025-06-27 16:20:06 +00:00
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
opacity: 0;
transition: opacity 0.15s ease;
2020-09-13 16:24:48 +00:00
}
2025-06-27 16:20:06 +00:00
.checkbox.selected .checkmark {
opacity: 1;
2020-09-13 16:24:48 +00:00
}
2025-06-27 16:20:06 +00:00
.checkbox .checkmark svg {
width: 12px;
height: 12px;
stroke: white;
stroke-width: 3;
2021-08-27 13:38:08 +02:00
}
2025-06-27 16:20:06 +00:00
/* Disabled state */
.maincontainer.disabled {
cursor: not-allowed;
opacity: 0.5;
2020-09-13 16:24:48 +00:00
}
2025-06-26 15:08:14 +00:00
2025-06-27 16:20:06 +00:00
.checkbox.disabled {
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%)')};
2025-06-26 15:08:14 +00:00
}
2025-06-27 16:20:06 +00:00
/* Label */
.label-container {
display: flex;
flex-direction: column;
gap: 2px;
flex: 1;
2025-06-26 15:08:14 +00:00
}
2025-06-27 16:20:06 +00:00
.checkbox-label {
font-size: 14px;
font-weight: 500;
line-height: 20px;
color: ${cssManager.bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 90%)')};
transition: color 0.15s ease;
letter-spacing: -0.01em;
2025-06-26 15:08:14 +00:00
}
2025-06-27 16:20:06 +00:00
.maincontainer:hover .checkbox-label {
color: ${cssManager.bdTheme('hsl(0 0% 9%)', 'hsl(0 0% 95%)')};
2025-06-26 15:08:14 +00:00
}
2025-06-27 16:20:06 +00:00
.maincontainer.disabled:hover .checkbox-label {
color: ${cssManager.bdTheme('hsl(0 0% 15%)', 'hsl(0 0% 90%)')};
2025-06-26 15:08:14 +00:00
}
2025-06-27 16:20:06 +00:00
/* Description */
2025-06-26 15:08:14 +00:00
.description-text {
font-size: 12px;
2025-06-27 16:20:06 +00:00
color: ${cssManager.bdTheme('hsl(0 0% 45.1%)', 'hsl(0 0% 63.9%)')};
line-height: 1.5;
2025-06-26 15:08:14 +00:00
}
`,
];
public render(): TemplateResult {
return html`
<div class="input-wrapper">
2025-06-26 15:08:14 +00:00
<div class="maincontainer ${this.disabled ? 'disabled' : ''}" @click="${this.toggleSelected}">
2025-06-27 16:20:06 +00:00
<div
class="checkbox ${this.value ? 'selected' : ''} ${this.disabled ? 'disabled' : ''}"
tabindex="${this.disabled ? '-1' : '0'}"
@keydown="${this.handleKeydown}"
>
${this.value
? html`
<span class="checkmark">
2025-06-27 16:20:06 +00:00
<svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M20 6L9 17L4 12" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</span>
`
: html``}
</div>
2025-06-27 16:20:06 +00:00
<div class="label-container">
${this.label ? html`<div class="checkbox-label">${this.label}</div>` : ''}
${this.description ? html`<div class="description-text">${this.description}</div>` : ''}
</div>
2020-09-13 16:24:48 +00:00
</div>
</div>
`;
}
public async toggleSelected() {
2021-08-26 21:30:35 +02:00
if (this.disabled) {
return;
}
2020-09-13 16:24:48 +00:00
this.value = !this.value;
this.dispatchEvent(
new CustomEvent('newValue', {
detail: this.value,
bubbles: true,
})
);
2021-08-20 00:25:14 +02:00
this.changeSubject.next(this);
2020-09-13 16:24:48 +00:00
}
2023-08-19 11:47:45 +02:00
public getValue(): boolean {
return this.value;
}
public setValue(value: boolean): void {
this.value = value;
}
2023-08-19 11:47:45 +02:00
public focus(): void {
const checkboxDiv = this.shadowRoot.querySelector('.checkbox');
if (checkboxDiv) {
(checkboxDiv as any).focus();
}
}
2025-06-27 16:20:06 +00:00
private handleKeydown(event: KeyboardEvent) {
if (event.key === ' ' || event.key === 'Enter') {
event.preventDefault();
this.toggleSelected();
}
}
2020-09-13 16:24:48 +00:00
}