@testgorilla/tgo-ui 12.1.0 → 12.3.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/testgorilla-tgo-ui-components-ai-feedback.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-ai-feedback.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-alert-banner.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-alert-banner.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-avatar.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-avatar.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-badge.mjs +2 -2
- package/fesm2022/testgorilla-tgo-ui-components-badge.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-breadcrumb.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-breadcrumb.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-button.mjs +19 -4
- package/fesm2022/testgorilla-tgo-ui-components-button.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-checklist.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-checklist.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-core.mjs +11 -1
- package/fesm2022/testgorilla-tgo-ui-components-core.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-dialog.mjs +6 -0
- package/fesm2022/testgorilla-tgo-ui-components-dialog.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-dropdown.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-dropdown.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-empty-state.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-empty-state.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-field.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-field.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-filter-button.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-filter-button.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-inline-field.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-inline-field.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-media-card.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-media-card.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-media-dialog.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-media-dialog.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-navbar.mjs +6 -0
- package/fesm2022/testgorilla-tgo-ui-components-navbar.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-overflow-menu.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-overflow-menu.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-page-header.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-page-header.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-popover.mjs +250 -50
- package/fesm2022/testgorilla-tgo-ui-components-popover.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-prompt.mjs +4 -0
- package/fesm2022/testgorilla-tgo-ui-components-prompt.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-radial-progress.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-radial-progress.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-scale-table.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-scale-table.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-side-navigation.mjs +89 -7
- package/fesm2022/testgorilla-tgo-ui-components-side-navigation.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-side-panel.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-side-panel.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-side-sheet.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-side-sheet.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-snackbar.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-snackbar.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-table.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-table.mjs.map +1 -1
- package/fesm2022/testgorilla-tgo-ui-components-write-with-ai.mjs +3 -0
- package/fesm2022/testgorilla-tgo-ui-components-write-with-ai.mjs.map +1 -1
- package/mcp/catalog.json +1 -1
- package/package.json +1 -1
- package/types/testgorilla-tgo-ui-components-button.d.ts +32 -0
- package/types/testgorilla-tgo-ui-components-core.d.ts +1 -0
- package/types/testgorilla-tgo-ui-components-popover.d.ts +51 -5
- package/types/testgorilla-tgo-ui-components-side-navigation.d.ts +59 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testgorilla-tgo-ui-components-table.mjs","names":[],"sources":["../../../components/table/sentence-case.pipe.ts","../../../components/table/table.model.ts","../../../components/table/table.utils.ts","../../../components/table/table.component.ts","../../../components/table/table.component.html","../../../components/table/table.component.module.ts"],"sourcesContent":["import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({ name: 'sentencecase' })\nexport class SentenceCasePipe implements PipeTransform {\n transform(value: string | undefined): string {\n if (!value) {\n return '';\n }\n return value.charAt(0).toUpperCase() + value.slice(1).toLowerCase();\n }\n}\n","import { TemplateRef, Type } from '@angular/core';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- consumer-ergonomic default row type; consumers narrow via TableConfig<MyRow>\nexport interface TableConfig<T = any> {\n columns: TableColumn<T>[];\n pagination?: Pagination;\n title?: string;\n width?: number;\n sort?: Sort;\n hidePagination?: boolean;\n noDataRowTpl?: TemplateRef<unknown>;\n sortable?: boolean;\n}\n\nexport interface TableConfigWithPagination<T> extends TableConfig<T> {\n pagination?: Pagination;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- consumer-ergonomic default row type; consumers narrow via TableColumn<MyRow>\nexport interface TableColumn<T = any> {\n title?: string;\n key: string;\n allowMultiline?: boolean;\n bold?: boolean;\n showTooltip?: boolean;\n tooltip?: string;\n allowSort?: boolean;\n isSticky?: boolean;\n headerCellTemplate?: TemplateRef<unknown>;\n rowCellTemplate?: TemplateRef<unknown>;\n rowCellTemplateClick?: () => void;\n sortHeader?: string;\n hidden?: boolean;\n order?: number;\n fontSize?: '12px' | '14px';\n field?: string;\n type?: ColumnType;\n function?: (v: T) => string;\n renderer?: (v: T) => ComponentRenderer | string;\n styles?: ColumnStyles;\n sortStart?: SortDirection;\n uniqueId?: string;\n}\n\nexport interface Pagination {\n itemsPerPageOptions: number[];\n itemsPerPage: number;\n currentPage: number;\n totalItems: number;\n}\n\nexport type TableData = Record<string, unknown>[];\n\nexport interface ColumnEllipse {\n index: number;\n showTooltip: boolean;\n}\n\nexport interface Sort {\n active: string;\n direction: SortDirection;\n defaultSortStart?: SortDirection;\n}\n\nexport type SortDirection = 'asc' | 'desc' | '';\n\nexport interface TableDetailColumn<T, TDetail> {\n columnDefs: TableColumn<TDetail>[];\n setDetailRowData: (params: DetailRowDataParams<T, TDetail>) => void;\n}\n\nexport interface DetailRowDataParams<T, TDetail> {\n data: T;\n\n setDetailDataSource(rowData: TDetail[]): void;\n}\n\nexport enum ColumnType {\n FIELD = 'field',\n FUNCTION = 'function',\n RENDERER = 'renderer',\n}\n\nexport interface ComponentRenderer {\n component: Type<unknown>;\n inputs?: Record<string, unknown>;\n outputs?: { [key: string]: (event: unknown) => void };\n}\n\nexport interface ColumnStyles {\n alignment?: ColumnAlignment;\n width?: string;\n 'min-width'?: string;\n padding?: string;\n}\n\nexport enum ColumnAlignment {\n LEFT = 'left',\n RIGHT = 'right',\n CENTER = 'center',\n}\n\nexport enum ColumnTypeEnum {\n FIELD = 'field',\n FUNCTION = 'function',\n RENDERER = 'renderer',\n}\n\nexport enum ColumnAlignmentEnum {\n LEFT = 'left',\n RIGHT = 'right',\n CENTER = 'center',\n}\n\nexport type DataSource = {\n [key: string]: unknown;\n};\n\nexport type ScrollSettings = { scrollEnd: boolean; horizontalScroll: boolean; scrollStart: boolean };\n","import { TableColumn } from './table.model';\n\n/**\n * Sorting table columns by order value if set.\n * The rest columns keep the same ordering and displayed after the sorted ones.\n */\nexport const sortByOrder = <T>(columns: TableColumn<T>[]): TableColumn<T>[] => {\n const withOrderColumns = columns.filter(v => v.order);\n const withoutOrderColumns = columns.filter(v => !v.order);\n\n if (!withOrderColumns.length) {\n return columns;\n }\n\n if (withoutOrderColumns.length) {\n const sortedColumns = new Array<TableColumn<T>>(columns.length);\n withOrderColumns.forEach(column => (sortedColumns[(column.order ?? 1) - 1] = column));\n withoutOrderColumns.forEach(column => {\n const emptyIndex = sortedColumns.findIndex(v => !v);\n sortedColumns[emptyIndex] = column;\n });\n return sortedColumns;\n } else {\n const sortedOrderedColumns = withOrderColumns.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\n\n return [...sortedOrderedColumns, ...withoutOrderColumns];\n }\n};\n","import { animate, state, style, transition, trigger } from '@angular/animations';\nimport { NgClass, NgStyle, NgTemplateOutlet, AsyncPipe, UpperCasePipe } from '@angular/common';\nimport {\n AfterViewInit,\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n EventEmitter,\n Inject,\n Input,\n OnChanges,\n Optional,\n Output,\n SimpleChanges,\n ViewChild,\n OnInit,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { PageEvent } from '@angular/material/paginator';\nimport { Sort, MatSort, MatSortHeader } from '@angular/material/sort';\nimport {\n MatTableDataSource,\n MatTable,\n MatColumnDef,\n MatHeaderCellDef,\n MatHeaderCell,\n MatCellDef,\n MatCell,\n MatHeaderRowDef,\n MatHeaderRow,\n MatRowDef,\n MatRow,\n MatNoDataRow,\n} from '@angular/material/table';\nimport { MatTooltip } from '@angular/material/tooltip';\nimport { BehaviorSubject, fromEvent, Observable } from 'rxjs';\n\nimport { ButtonComponent } from '@testgorilla/tgo-ui/components/button';\nimport {\n DynamicComponentDirective,\n ApplicationTheme,\n IS_MOBILE_TOKEN,\n EllipseTextDirective,\n DataPropertyGetterPipe,\n MemoizeFuncPipe,\n} from '@testgorilla/tgo-ui/components/core';\nimport { IconComponent } from '@testgorilla/tgo-ui/components/icon';\nimport { PaginatorComponent } from '@testgorilla/tgo-ui/components/paginator';\nimport { SkeletonComponent } from '@testgorilla/tgo-ui/components/skeleton';\n\nimport { SentenceCasePipe } from './sentence-case.pipe';\nimport {\n ColumnEllipse,\n ColumnType,\n ComponentRenderer,\n DataSource,\n Pagination,\n ScrollSettings,\n TableColumn,\n TableConfig,\n TableConfigWithPagination,\n TableData,\n TableDetailColumn,\n} from './table.model';\nimport { sortByOrder } from './table.utils';\n\n@Component({\n selector: 'ui-table',\n templateUrl: './table.component.html',\n styleUrls: ['./table.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n /* eslint-disable @typescript-eslint/no-deprecated -- the @angular/animations trigger/state/style/animate/transition DSL is deprecated in 20.2 in favor of template-level animate.enter/animate.leave; migrating every Material/component animation is out of scope for this lint pass */\n animations: [\n trigger('expandDetail', [\n state('collapsed, void', style({ height: '0px' })),\n state('expanded', style({ height: '*' })),\n transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),\n transition('expanded <=> void', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),\n ]),\n ],\n imports: [\n NgClass,\n MatTable,\n MatSort,\n MatColumnDef,\n MatHeaderCellDef,\n MatHeaderCell,\n MatSortHeader,\n NgStyle,\n NgTemplateOutlet,\n MatCellDef,\n MatCell,\n SkeletonComponent,\n MatHeaderRowDef,\n MatHeaderRow,\n MatRowDef,\n MatRow,\n DynamicComponentDirective,\n MatNoDataRow,\n PaginatorComponent,\n ButtonComponent,\n EllipseTextDirective,\n IconComponent,\n MatTooltip,\n AsyncPipe,\n UpperCasePipe,\n DataPropertyGetterPipe,\n MemoizeFuncPipe,\n SentenceCasePipe,\n ],\n})\nexport class TableComponent<T extends DataSource, TDetail extends DataSource>\n implements OnChanges, AfterViewInit, OnInit\n{\n /**\n * Table configuration\n *\n * @type {TableConfig}\n * @memberof TableComponent\n */\n @Input({ required: true }) config: TableConfigWithPagination<T>;\n\n /**\n * Input property for providing the table data.\n *\n * @type {TableData}\n * @memberof TableComponent\n */\n @Input() data: TableData;\n\n /**\n * Input property indicating whether the table is in a loading state.\n *\n * @type {boolean}\n * @memberof TableComponent\n * @default false\n */\n @Input() loading = false;\n\n /**\n *\n * Defines the application theme\n * @type {ApplicationTheme}\n * @memberof TableComponent\n */\n @Input() applicationTheme: ApplicationTheme = 'light';\n\n /**\n * Data structure to select which columns should be rendered and their capabilities\n *\n * @type {TableDetailColumn}\n * @memberof TableComponent\n */\n @Input() tableDetailColumns: TableDetailColumn<T, TDetail>;\n @Input() tableDetails = false;\n\n /**\n * Disable border radius for table\n *\n * @type {boolean}\n * @memberof TableComponent\n */\n @Input() disableBorderRadius = false;\n\n /**\n * Condensed table\n *\n * @type {boolean}\n * @memberof TableComponent\n */\n @Input() isCondensed = false;\n\n /**\n * Sticky header\n *\n * @type {boolean}\n * @memberof TableComponent\n */\n @Input() stickyHeader = false;\n\n /**\n * Max height\n *\n * @type {string}\n * @memberof TableComponent\n */\n @Input() maxHeight = '576px';\n\n @Input() testId: string | null = null;\n\n @Input() ariaLabel = '';\n\n // eslint-disable-next-line @angular-eslint/no-output-on-prefix -- public output; dropping on- prefix is breaking, deferred to the breaking-change MAJOR (see plan)\n @Output() onRowClickEvent = new EventEmitter<T & { index: number }>();\n // eslint-disable-next-line @angular-eslint/no-output-on-prefix -- public output; dropping on- prefix is breaking, deferred to the breaking-change MAJOR (see plan)\n @Output() onDetailRowClickEvent = new EventEmitter<TDetail>();\n @Output() paginatorChange = new EventEmitter<PageEvent>();\n @Output() sortChange = new EventEmitter<Sort>();\n\n @ViewChild('table') table: ElementRef<HTMLElement>;\n\n protected tableData: TableData;\n protected sourceData: TableData;\n protected columnsTooltipState: ColumnEllipse[] = [];\n protected tableConfig: TableConfigWithPagination<T>;\n protected displayedColumns: string[] = [];\n protected columnsDetailToDisplay: string[] = [];\n protected skeletonStyleConfig = {\n background: '#F6F6F6',\n 'border-radius': '4px',\n height: '24px',\n };\n protected dataSourceDetail = new MatTableDataSource<TDetail>([]);\n protected elementDetail: T | null;\n protected readonly DataType = ColumnType;\n protected scrollSettings$ = new BehaviorSubject<ScrollSettings>({\n scrollEnd: false,\n horizontalScroll: false,\n scrollStart: false,\n });\n\n constructor(\n @Optional() @Inject('CANOPYUI_DEFAULT_APPLICATION_THEME') private readonly defaultAppTheme: ApplicationTheme,\n private readonly destroyRef: DestroyRef,\n @Inject(IS_MOBILE_TOKEN) protected readonly isMobile$: Observable<boolean>\n ) {\n if (defaultAppTheme) {\n this.applicationTheme = defaultAppTheme;\n }\n }\n\n ngOnInit() {\n this.setTableConfig(this.config);\n this.setTableData(this.data);\n\n if (this.applicationTheme !== 'classic') {\n this.skeletonStyleConfig.background = '#F4F4F4';\n }\n document.body.setAttribute('theme', this.applicationTheme);\n\n if (this.tableDetailColumns) {\n const filteredColumns = this.tableDetailColumns.columnDefs.filter(column => !column.hidden);\n this.columnsDetailToDisplay = filteredColumns.length\n ? filteredColumns.map((tableColumn: TableColumn<TDetail>) => tableColumn.title ?? '')\n : [];\n }\n\n if (this.tableConfig?.sortable && this.tableConfig?.sort) {\n this.onSortChange(this.tableConfig.sort, false);\n }\n }\n\n ngAfterViewInit() {\n this.hasTableScroll();\n fromEvent(this.table.nativeElement, 'scroll')\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(() => this.hasTableScroll());\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['config']?.currentValue) {\n const config = changes['config'].currentValue as TableConfig<T>;\n this.setTableConfig(config);\n }\n if (changes['data']?.currentValue) {\n this.setTableData(changes['data'].currentValue as TableData);\n }\n }\n\n hasTableScroll(): void {\n const table = this.table.nativeElement;\n const horizontalScroll = table.scrollWidth > table.clientWidth;\n const scrollEnd = table.scrollLeft + table.clientWidth >= table.scrollWidth;\n this.scrollSettings$.next({\n scrollStart: !table.scrollLeft,\n scrollEnd,\n horizontalScroll,\n });\n }\n\n callRenderer([rendererFn, element]: [(v: T) => ComponentRenderer | string, T]):\n | ComponentRenderer\n | string\n | undefined {\n return rendererFn ? rendererFn(element) : undefined;\n }\n\n protected onPaginatorChange(event: PageEvent): void {\n this.paginatorChange.emit(event);\n }\n\n protected onChangeColumnSize(columnIndex: number, showTooltip: boolean): void {\n this.columnsTooltipState = this.columnsTooltipState.map(column => {\n if (column.index === columnIndex) {\n column.showTooltip = showTooltip;\n }\n return column;\n });\n }\n\n protected onSortChange(sortState: Sort, emitEvent = true): void {\n if (this.loading) {\n return;\n }\n\n if (emitEvent) {\n this.sortChange.emit(sortState);\n }\n\n if (this.tableConfig?.sortable) {\n this.tableData = [\n ...this.tableData.sort((a, b) => {\n const isAsc = sortState.direction === 'asc';\n // Cell values are dynamically keyed (TableData is Record<string, any>); assert a\n // comparable type — the cast is erased at runtime so JS relational compare is unchanged.\n const aVal = a[sortState.active] as number;\n const bVal = b[sortState.active] as number;\n return (aVal < bVal ? -1 : 1) * (isAsc ? 1 : -1);\n }),\n ];\n\n if (!sortState.direction) {\n this.tableData = [...this.sourceData];\n }\n }\n }\n\n protected onRowClick(rowParams: T, rowIndex: number): void {\n this.onRowClickEvent.emit({ ...rowParams, index: rowIndex });\n }\n\n protected onDetailRowClick(rowParams: TDetail): void {\n this.onDetailRowClickEvent.emit(rowParams);\n }\n\n protected toggleRow(element: T): void {\n if (this.tableDetails) {\n this.elementDetail = this.elementDetail === element ? null : element;\n if (this.elementDetail) {\n this.tableDetailColumns.setDetailRowData({\n data: element,\n setDetailDataSource: this.setTableDetailDataSource.bind(this),\n });\n }\n }\n }\n\n private setTableDetailDataSource(rowData: TDetail[]): void {\n this.dataSourceDetail = new MatTableDataSource<TDetail>(rowData);\n }\n\n private setTableConfig(config: TableConfig<T>): void {\n config.pagination = config?.pagination ?? this.defaultPaginationConfig;\n\n this.tableConfig = config;\n\n this.columnsTooltipState = config.columns.map((column, index) => ({\n index,\n showTooltip: column.showTooltip ?? false,\n }));\n this.displayedColumns = sortByOrder<T>(config.columns.filter(column => !column.hidden)).map(\n column => column.uniqueId ?? column.key\n );\n }\n\n private setTableData(data: TableData): void {\n this.sourceData = data;\n this.tableData = data;\n }\n\n private readonly defaultPaginationConfig: Pagination = {\n currentPage: 0,\n itemsPerPage: 10,\n itemsPerPageOptions: [10, 25, 50],\n totalItems: 20,\n };\n\n trackColumnUniqueId = (index: number, column: TableColumn<T>): string => column.uniqueId ?? column.key;\n}\n","<div\n #tableContainer\n class=\"table-container\"\n [ngClass]=\"{ 'without-title': !tableConfig?.title, 'disable-border-radius': disableBorderRadius }\"\n [attr.theme]=\"applicationTheme\"\n>\n @if (tableConfig?.title) {\n <div class=\"table-header\">\n {{ tableConfig.title | sentencecase }}\n <ng-content select=\"[title-actions]\"></ng-content>\n </div>\n }\n @if (scrollSettings$ | async; as scrollSettings) {\n <div #table class=\"table-wrapper\" [class.sticky-header]=\"stickyHeader\" [style.--table-max-height]=\"maxHeight\">\n <table\n [attr.data-testid]=\"testId ?? 'table-main'\"\n [attr.aria-label]=\"ariaLabel || null\"\n [tabIndex]=\"0\"\n class=\"main-table\"\n [class.condensed]=\"isCondensed\"\n [class.sort-disabled]=\"loading\"\n mat-table\n [dataSource]=\"tableData\"\n matSort\n [matSortStart]=\"tableConfig?.sort?.defaultSortStart ?? 'asc'\"\n [matSortActive]=\"tableConfig?.sort?.active ?? ''\"\n [matSortDirection]=\"tableConfig?.sort?.direction ?? ''\"\n (matSortChange)=\"onSortChange($event)\"\n multiTemplateDataRows\n >\n @for (column of tableConfig.columns; track trackColumnUniqueId(i, column); let i = $index; let isLast = $last) {\n @if (isLast && column.isSticky && column.allowSort) {\n <ng-container [matColumnDef]=\"column.uniqueId ?? column.key\" [stickyEnd]=\"!scrollSettings?.scrollEnd\">\n <th\n mat-header-cell\n [start]=\"column.sortStart ?? 'asc'\"\n [mat-sort-header]=\"column.sortHeader ?? column.key\"\n *matHeaderCellDef\n [attr.sortable]=\"column.allowSort ?? false\"\n [ngStyle]=\"{\n width: $safeNavigationMigration(column.styles?.width),\n minWidth: $safeNavigationMigration(column.styles?.['min-width']),\n }\"\n [ngClass]=\"column.styles?.alignment ? 'th-' + $safeNavigationMigration(column.styles?.alignment) : ''\"\n [style.font-weight]=\"'bold'\"\n >\n @if (column.headerCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"\n column.headerCellTemplate;\n context: { $implicit: column.title, column, colIndex: i }\n \"\n ></ng-container>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"columnHeader\"\n [ngTemplateOutletContext]=\"{ i, column }\"\n ></ng-container>\n }\n </th>\n <td\n mat-cell\n *matCellDef=\"let element; let rowIndex = dataIndex\"\n [align]=\"$safeNavigationMigration(column.styles?.alignment)\"\n [ngClass]=\"[column.styles?.alignment ? 'td-' + $safeNavigationMigration(column.styles?.alignment) : '']\"\n (click)=\"\n onRowClick(element, rowIndex); column?.rowCellTemplateClick ? column!.rowCellTemplateClick?.() : ''\n \"\n >\n @if (loading) {\n <ui-skeleton\n class=\"table-skeleton-loader\"\n [count]=\"1\"\n [theme]=\"skeletonStyleConfig\"\n [appearance]=\"'line'\"\n ></ui-skeleton>\n } @else {\n <div class=\"row-value\">\n <ng-container\n [ngTemplateOutlet]=\"expandButton\"\n [ngTemplateOutletContext]=\"{ index: i, element }\"\n ></ng-container>\n @if (column?.type) {\n <ng-container\n *ngTemplateOutlet=\"tableDataTpl; context: { element, tableColumn: column }\"\n ></ng-container>\n } @else {\n @if (column.rowCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.rowCellTemplate; context: { $implicit: element, rowIndex }\"\n ></ng-container>\n } @else {\n <span\n [style.font-weight]=\"column.bold ? 'bold' : 'normal'\"\n [style.font-size]=\"column.fontSize ?? '14px'\"\n >{{ element | dataPropertyGetter: column.key }}</span\n >\n }\n }\n </div>\n }\n </td>\n </ng-container>\n }\n @if (isLast && column.isSticky && !column.allowSort) {\n <ng-container\n [matColumnDef]=\"column.uniqueId ?? column.key\"\n [stickyEnd]=\"scrollSettings.horizontalScroll ? !scrollSettings.scrollEnd : true\"\n >\n <th\n mat-header-cell\n *matHeaderCellDef\n [attr.sortable]=\"column.allowSort ?? false\"\n [ngStyle]=\"{\n width: $safeNavigationMigration(column.styles?.width),\n minWidth: $safeNavigationMigration(column.styles?.['min-width']),\n }\"\n [ngClass]=\"column.styles?.alignment ? 'th-' + $safeNavigationMigration(column.styles?.alignment) : ''\"\n [style.font-weight]=\"'bold'\"\n >\n @if (column.headerCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"\n column.headerCellTemplate;\n context: { $implicit: column.title, column, colIndex: i }\n \"\n ></ng-container>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"columnHeader\"\n [ngTemplateOutletContext]=\"{ i, column }\"\n ></ng-container>\n }\n </th>\n <td\n mat-cell\n *matCellDef=\"let element; let rowIndex = dataIndex\"\n [align]=\"$safeNavigationMigration(column.styles?.alignment)\"\n [ngClass]=\"[column.styles?.alignment ? 'td-' + $safeNavigationMigration(column.styles?.alignment) : '']\"\n (click)=\"\n onRowClick(element, rowIndex); column?.rowCellTemplateClick ? column!.rowCellTemplateClick?.() : ''\n \"\n >\n @if (loading) {\n <ui-skeleton\n class=\"table-skeleton-loader\"\n [count]=\"1\"\n [theme]=\"skeletonStyleConfig\"\n [appearance]=\"'line'\"\n ></ui-skeleton>\n } @else {\n <div class=\"row-value\">\n <ng-container\n [ngTemplateOutlet]=\"expandButton\"\n [ngTemplateOutletContext]=\"{ index: i, element }\"\n ></ng-container>\n @if (column?.type) {\n <ng-container\n *ngTemplateOutlet=\"tableDataTpl; context: { element, tableColumn: column }\"\n ></ng-container>\n } @else {\n @if (column.rowCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.rowCellTemplate; context: { $implicit: element, rowIndex }\"\n ></ng-container>\n } @else {\n <span\n [style.font-weight]=\"column.bold ? 'bold' : 'normal'\"\n [style.font-size]=\"column.fontSize ?? '14px'\"\n >{{ element | dataPropertyGetter: column.key }}</span\n >\n }\n }\n </div>\n }\n </td>\n </ng-container>\n }\n @if (!(isLast && column.isSticky) && column.allowSort) {\n <ng-container\n [matColumnDef]=\"column.uniqueId ?? column.key\"\n [sticky]=\"(isMobile$ | async) ? false : !scrollSettings.scrollStart && !!column.isSticky\"\n >\n <th\n mat-header-cell\n [start]=\"column.sortStart ?? 'asc'\"\n [mat-sort-header]=\"column.sortHeader ?? column.key\"\n [attr.sortable]=\"column.allowSort ?? false\"\n *matHeaderCellDef\n [style.font-weight]=\"'bold'\"\n [ngStyle]=\"{\n width: $safeNavigationMigration(column.styles?.width),\n minWidth: $safeNavigationMigration(column.styles?.['min-width']),\n }\"\n [ngClass]=\"column.styles?.alignment ? 'th-' + $safeNavigationMigration(column.styles?.alignment) : ''\"\n >\n @if (column.headerCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"\n column.headerCellTemplate;\n context: { $implicit: column.title, column, colIndex: i }\n \"\n ></ng-container>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"columnHeader\"\n [ngTemplateOutletContext]=\"{ i, column }\"\n ></ng-container>\n }\n </th>\n <td\n mat-cell\n *matCellDef=\"let element; let rowIndex = dataIndex\"\n [align]=\"$safeNavigationMigration(column.styles?.alignment)\"\n [ngClass]=\"[column.styles?.alignment ? 'td-' + $safeNavigationMigration(column.styles?.alignment) : '']\"\n (click)=\"\n onRowClick(element, rowIndex); column?.rowCellTemplateClick ? column!.rowCellTemplateClick?.() : ''\n \"\n >\n @if (loading) {\n <ui-skeleton\n class=\"table-skeleton-loader\"\n [count]=\"1\"\n [theme]=\"skeletonStyleConfig\"\n [appearance]=\"'line'\"\n ></ui-skeleton>\n } @else {\n <div class=\"row-value\">\n <ng-container\n [ngTemplateOutlet]=\"expandButton\"\n [ngTemplateOutletContext]=\"{ index: i, element }\"\n ></ng-container>\n @if (column?.type) {\n <ng-container\n *ngTemplateOutlet=\"tableDataTpl; context: { element, tableColumn: column }\"\n ></ng-container>\n } @else {\n @if (column.rowCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.rowCellTemplate; context: { $implicit: element, rowIndex }\"\n ></ng-container>\n } @else {\n <span\n [style.font-weight]=\"column.bold ? 'bold' : 'normal'\"\n [style.font-size]=\"column.fontSize ?? '14px'\"\n >{{ element | dataPropertyGetter: column.key }}</span\n >\n }\n }\n </div>\n }\n </td>\n </ng-container>\n }\n @if (!(isLast && column.isSticky) && !column.allowSort) {\n <ng-container\n [matColumnDef]=\"column.uniqueId ?? column.key\"\n [sticky]=\"(isMobile$ | async) ? false : !scrollSettings.scrollStart && !!column.isSticky\"\n >\n <th\n mat-header-cell\n [attr.sortable]=\"column.allowSort ?? false\"\n *matHeaderCellDef\n [style.font-weight]=\"'bold'\"\n [ngStyle]=\"{\n width: $safeNavigationMigration(column.styles?.width),\n minWidth: $safeNavigationMigration(column.styles?.['min-width']),\n }\"\n [ngClass]=\"column.styles?.alignment ? 'th-' + $safeNavigationMigration(column.styles?.alignment) : ''\"\n >\n @if (column.headerCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"\n column.headerCellTemplate;\n context: { $implicit: column.title, column, colIndex: i }\n \"\n ></ng-container>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"columnHeader\"\n [ngTemplateOutletContext]=\"{ i, column }\"\n ></ng-container>\n }\n </th>\n <td\n mat-cell\n *matCellDef=\"let element; let rowIndex = dataIndex\"\n [align]=\"$safeNavigationMigration(column.styles?.alignment)\"\n [ngClass]=\"[column.styles?.alignment ? 'td-' + $safeNavigationMigration(column.styles?.alignment) : '']\"\n (click)=\"\n onRowClick(element, rowIndex); column?.rowCellTemplateClick ? column!.rowCellTemplateClick?.() : ''\n \"\n >\n @if (loading) {\n <ui-skeleton\n class=\"table-skeleton-loader\"\n [count]=\"1\"\n [theme]=\"skeletonStyleConfig\"\n [appearance]=\"'line'\"\n ></ui-skeleton>\n } @else {\n <div class=\"row-value\">\n <ng-container\n [ngTemplateOutlet]=\"expandButton\"\n [ngTemplateOutletContext]=\"{ index: i, element }\"\n ></ng-container>\n @if (column?.type) {\n <ng-container\n *ngTemplateOutlet=\"tableDataTpl; context: { element, tableColumn: column }\"\n ></ng-container>\n } @else {\n @if (column.rowCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.rowCellTemplate; context: { $implicit: element, rowIndex }\"\n ></ng-container>\n } @else {\n <span\n [style.font-weight]=\"column.bold ? 'bold' : 'normal'\"\n [style.font-size]=\"column.fontSize ?? '14px'\"\n >{{ element | dataPropertyGetter: column.key }}</span\n >\n }\n }\n </div>\n }\n </td>\n </ng-container>\n }\n }\n <ng-container matColumnDef=\"expandedDetail\">\n <td mat-cell *matCellDef=\"let element\" [attr.colspan]=\"displayedColumns.length\">\n @if (dataSourceDetail.data.length) {\n <div class=\"element-detail\" [@expandDetail]=\"element === elementDetail ? 'expanded' : 'collapsed'\">\n <table\n data-testid=\"table-detail\"\n mat-table\n [dataSource]=\"dataSourceDetail\"\n [ngClass]=\"{ 'hide-borders': element === tableData[tableData.length - 1] }\"\n >\n @for (tableColumn of tableDetailColumns.columnDefs; track tableColumn) {\n <ng-container [matColumnDef]=\"tableColumn.title ?? ''\">\n <th\n mat-header-cell\n *matHeaderCellDef=\"let element\"\n arrowPosition=\"after\"\n [ngStyle]=\"{ width: $safeNavigationMigration(tableColumn.styles?.width) }\"\n [ngClass]=\"\n tableColumn.styles?.alignment\n ? 'th-' + $safeNavigationMigration(tableColumn.styles?.alignment)\n : ''\n \"\n >\n {{ tableColumn.title | uppercase }}\n </th>\n <td\n mat-cell\n *matCellDef=\"let element\"\n (click)=\"onDetailRowClick(element)\"\n [align]=\"$safeNavigationMigration(tableColumn.styles?.alignment)\"\n [ngClass]=\"\n tableColumn.styles?.alignment\n ? 'td-' + $safeNavigationMigration(tableColumn.styles?.alignment)\n : ''\n \"\n [ngStyle]=\"{ width: $safeNavigationMigration(tableColumn.styles?.width) }\"\n >\n <ng-container\n *ngTemplateOutlet=\"tableDataTpl; context: { element, tableColumn }\"\n ></ng-container>\n </td>\n </ng-container>\n }\n <tr mat-header-row *matHeaderRowDef=\"columnsDetailToDisplay\"></tr>\n <tr mat-row *matRowDef=\"let rowDetail; columns: columnsDetailToDisplay\"></tr>\n </table>\n </div>\n }\n </td>\n </ng-container>\n <ng-template #tableDataTpl let-element=\"element\" let-tableColumn=\"tableColumn\">\n <div class=\"align-wrapper\">\n @switch (tableColumn.type) {\n @case (DataType.FIELD) {\n {{ element | dataPropertyGetter: tableColumn.key }}\n }\n @case (DataType.FUNCTION) {\n {{ tableColumn.function?.(element) }}\n }\n @case (DataType.RENDERER) {\n <ng-template [dynamicComponent]=\"$any([tableColumn.renderer, element] | memoizeFunc: callRenderer)\">\n </ng-template>\n }\n @default {\n {{ element | dataPropertyGetter: tableColumn.key }}\n }\n }\n </div>\n </ng-template>\n <tr\n mat-header-row\n *matHeaderRowDef=\"displayedColumns; sticky: stickyHeader\"\n [class.is-title-present]=\"tableConfig.title\"\n ></tr>\n <tr\n mat-row\n *matRowDef=\"let row; columns: displayedColumns\"\n [ngClass]=\"{\n 'expanded-row': elementDetail === row,\n 'row-clickable': tableDetails,\n selected: $safeNavigationMigration(row?.selected),\n 'last-row': row === tableData[tableData.length - 1] && !elementDetail,\n }\"\n (click)=\"toggleRow(row)\"\n ></tr>\n @if (tableDetails && tableDetailColumns?.columnDefs?.length) {\n <tr mat-row *matRowDef=\"let row; columns: ['expandedDetail']\" class=\"detail-row\"></tr>\n }\n @if (tableConfig.noDataRowTpl) {\n <tr *matNoDataRow>\n <ng-container *ngTemplateOutlet=\"tableConfig.noDataRowTpl\"></ng-container>\n </tr>\n }\n </table>\n </div>\n }\n\n @if (!tableConfig?.hidePagination && tableConfig?.pagination) {\n <ui-paginator\n [disabled]=\"loading\"\n [applicationTheme]=\"applicationTheme !== 'classic' ? 'light' : 'classic'\"\n [pageSize]=\"tableConfig.pagination?.itemsPerPage ?? 25\"\n [length]=\"tableConfig.pagination?.totalItems ?? 0\"\n [currentPage]=\"tableConfig.pagination?.currentPage ?? 0\"\n [pageSizeOptions]=\"tableConfig.pagination?.itemsPerPageOptions ?? [10, 25, 50]\"\n (paginatorChange)=\"onPaginatorChange($event)\"\n ></ui-paginator>\n }\n</div>\n\n<ng-template #expandButton let-i=\"index\" let-element=\"element\">\n @if (!i && tableDetails) {\n <ui-button\n [applicationTheme]=\"applicationTheme\"\n variant=\"icon-button\"\n [ngClass]=\"{ opened: elementDetail && element === elementDetail }\"\n [iconName]=\"\n elementDetail && element === elementDetail ? 'Arrow-chevron-up-in-line' : 'Arrow-chevron-down-in-line'\n \"\n ></ui-button>\n }\n</ng-template>\n\n<ng-template #columnHeader let-column=\"column\" let-i=\"i\">\n <div class=\"header-section\">\n <span uiEllipseText (onChangeTextState)=\"onChangeColumnSize(i, $event)\" class=\"column-title\"\n >{{ column.title | sentencecase }}\n </span>\n @if (column?.showTooltip) {\n <ui-icon\n [name]=\"'Help-in-line'\"\n [matTooltipClass]=\"applicationTheme\"\n [matTooltip]=\"(column?.showTooltip ? (column?.tooltip ? column.tooltip : column.title) : '') || ''\"\n ></ui-icon>\n }\n </div>\n</ng-template>\n","import { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { MatSortModule } from '@angular/material/sort';\nimport { MatTableModule } from '@angular/material/table';\nimport { MatTooltipModule } from '@angular/material/tooltip';\n\nimport { ButtonComponentModule } from '@testgorilla/tgo-ui/components/button';\nimport {\n EllipseTextDirective,\n MemoizeFuncPipe,\n DataPropertyGetterPipe,\n DynamicComponentDirective,\n} from '@testgorilla/tgo-ui/components/core';\nimport { IconComponentModule } from '@testgorilla/tgo-ui/components/icon';\nimport { PaginatorComponentModule } from '@testgorilla/tgo-ui/components/paginator';\nimport { SkeletonComponent } from '@testgorilla/tgo-ui/components/skeleton';\n\nimport { SentenceCasePipe } from './sentence-case.pipe';\nimport { TableComponent } from './table.component';\n\n@NgModule({\n imports: [\n CommonModule,\n MatTableModule,\n MatTooltipModule,\n SkeletonComponent,\n PaginatorComponentModule,\n ButtonComponentModule,\n MatSortModule,\n IconComponentModule,\n EllipseTextDirective,\n DynamicComponentDirective,\n DataPropertyGetterPipe,\n MemoizeFuncPipe,\n TableComponent,\n SentenceCasePipe,\n ],\n exports: [TableComponent],\n})\nexport class TableComponentModule {}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"testgorilla-tgo-ui-components-table.mjs","names":[],"sources":["../../../components/table/sentence-case.pipe.ts","../../../components/table/table.model.ts","../../../components/table/table.utils.ts","../../../components/table/table.component.ts","../../../components/table/table.component.html","../../../components/table/table.component.module.ts"],"sourcesContent":["import { Pipe, PipeTransform } from '@angular/core';\n\n@Pipe({ name: 'sentencecase' })\nexport class SentenceCasePipe implements PipeTransform {\n transform(value: string | undefined): string {\n if (!value) {\n return '';\n }\n return value.charAt(0).toUpperCase() + value.slice(1).toLowerCase();\n }\n}\n","import { TemplateRef, Type } from '@angular/core';\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- consumer-ergonomic default row type; consumers narrow via TableConfig<MyRow>\nexport interface TableConfig<T = any> {\n columns: TableColumn<T>[];\n pagination?: Pagination;\n title?: string;\n width?: number;\n sort?: Sort;\n hidePagination?: boolean;\n noDataRowTpl?: TemplateRef<unknown>;\n sortable?: boolean;\n}\n\nexport interface TableConfigWithPagination<T> extends TableConfig<T> {\n pagination?: Pagination;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- consumer-ergonomic default row type; consumers narrow via TableColumn<MyRow>\nexport interface TableColumn<T = any> {\n title?: string;\n key: string;\n allowMultiline?: boolean;\n bold?: boolean;\n showTooltip?: boolean;\n tooltip?: string;\n allowSort?: boolean;\n isSticky?: boolean;\n headerCellTemplate?: TemplateRef<unknown>;\n rowCellTemplate?: TemplateRef<unknown>;\n rowCellTemplateClick?: () => void;\n sortHeader?: string;\n hidden?: boolean;\n order?: number;\n fontSize?: '12px' | '14px';\n field?: string;\n type?: ColumnType;\n function?: (v: T) => string;\n renderer?: (v: T) => ComponentRenderer | string;\n styles?: ColumnStyles;\n sortStart?: SortDirection;\n uniqueId?: string;\n}\n\nexport interface Pagination {\n itemsPerPageOptions: number[];\n itemsPerPage: number;\n currentPage: number;\n totalItems: number;\n}\n\nexport type TableData = Record<string, unknown>[];\n\nexport interface ColumnEllipse {\n index: number;\n showTooltip: boolean;\n}\n\nexport interface Sort {\n active: string;\n direction: SortDirection;\n defaultSortStart?: SortDirection;\n}\n\nexport type SortDirection = 'asc' | 'desc' | '';\n\nexport interface TableDetailColumn<T, TDetail> {\n columnDefs: TableColumn<TDetail>[];\n setDetailRowData: (params: DetailRowDataParams<T, TDetail>) => void;\n}\n\nexport interface DetailRowDataParams<T, TDetail> {\n data: T;\n\n setDetailDataSource(rowData: TDetail[]): void;\n}\n\nexport enum ColumnType {\n FIELD = 'field',\n FUNCTION = 'function',\n RENDERER = 'renderer',\n}\n\nexport interface ComponentRenderer {\n component: Type<unknown>;\n inputs?: Record<string, unknown>;\n outputs?: { [key: string]: (event: unknown) => void };\n}\n\nexport interface ColumnStyles {\n alignment?: ColumnAlignment;\n width?: string;\n 'min-width'?: string;\n padding?: string;\n}\n\nexport enum ColumnAlignment {\n LEFT = 'left',\n RIGHT = 'right',\n CENTER = 'center',\n}\n\nexport enum ColumnTypeEnum {\n FIELD = 'field',\n FUNCTION = 'function',\n RENDERER = 'renderer',\n}\n\nexport enum ColumnAlignmentEnum {\n LEFT = 'left',\n RIGHT = 'right',\n CENTER = 'center',\n}\n\nexport type DataSource = {\n [key: string]: unknown;\n};\n\nexport type ScrollSettings = { scrollEnd: boolean; horizontalScroll: boolean; scrollStart: boolean };\n","import { TableColumn } from './table.model';\n\n/**\n * Sorting table columns by order value if set.\n * The rest columns keep the same ordering and displayed after the sorted ones.\n */\nexport const sortByOrder = <T>(columns: TableColumn<T>[]): TableColumn<T>[] => {\n const withOrderColumns = columns.filter(v => v.order);\n const withoutOrderColumns = columns.filter(v => !v.order);\n\n if (!withOrderColumns.length) {\n return columns;\n }\n\n if (withoutOrderColumns.length) {\n const sortedColumns = new Array<TableColumn<T>>(columns.length);\n withOrderColumns.forEach(column => (sortedColumns[(column.order ?? 1) - 1] = column));\n withoutOrderColumns.forEach(column => {\n const emptyIndex = sortedColumns.findIndex(v => !v);\n sortedColumns[emptyIndex] = column;\n });\n return sortedColumns;\n } else {\n const sortedOrderedColumns = withOrderColumns.sort((a, b) => (a.order ?? 0) - (b.order ?? 0));\n\n return [...sortedOrderedColumns, ...withoutOrderColumns];\n }\n};\n","import { animate, state, style, transition, trigger } from '@angular/animations';\nimport { NgClass, NgStyle, NgTemplateOutlet, AsyncPipe, UpperCasePipe } from '@angular/common';\nimport {\n AfterViewInit,\n ChangeDetectionStrategy,\n Component,\n DestroyRef,\n ElementRef,\n EventEmitter,\n Inject,\n Input,\n OnChanges,\n Optional,\n Output,\n SimpleChanges,\n ViewChild,\n OnInit,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { PageEvent } from '@angular/material/paginator';\nimport { Sort, MatSort, MatSortHeader } from '@angular/material/sort';\nimport {\n MatTableDataSource,\n MatTable,\n MatColumnDef,\n MatHeaderCellDef,\n MatHeaderCell,\n MatCellDef,\n MatCell,\n MatHeaderRowDef,\n MatHeaderRow,\n MatRowDef,\n MatRow,\n MatNoDataRow,\n} from '@angular/material/table';\nimport { MatTooltip } from '@angular/material/tooltip';\nimport { BehaviorSubject, fromEvent, Observable } from 'rxjs';\n\nimport { ButtonComponent } from '@testgorilla/tgo-ui/components/button';\nimport {\n DynamicComponentDirective,\n ApplicationTheme,\n IS_MOBILE_TOKEN,\n EllipseTextDirective,\n DataPropertyGetterPipe,\n MemoizeFuncPipe,\n} from '@testgorilla/tgo-ui/components/core';\nimport { IconComponent } from '@testgorilla/tgo-ui/components/icon';\nimport { PaginatorComponent } from '@testgorilla/tgo-ui/components/paginator';\nimport { SkeletonComponent } from '@testgorilla/tgo-ui/components/skeleton';\n\nimport { SentenceCasePipe } from './sentence-case.pipe';\nimport {\n ColumnEllipse,\n ColumnType,\n ComponentRenderer,\n DataSource,\n Pagination,\n ScrollSettings,\n TableColumn,\n TableConfig,\n TableConfigWithPagination,\n TableData,\n TableDetailColumn,\n} from './table.model';\nimport { sortByOrder } from './table.utils';\n\n@Component({\n selector: 'ui-table',\n templateUrl: './table.component.html',\n styleUrls: ['./table.component.scss'],\n changeDetection: ChangeDetectionStrategy.OnPush,\n /* eslint-disable @typescript-eslint/no-deprecated -- the @angular/animations trigger/state/style/animate/transition DSL is deprecated in 20.2 in favor of template-level animate.enter/animate.leave; migrating every Material/component animation is out of scope for this lint pass */\n animations: [\n trigger('expandDetail', [\n state('collapsed, void', style({ height: '0px' })),\n state('expanded', style({ height: '*' })),\n transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),\n transition('expanded <=> void', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),\n ]),\n ],\n imports: [\n NgClass,\n MatTable,\n MatSort,\n MatColumnDef,\n MatHeaderCellDef,\n MatHeaderCell,\n MatSortHeader,\n NgStyle,\n NgTemplateOutlet,\n MatCellDef,\n MatCell,\n SkeletonComponent,\n MatHeaderRowDef,\n MatHeaderRow,\n MatRowDef,\n MatRow,\n DynamicComponentDirective,\n MatNoDataRow,\n PaginatorComponent,\n ButtonComponent,\n EllipseTextDirective,\n IconComponent,\n MatTooltip,\n AsyncPipe,\n UpperCasePipe,\n DataPropertyGetterPipe,\n MemoizeFuncPipe,\n SentenceCasePipe,\n ],\n})\nexport class TableComponent<T extends DataSource, TDetail extends DataSource>\n implements OnChanges, AfterViewInit, OnInit\n{\n /**\n * Table configuration\n *\n * @type {TableConfig}\n * @memberof TableComponent\n */\n @Input({ required: true }) config: TableConfigWithPagination<T>;\n\n /**\n * Input property for providing the table data.\n *\n * @type {TableData}\n * @memberof TableComponent\n */\n @Input() data: TableData;\n\n /**\n * Input property indicating whether the table is in a loading state.\n *\n * @type {boolean}\n * @memberof TableComponent\n * @default false\n */\n @Input() loading = false;\n\n /**\n *\n * Defines the application theme\n * @type {ApplicationTheme}\n * @memberof TableComponent\n */\n @Input() applicationTheme: ApplicationTheme = 'light';\n\n /**\n * Data structure to select which columns should be rendered and their capabilities\n *\n * @type {TableDetailColumn}\n * @memberof TableComponent\n */\n @Input() tableDetailColumns: TableDetailColumn<T, TDetail>;\n @Input() tableDetails = false;\n\n /**\n * Disable border radius for table\n *\n * @type {boolean}\n * @memberof TableComponent\n */\n @Input() disableBorderRadius = false;\n\n /**\n * Condensed table\n *\n * @type {boolean}\n * @memberof TableComponent\n */\n @Input() isCondensed = false;\n\n /**\n * Sticky header\n *\n * @type {boolean}\n * @memberof TableComponent\n */\n @Input() stickyHeader = false;\n\n /**\n * Max height\n *\n * @type {string}\n * @memberof TableComponent\n */\n @Input() maxHeight = '576px';\n\n @Input() testId: string | null = null;\n\n @Input() ariaLabel = '';\n\n // eslint-disable-next-line @angular-eslint/no-output-on-prefix -- public output; dropping on- prefix is breaking, deferred to the breaking-change MAJOR (see plan)\n @Output() onRowClickEvent = new EventEmitter<T & { index: number }>();\n // eslint-disable-next-line @angular-eslint/no-output-on-prefix -- public output; dropping on- prefix is breaking, deferred to the breaking-change MAJOR (see plan)\n @Output() onDetailRowClickEvent = new EventEmitter<TDetail>();\n @Output() paginatorChange = new EventEmitter<PageEvent>();\n @Output() sortChange = new EventEmitter<Sort>();\n\n @ViewChild('table') table: ElementRef<HTMLElement>;\n\n protected tableData: TableData;\n protected sourceData: TableData;\n protected columnsTooltipState: ColumnEllipse[] = [];\n protected tableConfig: TableConfigWithPagination<T>;\n protected displayedColumns: string[] = [];\n protected columnsDetailToDisplay: string[] = [];\n protected skeletonStyleConfig = {\n background: '#F6F6F6',\n 'border-radius': '4px',\n height: '24px',\n };\n protected dataSourceDetail = new MatTableDataSource<TDetail>([]);\n protected elementDetail: T | null;\n protected readonly DataType = ColumnType;\n protected scrollSettings$ = new BehaviorSubject<ScrollSettings>({\n scrollEnd: false,\n horizontalScroll: false,\n scrollStart: false,\n });\n\n constructor(\n @Optional() @Inject('CANOPYUI_DEFAULT_APPLICATION_THEME') private readonly defaultAppTheme: ApplicationTheme,\n private readonly destroyRef: DestroyRef,\n @Inject(IS_MOBILE_TOKEN) protected readonly isMobile$: Observable<boolean>\n ) {\n if (defaultAppTheme) {\n this.applicationTheme = defaultAppTheme;\n }\n }\n\n ngOnInit() {\n this.setTableConfig(this.config);\n this.setTableData(this.data);\n\n if (this.applicationTheme !== 'classic') {\n this.skeletonStyleConfig.background = '#F4F4F4';\n }\n document.body.setAttribute('theme', this.applicationTheme);\n\n if (this.tableDetailColumns) {\n const filteredColumns = this.tableDetailColumns.columnDefs.filter(column => !column.hidden);\n this.columnsDetailToDisplay = filteredColumns.length\n ? filteredColumns.map((tableColumn: TableColumn<TDetail>) => tableColumn.title ?? '')\n : [];\n }\n\n if (this.tableConfig?.sortable && this.tableConfig?.sort) {\n this.onSortChange(this.tableConfig.sort, false);\n }\n }\n\n ngAfterViewInit() {\n this.hasTableScroll();\n fromEvent(this.table.nativeElement, 'scroll')\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe(() => this.hasTableScroll());\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes['config']?.currentValue) {\n const config = changes['config'].currentValue as TableConfig<T>;\n this.setTableConfig(config);\n }\n if (changes['data']?.currentValue) {\n this.setTableData(changes['data'].currentValue as TableData);\n }\n }\n\n hasTableScroll(): void {\n const table = this.table.nativeElement;\n const horizontalScroll = table.scrollWidth > table.clientWidth;\n const scrollEnd = table.scrollLeft + table.clientWidth >= table.scrollWidth;\n this.scrollSettings$.next({\n scrollStart: !table.scrollLeft,\n scrollEnd,\n horizontalScroll,\n });\n }\n\n callRenderer([rendererFn, element]: [(v: T) => ComponentRenderer | string, T]):\n | ComponentRenderer\n | string\n | undefined {\n return rendererFn ? rendererFn(element) : undefined;\n }\n\n protected onPaginatorChange(event: PageEvent): void {\n this.paginatorChange.emit(event);\n }\n\n protected onChangeColumnSize(columnIndex: number, showTooltip: boolean): void {\n this.columnsTooltipState = this.columnsTooltipState.map(column => {\n if (column.index === columnIndex) {\n column.showTooltip = showTooltip;\n }\n return column;\n });\n }\n\n protected onSortChange(sortState: Sort, emitEvent = true): void {\n if (this.loading) {\n return;\n }\n\n if (emitEvent) {\n this.sortChange.emit(sortState);\n }\n\n if (this.tableConfig?.sortable) {\n this.tableData = [\n ...this.tableData.sort((a, b) => {\n const isAsc = sortState.direction === 'asc';\n // Cell values are dynamically keyed (TableData is Record<string, any>); assert a\n // comparable type — the cast is erased at runtime so JS relational compare is unchanged.\n const aVal = a[sortState.active] as number;\n const bVal = b[sortState.active] as number;\n return (aVal < bVal ? -1 : 1) * (isAsc ? 1 : -1);\n }),\n ];\n\n if (!sortState.direction) {\n this.tableData = [...this.sourceData];\n }\n }\n }\n\n protected onRowClick(rowParams: T, rowIndex: number): void {\n this.onRowClickEvent.emit({ ...rowParams, index: rowIndex });\n }\n\n protected onDetailRowClick(rowParams: TDetail): void {\n this.onDetailRowClickEvent.emit(rowParams);\n }\n\n protected toggleRow(element: T): void {\n if (this.tableDetails) {\n this.elementDetail = this.elementDetail === element ? null : element;\n if (this.elementDetail) {\n this.tableDetailColumns.setDetailRowData({\n data: element,\n setDetailDataSource: this.setTableDetailDataSource.bind(this),\n });\n }\n }\n }\n\n private setTableDetailDataSource(rowData: TDetail[]): void {\n this.dataSourceDetail = new MatTableDataSource<TDetail>(rowData);\n }\n\n private setTableConfig(config: TableConfig<T>): void {\n config.pagination = config?.pagination ?? this.defaultPaginationConfig;\n\n this.tableConfig = config;\n\n this.columnsTooltipState = config.columns.map((column, index) => ({\n index,\n showTooltip: column.showTooltip ?? false,\n }));\n this.displayedColumns = sortByOrder<T>(config.columns.filter(column => !column.hidden)).map(\n column => column.uniqueId ?? column.key\n );\n }\n\n private setTableData(data: TableData): void {\n this.sourceData = data;\n this.tableData = data;\n }\n\n private readonly defaultPaginationConfig: Pagination = {\n currentPage: 0,\n itemsPerPage: 10,\n itemsPerPageOptions: [10, 25, 50],\n totalItems: 20,\n };\n\n trackColumnUniqueId = (index: number, column: TableColumn<T>): string => column.uniqueId ?? column.key;\n}\n","<div\n #tableContainer\n class=\"table-container\"\n [ngClass]=\"{ 'without-title': !tableConfig?.title, 'disable-border-radius': disableBorderRadius }\"\n [attr.theme]=\"applicationTheme\"\n>\n @if (tableConfig?.title) {\n <div class=\"table-header\">\n {{ tableConfig.title | sentencecase }}\n <ng-content select=\"[title-actions]\"></ng-content>\n </div>\n }\n @if (scrollSettings$ | async; as scrollSettings) {\n <div #table class=\"table-wrapper\" [class.sticky-header]=\"stickyHeader\" [style.--table-max-height]=\"maxHeight\">\n <table\n [attr.data-testid]=\"testId ?? 'table-main'\"\n [attr.aria-label]=\"ariaLabel || null\"\n [tabIndex]=\"0\"\n class=\"main-table\"\n [class.condensed]=\"isCondensed\"\n [class.sort-disabled]=\"loading\"\n mat-table\n [dataSource]=\"tableData\"\n matSort\n [matSortStart]=\"tableConfig?.sort?.defaultSortStart ?? 'asc'\"\n [matSortActive]=\"tableConfig?.sort?.active ?? ''\"\n [matSortDirection]=\"tableConfig?.sort?.direction ?? ''\"\n (matSortChange)=\"onSortChange($event)\"\n multiTemplateDataRows\n >\n @for (column of tableConfig.columns; track trackColumnUniqueId(i, column); let i = $index; let isLast = $last) {\n @if (isLast && column.isSticky && column.allowSort) {\n <ng-container [matColumnDef]=\"column.uniqueId ?? column.key\" [stickyEnd]=\"!scrollSettings?.scrollEnd\">\n <th\n mat-header-cell\n [start]=\"column.sortStart ?? 'asc'\"\n [mat-sort-header]=\"column.sortHeader ?? column.key\"\n *matHeaderCellDef\n [attr.sortable]=\"column.allowSort ?? false\"\n [ngStyle]=\"{\n width: $safeNavigationMigration(column.styles?.width),\n minWidth: $safeNavigationMigration(column.styles?.['min-width']),\n }\"\n [ngClass]=\"column.styles?.alignment ? 'th-' + $safeNavigationMigration(column.styles?.alignment) : ''\"\n [style.font-weight]=\"'bold'\"\n >\n @if (column.headerCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"\n column.headerCellTemplate;\n context: { $implicit: column.title, column, colIndex: i }\n \"\n ></ng-container>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"columnHeader\"\n [ngTemplateOutletContext]=\"{ i, column }\"\n ></ng-container>\n }\n </th>\n <td\n mat-cell\n *matCellDef=\"let element; let rowIndex = dataIndex\"\n [align]=\"$safeNavigationMigration(column.styles?.alignment)\"\n [ngClass]=\"[column.styles?.alignment ? 'td-' + $safeNavigationMigration(column.styles?.alignment) : '']\"\n (click)=\"\n onRowClick(element, rowIndex); column?.rowCellTemplateClick ? column!.rowCellTemplateClick?.() : ''\n \"\n >\n @if (loading) {\n <ui-skeleton\n class=\"table-skeleton-loader\"\n [count]=\"1\"\n [theme]=\"skeletonStyleConfig\"\n [appearance]=\"'line'\"\n ></ui-skeleton>\n } @else {\n <div class=\"row-value\">\n <ng-container\n [ngTemplateOutlet]=\"expandButton\"\n [ngTemplateOutletContext]=\"{ index: i, element }\"\n ></ng-container>\n @if (column?.type) {\n <ng-container\n *ngTemplateOutlet=\"tableDataTpl; context: { element, tableColumn: column }\"\n ></ng-container>\n } @else {\n @if (column.rowCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.rowCellTemplate; context: { $implicit: element, rowIndex }\"\n ></ng-container>\n } @else {\n <span\n [style.font-weight]=\"column.bold ? 'bold' : 'normal'\"\n [style.font-size]=\"column.fontSize ?? '14px'\"\n >{{ element | dataPropertyGetter: column.key }}</span\n >\n }\n }\n </div>\n }\n </td>\n </ng-container>\n }\n @if (isLast && column.isSticky && !column.allowSort) {\n <ng-container\n [matColumnDef]=\"column.uniqueId ?? column.key\"\n [stickyEnd]=\"scrollSettings.horizontalScroll ? !scrollSettings.scrollEnd : true\"\n >\n <th\n mat-header-cell\n *matHeaderCellDef\n [attr.sortable]=\"column.allowSort ?? false\"\n [ngStyle]=\"{\n width: $safeNavigationMigration(column.styles?.width),\n minWidth: $safeNavigationMigration(column.styles?.['min-width']),\n }\"\n [ngClass]=\"column.styles?.alignment ? 'th-' + $safeNavigationMigration(column.styles?.alignment) : ''\"\n [style.font-weight]=\"'bold'\"\n >\n @if (column.headerCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"\n column.headerCellTemplate;\n context: { $implicit: column.title, column, colIndex: i }\n \"\n ></ng-container>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"columnHeader\"\n [ngTemplateOutletContext]=\"{ i, column }\"\n ></ng-container>\n }\n </th>\n <td\n mat-cell\n *matCellDef=\"let element; let rowIndex = dataIndex\"\n [align]=\"$safeNavigationMigration(column.styles?.alignment)\"\n [ngClass]=\"[column.styles?.alignment ? 'td-' + $safeNavigationMigration(column.styles?.alignment) : '']\"\n (click)=\"\n onRowClick(element, rowIndex); column?.rowCellTemplateClick ? column!.rowCellTemplateClick?.() : ''\n \"\n >\n @if (loading) {\n <ui-skeleton\n class=\"table-skeleton-loader\"\n [count]=\"1\"\n [theme]=\"skeletonStyleConfig\"\n [appearance]=\"'line'\"\n ></ui-skeleton>\n } @else {\n <div class=\"row-value\">\n <ng-container\n [ngTemplateOutlet]=\"expandButton\"\n [ngTemplateOutletContext]=\"{ index: i, element }\"\n ></ng-container>\n @if (column?.type) {\n <ng-container\n *ngTemplateOutlet=\"tableDataTpl; context: { element, tableColumn: column }\"\n ></ng-container>\n } @else {\n @if (column.rowCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.rowCellTemplate; context: { $implicit: element, rowIndex }\"\n ></ng-container>\n } @else {\n <span\n [style.font-weight]=\"column.bold ? 'bold' : 'normal'\"\n [style.font-size]=\"column.fontSize ?? '14px'\"\n >{{ element | dataPropertyGetter: column.key }}</span\n >\n }\n }\n </div>\n }\n </td>\n </ng-container>\n }\n @if (!(isLast && column.isSticky) && column.allowSort) {\n <ng-container\n [matColumnDef]=\"column.uniqueId ?? column.key\"\n [sticky]=\"(isMobile$ | async) ? false : !scrollSettings.scrollStart && !!column.isSticky\"\n >\n <th\n mat-header-cell\n [start]=\"column.sortStart ?? 'asc'\"\n [mat-sort-header]=\"column.sortHeader ?? column.key\"\n [attr.sortable]=\"column.allowSort ?? false\"\n *matHeaderCellDef\n [style.font-weight]=\"'bold'\"\n [ngStyle]=\"{\n width: $safeNavigationMigration(column.styles?.width),\n minWidth: $safeNavigationMigration(column.styles?.['min-width']),\n }\"\n [ngClass]=\"column.styles?.alignment ? 'th-' + $safeNavigationMigration(column.styles?.alignment) : ''\"\n >\n @if (column.headerCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"\n column.headerCellTemplate;\n context: { $implicit: column.title, column, colIndex: i }\n \"\n ></ng-container>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"columnHeader\"\n [ngTemplateOutletContext]=\"{ i, column }\"\n ></ng-container>\n }\n </th>\n <td\n mat-cell\n *matCellDef=\"let element; let rowIndex = dataIndex\"\n [align]=\"$safeNavigationMigration(column.styles?.alignment)\"\n [ngClass]=\"[column.styles?.alignment ? 'td-' + $safeNavigationMigration(column.styles?.alignment) : '']\"\n (click)=\"\n onRowClick(element, rowIndex); column?.rowCellTemplateClick ? column!.rowCellTemplateClick?.() : ''\n \"\n >\n @if (loading) {\n <ui-skeleton\n class=\"table-skeleton-loader\"\n [count]=\"1\"\n [theme]=\"skeletonStyleConfig\"\n [appearance]=\"'line'\"\n ></ui-skeleton>\n } @else {\n <div class=\"row-value\">\n <ng-container\n [ngTemplateOutlet]=\"expandButton\"\n [ngTemplateOutletContext]=\"{ index: i, element }\"\n ></ng-container>\n @if (column?.type) {\n <ng-container\n *ngTemplateOutlet=\"tableDataTpl; context: { element, tableColumn: column }\"\n ></ng-container>\n } @else {\n @if (column.rowCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.rowCellTemplate; context: { $implicit: element, rowIndex }\"\n ></ng-container>\n } @else {\n <span\n [style.font-weight]=\"column.bold ? 'bold' : 'normal'\"\n [style.font-size]=\"column.fontSize ?? '14px'\"\n >{{ element | dataPropertyGetter: column.key }}</span\n >\n }\n }\n </div>\n }\n </td>\n </ng-container>\n }\n @if (!(isLast && column.isSticky) && !column.allowSort) {\n <ng-container\n [matColumnDef]=\"column.uniqueId ?? column.key\"\n [sticky]=\"(isMobile$ | async) ? false : !scrollSettings.scrollStart && !!column.isSticky\"\n >\n <th\n mat-header-cell\n [attr.sortable]=\"column.allowSort ?? false\"\n *matHeaderCellDef\n [style.font-weight]=\"'bold'\"\n [ngStyle]=\"{\n width: $safeNavigationMigration(column.styles?.width),\n minWidth: $safeNavigationMigration(column.styles?.['min-width']),\n }\"\n [ngClass]=\"column.styles?.alignment ? 'th-' + $safeNavigationMigration(column.styles?.alignment) : ''\"\n >\n @if (column.headerCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"\n column.headerCellTemplate;\n context: { $implicit: column.title, column, colIndex: i }\n \"\n ></ng-container>\n } @else {\n <ng-container\n [ngTemplateOutlet]=\"columnHeader\"\n [ngTemplateOutletContext]=\"{ i, column }\"\n ></ng-container>\n }\n </th>\n <td\n mat-cell\n *matCellDef=\"let element; let rowIndex = dataIndex\"\n [align]=\"$safeNavigationMigration(column.styles?.alignment)\"\n [ngClass]=\"[column.styles?.alignment ? 'td-' + $safeNavigationMigration(column.styles?.alignment) : '']\"\n (click)=\"\n onRowClick(element, rowIndex); column?.rowCellTemplateClick ? column!.rowCellTemplateClick?.() : ''\n \"\n >\n @if (loading) {\n <ui-skeleton\n class=\"table-skeleton-loader\"\n [count]=\"1\"\n [theme]=\"skeletonStyleConfig\"\n [appearance]=\"'line'\"\n ></ui-skeleton>\n } @else {\n <div class=\"row-value\">\n <ng-container\n [ngTemplateOutlet]=\"expandButton\"\n [ngTemplateOutletContext]=\"{ index: i, element }\"\n ></ng-container>\n @if (column?.type) {\n <ng-container\n *ngTemplateOutlet=\"tableDataTpl; context: { element, tableColumn: column }\"\n ></ng-container>\n } @else {\n @if (column.rowCellTemplate) {\n <ng-container\n *ngTemplateOutlet=\"column.rowCellTemplate; context: { $implicit: element, rowIndex }\"\n ></ng-container>\n } @else {\n <span\n [style.font-weight]=\"column.bold ? 'bold' : 'normal'\"\n [style.font-size]=\"column.fontSize ?? '14px'\"\n >{{ element | dataPropertyGetter: column.key }}</span\n >\n }\n }\n </div>\n }\n </td>\n </ng-container>\n }\n }\n <ng-container matColumnDef=\"expandedDetail\">\n <td mat-cell *matCellDef=\"let element\" [attr.colspan]=\"displayedColumns.length\">\n @if (dataSourceDetail.data.length) {\n <div class=\"element-detail\" [@expandDetail]=\"element === elementDetail ? 'expanded' : 'collapsed'\">\n <table\n data-testid=\"table-detail\"\n mat-table\n [dataSource]=\"dataSourceDetail\"\n [ngClass]=\"{ 'hide-borders': element === tableData[tableData.length - 1] }\"\n >\n @for (tableColumn of tableDetailColumns.columnDefs; track tableColumn) {\n <ng-container [matColumnDef]=\"tableColumn.title ?? ''\">\n <th\n mat-header-cell\n *matHeaderCellDef=\"let element\"\n arrowPosition=\"after\"\n [ngStyle]=\"{ width: $safeNavigationMigration(tableColumn.styles?.width) }\"\n [ngClass]=\"\n tableColumn.styles?.alignment\n ? 'th-' + $safeNavigationMigration(tableColumn.styles?.alignment)\n : ''\n \"\n >\n {{ tableColumn.title | uppercase }}\n </th>\n <td\n mat-cell\n *matCellDef=\"let element\"\n (click)=\"onDetailRowClick(element)\"\n [align]=\"$safeNavigationMigration(tableColumn.styles?.alignment)\"\n [ngClass]=\"\n tableColumn.styles?.alignment\n ? 'td-' + $safeNavigationMigration(tableColumn.styles?.alignment)\n : ''\n \"\n [ngStyle]=\"{ width: $safeNavigationMigration(tableColumn.styles?.width) }\"\n >\n <ng-container\n *ngTemplateOutlet=\"tableDataTpl; context: { element, tableColumn }\"\n ></ng-container>\n </td>\n </ng-container>\n }\n <tr mat-header-row *matHeaderRowDef=\"columnsDetailToDisplay\"></tr>\n <tr mat-row *matRowDef=\"let rowDetail; columns: columnsDetailToDisplay\"></tr>\n </table>\n </div>\n }\n </td>\n </ng-container>\n <ng-template #tableDataTpl let-element=\"element\" let-tableColumn=\"tableColumn\">\n <div class=\"align-wrapper\">\n @switch (tableColumn.type) {\n @case (DataType.FIELD) {\n {{ element | dataPropertyGetter: tableColumn.key }}\n }\n @case (DataType.FUNCTION) {\n {{ tableColumn.function?.(element) }}\n }\n @case (DataType.RENDERER) {\n <ng-template [dynamicComponent]=\"$any([tableColumn.renderer, element] | memoizeFunc: callRenderer)\">\n </ng-template>\n }\n @default {\n {{ element | dataPropertyGetter: tableColumn.key }}\n }\n }\n </div>\n </ng-template>\n <tr\n mat-header-row\n *matHeaderRowDef=\"displayedColumns; sticky: stickyHeader\"\n [class.is-title-present]=\"tableConfig.title\"\n ></tr>\n <tr\n mat-row\n *matRowDef=\"let row; columns: displayedColumns\"\n [ngClass]=\"{\n 'expanded-row': elementDetail === row,\n 'row-clickable': tableDetails,\n selected: $safeNavigationMigration(row?.selected),\n 'last-row': row === tableData[tableData.length - 1] && !elementDetail,\n }\"\n (click)=\"toggleRow(row)\"\n ></tr>\n @if (tableDetails && tableDetailColumns?.columnDefs?.length) {\n <tr mat-row *matRowDef=\"let row; columns: ['expandedDetail']\" class=\"detail-row\"></tr>\n }\n @if (tableConfig.noDataRowTpl) {\n <tr *matNoDataRow>\n <ng-container *ngTemplateOutlet=\"tableConfig.noDataRowTpl\"></ng-container>\n </tr>\n }\n </table>\n </div>\n }\n\n @if (!tableConfig?.hidePagination && tableConfig?.pagination) {\n <ui-paginator\n [disabled]=\"loading\"\n [applicationTheme]=\"applicationTheme !== 'classic' ? 'light' : 'classic'\"\n [pageSize]=\"tableConfig.pagination?.itemsPerPage ?? 25\"\n [length]=\"tableConfig.pagination?.totalItems ?? 0\"\n [currentPage]=\"tableConfig.pagination?.currentPage ?? 0\"\n [pageSizeOptions]=\"tableConfig.pagination?.itemsPerPageOptions ?? [10, 25, 50]\"\n (paginatorChange)=\"onPaginatorChange($event)\"\n ></ui-paginator>\n }\n</div>\n\n<ng-template #expandButton let-i=\"index\" let-element=\"element\">\n @if (!i && tableDetails) {\n <ui-button\n [applicationTheme]=\"applicationTheme\"\n variant=\"icon-button\"\n [ngClass]=\"{ opened: elementDetail && element === elementDetail }\"\n [iconName]=\"\n elementDetail && element === elementDetail ? 'Arrow-chevron-up-in-line' : 'Arrow-chevron-down-in-line'\n \"\n ></ui-button>\n }\n</ng-template>\n\n<ng-template #columnHeader let-column=\"column\" let-i=\"i\">\n <div class=\"header-section\">\n <span uiEllipseText (onChangeTextState)=\"onChangeColumnSize(i, $event)\" class=\"column-title\"\n >{{ column.title | sentencecase }}\n </span>\n @if (column?.showTooltip) {\n <ui-icon\n [name]=\"'Help-in-line'\"\n [matTooltipClass]=\"applicationTheme\"\n [matTooltip]=\"(column?.showTooltip ? (column?.tooltip ? column.tooltip : column.title) : '') || ''\"\n ></ui-icon>\n }\n </div>\n</ng-template>\n","import { CommonModule } from '@angular/common';\nimport { NgModule } from '@angular/core';\nimport { MatSortModule } from '@angular/material/sort';\nimport { MatTableModule } from '@angular/material/table';\nimport { MatTooltipModule } from '@angular/material/tooltip';\n\nimport { ButtonComponentModule } from '@testgorilla/tgo-ui/components/button';\nimport {\n EllipseTextDirective,\n MemoizeFuncPipe,\n DataPropertyGetterPipe,\n DynamicComponentDirective,\n} from '@testgorilla/tgo-ui/components/core';\nimport { IconComponentModule } from '@testgorilla/tgo-ui/components/icon';\nimport { PaginatorComponentModule } from '@testgorilla/tgo-ui/components/paginator';\nimport { SkeletonComponent } from '@testgorilla/tgo-ui/components/skeleton';\n\nimport { SentenceCasePipe } from './sentence-case.pipe';\nimport { TableComponent } from './table.component';\n\n@NgModule({\n imports: [\n CommonModule,\n MatTableModule,\n MatTooltipModule,\n SkeletonComponent,\n PaginatorComponentModule,\n ButtonComponentModule,\n MatSortModule,\n IconComponentModule,\n EllipseTextDirective,\n DynamicComponentDirective,\n DataPropertyGetterPipe,\n MemoizeFuncPipe,\n TableComponent,\n SentenceCasePipe,\n ],\n exports: [TableComponent],\n})\nexport class TableComponentModule {}\n"],"mappings":"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"}
|
|
@@ -627,12 +627,15 @@ var WriteWithAiComponent = class WriteWithAiComponent {
|
|
|
627
627
|
"ariaExpanded",
|
|
628
628
|
"ariaControls",
|
|
629
629
|
"ariaPressed",
|
|
630
|
+
"ariaHasPopup",
|
|
630
631
|
"ariaRequired",
|
|
631
632
|
"ariaLabelledby",
|
|
632
633
|
"ariaDescribedby",
|
|
633
634
|
"preventDefault",
|
|
634
635
|
"hasBackground",
|
|
635
636
|
"circular",
|
|
637
|
+
"isSingleLineLabel",
|
|
638
|
+
"iconButtonShape",
|
|
636
639
|
"tooltipPosition",
|
|
637
640
|
"role",
|
|
638
641
|
"iconFilled",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testgorilla-tgo-ui-components-write-with-ai.mjs","names":["i1"],"sources":["../../../components/write-with-ai/llm.service.ts","../../../components/write-with-ai/write-with-ai.component.ts","../../../components/write-with-ai/write-with-ai.component.html","../../../components/write-with-ai/write-with-ai.module.ts"],"sourcesContent":["import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';\nimport { Injectable } from '@angular/core';\nimport { Observable, of, delay, map } from 'rxjs';\n\nimport { WriteWithAiLlmConfig } from './write-with-ai.model';\n\nexport interface LlmRequest {\n sourceText: string;\n prompt: string;\n context?: string;\n}\n\ninterface OpenAiChatResponse {\n choices: { message: { content: string } }[];\n}\n\ninterface GeminiResponse {\n candidates: { content: { parts: { text: string }[] } }[];\n}\n\nconst OPENAI_DEFAULT_ENDPOINT = 'https://api.openai.com/v1/chat/completions';\nconst OPENAI_DEFAULT_MODEL = 'gpt-5-mini';\nconst GEMINI_DEFAULT_MODEL = 'gemini-3.0-flash';\n\n@Injectable({ providedIn: 'root' })\nexport class WriteWithAiLlmService {\n constructor(private readonly http: HttpClient) {}\n\n generate(request: LlmRequest, config: WriteWithAiLlmConfig): Observable<string> {\n if (!config.apiKey) {\n return this.simulateResponse(request, config);\n }\n\n if (config.provider === 'gemini') {\n return this.callGemini(request, config);\n }\n\n return this.callOpenAi(request, config);\n }\n\n private resolveEndpoint(config: WriteWithAiLlmConfig): string {\n return config.endpoint ?? config.baseUrl ?? OPENAI_DEFAULT_ENDPOINT;\n }\n\n private callOpenAi(request: LlmRequest, config: WriteWithAiLlmConfig): Observable<string> {\n const endpoint = this.resolveEndpoint(config);\n const model = config.model ?? OPENAI_DEFAULT_MODEL;\n const systemMessage = this.buildSystemMessage(request.sourceText, request.context ?? config.context);\n\n const body = {\n model,\n messages: [\n { role: 'system', content: systemMessage },\n { role: 'user', content: request.prompt },\n ],\n };\n\n const headers = new HttpHeaders({\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`,\n });\n\n return this.http\n .post<OpenAiChatResponse>(endpoint, body, { headers })\n .pipe(map(res => res.choices[0]?.message?.content ?? ''));\n }\n\n private callGemini(request: LlmRequest, config: WriteWithAiLlmConfig): Observable<string> {\n const model = config.model ?? GEMINI_DEFAULT_MODEL;\n const baseUrl =\n config.endpoint ??\n config.baseUrl ??\n `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent`;\n const systemMessage = this.buildSystemMessage(request.sourceText, request.context ?? config.context);\n\n const body = {\n system_instruction: { parts: [{ text: systemMessage }] },\n contents: [{ role: 'user', parts: [{ text: request.prompt }] }],\n };\n\n const apiKey = config.apiKey;\n if (!apiKey) {\n return this.simulateResponse(request, config);\n }\n\n const headers = new HttpHeaders({ 'Content-Type': 'application/json' });\n const params = new HttpParams().set('key', apiKey);\n\n return this.http\n .post<GeminiResponse>(baseUrl, body, { headers, params })\n .pipe(map(res => res.candidates?.[0]?.content?.parts?.[0]?.text ?? ''));\n }\n\n private simulateResponse(request: LlmRequest, _config: WriteWithAiLlmConfig): Observable<string> {\n const source = request.sourceText?.trim();\n const prompt = request.prompt?.trim();\n\n let response: string;\n\n if (source && prompt) {\n const truncated = source.length > 200 ? `${source.substring(0, 200)}…` : source;\n response =\n `Based on the following text:\\n\\n\"${truncated}\"\\n\\n` +\n `Here is the result for \"${prompt}\":\\n\\n${this.generatePlaceholderContent(prompt, source)}`;\n } else if (prompt) {\n response = this.generatePlaceholderContent(prompt, '');\n } else {\n response = 'Please provide a prompt describing what you would like me to write.';\n }\n\n return of(response).pipe(delay(1200));\n }\n\n private generatePlaceholderContent(prompt: string, source: string): string {\n const lower = prompt.toLowerCase();\n\n if (lower.includes('shorter') || lower.includes('concise') || lower.includes('summarize')) {\n const sentences = source.split(/[.!?]+/).filter(s => s.trim());\n if (sentences.length > 1) {\n return `${sentences\n .slice(0, Math.ceil(sentences.length / 2))\n .join('. ')\n .trim()}.`;\n }\n return `${source.substring(0, Math.ceil(source.length * 0.6)).trim()}…`;\n }\n\n if (lower.includes('formal') || lower.includes('professional') || lower.includes('tone')) {\n return `Dear Recipient,\\n\\nI hope this message finds you well. ${source || 'I am writing to follow up on our recent discussion.'}\\n\\nPlease do not hesitate to reach out should you require further information.\\n\\nBest regards`;\n }\n\n if (lower.includes('email') || lower.includes('draft') || lower.includes('write')) {\n return `Subject: Follow-up\\n\\nHi there,\\n\\n${source || 'Thank you for your time. I wanted to reach out regarding the next steps.'}\\n\\nLooking forward to hearing from you.\\n\\nBest regards`;\n }\n\n return `[Simulated LLM response]\\n\\nPrompt: ${prompt}\\n\\nThis is a simulated response. To enable real LLM calls, provide an apiKey in the llmConfig input. The service supports OpenAI-compatible and Gemini endpoints.`;\n }\n\n private buildSystemMessage(sourceText: string, context?: string): string {\n const parts: string[] = [];\n\n if (context) {\n parts.push(context);\n }\n\n if (sourceText) {\n parts.push(`The user is working with the following source text:\\n\\n\"\"\"${sourceText}\"\"\"`);\n }\n\n parts.push('Respond with only the requested content. Do not include explanations or preamble.');\n\n return parts.join('\\n\\n');\n }\n}\n","import { AsyncPipe } from '@angular/common';\nimport {\n afterRenderEffect,\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n effect,\n ElementRef,\n forwardRef,\n inject,\n input,\n output,\n signal,\n viewChild,\n OnInit,\n untracked,\n} from '@angular/core';\nimport { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';\nimport { FormsModule, NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';\nimport { combineLatest, map, Subject, takeUntil } from 'rxjs';\n\nimport { AiCaveatComponentModule } from '@testgorilla/tgo-ui/components/ai-caveat';\nimport { AlertBannerComponentModule, AlertBannerAction } from '@testgorilla/tgo-ui/components/alert-banner';\nimport { ButtonComponentModule } from '@testgorilla/tgo-ui/components/button';\nimport { AlertBarType, UiTranslatePipe } from '@testgorilla/tgo-ui/components/core';\nimport { FieldComponentModule } from '@testgorilla/tgo-ui/components/field';\nimport { IconComponentModule } from '@testgorilla/tgo-ui/components/icon';\nimport { PromptData, PromptTag, PromptModule } from '@testgorilla/tgo-ui/components/prompt';\nimport { TagComponentModule } from '@testgorilla/tgo-ui/components/tag';\n\nimport { WriteWithAiLlmService } from './llm.service';\nimport {\n WriteWithAiStatus,\n WriteWithAiTagOption,\n WriteWithAiLlmConfig,\n WriteWithAiSubmitEvent,\n} from './write-with-ai.model';\n\ninterface StatusConfig {\n variant: 'loading' | 'success' | 'error';\n alertType: AlertBarType;\n messageKey: string;\n actions: AlertBannerAction[];\n}\n\n@Component({\n selector: 'ui-write-with-ai',\n templateUrl: './write-with-ai.component.html',\n styleUrl: './write-with-ai.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { style: 'display: block' },\n providers: [\n UiTranslatePipe,\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => WriteWithAiComponent),\n multi: true,\n },\n ],\n imports: [\n AsyncPipe,\n FormsModule,\n FieldComponentModule,\n ButtonComponentModule,\n IconComponentModule,\n PromptModule,\n AiCaveatComponentModule,\n AlertBannerComponentModule,\n TagComponentModule,\n UiTranslatePipe,\n ],\n})\nexport class WriteWithAiComponent implements OnInit, ControlValueAccessor {\n readonly value = input('');\n readonly standalone = input(false);\n readonly defaultOpen = input(false);\n readonly fieldLabel = input('');\n readonly header = input('');\n readonly placeholder = input('');\n readonly promptValue = input('');\n readonly tags = input<WriteWithAiTagOption[]>([]);\n readonly status = input<WriteWithAiStatus>('idle');\n readonly subheader = input<string | undefined>(undefined);\n readonly llmConfig = input<WriteWithAiLlmConfig | undefined>(undefined);\n\n /** Layout: make the inner field stretch to fill its container height. */\n readonly fullHeight = input(false);\n\n /** Layout: render the inner field without a visible border. */\n readonly borderless = input(false);\n\n /**\n * When true, hides the free-text `ui-prompt` and renders the `tags` chips on their own.\n * Clicking a chip submits its label as the prompt via `promptSubmit`.\n * Use this when the host backend only accepts a constrained set of prompts (e.g. an enum).\n */\n readonly tagsOnly = input(false, { transform: booleanAttribute });\n\n /** Opaque host metadata emitted with promptSubmit for backend integrations. */\n readonly metadata = input<Record<string, unknown>>({});\n\n readonly valueChange = output<string>();\n readonly promptChange = output<string>();\n readonly promptSubmit = output<WriteWithAiSubmitEvent>();\n readonly cancelPending = output<void>();\n readonly acceptResult = output<void>();\n readonly requestRefine = output<void>();\n\n private readonly destroyRef = inject(DestroyRef);\n private readonly llmService = inject(WriteWithAiLlmService);\n private readonly uiTranslate = inject(UiTranslatePipe);\n private readonly promptModel = signal('');\n private readonly isPanelManuallyOpen = signal(false);\n private readonly internalStatus = signal<WriteWithAiStatus>('idle');\n private readonly internalValue = signal('');\n private readonly cancelRequest$ = new Subject<void>();\n\n /** ControlValueAccessor: whether the form control is disabled. */\n readonly cvaDisabled = signal(false);\n\n /** Tag carousel (tagsOnly mode): scroll container + arrow-enabled state. */\n private readonly tagsScrollRef = viewChild<ElementRef<HTMLDivElement>>('tagsScrollContainer');\n readonly canScrollTagsLeft = signal(false);\n readonly canScrollTagsRight = signal(false);\n\n /** ControlValueAccessor callbacks. */\n private onChange: (value: string) => void = () => {};\n private onTouched: () => void = () => {};\n\n readonly translationContext = 'WRITE_WITH_AI.';\n\n private readonly labels = toSignal(\n combineLatest([\n this.uiTranslate.transform(`${this.translationContext}CANCEL`),\n this.uiTranslate.transform(`${this.translationContext}ACCEPT`),\n this.uiTranslate.transform(`${this.translationContext}MAKE_CHANGES`),\n this.uiTranslate.transform(`${this.translationContext}TRY_AGAIN`),\n ]).pipe(map(([cancel, accept, makeChanges, tryAgain]) => ({ cancel, accept, makeChanges, tryAgain }))),\n { initialValue: { cancel: '', accept: '', makeChanges: '', tryAgain: '' } }\n );\n\n readonly isDefaultMode = computed(() => this.llmConfig()?.default === true);\n\n readonly effectiveStatus = computed(() => (this.isDefaultMode() ? this.internalStatus() : this.status()));\n\n readonly effectiveValue = computed(() => (this.isDefaultMode() ? this.internalValue() : this.value()));\n\n readonly isPanelVisible = computed(() => this.standalone() || this.isPanelManuallyOpen());\n\n readonly promptTags = computed<PromptTag[]>(() =>\n this.tags().map(tag => ({ id: tag.id, label: tag.label, autocomplete: tag.description ?? '' }))\n );\n\n readonly statusConfig = computed<StatusConfig | null>(() => {\n const l = this.labels();\n switch (this.effectiveStatus()) {\n case 'loading':\n return {\n variant: 'loading',\n alertType: 'info',\n messageKey: `${this.translationContext}WRITING`,\n actions: [{ label: l.cancel, onClick: () => this.handleCancel() }],\n };\n case 'success':\n return {\n variant: 'success',\n alertType: 'success',\n messageKey: `${this.translationContext}CONTENT_GENERATED`,\n actions: [\n { label: l.makeChanges, onClick: () => this.handleRefine() },\n { label: l.accept, onClick: () => this.handleAccept() },\n ],\n };\n case 'error':\n return {\n variant: 'error',\n alertType: 'error',\n messageKey: `${this.translationContext}ERROR_MESSAGE`,\n actions: [{ label: l.tryAgain, onClick: () => this.handleRefine() }],\n };\n case 'idle':\n return null;\n default:\n return null;\n }\n });\n\n constructor() {\n effect(() => {\n const promptValue = this.promptValue();\n const isDefault = this.isDefaultMode();\n if (!isDefault) {\n untracked(() => this.promptModel.set(promptValue));\n }\n });\n\n effect(() => {\n const value = this.value();\n const isDefault = this.isDefaultMode();\n if (isDefault) {\n untracked(() => this.internalValue.set(value));\n }\n });\n\n // Scroll events don't trigger change detection, so the arrow disabled-state\n // is kept in signals. This re-measures whenever the carousel (re)mounts or\n // the tag set changes; runtime scrolling is handled by the (scroll) listener.\n // It only reads layout, so it runs in the dedicated `read` phase.\n afterRenderEffect({\n read: () => {\n this.tags();\n const el = this.tagsScrollRef()?.nativeElement;\n if (el) {\n this.measureTagScroll(el);\n }\n },\n });\n\n // Resizing the host can change overflow without a scroll or tag-set change,\n // so observe the carousel and re-measure when its box changes.\n effect(onCleanup => {\n const el = this.tagsScrollRef()?.nativeElement;\n if (!el || typeof ResizeObserver === 'undefined') {\n return;\n }\n const observer = new ResizeObserver(() => this.measureTagScroll(el));\n observer.observe(el);\n onCleanup(() => observer.disconnect());\n });\n }\n\n readonly promptModelData = computed<PromptData>(() => ({ text: this.promptModel(), files: [] }));\n\n handlePromptModelChange(value: PromptData | string): void {\n const text = typeof value === 'string' ? value : (value?.text ?? '');\n this.promptModel.set(text);\n this.promptChange.emit(text);\n }\n\n ngOnInit() {\n if (this.defaultOpen()) {\n this.isPanelManuallyOpen.set(true);\n }\n }\n\n togglePanel(): void {\n if (this.standalone()) {\n return;\n }\n this.isPanelManuallyOpen.update(current => !current);\n }\n\n handleValueInput(value: string): void {\n if (this.isDefaultMode()) {\n this.internalValue.set(value);\n }\n this.valueChange.emit(value);\n this.onChange(value);\n this.onTouched();\n }\n\n handlePromptSubmit(promptData?: PromptData | string): void {\n const prompt = typeof promptData === 'string' ? promptData : (promptData?.text ?? this.promptModel());\n this.promptModel.set(prompt);\n this.promptChange.emit(prompt);\n\n const submitEvent: WriteWithAiSubmitEvent = {\n prompt,\n content: this.effectiveValue(),\n metadata: this.metadata(),\n };\n\n if (this.isDefaultMode()) {\n this.executeDefaultFlow(prompt);\n }\n\n this.promptSubmit.emit(submitEvent);\n }\n\n handleTagClick(tag: WriteWithAiTagOption): void {\n // ui-tag's press fires even when isDisabled, so guard here.\n if (this.cvaDisabled()) {\n return;\n }\n this.handlePromptSubmit(tag.label);\n }\n\n measureTagScroll(el: HTMLElement): void {\n this.canScrollTagsLeft.set(el.scrollLeft > 0);\n this.canScrollTagsRight.set(Math.ceil(el.scrollLeft + el.clientWidth) < el.scrollWidth);\n }\n\n scrollTags(el: HTMLElement, direction: -1 | 1): void {\n el.scrollBy({ left: direction * el.clientWidth * 0.8, behavior: 'smooth' });\n }\n\n handlePrimaryAction(): void {\n const status = this.effectiveStatus();\n if (status === 'loading') {\n this.handleCancel();\n } else if (status === 'success') {\n this.handleAccept();\n } else if (status === 'error') {\n this.handleRefine();\n }\n }\n\n handleSecondaryAction(): void {\n if (this.effectiveStatus() === 'success') {\n this.handleRefine();\n }\n }\n\n // --- ControlValueAccessor ---\n\n writeValue(value: string): void {\n const v = value ?? '';\n if (this.isDefaultMode()) {\n this.internalValue.set(v);\n }\n // For integration mode the host uses the [value] input directly,\n // but we still keep internal state in sync for CVA consumers.\n this.internalValue.set(v);\n }\n\n registerOnChange(fn: (value: string) => void): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.cvaDisabled.set(isDisabled);\n }\n\n // --- Private helpers ---\n\n private executeDefaultFlow(prompt: string): void {\n const config = this.llmConfig();\n if (!config) {\n return;\n }\n\n this.cancelRequest$.next();\n this.internalStatus.set('loading');\n\n this.llmService\n .generate({ sourceText: this.effectiveValue(), prompt, context: config.context }, config)\n .pipe(takeUntilDestroyed(this.destroyRef), takeUntil(this.cancelRequest$))\n .subscribe({\n next: result => {\n this.internalValue.set(result);\n this.valueChange.emit(result);\n this.onChange(result);\n this.internalStatus.set('success');\n },\n error: () => {\n this.internalStatus.set('error');\n },\n });\n }\n\n private handleCancel(): void {\n if (this.isDefaultMode()) {\n this.cancelRequest$.next();\n this.internalStatus.set('idle');\n }\n this.cancelPending.emit();\n }\n\n private handleAccept(): void {\n if (this.isDefaultMode()) {\n this.internalStatus.set('idle');\n this.promptModel.set('');\n }\n if (!this.standalone()) {\n this.isPanelManuallyOpen.set(false);\n }\n this.acceptResult.emit();\n }\n\n private handleRefine(): void {\n if (this.isDefaultMode()) {\n this.internalStatus.set('idle');\n }\n this.requestRefine.emit();\n }\n}\n","<div\n class=\"write-with-ai\"\n [class.write-with-ai--standalone]=\"standalone()\"\n [class.write-with-ai--full-height]=\"fullHeight()\"\n>\n @if (!standalone()) {\n <div class=\"write-with-ai__host\">\n <ui-field\n [label]=\"fieldLabel() || (translationContext + 'FIELD_LABEL' | uiTranslate | async)!\"\n type=\"textarea\"\n [showBottomContent]=\"false\"\n [fullHeight]=\"fullHeight()\"\n [borderless]=\"borderless()\"\n [disabled]=\"cvaDisabled()\"\n [ngModel]=\"effectiveValue()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"handleValueInput($event)\"\n ></ui-field>\n <ui-button\n class=\"write-with-ai__cta\"\n variant=\"ghost-ai\"\n size=\"small\"\n [label]=\"(translationContext + 'AI_ASSIST' | uiTranslate | async)!\"\n iconName=\"Sparkle-in-line\"\n iconPosition=\"left\"\n [disabled]=\"isPanelVisible() || cvaDisabled()\"\n (buttonClickEvent)=\"togglePanel()\"\n ></ui-button>\n </div>\n }\n\n @if (isPanelVisible()) {\n <section\n class=\"write-with-ai__panel\"\n [class.write-with-ai__panel--loading]=\"effectiveStatus() === 'loading'\"\n role=\"region\"\n [attr.aria-label]=\"(translationContext + 'AI_WRITING_ASSISTANT' | uiTranslate | async)!\"\n >\n <header class=\"write-with-ai__panel-header\">\n <div class=\"write-with-ai__panel-heading\">\n <div class=\"write-with-ai__title-row\">\n @if (effectiveStatus() !== 'loading') {\n <ui-icon class=\"write-with-ai__title-icon\" name=\"Sparkle-in-line\" color=\"ai\"></ui-icon>\n }\n <h4 class=\"write-with-ai__title\">\n {{ header() || (translationContext + 'HEADER' | uiTranslate | async) }}\n </h4>\n </div>\n @if (subheader()) {\n <p class=\"write-with-ai__subheader\">{{ subheader() }}</p>\n }\n </div>\n @if (!standalone()) {\n <ui-button\n variant=\"icon-button\"\n iconName=\"Close\"\n size=\"small\"\n [tooltip]=\"(translationContext + 'CLOSE' | uiTranslate | async)!\"\n [ariaLabel]=\"(translationContext + 'CLOSE_AI_ASSISTANT' | uiTranslate | async)!\"\n (buttonClickEvent)=\"togglePanel()\"\n ></ui-button>\n }\n </header>\n\n @if (effectiveStatus() === 'idle') {\n @if (tagsOnly()) {\n @if (tags().length) {\n <div class=\"write-with-ai__tags-prompt\">\n <div\n class=\"write-with-ai__tags-container\"\n role=\"group\"\n [attr.aria-label]=\"header() || (translationContext + 'HEADER' | uiTranslate | async)\"\n #tagsScrollContainer\n (scroll)=\"measureTagScroll(tagsScrollContainer)\"\n >\n @for (tag of tags(); track tag.id) {\n <ui-tag\n [label]=\"tag.label\"\n [ariaLabel]=\"tag.label\"\n [isDisabled]=\"cvaDisabled()\"\n (press)=\"handleTagClick(tag)\"\n ></ui-tag>\n }\n </div>\n <div class=\"write-with-ai__tags-arrows\">\n <ui-button\n variant=\"icon-button\"\n size=\"small\"\n iconName=\"Arrow-chevron-left-in-line\"\n [tooltip]=\"(translationContext + 'SCROLL_TAGS_LEFT' | uiTranslate | async)!\"\n [ariaLabel]=\"(translationContext + 'SCROLL_TAGS_LEFT' | uiTranslate | async)!\"\n [disabled]=\"cvaDisabled() || !canScrollTagsLeft()\"\n (buttonClickEvent)=\"scrollTags(tagsScrollContainer, -1)\"\n ></ui-button>\n <ui-button\n variant=\"icon-button\"\n size=\"small\"\n iconName=\"Arrow-chevron-right-in-line\"\n [tooltip]=\"(translationContext + 'SCROLL_TAGS_RIGHT' | uiTranslate | async)!\"\n [ariaLabel]=\"(translationContext + 'SCROLL_TAGS_RIGHT' | uiTranslate | async)!\"\n [disabled]=\"cvaDisabled() || !canScrollTagsRight()\"\n (buttonClickEvent)=\"scrollTags(tagsScrollContainer, 1)\"\n ></ui-button>\n </div>\n </div>\n }\n } @else {\n <div class=\"write-with-ai__prompt\">\n <ui-prompt\n [ngModel]=\"promptModelData()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"handlePromptModelChange($event)\"\n [tags]=\"promptTags()\"\n [placeholder]=\"placeholder() || (translationContext + 'PLACEHOLDER' | uiTranslate | async)!\"\n [showSendButton]=\"true\"\n (promptData)=\"handlePromptSubmit($event)\"\n ></ui-prompt>\n </div>\n }\n }\n\n @if (statusConfig(); as cfg) {\n <ui-alert-banner\n [alertType]=\"cfg.alertType\"\n alertVariant=\"callout\"\n [message]=\"(cfg.messageKey | uiTranslate | async)!\"\n [includeDismissButton]=\"false\"\n [isLoading]=\"cfg.variant === 'loading'\"\n [hasIcon]=\"cfg.variant !== 'loading'\"\n [actions]=\"cfg.actions\"\n [isFullWidth]=\"true\"\n ></ui-alert-banner>\n }\n\n <div class=\"write-with-ai__caveat\">\n <ui-ai-caveat></ui-ai-caveat>\n </div>\n </section>\n }\n</div>\n","import { NgModule } from '@angular/core';\n\nimport { WriteWithAiComponent } from './write-with-ai.component';\n\n@NgModule({\n imports: [WriteWithAiComponent],\n exports: [WriteWithAiComponent],\n})\nexport class WriteWithAiComponentModule {}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"testgorilla-tgo-ui-components-write-with-ai.mjs","names":["i1"],"sources":["../../../components/write-with-ai/llm.service.ts","../../../components/write-with-ai/write-with-ai.component.ts","../../../components/write-with-ai/write-with-ai.component.html","../../../components/write-with-ai/write-with-ai.module.ts"],"sourcesContent":["import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';\nimport { Injectable } from '@angular/core';\nimport { Observable, of, delay, map } from 'rxjs';\n\nimport { WriteWithAiLlmConfig } from './write-with-ai.model';\n\nexport interface LlmRequest {\n sourceText: string;\n prompt: string;\n context?: string;\n}\n\ninterface OpenAiChatResponse {\n choices: { message: { content: string } }[];\n}\n\ninterface GeminiResponse {\n candidates: { content: { parts: { text: string }[] } }[];\n}\n\nconst OPENAI_DEFAULT_ENDPOINT = 'https://api.openai.com/v1/chat/completions';\nconst OPENAI_DEFAULT_MODEL = 'gpt-5-mini';\nconst GEMINI_DEFAULT_MODEL = 'gemini-3.0-flash';\n\n@Injectable({ providedIn: 'root' })\nexport class WriteWithAiLlmService {\n constructor(private readonly http: HttpClient) {}\n\n generate(request: LlmRequest, config: WriteWithAiLlmConfig): Observable<string> {\n if (!config.apiKey) {\n return this.simulateResponse(request, config);\n }\n\n if (config.provider === 'gemini') {\n return this.callGemini(request, config);\n }\n\n return this.callOpenAi(request, config);\n }\n\n private resolveEndpoint(config: WriteWithAiLlmConfig): string {\n return config.endpoint ?? config.baseUrl ?? OPENAI_DEFAULT_ENDPOINT;\n }\n\n private callOpenAi(request: LlmRequest, config: WriteWithAiLlmConfig): Observable<string> {\n const endpoint = this.resolveEndpoint(config);\n const model = config.model ?? OPENAI_DEFAULT_MODEL;\n const systemMessage = this.buildSystemMessage(request.sourceText, request.context ?? config.context);\n\n const body = {\n model,\n messages: [\n { role: 'system', content: systemMessage },\n { role: 'user', content: request.prompt },\n ],\n };\n\n const headers = new HttpHeaders({\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${config.apiKey}`,\n });\n\n return this.http\n .post<OpenAiChatResponse>(endpoint, body, { headers })\n .pipe(map(res => res.choices[0]?.message?.content ?? ''));\n }\n\n private callGemini(request: LlmRequest, config: WriteWithAiLlmConfig): Observable<string> {\n const model = config.model ?? GEMINI_DEFAULT_MODEL;\n const baseUrl =\n config.endpoint ??\n config.baseUrl ??\n `https://generativelanguage.googleapis.com/v1beta/models/${model}:generateContent`;\n const systemMessage = this.buildSystemMessage(request.sourceText, request.context ?? config.context);\n\n const body = {\n system_instruction: { parts: [{ text: systemMessage }] },\n contents: [{ role: 'user', parts: [{ text: request.prompt }] }],\n };\n\n const apiKey = config.apiKey;\n if (!apiKey) {\n return this.simulateResponse(request, config);\n }\n\n const headers = new HttpHeaders({ 'Content-Type': 'application/json' });\n const params = new HttpParams().set('key', apiKey);\n\n return this.http\n .post<GeminiResponse>(baseUrl, body, { headers, params })\n .pipe(map(res => res.candidates?.[0]?.content?.parts?.[0]?.text ?? ''));\n }\n\n private simulateResponse(request: LlmRequest, _config: WriteWithAiLlmConfig): Observable<string> {\n const source = request.sourceText?.trim();\n const prompt = request.prompt?.trim();\n\n let response: string;\n\n if (source && prompt) {\n const truncated = source.length > 200 ? `${source.substring(0, 200)}…` : source;\n response =\n `Based on the following text:\\n\\n\"${truncated}\"\\n\\n` +\n `Here is the result for \"${prompt}\":\\n\\n${this.generatePlaceholderContent(prompt, source)}`;\n } else if (prompt) {\n response = this.generatePlaceholderContent(prompt, '');\n } else {\n response = 'Please provide a prompt describing what you would like me to write.';\n }\n\n return of(response).pipe(delay(1200));\n }\n\n private generatePlaceholderContent(prompt: string, source: string): string {\n const lower = prompt.toLowerCase();\n\n if (lower.includes('shorter') || lower.includes('concise') || lower.includes('summarize')) {\n const sentences = source.split(/[.!?]+/).filter(s => s.trim());\n if (sentences.length > 1) {\n return `${sentences\n .slice(0, Math.ceil(sentences.length / 2))\n .join('. ')\n .trim()}.`;\n }\n return `${source.substring(0, Math.ceil(source.length * 0.6)).trim()}…`;\n }\n\n if (lower.includes('formal') || lower.includes('professional') || lower.includes('tone')) {\n return `Dear Recipient,\\n\\nI hope this message finds you well. ${source || 'I am writing to follow up on our recent discussion.'}\\n\\nPlease do not hesitate to reach out should you require further information.\\n\\nBest regards`;\n }\n\n if (lower.includes('email') || lower.includes('draft') || lower.includes('write')) {\n return `Subject: Follow-up\\n\\nHi there,\\n\\n${source || 'Thank you for your time. I wanted to reach out regarding the next steps.'}\\n\\nLooking forward to hearing from you.\\n\\nBest regards`;\n }\n\n return `[Simulated LLM response]\\n\\nPrompt: ${prompt}\\n\\nThis is a simulated response. To enable real LLM calls, provide an apiKey in the llmConfig input. The service supports OpenAI-compatible and Gemini endpoints.`;\n }\n\n private buildSystemMessage(sourceText: string, context?: string): string {\n const parts: string[] = [];\n\n if (context) {\n parts.push(context);\n }\n\n if (sourceText) {\n parts.push(`The user is working with the following source text:\\n\\n\"\"\"${sourceText}\"\"\"`);\n }\n\n parts.push('Respond with only the requested content. Do not include explanations or preamble.');\n\n return parts.join('\\n\\n');\n }\n}\n","import { AsyncPipe } from '@angular/common';\nimport {\n afterRenderEffect,\n booleanAttribute,\n ChangeDetectionStrategy,\n Component,\n computed,\n DestroyRef,\n effect,\n ElementRef,\n forwardRef,\n inject,\n input,\n output,\n signal,\n viewChild,\n OnInit,\n untracked,\n} from '@angular/core';\nimport { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';\nimport { FormsModule, NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';\nimport { combineLatest, map, Subject, takeUntil } from 'rxjs';\n\nimport { AiCaveatComponentModule } from '@testgorilla/tgo-ui/components/ai-caveat';\nimport { AlertBannerComponentModule, AlertBannerAction } from '@testgorilla/tgo-ui/components/alert-banner';\nimport { ButtonComponentModule } from '@testgorilla/tgo-ui/components/button';\nimport { AlertBarType, UiTranslatePipe } from '@testgorilla/tgo-ui/components/core';\nimport { FieldComponentModule } from '@testgorilla/tgo-ui/components/field';\nimport { IconComponentModule } from '@testgorilla/tgo-ui/components/icon';\nimport { PromptData, PromptTag, PromptModule } from '@testgorilla/tgo-ui/components/prompt';\nimport { TagComponentModule } from '@testgorilla/tgo-ui/components/tag';\n\nimport { WriteWithAiLlmService } from './llm.service';\nimport {\n WriteWithAiStatus,\n WriteWithAiTagOption,\n WriteWithAiLlmConfig,\n WriteWithAiSubmitEvent,\n} from './write-with-ai.model';\n\ninterface StatusConfig {\n variant: 'loading' | 'success' | 'error';\n alertType: AlertBarType;\n messageKey: string;\n actions: AlertBannerAction[];\n}\n\n@Component({\n selector: 'ui-write-with-ai',\n templateUrl: './write-with-ai.component.html',\n styleUrl: './write-with-ai.component.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n host: { style: 'display: block' },\n providers: [\n UiTranslatePipe,\n {\n provide: NG_VALUE_ACCESSOR,\n useExisting: forwardRef(() => WriteWithAiComponent),\n multi: true,\n },\n ],\n imports: [\n AsyncPipe,\n FormsModule,\n FieldComponentModule,\n ButtonComponentModule,\n IconComponentModule,\n PromptModule,\n AiCaveatComponentModule,\n AlertBannerComponentModule,\n TagComponentModule,\n UiTranslatePipe,\n ],\n})\nexport class WriteWithAiComponent implements OnInit, ControlValueAccessor {\n readonly value = input('');\n readonly standalone = input(false);\n readonly defaultOpen = input(false);\n readonly fieldLabel = input('');\n readonly header = input('');\n readonly placeholder = input('');\n readonly promptValue = input('');\n readonly tags = input<WriteWithAiTagOption[]>([]);\n readonly status = input<WriteWithAiStatus>('idle');\n readonly subheader = input<string | undefined>(undefined);\n readonly llmConfig = input<WriteWithAiLlmConfig | undefined>(undefined);\n\n /** Layout: make the inner field stretch to fill its container height. */\n readonly fullHeight = input(false);\n\n /** Layout: render the inner field without a visible border. */\n readonly borderless = input(false);\n\n /**\n * When true, hides the free-text `ui-prompt` and renders the `tags` chips on their own.\n * Clicking a chip submits its label as the prompt via `promptSubmit`.\n * Use this when the host backend only accepts a constrained set of prompts (e.g. an enum).\n */\n readonly tagsOnly = input(false, { transform: booleanAttribute });\n\n /** Opaque host metadata emitted with promptSubmit for backend integrations. */\n readonly metadata = input<Record<string, unknown>>({});\n\n readonly valueChange = output<string>();\n readonly promptChange = output<string>();\n readonly promptSubmit = output<WriteWithAiSubmitEvent>();\n readonly cancelPending = output<void>();\n readonly acceptResult = output<void>();\n readonly requestRefine = output<void>();\n\n private readonly destroyRef = inject(DestroyRef);\n private readonly llmService = inject(WriteWithAiLlmService);\n private readonly uiTranslate = inject(UiTranslatePipe);\n private readonly promptModel = signal('');\n private readonly isPanelManuallyOpen = signal(false);\n private readonly internalStatus = signal<WriteWithAiStatus>('idle');\n private readonly internalValue = signal('');\n private readonly cancelRequest$ = new Subject<void>();\n\n /** ControlValueAccessor: whether the form control is disabled. */\n readonly cvaDisabled = signal(false);\n\n /** Tag carousel (tagsOnly mode): scroll container + arrow-enabled state. */\n private readonly tagsScrollRef = viewChild<ElementRef<HTMLDivElement>>('tagsScrollContainer');\n readonly canScrollTagsLeft = signal(false);\n readonly canScrollTagsRight = signal(false);\n\n /** ControlValueAccessor callbacks. */\n private onChange: (value: string) => void = () => {};\n private onTouched: () => void = () => {};\n\n readonly translationContext = 'WRITE_WITH_AI.';\n\n private readonly labels = toSignal(\n combineLatest([\n this.uiTranslate.transform(`${this.translationContext}CANCEL`),\n this.uiTranslate.transform(`${this.translationContext}ACCEPT`),\n this.uiTranslate.transform(`${this.translationContext}MAKE_CHANGES`),\n this.uiTranslate.transform(`${this.translationContext}TRY_AGAIN`),\n ]).pipe(map(([cancel, accept, makeChanges, tryAgain]) => ({ cancel, accept, makeChanges, tryAgain }))),\n { initialValue: { cancel: '', accept: '', makeChanges: '', tryAgain: '' } }\n );\n\n readonly isDefaultMode = computed(() => this.llmConfig()?.default === true);\n\n readonly effectiveStatus = computed(() => (this.isDefaultMode() ? this.internalStatus() : this.status()));\n\n readonly effectiveValue = computed(() => (this.isDefaultMode() ? this.internalValue() : this.value()));\n\n readonly isPanelVisible = computed(() => this.standalone() || this.isPanelManuallyOpen());\n\n readonly promptTags = computed<PromptTag[]>(() =>\n this.tags().map(tag => ({ id: tag.id, label: tag.label, autocomplete: tag.description ?? '' }))\n );\n\n readonly statusConfig = computed<StatusConfig | null>(() => {\n const l = this.labels();\n switch (this.effectiveStatus()) {\n case 'loading':\n return {\n variant: 'loading',\n alertType: 'info',\n messageKey: `${this.translationContext}WRITING`,\n actions: [{ label: l.cancel, onClick: () => this.handleCancel() }],\n };\n case 'success':\n return {\n variant: 'success',\n alertType: 'success',\n messageKey: `${this.translationContext}CONTENT_GENERATED`,\n actions: [\n { label: l.makeChanges, onClick: () => this.handleRefine() },\n { label: l.accept, onClick: () => this.handleAccept() },\n ],\n };\n case 'error':\n return {\n variant: 'error',\n alertType: 'error',\n messageKey: `${this.translationContext}ERROR_MESSAGE`,\n actions: [{ label: l.tryAgain, onClick: () => this.handleRefine() }],\n };\n case 'idle':\n return null;\n default:\n return null;\n }\n });\n\n constructor() {\n effect(() => {\n const promptValue = this.promptValue();\n const isDefault = this.isDefaultMode();\n if (!isDefault) {\n untracked(() => this.promptModel.set(promptValue));\n }\n });\n\n effect(() => {\n const value = this.value();\n const isDefault = this.isDefaultMode();\n if (isDefault) {\n untracked(() => this.internalValue.set(value));\n }\n });\n\n // Scroll events don't trigger change detection, so the arrow disabled-state\n // is kept in signals. This re-measures whenever the carousel (re)mounts or\n // the tag set changes; runtime scrolling is handled by the (scroll) listener.\n // It only reads layout, so it runs in the dedicated `read` phase.\n afterRenderEffect({\n read: () => {\n this.tags();\n const el = this.tagsScrollRef()?.nativeElement;\n if (el) {\n this.measureTagScroll(el);\n }\n },\n });\n\n // Resizing the host can change overflow without a scroll or tag-set change,\n // so observe the carousel and re-measure when its box changes.\n effect(onCleanup => {\n const el = this.tagsScrollRef()?.nativeElement;\n if (!el || typeof ResizeObserver === 'undefined') {\n return;\n }\n const observer = new ResizeObserver(() => this.measureTagScroll(el));\n observer.observe(el);\n onCleanup(() => observer.disconnect());\n });\n }\n\n readonly promptModelData = computed<PromptData>(() => ({ text: this.promptModel(), files: [] }));\n\n handlePromptModelChange(value: PromptData | string): void {\n const text = typeof value === 'string' ? value : (value?.text ?? '');\n this.promptModel.set(text);\n this.promptChange.emit(text);\n }\n\n ngOnInit() {\n if (this.defaultOpen()) {\n this.isPanelManuallyOpen.set(true);\n }\n }\n\n togglePanel(): void {\n if (this.standalone()) {\n return;\n }\n this.isPanelManuallyOpen.update(current => !current);\n }\n\n handleValueInput(value: string): void {\n if (this.isDefaultMode()) {\n this.internalValue.set(value);\n }\n this.valueChange.emit(value);\n this.onChange(value);\n this.onTouched();\n }\n\n handlePromptSubmit(promptData?: PromptData | string): void {\n const prompt = typeof promptData === 'string' ? promptData : (promptData?.text ?? this.promptModel());\n this.promptModel.set(prompt);\n this.promptChange.emit(prompt);\n\n const submitEvent: WriteWithAiSubmitEvent = {\n prompt,\n content: this.effectiveValue(),\n metadata: this.metadata(),\n };\n\n if (this.isDefaultMode()) {\n this.executeDefaultFlow(prompt);\n }\n\n this.promptSubmit.emit(submitEvent);\n }\n\n handleTagClick(tag: WriteWithAiTagOption): void {\n // ui-tag's press fires even when isDisabled, so guard here.\n if (this.cvaDisabled()) {\n return;\n }\n this.handlePromptSubmit(tag.label);\n }\n\n measureTagScroll(el: HTMLElement): void {\n this.canScrollTagsLeft.set(el.scrollLeft > 0);\n this.canScrollTagsRight.set(Math.ceil(el.scrollLeft + el.clientWidth) < el.scrollWidth);\n }\n\n scrollTags(el: HTMLElement, direction: -1 | 1): void {\n el.scrollBy({ left: direction * el.clientWidth * 0.8, behavior: 'smooth' });\n }\n\n handlePrimaryAction(): void {\n const status = this.effectiveStatus();\n if (status === 'loading') {\n this.handleCancel();\n } else if (status === 'success') {\n this.handleAccept();\n } else if (status === 'error') {\n this.handleRefine();\n }\n }\n\n handleSecondaryAction(): void {\n if (this.effectiveStatus() === 'success') {\n this.handleRefine();\n }\n }\n\n // --- ControlValueAccessor ---\n\n writeValue(value: string): void {\n const v = value ?? '';\n if (this.isDefaultMode()) {\n this.internalValue.set(v);\n }\n // For integration mode the host uses the [value] input directly,\n // but we still keep internal state in sync for CVA consumers.\n this.internalValue.set(v);\n }\n\n registerOnChange(fn: (value: string) => void): void {\n this.onChange = fn;\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this.cvaDisabled.set(isDisabled);\n }\n\n // --- Private helpers ---\n\n private executeDefaultFlow(prompt: string): void {\n const config = this.llmConfig();\n if (!config) {\n return;\n }\n\n this.cancelRequest$.next();\n this.internalStatus.set('loading');\n\n this.llmService\n .generate({ sourceText: this.effectiveValue(), prompt, context: config.context }, config)\n .pipe(takeUntilDestroyed(this.destroyRef), takeUntil(this.cancelRequest$))\n .subscribe({\n next: result => {\n this.internalValue.set(result);\n this.valueChange.emit(result);\n this.onChange(result);\n this.internalStatus.set('success');\n },\n error: () => {\n this.internalStatus.set('error');\n },\n });\n }\n\n private handleCancel(): void {\n if (this.isDefaultMode()) {\n this.cancelRequest$.next();\n this.internalStatus.set('idle');\n }\n this.cancelPending.emit();\n }\n\n private handleAccept(): void {\n if (this.isDefaultMode()) {\n this.internalStatus.set('idle');\n this.promptModel.set('');\n }\n if (!this.standalone()) {\n this.isPanelManuallyOpen.set(false);\n }\n this.acceptResult.emit();\n }\n\n private handleRefine(): void {\n if (this.isDefaultMode()) {\n this.internalStatus.set('idle');\n }\n this.requestRefine.emit();\n }\n}\n","<div\n class=\"write-with-ai\"\n [class.write-with-ai--standalone]=\"standalone()\"\n [class.write-with-ai--full-height]=\"fullHeight()\"\n>\n @if (!standalone()) {\n <div class=\"write-with-ai__host\">\n <ui-field\n [label]=\"fieldLabel() || (translationContext + 'FIELD_LABEL' | uiTranslate | async)!\"\n type=\"textarea\"\n [showBottomContent]=\"false\"\n [fullHeight]=\"fullHeight()\"\n [borderless]=\"borderless()\"\n [disabled]=\"cvaDisabled()\"\n [ngModel]=\"effectiveValue()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"handleValueInput($event)\"\n ></ui-field>\n <ui-button\n class=\"write-with-ai__cta\"\n variant=\"ghost-ai\"\n size=\"small\"\n [label]=\"(translationContext + 'AI_ASSIST' | uiTranslate | async)!\"\n iconName=\"Sparkle-in-line\"\n iconPosition=\"left\"\n [disabled]=\"isPanelVisible() || cvaDisabled()\"\n (buttonClickEvent)=\"togglePanel()\"\n ></ui-button>\n </div>\n }\n\n @if (isPanelVisible()) {\n <section\n class=\"write-with-ai__panel\"\n [class.write-with-ai__panel--loading]=\"effectiveStatus() === 'loading'\"\n role=\"region\"\n [attr.aria-label]=\"(translationContext + 'AI_WRITING_ASSISTANT' | uiTranslate | async)!\"\n >\n <header class=\"write-with-ai__panel-header\">\n <div class=\"write-with-ai__panel-heading\">\n <div class=\"write-with-ai__title-row\">\n @if (effectiveStatus() !== 'loading') {\n <ui-icon class=\"write-with-ai__title-icon\" name=\"Sparkle-in-line\" color=\"ai\"></ui-icon>\n }\n <h4 class=\"write-with-ai__title\">\n {{ header() || (translationContext + 'HEADER' | uiTranslate | async) }}\n </h4>\n </div>\n @if (subheader()) {\n <p class=\"write-with-ai__subheader\">{{ subheader() }}</p>\n }\n </div>\n @if (!standalone()) {\n <ui-button\n variant=\"icon-button\"\n iconName=\"Close\"\n size=\"small\"\n [tooltip]=\"(translationContext + 'CLOSE' | uiTranslate | async)!\"\n [ariaLabel]=\"(translationContext + 'CLOSE_AI_ASSISTANT' | uiTranslate | async)!\"\n (buttonClickEvent)=\"togglePanel()\"\n ></ui-button>\n }\n </header>\n\n @if (effectiveStatus() === 'idle') {\n @if (tagsOnly()) {\n @if (tags().length) {\n <div class=\"write-with-ai__tags-prompt\">\n <div\n class=\"write-with-ai__tags-container\"\n role=\"group\"\n [attr.aria-label]=\"header() || (translationContext + 'HEADER' | uiTranslate | async)\"\n #tagsScrollContainer\n (scroll)=\"measureTagScroll(tagsScrollContainer)\"\n >\n @for (tag of tags(); track tag.id) {\n <ui-tag\n [label]=\"tag.label\"\n [ariaLabel]=\"tag.label\"\n [isDisabled]=\"cvaDisabled()\"\n (press)=\"handleTagClick(tag)\"\n ></ui-tag>\n }\n </div>\n <div class=\"write-with-ai__tags-arrows\">\n <ui-button\n variant=\"icon-button\"\n size=\"small\"\n iconName=\"Arrow-chevron-left-in-line\"\n [tooltip]=\"(translationContext + 'SCROLL_TAGS_LEFT' | uiTranslate | async)!\"\n [ariaLabel]=\"(translationContext + 'SCROLL_TAGS_LEFT' | uiTranslate | async)!\"\n [disabled]=\"cvaDisabled() || !canScrollTagsLeft()\"\n (buttonClickEvent)=\"scrollTags(tagsScrollContainer, -1)\"\n ></ui-button>\n <ui-button\n variant=\"icon-button\"\n size=\"small\"\n iconName=\"Arrow-chevron-right-in-line\"\n [tooltip]=\"(translationContext + 'SCROLL_TAGS_RIGHT' | uiTranslate | async)!\"\n [ariaLabel]=\"(translationContext + 'SCROLL_TAGS_RIGHT' | uiTranslate | async)!\"\n [disabled]=\"cvaDisabled() || !canScrollTagsRight()\"\n (buttonClickEvent)=\"scrollTags(tagsScrollContainer, 1)\"\n ></ui-button>\n </div>\n </div>\n }\n } @else {\n <div class=\"write-with-ai__prompt\">\n <ui-prompt\n [ngModel]=\"promptModelData()\"\n [ngModelOptions]=\"{ standalone: true }\"\n (ngModelChange)=\"handlePromptModelChange($event)\"\n [tags]=\"promptTags()\"\n [placeholder]=\"placeholder() || (translationContext + 'PLACEHOLDER' | uiTranslate | async)!\"\n [showSendButton]=\"true\"\n (promptData)=\"handlePromptSubmit($event)\"\n ></ui-prompt>\n </div>\n }\n }\n\n @if (statusConfig(); as cfg) {\n <ui-alert-banner\n [alertType]=\"cfg.alertType\"\n alertVariant=\"callout\"\n [message]=\"(cfg.messageKey | uiTranslate | async)!\"\n [includeDismissButton]=\"false\"\n [isLoading]=\"cfg.variant === 'loading'\"\n [hasIcon]=\"cfg.variant !== 'loading'\"\n [actions]=\"cfg.actions\"\n [isFullWidth]=\"true\"\n ></ui-alert-banner>\n }\n\n <div class=\"write-with-ai__caveat\">\n <ui-ai-caveat></ui-ai-caveat>\n </div>\n </section>\n }\n</div>\n","import { NgModule } from '@angular/core';\n\nimport { WriteWithAiComponent } from './write-with-ai.component';\n\n@NgModule({\n imports: [WriteWithAiComponent],\n exports: [WriteWithAiComponent],\n})\nexport class WriteWithAiComponentModule {}\n"],"mappings":"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"}
|