mn-angular-lib 0.0.81 → 0.0.83
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -2895,9 +2895,9 @@ class BaseModalBuilder {
|
|
|
2895
2895
|
this.config.sizeWidth = size;
|
|
2896
2896
|
return this;
|
|
2897
2897
|
}
|
|
2898
|
-
/** Set the height of the modal
|
|
2899
|
-
sizeHeight(
|
|
2900
|
-
this.config.sizeHeight =
|
|
2898
|
+
/** Set the height of the modal */
|
|
2899
|
+
sizeHeight(size) {
|
|
2900
|
+
this.config.sizeHeight = size;
|
|
2901
2901
|
return this;
|
|
2902
2902
|
}
|
|
2903
2903
|
closeMode(mode) {
|
|
@@ -3656,11 +3656,11 @@ class MnTable {
|
|
|
3656
3656
|
this.selectionChange.emit(rows);
|
|
3657
3657
|
}
|
|
3658
3658
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: MnTable, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
3659
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: MnTable, isStandalone: true, selector: "mn-table", inputs: { dataSource: "dataSource" }, outputs: { sortChange: "sortChange", selectionChange: "selectionChange", rowClick: "rowClick" }, ngImport: i0, template: "<!-- Toolbar: search + custom toolbar template -->\n<div class=\"flex flex-row items-center justify-end gap-2 mb-3\">\n @if (dataSource.canSearch) {\n <div>\n <input\n type=\"text\"\n class=\"input input-sm rounded border border-base-300 bg-base-200 px-3 py-1.5 text-sm text-base-content placeholder-base-content/50 focus:outline-none focus:border-brand-500 w-full max-w-xs\"\n [placeholder]=\"dataSource.searchPlaceholder ?? 'Search...'\"\n (input)=\"onSearch($any($event.target).value)\"\n aria-label=\"Search table\"\n />\n </div>\n }\n @if (dataSource.toolbarTemplate) {\n <ng-container [ngTemplateOutlet]=\"dataSource.toolbarTemplate\"></ng-container>\n }\n</div>\n\n<!-- Table wrapper with horizontal scroll -->\n<div class=\"overflow-x-auto\" role=\"region\" aria-label=\"Data table\">\n <table [class]=\"tableClasses\">\n <thead>\n <tr class=\"bg-base-100\">\n <!-- Selection checkbox column header -->\n @if (hasSelection) {\n <th class=\"w-10 text-center text-sm bg-base-200 px-2 py-2\">\n @if (isMultiSelect) {\n <label>\n <input\n type=\"checkbox\"\n class=\"accent-brand-500\"\n [checked]=\"allSelected\"\n (change)=\"toggleAll()\"\n aria-label=\"Select all rows\"\n />\n </label>\n }\n </th>\n }\n\n <!-- Data columns -->\n @for (column of dataSource.columns; track column.key) {\n <th\n class=\"text-sm px-4 py-2\"\n [class.cursor-pointer]=\"isSortable(column)\"\n [class.select-none]=\"isSortable(column)\"\n [class.hover:bg-base-200]=\"isSortable(column)\"\n [class.text-left]=\"(column.align ?? 'left') === 'left'\"\n [class.text-center]=\"column.align === 'center'\"\n [class.text-right]=\"column.align === 'right'\"\n [class.hidden]=\"column.hiddenBelow === 'sm' || column.hiddenBelow === 'md' || column.hiddenBelow === 'lg'\"\n [class.sm:table-cell]=\"column.hiddenBelow === 'sm'\"\n [class.md:table-cell]=\"column.hiddenBelow === 'md'\"\n [class.lg:table-cell]=\"column.hiddenBelow === 'lg'\"\n [style.width]=\"column.width ?? null\"\n [attr.aria-sort]=\"currentSort?.columnKey === column.key ? (currentSort!.direction === 'asc' ? 'ascending' : 'descending') : null\"\n (click)=\"sort(column)\"\n >\n <span class=\"inline-flex items-center gap-1\">\n @if (isTemplateRef(column.header)) {\n <ng-container [ngTemplateOutlet]=\"$any(column.header)\"></ng-container>\n } @else {\n <span>{{ column.header }}</span>\n }\n @if (isSortable(column)) {\n <span class=\"text-[0.65rem] opacity-70 min-w-3 inline-block\">{{ getSortIcon(column) }}</span>\n }\n </span>\n </th>\n }\n\n </tr>\n\n <!-- Per-column filter row -->\n @if (hasColumnFilters) {\n <tr class=\"bg-base-100 border-b border-base-300\">\n @if (hasSelection) {\n <th class=\"px-2 py-1\"></th>\n }\n @for (column of dataSource.columns; track column.key) {\n <th\n class=\"px-4 py-1\"\n [class.hidden]=\"column.hiddenBelow === 'sm' || column.hiddenBelow === 'md' || column.hiddenBelow === 'lg'\"\n [class.sm:table-cell]=\"column.hiddenBelow === 'sm'\"\n [class.md:table-cell]=\"column.hiddenBelow === 'md'\"\n [class.lg:table-cell]=\"column.hiddenBelow === 'lg'\"\n >\n @if (column.filterable) {\n @if ((column.filterType ?? 'text') === 'text') {\n <input\n type=\"text\"\n class=\"input input-xs rounded border border-base-300 bg-base-200 px-2 py-1 text-xs text-base-content placeholder-base-content/50 focus:outline-none focus:border-brand-500 w-full\"\n [placeholder]=\"column.filterPlaceholder ?? ''\"\n [value]=\"columnFilters[column.key]\"\n [disabled]=\"column.filterDisabled ?? false\"\n [attr.autocomplete]=\"column.filterAutocomplete ?? null\"\n [attr.maxlength]=\"column.filterMaxLength ?? null\"\n (input)=\"onColumnFilter(column.key, $any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"'Filter ' + column.key\"\n />\n } @else if (column.filterType === 'select') {\n <select\n class=\"select select-xs rounded border border-base-300 bg-base-200 px-2 py-1 text-xs text-base-content focus:outline-none focus:border-brand-500 w-full\"\n [value]=\"columnFilters[column.key]\"\n [disabled]=\"column.filterDisabled ?? false\"\n (change)=\"onColumnFilter(column.key, $any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"'Filter ' + column.key\"\n >\n <option value=\"\">{{ column.filterPlaceholder ?? 'All' }}</option>\n @for (opt of column.filterOptions ?? []; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n }\n </th>\n }\n </tr>\n }\n </thead>\n\n <tbody>\n <!-- Loading state -->\n @if (dataSource.isDataLoading) {\n @for (_ of skeletonRows; track $index) {\n <tr class=\"animate-pulse\">\n @if (hasSelection) {\n <td class=\"px-2 py-3\"><div class=\"h-4 w-4 rounded bg-base-300\"></div></td>\n }\n @for (column of dataSource.columns; track column.key) {\n <td class=\"px-4 py-3\"\n [class.hidden]=\"column.hiddenBelow === 'sm' || column.hiddenBelow === 'md' || column.hiddenBelow === 'lg'\"\n [class.sm:table-cell]=\"column.hiddenBelow === 'sm'\"\n [class.md:table-cell]=\"column.hiddenBelow === 'md'\"\n [class.lg:table-cell]=\"column.hiddenBelow === 'lg'\"\n >\n <div class=\"h-4 w-3/4 rounded bg-base-300\"></div>\n </td>\n }\n </tr>\n }\n } @else {\n <!-- Empty state -->\n @if (filteredItems.length === 0) {\n <tr class=\"bg-base-100\">\n <td [attr.colspan]=\"totalColumnCount\" class=\"text-center text-xs py-8\">\n @if (dataSource.emptyTemplate) {\n <ng-container [ngTemplateOutlet]=\"dataSource.emptyTemplate\"></ng-container>\n } @else {\n <div class=\"flex flex-col items-center gap-2 text-base-content/50\">\n <p class=\"text-sm\">{{ dataSource.emptyMessage }}</p>\n </div>\n }\n </td>\n </tr>\n }\n\n <!-- Data rows -->\n @for (row of paginatedItems; track trackByID($index, row); let odd = $odd; let last = $last) {\n <tr\n class=\"bg-base-100 transition-colors duration-150\"\n [class.bg-brand-50]=\"isSelected(row)\"\n [class.bg-base-200]=\"!isSelected(row) && odd && dataSource.appearance?.striped\"\n [class.hover:bg-base-200]=\"dataSource.appearance?.hover !== false\"\n [class.cursor-pointer]=\"!!dataSource.onRowClick\"\n [class.border-b]=\"!last\"\n [class.border-base-300]=\"!last\"\n [class.border-b-1]=\"last\"\n [class.border-black]=\"last\"\n [class.shadow-3xl]=\"last\"\n (click)=\"onRowClick(row)\"\n >\n <!-- Selection checkbox -->\n @if (hasSelection) {\n <td class=\"w-10 text-center px-2 py-2\">\n <label>\n @if (isMultiSelect) {\n <input\n type=\"checkbox\"\n class=\"accent-brand-500\"\n [checked]=\"isSelected(row)\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n />\n } @else {\n <input\n type=\"radio\"\n class=\"accent-brand-500\"\n [checked]=\"isSelected(row)\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n name=\"mn-table-single-select\"\n />\n }\n </label>\n </td>\n }\n\n <!-- Data cells -->\n @for (column of dataSource.columns; track column.key) {\n <td\n class=\"text-xs px-4 py-2\"\n [class.text-left]=\"(column.align ?? 'left') === 'left'\"\n [class.text-center]=\"column.align === 'center'\"\n [class.text-right]=\"column.align === 'right'\"\n [class.hidden]=\"column.hiddenBelow === 'sm' || column.hiddenBelow === 'md' || column.hiddenBelow === 'lg'\"\n [class.sm:table-cell]=\"column.hiddenBelow === 'sm'\"\n [class.md:table-cell]=\"column.hiddenBelow === 'md'\"\n [class.lg:table-cell]=\"column.hiddenBelow === 'lg'\"\n [style.width]=\"column.width ?? null\"\n >\n @if (isTemplateRef(column.cell)) {\n <ng-container [ngTemplateOutlet]=\"$any(column.cell)\" [ngTemplateOutletContext]=\"{ $implicit: row, data: row }\"></ng-container>\n } @else {\n {{ getCellValue(column, row) }}\n }\n </td>\n }\n\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n<!-- Load more button -->\n@if (showLoadMore) {\n <div class=\"flex justify-center py-4\">\n <button\n class=\"px-4 py-1.5 text-sm rounded border border-brand-500 text-brand-500 hover:bg-brand-100 transition-colors disabled:opacity-50\"\n (click)=\"loadMoreRows()\"\n [disabled]=\"loadingMoreRows\"\n >\n @if (loadingMoreRows) {\n <span class=\"inline-block w-3 h-3 border-2 border-brand-500 border-t-transparent rounded-full animate-spin mr-2\"></span>\n }\n Load more\n </button>\n </div>\n}\n\n<!-- Pagination controls -->\n@if (isPaginated && totalPages > 1) {\n <div class=\"flex items-center justify-between px-2 py-3 text-sm text-base-content\">\n <div class=\"flex items-center gap-2\">\n <span>Rows per page:</span>\n <select\n class=\"select select-xs rounded border border-base-300 bg-base-200 px-2 py-1 text-xs focus:outline-none focus:border-brand-500\"\n [value]=\"pageSize\"\n (change)=\"onPageSizeChange(+$any($event.target).value)\"\n aria-label=\"Rows per page\"\n >\n @for (opt of resolvedPageSizeOptions; track opt) {\n <option [value]=\"opt\" [selected]=\"opt === pageSize\">{{ opt }}</option>\n }\n </select>\n </div>\n\n <div class=\"flex items-center gap-1\">\n <span class=\"text-xs mr-2\">{{ (currentPage - 1) * pageSize + 1 }}\u2013{{ currentPage * pageSize > filteredItems.length ? filteredItems.length : currentPage * pageSize }} of {{ filteredItems.length }}</span>\n\n <button\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n [disabled]=\"currentPage === 1\"\n (click)=\"goToPage(1)\"\n aria-label=\"First page\"\n >\u00AB</button>\n\n <button\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n [disabled]=\"currentPage === 1\"\n (click)=\"goToPage(currentPage - 1)\"\n aria-label=\"Previous page\"\n >\u2039</button>\n\n @for (page of visiblePages; track page) {\n <button\n class=\"px-2.5 py-1 rounded border transition-colors text-xs\"\n [class.border-brand-500]=\"page === currentPage\"\n [class.bg-brand-500]=\"page === currentPage\"\n [class.text-white]=\"page === currentPage\"\n [class.border-base-300]=\"page !== currentPage\"\n [class.hover:bg-base-200]=\"page !== currentPage\"\n (click)=\"goToPage(page)\"\n [attr.aria-label]=\"'Page ' + page\"\n [attr.aria-current]=\"page === currentPage ? 'page' : null\"\n >{{ page }}</button>\n }\n\n <button\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n [disabled]=\"currentPage === totalPages\"\n (click)=\"goToPage(currentPage + 1)\"\n aria-label=\"Next page\"\n >\u203A</button>\n\n <button\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n [disabled]=\"currentPage === totalPages\"\n (click)=\"goToPage(totalPages)\"\n aria-label=\"Last page\"\n >\u00BB</button>\n </div>\n </div>\n}\n", styles: [""], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3659
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: MnTable, isStandalone: true, selector: "mn-table", inputs: { dataSource: "dataSource" }, outputs: { sortChange: "sortChange", selectionChange: "selectionChange", rowClick: "rowClick" }, ngImport: i0, template: "<!-- Toolbar: search + custom toolbar template -->\n<div class=\"flex flex-row items-center justify-end gap-2 mb-3\">\n @if (dataSource.canSearch) {\n <div>\n <input\n type=\"text\"\n class=\"input input-sm rounded border border-base-300 bg-base-200 px-3 py-1.5 text-sm text-base-content placeholder-base-content/50 focus:outline-none focus:border-brand-500 w-full max-w-xs\"\n [placeholder]=\"dataSource.searchPlaceholder ?? 'Search...'\"\n (input)=\"onSearch($any($event.target).value)\"\n aria-label=\"Search table\"\n />\n </div>\n }\n @if (dataSource.toolbarTemplate) {\n <ng-container [ngTemplateOutlet]=\"dataSource.toolbarTemplate\"></ng-container>\n }\n</div>\n\n<!-- Table wrapper with horizontal scroll -->\n<div class=\"overflow-x-auto\" role=\"region\" aria-label=\"Data table\">\n <table [class]=\"tableClasses\">\n <thead>\n <tr class=\"bg-base-100\">\n <!-- Selection checkbox column header -->\n @if (hasSelection) {\n <th class=\"w-10 text-center text-sm bg-base-200 px-2 py-2\">\n @if (isMultiSelect) {\n <label>\n <input\n type=\"checkbox\"\n class=\"checkbox checkbox-sm checkbox-primary\"\n [checked]=\"allSelected\"\n (change)=\"toggleAll()\"\n aria-label=\"Select all rows\"\n />\n </label>\n }\n </th>\n }\n\n <!-- Data columns -->\n @for (column of dataSource.columns; track column.key) {\n <th\n class=\"text-sm px-4 py-2\"\n [class.cursor-pointer]=\"isSortable(column)\"\n [class.select-none]=\"isSortable(column)\"\n [class.hover:bg-base-200]=\"isSortable(column)\"\n [class.text-left]=\"(column.align ?? 'left') === 'left'\"\n [class.text-center]=\"column.align === 'center'\"\n [class.text-right]=\"column.align === 'right'\"\n [class.hidden]=\"column.hiddenBelow === 'sm' || column.hiddenBelow === 'md' || column.hiddenBelow === 'lg'\"\n [class.sm:table-cell]=\"column.hiddenBelow === 'sm'\"\n [class.md:table-cell]=\"column.hiddenBelow === 'md'\"\n [class.lg:table-cell]=\"column.hiddenBelow === 'lg'\"\n [style.width]=\"column.width ?? null\"\n [attr.aria-sort]=\"currentSort?.columnKey === column.key ? (currentSort!.direction === 'asc' ? 'ascending' : 'descending') : null\"\n (click)=\"sort(column)\"\n >\n <span class=\"inline-flex items-center gap-1\">\n @if (isTemplateRef(column.header)) {\n <ng-container [ngTemplateOutlet]=\"$any(column.header)\"></ng-container>\n } @else {\n <span>{{ column.header }}</span>\n }\n @if (isSortable(column)) {\n <span class=\"text-[0.65rem] opacity-70 min-w-3 inline-block\">{{ getSortIcon(column) }}</span>\n }\n </span>\n </th>\n }\n\n </tr>\n\n <!-- Per-column filter row -->\n @if (hasColumnFilters) {\n <tr class=\"bg-base-100 border-b border-base-300\">\n @if (hasSelection) {\n <th class=\"px-2 py-1\"></th>\n }\n @for (column of dataSource.columns; track column.key) {\n <th\n class=\"px-4 py-1\"\n [class.hidden]=\"column.hiddenBelow === 'sm' || column.hiddenBelow === 'md' || column.hiddenBelow === 'lg'\"\n [class.sm:table-cell]=\"column.hiddenBelow === 'sm'\"\n [class.md:table-cell]=\"column.hiddenBelow === 'md'\"\n [class.lg:table-cell]=\"column.hiddenBelow === 'lg'\"\n >\n @if (column.filterable) {\n @if ((column.filterType ?? 'text') === 'text') {\n <input\n type=\"text\"\n class=\"input input-xs rounded border border-base-300 bg-base-200 px-2 py-1 text-xs text-base-content placeholder-base-content/50 focus:outline-none focus:border-brand-500 w-full\"\n [placeholder]=\"column.filterPlaceholder ?? ''\"\n [value]=\"columnFilters[column.key]\"\n [disabled]=\"column.filterDisabled ?? false\"\n [attr.autocomplete]=\"column.filterAutocomplete ?? null\"\n [attr.maxlength]=\"column.filterMaxLength ?? null\"\n (input)=\"onColumnFilter(column.key, $any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"'Filter ' + column.key\"\n />\n } @else if (column.filterType === 'select') {\n <select\n class=\"select select-xs rounded border border-base-300 bg-base-200 px-2 py-1 text-xs text-base-content focus:outline-none focus:border-brand-500 w-full\"\n [value]=\"columnFilters[column.key]\"\n [disabled]=\"column.filterDisabled ?? false\"\n (change)=\"onColumnFilter(column.key, $any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"'Filter ' + column.key\"\n >\n <option value=\"\">{{ column.filterPlaceholder ?? 'All' }}</option>\n @for (opt of column.filterOptions ?? []; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n }\n </th>\n }\n </tr>\n }\n </thead>\n\n <tbody>\n <!-- Loading state -->\n @if (dataSource.isDataLoading) {\n @for (_ of skeletonRows; track $index) {\n <tr class=\"animate-pulse\">\n @if (hasSelection) {\n <td class=\"px-2 py-3\"><div class=\"h-4 w-4 rounded bg-base-300\"></div></td>\n }\n @for (column of dataSource.columns; track column.key) {\n <td class=\"px-4 py-3\"\n [class.hidden]=\"column.hiddenBelow === 'sm' || column.hiddenBelow === 'md' || column.hiddenBelow === 'lg'\"\n [class.sm:table-cell]=\"column.hiddenBelow === 'sm'\"\n [class.md:table-cell]=\"column.hiddenBelow === 'md'\"\n [class.lg:table-cell]=\"column.hiddenBelow === 'lg'\"\n >\n <div class=\"h-4 w-3/4 rounded bg-base-300\"></div>\n </td>\n }\n </tr>\n }\n } @else {\n <!-- Empty state -->\n @if (filteredItems.length === 0) {\n <tr class=\"bg-base-100\">\n <td [attr.colspan]=\"totalColumnCount\" class=\"text-center text-xs py-8\">\n @if (dataSource.emptyTemplate) {\n <ng-container [ngTemplateOutlet]=\"dataSource.emptyTemplate\"></ng-container>\n } @else {\n <div class=\"flex flex-col items-center gap-2 text-base-content/50\">\n <p class=\"text-sm\">{{ dataSource.emptyMessage }}</p>\n </div>\n }\n </td>\n </tr>\n }\n\n <!-- Data rows -->\n @for (row of paginatedItems; track trackByID($index, row); let odd = $odd; let last = $last) {\n <tr\n class=\"bg-base-100 transition-colors duration-150\"\n [class.bg-brand-50]=\"isSelected(row)\"\n [class.bg-base-200]=\"!isSelected(row) && odd && dataSource.appearance?.striped\"\n [class.hover:bg-base-200]=\"dataSource.appearance?.hover !== false\"\n [class.cursor-pointer]=\"!!dataSource.onRowClick\"\n [class.border-b]=\"!last\"\n [class.border-base-300]=\"!last\"\n [class.border-b-1]=\"last\"\n [class.border-black]=\"last\"\n [class.shadow-3xl]=\"last\"\n (click)=\"onRowClick(row)\"\n >\n <!-- Selection checkbox -->\n @if (hasSelection) {\n <td class=\"w-10 text-center px-2 py-2\">\n <label>\n <input\n type=\"checkbox\"\n class=\"checkbox checkbox-sm checkbox-primary\"\n [checked]=\"isSelected(row)\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n />\n </label>\n </td>\n }\n\n <!-- Data cells -->\n @for (column of dataSource.columns; track column.key) {\n <td\n class=\"text-xs px-4 py-2\"\n [class.text-left]=\"(column.align ?? 'left') === 'left'\"\n [class.text-center]=\"column.align === 'center'\"\n [class.text-right]=\"column.align === 'right'\"\n [class.hidden]=\"column.hiddenBelow === 'sm' || column.hiddenBelow === 'md' || column.hiddenBelow === 'lg'\"\n [class.sm:table-cell]=\"column.hiddenBelow === 'sm'\"\n [class.md:table-cell]=\"column.hiddenBelow === 'md'\"\n [class.lg:table-cell]=\"column.hiddenBelow === 'lg'\"\n [style.width]=\"column.width ?? null\"\n >\n @if (isTemplateRef(column.cell)) {\n <ng-container [ngTemplateOutlet]=\"$any(column.cell)\" [ngTemplateOutletContext]=\"{ $implicit: row, data: row }\"></ng-container>\n } @else {\n {{ getCellValue(column, row) }}\n }\n </td>\n }\n\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n<!-- Load more button -->\n@if (showLoadMore) {\n <div class=\"flex justify-center py-4\">\n <button\n class=\"px-4 py-1.5 text-sm rounded border border-brand-500 text-brand-500 hover:bg-brand-100 transition-colors disabled:opacity-50\"\n (click)=\"loadMoreRows()\"\n [disabled]=\"loadingMoreRows\"\n >\n @if (loadingMoreRows) {\n <span class=\"inline-block w-3 h-3 border-2 border-brand-500 border-t-transparent rounded-full animate-spin mr-2\"></span>\n }\n Load more\n </button>\n </div>\n}\n\n<!-- Pagination controls -->\n@if (isPaginated && totalPages > 1) {\n <div class=\"flex items-center justify-between px-2 py-3 text-sm text-base-content\">\n <div class=\"flex items-center gap-2\">\n <span>Rows per page:</span>\n <select\n class=\"select select-xs rounded border border-base-300 bg-base-200 px-2 py-1 text-xs focus:outline-none focus:border-brand-500\"\n [value]=\"pageSize\"\n (change)=\"onPageSizeChange(+$any($event.target).value)\"\n aria-label=\"Rows per page\"\n >\n @for (opt of resolvedPageSizeOptions; track opt) {\n <option [value]=\"opt\" [selected]=\"opt === pageSize\">{{ opt }}</option>\n }\n </select>\n </div>\n\n <div class=\"flex items-center gap-1\">\n <span class=\"text-xs mr-2\">{{ (currentPage - 1) * pageSize + 1 }}\u2013{{ currentPage * pageSize > filteredItems.length ? filteredItems.length : currentPage * pageSize }} of {{ filteredItems.length }}</span>\n\n <button\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n [disabled]=\"currentPage === 1\"\n (click)=\"goToPage(1)\"\n aria-label=\"First page\"\n >\u00AB</button>\n\n <button\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n [disabled]=\"currentPage === 1\"\n (click)=\"goToPage(currentPage - 1)\"\n aria-label=\"Previous page\"\n >\u2039</button>\n\n @for (page of visiblePages; track page) {\n <button\n class=\"px-2.5 py-1 rounded border transition-colors text-xs\"\n [class.border-brand-500]=\"page === currentPage\"\n [class.bg-brand-500]=\"page === currentPage\"\n [class.text-white]=\"page === currentPage\"\n [class.border-base-300]=\"page !== currentPage\"\n [class.hover:bg-base-200]=\"page !== currentPage\"\n (click)=\"goToPage(page)\"\n [attr.aria-label]=\"'Page ' + page\"\n [attr.aria-current]=\"page === currentPage ? 'page' : null\"\n >{{ page }}</button>\n }\n\n <button\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n [disabled]=\"currentPage === totalPages\"\n (click)=\"goToPage(currentPage + 1)\"\n aria-label=\"Next page\"\n >\u203A</button>\n\n <button\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n [disabled]=\"currentPage === totalPages\"\n (click)=\"goToPage(totalPages)\"\n aria-label=\"Last page\"\n >\u00BB</button>\n </div>\n </div>\n}\n", styles: [""], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
3660
3660
|
}
|
|
3661
3661
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: MnTable, decorators: [{
|
|
3662
3662
|
type: Component,
|
|
3663
|
-
args: [{ selector: 'mn-table', standalone: true, imports: [NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Toolbar: search + custom toolbar template -->\n<div class=\"flex flex-row items-center justify-end gap-2 mb-3\">\n @if (dataSource.canSearch) {\n <div>\n <input\n type=\"text\"\n class=\"input input-sm rounded border border-base-300 bg-base-200 px-3 py-1.5 text-sm text-base-content placeholder-base-content/50 focus:outline-none focus:border-brand-500 w-full max-w-xs\"\n [placeholder]=\"dataSource.searchPlaceholder ?? 'Search...'\"\n (input)=\"onSearch($any($event.target).value)\"\n aria-label=\"Search table\"\n />\n </div>\n }\n @if (dataSource.toolbarTemplate) {\n <ng-container [ngTemplateOutlet]=\"dataSource.toolbarTemplate\"></ng-container>\n }\n</div>\n\n<!-- Table wrapper with horizontal scroll -->\n<div class=\"overflow-x-auto\" role=\"region\" aria-label=\"Data table\">\n <table [class]=\"tableClasses\">\n <thead>\n <tr class=\"bg-base-100\">\n <!-- Selection checkbox column header -->\n @if (hasSelection) {\n <th class=\"w-10 text-center text-sm bg-base-200 px-2 py-2\">\n @if (isMultiSelect) {\n <label>\n <input\n type=\"checkbox\"\n class=\"accent-brand-500\"\n [checked]=\"allSelected\"\n (change)=\"toggleAll()\"\n aria-label=\"Select all rows\"\n />\n </label>\n }\n </th>\n }\n\n <!-- Data columns -->\n @for (column of dataSource.columns; track column.key) {\n <th\n class=\"text-sm px-4 py-2\"\n [class.cursor-pointer]=\"isSortable(column)\"\n [class.select-none]=\"isSortable(column)\"\n [class.hover:bg-base-200]=\"isSortable(column)\"\n [class.text-left]=\"(column.align ?? 'left') === 'left'\"\n [class.text-center]=\"column.align === 'center'\"\n [class.text-right]=\"column.align === 'right'\"\n [class.hidden]=\"column.hiddenBelow === 'sm' || column.hiddenBelow === 'md' || column.hiddenBelow === 'lg'\"\n [class.sm:table-cell]=\"column.hiddenBelow === 'sm'\"\n [class.md:table-cell]=\"column.hiddenBelow === 'md'\"\n [class.lg:table-cell]=\"column.hiddenBelow === 'lg'\"\n [style.width]=\"column.width ?? null\"\n [attr.aria-sort]=\"currentSort?.columnKey === column.key ? (currentSort!.direction === 'asc' ? 'ascending' : 'descending') : null\"\n (click)=\"sort(column)\"\n >\n <span class=\"inline-flex items-center gap-1\">\n @if (isTemplateRef(column.header)) {\n <ng-container [ngTemplateOutlet]=\"$any(column.header)\"></ng-container>\n } @else {\n <span>{{ column.header }}</span>\n }\n @if (isSortable(column)) {\n <span class=\"text-[0.65rem] opacity-70 min-w-3 inline-block\">{{ getSortIcon(column) }}</span>\n }\n </span>\n </th>\n }\n\n </tr>\n\n <!-- Per-column filter row -->\n @if (hasColumnFilters) {\n <tr class=\"bg-base-100 border-b border-base-300\">\n @if (hasSelection) {\n <th class=\"px-2 py-1\"></th>\n }\n @for (column of dataSource.columns; track column.key) {\n <th\n class=\"px-4 py-1\"\n [class.hidden]=\"column.hiddenBelow === 'sm' || column.hiddenBelow === 'md' || column.hiddenBelow === 'lg'\"\n [class.sm:table-cell]=\"column.hiddenBelow === 'sm'\"\n [class.md:table-cell]=\"column.hiddenBelow === 'md'\"\n [class.lg:table-cell]=\"column.hiddenBelow === 'lg'\"\n >\n @if (column.filterable) {\n @if ((column.filterType ?? 'text') === 'text') {\n <input\n type=\"text\"\n class=\"input input-xs rounded border border-base-300 bg-base-200 px-2 py-1 text-xs text-base-content placeholder-base-content/50 focus:outline-none focus:border-brand-500 w-full\"\n [placeholder]=\"column.filterPlaceholder ?? ''\"\n [value]=\"columnFilters[column.key]\"\n [disabled]=\"column.filterDisabled ?? false\"\n [attr.autocomplete]=\"column.filterAutocomplete ?? null\"\n [attr.maxlength]=\"column.filterMaxLength ?? null\"\n (input)=\"onColumnFilter(column.key, $any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"'Filter ' + column.key\"\n />\n } @else if (column.filterType === 'select') {\n <select\n class=\"select select-xs rounded border border-base-300 bg-base-200 px-2 py-1 text-xs text-base-content focus:outline-none focus:border-brand-500 w-full\"\n [value]=\"columnFilters[column.key]\"\n [disabled]=\"column.filterDisabled ?? false\"\n (change)=\"onColumnFilter(column.key, $any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"'Filter ' + column.key\"\n >\n <option value=\"\">{{ column.filterPlaceholder ?? 'All' }}</option>\n @for (opt of column.filterOptions ?? []; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n }\n </th>\n }\n </tr>\n }\n </thead>\n\n <tbody>\n <!-- Loading state -->\n @if (dataSource.isDataLoading) {\n @for (_ of skeletonRows; track $index) {\n <tr class=\"animate-pulse\">\n @if (hasSelection) {\n <td class=\"px-2 py-3\"><div class=\"h-4 w-4 rounded bg-base-300\"></div></td>\n }\n @for (column of dataSource.columns; track column.key) {\n <td class=\"px-4 py-3\"\n [class.hidden]=\"column.hiddenBelow === 'sm' || column.hiddenBelow === 'md' || column.hiddenBelow === 'lg'\"\n [class.sm:table-cell]=\"column.hiddenBelow === 'sm'\"\n [class.md:table-cell]=\"column.hiddenBelow === 'md'\"\n [class.lg:table-cell]=\"column.hiddenBelow === 'lg'\"\n >\n <div class=\"h-4 w-3/4 rounded bg-base-300\"></div>\n </td>\n }\n </tr>\n }\n } @else {\n <!-- Empty state -->\n @if (filteredItems.length === 0) {\n <tr class=\"bg-base-100\">\n <td [attr.colspan]=\"totalColumnCount\" class=\"text-center text-xs py-8\">\n @if (dataSource.emptyTemplate) {\n <ng-container [ngTemplateOutlet]=\"dataSource.emptyTemplate\"></ng-container>\n } @else {\n <div class=\"flex flex-col items-center gap-2 text-base-content/50\">\n <p class=\"text-sm\">{{ dataSource.emptyMessage }}</p>\n </div>\n }\n </td>\n </tr>\n }\n\n <!-- Data rows -->\n @for (row of paginatedItems; track trackByID($index, row); let odd = $odd; let last = $last) {\n <tr\n class=\"bg-base-100 transition-colors duration-150\"\n [class.bg-brand-50]=\"isSelected(row)\"\n [class.bg-base-200]=\"!isSelected(row) && odd && dataSource.appearance?.striped\"\n [class.hover:bg-base-200]=\"dataSource.appearance?.hover !== false\"\n [class.cursor-pointer]=\"!!dataSource.onRowClick\"\n [class.border-b]=\"!last\"\n [class.border-base-300]=\"!last\"\n [class.border-b-1]=\"last\"\n [class.border-black]=\"last\"\n [class.shadow-3xl]=\"last\"\n (click)=\"onRowClick(row)\"\n >\n <!-- Selection checkbox -->\n @if (hasSelection) {\n <td class=\"w-10 text-center px-2 py-2\">\n <label>\n @if (isMultiSelect) {\n <input\n type=\"checkbox\"\n class=\"accent-brand-500\"\n [checked]=\"isSelected(row)\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n />\n } @else {\n <input\n type=\"radio\"\n class=\"accent-brand-500\"\n [checked]=\"isSelected(row)\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n name=\"mn-table-single-select\"\n />\n }\n </label>\n </td>\n }\n\n <!-- Data cells -->\n @for (column of dataSource.columns; track column.key) {\n <td\n class=\"text-xs px-4 py-2\"\n [class.text-left]=\"(column.align ?? 'left') === 'left'\"\n [class.text-center]=\"column.align === 'center'\"\n [class.text-right]=\"column.align === 'right'\"\n [class.hidden]=\"column.hiddenBelow === 'sm' || column.hiddenBelow === 'md' || column.hiddenBelow === 'lg'\"\n [class.sm:table-cell]=\"column.hiddenBelow === 'sm'\"\n [class.md:table-cell]=\"column.hiddenBelow === 'md'\"\n [class.lg:table-cell]=\"column.hiddenBelow === 'lg'\"\n [style.width]=\"column.width ?? null\"\n >\n @if (isTemplateRef(column.cell)) {\n <ng-container [ngTemplateOutlet]=\"$any(column.cell)\" [ngTemplateOutletContext]=\"{ $implicit: row, data: row }\"></ng-container>\n } @else {\n {{ getCellValue(column, row) }}\n }\n </td>\n }\n\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n<!-- Load more button -->\n@if (showLoadMore) {\n <div class=\"flex justify-center py-4\">\n <button\n class=\"px-4 py-1.5 text-sm rounded border border-brand-500 text-brand-500 hover:bg-brand-100 transition-colors disabled:opacity-50\"\n (click)=\"loadMoreRows()\"\n [disabled]=\"loadingMoreRows\"\n >\n @if (loadingMoreRows) {\n <span class=\"inline-block w-3 h-3 border-2 border-brand-500 border-t-transparent rounded-full animate-spin mr-2\"></span>\n }\n Load more\n </button>\n </div>\n}\n\n<!-- Pagination controls -->\n@if (isPaginated && totalPages > 1) {\n <div class=\"flex items-center justify-between px-2 py-3 text-sm text-base-content\">\n <div class=\"flex items-center gap-2\">\n <span>Rows per page:</span>\n <select\n class=\"select select-xs rounded border border-base-300 bg-base-200 px-2 py-1 text-xs focus:outline-none focus:border-brand-500\"\n [value]=\"pageSize\"\n (change)=\"onPageSizeChange(+$any($event.target).value)\"\n aria-label=\"Rows per page\"\n >\n @for (opt of resolvedPageSizeOptions; track opt) {\n <option [value]=\"opt\" [selected]=\"opt === pageSize\">{{ opt }}</option>\n }\n </select>\n </div>\n\n <div class=\"flex items-center gap-1\">\n <span class=\"text-xs mr-2\">{{ (currentPage - 1) * pageSize + 1 }}\u2013{{ currentPage * pageSize > filteredItems.length ? filteredItems.length : currentPage * pageSize }} of {{ filteredItems.length }}</span>\n\n <button\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n [disabled]=\"currentPage === 1\"\n (click)=\"goToPage(1)\"\n aria-label=\"First page\"\n >\u00AB</button>\n\n <button\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n [disabled]=\"currentPage === 1\"\n (click)=\"goToPage(currentPage - 1)\"\n aria-label=\"Previous page\"\n >\u2039</button>\n\n @for (page of visiblePages; track page) {\n <button\n class=\"px-2.5 py-1 rounded border transition-colors text-xs\"\n [class.border-brand-500]=\"page === currentPage\"\n [class.bg-brand-500]=\"page === currentPage\"\n [class.text-white]=\"page === currentPage\"\n [class.border-base-300]=\"page !== currentPage\"\n [class.hover:bg-base-200]=\"page !== currentPage\"\n (click)=\"goToPage(page)\"\n [attr.aria-label]=\"'Page ' + page\"\n [attr.aria-current]=\"page === currentPage ? 'page' : null\"\n >{{ page }}</button>\n }\n\n <button\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n [disabled]=\"currentPage === totalPages\"\n (click)=\"goToPage(currentPage + 1)\"\n aria-label=\"Next page\"\n >\u203A</button>\n\n <button\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n [disabled]=\"currentPage === totalPages\"\n (click)=\"goToPage(totalPages)\"\n aria-label=\"Last page\"\n >\u00BB</button>\n </div>\n </div>\n}\n" }]
|
|
3663
|
+
args: [{ selector: 'mn-table', standalone: true, imports: [NgTemplateOutlet], changeDetection: ChangeDetectionStrategy.OnPush, template: "<!-- Toolbar: search + custom toolbar template -->\n<div class=\"flex flex-row items-center justify-end gap-2 mb-3\">\n @if (dataSource.canSearch) {\n <div>\n <input\n type=\"text\"\n class=\"input input-sm rounded border border-base-300 bg-base-200 px-3 py-1.5 text-sm text-base-content placeholder-base-content/50 focus:outline-none focus:border-brand-500 w-full max-w-xs\"\n [placeholder]=\"dataSource.searchPlaceholder ?? 'Search...'\"\n (input)=\"onSearch($any($event.target).value)\"\n aria-label=\"Search table\"\n />\n </div>\n }\n @if (dataSource.toolbarTemplate) {\n <ng-container [ngTemplateOutlet]=\"dataSource.toolbarTemplate\"></ng-container>\n }\n</div>\n\n<!-- Table wrapper with horizontal scroll -->\n<div class=\"overflow-x-auto\" role=\"region\" aria-label=\"Data table\">\n <table [class]=\"tableClasses\">\n <thead>\n <tr class=\"bg-base-100\">\n <!-- Selection checkbox column header -->\n @if (hasSelection) {\n <th class=\"w-10 text-center text-sm bg-base-200 px-2 py-2\">\n @if (isMultiSelect) {\n <label>\n <input\n type=\"checkbox\"\n class=\"checkbox checkbox-sm checkbox-primary\"\n [checked]=\"allSelected\"\n (change)=\"toggleAll()\"\n aria-label=\"Select all rows\"\n />\n </label>\n }\n </th>\n }\n\n <!-- Data columns -->\n @for (column of dataSource.columns; track column.key) {\n <th\n class=\"text-sm px-4 py-2\"\n [class.cursor-pointer]=\"isSortable(column)\"\n [class.select-none]=\"isSortable(column)\"\n [class.hover:bg-base-200]=\"isSortable(column)\"\n [class.text-left]=\"(column.align ?? 'left') === 'left'\"\n [class.text-center]=\"column.align === 'center'\"\n [class.text-right]=\"column.align === 'right'\"\n [class.hidden]=\"column.hiddenBelow === 'sm' || column.hiddenBelow === 'md' || column.hiddenBelow === 'lg'\"\n [class.sm:table-cell]=\"column.hiddenBelow === 'sm'\"\n [class.md:table-cell]=\"column.hiddenBelow === 'md'\"\n [class.lg:table-cell]=\"column.hiddenBelow === 'lg'\"\n [style.width]=\"column.width ?? null\"\n [attr.aria-sort]=\"currentSort?.columnKey === column.key ? (currentSort!.direction === 'asc' ? 'ascending' : 'descending') : null\"\n (click)=\"sort(column)\"\n >\n <span class=\"inline-flex items-center gap-1\">\n @if (isTemplateRef(column.header)) {\n <ng-container [ngTemplateOutlet]=\"$any(column.header)\"></ng-container>\n } @else {\n <span>{{ column.header }}</span>\n }\n @if (isSortable(column)) {\n <span class=\"text-[0.65rem] opacity-70 min-w-3 inline-block\">{{ getSortIcon(column) }}</span>\n }\n </span>\n </th>\n }\n\n </tr>\n\n <!-- Per-column filter row -->\n @if (hasColumnFilters) {\n <tr class=\"bg-base-100 border-b border-base-300\">\n @if (hasSelection) {\n <th class=\"px-2 py-1\"></th>\n }\n @for (column of dataSource.columns; track column.key) {\n <th\n class=\"px-4 py-1\"\n [class.hidden]=\"column.hiddenBelow === 'sm' || column.hiddenBelow === 'md' || column.hiddenBelow === 'lg'\"\n [class.sm:table-cell]=\"column.hiddenBelow === 'sm'\"\n [class.md:table-cell]=\"column.hiddenBelow === 'md'\"\n [class.lg:table-cell]=\"column.hiddenBelow === 'lg'\"\n >\n @if (column.filterable) {\n @if ((column.filterType ?? 'text') === 'text') {\n <input\n type=\"text\"\n class=\"input input-xs rounded border border-base-300 bg-base-200 px-2 py-1 text-xs text-base-content placeholder-base-content/50 focus:outline-none focus:border-brand-500 w-full\"\n [placeholder]=\"column.filterPlaceholder ?? ''\"\n [value]=\"columnFilters[column.key]\"\n [disabled]=\"column.filterDisabled ?? false\"\n [attr.autocomplete]=\"column.filterAutocomplete ?? null\"\n [attr.maxlength]=\"column.filterMaxLength ?? null\"\n (input)=\"onColumnFilter(column.key, $any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"'Filter ' + column.key\"\n />\n } @else if (column.filterType === 'select') {\n <select\n class=\"select select-xs rounded border border-base-300 bg-base-200 px-2 py-1 text-xs text-base-content focus:outline-none focus:border-brand-500 w-full\"\n [value]=\"columnFilters[column.key]\"\n [disabled]=\"column.filterDisabled ?? false\"\n (change)=\"onColumnFilter(column.key, $any($event.target).value)\"\n (click)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"'Filter ' + column.key\"\n >\n <option value=\"\">{{ column.filterPlaceholder ?? 'All' }}</option>\n @for (opt of column.filterOptions ?? []; track opt.value) {\n <option [value]=\"opt.value\">{{ opt.label }}</option>\n }\n </select>\n }\n }\n </th>\n }\n </tr>\n }\n </thead>\n\n <tbody>\n <!-- Loading state -->\n @if (dataSource.isDataLoading) {\n @for (_ of skeletonRows; track $index) {\n <tr class=\"animate-pulse\">\n @if (hasSelection) {\n <td class=\"px-2 py-3\"><div class=\"h-4 w-4 rounded bg-base-300\"></div></td>\n }\n @for (column of dataSource.columns; track column.key) {\n <td class=\"px-4 py-3\"\n [class.hidden]=\"column.hiddenBelow === 'sm' || column.hiddenBelow === 'md' || column.hiddenBelow === 'lg'\"\n [class.sm:table-cell]=\"column.hiddenBelow === 'sm'\"\n [class.md:table-cell]=\"column.hiddenBelow === 'md'\"\n [class.lg:table-cell]=\"column.hiddenBelow === 'lg'\"\n >\n <div class=\"h-4 w-3/4 rounded bg-base-300\"></div>\n </td>\n }\n </tr>\n }\n } @else {\n <!-- Empty state -->\n @if (filteredItems.length === 0) {\n <tr class=\"bg-base-100\">\n <td [attr.colspan]=\"totalColumnCount\" class=\"text-center text-xs py-8\">\n @if (dataSource.emptyTemplate) {\n <ng-container [ngTemplateOutlet]=\"dataSource.emptyTemplate\"></ng-container>\n } @else {\n <div class=\"flex flex-col items-center gap-2 text-base-content/50\">\n <p class=\"text-sm\">{{ dataSource.emptyMessage }}</p>\n </div>\n }\n </td>\n </tr>\n }\n\n <!-- Data rows -->\n @for (row of paginatedItems; track trackByID($index, row); let odd = $odd; let last = $last) {\n <tr\n class=\"bg-base-100 transition-colors duration-150\"\n [class.bg-brand-50]=\"isSelected(row)\"\n [class.bg-base-200]=\"!isSelected(row) && odd && dataSource.appearance?.striped\"\n [class.hover:bg-base-200]=\"dataSource.appearance?.hover !== false\"\n [class.cursor-pointer]=\"!!dataSource.onRowClick\"\n [class.border-b]=\"!last\"\n [class.border-base-300]=\"!last\"\n [class.border-b-1]=\"last\"\n [class.border-black]=\"last\"\n [class.shadow-3xl]=\"last\"\n (click)=\"onRowClick(row)\"\n >\n <!-- Selection checkbox -->\n @if (hasSelection) {\n <td class=\"w-10 text-center px-2 py-2\">\n <label>\n <input\n type=\"checkbox\"\n class=\"checkbox checkbox-sm checkbox-primary\"\n [checked]=\"isSelected(row)\"\n (click)=\"$event.stopPropagation()\"\n (change)=\"toggleRow(row)\"\n />\n </label>\n </td>\n }\n\n <!-- Data cells -->\n @for (column of dataSource.columns; track column.key) {\n <td\n class=\"text-xs px-4 py-2\"\n [class.text-left]=\"(column.align ?? 'left') === 'left'\"\n [class.text-center]=\"column.align === 'center'\"\n [class.text-right]=\"column.align === 'right'\"\n [class.hidden]=\"column.hiddenBelow === 'sm' || column.hiddenBelow === 'md' || column.hiddenBelow === 'lg'\"\n [class.sm:table-cell]=\"column.hiddenBelow === 'sm'\"\n [class.md:table-cell]=\"column.hiddenBelow === 'md'\"\n [class.lg:table-cell]=\"column.hiddenBelow === 'lg'\"\n [style.width]=\"column.width ?? null\"\n >\n @if (isTemplateRef(column.cell)) {\n <ng-container [ngTemplateOutlet]=\"$any(column.cell)\" [ngTemplateOutletContext]=\"{ $implicit: row, data: row }\"></ng-container>\n } @else {\n {{ getCellValue(column, row) }}\n }\n </td>\n }\n\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n<!-- Load more button -->\n@if (showLoadMore) {\n <div class=\"flex justify-center py-4\">\n <button\n class=\"px-4 py-1.5 text-sm rounded border border-brand-500 text-brand-500 hover:bg-brand-100 transition-colors disabled:opacity-50\"\n (click)=\"loadMoreRows()\"\n [disabled]=\"loadingMoreRows\"\n >\n @if (loadingMoreRows) {\n <span class=\"inline-block w-3 h-3 border-2 border-brand-500 border-t-transparent rounded-full animate-spin mr-2\"></span>\n }\n Load more\n </button>\n </div>\n}\n\n<!-- Pagination controls -->\n@if (isPaginated && totalPages > 1) {\n <div class=\"flex items-center justify-between px-2 py-3 text-sm text-base-content\">\n <div class=\"flex items-center gap-2\">\n <span>Rows per page:</span>\n <select\n class=\"select select-xs rounded border border-base-300 bg-base-200 px-2 py-1 text-xs focus:outline-none focus:border-brand-500\"\n [value]=\"pageSize\"\n (change)=\"onPageSizeChange(+$any($event.target).value)\"\n aria-label=\"Rows per page\"\n >\n @for (opt of resolvedPageSizeOptions; track opt) {\n <option [value]=\"opt\" [selected]=\"opt === pageSize\">{{ opt }}</option>\n }\n </select>\n </div>\n\n <div class=\"flex items-center gap-1\">\n <span class=\"text-xs mr-2\">{{ (currentPage - 1) * pageSize + 1 }}\u2013{{ currentPage * pageSize > filteredItems.length ? filteredItems.length : currentPage * pageSize }} of {{ filteredItems.length }}</span>\n\n <button\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n [disabled]=\"currentPage === 1\"\n (click)=\"goToPage(1)\"\n aria-label=\"First page\"\n >\u00AB</button>\n\n <button\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n [disabled]=\"currentPage === 1\"\n (click)=\"goToPage(currentPage - 1)\"\n aria-label=\"Previous page\"\n >\u2039</button>\n\n @for (page of visiblePages; track page) {\n <button\n class=\"px-2.5 py-1 rounded border transition-colors text-xs\"\n [class.border-brand-500]=\"page === currentPage\"\n [class.bg-brand-500]=\"page === currentPage\"\n [class.text-white]=\"page === currentPage\"\n [class.border-base-300]=\"page !== currentPage\"\n [class.hover:bg-base-200]=\"page !== currentPage\"\n (click)=\"goToPage(page)\"\n [attr.aria-label]=\"'Page ' + page\"\n [attr.aria-current]=\"page === currentPage ? 'page' : null\"\n >{{ page }}</button>\n }\n\n <button\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n [disabled]=\"currentPage === totalPages\"\n (click)=\"goToPage(currentPage + 1)\"\n aria-label=\"Next page\"\n >\u203A</button>\n\n <button\n class=\"px-2 py-1 rounded border border-base-300 hover:bg-base-200 transition-colors disabled:opacity-40 disabled:cursor-not-allowed\"\n [disabled]=\"currentPage === totalPages\"\n (click)=\"goToPage(totalPages)\"\n aria-label=\"Last page\"\n >\u00BB</button>\n </div>\n </div>\n}\n" }]
|
|
3664
3664
|
}], propDecorators: { dataSource: [{
|
|
3665
3665
|
type: Input
|
|
3666
3666
|
}], sortChange: [{
|
|
@@ -4681,11 +4681,11 @@ class MnWizardBodyComponent {
|
|
|
4681
4681
|
}
|
|
4682
4682
|
}
|
|
4683
4683
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: MnWizardBodyComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
4684
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: MnWizardBodyComponent, isStandalone: true, selector: "mn-wizard-body", inputs: { config: "config", modalRef: "modalRef" }, viewQueries: [{ propertyName: "formBodies", predicate: MnFormBodyComponent, descendants: true }], ngImport: i0, template: "<div class=\"flex flex-col gap-6\">\n @if (config.component || config.template) {\n <mn-custom-body-host\n [config]=\"asAny(config)\"\n [modalRef]=\"asAny(modalRef)\"\n class=\"block\"\n ></mn-custom-body-host>\n }\n\n <div class=\"flex gap-2 pb-4 border-b border-base-300\">\n @for (step of visibleSteps; track step.id; let i = $index) {\n <div\n class=\"flex items-center gap-2 flex-1\"\n [class.active]=\"step.id === currentStepId\"\n [class.complete]=\"visitedStepIds.includes(step.id) && step.id !== currentStepId\"\n [class.cursor-pointer]=\"isFreeFlow && canNavigateToStep(step)\"\n (click)=\"isFreeFlow ? goToStep(step) : null\"\n >\n <div\n class=\"w-8 h-8 rounded-full flex items-center justify-center font-semibold transition-all text-sm\"\n [ngClass]=\"{\n 'bg-blue-500 text-white': step.id === currentStepId,\n 'bg-green-500 text-white': visitedStepIds.includes(step.id) && step.id !== currentStepId,\n 'bg-base-200 text-base-content/50': !visitedStepIds.includes(step.id) && step.id !== currentStepId\n }\"\n >{{ i + 1 }}</div>\n <div\n class=\"text-sm\"\n [ngClass]=\"{\n 'text-base-content font-semibold': step.id === currentStepId,\n 'text-base-content/50': step.id !== currentStepId\n }\"\n >{{ step.title }}</div>\n </div>\n }\n </div>\n\n <div class=\"min-h-48\">\n @for (step of config.steps; track step.id) {\n <div [style.display]=\"step.id === currentStepId ? 'block' : 'none'\">\n <h3 class=\"text-lg font-semibold text-base-content mb-4\">{{ step.title }}</h3>\n <div class=\"text-base-content/80\">\n <!-- Form step -->\n @if (stepFormConfigs[step.id]) {\n <mn-form-body\n [config]=\"stepFormConfigs[step.id]\"\n [modalRef]=\"asAny(modalRef)\"\n [hideFooter]=\"true\"\n [hideCustomBody]=\"true\"\n ></mn-form-body>\n }\n\n <!-- Text body -->\n @if (!stepFormConfigs[step.id] && isTextBody(step)) {\n <div>\n {{ step.body }}\n </div>\n }\n\n <!-- Dynamic content container for component/template bodies -->\n <ng-container #dynamicContainer></ng-container>\n </div>\n </div>\n }\n </div>\n\n <!-- Wizard-level errors (from onBeforeComplete) -->\n @if (wizardErrors && (wizardErrors | keyvalue).length > 0) {\n <div class=\"flex flex-col gap-1 px-2 py-2 bg-red-50 rounded-md\">\n @for (err of wizardErrors | keyvalue; track err.key) {\n <div class=\"text-red-500 text-sm\">\n {{ err.value }}\n </div>\n }\n </div>\n }\n\n <div class=\"flex gap-3 pt-4 border-t border-base-300\">\n @if (!currentStep?.hideBack) {\n <button\n mnButton\n [data]=\"{ variant: 'outline', color: 'secondary' }\"\n (click)=\"back()\"\n >\n {{ currentStep?.backLabel || (canGoBack ? labels.back : labels.close) }}\n </button>\n }\n\n <!-- Custom footer actions (left-positioned, e.g. Delete) -->\n @if (config.footerActions) {\n @for (action of config.footerActions; track action.label) {\n @if (action.position === 'left') {\n <button\n mnButton\n [data]=\"getFooterActionButtonData(action)\"\n [disabled]=\"action.disabled || false\"\n (click)=\"handleFooterAction(action)\"\n >\n {{ action.label }}\n </button>\n }\n }\n }\n\n <div class=\"flex-1\"></div>\n\n <!-- Custom footer actions (right-positioned) -->\n @if (config.footerActions) {\n @for (action of config.footerActions; track action.label) {\n @if (action.position !== 'left') {\n <button\n mnButton\n [data]=\"getFooterActionButtonData(action)\"\n [disabled]=\"action.disabled || false\"\n (click)=\"handleFooterAction(action)\"\n >\n {{ action.label }}\n </button>\n }\n }\n }\n\n @if (!isLastStep) {\n <button\n mnButton\n [data]=\"{ variant: 'fill', color: 'primary', disabled: !isCurrentStepValid }\"\n (click)=\"next()\"\n >\n {{ currentStep?.nextLabel || labels.next }}\n </button>\n }\n\n @if (isLastStep) {\n <button\n mnButton\n [data]=\"{ variant: 'fill', color: 'primary', disabled: !isCurrentStepValid || isCompleting }\"\n [disabled]=\"!isCurrentStepValid || isCompleting\"\n (click)=\"complete()\"\n >\n {{ currentStep?.nextLabel || (isCompleting ? labels.completing : labels.complete) }}\n </button>\n }\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: MnButton, selector: "button[mnButton], a[mnButton]", inputs: ["data"] }, { kind: "component", type: MnFormBodyComponent, selector: "mn-form-body", inputs: ["config", "modalRef", "hideFooter", "hideCustomBody"], outputs: ["formStatusChange"] }, { kind: "component", type: MnCustomBodyHostComponent, selector: "mn-custom-body-host", inputs: ["config", "modalRef"] }, { kind: "pipe", type: i1.KeyValuePipe, name: "keyvalue" }] });
|
|
4684
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.3", type: MnWizardBodyComponent, isStandalone: true, selector: "mn-wizard-body", inputs: { config: "config", modalRef: "modalRef" }, viewQueries: [{ propertyName: "formBodies", predicate: MnFormBodyComponent, descendants: true }], ngImport: i0, template: "<div class=\"flex flex-col gap-6\" [class.h-full]=\"config.sizeHeight\">\n @if (config.component || config.template) {\n <mn-custom-body-host\n [config]=\"asAny(config)\"\n [modalRef]=\"asAny(modalRef)\"\n class=\"block\"\n ></mn-custom-body-host>\n }\n\n <div class=\"flex gap-2 pb-4 border-b border-base-300\">\n @for (step of visibleSteps; track step.id; let i = $index) {\n <div\n class=\"flex items-center gap-2 flex-1\"\n [class.active]=\"step.id === currentStepId\"\n [class.complete]=\"visitedStepIds.includes(step.id) && step.id !== currentStepId\"\n [class.cursor-pointer]=\"isFreeFlow && canNavigateToStep(step)\"\n (click)=\"isFreeFlow ? goToStep(step) : null\"\n >\n <div\n class=\"w-8 h-8 rounded-full flex items-center justify-center font-semibold transition-all text-sm\"\n [ngClass]=\"{\n 'bg-blue-500 text-white': step.id === currentStepId,\n 'bg-green-500 text-white': visitedStepIds.includes(step.id) && step.id !== currentStepId,\n 'bg-base-200 text-base-content/50': !visitedStepIds.includes(step.id) && step.id !== currentStepId\n }\"\n >{{ i + 1 }}</div>\n <div\n class=\"text-sm\"\n [ngClass]=\"{\n 'text-base-content font-semibold': step.id === currentStepId,\n 'text-base-content/50': step.id !== currentStepId\n }\"\n >{{ step.title }}</div>\n </div>\n }\n </div>\n\n <div class=\"min-h-48 flex-1\">\n @for (step of config.steps; track step.id) {\n <div [style.display]=\"step.id === currentStepId ? 'block' : 'none'\">\n <h3 class=\"text-lg font-semibold text-base-content mb-4\">{{ step.title }}</h3>\n <div class=\"text-base-content/80\">\n <!-- Form step -->\n @if (stepFormConfigs[step.id]) {\n <mn-form-body\n [config]=\"stepFormConfigs[step.id]\"\n [modalRef]=\"asAny(modalRef)\"\n [hideFooter]=\"true\"\n [hideCustomBody]=\"true\"\n ></mn-form-body>\n }\n\n <!-- Text body -->\n @if (!stepFormConfigs[step.id] && isTextBody(step)) {\n <div>\n {{ step.body }}\n </div>\n }\n\n <!-- Dynamic content container for component/template bodies -->\n <ng-container #dynamicContainer></ng-container>\n </div>\n </div>\n }\n </div>\n\n <!-- Wizard-level errors (from onBeforeComplete) -->\n @if (wizardErrors && (wizardErrors | keyvalue).length > 0) {\n <div class=\"flex flex-col gap-1 px-2 py-2 bg-red-50 rounded-md\">\n @for (err of wizardErrors | keyvalue; track err.key) {\n <div class=\"text-red-500 text-sm\">\n {{ err.value }}\n </div>\n }\n </div>\n }\n\n <div class=\"flex gap-3 pt-4 border-t border-base-300\">\n @if (!currentStep?.hideBack) {\n <button\n mnButton\n [data]=\"{ variant: 'outline', color: 'secondary' }\"\n (click)=\"back()\"\n >\n {{ currentStep?.backLabel || (canGoBack ? labels.back : labels.close) }}\n </button>\n }\n\n <!-- Custom footer actions (left-positioned, e.g. Delete) -->\n @if (config.footerActions) {\n @for (action of config.footerActions; track action.label) {\n @if (action.position === 'left') {\n <button\n mnButton\n [data]=\"getFooterActionButtonData(action)\"\n [disabled]=\"action.disabled || false\"\n (click)=\"handleFooterAction(action)\"\n >\n {{ action.label }}\n </button>\n }\n }\n }\n\n <div class=\"flex-1\"></div>\n\n <!-- Custom footer actions (right-positioned) -->\n @if (config.footerActions) {\n @for (action of config.footerActions; track action.label) {\n @if (action.position !== 'left') {\n <button\n mnButton\n [data]=\"getFooterActionButtonData(action)\"\n [disabled]=\"action.disabled || false\"\n (click)=\"handleFooterAction(action)\"\n >\n {{ action.label }}\n </button>\n }\n }\n }\n\n @if (!isLastStep) {\n <button\n mnButton\n [data]=\"{ variant: 'fill', color: 'primary', disabled: !isCurrentStepValid }\"\n (click)=\"next()\"\n >\n {{ currentStep?.nextLabel || labels.next }}\n </button>\n }\n\n @if (isLastStep) {\n <button\n mnButton\n [data]=\"{ variant: 'fill', color: 'primary', disabled: !isCurrentStepValid || isCompleting }\"\n [disabled]=\"!isCurrentStepValid || isCompleting\"\n (click)=\"complete()\"\n >\n {{ currentStep?.nextLabel || (isCompleting ? labels.completing : labels.complete) }}\n </button>\n }\n </div>\n</div>\n", styles: [""], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: MnButton, selector: "button[mnButton], a[mnButton]", inputs: ["data"] }, { kind: "component", type: MnFormBodyComponent, selector: "mn-form-body", inputs: ["config", "modalRef", "hideFooter", "hideCustomBody"], outputs: ["formStatusChange"] }, { kind: "component", type: MnCustomBodyHostComponent, selector: "mn-custom-body-host", inputs: ["config", "modalRef"] }, { kind: "pipe", type: i1.KeyValuePipe, name: "keyvalue" }] });
|
|
4685
4685
|
}
|
|
4686
4686
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.3", ngImport: i0, type: MnWizardBodyComponent, decorators: [{
|
|
4687
4687
|
type: Component,
|
|
4688
|
-
args: [{ selector: 'mn-wizard-body', standalone: true, imports: [CommonModule, ReactiveFormsModule, MnButton, MnFormBodyComponent, MnCustomBodyHostComponent], template: "<div class=\"flex flex-col gap-6\">\n @if (config.component || config.template) {\n <mn-custom-body-host\n [config]=\"asAny(config)\"\n [modalRef]=\"asAny(modalRef)\"\n class=\"block\"\n ></mn-custom-body-host>\n }\n\n <div class=\"flex gap-2 pb-4 border-b border-base-300\">\n @for (step of visibleSteps; track step.id; let i = $index) {\n <div\n class=\"flex items-center gap-2 flex-1\"\n [class.active]=\"step.id === currentStepId\"\n [class.complete]=\"visitedStepIds.includes(step.id) && step.id !== currentStepId\"\n [class.cursor-pointer]=\"isFreeFlow && canNavigateToStep(step)\"\n (click)=\"isFreeFlow ? goToStep(step) : null\"\n >\n <div\n class=\"w-8 h-8 rounded-full flex items-center justify-center font-semibold transition-all text-sm\"\n [ngClass]=\"{\n 'bg-blue-500 text-white': step.id === currentStepId,\n 'bg-green-500 text-white': visitedStepIds.includes(step.id) && step.id !== currentStepId,\n 'bg-base-200 text-base-content/50': !visitedStepIds.includes(step.id) && step.id !== currentStepId\n }\"\n >{{ i + 1 }}</div>\n <div\n class=\"text-sm\"\n [ngClass]=\"{\n 'text-base-content font-semibold': step.id === currentStepId,\n 'text-base-content/50': step.id !== currentStepId\n }\"\n >{{ step.title }}</div>\n </div>\n }\n </div>\n\n <div class=\"min-h-48\">\n @for (step of config.steps; track step.id) {\n <div [style.display]=\"step.id === currentStepId ? 'block' : 'none'\">\n <h3 class=\"text-lg font-semibold text-base-content mb-4\">{{ step.title }}</h3>\n <div class=\"text-base-content/80\">\n <!-- Form step -->\n @if (stepFormConfigs[step.id]) {\n <mn-form-body\n [config]=\"stepFormConfigs[step.id]\"\n [modalRef]=\"asAny(modalRef)\"\n [hideFooter]=\"true\"\n [hideCustomBody]=\"true\"\n ></mn-form-body>\n }\n\n <!-- Text body -->\n @if (!stepFormConfigs[step.id] && isTextBody(step)) {\n <div>\n {{ step.body }}\n </div>\n }\n\n <!-- Dynamic content container for component/template bodies -->\n <ng-container #dynamicContainer></ng-container>\n </div>\n </div>\n }\n </div>\n\n <!-- Wizard-level errors (from onBeforeComplete) -->\n @if (wizardErrors && (wizardErrors | keyvalue).length > 0) {\n <div class=\"flex flex-col gap-1 px-2 py-2 bg-red-50 rounded-md\">\n @for (err of wizardErrors | keyvalue; track err.key) {\n <div class=\"text-red-500 text-sm\">\n {{ err.value }}\n </div>\n }\n </div>\n }\n\n <div class=\"flex gap-3 pt-4 border-t border-base-300\">\n @if (!currentStep?.hideBack) {\n <button\n mnButton\n [data]=\"{ variant: 'outline', color: 'secondary' }\"\n (click)=\"back()\"\n >\n {{ currentStep?.backLabel || (canGoBack ? labels.back : labels.close) }}\n </button>\n }\n\n <!-- Custom footer actions (left-positioned, e.g. Delete) -->\n @if (config.footerActions) {\n @for (action of config.footerActions; track action.label) {\n @if (action.position === 'left') {\n <button\n mnButton\n [data]=\"getFooterActionButtonData(action)\"\n [disabled]=\"action.disabled || false\"\n (click)=\"handleFooterAction(action)\"\n >\n {{ action.label }}\n </button>\n }\n }\n }\n\n <div class=\"flex-1\"></div>\n\n <!-- Custom footer actions (right-positioned) -->\n @if (config.footerActions) {\n @for (action of config.footerActions; track action.label) {\n @if (action.position !== 'left') {\n <button\n mnButton\n [data]=\"getFooterActionButtonData(action)\"\n [disabled]=\"action.disabled || false\"\n (click)=\"handleFooterAction(action)\"\n >\n {{ action.label }}\n </button>\n }\n }\n }\n\n @if (!isLastStep) {\n <button\n mnButton\n [data]=\"{ variant: 'fill', color: 'primary', disabled: !isCurrentStepValid }\"\n (click)=\"next()\"\n >\n {{ currentStep?.nextLabel || labels.next }}\n </button>\n }\n\n @if (isLastStep) {\n <button\n mnButton\n [data]=\"{ variant: 'fill', color: 'primary', disabled: !isCurrentStepValid || isCompleting }\"\n [disabled]=\"!isCurrentStepValid || isCompleting\"\n (click)=\"complete()\"\n >\n {{ currentStep?.nextLabel || (isCompleting ? labels.completing : labels.complete) }}\n </button>\n }\n </div>\n</div>\n" }]
|
|
4688
|
+
args: [{ selector: 'mn-wizard-body', standalone: true, imports: [CommonModule, ReactiveFormsModule, MnButton, MnFormBodyComponent, MnCustomBodyHostComponent], template: "<div class=\"flex flex-col gap-6\" [class.h-full]=\"config.sizeHeight\">\n @if (config.component || config.template) {\n <mn-custom-body-host\n [config]=\"asAny(config)\"\n [modalRef]=\"asAny(modalRef)\"\n class=\"block\"\n ></mn-custom-body-host>\n }\n\n <div class=\"flex gap-2 pb-4 border-b border-base-300\">\n @for (step of visibleSteps; track step.id; let i = $index) {\n <div\n class=\"flex items-center gap-2 flex-1\"\n [class.active]=\"step.id === currentStepId\"\n [class.complete]=\"visitedStepIds.includes(step.id) && step.id !== currentStepId\"\n [class.cursor-pointer]=\"isFreeFlow && canNavigateToStep(step)\"\n (click)=\"isFreeFlow ? goToStep(step) : null\"\n >\n <div\n class=\"w-8 h-8 rounded-full flex items-center justify-center font-semibold transition-all text-sm\"\n [ngClass]=\"{\n 'bg-blue-500 text-white': step.id === currentStepId,\n 'bg-green-500 text-white': visitedStepIds.includes(step.id) && step.id !== currentStepId,\n 'bg-base-200 text-base-content/50': !visitedStepIds.includes(step.id) && step.id !== currentStepId\n }\"\n >{{ i + 1 }}</div>\n <div\n class=\"text-sm\"\n [ngClass]=\"{\n 'text-base-content font-semibold': step.id === currentStepId,\n 'text-base-content/50': step.id !== currentStepId\n }\"\n >{{ step.title }}</div>\n </div>\n }\n </div>\n\n <div class=\"min-h-48 flex-1\">\n @for (step of config.steps; track step.id) {\n <div [style.display]=\"step.id === currentStepId ? 'block' : 'none'\">\n <h3 class=\"text-lg font-semibold text-base-content mb-4\">{{ step.title }}</h3>\n <div class=\"text-base-content/80\">\n <!-- Form step -->\n @if (stepFormConfigs[step.id]) {\n <mn-form-body\n [config]=\"stepFormConfigs[step.id]\"\n [modalRef]=\"asAny(modalRef)\"\n [hideFooter]=\"true\"\n [hideCustomBody]=\"true\"\n ></mn-form-body>\n }\n\n <!-- Text body -->\n @if (!stepFormConfigs[step.id] && isTextBody(step)) {\n <div>\n {{ step.body }}\n </div>\n }\n\n <!-- Dynamic content container for component/template bodies -->\n <ng-container #dynamicContainer></ng-container>\n </div>\n </div>\n }\n </div>\n\n <!-- Wizard-level errors (from onBeforeComplete) -->\n @if (wizardErrors && (wizardErrors | keyvalue).length > 0) {\n <div class=\"flex flex-col gap-1 px-2 py-2 bg-red-50 rounded-md\">\n @for (err of wizardErrors | keyvalue; track err.key) {\n <div class=\"text-red-500 text-sm\">\n {{ err.value }}\n </div>\n }\n </div>\n }\n\n <div class=\"flex gap-3 pt-4 border-t border-base-300\">\n @if (!currentStep?.hideBack) {\n <button\n mnButton\n [data]=\"{ variant: 'outline', color: 'secondary' }\"\n (click)=\"back()\"\n >\n {{ currentStep?.backLabel || (canGoBack ? labels.back : labels.close) }}\n </button>\n }\n\n <!-- Custom footer actions (left-positioned, e.g. Delete) -->\n @if (config.footerActions) {\n @for (action of config.footerActions; track action.label) {\n @if (action.position === 'left') {\n <button\n mnButton\n [data]=\"getFooterActionButtonData(action)\"\n [disabled]=\"action.disabled || false\"\n (click)=\"handleFooterAction(action)\"\n >\n {{ action.label }}\n </button>\n }\n }\n }\n\n <div class=\"flex-1\"></div>\n\n <!-- Custom footer actions (right-positioned) -->\n @if (config.footerActions) {\n @for (action of config.footerActions; track action.label) {\n @if (action.position !== 'left') {\n <button\n mnButton\n [data]=\"getFooterActionButtonData(action)\"\n [disabled]=\"action.disabled || false\"\n (click)=\"handleFooterAction(action)\"\n >\n {{ action.label }}\n </button>\n }\n }\n }\n\n @if (!isLastStep) {\n <button\n mnButton\n [data]=\"{ variant: 'fill', color: 'primary', disabled: !isCurrentStepValid }\"\n (click)=\"next()\"\n >\n {{ currentStep?.nextLabel || labels.next }}\n </button>\n }\n\n @if (isLastStep) {\n <button\n mnButton\n [data]=\"{ variant: 'fill', color: 'primary', disabled: !isCurrentStepValid || isCompleting }\"\n [disabled]=\"!isCurrentStepValid || isCompleting\"\n (click)=\"complete()\"\n >\n {{ currentStep?.nextLabel || (isCompleting ? labels.completing : labels.complete) }}\n </button>\n }\n </div>\n</div>\n" }]
|
|
4689
4689
|
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }], propDecorators: { config: [{
|
|
4690
4690
|
type: Input
|
|
4691
4691
|
}], modalRef: [{
|
|
@@ -4951,7 +4951,16 @@ class MnModalShellComponent {
|
|
|
4951
4951
|
if (this.config.sizeWidth === ModalSize.FULL && !this.config.sizeHeight) {
|
|
4952
4952
|
return '95vh';
|
|
4953
4953
|
}
|
|
4954
|
-
|
|
4954
|
+
if (!this.config.sizeHeight)
|
|
4955
|
+
return null;
|
|
4956
|
+
switch (this.config.sizeHeight) {
|
|
4957
|
+
case ModalSize.SM: return '30vh';
|
|
4958
|
+
case ModalSize.MD: return '50vh';
|
|
4959
|
+
case ModalSize.LG: return '70vh';
|
|
4960
|
+
case ModalSize.XL: return '85vh';
|
|
4961
|
+
case ModalSize.FULL: return '95vh';
|
|
4962
|
+
default: return null;
|
|
4963
|
+
}
|
|
4955
4964
|
}
|
|
4956
4965
|
get showCloseButton() {
|
|
4957
4966
|
return this.config.closeMode !== CloseMode.DISABLED;
|