@lifecorner/angular-ui-kit 3.16.0 → 3.17.0
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.
- package/fesm2022/lifecorner-angular-ui-kit-button.mjs +12 -7
- package/fesm2022/lifecorner-angular-ui-kit-button.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-list.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-list.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-progress-bar.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-progress-bar.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-table.mjs +6 -4
- package/fesm2022/lifecorner-angular-ui-kit-table.mjs.map +1 -1
- package/fesm2022/lifecorner-angular-ui-kit-toast.mjs +2 -2
- package/fesm2022/lifecorner-angular-ui-kit-toast.mjs.map +1 -1
- package/package.json +1 -1
- package/src/styles/theme-contrast.spec.ts +57 -0
- package/types/lifecorner-angular-ui-kit-button.d.ts +28 -1
- package/types/lifecorner-angular-ui-kit-progress-bar.d.ts +12 -1
- package/types/lifecorner-angular-ui-kit-table.d.ts +19 -1
- package/types/lifecorner-angular-ui-kit-toast.d.ts +3 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecorner-angular-ui-kit-progress-bar.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/progress-bar/progress-bar.component.ts","../../../../libs/angular-ui-kit/src/lib/progress-bar/progress-bar.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n input,\n computed,\n} from '@angular/core';\n\nexport type ProgressBarColor = 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info';\nexport type ProgressBarSize = 'xs' | 'sm' | 'md' | 'lg';\nexport type ProgressBarVariant = 'linear' | 'circular';\n\n/**\n * Progress bar component for displaying completion status.\n *\n * Features:\n * - Linear and circular progress variants\n * - Color theme options (primary, secondary, success, warning, error)\n * - Multiple size presets (xs, sm, md, lg)\n * - Animated value transitions\n * - Accessible with ARIA progressbar role\n *\n * @example\n * ```html\n * <lc-progress-bar [value]=\"75\" color=\"primary\" size=\"md\"></lc-progress-bar>\n * <lc-progress-bar [value]=\"50\" variant=\"circular\" color=\"success\"></lc-progress-bar>\n *\n * <!-- thin bar inside a list row: fixed width, flows with the line -->\n * <lc-progress-bar [value]=\"60\" size=\"sm\" [inline]=\"true\"\n * style=\"--lc-progress-bar-height: 6px\"></lc-progress-bar>\n * ```\n */\n@Component({\n selector: 'lc-progress-bar',\n standalone: true,\n templateUrl: './progress-bar.component.html',\n styleUrls: ['./progress-bar.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class.lc-progress-bar--inline]': 'inline()',\n },\n})\nexport class ProgressBarComponent {\n /**\n * Progress value between 0 and 100.\n * @default 0\n */\n value = input<number>(0);\n\n /**\n * Color theme.\n * @default 'primary'\n */\n color = input<ProgressBarColor>('primary');\n\n /**\n * Height/thickness of the bar.\n * @default 'md'\n */\n size = input<ProgressBarSize>('md');\n\n /**\n * Visual variant.\n * @default 'linear'\n */\n variant = input<ProgressBarVariant>('linear');\n\n /**\n * Whether to show the percentage label.\n * @default false\n */\n showLabel = input<boolean>(false);\n\n /**\n * Inline mode for list rows: the bar flows with the surrounding line at a\n * fixed width instead of filling its container. Width is settable via\n * `--lc-progress-bar-inline-width` (default 5rem), the track height via\n * `--lc-progress-bar-height` (e.g. 6px), which also works in block mode.\n * @default false\n */\n inline = input<boolean>(false);\n\n /**\n *
|
|
1
|
+
{"version":3,"file":"lifecorner-angular-ui-kit-progress-bar.mjs","names":[],"sources":["../../../../libs/angular-ui-kit/src/lib/progress-bar/progress-bar.component.ts","../../../../libs/angular-ui-kit/src/lib/progress-bar/progress-bar.component.html"],"sourcesContent":["import {\n ChangeDetectionStrategy,\n Component,\n input,\n computed,\n} from '@angular/core';\n\nexport type ProgressBarColor = 'primary' | 'secondary' | 'success' | 'warning' | 'error' | 'info';\nexport type ProgressBarSize = 'xs' | 'sm' | 'md' | 'lg';\nexport type ProgressBarVariant = 'linear' | 'circular';\n\n/**\n * Progress bar component for displaying completion status.\n *\n * Features:\n * - Linear and circular progress variants\n * - Color theme options (primary, secondary, success, warning, error)\n * - Multiple size presets (xs, sm, md, lg)\n * - Animated value transitions\n * - Accessible with ARIA progressbar role\n *\n * The bar is a visual aid; the text next to it carries the meaning. Write the\n * status as text ('USM wird geladen …') and announce changes from a live\n * region (`role=\"status\"`). Screen readers don't announce a progress bar's\n * changes by themselves. Give `ariaLabel` the same words as the status. Under\n * `forced-colors: active` the fill is `Highlight`, the linear track gets a\n * 1 px `CanvasText` outline and the circle's track is `GrayText` (3.17).\n *\n * @example\n * ```html\n * <lc-progress-bar [value]=\"75\" color=\"primary\" size=\"md\"></lc-progress-bar>\n * <lc-progress-bar [value]=\"50\" variant=\"circular\" color=\"success\"></lc-progress-bar>\n *\n * <!-- thin bar inside a list row: fixed width, flows with the line -->\n * <lc-progress-bar [value]=\"60\" size=\"sm\" [inline]=\"true\"\n * style=\"--lc-progress-bar-height: 6px\"></lc-progress-bar>\n * ```\n */\n@Component({\n selector: 'lc-progress-bar',\n standalone: true,\n templateUrl: './progress-bar.component.html',\n styleUrls: ['./progress-bar.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: {\n '[class.lc-progress-bar--inline]': 'inline()',\n },\n})\nexport class ProgressBarComponent {\n /**\n * Progress value between 0 and 100.\n * @default 0\n */\n value = input<number>(0);\n\n /**\n * Color theme.\n * @default 'primary'\n */\n color = input<ProgressBarColor>('primary');\n\n /**\n * Height/thickness of the bar.\n * @default 'md'\n */\n size = input<ProgressBarSize>('md');\n\n /**\n * Visual variant.\n * @default 'linear'\n */\n variant = input<ProgressBarVariant>('linear');\n\n /**\n * Whether to show the percentage label.\n * @default false\n */\n showLabel = input<boolean>(false);\n\n /**\n * Inline mode for list rows: the bar flows with the surrounding line at a\n * fixed width instead of filling its container. Width is settable via\n * `--lc-progress-bar-inline-width` (default 5rem), the track height via\n * `--lc-progress-bar-height` (e.g. 6px), which also works in block mode.\n * @default false\n */\n inline = input<boolean>(false);\n\n /**\n * Progress of unknown length: no value (`aria-valuenow` is absent) and no\n * label. The linear bar moves a 40 % segment across the track, and the\n * circle spins. Under `prefers-reduced-motion: reduce` nothing moves: the\n * linear bar shows a full-width striped fill and the circle a dashed ring,\n * so it still reads as busy, not as a value (3.17).\n * @default false\n */\n indeterminate = input<boolean>(false);\n\n /**\n * Accessible label for screen readers.\n */\n ariaLabel = input<string>('Progress');\n\n protected clampedValue = computed(() => Math.max(0, Math.min(100, this.value())));\n\n protected barClasses = computed(() => {\n return [\n 'progress-bar',\n `progress-bar--${this.color()}`,\n `progress-bar--${this.size()}`,\n this.indeterminate() ? 'progress-bar--indeterminate' : '',\n ]\n .filter(Boolean)\n .join(' ');\n });\n\n // Circular variant helpers\n protected readonly circleRadius = 40;\n protected readonly circleCircumference = 2 * Math.PI * 40;\n\n protected strokeDashoffset = computed(() => {\n return this.circleCircumference * (1 - this.clampedValue() / 100);\n });\n}\n","@if (variant() === 'linear') {\n <div\n [class]=\"barClasses()\"\n role=\"progressbar\"\n [attr.aria-valuenow]=\"indeterminate() ? null : clampedValue()\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"100\"\n [attr.aria-label]=\"ariaLabel()\"\n >\n <div class=\"progress-bar__track\">\n <div\n class=\"progress-bar__fill\"\n [style.width.%]=\"indeterminate() ? 0 : clampedValue()\"\n ></div>\n </div>\n @if (showLabel() && !indeterminate()) {\n <span class=\"progress-bar__label\">{{ clampedValue() }}%</span>\n }\n </div>\n} @else {\n <div\n class=\"progress-bar-circular\"\n [class]=\"'progress-bar-circular progress-bar-circular--' + color() + ' progress-bar-circular--' + size()\"\n role=\"progressbar\"\n [attr.aria-valuenow]=\"indeterminate() ? null : clampedValue()\"\n [attr.aria-valuemin]=\"0\"\n [attr.aria-valuemax]=\"100\"\n [attr.aria-label]=\"ariaLabel()\"\n >\n <svg viewBox=\"0 0 100 100\" class=\"progress-bar-circular__svg\">\n <circle\n class=\"progress-bar-circular__track\"\n cx=\"50\" cy=\"50\" [attr.r]=\"circleRadius\"\n fill=\"none\"\n />\n <circle\n class=\"progress-bar-circular__fill\"\n cx=\"50\" cy=\"50\" [attr.r]=\"circleRadius\"\n fill=\"none\"\n [attr.stroke-dasharray]=\"circleCircumference\"\n [attr.stroke-dashoffset]=\"indeterminate() ? circleCircumference * 0.75 : strokeDashoffset()\"\n [class.progress-bar-circular__fill--indeterminate]=\"indeterminate()\"\n />\n </svg>\n @if (showLabel() && !indeterminate()) {\n <span class=\"progress-bar-circular__label\">{{ clampedValue() }}%</span>\n }\n </div>\n}\n"],"mappings":";;AAgDA,IAAa,uBAAb,MAAa,qBAAoB;CAK/B,QAAQ,MAAc,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAMxB,QAAQ,MAAwB,WAAU,GAAA,YAAA,CAAA,EAAA,WAAA,QAAA,CAAA,+BAAA,CAAA,CAAA;CAM1C,OAAO,MAAuB,MAAK,GAAA,YAAA,CAAA,EAAA,WAAA,OAAA,CAAA,+BAAA,CAAA,CAAA;CAMnC,UAAU,MAA0B,UAAS,GAAA,YAAA,CAAA,EAAA,WAAA,UAAA,CAAA,+BAAA,CAAA,CAAA;CAM7C,YAAY,MAAe,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CASjC,SAAS,MAAe,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,SAAA,CAAA,+BAAA,CAAA,CAAA;CAU9B,gBAAgB,MAAe,OAAM,GAAA,YAAA,CAAA,EAAA,WAAA,gBAAA,CAAA,+BAAA,CAAA,CAAA;CAKrC,YAAY,MAAc,YAAW,GAAA,YAAA,CAAA,EAAA,WAAA,YAAA,CAAA,+BAAA,CAAA,CAAA;CAE3B,eAAe,eAAe,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,KAAK,MAAK,CAAE,CAAC,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,eAAA,CAAA,+BAAA,CAAA,CAAA;CAEvE,aAAa,eAAc;EACnC,OAAO;GACL;GACA,iBAAiB,KAAK,MAAK;GAC3B,iBAAiB,KAAK,KAAI;GAC1B,KAAK,cAAa,IAAK,gCAAgC;EACxD,CAAA,CACE,OAAO,OAAO,CAAC,CACf,KAAK,GAAG;CACb,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,aAAA,CAAA,+BAAA,CAAA,CAAA;CAGiB,eAAe;CACf,sBAAsB,IAAI,KAAK,KAAK;CAE7C,mBAAmB,eAAc;EACzC,OAAO,KAAK,uBAAuB,IAAI,KAAK,aAAY,IAAK;CAC/D,GAAE,GAAA,YAAA,CAAA,EAAA,WAAA,mBAAA,CAAA,+BAAA,CAAA,CAAA;CA1ES,OAAA,OAAA,GAAA,mBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,UAAA;EAAA,MAAA;EAAoB,MAAA,CAAA;EAAA,QAAA,GAAA,gBAAA;CAAA,CAAA;CAApB,OAAA,OAAA,GAAA,qBAAA;EAAA,YAAA;EAAA,SAAA;EAAA,MAAA;EAAoB,cAAA;EAAA,UAAA;EAAA,QAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,OAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,MAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,SAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,WAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,QAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,eAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;GAAA,WAAA;IAAA,mBAAA;IAAA,YAAA;IAAA,UAAA;IAAA,YAAA;IAAA,mBAAA;GAAA;EAAA;EAAA,MAAA,EAAA,YAAA,EAAA,iCAAA,WAAA,EAAA;EAAA,UAAA;EAAA,UChDjC;EAiDA,QAAA,CAAA,20IAAA;EAAA,iBAAA,GAAA,wBAAA;CAAA,CAAA;;ADDa,GAAA,yBAAA;CAAA,YAAA;CAAA,SAAA;CAAA,UAAA;CAAA,MAAA;CAAoB,YAAA,CAAA;EAVhC,MAAA;EACW,MAAA,CAAA;GAAA,UAAA;GAAiB,YACf;GAAI,iBAGC,wBAAwB;GAAM,MACzC,EACJ,mCAAmC,WACpC;GAAA,UAAA;GAAA,QAAA,CAAA,20IAAA;EAAA,CAAA"}
|
|
@@ -390,6 +390,7 @@ var TableComponent = class TableComponent {
|
|
|
390
390
|
if (column.sortable) classes.push("sortable");
|
|
391
391
|
const sortState = this.getSortState(column.key);
|
|
392
392
|
if (sortState) classes.push(`sorted-${sortState}`);
|
|
393
|
+
if (column.align === "end") classes.push("lc-table__cell--end");
|
|
393
394
|
return classes.join(" ");
|
|
394
395
|
}
|
|
395
396
|
getCellValue(row, columnKey) {
|
|
@@ -403,6 +404,7 @@ var TableComponent = class TableComponent {
|
|
|
403
404
|
getCellClasses(row, column, rowIndex) {
|
|
404
405
|
const classes = [];
|
|
405
406
|
if (column.cssClass) classes.push(column.cssClass);
|
|
407
|
+
if (column.align === "end") classes.push("lc-table__cell--end");
|
|
406
408
|
if (typeof column.cellClass === "string") classes.push(column.cellClass);
|
|
407
409
|
else if (typeof column.cellClass === "function") {
|
|
408
410
|
const resolved = column.cellClass(this.getCellValue(row, column.key), row, column, rowIndex);
|
|
@@ -973,8 +975,8 @@ var TableComponent = class TableComponent {
|
|
|
973
975
|
isSignal: true
|
|
974
976
|
}],
|
|
975
977
|
ngImport: i0,
|
|
976
|
-
template: "<div [class]=\"wrapperClasses()\">\n <table [class]=\"tableClasses()\" [attr.role]=\"treeMode() ? 'treegrid' : 'table'\">\n @if (caption()) {\n <!-- First child of the table, so it names the table (and the treegrid). -->\n <caption class=\"lc-table__caption\" [class.lc-table__caption--hidden]=\"!showCaption()\">{{ caption() }}</caption>\n }\n <thead>\n <!-- Filter row -->\n @if (filterable()) {\n <tr class=\"lc-table__filter-row\">\n @if (selectable()) {\n <th class=\"lc-table__select-cell\"></th>\n }\n @for (column of columns(); track column.key) {\n <th>\n @if (column.filterable !== false) {\n <lc-input\n class=\"lc-table__filter-input\"\n size=\"xs\"\n [placeholder]=\"filterPlaceholderLabel() + ' ' + column.label\"\n [ariaLabel]=\"filterAriaLabel() + ' ' + column.label\"\n [ngModel]=\"getFilterValue(column.key)\"\n (ngModelChange)=\"onFilterChange(column.key, $event)\"\n />\n }\n </th>\n }\n @if (hasActions()) {\n <th class=\"lc-table__actions-cell\"></th>\n }\n </tr>\n }\n <!-- Header row -->\n <tr>\n @if (selectable()) {\n <th class=\"lc-table__select-cell\" scope=\"col\">\n <input\n type=\"checkbox\"\n class=\"lc-table__checkbox\"\n [checked]=\"allSelected()\"\n [indeterminate]=\"someSelected()\"\n (change)=\"toggleSelectAll()\"\n [attr.aria-label]=\"selectAllAriaLabel()\"\n />\n </th>\n }\n @for (column of columns(); track column.key) {\n <!-- A sortable header is a keyboard stop too: Enter/Space sort like a click. -->\n <th\n scope=\"col\"\n [class]=\"getHeaderClasses(column) + (column.cssClass ? ' ' + column.cssClass : '')\"\n [attr.aria-sort]=\"getAriaSort(column.key)\"\n [attr.tabindex]=\"column.sortable ? 0 : null\"\n [style.width]=\"column.width\"\n [title]=\"column.tooltip || ''\"\n (click)=\"handleSort(column.key)\"\n (keydown)=\"column.sortable ? onHeaderKeydown($event, column.key) : null\">\n {{ column.label }}\n @if (column.sortable && getSortState(column.key)) {\n <span class=\"sort-indicator\" [attr.aria-label]=\"getSortState(column.key) === 'asc' ? sortedAscendingLabel() : sortedDescendingLabel()\">\n @if (getSortState(column.key) === 'asc') {\n ↑\n } @else {\n ↓\n }\n </span>\n }\n </th>\n }\n @if (hasActions()) {\n <th\n scope=\"col\"\n class=\"lc-table__actions-cell\"\n [class]=\"'lc-table__actions-cell--' + actionsAlign()\"\n [style.width]=\"actionsWidth()\"\n >\n {{ actionsLabel() }}\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (displayRows().length === 0) {\n <tr>\n <td [attr.colspan]=\"columns().length + (selectable() ? 1 : 0) + (hasActions() ? 1 : 0)\" class=\"lc-table__empty\">\n {{ emptyText() }}\n </td>\n </tr>\n } @else {\n @for (dr of displayRows(); track dr.key) {\n <!-- In tree mode the rows form the treegrid's keyboard model: a roving\n tab stop plus Arrow/Home/End/Enter/Space handling (see the\n component). Flat mode keeps plain table rows. -->\n <tr\n #dataRow\n [class.lc-table__row--selected]=\"selectable() && isRowSelected(dr.row)\"\n [class.lc-table__row--group]=\"dr.hasChildren\"\n [attr.role]=\"treeMode() ? 'row' : null\"\n [attr.tabindex]=\"rowTabindex(dr)\"\n [attr.aria-level]=\"treeMode() ? dr.level : null\"\n [attr.aria-expanded]=\"treeMode() && dr.hasChildren ? dr.expanded : null\"\n [attr.aria-posinset]=\"treeMode() ? dr.posInSet : null\"\n [attr.aria-setsize]=\"treeMode() ? dr.setSize : null\"\n [attr.aria-selected]=\"treeMode() && selectable() ? isRowSelected(dr.row) : null\"\n (click)=\"onRowClick(dr.row, $event)\"\n (focus)=\"onRowFocus(dr)\"\n (keydown)=\"onRowKeydown($event, dr)\"\n >\n @if (selectable()) {\n <td class=\"lc-table__select-cell\" [attr.role]=\"treeMode() ? 'gridcell' : null\">\n <input\n type=\"checkbox\"\n class=\"lc-table__checkbox\"\n [checked]=\"isRowSelected(dr.row)\"\n (change)=\"toggleRowSelect(dr.row)\"\n (click)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"selectRowAriaLabel() + ' ' + (dr.absIndex + 1)\"\n />\n </td>\n }\n @for (column of columns(); track column.key) {\n <td\n [class]=\"getCellClasses(dr.row, column, dr.absIndex)\"\n [ngStyle]=\"getCellStyles(dr.row, column, dr.absIndex)\"\n [attr.role]=\"treeMode() ? 'gridcell' : null\"\n (dblclick)=\"editable() ? startEdit(dr.row, column.key, getCellValue(dr.row, column.key)) : null\"\n >\n @if (isTreeColumn(column.key)) {\n <span class=\"lc-table__tree-cell\">\n @for (lvl of indentLevels(dr.depth); track lvl) {\n <span class=\"lc-table__tree-indent\" [style.width.px]=\"indentSize()\"></span>\n }\n <span class=\"lc-table__tree-chevron\" [style.width.px]=\"indentSize()\">\n @if (dr.hasChildren) {\n <button\n type=\"button\"\n class=\"lc-table__chevron-btn\"\n [class.lc-table__chevron-btn--expanded]=\"dr.expanded\"\n [attr.aria-label]=\"(dr.expanded ? collapseRowAriaLabel() : expandRowAriaLabel()) + ' ' + treeCellLabel(dr.row)\"\n [attr.aria-expanded]=\"dr.expanded\"\n (click)=\"onChevronClick(dr, $event)\"\n >\n <lc-icon name=\"chevron-right\" size=\"xs\" [decorative]=\"true\" />\n </button>\n }\n </span>\n <span class=\"lc-table__tree-content\">\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { row: dr.row, column: column, absIndex: dr.absIndex }\"\n ></ng-container>\n </span>\n </span>\n } @else {\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { row: dr.row, column: column, absIndex: dr.absIndex }\"\n ></ng-container>\n }\n </td>\n }\n @if (hasActions()) {\n <td\n class=\"lc-table__actions-cell\"\n [class]=\"'lc-table__actions-cell--' + actionsAlign()\"\n [attr.role]=\"treeMode() ? 'gridcell' : null\"\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"lc-table__actions\">\n @for (action of actions(); track action.key) {\n @if (!isActionHidden(action, dr.row, dr.absIndex)) {\n <lc-button\n [variant]=\"action.variant ?? 'ghost'\"\n size=\"xs\"\n [iconOnly]=\"!action.label\"\n [disabled]=\"isActionDisabled(action, dr.row, dr.absIndex)\"\n [ariaLabel]=\"action.tooltip ?? action.label ?? action.key\"\n (clicked)=\"onActionClick(action, dr.row, dr.absIndex)\"\n >\n @if (action.icon) {\n <lc-icon [name]=\"action.icon\" size=\"sm\" [decorative]=\"true\" />\n }\n @if (action.label) {\n {{ action.label }}\n }\n </lc-button>\n }\n }\n </div>\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n<!-- Shared cell content (edit input / custom template / formatted value) -->\n<ng-template #cellContent let-row=\"row\" let-column=\"column\" let-absIndex=\"absIndex\">\n @if (isEditing(row, column.key)) {\n <input\n #editInput\n type=\"text\"\n class=\"lc-table__edit-input\"\n [value]=\"editValue()\"\n (input)=\"editValue.set(getInputValue($event))\"\n (blur)=\"commitEdit(row, column.key)\"\n (keydown)=\"onEditKeydown($event, row, column.key)\"\n />\n } @else if (hasCustomTemplate(column.key)) {\n <ng-container *ngTemplateOutlet=\"getCellTemplate(column.key)!.template; context: { $implicit: row }\"></ng-container>\n } @else {\n {{ getFormattedCellValue(row, column, absIndex) }}\n }\n</ng-template>\n\n<!-- Pagination -->\n@if (paginate()) {\n <div class=\"lc-table-pagination\">\n <div class=\"lc-table-pagination__info\">\n {{ paginationStart }}–{{ paginationEnd }} {{ rangeOfLabel() }} {{ totalRows() }}\n </div>\n <div class=\"lc-table-pagination__controls\">\n <lc-select\n class=\"lc-table-pagination__size\"\n [size]=\"size() === 'sm' ? 'sm' : size() === 'lg' ? 'lg' : 'md'\"\n [options]=\"pageSizeSelectOptions()\"\n [ngModel]=\"internalPageSize()\"\n [ariaLabel]=\"rowsPerPageAriaLabel()\"\n (ngModelChange)=\"onPageSizeModelChange($event)\"\n />\n <button\n type=\"button\"\n class=\"lc-table-pagination__btn\"\n [disabled]=\"currentPage() === 0\"\n (click)=\"goToPage(currentPage() - 1)\"\n [attr.aria-label]=\"previousPageAriaLabel()\"\n >‹</button>\n <span class=\"lc-table-pagination__page\">\n {{ currentPage() + 1 }} / {{ totalPages() }}\n </span>\n <button\n type=\"button\"\n class=\"lc-table-pagination__btn\"\n [disabled]=\"currentPage() >= totalPages() - 1\"\n (click)=\"goToPage(currentPage() + 1)\"\n [attr.aria-label]=\"nextPageAriaLabel()\"\n >›</button>\n </div>\n </div>\n}\n",
|
|
977
|
-
styles: [".lc-table-wrapper{width:100%}.lc-table-wrapper--responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media(max-width:768px){.lc-table-wrapper--responsive::-webkit-scrollbar{height:8px}.lc-table-wrapper--responsive::-webkit-scrollbar-thumb{background-color:var(--color-border);border-radius:var(--border-radius-sm)}}.lc-table{width:100%;border-collapse:collapse;border-spacing:0;background-color:var(--color-surface);color:var(--color-text-primary);font-family:var(--typography-font-family)}.lc-table thead{background-color:var(--color-surface-2);border-bottom:2px solid var(--color-border-strong)}.lc-table thead tr th{padding:var(--lc-density-padding-sm, var(--spacing-3)) var(--lc-density-padding-md, var(--spacing-4));text-align:left;font-weight:var(--typography-font-weight-semibold);font-size:var(--typography-font-size-sm);text-transform:uppercase;letter-spacing:.04em;color:var(--color-text-secondary);white-space:nowrap;-webkit-user-select:none;user-select:none}.lc-table thead tr th.sortable{cursor:pointer;position:relative;padding-right:var(--spacing-8);transition:background-color .2s ease}.lc-table thead tr th.sortable:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:-2px}.lc-table thead tr th.sortable:hover{background-color:var(--color-surface-hover);color:var(--color-text-primary)}.lc-table thead tr th.sortable .sort-indicator{position:absolute;right:var(--spacing-3);top:50%;transform:translateY(-50%);font-size:var(--typography-font-size-xs);color:var(--color-primary)}.lc-table thead tr th.sorted-asc,.lc-table thead tr th.sorted-desc{background-color:var(--color-surface-hover);color:var(--color-text-primary)}.lc-table tbody tr{border-bottom:1px solid var(--color-divider)}.lc-table tbody tr:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:-2px}.lc-table tbody tr:last-child{border-bottom:none}.lc-table tbody tr td{padding:var(--lc-density-padding-sm, var(--spacing-3)) var(--lc-density-padding-md, var(--spacing-4));font-size:var(--typography-font-size-sm);color:var(--color-text-primary)}.lc-table__empty{text-align:center;padding:var(--spacing-8) var(--spacing-4)!important;color:var(--color-text-secondary);font-style:italic}.lc-table--striped tbody tr:nth-child(2n){background-color:var(--color-surface-2)}.lc-table--bordered{border:1px solid var(--color-border)}.lc-table--bordered thead tr th,.lc-table--bordered tbody tr td{border-right:1px solid var(--color-divider)}.lc-table--bordered thead tr th:last-child,.lc-table--bordered tbody tr td:last-child{border-right:none}.lc-table--bordered tbody tr{border-bottom:1px solid var(--color-border)}.lc-table--hoverable tbody tr,.lc-table--clickable tbody tr{transition:background-color .15s ease;cursor:pointer}.lc-table--hoverable tbody tr:hover,.lc-table--clickable tbody tr:hover{background-color:var(--color-surface-hover)}.lc-table--sm thead tr th,.lc-table--sm tbody tr td{padding:var(--lc-density-padding-xs, var(--spacing-2)) var(--lc-density-padding-sm, var(--spacing-3));font-size:var(--typography-font-size-xs)}.lc-table--lg thead tr th,.lc-table--lg tbody tr td{padding:var(--lc-density-padding-md, var(--spacing-4)) var(--spacing-5);font-size:var(--typography-font-size-base)}.lc-table__caption{caption-side:top;padding:0 0 var(--spacing-3);text-align:start;font-family:var(--typography-font-family);font-size:var(--typography-font-size-base);font-weight:var(--typography-font-weight-semibold);line-height:var(--typography-line-height-normal);color:var(--color-text-primary)}.lc-table__caption--hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media(forced-colors:active){.lc-table tbody tr:focus-visible{outline:2px solid Highlight}}.lc-table__filter-row th{padding:var(--spacing-2) var(--spacing-4)!important;background-color:var(--color-surface)!important;border-bottom:1px solid var(--color-divider)!important}.lc-table__filter-input{width:100%;display:block}.lc-table__filter-input .input-field{font-size:var(--typography-font-size-xs)}.lc-table__select-cell{width:40px;text-align:center!important;padding:var(--spacing-2)!important}.lc-table__checkbox{width:16px;height:16px;cursor:pointer;accent-color:var(--color-primary)}.lc-table__row--selected{background-color:var(--color-surface-selected)!important}.lc-table__actions-cell{white-space:nowrap}.lc-table th.lc-table__actions-cell--start,.lc-table td.lc-table__actions-cell--start{text-align:left}.lc-table th.lc-table__actions-cell--center,.lc-table td.lc-table__actions-cell--center{text-align:center}.lc-table th.lc-table__actions-cell--end,.lc-table td.lc-table__actions-cell--end{text-align:right}.lc-table__actions{display:flex;align-items:center;gap:var(--spacing-2);justify-content:flex-start}.lc-table__actions-cell--center .lc-table__actions{justify-content:center}.lc-table__actions-cell--end .lc-table__actions{justify-content:flex-end}.lc-table__tree-cell{display:flex;align-items:center;min-width:0}.lc-table__tree-indent{flex:0 0 auto;align-self:stretch;position:relative}.lc-table__tree-indent:before{content:\"\";position:absolute;left:50%;top:0;bottom:0;width:1px;background-color:var(--color-border)}.lc-table__tree-chevron{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center}.lc-table__chevron-btn{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border:none;background:transparent;color:var(--color-text-secondary);cursor:pointer;border-radius:var(--border-radius-sm);transition:transform .2s ease,background-color .15s ease,color .15s ease}.lc-table__chevron-btn:hover{background-color:var(--color-surface-hover);color:var(--color-text-primary)}.lc-table__chevron-btn:focus-visible{outline:2px solid var(--color-primary);outline-offset:1px}.lc-table__chevron-btn--expanded{transform:rotate(90deg)}.lc-table__tree-content{flex:1 1 auto;min-width:0}.lc-table__row--group .lc-table__tree-content{font-weight:var(--typography-font-weight-semibold)}.lc-table__edit-input{width:100%;padding:var(--spacing-1) var(--spacing-2);border:2px solid var(--color-primary);border-radius:var(--border-radius-sm);font-size:inherit;background-color:var(--color-surface-2);color:var(--color-text-primary);outline:none}.lc-table-pagination{display:flex;align-items:center;justify-content:space-between;padding:var(--spacing-3) var(--spacing-1);font-size:var(--typography-font-size-sm);color:var(--color-text-secondary)}.lc-table-pagination__info{white-space:nowrap}.lc-table-pagination__controls{display:flex;align-items:center;gap:var(--spacing-2)}.lc-table-pagination__size{display:block;min-width:110px}.lc-table-pagination__btn{appearance:none;border:1px solid var(--color-border);background-color:var(--color-surface);color:var(--color-text-primary);width:28px;height:28px;display:flex;align-items:center;justify-content:center;border-radius:var(--border-radius-sm);font-size:var(--typography-font-size-base);cursor:pointer;transition:background-color .15s ease}.lc-table-pagination__btn:hover:not(:disabled){background-color:var(--color-surface-hover)}.lc-table-pagination__btn:disabled{opacity:.4;cursor:not-allowed}.lc-table-pagination__page{white-space:nowrap;min-width:60px;text-align:center}@media(max-width:640px){.lc-table-wrapper--stack .lc-table thead{display:none}.lc-table-wrapper--stack .lc-table tbody tr{display:block;margin-bottom:var(--spacing-4);border:1px solid var(--color-border);border-radius:var(--border-radius-md)}.lc-table-wrapper--stack .lc-table tbody tr td{display:block;text-align:right;padding:var(--spacing-2) var(--spacing-4);border-bottom:1px solid var(--color-divider)}.lc-table-wrapper--stack .lc-table tbody tr td:last-child{border-bottom:none}.lc-table-wrapper--stack .lc-table tbody tr td:before{content:attr(data-label);float:left;font-weight:var(--typography-font-weight-semibold);color:var(--color-text-secondary)}}\n"],
|
|
978
|
+
template: "<div [class]=\"wrapperClasses()\">\n <table [class]=\"tableClasses()\" [attr.role]=\"treeMode() ? 'treegrid' : 'table'\">\n @if (caption()) {\n <!-- First child of the table, so it names the table (and the treegrid). -->\n <caption class=\"lc-table__caption\" [class.lc-table__caption--hidden]=\"!showCaption()\">{{ caption() }}</caption>\n }\n <thead>\n <!-- Filter row -->\n @if (filterable()) {\n <tr class=\"lc-table__filter-row\">\n @if (selectable()) {\n <th class=\"lc-table__select-cell\"></th>\n }\n @for (column of columns(); track column.key) {\n <th>\n @if (column.filterable !== false) {\n <lc-input\n class=\"lc-table__filter-input\"\n size=\"xs\"\n [placeholder]=\"filterPlaceholderLabel() + ' ' + column.label\"\n [ariaLabel]=\"filterAriaLabel() + ' ' + column.label\"\n [ngModel]=\"getFilterValue(column.key)\"\n (ngModelChange)=\"onFilterChange(column.key, $event)\"\n />\n }\n </th>\n }\n @if (hasActions()) {\n <th class=\"lc-table__actions-cell\"></th>\n }\n </tr>\n }\n <!-- Header row -->\n <tr>\n @if (selectable()) {\n <th class=\"lc-table__select-cell\" scope=\"col\">\n <input\n type=\"checkbox\"\n class=\"lc-table__checkbox\"\n [checked]=\"allSelected()\"\n [indeterminate]=\"someSelected()\"\n (change)=\"toggleSelectAll()\"\n [attr.aria-label]=\"selectAllAriaLabel()\"\n />\n </th>\n }\n @for (column of columns(); track column.key) {\n <!-- A sortable header is a keyboard stop too: Enter/Space sort like a click. -->\n <th\n scope=\"col\"\n [class]=\"getHeaderClasses(column) + (column.cssClass ? ' ' + column.cssClass : '')\"\n [attr.aria-sort]=\"getAriaSort(column.key)\"\n [attr.tabindex]=\"column.sortable ? 0 : null\"\n [style.width]=\"column.width\"\n [title]=\"column.tooltip || ''\"\n (click)=\"handleSort(column.key)\"\n (keydown)=\"column.sortable ? onHeaderKeydown($event, column.key) : null\">\n @if (column.align === 'end') {\n <!-- 3.17: the arrow is placed before the label (CSS), so the label stays\n flush with the figures; in the DOM it still follows the label. No\n whitespace between the label and the arrow. -->\n <span class=\"lc-table__sort-label\">{{ column.label }}@if (column.sortable && getSortState(column.key)) {<span class=\"sort-indicator\" [attr.aria-label]=\"getSortState(column.key) === 'asc' ? sortedAscendingLabel() : sortedDescendingLabel()\">\n @if (getSortState(column.key) === 'asc') {\n ↑\n } @else {\n ↓\n }\n </span>}</span>\n } @else {\n {{ column.label }}\n @if (column.sortable && getSortState(column.key)) {\n <span class=\"sort-indicator\" [attr.aria-label]=\"getSortState(column.key) === 'asc' ? sortedAscendingLabel() : sortedDescendingLabel()\">\n @if (getSortState(column.key) === 'asc') {\n ↑\n } @else {\n ↓\n }\n </span>\n }\n }\n </th>\n }\n @if (hasActions()) {\n <th\n scope=\"col\"\n class=\"lc-table__actions-cell\"\n [class]=\"'lc-table__actions-cell--' + actionsAlign()\"\n [style.width]=\"actionsWidth()\"\n >\n {{ actionsLabel() }}\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (displayRows().length === 0) {\n <tr>\n <td [attr.colspan]=\"columns().length + (selectable() ? 1 : 0) + (hasActions() ? 1 : 0)\" class=\"lc-table__empty\">\n {{ emptyText() }}\n </td>\n </tr>\n } @else {\n @for (dr of displayRows(); track dr.key) {\n <!-- In tree mode the rows form the treegrid's keyboard model: a roving\n tab stop plus Arrow/Home/End/Enter/Space handling (see the\n component). Flat mode keeps plain table rows. -->\n <tr\n #dataRow\n [class.lc-table__row--selected]=\"selectable() && isRowSelected(dr.row)\"\n [class.lc-table__row--group]=\"dr.hasChildren\"\n [attr.role]=\"treeMode() ? 'row' : null\"\n [attr.tabindex]=\"rowTabindex(dr)\"\n [attr.aria-level]=\"treeMode() ? dr.level : null\"\n [attr.aria-expanded]=\"treeMode() && dr.hasChildren ? dr.expanded : null\"\n [attr.aria-posinset]=\"treeMode() ? dr.posInSet : null\"\n [attr.aria-setsize]=\"treeMode() ? dr.setSize : null\"\n [attr.aria-selected]=\"treeMode() && selectable() ? isRowSelected(dr.row) : null\"\n (click)=\"onRowClick(dr.row, $event)\"\n (focus)=\"onRowFocus(dr)\"\n (keydown)=\"onRowKeydown($event, dr)\"\n >\n @if (selectable()) {\n <td class=\"lc-table__select-cell\" [attr.role]=\"treeMode() ? 'gridcell' : null\">\n <input\n type=\"checkbox\"\n class=\"lc-table__checkbox\"\n [checked]=\"isRowSelected(dr.row)\"\n (change)=\"toggleRowSelect(dr.row)\"\n (click)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"selectRowAriaLabel() + ' ' + (dr.absIndex + 1)\"\n />\n </td>\n }\n @for (column of columns(); track column.key) {\n <td\n [class]=\"getCellClasses(dr.row, column, dr.absIndex)\"\n [ngStyle]=\"getCellStyles(dr.row, column, dr.absIndex)\"\n [attr.role]=\"treeMode() ? 'gridcell' : null\"\n (dblclick)=\"editable() ? startEdit(dr.row, column.key, getCellValue(dr.row, column.key)) : null\"\n >\n @if (isTreeColumn(column.key)) {\n <span class=\"lc-table__tree-cell\">\n @for (lvl of indentLevels(dr.depth); track lvl) {\n <span class=\"lc-table__tree-indent\" [style.width.px]=\"indentSize()\"></span>\n }\n <span class=\"lc-table__tree-chevron\" [style.width.px]=\"indentSize()\">\n @if (dr.hasChildren) {\n <button\n type=\"button\"\n class=\"lc-table__chevron-btn\"\n [class.lc-table__chevron-btn--expanded]=\"dr.expanded\"\n [attr.aria-label]=\"(dr.expanded ? collapseRowAriaLabel() : expandRowAriaLabel()) + ' ' + treeCellLabel(dr.row)\"\n [attr.aria-expanded]=\"dr.expanded\"\n (click)=\"onChevronClick(dr, $event)\"\n >\n <lc-icon name=\"chevron-right\" size=\"xs\" [decorative]=\"true\" />\n </button>\n }\n </span>\n <span class=\"lc-table__tree-content\">\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { row: dr.row, column: column, absIndex: dr.absIndex }\"\n ></ng-container>\n </span>\n </span>\n } @else {\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { row: dr.row, column: column, absIndex: dr.absIndex }\"\n ></ng-container>\n }\n </td>\n }\n @if (hasActions()) {\n <td\n class=\"lc-table__actions-cell\"\n [class]=\"'lc-table__actions-cell--' + actionsAlign()\"\n [attr.role]=\"treeMode() ? 'gridcell' : null\"\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"lc-table__actions\">\n @for (action of actions(); track action.key) {\n @if (!isActionHidden(action, dr.row, dr.absIndex)) {\n <lc-button\n [variant]=\"action.variant ?? 'ghost'\"\n size=\"xs\"\n [iconOnly]=\"!action.label\"\n [disabled]=\"isActionDisabled(action, dr.row, dr.absIndex)\"\n [ariaLabel]=\"action.tooltip ?? action.label ?? action.key\"\n (clicked)=\"onActionClick(action, dr.row, dr.absIndex)\"\n >\n @if (action.icon) {\n <lc-icon [name]=\"action.icon\" size=\"sm\" [decorative]=\"true\" />\n }\n @if (action.label) {\n {{ action.label }}\n }\n </lc-button>\n }\n }\n </div>\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n<!-- Shared cell content (edit input / custom template / formatted value) -->\n<ng-template #cellContent let-row=\"row\" let-column=\"column\" let-absIndex=\"absIndex\">\n @if (isEditing(row, column.key)) {\n <input\n #editInput\n type=\"text\"\n class=\"lc-table__edit-input\"\n [value]=\"editValue()\"\n (input)=\"editValue.set(getInputValue($event))\"\n (blur)=\"commitEdit(row, column.key)\"\n (keydown)=\"onEditKeydown($event, row, column.key)\"\n />\n } @else if (hasCustomTemplate(column.key)) {\n <ng-container *ngTemplateOutlet=\"getCellTemplate(column.key)!.template; context: { $implicit: row }\"></ng-container>\n } @else {\n {{ getFormattedCellValue(row, column, absIndex) }}\n }\n</ng-template>\n\n<!-- Pagination -->\n@if (paginate()) {\n <div class=\"lc-table-pagination\">\n <div class=\"lc-table-pagination__info\">\n {{ paginationStart }}–{{ paginationEnd }} {{ rangeOfLabel() }} {{ totalRows() }}\n </div>\n <div class=\"lc-table-pagination__controls\">\n <lc-select\n class=\"lc-table-pagination__size\"\n [size]=\"size() === 'sm' ? 'sm' : size() === 'lg' ? 'lg' : 'md'\"\n [options]=\"pageSizeSelectOptions()\"\n [ngModel]=\"internalPageSize()\"\n [ariaLabel]=\"rowsPerPageAriaLabel()\"\n (ngModelChange)=\"onPageSizeModelChange($event)\"\n />\n <button\n type=\"button\"\n class=\"lc-table-pagination__btn\"\n [disabled]=\"currentPage() === 0\"\n (click)=\"goToPage(currentPage() - 1)\"\n [attr.aria-label]=\"previousPageAriaLabel()\"\n >‹</button>\n <span class=\"lc-table-pagination__page\">\n {{ currentPage() + 1 }} / {{ totalPages() }}\n </span>\n <button\n type=\"button\"\n class=\"lc-table-pagination__btn\"\n [disabled]=\"currentPage() >= totalPages() - 1\"\n (click)=\"goToPage(currentPage() + 1)\"\n [attr.aria-label]=\"nextPageAriaLabel()\"\n >›</button>\n </div>\n </div>\n}\n",
|
|
979
|
+
styles: [".lc-table-wrapper{width:100%}.lc-table-wrapper--responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media(max-width:768px){.lc-table-wrapper--responsive::-webkit-scrollbar{height:8px}.lc-table-wrapper--responsive::-webkit-scrollbar-thumb{background-color:var(--color-border);border-radius:var(--border-radius-sm)}}.lc-table{width:100%;border-collapse:collapse;border-spacing:0;background-color:var(--color-surface);color:var(--color-text-primary);font-family:var(--typography-font-family)}.lc-table thead{background-color:var(--color-surface-2);border-bottom:2px solid var(--color-border-strong)}.lc-table thead tr th{padding:var(--lc-density-padding-sm, var(--spacing-3)) var(--lc-density-padding-md, var(--spacing-4));text-align:left;font-weight:var(--typography-font-weight-semibold);font-size:var(--typography-font-size-sm);text-transform:uppercase;letter-spacing:.04em;color:var(--color-text-secondary);white-space:nowrap;-webkit-user-select:none;user-select:none}.lc-table thead tr th.sortable{cursor:pointer;position:relative;padding-right:var(--spacing-8);transition:background-color .2s ease}.lc-table thead tr th.sortable:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:-2px}.lc-table thead tr th.sortable:hover{background-color:var(--color-surface-hover);color:var(--color-text-primary)}.lc-table thead tr th.sortable .sort-indicator{position:absolute;right:var(--spacing-3);top:50%;transform:translateY(-50%);font-size:var(--typography-font-size-xs);color:var(--color-primary)}.lc-table thead tr th.sorted-asc,.lc-table thead tr th.sorted-desc{background-color:var(--color-surface-hover);color:var(--color-text-primary)}.lc-table tbody tr{border-bottom:1px solid var(--color-divider)}.lc-table tbody tr:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:-2px}.lc-table tbody tr:last-child{border-bottom:none}.lc-table tbody tr td{padding:var(--lc-density-padding-sm, var(--spacing-3)) var(--lc-density-padding-md, var(--spacing-4));font-size:var(--typography-font-size-sm);color:var(--color-text-primary)}.lc-table__empty{text-align:center;padding:var(--spacing-8) var(--spacing-4)!important;color:var(--color-text-secondary);font-style:italic}.lc-table--striped tbody tr:nth-child(2n){background-color:var(--color-surface-2)}.lc-table--bordered{border:1px solid var(--color-border)}.lc-table--bordered thead tr th,.lc-table--bordered tbody tr td{border-right:1px solid var(--color-divider)}.lc-table--bordered thead tr th:last-child,.lc-table--bordered tbody tr td:last-child{border-right:none}.lc-table--bordered tbody tr{border-bottom:1px solid var(--color-border)}.lc-table--hoverable tbody tr,.lc-table--clickable tbody tr{transition:background-color .15s ease;cursor:pointer}.lc-table--hoverable tbody tr:hover,.lc-table--clickable tbody tr:hover{background-color:var(--color-surface-hover)}.lc-table--sm thead tr th,.lc-table--sm tbody tr td{padding:var(--lc-density-padding-xs, var(--spacing-2)) var(--lc-density-padding-sm, var(--spacing-3));font-size:var(--typography-font-size-xs)}.lc-table--lg thead tr th,.lc-table--lg tbody tr td{padding:var(--lc-density-padding-md, var(--spacing-4)) var(--spacing-5);font-size:var(--typography-font-size-base)}.lc-table thead tr th.lc-table__cell--end,.lc-table tbody tr td.lc-table__cell--end{text-align:end;font-variant-numeric:tabular-nums}.lc-table thead tr th.sortable.lc-table__cell--end{padding-inline-start:var(--spacing-8);padding-inline-end:var(--lc-density-padding-md, var(--spacing-4))}.lc-table thead tr th.sortable.lc-table__cell--end .sort-indicator{right:auto;inset-inline-end:calc(100% + var(--spacing-2))}.lc-table--sm thead tr th.sortable.lc-table__cell--end{padding-inline-end:var(--lc-density-padding-sm, var(--spacing-3))}.lc-table--lg thead tr th.sortable.lc-table__cell--end{padding-inline-end:var(--spacing-5)}.lc-table__sort-label{position:relative;display:inline-block}.lc-table__cell--end .lc-table__edit-input{text-align:end;font-variant-numeric:tabular-nums}.lc-table__caption{caption-side:top;padding:0 0 var(--spacing-3);text-align:start;font-family:var(--typography-font-family);font-size:var(--typography-font-size-base);font-weight:var(--typography-font-weight-semibold);line-height:var(--typography-line-height-normal);color:var(--color-text-primary)}.lc-table__caption--hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media(forced-colors:active){.lc-table tbody tr:focus-visible{outline:2px solid Highlight}}.lc-table__filter-row th{padding:var(--spacing-2) var(--spacing-4)!important;background-color:var(--color-surface)!important;border-bottom:1px solid var(--color-divider)!important}.lc-table__filter-input{width:100%;display:block}.lc-table__filter-input .input-field{font-size:var(--typography-font-size-xs)}.lc-table__select-cell{width:40px;text-align:center!important;padding:var(--spacing-2)!important}.lc-table__checkbox{width:16px;height:16px;cursor:pointer;accent-color:var(--color-primary)}.lc-table__row--selected{background-color:var(--color-surface-selected)!important}.lc-table__actions-cell{white-space:nowrap}.lc-table thead tr th.lc-table__actions-cell--start,.lc-table tbody tr td.lc-table__actions-cell--start{text-align:left}.lc-table thead tr th.lc-table__actions-cell--center,.lc-table tbody tr td.lc-table__actions-cell--center{text-align:center}.lc-table thead tr th.lc-table__actions-cell--end,.lc-table tbody tr td.lc-table__actions-cell--end{text-align:right}.lc-table__actions{display:flex;align-items:center;gap:var(--spacing-2);justify-content:flex-start}.lc-table__actions-cell--center .lc-table__actions{justify-content:center}.lc-table__actions-cell--end .lc-table__actions{justify-content:flex-end}.lc-table__tree-cell{display:flex;align-items:center;min-width:0}.lc-table__tree-indent{flex:0 0 auto;align-self:stretch;position:relative}.lc-table__tree-indent:before{content:\"\";position:absolute;left:50%;top:0;bottom:0;width:1px;background-color:var(--color-border)}.lc-table__tree-chevron{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center}.lc-table__chevron-btn{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border:none;background:transparent;color:var(--color-text-secondary);cursor:pointer;border-radius:var(--border-radius-sm);transition:transform .2s ease,background-color .15s ease,color .15s ease}.lc-table__chevron-btn:hover{background-color:var(--color-surface-hover);color:var(--color-text-primary)}.lc-table__chevron-btn:focus-visible{outline:2px solid var(--color-primary);outline-offset:1px}.lc-table__chevron-btn--expanded{transform:rotate(90deg)}.lc-table__tree-content{flex:1 1 auto;min-width:0}.lc-table__row--group .lc-table__tree-content{font-weight:var(--typography-font-weight-semibold)}.lc-table__edit-input{width:100%;padding:var(--spacing-1) var(--spacing-2);border:2px solid var(--color-primary);border-radius:var(--border-radius-sm);font-size:inherit;background-color:var(--color-surface-2);color:var(--color-text-primary);outline:none}.lc-table-pagination{display:flex;align-items:center;justify-content:space-between;padding:var(--spacing-3) var(--spacing-1);font-size:var(--typography-font-size-sm);color:var(--color-text-secondary)}.lc-table-pagination__info{white-space:nowrap}.lc-table-pagination__controls{display:flex;align-items:center;gap:var(--spacing-2)}.lc-table-pagination__size{display:block;min-width:110px}.lc-table-pagination__btn{appearance:none;border:1px solid var(--color-border);background-color:var(--color-surface);color:var(--color-text-primary);width:28px;height:28px;display:flex;align-items:center;justify-content:center;border-radius:var(--border-radius-sm);font-size:var(--typography-font-size-base);cursor:pointer;transition:background-color .15s ease}.lc-table-pagination__btn:hover:not(:disabled){background-color:var(--color-surface-hover)}.lc-table-pagination__btn:disabled{opacity:.4;cursor:not-allowed}.lc-table-pagination__page{white-space:nowrap;min-width:60px;text-align:center}@media(max-width:640px){.lc-table-wrapper--stack .lc-table thead{display:none}.lc-table-wrapper--stack .lc-table tbody tr{display:block;margin-bottom:var(--spacing-4);border:1px solid var(--color-border);border-radius:var(--border-radius-md)}.lc-table-wrapper--stack .lc-table tbody tr td{display:block;text-align:right;padding:var(--spacing-2) var(--spacing-4);border-bottom:1px solid var(--color-divider)}.lc-table-wrapper--stack .lc-table tbody tr td:last-child{border-bottom:none}.lc-table-wrapper--stack .lc-table tbody tr td:before{content:attr(data-label);float:left;font-weight:var(--typography-font-weight-semibold);color:var(--color-text-secondary)}}\n"],
|
|
978
980
|
dependencies: [
|
|
979
981
|
{
|
|
980
982
|
kind: "directive",
|
|
@@ -1148,8 +1150,8 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
1148
1150
|
],
|
|
1149
1151
|
viewProviders: [ɵprovideKitIcons([ICON_CHEVRON_RIGHT])],
|
|
1150
1152
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1151
|
-
template: "<div [class]=\"wrapperClasses()\">\n <table [class]=\"tableClasses()\" [attr.role]=\"treeMode() ? 'treegrid' : 'table'\">\n @if (caption()) {\n <!-- First child of the table, so it names the table (and the treegrid). -->\n <caption class=\"lc-table__caption\" [class.lc-table__caption--hidden]=\"!showCaption()\">{{ caption() }}</caption>\n }\n <thead>\n <!-- Filter row -->\n @if (filterable()) {\n <tr class=\"lc-table__filter-row\">\n @if (selectable()) {\n <th class=\"lc-table__select-cell\"></th>\n }\n @for (column of columns(); track column.key) {\n <th>\n @if (column.filterable !== false) {\n <lc-input\n class=\"lc-table__filter-input\"\n size=\"xs\"\n [placeholder]=\"filterPlaceholderLabel() + ' ' + column.label\"\n [ariaLabel]=\"filterAriaLabel() + ' ' + column.label\"\n [ngModel]=\"getFilterValue(column.key)\"\n (ngModelChange)=\"onFilterChange(column.key, $event)\"\n />\n }\n </th>\n }\n @if (hasActions()) {\n <th class=\"lc-table__actions-cell\"></th>\n }\n </tr>\n }\n <!-- Header row -->\n <tr>\n @if (selectable()) {\n <th class=\"lc-table__select-cell\" scope=\"col\">\n <input\n type=\"checkbox\"\n class=\"lc-table__checkbox\"\n [checked]=\"allSelected()\"\n [indeterminate]=\"someSelected()\"\n (change)=\"toggleSelectAll()\"\n [attr.aria-label]=\"selectAllAriaLabel()\"\n />\n </th>\n }\n @for (column of columns(); track column.key) {\n <!-- A sortable header is a keyboard stop too: Enter/Space sort like a click. -->\n <th\n scope=\"col\"\n [class]=\"getHeaderClasses(column) + (column.cssClass ? ' ' + column.cssClass : '')\"\n [attr.aria-sort]=\"getAriaSort(column.key)\"\n [attr.tabindex]=\"column.sortable ? 0 : null\"\n [style.width]=\"column.width\"\n [title]=\"column.tooltip || ''\"\n (click)=\"handleSort(column.key)\"\n (keydown)=\"column.sortable ? onHeaderKeydown($event, column.key) : null\">\n {{ column.label }}\n @if (column.sortable && getSortState(column.key)) {\n <span class=\"sort-indicator\" [attr.aria-label]=\"getSortState(column.key) === 'asc' ? sortedAscendingLabel() : sortedDescendingLabel()\">\n @if (getSortState(column.key) === 'asc') {\n ↑\n } @else {\n ↓\n }\n </span>\n }\n </th>\n }\n @if (hasActions()) {\n <th\n scope=\"col\"\n class=\"lc-table__actions-cell\"\n [class]=\"'lc-table__actions-cell--' + actionsAlign()\"\n [style.width]=\"actionsWidth()\"\n >\n {{ actionsLabel() }}\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (displayRows().length === 0) {\n <tr>\n <td [attr.colspan]=\"columns().length + (selectable() ? 1 : 0) + (hasActions() ? 1 : 0)\" class=\"lc-table__empty\">\n {{ emptyText() }}\n </td>\n </tr>\n } @else {\n @for (dr of displayRows(); track dr.key) {\n <!-- In tree mode the rows form the treegrid's keyboard model: a roving\n tab stop plus Arrow/Home/End/Enter/Space handling (see the\n component). Flat mode keeps plain table rows. -->\n <tr\n #dataRow\n [class.lc-table__row--selected]=\"selectable() && isRowSelected(dr.row)\"\n [class.lc-table__row--group]=\"dr.hasChildren\"\n [attr.role]=\"treeMode() ? 'row' : null\"\n [attr.tabindex]=\"rowTabindex(dr)\"\n [attr.aria-level]=\"treeMode() ? dr.level : null\"\n [attr.aria-expanded]=\"treeMode() && dr.hasChildren ? dr.expanded : null\"\n [attr.aria-posinset]=\"treeMode() ? dr.posInSet : null\"\n [attr.aria-setsize]=\"treeMode() ? dr.setSize : null\"\n [attr.aria-selected]=\"treeMode() && selectable() ? isRowSelected(dr.row) : null\"\n (click)=\"onRowClick(dr.row, $event)\"\n (focus)=\"onRowFocus(dr)\"\n (keydown)=\"onRowKeydown($event, dr)\"\n >\n @if (selectable()) {\n <td class=\"lc-table__select-cell\" [attr.role]=\"treeMode() ? 'gridcell' : null\">\n <input\n type=\"checkbox\"\n class=\"lc-table__checkbox\"\n [checked]=\"isRowSelected(dr.row)\"\n (change)=\"toggleRowSelect(dr.row)\"\n (click)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"selectRowAriaLabel() + ' ' + (dr.absIndex + 1)\"\n />\n </td>\n }\n @for (column of columns(); track column.key) {\n <td\n [class]=\"getCellClasses(dr.row, column, dr.absIndex)\"\n [ngStyle]=\"getCellStyles(dr.row, column, dr.absIndex)\"\n [attr.role]=\"treeMode() ? 'gridcell' : null\"\n (dblclick)=\"editable() ? startEdit(dr.row, column.key, getCellValue(dr.row, column.key)) : null\"\n >\n @if (isTreeColumn(column.key)) {\n <span class=\"lc-table__tree-cell\">\n @for (lvl of indentLevels(dr.depth); track lvl) {\n <span class=\"lc-table__tree-indent\" [style.width.px]=\"indentSize()\"></span>\n }\n <span class=\"lc-table__tree-chevron\" [style.width.px]=\"indentSize()\">\n @if (dr.hasChildren) {\n <button\n type=\"button\"\n class=\"lc-table__chevron-btn\"\n [class.lc-table__chevron-btn--expanded]=\"dr.expanded\"\n [attr.aria-label]=\"(dr.expanded ? collapseRowAriaLabel() : expandRowAriaLabel()) + ' ' + treeCellLabel(dr.row)\"\n [attr.aria-expanded]=\"dr.expanded\"\n (click)=\"onChevronClick(dr, $event)\"\n >\n <lc-icon name=\"chevron-right\" size=\"xs\" [decorative]=\"true\" />\n </button>\n }\n </span>\n <span class=\"lc-table__tree-content\">\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { row: dr.row, column: column, absIndex: dr.absIndex }\"\n ></ng-container>\n </span>\n </span>\n } @else {\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { row: dr.row, column: column, absIndex: dr.absIndex }\"\n ></ng-container>\n }\n </td>\n }\n @if (hasActions()) {\n <td\n class=\"lc-table__actions-cell\"\n [class]=\"'lc-table__actions-cell--' + actionsAlign()\"\n [attr.role]=\"treeMode() ? 'gridcell' : null\"\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"lc-table__actions\">\n @for (action of actions(); track action.key) {\n @if (!isActionHidden(action, dr.row, dr.absIndex)) {\n <lc-button\n [variant]=\"action.variant ?? 'ghost'\"\n size=\"xs\"\n [iconOnly]=\"!action.label\"\n [disabled]=\"isActionDisabled(action, dr.row, dr.absIndex)\"\n [ariaLabel]=\"action.tooltip ?? action.label ?? action.key\"\n (clicked)=\"onActionClick(action, dr.row, dr.absIndex)\"\n >\n @if (action.icon) {\n <lc-icon [name]=\"action.icon\" size=\"sm\" [decorative]=\"true\" />\n }\n @if (action.label) {\n {{ action.label }}\n }\n </lc-button>\n }\n }\n </div>\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n<!-- Shared cell content (edit input / custom template / formatted value) -->\n<ng-template #cellContent let-row=\"row\" let-column=\"column\" let-absIndex=\"absIndex\">\n @if (isEditing(row, column.key)) {\n <input\n #editInput\n type=\"text\"\n class=\"lc-table__edit-input\"\n [value]=\"editValue()\"\n (input)=\"editValue.set(getInputValue($event))\"\n (blur)=\"commitEdit(row, column.key)\"\n (keydown)=\"onEditKeydown($event, row, column.key)\"\n />\n } @else if (hasCustomTemplate(column.key)) {\n <ng-container *ngTemplateOutlet=\"getCellTemplate(column.key)!.template; context: { $implicit: row }\"></ng-container>\n } @else {\n {{ getFormattedCellValue(row, column, absIndex) }}\n }\n</ng-template>\n\n<!-- Pagination -->\n@if (paginate()) {\n <div class=\"lc-table-pagination\">\n <div class=\"lc-table-pagination__info\">\n {{ paginationStart }}–{{ paginationEnd }} {{ rangeOfLabel() }} {{ totalRows() }}\n </div>\n <div class=\"lc-table-pagination__controls\">\n <lc-select\n class=\"lc-table-pagination__size\"\n [size]=\"size() === 'sm' ? 'sm' : size() === 'lg' ? 'lg' : 'md'\"\n [options]=\"pageSizeSelectOptions()\"\n [ngModel]=\"internalPageSize()\"\n [ariaLabel]=\"rowsPerPageAriaLabel()\"\n (ngModelChange)=\"onPageSizeModelChange($event)\"\n />\n <button\n type=\"button\"\n class=\"lc-table-pagination__btn\"\n [disabled]=\"currentPage() === 0\"\n (click)=\"goToPage(currentPage() - 1)\"\n [attr.aria-label]=\"previousPageAriaLabel()\"\n >‹</button>\n <span class=\"lc-table-pagination__page\">\n {{ currentPage() + 1 }} / {{ totalPages() }}\n </span>\n <button\n type=\"button\"\n class=\"lc-table-pagination__btn\"\n [disabled]=\"currentPage() >= totalPages() - 1\"\n (click)=\"goToPage(currentPage() + 1)\"\n [attr.aria-label]=\"nextPageAriaLabel()\"\n >›</button>\n </div>\n </div>\n}\n",
|
|
1152
|
-
styles: [".lc-table-wrapper{width:100%}.lc-table-wrapper--responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media(max-width:768px){.lc-table-wrapper--responsive::-webkit-scrollbar{height:8px}.lc-table-wrapper--responsive::-webkit-scrollbar-thumb{background-color:var(--color-border);border-radius:var(--border-radius-sm)}}.lc-table{width:100%;border-collapse:collapse;border-spacing:0;background-color:var(--color-surface);color:var(--color-text-primary);font-family:var(--typography-font-family)}.lc-table thead{background-color:var(--color-surface-2);border-bottom:2px solid var(--color-border-strong)}.lc-table thead tr th{padding:var(--lc-density-padding-sm, var(--spacing-3)) var(--lc-density-padding-md, var(--spacing-4));text-align:left;font-weight:var(--typography-font-weight-semibold);font-size:var(--typography-font-size-sm);text-transform:uppercase;letter-spacing:.04em;color:var(--color-text-secondary);white-space:nowrap;-webkit-user-select:none;user-select:none}.lc-table thead tr th.sortable{cursor:pointer;position:relative;padding-right:var(--spacing-8);transition:background-color .2s ease}.lc-table thead tr th.sortable:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:-2px}.lc-table thead tr th.sortable:hover{background-color:var(--color-surface-hover);color:var(--color-text-primary)}.lc-table thead tr th.sortable .sort-indicator{position:absolute;right:var(--spacing-3);top:50%;transform:translateY(-50%);font-size:var(--typography-font-size-xs);color:var(--color-primary)}.lc-table thead tr th.sorted-asc,.lc-table thead tr th.sorted-desc{background-color:var(--color-surface-hover);color:var(--color-text-primary)}.lc-table tbody tr{border-bottom:1px solid var(--color-divider)}.lc-table tbody tr:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:-2px}.lc-table tbody tr:last-child{border-bottom:none}.lc-table tbody tr td{padding:var(--lc-density-padding-sm, var(--spacing-3)) var(--lc-density-padding-md, var(--spacing-4));font-size:var(--typography-font-size-sm);color:var(--color-text-primary)}.lc-table__empty{text-align:center;padding:var(--spacing-8) var(--spacing-4)!important;color:var(--color-text-secondary);font-style:italic}.lc-table--striped tbody tr:nth-child(2n){background-color:var(--color-surface-2)}.lc-table--bordered{border:1px solid var(--color-border)}.lc-table--bordered thead tr th,.lc-table--bordered tbody tr td{border-right:1px solid var(--color-divider)}.lc-table--bordered thead tr th:last-child,.lc-table--bordered tbody tr td:last-child{border-right:none}.lc-table--bordered tbody tr{border-bottom:1px solid var(--color-border)}.lc-table--hoverable tbody tr,.lc-table--clickable tbody tr{transition:background-color .15s ease;cursor:pointer}.lc-table--hoverable tbody tr:hover,.lc-table--clickable tbody tr:hover{background-color:var(--color-surface-hover)}.lc-table--sm thead tr th,.lc-table--sm tbody tr td{padding:var(--lc-density-padding-xs, var(--spacing-2)) var(--lc-density-padding-sm, var(--spacing-3));font-size:var(--typography-font-size-xs)}.lc-table--lg thead tr th,.lc-table--lg tbody tr td{padding:var(--lc-density-padding-md, var(--spacing-4)) var(--spacing-5);font-size:var(--typography-font-size-base)}.lc-table__caption{caption-side:top;padding:0 0 var(--spacing-3);text-align:start;font-family:var(--typography-font-family);font-size:var(--typography-font-size-base);font-weight:var(--typography-font-weight-semibold);line-height:var(--typography-line-height-normal);color:var(--color-text-primary)}.lc-table__caption--hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media(forced-colors:active){.lc-table tbody tr:focus-visible{outline:2px solid Highlight}}.lc-table__filter-row th{padding:var(--spacing-2) var(--spacing-4)!important;background-color:var(--color-surface)!important;border-bottom:1px solid var(--color-divider)!important}.lc-table__filter-input{width:100%;display:block}.lc-table__filter-input .input-field{font-size:var(--typography-font-size-xs)}.lc-table__select-cell{width:40px;text-align:center!important;padding:var(--spacing-2)!important}.lc-table__checkbox{width:16px;height:16px;cursor:pointer;accent-color:var(--color-primary)}.lc-table__row--selected{background-color:var(--color-surface-selected)!important}.lc-table__actions-cell{white-space:nowrap}.lc-table th.lc-table__actions-cell--start,.lc-table td.lc-table__actions-cell--start{text-align:left}.lc-table th.lc-table__actions-cell--center,.lc-table td.lc-table__actions-cell--center{text-align:center}.lc-table th.lc-table__actions-cell--end,.lc-table td.lc-table__actions-cell--end{text-align:right}.lc-table__actions{display:flex;align-items:center;gap:var(--spacing-2);justify-content:flex-start}.lc-table__actions-cell--center .lc-table__actions{justify-content:center}.lc-table__actions-cell--end .lc-table__actions{justify-content:flex-end}.lc-table__tree-cell{display:flex;align-items:center;min-width:0}.lc-table__tree-indent{flex:0 0 auto;align-self:stretch;position:relative}.lc-table__tree-indent:before{content:\"\";position:absolute;left:50%;top:0;bottom:0;width:1px;background-color:var(--color-border)}.lc-table__tree-chevron{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center}.lc-table__chevron-btn{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border:none;background:transparent;color:var(--color-text-secondary);cursor:pointer;border-radius:var(--border-radius-sm);transition:transform .2s ease,background-color .15s ease,color .15s ease}.lc-table__chevron-btn:hover{background-color:var(--color-surface-hover);color:var(--color-text-primary)}.lc-table__chevron-btn:focus-visible{outline:2px solid var(--color-primary);outline-offset:1px}.lc-table__chevron-btn--expanded{transform:rotate(90deg)}.lc-table__tree-content{flex:1 1 auto;min-width:0}.lc-table__row--group .lc-table__tree-content{font-weight:var(--typography-font-weight-semibold)}.lc-table__edit-input{width:100%;padding:var(--spacing-1) var(--spacing-2);border:2px solid var(--color-primary);border-radius:var(--border-radius-sm);font-size:inherit;background-color:var(--color-surface-2);color:var(--color-text-primary);outline:none}.lc-table-pagination{display:flex;align-items:center;justify-content:space-between;padding:var(--spacing-3) var(--spacing-1);font-size:var(--typography-font-size-sm);color:var(--color-text-secondary)}.lc-table-pagination__info{white-space:nowrap}.lc-table-pagination__controls{display:flex;align-items:center;gap:var(--spacing-2)}.lc-table-pagination__size{display:block;min-width:110px}.lc-table-pagination__btn{appearance:none;border:1px solid var(--color-border);background-color:var(--color-surface);color:var(--color-text-primary);width:28px;height:28px;display:flex;align-items:center;justify-content:center;border-radius:var(--border-radius-sm);font-size:var(--typography-font-size-base);cursor:pointer;transition:background-color .15s ease}.lc-table-pagination__btn:hover:not(:disabled){background-color:var(--color-surface-hover)}.lc-table-pagination__btn:disabled{opacity:.4;cursor:not-allowed}.lc-table-pagination__page{white-space:nowrap;min-width:60px;text-align:center}@media(max-width:640px){.lc-table-wrapper--stack .lc-table thead{display:none}.lc-table-wrapper--stack .lc-table tbody tr{display:block;margin-bottom:var(--spacing-4);border:1px solid var(--color-border);border-radius:var(--border-radius-md)}.lc-table-wrapper--stack .lc-table tbody tr td{display:block;text-align:right;padding:var(--spacing-2) var(--spacing-4);border-bottom:1px solid var(--color-divider)}.lc-table-wrapper--stack .lc-table tbody tr td:last-child{border-bottom:none}.lc-table-wrapper--stack .lc-table tbody tr td:before{content:attr(data-label);float:left;font-weight:var(--typography-font-weight-semibold);color:var(--color-text-secondary)}}\n"]
|
|
1153
|
+
template: "<div [class]=\"wrapperClasses()\">\n <table [class]=\"tableClasses()\" [attr.role]=\"treeMode() ? 'treegrid' : 'table'\">\n @if (caption()) {\n <!-- First child of the table, so it names the table (and the treegrid). -->\n <caption class=\"lc-table__caption\" [class.lc-table__caption--hidden]=\"!showCaption()\">{{ caption() }}</caption>\n }\n <thead>\n <!-- Filter row -->\n @if (filterable()) {\n <tr class=\"lc-table__filter-row\">\n @if (selectable()) {\n <th class=\"lc-table__select-cell\"></th>\n }\n @for (column of columns(); track column.key) {\n <th>\n @if (column.filterable !== false) {\n <lc-input\n class=\"lc-table__filter-input\"\n size=\"xs\"\n [placeholder]=\"filterPlaceholderLabel() + ' ' + column.label\"\n [ariaLabel]=\"filterAriaLabel() + ' ' + column.label\"\n [ngModel]=\"getFilterValue(column.key)\"\n (ngModelChange)=\"onFilterChange(column.key, $event)\"\n />\n }\n </th>\n }\n @if (hasActions()) {\n <th class=\"lc-table__actions-cell\"></th>\n }\n </tr>\n }\n <!-- Header row -->\n <tr>\n @if (selectable()) {\n <th class=\"lc-table__select-cell\" scope=\"col\">\n <input\n type=\"checkbox\"\n class=\"lc-table__checkbox\"\n [checked]=\"allSelected()\"\n [indeterminate]=\"someSelected()\"\n (change)=\"toggleSelectAll()\"\n [attr.aria-label]=\"selectAllAriaLabel()\"\n />\n </th>\n }\n @for (column of columns(); track column.key) {\n <!-- A sortable header is a keyboard stop too: Enter/Space sort like a click. -->\n <th\n scope=\"col\"\n [class]=\"getHeaderClasses(column) + (column.cssClass ? ' ' + column.cssClass : '')\"\n [attr.aria-sort]=\"getAriaSort(column.key)\"\n [attr.tabindex]=\"column.sortable ? 0 : null\"\n [style.width]=\"column.width\"\n [title]=\"column.tooltip || ''\"\n (click)=\"handleSort(column.key)\"\n (keydown)=\"column.sortable ? onHeaderKeydown($event, column.key) : null\">\n @if (column.align === 'end') {\n <!-- 3.17: the arrow is placed before the label (CSS), so the label stays\n flush with the figures; in the DOM it still follows the label. No\n whitespace between the label and the arrow. -->\n <span class=\"lc-table__sort-label\">{{ column.label }}@if (column.sortable && getSortState(column.key)) {<span class=\"sort-indicator\" [attr.aria-label]=\"getSortState(column.key) === 'asc' ? sortedAscendingLabel() : sortedDescendingLabel()\">\n @if (getSortState(column.key) === 'asc') {\n ↑\n } @else {\n ↓\n }\n </span>}</span>\n } @else {\n {{ column.label }}\n @if (column.sortable && getSortState(column.key)) {\n <span class=\"sort-indicator\" [attr.aria-label]=\"getSortState(column.key) === 'asc' ? sortedAscendingLabel() : sortedDescendingLabel()\">\n @if (getSortState(column.key) === 'asc') {\n ↑\n } @else {\n ↓\n }\n </span>\n }\n }\n </th>\n }\n @if (hasActions()) {\n <th\n scope=\"col\"\n class=\"lc-table__actions-cell\"\n [class]=\"'lc-table__actions-cell--' + actionsAlign()\"\n [style.width]=\"actionsWidth()\"\n >\n {{ actionsLabel() }}\n </th>\n }\n </tr>\n </thead>\n <tbody>\n @if (displayRows().length === 0) {\n <tr>\n <td [attr.colspan]=\"columns().length + (selectable() ? 1 : 0) + (hasActions() ? 1 : 0)\" class=\"lc-table__empty\">\n {{ emptyText() }}\n </td>\n </tr>\n } @else {\n @for (dr of displayRows(); track dr.key) {\n <!-- In tree mode the rows form the treegrid's keyboard model: a roving\n tab stop plus Arrow/Home/End/Enter/Space handling (see the\n component). Flat mode keeps plain table rows. -->\n <tr\n #dataRow\n [class.lc-table__row--selected]=\"selectable() && isRowSelected(dr.row)\"\n [class.lc-table__row--group]=\"dr.hasChildren\"\n [attr.role]=\"treeMode() ? 'row' : null\"\n [attr.tabindex]=\"rowTabindex(dr)\"\n [attr.aria-level]=\"treeMode() ? dr.level : null\"\n [attr.aria-expanded]=\"treeMode() && dr.hasChildren ? dr.expanded : null\"\n [attr.aria-posinset]=\"treeMode() ? dr.posInSet : null\"\n [attr.aria-setsize]=\"treeMode() ? dr.setSize : null\"\n [attr.aria-selected]=\"treeMode() && selectable() ? isRowSelected(dr.row) : null\"\n (click)=\"onRowClick(dr.row, $event)\"\n (focus)=\"onRowFocus(dr)\"\n (keydown)=\"onRowKeydown($event, dr)\"\n >\n @if (selectable()) {\n <td class=\"lc-table__select-cell\" [attr.role]=\"treeMode() ? 'gridcell' : null\">\n <input\n type=\"checkbox\"\n class=\"lc-table__checkbox\"\n [checked]=\"isRowSelected(dr.row)\"\n (change)=\"toggleRowSelect(dr.row)\"\n (click)=\"$event.stopPropagation()\"\n [attr.aria-label]=\"selectRowAriaLabel() + ' ' + (dr.absIndex + 1)\"\n />\n </td>\n }\n @for (column of columns(); track column.key) {\n <td\n [class]=\"getCellClasses(dr.row, column, dr.absIndex)\"\n [ngStyle]=\"getCellStyles(dr.row, column, dr.absIndex)\"\n [attr.role]=\"treeMode() ? 'gridcell' : null\"\n (dblclick)=\"editable() ? startEdit(dr.row, column.key, getCellValue(dr.row, column.key)) : null\"\n >\n @if (isTreeColumn(column.key)) {\n <span class=\"lc-table__tree-cell\">\n @for (lvl of indentLevels(dr.depth); track lvl) {\n <span class=\"lc-table__tree-indent\" [style.width.px]=\"indentSize()\"></span>\n }\n <span class=\"lc-table__tree-chevron\" [style.width.px]=\"indentSize()\">\n @if (dr.hasChildren) {\n <button\n type=\"button\"\n class=\"lc-table__chevron-btn\"\n [class.lc-table__chevron-btn--expanded]=\"dr.expanded\"\n [attr.aria-label]=\"(dr.expanded ? collapseRowAriaLabel() : expandRowAriaLabel()) + ' ' + treeCellLabel(dr.row)\"\n [attr.aria-expanded]=\"dr.expanded\"\n (click)=\"onChevronClick(dr, $event)\"\n >\n <lc-icon name=\"chevron-right\" size=\"xs\" [decorative]=\"true\" />\n </button>\n }\n </span>\n <span class=\"lc-table__tree-content\">\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { row: dr.row, column: column, absIndex: dr.absIndex }\"\n ></ng-container>\n </span>\n </span>\n } @else {\n <ng-container\n *ngTemplateOutlet=\"cellContent; context: { row: dr.row, column: column, absIndex: dr.absIndex }\"\n ></ng-container>\n }\n </td>\n }\n @if (hasActions()) {\n <td\n class=\"lc-table__actions-cell\"\n [class]=\"'lc-table__actions-cell--' + actionsAlign()\"\n [attr.role]=\"treeMode() ? 'gridcell' : null\"\n (click)=\"$event.stopPropagation()\"\n >\n <div class=\"lc-table__actions\">\n @for (action of actions(); track action.key) {\n @if (!isActionHidden(action, dr.row, dr.absIndex)) {\n <lc-button\n [variant]=\"action.variant ?? 'ghost'\"\n size=\"xs\"\n [iconOnly]=\"!action.label\"\n [disabled]=\"isActionDisabled(action, dr.row, dr.absIndex)\"\n [ariaLabel]=\"action.tooltip ?? action.label ?? action.key\"\n (clicked)=\"onActionClick(action, dr.row, dr.absIndex)\"\n >\n @if (action.icon) {\n <lc-icon [name]=\"action.icon\" size=\"sm\" [decorative]=\"true\" />\n }\n @if (action.label) {\n {{ action.label }}\n }\n </lc-button>\n }\n }\n </div>\n </td>\n }\n </tr>\n }\n }\n </tbody>\n </table>\n</div>\n\n<!-- Shared cell content (edit input / custom template / formatted value) -->\n<ng-template #cellContent let-row=\"row\" let-column=\"column\" let-absIndex=\"absIndex\">\n @if (isEditing(row, column.key)) {\n <input\n #editInput\n type=\"text\"\n class=\"lc-table__edit-input\"\n [value]=\"editValue()\"\n (input)=\"editValue.set(getInputValue($event))\"\n (blur)=\"commitEdit(row, column.key)\"\n (keydown)=\"onEditKeydown($event, row, column.key)\"\n />\n } @else if (hasCustomTemplate(column.key)) {\n <ng-container *ngTemplateOutlet=\"getCellTemplate(column.key)!.template; context: { $implicit: row }\"></ng-container>\n } @else {\n {{ getFormattedCellValue(row, column, absIndex) }}\n }\n</ng-template>\n\n<!-- Pagination -->\n@if (paginate()) {\n <div class=\"lc-table-pagination\">\n <div class=\"lc-table-pagination__info\">\n {{ paginationStart }}–{{ paginationEnd }} {{ rangeOfLabel() }} {{ totalRows() }}\n </div>\n <div class=\"lc-table-pagination__controls\">\n <lc-select\n class=\"lc-table-pagination__size\"\n [size]=\"size() === 'sm' ? 'sm' : size() === 'lg' ? 'lg' : 'md'\"\n [options]=\"pageSizeSelectOptions()\"\n [ngModel]=\"internalPageSize()\"\n [ariaLabel]=\"rowsPerPageAriaLabel()\"\n (ngModelChange)=\"onPageSizeModelChange($event)\"\n />\n <button\n type=\"button\"\n class=\"lc-table-pagination__btn\"\n [disabled]=\"currentPage() === 0\"\n (click)=\"goToPage(currentPage() - 1)\"\n [attr.aria-label]=\"previousPageAriaLabel()\"\n >‹</button>\n <span class=\"lc-table-pagination__page\">\n {{ currentPage() + 1 }} / {{ totalPages() }}\n </span>\n <button\n type=\"button\"\n class=\"lc-table-pagination__btn\"\n [disabled]=\"currentPage() >= totalPages() - 1\"\n (click)=\"goToPage(currentPage() + 1)\"\n [attr.aria-label]=\"nextPageAriaLabel()\"\n >›</button>\n </div>\n </div>\n}\n",
|
|
1154
|
+
styles: [".lc-table-wrapper{width:100%}.lc-table-wrapper--responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media(max-width:768px){.lc-table-wrapper--responsive::-webkit-scrollbar{height:8px}.lc-table-wrapper--responsive::-webkit-scrollbar-thumb{background-color:var(--color-border);border-radius:var(--border-radius-sm)}}.lc-table{width:100%;border-collapse:collapse;border-spacing:0;background-color:var(--color-surface);color:var(--color-text-primary);font-family:var(--typography-font-family)}.lc-table thead{background-color:var(--color-surface-2);border-bottom:2px solid var(--color-border-strong)}.lc-table thead tr th{padding:var(--lc-density-padding-sm, var(--spacing-3)) var(--lc-density-padding-md, var(--spacing-4));text-align:left;font-weight:var(--typography-font-weight-semibold);font-size:var(--typography-font-size-sm);text-transform:uppercase;letter-spacing:.04em;color:var(--color-text-secondary);white-space:nowrap;-webkit-user-select:none;user-select:none}.lc-table thead tr th.sortable{cursor:pointer;position:relative;padding-right:var(--spacing-8);transition:background-color .2s ease}.lc-table thead tr th.sortable:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:-2px}.lc-table thead tr th.sortable:hover{background-color:var(--color-surface-hover);color:var(--color-text-primary)}.lc-table thead tr th.sortable .sort-indicator{position:absolute;right:var(--spacing-3);top:50%;transform:translateY(-50%);font-size:var(--typography-font-size-xs);color:var(--color-primary)}.lc-table thead tr th.sorted-asc,.lc-table thead tr th.sorted-desc{background-color:var(--color-surface-hover);color:var(--color-text-primary)}.lc-table tbody tr{border-bottom:1px solid var(--color-divider)}.lc-table tbody tr:focus-visible{outline:2px solid var(--color-primary-500);outline-offset:-2px}.lc-table tbody tr:last-child{border-bottom:none}.lc-table tbody tr td{padding:var(--lc-density-padding-sm, var(--spacing-3)) var(--lc-density-padding-md, var(--spacing-4));font-size:var(--typography-font-size-sm);color:var(--color-text-primary)}.lc-table__empty{text-align:center;padding:var(--spacing-8) var(--spacing-4)!important;color:var(--color-text-secondary);font-style:italic}.lc-table--striped tbody tr:nth-child(2n){background-color:var(--color-surface-2)}.lc-table--bordered{border:1px solid var(--color-border)}.lc-table--bordered thead tr th,.lc-table--bordered tbody tr td{border-right:1px solid var(--color-divider)}.lc-table--bordered thead tr th:last-child,.lc-table--bordered tbody tr td:last-child{border-right:none}.lc-table--bordered tbody tr{border-bottom:1px solid var(--color-border)}.lc-table--hoverable tbody tr,.lc-table--clickable tbody tr{transition:background-color .15s ease;cursor:pointer}.lc-table--hoverable tbody tr:hover,.lc-table--clickable tbody tr:hover{background-color:var(--color-surface-hover)}.lc-table--sm thead tr th,.lc-table--sm tbody tr td{padding:var(--lc-density-padding-xs, var(--spacing-2)) var(--lc-density-padding-sm, var(--spacing-3));font-size:var(--typography-font-size-xs)}.lc-table--lg thead tr th,.lc-table--lg tbody tr td{padding:var(--lc-density-padding-md, var(--spacing-4)) var(--spacing-5);font-size:var(--typography-font-size-base)}.lc-table thead tr th.lc-table__cell--end,.lc-table tbody tr td.lc-table__cell--end{text-align:end;font-variant-numeric:tabular-nums}.lc-table thead tr th.sortable.lc-table__cell--end{padding-inline-start:var(--spacing-8);padding-inline-end:var(--lc-density-padding-md, var(--spacing-4))}.lc-table thead tr th.sortable.lc-table__cell--end .sort-indicator{right:auto;inset-inline-end:calc(100% + var(--spacing-2))}.lc-table--sm thead tr th.sortable.lc-table__cell--end{padding-inline-end:var(--lc-density-padding-sm, var(--spacing-3))}.lc-table--lg thead tr th.sortable.lc-table__cell--end{padding-inline-end:var(--spacing-5)}.lc-table__sort-label{position:relative;display:inline-block}.lc-table__cell--end .lc-table__edit-input{text-align:end;font-variant-numeric:tabular-nums}.lc-table__caption{caption-side:top;padding:0 0 var(--spacing-3);text-align:start;font-family:var(--typography-font-family);font-size:var(--typography-font-size-base);font-weight:var(--typography-font-weight-semibold);line-height:var(--typography-line-height-normal);color:var(--color-text-primary)}.lc-table__caption--hidden{position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}@media(forced-colors:active){.lc-table tbody tr:focus-visible{outline:2px solid Highlight}}.lc-table__filter-row th{padding:var(--spacing-2) var(--spacing-4)!important;background-color:var(--color-surface)!important;border-bottom:1px solid var(--color-divider)!important}.lc-table__filter-input{width:100%;display:block}.lc-table__filter-input .input-field{font-size:var(--typography-font-size-xs)}.lc-table__select-cell{width:40px;text-align:center!important;padding:var(--spacing-2)!important}.lc-table__checkbox{width:16px;height:16px;cursor:pointer;accent-color:var(--color-primary)}.lc-table__row--selected{background-color:var(--color-surface-selected)!important}.lc-table__actions-cell{white-space:nowrap}.lc-table thead tr th.lc-table__actions-cell--start,.lc-table tbody tr td.lc-table__actions-cell--start{text-align:left}.lc-table thead tr th.lc-table__actions-cell--center,.lc-table tbody tr td.lc-table__actions-cell--center{text-align:center}.lc-table thead tr th.lc-table__actions-cell--end,.lc-table tbody tr td.lc-table__actions-cell--end{text-align:right}.lc-table__actions{display:flex;align-items:center;gap:var(--spacing-2);justify-content:flex-start}.lc-table__actions-cell--center .lc-table__actions{justify-content:center}.lc-table__actions-cell--end .lc-table__actions{justify-content:flex-end}.lc-table__tree-cell{display:flex;align-items:center;min-width:0}.lc-table__tree-indent{flex:0 0 auto;align-self:stretch;position:relative}.lc-table__tree-indent:before{content:\"\";position:absolute;left:50%;top:0;bottom:0;width:1px;background-color:var(--color-border)}.lc-table__tree-chevron{flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center}.lc-table__chevron-btn{display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;padding:0;border:none;background:transparent;color:var(--color-text-secondary);cursor:pointer;border-radius:var(--border-radius-sm);transition:transform .2s ease,background-color .15s ease,color .15s ease}.lc-table__chevron-btn:hover{background-color:var(--color-surface-hover);color:var(--color-text-primary)}.lc-table__chevron-btn:focus-visible{outline:2px solid var(--color-primary);outline-offset:1px}.lc-table__chevron-btn--expanded{transform:rotate(90deg)}.lc-table__tree-content{flex:1 1 auto;min-width:0}.lc-table__row--group .lc-table__tree-content{font-weight:var(--typography-font-weight-semibold)}.lc-table__edit-input{width:100%;padding:var(--spacing-1) var(--spacing-2);border:2px solid var(--color-primary);border-radius:var(--border-radius-sm);font-size:inherit;background-color:var(--color-surface-2);color:var(--color-text-primary);outline:none}.lc-table-pagination{display:flex;align-items:center;justify-content:space-between;padding:var(--spacing-3) var(--spacing-1);font-size:var(--typography-font-size-sm);color:var(--color-text-secondary)}.lc-table-pagination__info{white-space:nowrap}.lc-table-pagination__controls{display:flex;align-items:center;gap:var(--spacing-2)}.lc-table-pagination__size{display:block;min-width:110px}.lc-table-pagination__btn{appearance:none;border:1px solid var(--color-border);background-color:var(--color-surface);color:var(--color-text-primary);width:28px;height:28px;display:flex;align-items:center;justify-content:center;border-radius:var(--border-radius-sm);font-size:var(--typography-font-size-base);cursor:pointer;transition:background-color .15s ease}.lc-table-pagination__btn:hover:not(:disabled){background-color:var(--color-surface-hover)}.lc-table-pagination__btn:disabled{opacity:.4;cursor:not-allowed}.lc-table-pagination__page{white-space:nowrap;min-width:60px;text-align:center}@media(max-width:640px){.lc-table-wrapper--stack .lc-table thead{display:none}.lc-table-wrapper--stack .lc-table tbody tr{display:block;margin-bottom:var(--spacing-4);border:1px solid var(--color-border);border-radius:var(--border-radius-md)}.lc-table-wrapper--stack .lc-table tbody tr td{display:block;text-align:right;padding:var(--spacing-2) var(--spacing-4);border-bottom:1px solid var(--color-divider)}.lc-table-wrapper--stack .lc-table tbody tr td:last-child{border-bottom:none}.lc-table-wrapper--stack .lc-table tbody tr td:before{content:attr(data-label);float:left;font-weight:var(--typography-font-weight-semibold);color:var(--color-text-secondary)}}\n"]
|
|
1153
1155
|
}]
|
|
1154
1156
|
}],
|
|
1155
1157
|
ctorParameters: () => [],
|