import { customElement, html, DeesElement, property, type TemplateResult, cssManager, css, type CSSResult, unsafeCSS, } from '@design.estate/dees-element'; import * as domtools from '@design.estate/dees-domtools'; import { demoFunc } from './dees-chips.demo.js'; declare global { interface HTMLElementTagNameMap { 'dees-chips': DeesChips; } } type Tag = { key: string; value: string }; @customElement('dees-chips') export class DeesChips extends DeesElement { public static demo = demoFunc; @property() public selectionMode: 'none' | 'single' | 'multiple' = 'single'; @property({ type: Boolean, }) public chipsAreRemovable: boolean = false; @property({ type: Array, }) public selectableChips: Tag[] = []; @property() public selectedChip: Tag = null; @property({ type: Array, }) public selectedChips: Tag[] = []; constructor() { super(); } public static styles = [ cssManager.defaultStyles, css` :host { display: block; box-sizing: border-box; } .mainbox { user-select: none; display: flex; flex-wrap: wrap; gap: 8px; } .chip { background: ${cssManager.bdTheme('#f4f4f5', '#27272a')}; border: 1px solid ${cssManager.bdTheme('#e5e7eb', '#3f3f46')}; display: inline-flex; align-items: center; height: 32px; padding: 0px 12px; font-size: 14px; font-weight: 500; color: ${cssManager.bdTheme('#09090b', '#fafafa')}; border-radius: 6px; position: relative; cursor: pointer; transition: all 0.15s ease; box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); } .chip:hover { background: ${cssManager.bdTheme('#e5e7eb', '#3f3f46')}; border-color: ${cssManager.bdTheme('#d1d5db', '#52525b')}; } .chip:active { transform: scale(0.98); } .chip.selected { background: ${cssManager.bdTheme('#3b82f6', '#3b82f6')}; border-color: ${cssManager.bdTheme('#3b82f6', '#3b82f6')}; color: #ffffff; } .chip.selected:hover { background: ${cssManager.bdTheme('#2563eb', '#2563eb')}; border-color: ${cssManager.bdTheme('#2563eb', '#2563eb')}; } .chipKey { background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.06)', 'rgba(255, 255, 255, 0.1)')}; height: 20px; line-height: 20px; display: inline-flex; align-items: center; margin-left: -8px; padding: 0px 8px; margin-right: 8px; border-radius: 4px; font-size: 12px; font-weight: 600; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; } .chip.selected .chipKey { background: rgba(255, 255, 255, 0.2); color: rgba(255, 255, 255, 0.9); } dees-icon { display: flex; align-items: center; justify-content: center; width: 16px; height: 16px; margin-left: 8px; margin-right: -6px; border-radius: 3px; transition: all 0.15s ease; color: ${cssManager.bdTheme('#71717a', '#a1a1aa')}; } .chip.selected dees-icon { color: rgba(255, 255, 255, 0.8); } dees-icon:hover { background: ${cssManager.bdTheme('rgba(0, 0, 0, 0.1)', 'rgba(255, 255, 255, 0.1)')}; color: ${cssManager.bdTheme('#ef4444', '#ef4444')}; } .chip.selected dees-icon:hover { background: rgba(255, 255, 255, 0.2); color: #ffffff; } `, ]; public render(): TemplateResult { return html`
${this.selectableChips.map( (chip) => html`
this.selectChip(chip)} class="chip ${this.isSelected(chip) ? 'selected' : ''}" > ${chip.key ? html`
${chip.key}
` : html``} ${chip.value} ${this.chipsAreRemovable ? html` { event.stopPropagation(); // prevent the selectChip event from being triggered this.removeChip(chip); }} .iconFA=${'xmark'} > ` : html``}
` )}
`; } public async firstUpdated() { // Component initialized } private isSelected(chip: Tag): boolean { if (this.selectionMode === 'single') { return this.selectedChip ? this.isSameChip(this.selectedChip, chip) : false; } else { return this.selectedChips.some((selected) => this.isSameChip(selected, chip)); } } private isSameChip(chip1: Tag, chip2: Tag): boolean { // If both have keys, compare by key if (chip1.key && chip2.key) { return chip1.key === chip2.key; } // Otherwise compare by value (and key if present) return chip1.value === chip2.value && chip1.key === chip2.key; } public async selectChip(chip: Tag) { if (this.selectionMode === 'none') { return; } if (this.selectionMode === 'single') { if (this.isSelected(chip)) { this.selectedChip = null; this.selectedChips = []; } else { this.selectedChip = chip; this.selectedChips = [chip]; } } else if (this.selectionMode === 'multiple') { if (this.isSelected(chip)) { this.selectedChips = this.selectedChips.filter((selected) => !this.isSameChip(selected, chip)); } else { this.selectedChips = [...this.selectedChips, chip]; } this.requestUpdate(); } console.log(this.selectedChips); } public removeChip(chipToRemove: Tag): void { // Remove the chip from selectableChips this.selectableChips = this.selectableChips.filter((chip) => !this.isSameChip(chip, chipToRemove)); // Remove the chip from selectedChips if present this.selectedChips = this.selectedChips.filter((chip) => !this.isSameChip(chip, chipToRemove)); // If the removed chip was the selectedChip, set selectedChip to null if (this.selectedChip && this.isSameChip(this.selectedChip, chipToRemove)) { this.selectedChip = null; } // Trigger an update to re-render the component this.requestUpdate(); } }