Files
dees-catalog/ts_web/elements/dees-chips.ts

243 lines
6.3 KiB
TypeScript
Raw Normal View History

2021-10-08 16:07:40 +02:00
import {
customElement,
html,
DeesElement,
property,
2023-08-07 20:02:18 +02:00
type TemplateResult,
2021-10-08 16:07:40 +02:00
cssManager,
css,
2023-08-08 01:10:02 +02:00
type CSSResult,
2021-10-08 16:07:40 +02:00
unsafeCSS,
2023-08-07 19:13:29 +02:00
} from '@design.estate/dees-element';
2021-10-08 16:07:40 +02:00
2023-08-07 19:13:29 +02:00
import * as domtools from '@design.estate/dees-domtools';
2023-10-23 21:23:18 +02:00
import { demoFunc } from './dees-chips.demo.js';
2021-10-08 16:07:40 +02:00
declare global {
interface HTMLElementTagNameMap {
'dees-chips': DeesChips;
}
}
2023-10-31 13:44:18 +01:00
type Tag = { key: string; value: string };
2023-10-23 21:23:18 +02:00
2021-10-08 16:07:40 +02:00
@customElement('dees-chips')
export class DeesChips extends DeesElement {
2023-10-23 21:23:18 +02:00
public static demo = demoFunc;
2021-10-08 16:07:40 +02:00
@property()
2023-10-23 21:23:18 +02:00
public selectionMode: 'none' | 'single' | 'multiple' = 'single';
2021-10-08 16:07:40 +02:00
@property({
2023-10-31 13:44:18 +01:00
type: Boolean,
})
public chipsAreRemovable: boolean = false;
@property({
type: Array,
2021-10-08 16:07:40 +02:00
})
2023-10-23 21:23:18 +02:00
public selectableChips: Tag[] = [];
2021-10-08 16:07:40 +02:00
@property()
2023-10-23 21:23:18 +02:00
public selectedChip: Tag = null;
2021-10-08 16:07:40 +02:00
@property({
2023-10-31 13:44:18 +01:00
type: Array,
2021-10-08 16:07:40 +02:00
})
2023-10-23 21:23:18 +02:00
public selectedChips: Tag[] = [];
2021-10-08 16:07:40 +02:00
constructor() {
super();
}
public static styles = [
cssManager.defaultStyles,
css`
:host {
display: block;
box-sizing: border-box;
}
.mainbox {
2023-10-23 21:23:18 +02:00
user-select: none;
2025-06-27 21:01:12 +00:00
display: flex;
flex-wrap: wrap;
gap: 8px;
2021-10-08 16:07:40 +02:00
}
.chip {
2025-06-27 21:01:12 +00:00
background: ${cssManager.bdTheme('#f4f4f5', '#27272a')};
border: 1px solid ${cssManager.bdTheme('#e5e7eb', '#3f3f46')};
2023-10-23 21:23:18 +02:00
display: inline-flex;
2025-06-27 21:01:12 +00:00
align-items: center;
height: 32px;
padding: 0px 12px;
font-size: 14px;
font-weight: 500;
color: ${cssManager.bdTheme('#09090b', '#fafafa')};
border-radius: 6px;
2023-10-23 21:23:18 +02:00
position: relative;
2025-06-27 21:01:12 +00:00
cursor: pointer;
transition: all 0.15s ease;
box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
2021-10-08 16:07:40 +02:00
}
.chip:hover {
2025-06-27 21:01:12 +00:00
background: ${cssManager.bdTheme('#e5e7eb', '#3f3f46')};
border-color: ${cssManager.bdTheme('#d1d5db', '#52525b')};
}
.chip:active {
transform: scale(0.98);
2021-10-08 16:07:40 +02:00
}
.chip.selected {
2025-06-27 21:01:12 +00:00
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')};
2021-10-08 16:07:40 +02:00
}
2023-10-23 21:23:18 +02:00
.chipKey {
2025-06-27 21:01:12 +00:00
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;
2023-10-23 21:23:18 +02:00
margin-left: -8px;
2025-06-27 21:01:12 +00:00
padding: 0px 8px;
2023-10-23 21:23:18 +02:00
margin-right: 8px;
2025-06-27 21:01:12 +00:00
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);
2023-10-23 21:23:18 +02:00
}
2023-10-31 13:44:18 +01:00
dees-icon {
2025-06-27 21:01:12 +00:00
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);
2023-10-31 13:44:18 +01:00
}
dees-icon:hover {
2025-06-27 21:01:12 +00:00
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;
2023-10-31 13:44:18 +01:00
}
2021-10-08 16:07:40 +02:00
`,
];
public render(): TemplateResult {
return html`
<div class="mainbox">
2023-10-31 13:44:18 +01:00
${this.selectableChips.map(
(chip) => html`
<div
@click=${() => this.selectChip(chip)}
class="chip ${this.isSelected(chip) ? 'selected' : ''}"
>
${chip.key ? html`<div class="chipKey">${chip.key}</div>` : html``} ${chip.value}
${this.chipsAreRemovable
? html`
<dees-icon
@click=${(event: Event) => {
event.stopPropagation(); // prevent the selectChip event from being triggered
this.removeChip(chip);
}}
.iconFA=${'xmark'}
></dees-icon>
`
: html``}
</div>
`
)}
2021-10-08 16:07:40 +02:00
</div>
`;
}
public async firstUpdated() {
2025-06-27 21:01:12 +00:00
// Component initialized
2021-10-08 16:07:40 +02:00
}
2023-10-23 21:23:18 +02:00
private isSelected(chip: Tag): boolean {
if (this.selectionMode === 'single') {
2025-06-27 21:01:12 +00:00
return this.selectedChip ? this.isSameChip(this.selectedChip, chip) : false;
2023-10-23 21:23:18 +02:00
} else {
2025-06-27 21:01:12 +00:00
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;
2023-10-23 21:23:18 +02:00
}
2025-06-27 21:01:12 +00:00
// Otherwise compare by value (and key if present)
return chip1.value === chip2.value && chip1.key === chip2.key;
2023-10-23 21:23:18 +02:00
}
public async selectChip(chip: Tag) {
if (this.selectionMode === 'none') {
return;
}
2021-10-08 16:07:40 +02:00
if (this.selectionMode === 'single') {
2023-10-23 21:23:18 +02:00
if (this.isSelected(chip)) {
2021-10-08 16:07:40 +02:00
this.selectedChip = null;
this.selectedChips = [];
} else {
2023-10-23 21:23:18 +02:00
this.selectedChip = chip;
this.selectedChips = [chip];
2021-10-08 16:07:40 +02:00
}
2023-10-31 13:44:18 +01:00
} else if (this.selectionMode === 'multiple') {
2023-10-23 21:23:18 +02:00
if (this.isSelected(chip)) {
2025-06-27 21:01:12 +00:00
this.selectedChips = this.selectedChips.filter((selected) => !this.isSameChip(selected, chip));
2021-10-08 16:07:40 +02:00
} else {
2023-10-23 21:23:18 +02:00
this.selectedChips = [...this.selectedChips, chip];
2021-10-08 16:07:40 +02:00
}
this.requestUpdate();
}
console.log(this.selectedChips);
}
2023-10-31 13:44:18 +01:00
public removeChip(chipToRemove: Tag): void {
// Remove the chip from selectableChips
2025-06-27 21:01:12 +00:00
this.selectableChips = this.selectableChips.filter((chip) => !this.isSameChip(chip, chipToRemove));
2023-10-31 13:44:18 +01:00
// Remove the chip from selectedChips if present
2025-06-27 21:01:12 +00:00
this.selectedChips = this.selectedChips.filter((chip) => !this.isSameChip(chip, chipToRemove));
2023-10-31 13:44:18 +01:00
// If the removed chip was the selectedChip, set selectedChip to null
2025-06-27 21:01:12 +00:00
if (this.selectedChip && this.isSameChip(this.selectedChip, chipToRemove)) {
2023-10-31 13:44:18 +01:00
this.selectedChip = null;
}
// Trigger an update to re-render the component
this.requestUpdate();
}
2021-10-08 16:07:40 +02:00
}