sf-checklist
Version:
Superflows Checklist Component
378 lines (361 loc) • 13.6 kB
JavaScript
/**
* @license
* Copyright 2022 Superflow.dev
* SPDX-License-Identifier: MIT
*/
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { LitElement, html, css } from 'lit';
import { customElement, property } from 'lit/decorators.js';
/*
Modes: multiselect, select
Flows: view,edit
*/
/**
* SfChecklist element.
* @fires renderComplete - When the list is populated
* @fires valueChanged - When the value is changed
* @property apiId - backend api id
* @property label - input label
* @property name - name of the input
* @property mode - mode of operation
* @property selectedId - id to preselect
* @property selectedValue - callback function
*/
let SfChecklist = class SfChecklist extends LitElement {
constructor() {
super(...arguments);
// mode = ""
this.mode = "admin";
this.readonly = false;
// readonly = true
this.listname = "";
this.listelements = [];
// listelements: { name: string }[] = [
// {
// "name": "Contract term 1"
// },
// {
// "name": "contract term 2"
// },
// {
// "name": "contract term 3"
// }
// ]
// listelements: { name: string }[] = [{"name": "Terms1"},{"name": "Terms2"}]
// listelements: { name: string }[] = [
// {
// "name": "item 1"
// },
// {
// "name": "item 2"
// }
// ]
this.listselection = {};
// listselection: { [key: string]: boolean } = {
// "Contract term 1": true,
// "contract term 2": true,
// "contract term 3": true
// }
// listselection: any = {
// "First term": true,
// "Second term": true
// }
// listselection: any = {
// "Check 1": true,
// "Check 2": false,
// "Check 3": true
// }
this.selectedValues = () => {
console.log('checklist selectedvalues', JSON.stringify(this.listselection));
let retObj = {};
for (let key of this.listelements) {
retObj[key] = this.listselection[key] ?? false;
}
return this.listselection;
};
this.dispatchValueChanged = () => {
console.log("dispatchValueChanged");
let customEvent = new CustomEvent('valueChanged', {
detail: { source: 'InnerElement', id: this.id },
bubbles: true,
composed: true
});
this.dispatchEvent(customEvent);
};
this.initListeners = () => {
let addButton = this.shadowRoot?.getElementById("add-button");
let addInput = this.shadowRoot?.getElementById("add-input");
addButton?.addEventListener("click", () => {
let newItem = addInput?.value;
if (newItem) {
// this.listelements.push({ name: newItem });
this.listselection[newItem] = false;
addInput.value = "";
this.dispatchValueChanged();
this.loadMode();
}
});
let deleteButtons = this.shadowRoot?.querySelectorAll('.button-delete');
for (let deleteButton of deleteButtons) {
deleteButton.addEventListener('click', () => {
let id = deleteButton.id;
let index = parseInt(id.split('-')[2]);
let listelement = this.listelements[index];
this.listelements.splice(index, 1);
delete this.listselection[listelement];
this.dispatchValueChanged();
this.loadMode();
});
}
let upButtons = this.shadowRoot?.querySelectorAll('.button-up');
for (let upButton of upButtons) {
upButton.addEventListener('click', () => {
let id = upButton.id;
let index = parseInt(id.split('-')[2]);
this.listelements = this.reorderArray(this.listelements, index, index - 1);
let newMap = this.reorderMap(new Map(Object.entries(this.listselection)), this.listelements);
this.listselection = Object.fromEntries(newMap);
this.dispatchValueChanged();
this.loadMode();
});
}
let downButtons = this.shadowRoot?.querySelectorAll('.button-down');
for (let downButton of downButtons) {
downButton.addEventListener('click', () => {
let id = downButton.id;
let index = parseInt(id.split('-')[2]);
this.listelements = this.reorderArray(this.listelements, index, index + 1);
let newMap = this.reorderMap(new Map(Object.entries(this.listselection)), this.listelements);
this.listselection = Object.fromEntries(newMap);
this.dispatchValueChanged();
this.loadMode();
});
}
};
this.loadMode = async () => {
console.log("loadMode", this.mode, this.listelements, this.listselection);
this.listelements = Object.keys(this.listselection);
if (this.mode == "admin") {
let checklistInputContainer = this.shadowRoot?.getElementById('checklist-input-container');
checklistInputContainer.style.display = this.readonly ? 'none' : 'flex';
let checklistList = this.shadowRoot?.getElementById("checklist-list");
let innerHTML = '';
if (Array.isArray(this.listelements)) {
this.listelements.map((item, index) => {
innerHTML += `
<div part="checklist-item" class="d-flex align-center">
<label part="checklist-checkbox-label">${(item ?? "")}</label>${!this.readonly && index > 0 ? `<button id="button-up-${index}" part="button-icon" class="mrl-5 material-symbols-outlined button-up">arrow_upward</button>` : ''}${!this.readonly && index < (this.listelements.length - 1) ? `<button id="button-down-${index}" part="button-icon" class="mrl-5 material-symbols-outlined button-down">arrow_downward</button>` : ''}${!this.readonly ? `<button id="button-delete-${index}" part="button-icon" class="mrl-5 material-icons button-delete">delete</button>` : ''}
</div>
`;
});
}
checklistList.innerHTML = innerHTML;
console.log("checklistList", checklistList.innerHTML);
if (!this.readonly) {
this.initListeners();
}
}
else {
let checklistList = this.shadowRoot?.getElementById("checklist-list");
let innerHTML = '';
if (Array.isArray(this.listelements)) {
this.listelements.map((item) => {
console.log('sf-checklistt rendering checkbox', this.listselection[(item ?? "")]);
innerHTML += `
<div part="checklist-item" class="d-flex">
<input part="checklist-checkbox" type="checkbox" id="checkbox-${(item ?? "").replace(/ /g, '-')}" name="${(item ?? "")}" value="${(item ?? "")}" ${(this.listselection[(item ?? "")] ?? false) ? "checked" : ""} ${this.readonly ? "disabled" : ""}/>
<label part="checklist-checkbox-label" for="checkbox-${(item ?? "").replace(/ /g, '-')}">${(item ?? "")}</label>
</div>
`;
});
}
checklistList.innerHTML = innerHTML;
for (const item of this.listelements) {
const checkbox = this.shadowRoot?.getElementById(`checkbox-${(item ?? "").replace(/ /g, '-')}`);
if (checkbox) {
checkbox.addEventListener('change', () => {
const name = item ?? "";
this.listselection = {
...this.listselection,
[name]: checkbox.checked
};
console.log('checklist selected', this.listselection, typeof (this.listselection));
this.dispatchValueChanged();
});
}
if (this.listselection[(item ?? "")] == null) {
this.listselection[(item ?? "")] = false;
}
}
this.dispatchValueChanged();
}
};
}
reorderArray(arr, oldIndex, newIndex) {
if (oldIndex === newIndex) {
return arr;
}
const newArr = [...arr];
const [item] = newArr.splice(oldIndex, 1);
newArr.splice(newIndex, 0, item);
return newArr;
}
reorderMap(map, newOrder) {
const reordered = new Map();
for (const key of newOrder) {
if (map.has(key)) {
reordered.set(key, map.get(key));
}
}
return reordered;
}
firstUpdated(_changedProperties) {
this.loadMode();
}
connectedCallback() {
super.connectedCallback();
}
render() {
if (this.mode == "admin") {
return html `
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@48,400,0,0" />
<div part="checklist-container" class="d-flex flex-col">
${this.listname != "" ? `<h2 part="checklist-title">${this.listname}</h2>` : ''}
<div id="checklist-input-container" part="checklist-input-container" class="d-flex">
<input part="checklist-add-input" type="text" id="add-input" name="add-input" value="" placeholder="Add new item" />
<button id="add-button" part="checklist-add-button" class="ml-10">Add</button>
</div>
<div id="checklist-list" part="checklist-list" class="d-flex flex-col flex-wrap justify-center w-100-m-0">
</div>
</div>
`;
}
else {
return html `
<div part="checklist-container" class="d-flex">
${this.listname != "" ? `<h2 part="checklist-title">${this.listname}</h2>` : ''}
<div id="checklist-list" part="checklist-list" class="d-flex flex-col flex-wrap justify-center w-100-m-0">
</div>
</div>
`;
}
}
};
SfChecklist.styles = css `
:root {
--color: #fcc419;
--shadow: #f08c00;
--glare: hsl(0 0% 100% / 0.75);
--font-size: clamp(.75rem, 2vw, 1rem);
--transition: 0.2s;
}
* {
box-sizing: border-box;
}
.d-flex {
display: flex;
}
.flex-col {
flex-direction: column;
}
.flex-wrap {
flex-wrap: wrap;
}
.justify-center {
justify-content: center;
}
.justify-between {
justify-content: space-between;
}
.justify-end {
justify-content: flex-end;
}
.w-100-m-0 {
width: 100%;
}
.mb-20 {
margin-bottom: 20px;
}
.mt-20 {
margin-top: 20px;
}
.mr-10 {
margin-right: 10px;
}
.m-0 {
margin: 0px;
}
.m-20 {
margin: 20px;
}
.md-20-ml-10 {
margin-top: 20px;
margin-bottom: 20px;
margin-left: 10px;
margin-right: 10px;
}
.mrl-5 {
margin-left: 5px;
margin-right: 5px;
}
.mrl-10 {
margin-left: 10px;
margin-right: 10px;
}
.mt-10{
margin-top: 10px
}
.ml-10{
margin-left: 10px
}
.mr-20{
margin-right: 20px
}
.flex-grow {
flex-grow: 1;
}
.align-start {
align-items: flex-start;
}
.align-end {
align-items: flex-end;
}
.align-center {
align-items: center;
}
.align-stretch {
align-items: stretch;
}
body {
display: grid;
place-items: center;
min-height: 100vh;
font-family: 'Google Sans', sans-serif, system-ui;
}
`;
__decorate([
property({ type: String })
], SfChecklist.prototype, "mode", void 0);
__decorate([
property({ type: Boolean })
], SfChecklist.prototype, "readonly", void 0);
__decorate([
property()
], SfChecklist.prototype, "listname", void 0);
__decorate([
property({ type: Array })
], SfChecklist.prototype, "listelements", void 0);
__decorate([
property({ type: Object })
], SfChecklist.prototype, "listselection", void 0);
SfChecklist = __decorate([
customElement('sf-checklist')
], SfChecklist);
export { SfChecklist };
//# sourceMappingURL=sf-checklist.js.map