UNPKG

@sixbell-telco/sdk

Version:

A collection of reusable components designed for use in Sixbell Telco Angular projects

194 lines (190 loc) 19.4 kB
import * as i0 from '@angular/core'; import { input, signal, computed, output, effect, Component } from '@angular/core'; import { ReactiveFormsModule } from '@angular/forms'; import { TranslatePipe } from '@ngx-translate/core'; import { ButtonComponent } from '@sixbell-telco/sdk/components/button'; import { CheckboxComponent } from '@sixbell-telco/sdk/components/forms/checkbox'; import { InputComponent, InputContentComponent } from '@sixbell-telco/sdk/components/forms/input'; import { IconComponent } from '@sixbell-telco/sdk/components/icon'; import { matSearch } from '@sixbell-telco/sdk/components/icon/material/baseline'; import { matChevronLeftOutline, matChevronRightOutline } from '@sixbell-telco/sdk/components/icon/material/outline'; import { TableComponent } from '@sixbell-telco/sdk/components/table'; import { TypographyDirective } from '@sixbell-telco/sdk/directives/typography'; import * as i1 from 'ngx-pagination'; import { NgxPaginationModule } from 'ngx-pagination'; class DualListComponent { // Styles for tables size = input('sm'); height = input('sm'); // Styles for buttons chevronLeftIcon = matChevronLeftOutline; chevronRightIcon = matChevronRightOutline; searchIcon = matSearch; // Key and label inputs and getters key = input('id'); value = input('item'); label = input(''); titleLeft = input(''); titleRight = input(''); getKey(item) { return item[this.key()]; } getValue(item) { return item[this.value()]; } getLabel() { return this.label() .replace(/([A-Z])/g, ' $1') .replace(/^./, function (str) { return str.toUpperCase(); }); } // Signals for dual list management items = input.required(); target = signal([]); selectedItems = signal([]); itemsToRemove = signal([]); totalItems = input(0); addedItems = input.required({ // Input used when there are items added on dual list initialization transform: (items) => { this.selectedItems.set(items); this.handleAddItems(); return items; }, }); computedItems = computed(() => { return this.items().map((item) => { const selected = this.selectedItems().some((addedItem) => addedItem[this.key()] === item[this.key()]); return { ...item, selected }; }); }); allToAdd = computed(() => { return this.computedItems().filter((item) => item.selected).length === this.items().length; }); allToRemove = computed(() => { return this.target().length === this.itemsToRemove().length; }); // Output for dual list change itemsAdded = output(); itemsAddedEffect = effect(() => { this.itemsAdded.emit(this.target()); }); // Left side search (managed by parent) searchQuery = output(); handleSearch(search) { this.searchQuery.emit(search); } // Right side search (local) searchTarget = signal(''); searchTargetComputed = computed(() => { if (this.searchTarget() === '') return this.target(); return this.target().filter((item) => `${item[this.value()]}`.toLowerCase().includes(this.searchTarget().toLowerCase())); }); handleTargetListSearch(search) { this.searchTarget.set(search); } // Pagination pagination = input.required(); pageChanged = output(); pageSizeChanged = output(); handlePageChange(page) { this.pageChanged.emit(page); } handlePageSizeChange(size) { this.pageSizeChanged.emit(size); } // Select item handlers handleSelectSourceItem(checked, item) { if (checked) { const exists = this.selectedItems().some((selectedItem) => selectedItem[this.key()] === item[this.key()]); if (exists) return; this.selectedItems.update((items) => [...items, { ...item }]); } else { const selectedItems = this.selectedItems().filter((selectedItem) => { if (selectedItem && selectedItem[this.key()] === item[this.key()]) { return false; } return true; }); this.selectedItems.set(selectedItems); } } handleSelectTargetItem(checked, item) { if (checked) { item.selected = true; this.itemsToRemove.update((items) => [...items, { ...item, selected: true }]); } else { item.selected = false; const itemsToRemove = this.itemsToRemove().filter((selectedItem) => { if (selectedItem && selectedItem[this.key()] === item[this.key()]) { return false; } return true; }); this.itemsToRemove.set(itemsToRemove); } } // Select ALL handlers handleSelectAll(all) { const itemsList = this.items(); itemsList.forEach((item) => { this.handleSelectSourceItem(all, item); }); } handleSelectAllToRemove(all) { const targetList = this.target(); targetList.forEach((item) => { this.handleSelectTargetItem(all, item); }); } // Add and remove handlers handleAddItems() { const items = this.selectedItems().map((selectedItem) => { return { ...selectedItem, selected: false }; }); this.target.set(items); this.itemsToRemove.set([]); } handleRemoveItems() { if (this.itemsToRemove().length === 0) return; const selectedItems = this.selectedItems().filter((selectedItem) => this.itemsToRemove().every((itemToRemove) => selectedItem[this.key()] !== itemToRemove[this.key()])); this.selectedItems.set(selectedItems); this.updateTargetList(this.itemsToRemove()); this.itemsToRemove.set([]); this.handlePageChange(this.pagination().currentPage ?? 1); } updateTargetList(itemsToRemove) { const items = this.target().filter((addedItem) => { return itemsToRemove.every((itemToRemove) => addedItem[this.key()] !== itemToRemove[this.key()]); }); this.target.set(items); } static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: DualListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.0", type: DualListComponent, isStandalone: true, selector: "st-dual-list", inputs: { size: { classPropertyName: "size", publicName: "size", isSignal: true, isRequired: false, transformFunction: null }, height: { classPropertyName: "height", publicName: "height", isSignal: true, isRequired: false, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, titleLeft: { classPropertyName: "titleLeft", publicName: "titleLeft", isSignal: true, isRequired: false, transformFunction: null }, titleRight: { classPropertyName: "titleRight", publicName: "titleRight", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: true, transformFunction: null }, totalItems: { classPropertyName: "totalItems", publicName: "totalItems", isSignal: true, isRequired: false, transformFunction: null }, addedItems: { classPropertyName: "addedItems", publicName: "addedItems", isSignal: true, isRequired: true, transformFunction: null }, pagination: { classPropertyName: "pagination", publicName: "pagination", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { itemsAdded: "itemsAdded", searchQuery: "searchQuery", pageChanged: "pageChanged", pageSizeChanged: "pageSizeChanged" }, ngImport: i0, template: "@let id = pagination().id;\n@let currentPage = pagination().currentPage;\n@let itemsPerPage = pagination().itemsPerPage;\n@let titleLeftVar = titleLeft();\n@let titleRightVar = titleRight();\n@let heightVar = height();\n@let sizeVar = size();\n<div class=\"grid flex-1 grid-cols-[3fr_min-content_3fr] gap-6\">\n\t<div class=\"rounded-box border-neutral flex flex-col gap-6 border p-6\">\n\t\t@if (titleLeftVar) {\n\t\t\t<div>\n\t\t\t\t<h3 typography [tyVariant]=\"'h3'\">{{ titleLeftVar }}</h3>\n\t\t\t</div>\n\t\t}\n\t\t<div class=\"flex h-full flex-col gap-4\">\n\t\t\t<st-input\n\t\t\t\t[placeholder]=\"'sdk.dualList.searchPlaceHolder' | translate\"\n\t\t\t\t(enterPressed)=\"handleSearch($event)\"\n\t\t\t\t(valueDebounced)=\"handleSearch($event)\"\n\t\t\t>\n\t\t\t\t<st-input-content alignment=\"start\">\n\t\t\t\t\t<st-icon [icon]=\"searchIcon\"></st-icon>\n\t\t\t\t</st-input-content>\n\t\t\t</st-input>\n\t\t\t<st-table\n\t\t\t\tclass=\"h-full\"\n\t\t\t\t[pagination]=\"pagination()\"\n\t\t\t\t[totalItems]=\"totalItems()\"\n\t\t\t\t(pageChanged)=\"handlePageChange($event)\"\n\t\t\t\t(pageSizeChanged)=\"handlePageSizeChange($event)\"\n\t\t\t\t[showItemsPerPage]=\"false\"\n\t\t\t\t[showEntries]=\"false\"\n\t\t\t\t[maxSize]=\"4\"\n\t\t\t\t[size]=\"sizeVar\"\n\t\t\t\t[height]=\"heightVar\"\n\t\t\t\t[pinRows]=\"true\"\n\t\t\t\t[showEntries]=\"false\"\n\t\t\t\t[showItemsPerPage]=\"false\"\n\t\t\t>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th class=\"w-6\">\n\t\t\t\t\t\t\t<st-checkbox [value]=\"allToAdd()\" (valueUpdated)=\"handleSelectAll($event)\"></st-checkbox>\n\t\t\t\t\t\t</th>\n\t\t\t\t\t\t<th>{{ getLabel() }}</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t@for (item of computedItems() | paginate: { id, currentPage, itemsPerPage, totalItems: totalItems() }; track getKey(item)) {\n\t\t\t\t\t\t<tr class=\"hover:bg-neutral\">\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t<st-checkbox [(value)]=\"item.selected\" (valueUpdated)=\"handleSelectSourceItem($event, item)\"></st-checkbox>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>{{ getValue(item) }}</td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t}\n\t\t\t\t</tbody>\n\t\t\t</st-table>\n\t\t</div>\n\t</div>\n\n\t<!-- Buttons -->\n\t<div class=\"grid place-content-center gap-4\">\n\t\t<st-button variant=\"secondary\" [circle]=\"true\" [icon]=\"chevronRightIcon\" (click)=\"handleAddItems()\" />\n\t\t<st-button variant=\"secondary\" [circle]=\"true\" [icon]=\"chevronLeftIcon\" (click)=\"handleRemoveItems()\" />\n\t</div>\n\n\t<!-- END Buttons -->\n\n\t<div class=\"rounded-box border-neutral flex flex-1 flex-col gap-6 border p-6\">\n\t\t@if (titleRightVar) {\n\t\t\t<div>\n\t\t\t\t<h3 typography [tyVariant]=\"'h3'\">{{ titleRightVar }}</h3>\n\t\t\t</div>\n\t\t}\n\t\t<div class=\"flex h-full flex-col gap-4\">\n\t\t\t<st-input\n\t\t\t\t[placeholder]=\"'sdk.dualList.searchPlaceHolder' | translate\"\n\t\t\t\t(enterPressed)=\"handleTargetListSearch($event)\"\n\t\t\t\t(valueDebounced)=\"handleTargetListSearch($event)\"\n\t\t\t>\n\t\t\t\t<st-input-content alignment=\"start\">\n\t\t\t\t\t<st-icon [icon]=\"searchIcon\"></st-icon>\n\t\t\t\t</st-input-content>\n\t\t\t</st-input>\n\t\t\t@let added = searchTargetComputed();\n\t\t\t@if (added) {\n\t\t\t\t<st-table\n\t\t\t\t\t[data]=\"added\"\n\t\t\t\t\t[size]=\"sizeVar\"\n\t\t\t\t\t[height]=\"heightVar\"\n\t\t\t\t\t[pinRows]=\"true\"\n\t\t\t\t\t[showItemsPerPage]=\"false\"\n\t\t\t\t\t[showPagination]=\"false\"\n\t\t\t\t\t[totalItems]=\"added.length\"\n\t\t\t\t\tclass=\"h-full\"\n\t\t\t\t>\n\t\t\t\t\t<thead>\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<th class=\"w-6\">\n\t\t\t\t\t\t\t\t@if (searchTarget() === '') {\n\t\t\t\t\t\t\t\t\t<st-checkbox [value]=\"allToRemove()\" (valueUpdated)=\"handleSelectAllToRemove($event)\"></st-checkbox>\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t<th>{{ getLabel() }}</th>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t</thead>\n\t\t\t\t\t<tbody>\n\t\t\t\t\t\t@for (item of added; track getKey(item)) {\n\t\t\t\t\t\t\t<tr class=\"hover:bg-neutral\">\n\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t<st-checkbox [(value)]=\"item.selected\" (valueUpdated)=\"handleSelectTargetItem($event, item)\"></st-checkbox>\n\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t<td>{{ getValue(item) }}</td>\n\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t}\n\t\t\t\t\t</tbody>\n\t\t\t\t</st-table>\n\t\t\t}\n\t\t</div>\n\t</div>\n</div>\n", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: TableComponent, selector: "st-table", inputs: ["size", "height", "pinRows", "pinColumns", "zebra", "paginatorType", "data", "totalItems", "pagination", "maxSize", "showItemsPerPage", "showEntries", "showPagination", "showFooter"], outputs: ["pageChanged", "pageSizeChanged", "checkedItems"] }, { kind: "component", type: CheckboxComponent, selector: "st-checkbox", inputs: ["variant", "size", "label", "name", "value", "disabled"], outputs: ["valueChange", "valueUpdated", "disabledChange"] }, { kind: "component", type: InputComponent, selector: "st-input", inputs: ["variant", "size", "label", "type", "name", "placeholder", "readonly", "focus", "onlyNumbers", "ghost", "value", "parentForm", "formControlName", "disabled", "debounceTime"], outputs: ["valueChange", "disabledChange", "enterPressed", "blurred", "valueDebounced"] }, { kind: "ngmodule", type: NgxPaginationModule }, { kind: "pipe", type: i1.PaginatePipe, name: "paginate" }, { kind: "component", type: ButtonComponent, selector: "st-button", inputs: ["variant", "ghost", "outline", "link", "soft", "dash", "wide", "circle", "square", "glass", "block", "loader", "size", "shadow", "focusable", "icon", "iconPosition", "type", "disabled"] }, { kind: "directive", type: TypographyDirective, selector: "[typography]", inputs: ["tyVariant", "tyColor", "tyFontWeight", "tyTextOverflow"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }, { kind: "component", type: InputContentComponent, selector: "st-input-content", inputs: ["alignment"] }, { kind: "component", type: IconComponent, selector: "st-icon", inputs: ["color", "size", "icon"] }] }); } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.0", ngImport: i0, type: DualListComponent, decorators: [{ type: Component, args: [{ selector: 'st-dual-list', imports: [ ReactiveFormsModule, TableComponent, CheckboxComponent, InputComponent, NgxPaginationModule, ButtonComponent, TypographyDirective, TranslatePipe, InputContentComponent, IconComponent, ], template: "@let id = pagination().id;\n@let currentPage = pagination().currentPage;\n@let itemsPerPage = pagination().itemsPerPage;\n@let titleLeftVar = titleLeft();\n@let titleRightVar = titleRight();\n@let heightVar = height();\n@let sizeVar = size();\n<div class=\"grid flex-1 grid-cols-[3fr_min-content_3fr] gap-6\">\n\t<div class=\"rounded-box border-neutral flex flex-col gap-6 border p-6\">\n\t\t@if (titleLeftVar) {\n\t\t\t<div>\n\t\t\t\t<h3 typography [tyVariant]=\"'h3'\">{{ titleLeftVar }}</h3>\n\t\t\t</div>\n\t\t}\n\t\t<div class=\"flex h-full flex-col gap-4\">\n\t\t\t<st-input\n\t\t\t\t[placeholder]=\"'sdk.dualList.searchPlaceHolder' | translate\"\n\t\t\t\t(enterPressed)=\"handleSearch($event)\"\n\t\t\t\t(valueDebounced)=\"handleSearch($event)\"\n\t\t\t>\n\t\t\t\t<st-input-content alignment=\"start\">\n\t\t\t\t\t<st-icon [icon]=\"searchIcon\"></st-icon>\n\t\t\t\t</st-input-content>\n\t\t\t</st-input>\n\t\t\t<st-table\n\t\t\t\tclass=\"h-full\"\n\t\t\t\t[pagination]=\"pagination()\"\n\t\t\t\t[totalItems]=\"totalItems()\"\n\t\t\t\t(pageChanged)=\"handlePageChange($event)\"\n\t\t\t\t(pageSizeChanged)=\"handlePageSizeChange($event)\"\n\t\t\t\t[showItemsPerPage]=\"false\"\n\t\t\t\t[showEntries]=\"false\"\n\t\t\t\t[maxSize]=\"4\"\n\t\t\t\t[size]=\"sizeVar\"\n\t\t\t\t[height]=\"heightVar\"\n\t\t\t\t[pinRows]=\"true\"\n\t\t\t\t[showEntries]=\"false\"\n\t\t\t\t[showItemsPerPage]=\"false\"\n\t\t\t>\n\t\t\t\t<thead>\n\t\t\t\t\t<tr>\n\t\t\t\t\t\t<th class=\"w-6\">\n\t\t\t\t\t\t\t<st-checkbox [value]=\"allToAdd()\" (valueUpdated)=\"handleSelectAll($event)\"></st-checkbox>\n\t\t\t\t\t\t</th>\n\t\t\t\t\t\t<th>{{ getLabel() }}</th>\n\t\t\t\t\t</tr>\n\t\t\t\t</thead>\n\t\t\t\t<tbody>\n\t\t\t\t\t@for (item of computedItems() | paginate: { id, currentPage, itemsPerPage, totalItems: totalItems() }; track getKey(item)) {\n\t\t\t\t\t\t<tr class=\"hover:bg-neutral\">\n\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t<st-checkbox [(value)]=\"item.selected\" (valueUpdated)=\"handleSelectSourceItem($event, item)\"></st-checkbox>\n\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t<td>{{ getValue(item) }}</td>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t}\n\t\t\t\t</tbody>\n\t\t\t</st-table>\n\t\t</div>\n\t</div>\n\n\t<!-- Buttons -->\n\t<div class=\"grid place-content-center gap-4\">\n\t\t<st-button variant=\"secondary\" [circle]=\"true\" [icon]=\"chevronRightIcon\" (click)=\"handleAddItems()\" />\n\t\t<st-button variant=\"secondary\" [circle]=\"true\" [icon]=\"chevronLeftIcon\" (click)=\"handleRemoveItems()\" />\n\t</div>\n\n\t<!-- END Buttons -->\n\n\t<div class=\"rounded-box border-neutral flex flex-1 flex-col gap-6 border p-6\">\n\t\t@if (titleRightVar) {\n\t\t\t<div>\n\t\t\t\t<h3 typography [tyVariant]=\"'h3'\">{{ titleRightVar }}</h3>\n\t\t\t</div>\n\t\t}\n\t\t<div class=\"flex h-full flex-col gap-4\">\n\t\t\t<st-input\n\t\t\t\t[placeholder]=\"'sdk.dualList.searchPlaceHolder' | translate\"\n\t\t\t\t(enterPressed)=\"handleTargetListSearch($event)\"\n\t\t\t\t(valueDebounced)=\"handleTargetListSearch($event)\"\n\t\t\t>\n\t\t\t\t<st-input-content alignment=\"start\">\n\t\t\t\t\t<st-icon [icon]=\"searchIcon\"></st-icon>\n\t\t\t\t</st-input-content>\n\t\t\t</st-input>\n\t\t\t@let added = searchTargetComputed();\n\t\t\t@if (added) {\n\t\t\t\t<st-table\n\t\t\t\t\t[data]=\"added\"\n\t\t\t\t\t[size]=\"sizeVar\"\n\t\t\t\t\t[height]=\"heightVar\"\n\t\t\t\t\t[pinRows]=\"true\"\n\t\t\t\t\t[showItemsPerPage]=\"false\"\n\t\t\t\t\t[showPagination]=\"false\"\n\t\t\t\t\t[totalItems]=\"added.length\"\n\t\t\t\t\tclass=\"h-full\"\n\t\t\t\t>\n\t\t\t\t\t<thead>\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t<th class=\"w-6\">\n\t\t\t\t\t\t\t\t@if (searchTarget() === '') {\n\t\t\t\t\t\t\t\t\t<st-checkbox [value]=\"allToRemove()\" (valueUpdated)=\"handleSelectAllToRemove($event)\"></st-checkbox>\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t</th>\n\t\t\t\t\t\t\t<th>{{ getLabel() }}</th>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t</thead>\n\t\t\t\t\t<tbody>\n\t\t\t\t\t\t@for (item of added; track getKey(item)) {\n\t\t\t\t\t\t\t<tr class=\"hover:bg-neutral\">\n\t\t\t\t\t\t\t\t<td>\n\t\t\t\t\t\t\t\t\t<st-checkbox [(value)]=\"item.selected\" (valueUpdated)=\"handleSelectTargetItem($event, item)\"></st-checkbox>\n\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t<td>{{ getValue(item) }}</td>\n\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t}\n\t\t\t\t\t</tbody>\n\t\t\t\t</st-table>\n\t\t\t}\n\t\t</div>\n\t</div>\n</div>\n" }] }] }); /** * Generated bundle index. Do not edit. */ export { DualListComponent }; //# sourceMappingURL=sixbell-telco-sdk-components-dual-list.mjs.map