@kodaris/krubble-components 1.0.74 → 1.0.75
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/custom-elements.json +1109 -47
- package/dist/grid/grid.d.ts +187 -0
- package/dist/grid/grid.d.ts.map +1 -0
- package/dist/grid/grid.js +2419 -0
- package/dist/grid/grid.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/krubble-components.bundled.js +2521 -116
- package/dist/krubble-components.bundled.js.map +1 -1
- package/dist/krubble-components.bundled.min.js +1361 -131
- package/dist/krubble-components.bundled.min.js.map +1 -1
- package/dist/krubble-components.umd.js +2520 -115
- package/dist/krubble-components.umd.js.map +1 -1
- package/dist/krubble-components.umd.min.js +1319 -89
- package/dist/krubble-components.umd.min.js.map +1 -1
- package/package.json +5 -1
package/custom-elements.json
CHANGED
|
@@ -111,6 +111,14 @@
|
|
|
111
111
|
"module": "./table/table.js"
|
|
112
112
|
}
|
|
113
113
|
},
|
|
114
|
+
{
|
|
115
|
+
"kind": "js",
|
|
116
|
+
"name": "KRGrid",
|
|
117
|
+
"declaration": {
|
|
118
|
+
"name": "KRGrid",
|
|
119
|
+
"module": "./grid/grid.js"
|
|
120
|
+
}
|
|
121
|
+
},
|
|
114
122
|
{
|
|
115
123
|
"kind": "js",
|
|
116
124
|
"name": "KRQuery",
|
|
@@ -605,6 +613,11 @@
|
|
|
605
613
|
"name": "KRTable",
|
|
606
614
|
"default": "class KRTable extends i$2 { constructor() { super(...arguments); /** * Internal flag to switch between scroll edge modes: * - 'overlay': Fixed padding with overlay elements that hide content at edges (scrollbar at viewport edge) * - 'edge': Padding scrolls with content, allowing table to reach edges when scrolling */ this._scrollStyle = 'edge'; this._data = []; this._dataState = 'idle'; this._page = 1; this._pageSize = 50; this._totalItems = 0; this._totalPages = 0; this._searchQuery = ''; this._canScrollLeft = false; this._canScrollRight = false; this._canScrollHorizontal = false; this._columnPickerOpen = false; this._filterPanelOpened = null; this._filterPanelTab = 'filter'; this._buckets = new Map(); this._filterPanelPos = { top: 0, left: 0 }; this._sorts = []; this._resizing = null; this._resizeObserver = null; this._searchPositionLocked = false; this._columnWidthsLocked = false; this._model = new KRTableModel(); this.def = { columns: [] }; /** * Table layout variant. * - 'default': Full-page table that fills parent height with centered search. * - 'card': Embedded table that sizes itself to content, left-aligns search, and * reserves space for pageSize rows to prevent layout shift. */ this.variant = 'default'; this._handleClickOutside = (e) => { const path = e.composedPath(); if (this._columnPickerOpen) { const picker = this.shadowRoot?.querySelector('.column-picker-wrapper'); if (picker && !path.includes(picker)) { this._columnPickerOpen = false; } } if (this._filterPanelOpened) { if (!path.some((el) => el.classList?.contains('filter-panel'))) { this._handleFilterApply(); } } }; this._handleResizeMove = (e) => { if (!this._resizing) return; const col = this._model.columns.find(c => c.id === this._resizing.columnId); if (col) { const newWidth = this._resizing.startWidth + (e.clientX - this._resizing.startX); col.width = `${Math.min(900, Math.max(50, newWidth))}px`; this.requestUpdate(); } }; this._handleResizeEnd = () => { this._resizing = null; document.removeEventListener('mousemove', this._handleResizeMove); document.removeEventListener('mouseup', this._handleResizeEnd); }; } connectedCallback() { super.connectedCallback(); this.classList.toggle('kr-table--scroll-overlay', this._scrollStyle === 'overlay'); this.classList.toggle('kr-table--scroll-edge', this._scrollStyle === 'edge'); this._fetch(); this._initRefresh(); document.addEventListener('click', this._handleClickOutside); this._resizeObserver = new ResizeObserver(() => { // Unlock and recalculate on resize since layout changes this._searchPositionLocked = false; this._updateSearchPosition(); }); this._resizeObserver.observe(this); } disconnectedCallback() { super.disconnectedCallback(); clearInterval(this._refreshTimer); document.removeEventListener('click', this._handleClickOutside); this._resizeObserver?.disconnect(); } willUpdate(changedProperties) { if (changedProperties.has('def')) { // Build internal model from user-provided def this._columnWidthsLocked = false; this._model = new KRTableModel(); if (this.def.title) { this._model.title = this.def.title; } if (this.def.description) { this._model.description = this.def.description; } if (this.def.actions) { this._model.actions = this.def.actions; } if (this.def.data) { this._model.data = this.def.data; } if (this.def.dataSource) { this._model.dataSource = this.def.dataSource; } if (typeof this.def.refreshInterval === 'number') { this._model.refreshInterval = this.def.refreshInterval; } if (typeof this.def.pageSize === 'number') { this._model.pageSize = this.def.pageSize; this._pageSize = this.def.pageSize; } if (this.def.rowClickable) { this._model.rowClickable = this.def.rowClickable; } if (this.def.rowHref) { this._model.rowHref = this.def.rowHref; } this._sorts = []; this._model.columns = this.def.columns.map(col => { const column = { ...col, filter: null }; if (!column.type) { column.type = 'string'; } if (col.sort) { this._sorts.push({ sortBy: col.id, sortDirection: col.sort }); } if (column.type === 'actions') { column.label = col.label ?? ''; column.sticky = 'right'; column.resizable = false; return column; } if (col.filterable || col.facetable) { column.filter = new KRQuery(); column.filter.field = col.id; column.filter.type = column.type; if (col.filter) { column.filter.setOperator(col.filter.operator); column.filter.setValue(col.filter.value); } else if (col.facetable && !col.filterable) { column.filter.operator = 'in'; column.filter.value = []; } else if (column.filter.type === 'string') { column.filter.operator = 'contains'; } } return column; }); if (this.def.displayedColumns) { this._model.displayedColumns = this.def.displayedColumns; } else { this._model.displayedColumns = this._model.columns.map(c => c.id); } this._fetch(); this._initRefresh(); } } updated(changedProperties) { this.classList.toggle('kr-table--card', this.variant === 'card'); this._updateScrollFlags(); this._syncSlottedContent(); this._lockColumnWidths(); } /** Measures header cell widths and locks them to prevent column shift on subsequent data changes. */ _lockColumnWidths() { if (this._columnWidthsLocked || this._data.length === 0) return; const headerCells = this.shadowRoot?.querySelectorAll('.header-row > .header-cell'); if (!headerCells) return; const cols = this.getDisplayedColumns(); headerCells.forEach((cell, i) => { const cellWidth = cell.offsetWidth; if (i < cols.length && !cols[i].width && cols[i].type !== 'actions' && cellWidth > 0) { cols[i].width = `${cellWidth}px`; this._columnWidthsLocked = true; } }); } /** Syncs light DOM content for cells with custom render functions */ _syncSlottedContent() { const columns = this.getDisplayedColumns().filter(col => col.render); if (!columns.length) return; // Clear old slotted content this.querySelectorAll('[slot^=\"cell-\"]').forEach(el => el.remove()); // Create new slotted content this._data.forEach((row, rowIndex) => { columns.forEach(col => { const result = col.render(row); if (!result) return; const el = document.createElement('span'); el.slot = `cell-${rowIndex}-${col.id}`; if (col.type === 'actions') { el.style.display = 'flex'; el.style.gap = '8px'; } if (typeof result === 'string') { el.innerHTML = result; } else { D(result, el); } this.appendChild(el); }); }); } // ---------------------------------------------------------------------------- // Public Interface // ---------------------------------------------------------------------------- refresh() { this._fetch(); } goToPrevPage() { if (this._page > 1) { this._page--; this._fetch(); } } goToNextPage() { if (this._page < this._totalPages) { this._page++; this._fetch(); } } goToPage(page) { if (page >= 1 && page <= this._totalPages) { this._page = page; this._fetch(); } } // ---------------------------------------------------------------------------- // Data Fetching // ---------------------------------------------------------------------------- _toSolrData() { const request = { page: this._page - 1, size: this._pageSize, sorts: this._sorts, filterFields: [], queryFields: [], facetFields: [] }; for (const col of this._model.columns) { if (!col.filter || col.filter.isEmpty() || !col.filter.isValid()) { continue; } const filterData = col.filter.toSolrData(); if (col.facetable && (col.filter.operator === 'in' || col.filter.operator === 'n_in')) { filterData.tagged = true; } request.filterFields.push(filterData); } for (const col of this._model.columns) { if (!col.facetable) { continue; } request.facetFields.push({ name: col.id, type: 'FIELD', limit: 100, sort: 'count', minimumCount: 1 }); } if (this._searchQuery?.trim().length) { request.queryFields.push({ name: '_text_', operation: 'IS', value: termify(this._searchQuery, false) }); } return request; } _toDbParams() { const request = { page: this._page - 1, size: this._pageSize, sorts: this._sorts, filterFields: [], queryFields: [], facetFields: [] }; for (const col of this._model.columns) { if (!col.filter || col.filter.isEmpty() || !col.filter.isValid()) { continue; } request.filterFields.push(col.filter.toDbParams()); } if (this._searchQuery?.trim().length) { this._model.columns.filter(col => col.searchable).forEach(col => { request.queryFields.push({ name: col.id, operation: 'CONTAINS', value: this._searchQuery, and: false }); }); } return request; } /** * Fetches data from the API and updates the table. * Shows a loading spinner while fetching, then displays rows on success * or an error snackbar on failure. * Request/response format depends on dataSource.mode (solr, opensearch, db). */ _fetch() { if (this._model.data) { this._data = this._model.data; this._totalItems = this._model.data.length; this._totalPages = Math.ceil(this._model.data.length / this._pageSize); this._dataState = 'success'; return; } if (!this._model.dataSource) return; this._dataState = 'loading'; let request; if (this._model.dataSource.mode === 'db') { request = this._toDbParams(); } else { request = this._toSolrData(); } this._model.dataSource.fetch(request) .then(response => { // Parse response based on mode switch (this._model.dataSource?.mode) { case 'opensearch': { throw Error('Opensearch not supported yet'); } case 'db': { const res = response; this._data = res.data.content; this._totalItems = res.data.totalElements; this._totalPages = res.data.totalPages; this._pageSize = res.data.size; break; } default: { // solr const res = response; this._data = res.data.content; this._totalItems = res.data.totalElements; this._totalPages = res.data.totalPages; this._pageSize = res.data.size; this._parseFacetResults(res); } } this._dataState = 'success'; this._updateSearchPosition(); }) .catch(err => { this._dataState = 'error'; KRSnackbar.show({ message: err instanceof Error ? err.message : 'Failed to load data', type: 'error' }); }); } _parseFacetResults(response) { if (!response.data.facetFields) { return; } for (const col of this._model.columns) { if (!col.facetable) { continue; } const rawBuckets = response.data.facetFields[col.id]; if (!rawBuckets) { this._buckets.set(col.id, []); continue; } const buckets = []; for (const raw of rawBuckets) { // Solr returns boolean facet values as strings — coerce to actual booleans // so they match the filter values stored by toggle(). let val = raw.name; if (col.type === 'boolean' && typeof raw.name === 'string') { if (raw.name === 'true') { val = true; } else if (raw.name === 'false') { val = false; } } if (raw.name === null && raw.count > 0) { buckets.unshift({ val: null, count: raw.count }); } if (raw.name !== null) { buckets.push({ val: val, count: raw.count }); } } // Bucket sync: ensure selected values appear even with 0 results if (col.filter && (col.filter.operator === 'in' || col.filter.operator === 'n_in') && Array.isArray(col.filter.value)) { for (const selectedVal of col.filter.value) { if (!buckets.some(b => b.val === selectedVal)) { buckets.push({ val: selectedVal, count: 0 }); } } } this._buckets.set(col.id, buckets); } // Trigger re-render since Map mutation doesn't trigger Lit updates this._buckets = new Map(this._buckets); } /** * Sets up auto-refresh so the table automatically fetches fresh data * at a regular interval (useful for dashboards, monitoring views). * Configured via def.refreshInterval in milliseconds. */ _initRefresh() { clearInterval(this._refreshTimer); if (this._model.refreshInterval && this._model.refreshInterval > 0) { this._refreshTimer = window.setInterval(() => { this._fetch(); }, this._model.refreshInterval); } } _handleSearch(e) { const input = e.target; this._searchQuery = input.value; this._page = 1; this._fetch(); } _getGridTemplateColumns() { const cols = this.getDisplayedColumns(); return cols.map((col) => { // If column has explicit width, use it if (col.width) { return col.width; } // Actions columns: fit content without minimum if (col.type === 'actions') { return 'max-content'; } // No width specified - use content-based sizing with minimum return 'minmax(80px, auto)'; }).join(' '); } /** * Updates search position to be centered with equal gaps from title and tools. * On first call: resets to flex centering, measures position, then locks with fixed margin. * Subsequent calls are ignored unless _searchPositionLocked is reset (e.g., on resize). */ _updateSearchPosition() { // Skip if already locked (prevents shifts on pagination changes) if (this._searchPositionLocked) return; // In card mode, search is left-aligned via CSS — no position locking needed if (this.variant === 'card') return; const search = this.shadowRoot?.querySelector('.search'); const searchField = search?.querySelector('.search-field'); if (!search || !searchField) return; // Reset to flex centering search.style.justifyContent = 'center'; searchField.style.marginLeft = ''; requestAnimationFrame(() => { const searchRect = search.getBoundingClientRect(); const fieldRect = searchField.getBoundingClientRect(); // Calculate how far from the left of search container the field currently is const currentOffset = fieldRect.left - searchRect.left; // Lock position: switch to flex-start and use fixed margin search.style.justifyContent = 'flex-start'; searchField.style.marginLeft = `${currentOffset}px`; // Mark as locked so pagination changes don't shift the search this._searchPositionLocked = true; }); } // ---------------------------------------------------------------------------- // Columns // ---------------------------------------------------------------------------- _toggleColumnPicker() { this._columnPickerOpen = !this._columnPickerOpen; } _toggleColumn(columnId) { if (this._model.displayedColumns.includes(columnId)) { this._model.displayedColumns = this._model.displayedColumns.filter(id => id !== columnId); } else { this._model.displayedColumns = [...this._model.displayedColumns, columnId]; } this.requestUpdate(); } // Clear any existing text selection on mousedown so we only detect // selections made during this click gesture, not stale selections from elsewhere _handleRowMouseDown() { if (!this._model.rowClickable && !this._model.rowHref) { return; } window.getSelection()?.removeAllRanges(); } _handleRowClick(e, row, rowIndex) { if (!this._model.rowClickable && !this._model.rowHref) { return; } const selection = window.getSelection(); if (selection && selection.toString().length > 0) { e.preventDefault(); return; } this.dispatchEvent(new CustomEvent('row-click', { detail: { row, rowIndex }, bubbles: true, composed: true })); } // When a user toggles a column on via the column picker, it gets appended // to _displayedColumns. By mapping over _displayedColumns (not def.columns), // the new column appears at the right edge of the table instead of jumping // back to its original position in the column definition. // Actions columns are always moved to the end. getDisplayedColumns() { return this._model.displayedColumns .map(id => this._model.columns.find(col => col.id === id)) .sort((a, b) => { if (a.type === 'actions' && b.type !== 'actions') return 1; if (a.type !== 'actions' && b.type === 'actions') return -1; return 0; }); } // ---------------------------------------------------------------------------- // Scrolling // ---------------------------------------------------------------------------- /** * Scroll event handler that updates scroll flags in real-time as user scrolls. * Updates shadow indicators to show if more content exists left/right. */ _handleScroll(e) { const container = e.target; this._canScrollLeft = container.scrollLeft > 0; this._canScrollRight = container.scrollLeft < container.scrollWidth - container.clientWidth - 1; } /** * Updates scroll state flags for the table content container. * - _canScrollLeft: true if scrolled right (can scroll back left) * - _canScrollRight: true if more content exists to the right * - _canScrollHorizontal: true if content is wider than container * These flags control scroll shadow indicators and CSS classes. */ _updateScrollFlags() { const container = this.shadowRoot?.querySelector('.content'); if (container) { this._canScrollLeft = container.scrollLeft > 0; this._canScrollRight = container.scrollWidth > container.clientWidth && container.scrollLeft < container.scrollWidth - container.clientWidth - 1; this._canScrollHorizontal = container.scrollWidth > container.clientWidth; } this.classList.toggle('kr-table--scroll-left-available', this._canScrollLeft); this.classList.toggle('kr-table--scroll-right-available', this._canScrollRight); this.classList.toggle('kr-table--scroll-horizontal-available', this._canScrollHorizontal); this.classList.toggle('kr-table--sticky-left', this.getDisplayedColumns().some(c => c.sticky === 'left')); this.classList.toggle('kr-table--sticky-right', this.getDisplayedColumns().some(c => c.sticky === 'right')); } // ---------------------------------------------------------------------------- // Column Resizing // ---------------------------------------------------------------------------- _handleResizeStart(e, columnId) { e.preventDefault(); const headerCell = this.shadowRoot?.querySelector(`.header-cell[data-column-id=\"${columnId}\"]`); this._resizing = { columnId, startX: e.clientX, startWidth: headerCell?.offsetWidth || 200 }; document.addEventListener('mousemove', this._handleResizeMove); document.addEventListener('mouseup', this._handleResizeEnd); } // ---------------------------------------------------------------------------- // Sorting // ---------------------------------------------------------------------------- _handleSortClick(e, column) { if (e.shiftKey) { // Multi-sort: add or cycle existing const existingIndex = this._sorts.findIndex(s => s.sortBy === column.id); if (existingIndex === -1) { this._sorts.push({ sortBy: column.id, sortDirection: 'asc' }); } else { const existing = this._sorts[existingIndex]; if (existing.sortDirection === 'asc') { existing.sortDirection = 'desc'; } else { // on third click, remove sorting for the column this._sorts.splice(existingIndex, 1); } } this.requestUpdate(); } else { // Single sort: replace all let existing = null; if (this._sorts.length === 1) { existing = this._sorts.find(s => s.sortBy === column.id); } if (!existing) { this._sorts = [{ sortBy: column.id, sortDirection: 'asc' }]; } else if (existing.sortDirection === 'asc') { this._sorts = [{ sortBy: column.id, sortDirection: 'desc' }]; } else { this._sorts = []; } } this._page = 1; this._fetch(); } _renderSortIndicator(column) { if (!column.sortable) { return A; } const sortIndex = this._sorts.findIndex(s => s.sortBy === column.id); if (sortIndex === -1) { // Ghost arrow: visible only on hover via CSS return b ` <span class=\"header-cell__sort\" @click=${(e) => this._handleSortClick(e, column)}> <svg class=\"header-cell__sort-arrow header-cell__sort-arrow--ghost\" viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z\"/> </svg> </span> `; } let arrowStyle = {}; if (this._sorts[sortIndex].sortDirection === 'desc') { arrowStyle = { transform: 'rotate(180deg)' }; } return b ` <span class=\"header-cell__sort\" @click=${(e) => this._handleSortClick(e, column)}> <svg class=\"header-cell__sort-arrow\" viewBox=\"0 0 24 24\" fill=\"currentColor\" style=${o$1(arrowStyle)}> <path d=\"M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z\"/> </svg> ${this._sorts.length > 1 ? b ` <span class=\"header-cell__sort-priority\">${sortIndex + 1}</span> ` : A} </span> `; } // ---------------------------------------------------------------------------- // Header // ---------------------------------------------------------------------------- _handleAction(action) { if (action.href) { return; } this.dispatchEvent(new CustomEvent('action', { detail: { action: action.id }, bubbles: true, composed: true })); } // ---------------------------------------------------------------------------- // Filter Handlers // ---------------------------------------------------------------------------- _handleKqlChange(e, column) { const kql = e.target.value.trim(); if (!kql) { column.filter.clear(); this.requestUpdate(); } else { column.filter.setKql(kql); this.requestUpdate(); if (!column.filter.isValid()) { return; } } this._page = 1; this._fetch(); } _handleFilterPanelToggle(e, column) { e.stopPropagation(); if (this._filterPanelOpened === column.id) { this._filterPanelOpened = null; } else { const rect = e.currentTarget.getBoundingClientRect(); let left = rect.left; if (left + 328 > window.innerWidth) { left = window.innerWidth - 328; } this._filterPanelPos = { top: rect.bottom + 4, left }; this._filterPanelOpened = column.id; if (column.facetable) { this._filterPanelTab = 'counts'; } else { this._filterPanelTab = 'filter'; } } } _handleKqlClear(column) { column.filter.clear(); this._page = 1; this._fetch(); } _handleFilterClear() { const column = this._model.columns.find(c => c.id === this._filterPanelOpened); if (column) { column.filter.clear(); if (column.facetable && !column.filterable) { column.filter.operator = 'in'; column.filter.value = []; } } this._filterPanelOpened = null; this._page = 1; this._fetch(); } _handleFilterTextKeydown(e, column) { if (e.key === 'Enter') { e.preventDefault(); this._handleFilterApply(); } } _handleOperatorChange(e, column) { column.filter.setOperator(e.target.value); this.requestUpdate(); } _handleFilterStringChange(e, column) { column.filter.setValue(e.target.value); this.requestUpdate(); } _handleFilterNumberChange(e, column) { column.filter.setValue(Number(e.target.value)); this.requestUpdate(); } _handleFilterDateChange(e, column) { column.filter.setValue(new Date(e.target.value), 'day'); this.requestUpdate(); } _handleFilterBooleanChange(e, column) { column.filter.setValue(e.target.value === 'true'); this.requestUpdate(); } _handleFilterDateStartChange(e, column) { column.filter.setStart(new Date(e.target.value), 'day'); this.requestUpdate(); } _handleFilterDateEndChange(e, column) { column.filter.setEnd(new Date(e.target.value), 'day'); this.requestUpdate(); } _handleFilterNumberStartChange(e, column) { column.filter.setStart(Number(e.target.value)); this.requestUpdate(); } _handleFilterNumberEndChange(e, column) { column.filter.setEnd(Number(e.target.value)); this.requestUpdate(); } _handleFilterListChange(e, column) { const items = e.target.value.split(',').map((v) => v.trim()).filter((v) => v !== ''); if (column.type === 'number') { column.filter.setValue(items.map((v) => Number(v))); } else { column.filter.setValue(items); } this.requestUpdate(); } _handleFilterApply() { this._filterPanelOpened = null; this._page = 1; this._fetch(); } _handleFilterPanelTabChange(e) { this._filterPanelTab = e.detail.activeTabId; } _handleBucketToggle(e, column, bucket) { column.filter.toggle(bucket.val); this._page = 1; this._fetch(); } // ---------------------------------------------------------------------------- // Rendering // ---------------------------------------------------------------------------- _renderCellContent(column, row, rowIndex) { const value = row[column.id]; if (column.render) { // Use slot to project content from light DOM so external styles apply return b `<slot name=\"cell-${rowIndex}-${column.id}\"></slot>`; } if (value === null || value === undefined) { return ''; } switch (column.type) { case 'number': if (column.format === 'currency' && typeof value === 'number') { return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' }); } return String(value); case 'date': { let date; if (value instanceof Date) { date = value; } else if (typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}/.test(value)) { // MySQL datetime format (UTC): \"2026-01-28 01:33:44:517\" // Replace last colon before ms with dot, append Z for UTC const isoString = value.replace(/(\\d{2}:\\d{2}:\\d{2}):(\\d+)$/, '$1.$2').replace(' ', 'T') + 'Z'; date = new Date(isoString); } else { date = new Date(value); } // Show date and time for datetime values in UTC return date.toLocaleString(undefined, { year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit', timeZone: 'UTC' }); } case 'boolean': if (value === true) return 'Yes'; if (value === false) return 'No'; return ''; default: return String(value); } } /** * Returns CSS classes for a header cell based on column config. */ _getHeaderCellClasses(column, index) { return { 'header-cell': true, 'header-cell--sortable': !!column.sortable, 'header-cell--align-center': column.align === 'center', 'header-cell--align-right': column.align === 'right', 'header-cell--sticky-left': column.sticky === 'left', 'header-cell--sticky-left-last': column.sticky === 'left' && !this.getDisplayedColumns().slice(index + 1).some(c => c.sticky === 'left'), 'header-cell--sticky-right': column.sticky === 'right', 'header-cell--sticky-right-first': column.sticky === 'right' && !this.getDisplayedColumns().slice(0, index).some(c => c.sticky === 'right') }; } /** * Returns CSS classes for a table cell based on column config: * - Alignment (center, right) * - Sticky positioning (left, right) * - Border classes for the last left-sticky or first right-sticky column */ _getCellClasses(column, index) { return { 'cell': true, 'cell--actions': column.type === 'actions', 'cell--align-center': column.align === 'center', 'cell--align-right': column.align === 'right', 'cell--sticky-left': column.sticky === 'left', 'cell--sticky-left-last': column.sticky === 'left' && !this.getDisplayedColumns().slice(index + 1).some(c => c.sticky === 'left'), 'cell--sticky-right': column.sticky === 'right', 'cell--sticky-right-first': column.sticky === 'right' && !this.getDisplayedColumns().slice(0, index).some(c => c.sticky === 'right') }; } /** * Returns inline styles for a table cell: * - Width (from column config or default 150px) * - Min-width (if specified) * - Left/right offset for sticky columns (calculated from widths of preceding sticky columns) */ _getCellStyle(column, index) { const styles = {}; if (column.sticky === 'left') { let leftOffset = 0; for (let i = 0; i < index; i++) { const col = this.getDisplayedColumns()[i]; if (col.sticky === 'left') { leftOffset += parseInt(col.width || '0', 10); } } styles.left = `${leftOffset}px`; } if (column.sticky === 'right') { let rightOffset = 0; for (let i = index + 1; i < this.getDisplayedColumns().length; i++) { const col = this.getDisplayedColumns()[i]; if (col.sticky === 'right') { rightOffset += parseInt(col.width || '0', 10); } } styles.right = `${rightOffset}px`; } return styles; } /** * Renders the pagination controls: * - Previous page arrow (disabled on first page) * - Range text showing \"1-50 of 150\" format * - Next page arrow (disabled on last page) * * Hidden when there's no data or all data fits on one page. */ _renderPagination() { const start = (this._page - 1) * this._pageSize + 1; const end = Math.min(this._page * this._pageSize, this._totalItems); return b ` <div class=\"pagination\"> <span class=\"pagination-icon ${this._page === 1 ? 'pagination-icon--disabled' : ''}\" @click=${this.goToPrevPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z\"/></svg> </span> <span class=\"pagination-info\">${start}-${end} of ${this._totalItems}</span> <span class=\"pagination-icon ${this._page === this._totalPages ? 'pagination-icon--disabled' : ''}\" @click=${this.goToNextPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z\"/></svg> </span> </div> `; } /** Renders the card title block (title + description) above the toolbar in card mode. */ _renderCardHeader() { if (this.variant !== 'card') return A; if (!this._model.title && !this._model.description) return A; return b ` <div class=\"card-header\"> ${this._model.title ? b `<h2 class=\"card-header__title\">${this._model.title}</h2>` : A} ${this._model.description ? b `<p class=\"card-header__description\">${this._model.description}</p>` : A} </div> `; } /** * Renders the header toolbar containing: * - Title (left, default variant only) * - Search bar with view selector dropdown (center, or left-aligned in card variant) * - Tools (right): page navigation, refresh button, column visibility picker, actions dropdown * * Hidden when there's no title, no actions, and data fits on one page. */ _renderHeader() { if (!this._model.title && !this._model.actions?.length && this._totalPages <= 1) { return A; } return b ` <div class=\"header\"> ${this._model.title && this.variant !== 'card' ? b `<div class=\"title\">${this._model.title}</div>` : A} ${this._model.dataSource?.mode === 'db' && !this._model.columns.some(col => col.searchable) ? b `<div class=\"search\"></div>` : b ` <div class=\"search\"> <!-- TODO: Saved views dropdown <div class=\"views\"> <span>Default View</span> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z\"/></svg> </div> --> <div class=\"search-field\"> <svg class=\"search-icon\" viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z\"/></svg> <input type=\"text\" class=\"search-input\" placeholder=\"Search...\" .value=${this._searchQuery} @input=${this._handleSearch} /> </div> </div> `} <div class=\"tools\"> ${this._renderPagination()} <span class=\"refresh\" title=\"Refresh\" @click=${() => this.refresh()}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M480-160q-134 0-227-93t-93-227q0-134 93-227t227-93q69 0 132 28.5T720-690v-110h80v280H520v-80h168q-32-56-87.5-88T480-720q-100 0-170 70t-70 170q0 100 70 170t170 70q77 0 139-44t87-116h84q-28 106-114 173t-196 67Z\"/></svg> </span> <div class=\"column-picker-wrapper\"> <span class=\"header-icon\" title=\"Columns\" @click=${this._toggleColumnPicker}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M121-280v-400q0-33 23.5-56.5T201-760h559q33 0 56.5 23.5T840-680v400q0 33-23.5 56.5T760-200H201q-33 0-56.5-23.5T121-280Zm79 0h133v-400H200v400Zm213 0h133v-400H413v400Zm213 0h133v-400H626v400Z\"/></svg> </span> <div class=\"column-picker ${this._columnPickerOpen ? 'open' : ''}\"> ${[...this._model.columns].filter(col => col.type !== 'actions').sort((a, b) => (a.label ?? a.id).localeCompare(b.label ?? b.id)).map(col => b ` <div class=\"column-picker-item\" @click=${() => this._toggleColumn(col.id)}> <div class=\"column-picker-checkbox ${this._model.displayedColumns.includes(col.id) ? 'checked' : ''}\"> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/></svg> </div> <span class=\"column-picker-label\">${col.label ?? col.id}</span> </div> `)} </div> </div> ${this._model.actions?.length === 1 ? b ` <kr-button class=\"actions\" .href=${this._model.actions[0].href} .target=${this._model.actions[0].target} @click=${() => this._handleAction(this._model.actions[0])} > ${this._model.actions[0].label} </kr-button> ` : this._model.actions?.length ? b ` <kr-button class=\"actions\" .options=${this._model.actions.map(a => ({ id: a.id, label: a.label }))} @option-select=${(e) => this._handleAction({ id: e.detail.id, label: e.detail.label })} > Actions </kr-button> ` : A} </div> </div> `; } /** Renders status message (loading, error, empty) */ _renderStatus() { if (this._dataState === 'loading' && this._data.length === 0) { return b `<div class=\"status\">Loading...</div>`; } if (this._dataState === 'error' && this._data.length === 0) { return b `<div class=\"status status--error\">Error loading data</div>`; } if (this._data.length === 0) { return b `<div class=\"status\">No data available</div>`; } return A; } _renderFilterPanel() { if (!this._filterPanelOpened) { return A; } const column = this._model.columns.find(c => c.id === this._filterPanelOpened); // Build filter content (operator + value input) let valueInput = b ``; if (column.filter.operator === 'empty' || column.filter.operator === 'n_empty') { valueInput = b ` <input type=\"text\" class=\"filter-panel__input\" disabled .value=${column.filter.text} /> `; } else if (column.filter.operator === 'between' && column.type === 'date') { valueInput = b ` <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${column.filter.value?.start ?? null} @change=${(e) => this._handleFilterDateStartChange(e, column)} /> <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${column.filter.value?.end ?? null} @change=${(e) => this._handleFilterDateEndChange(e, column)} /> `; } else if (column.filter.operator === 'between' && column.type === 'number') { valueInput = b ` <input type=\"number\" class=\"filter-panel__input\" placeholder=\"Start\" .value=${column.filter.value?.start ?? ''} @input=${(e) => this._handleFilterNumberStartChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} /> <input type=\"number\" class=\"filter-panel__input\" placeholder=\"End\" .value=${column.filter.value?.end ?? ''} @input=${(e) => this._handleFilterNumberEndChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} /> `; } else if (column.filter.operator === 'in' || column.filter.operator === 'n_in') { valueInput = b ` <textarea class=\"filter-panel__textarea\" rows=\"3\" placeholder=\"Values (comma-separated)\" .value=${column.filter.text} @input=${(e) => this._handleFilterListChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} ></textarea> `; } else if (column.type === 'boolean') { valueInput = b ` <kr-select-field placeholder=\"Value\" .value=${String(column.filter.value ?? '')} @change=${(e) => this._handleFilterBooleanChange(e, column)} > <kr-select-option value=\"true\">Yes</kr-select-option> <kr-select-option value=\"false\">No</kr-select-option> </kr-select-field> `; } else if (column.type === 'date') { valueInput = b ` <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${column.filter.value} @change=${(e) => this._handleFilterDateChange(e, column)} /> `; } else if (column.type === 'number') { valueInput = b ` <input type=\"number\" class=\"filter-panel__input\" placeholder=\"Value\" min=\"0\" .value=${column.filter.text} @input=${(e) => this._handleFilterNumberChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} /> `; } else { valueInput = b ` <input type=\"text\" class=\"filter-panel__input\" placeholder=\"Value\" .value=${column.filter.text} @input=${(e) => this._handleFilterStringChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} /> `; } const filterContent = b ` <div class=\"filter-panel__content\"> <kr-select-field .value=${column.filter.operator} @change=${(e) => this._handleOperatorChange(e, column)} > ${getOperatorsForType(column.type).map(op => b ` <kr-select-option value=${op.key}>${op.label}</kr-select-option> `)} </kr-select-field> ${valueInput} </div> `; // Build bucket list content const buckets = this._buckets.get(column.id) || []; let bucketContent; if (!buckets.length) { bucketContent = b `<div class=\"bucket-empty\">No data</div>`; } else { bucketContent = b ` <div class=\"buckets\"> ${buckets.map(bucket => { let bucketLabel = '(Empty)'; if (bucket.val !== null && bucket.val !== undefined) { if (column.type === 'boolean') { if (bucket.val === true || bucket.val === 'true') { bucketLabel = 'Yes'; } else { bucketLabel = 'No'; } } else { bucketLabel = String(bucket.val); } } // When using n_in, the user sees all buckets checked by default and unchecks // the ones they want to hide. Under the hood, has() returns true for values // in the exclusion list, so we invert the check state for n_in. let checked = column.filter.has(bucket.val); if (column.filter.operator === 'n_in') { checked = !checked; } let checkIcon = A; if (checked) { checkIcon = b ` <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/> </svg> `; } return b ` <div class=\"bucket\" @click=${(e) => this._handleBucketToggle(e, column, bucket)} > <div class=${e$1({ 'bucket__checkbox': true, 'bucket__checkbox--checked': checked })}> ${checkIcon} </div> <span class=\"bucket__label\">${bucketLabel}</span> <span class=\"bucket__count\">${bucket.count}</span> </div> `; })} </div> `; } // Build panel body — tabs if both filterable+facetable, otherwise just the relevant content let panelBody; if (column.facetable && column.filterable) { panelBody = b ` <kr-tab-group size=\"small\" active-tab-id=${this._filterPanelTab} @tab-change=${(e) => this._handleFilterPanelTabChange(e)} > <kr-tab id=\"filter\" label=\"Filter\"> ${filterContent} </kr-tab> <kr-tab id=\"counts\" label=\"Counts\"> ${bucketContent} </kr-tab> </kr-tab-group> `; } else if (column.facetable) { panelBody = bucketContent; } else { panelBody = filterContent; } return b ` <div class=\"filter-panel\" style=${o$1({ top: this._filterPanelPos.top + 'px', left: this._filterPanelPos.left + 'px' })} > ${panelBody} <div class=\"filter-panel__actions\"> <kr-button variant=\"outline\" color=\"secondary\" size=\"small\" @click=${this._handleFilterClear}> Clear </kr-button> <kr-button size=\"small\" @click=${this._handleFilterApply}> Apply </kr-button> </div> </div> `; } /** * Renders filter row below column headers. * Only displays for columns with filterable: true. */ _renderFilterRow() { const columns = this.getDisplayedColumns(); if (!columns.some(col => col.filterable || col.facetable)) { return A; } return b ` <div class=\"filter-row\"> ${columns.map((col, i) => { if (!col.filterable && !col.facetable) { return b `<div class=${e$1({ 'filter-cell': true, 'filter-cell--sticky-left': col.sticky === 'left', 'filter-cell--sticky-right': col.sticky === 'right', 'filter-cell--sticky-right-first': col.sticky === 'right' && !columns.slice(0, i).some((c) => c.sticky === 'right') })} style=${o$1(this._getCellStyle(col, i))} ></div>`; } return b ` <div class=${e$1({ 'filter-cell': true, 'filter-cell--sticky-left': col.sticky === 'left', 'filter-cell--sticky-right': col.sticky === 'right', 'filter-cell--sticky-right-first': col.sticky === 'right' && !columns.slice(0, i).some((c) => c.sticky === 'right') })} style=${o$1(this._getCellStyle(col, i))} > <div class=\"filter-cell__wrapper\"> <input type=\"text\" class=${e$1({ 'filter-cell__input': true, 'filter-cell__input--invalid': !col.filter.isValid() })} .value=${col.filter.kql} @change=${(e) => this._handleKqlChange(e, col)} /> ${col.filter?.kql?.length > 0 ? b ` <button class=\"filter-cell__clear\" @click=${() => this._handleKqlClear(col)} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/> </svg> </button> ` : A} <button class=${e$1({ 'filter-cell__advanced': true, 'filter-cell__advanced--opened': this._filterPanelOpened === col.id })} @click=${(e) => this._handleFilterPanelToggle(e, col)} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z\"/> </svg> </button> </div> </div> `; })} </div> `; } /** Renders the scrollable data grid with column headers and rows. */ _renderTable() { return b ` <div class=\"wrapper\"> <div class=\"overlay-left\"></div> <div class=\"overlay-right\"></div> ${this._renderStatus()} <div class=\"content\" @scroll=${this._handleScroll}> <div class=\"table\" style=\"grid-template-columns: ${this._getGridTemplateColumns()}\"> <div class=\"header-row\"> ${this.getDisplayedColumns().map((col, i) => b ` <div class=${e$1(this._getHeaderCellClasses(col, i))} style=${o$1(this._getCellStyle(col, i))} data-column-id=${col.id} > <span class=\"header-cell__label\">${col.label ?? col.id}</span> ${this._renderSortIndicator(col)} ${col.resizable !== false ? b `<div class=\"header-cell__resize\" @mousedown=${(e) => this._handleResizeStart(e, col.id)} ></div>` : A} </div> `)} </div> ${this._renderFilterRow()} ${this._data.map((row, rowIndex) => { const cells = this.getDisplayedColumns().map((col, i) => b ` <div class=${e$1(this._getCellClasses(col, i))} style=${o$1(this._getCellStyle(col, i))} data-column-id=${col.id} > ${this._renderCellContent(col, row, rowIndex)} </div> `); if (this._model.rowHref) { return b ` <a href=${this._model.rowHref(row)} draggable=\"false\" class=${e$1({ 'row': true, 'row--clickable': true, 'row--link': true })} @mousedown=${() => this._handleRowMouseDown()} @click=${(e) => this._handleRowClick(e, row, rowIndex)} >${cells}</a> `; } return b ` <div class=${e$1({ 'row': true, 'row--clickable': !!this._model.rowClickable })} @mousedown=${() => this._handleRowMouseDown()} @click=${(e) => this._handleRowClick(e, row, rowIndex)} >${cells}</div> `; })} </div> </div> </div> `; } /** * Renders a data table with: * - Header bar with title, search input with view selector, and tools (pagination, refresh, column visibility, actions dropdown) * - Scrollable grid with sticky header row and optional sticky left/right columns * - Loading, error message, or empty state when no data */ render() { if (!this._model.columns.length) { return b `<slot></slot>`; } return b ` ${this._renderCardHeader()} ${this._renderHeader()} ${this._renderTable()} ${this._renderFilterPanel()} `; } }"
|
|
607
615
|
},
|
|
616
|
+
{
|
|
617
|
+
"kind": "variable",
|
|
618
|
+
"name": "KRGrid",
|
|
619
|
+
"default": "class KRGrid extends i$2 { constructor() { super(...arguments); /** * Internal flag to switch between scroll edge modes: * - 'overlay': Fixed padding with overlay elements that hide content at edges (scrollbar at viewport edge) * - 'edge': Padding scrolls with content, allowing table to reach edges when scrolling */ this._scrollStyle = 'edge'; this._data = []; this._dataState = 'idle'; this._page = 1; this._pageSize = 50; this._totalItems = 0; this._totalPages = 0; this._searchQuery = ''; this._canScrollLeft = false; this._canScrollRight = false; this._canScrollHorizontal = false; this._columnPickerOpen = false; this._filterPanelOpened = null; this._filterPanelTab = 'filter'; this._buckets = new Map(); this._filterPanelPos = { top: 0, left: 0 }; this._sorts = []; this._resizing = null; this._resizeObserver = null; this._searchPositionLocked = false; this._columnWidthsLocked = false; this._model = new KRGridModel(); this.def = { columns: [] }; /** * Table layout variant. * - 'default': Full-page table that fills parent height with centered search. * - 'card': Embedded table that sizes itself to content, left-aligns search, and * reserves space for pageSize rows to prevent layout shift. */ this.variant = 'default'; this._handleClickOutside = (e) => { const path = e.composedPath(); if (this._columnPickerOpen) { const picker = this.shadowRoot?.querySelector('.column-picker-wrapper'); if (picker && !path.includes(picker)) { this._columnPickerOpen = false; } } if (this._filterPanelOpened) { if (!path.some((el) => el.classList?.contains('filter-panel'))) { this._handleFilterApply(); } } }; this._handleResizeMove = (e) => { if (!this._resizing) return; const col = this._model.columns.find(c => c.id === this._resizing.columnId); if (col) { const newWidth = this._resizing.startWidth + (e.clientX - this._resizing.startX); col.width = `${Math.min(900, Math.max(50, newWidth))}px`; this.requestUpdate(); } }; this._handleResizeEnd = () => { this._resizing = null; document.removeEventListener('mousemove', this._handleResizeMove); document.removeEventListener('mouseup', this._handleResizeEnd); }; } connectedCallback() { super.connectedCallback(); this.classList.toggle('kr-table--scroll-overlay', this._scrollStyle === 'overlay'); this.classList.toggle('kr-table--scroll-edge', this._scrollStyle === 'edge'); this._fetch(); this._initRefresh(); document.addEventListener('click', this._handleClickOutside); this._resizeObserver = new ResizeObserver(() => { // Unlock and recalculate on resize since layout changes this._searchPositionLocked = false; this._updateSearchPosition(); }); this._resizeObserver.observe(this); } disconnectedCallback() { super.disconnectedCallback(); clearInterval(this._refreshTimer); document.removeEventListener('click', this._handleClickOutside); this._resizeObserver?.disconnect(); } willUpdate(changedProperties) { if (changedProperties.has('def')) { // Build internal model from user-provided def this._columnWidthsLocked = false; this._model = new KRGridModel(); if (this.def.title) { this._model.title = this.def.title; } if (this.def.description) { this._model.description = this.def.description; } if (this.def.actions) { this._model.actions = this.def.actions; } if (this.def.data) { this._model.data = this.def.data; } if (this.def.dataSource) { this._model.dataSource = this.def.dataSource; } if (typeof this.def.refreshInterval === 'number') { this._model.refreshInterval = this.def.refreshInterval; } if (typeof this.def.pageSize === 'number') { this._model.pageSize = this.def.pageSize; this._pageSize = this.def.pageSize; } if (this.def.rowClickable) { this._model.rowClickable = this.def.rowClickable; } if (this.def.rowHref) { this._model.rowHref = this.def.rowHref; } this._sorts = []; this._model.columns = this.def.columns.map(col => { const column = { ...col, filter: null }; if (!column.type) { column.type = 'string'; } if (col.sort) { this._sorts.push({ sortBy: col.id, sortDirection: col.sort }); } if (column.type === 'actions') { column.label = col.label ?? ''; column.sticky = 'right'; column.resizable = false; return column; } if (col.filterable || col.facetable) { column.filter = new KRQuery(); column.filter.field = col.id; column.filter.type = column.type; if (col.filter) { column.filter.setOperator(col.filter.operator); column.filter.setValue(col.filter.value); } else if (col.facetable && !col.filterable) { column.filter.operator = 'in'; column.filter.value = []; } else if (column.filter.type === 'string') { column.filter.operator = 'contains'; } } return column; }); if (this.def.displayedColumns) { this._model.displayedColumns = this.def.displayedColumns; } else { this._model.displayedColumns = this._model.columns.map(c => c.id); } this._fetch(); this._initRefresh(); } } updated(changedProperties) { this.classList.toggle('kr-table--card', this.variant === 'card'); this._updateScrollFlags(); this._syncSlottedContent(); this._lockColumnWidths(); } /** Measures header cell widths and locks them to prevent column shift on subsequent data changes. */ _lockColumnWidths() { if (this._columnWidthsLocked || this._data.length === 0) return; const headerCells = this.shadowRoot?.querySelectorAll('.header-row > .header-cell'); if (!headerCells) return; const cols = this.getDisplayedColumns(); headerCells.forEach((cell, i) => { const cellWidth = cell.offsetWidth; if (i < cols.length && !cols[i].width && cols[i].type !== 'actions' && cellWidth > 0) { cols[i].width = `${cellWidth}px`; this._columnWidthsLocked = true; } }); } /** Syncs light DOM content for cells with custom render functions */ _syncSlottedContent() { const columns = this.getDisplayedColumns().filter(col => col.render); if (!columns.length) return; // Clear old slotted content this.querySelectorAll('[slot^=\"cell-\"]').forEach(el => el.remove()); // Create new slotted content this._data.forEach((row, rowIndex) => { columns.forEach(col => { const result = col.render(row); if (!result) return; const el = document.createElement('span'); el.slot = `cell-${rowIndex}-${col.id}`; if (col.type === 'actions') { el.style.display = 'flex'; el.style.gap = '8px'; } if (typeof result === 'string') { el.innerHTML = result; } else { D(result, el); } this.appendChild(el); }); }); } // ---------------------------------------------------------------------------- // Public Interface // ---------------------------------------------------------------------------- refresh() { this._fetch(); } goToPrevPage() { if (this._page > 1) { this._page--; this._fetch(); } } goToNextPage() { if (this._page < this._totalPages) { this._page++; this._fetch(); } } goToPage(page) { if (page >= 1 && page <= this._totalPages) { this._page = page; this._fetch(); } } // ---------------------------------------------------------------------------- // Data Fetching // ---------------------------------------------------------------------------- _toSolrData() { const request = { page: this._page - 1, size: this._pageSize, sorts: this._sorts, filterFields: [], queryFields: [], facetFields: [] }; for (const col of this._model.columns) { if (!col.filter || col.filter.isEmpty() || !col.filter.isValid()) { continue; } const filterData = col.filter.toSolrData(); if (col.facetable && (col.filter.operator === 'in' || col.filter.operator === 'n_in')) { filterData.tagged = true; } request.filterFields.push(filterData); } for (const col of this._model.columns) { if (!col.facetable) { continue; } request.facetFields.push({ name: col.id, type: 'FIELD', limit: 100, sort: 'count', minimumCount: 1 }); } if (this._searchQuery?.trim().length) { request.queryFields.push({ name: '_text_', operation: 'IS', value: termify(this._searchQuery, false) }); } return request; } _toDbParams() { const request = { page: this._page - 1, size: this._pageSize, sorts: this._sorts, filterFields: [], queryFields: [], facetFields: [] }; for (const col of this._model.columns) { if (!col.filter || col.filter.isEmpty() || !col.filter.isValid()) { continue; } request.filterFields.push(col.filter.toDbParams()); } if (this._searchQuery?.trim().length) { this._model.columns.filter(col => col.searchable).forEach(col => { request.queryFields.push({ name: col.id, operation: 'CONTAINS', value: this._searchQuery, and: false }); }); } return request; } /** * Fetches data from the API and updates the table. * Shows a loading spinner while fetching, then displays rows on success * or an error snackbar on failure. * Request/response format depends on dataSource.mode (solr, opensearch, db). */ _fetch() { if (this._model.data) { this._data = this._model.data; this._totalItems = this._model.data.length; this._totalPages = Math.ceil(this._model.data.length / this._pageSize); this._dataState = 'success'; return; } if (!this._model.dataSource) return; this._dataState = 'loading'; let request; if (this._model.dataSource.mode === 'db') { request = this._toDbParams(); } else { request = this._toSolrData(); } this._model.dataSource.fetch(request) .then(response => { // Parse response based on mode switch (this._model.dataSource?.mode) { case 'opensearch': { throw Error('Opensearch not supported yet'); } case 'db': { const res = response; this._data = res.data.content; this._totalItems = res.data.totalElements; this._totalPages = res.data.totalPages; this._pageSize = res.data.size; break; } default: { // solr const res = response; this._data = res.data.content; this._totalItems = res.data.totalElements; this._totalPages = res.data.totalPages; this._pageSize = res.data.size; this._parseFacetResults(res); } } this._dataState = 'success'; this._updateSearchPosition(); }) .catch(err => { this._dataState = 'error'; KRSnackbar.show({ message: err instanceof Error ? err.message : 'Failed to load data', type: 'error' }); }); } _parseFacetResults(response) { if (!response.data.facetFields) { return; } for (const col of this._model.columns) { if (!col.facetable) { continue; } const rawBuckets = response.data.facetFields[col.id]; if (!rawBuckets) { this._buckets.set(col.id, []); continue; } const buckets = []; for (const raw of rawBuckets) { // Solr returns boolean facet values as strings — coerce to actual booleans // so they match the filter values stored by toggle(). let val = raw.name; if (col.type === 'boolean' && typeof raw.name === 'string') { if (raw.name === 'true') { val = true; } else if (raw.name === 'false') { val = false; } } if (raw.name === null && raw.count > 0) { buckets.unshift({ val: null, count: raw.count }); } if (raw.name !== null) { buckets.push({ val: val, count: raw.count }); } } // Bucket sync: ensure selected values appear even with 0 results if (col.filter && (col.filter.operator === 'in' || col.filter.operator === 'n_in') && Array.isArray(col.filter.value)) { for (const selectedVal of col.filter.value) { if (!buckets.some(b => b.val === selectedVal)) { buckets.push({ val: selectedVal, count: 0 }); } } } this._buckets.set(col.id, buckets); } // Trigger re-render since Map mutation doesn't trigger Lit updates this._buckets = new Map(this._buckets); } /** * Sets up auto-refresh so the table automatically fetches fresh data * at a regular interval (useful for dashboards, monitoring views). * Configured via def.refreshInterval in milliseconds. */ _initRefresh() { clearInterval(this._refreshTimer); if (this._model.refreshInterval && this._model.refreshInterval > 0) { this._refreshTimer = window.setInterval(() => { this._fetch(); }, this._model.refreshInterval); } } _handleSearch(e) { const input = e.target; this._searchQuery = input.value; this._page = 1; this._fetch(); } _getGridTemplateColumns() { const cols = this.getDisplayedColumns(); return cols.map((col) => { // If column has explicit width, use it if (col.width) { return col.width; } // Actions columns: fit content without minimum if (col.type === 'actions') { return 'max-content'; } // No width specified - use content-based sizing with minimum return 'minmax(80px, auto)'; }).join(' '); } /** * Updates search position to be centered with equal gaps from title and tools. * On first call: resets to flex centering, measures position, then locks with fixed margin. * Subsequent calls are ignored unless _searchPositionLocked is reset (e.g., on resize). */ _updateSearchPosition() { // Skip if already locked (prevents shifts on pagination changes) if (this._searchPositionLocked) return; // In card mode, search is left-aligned via CSS — no position locking needed if (this.variant === 'card') return; const search = this.shadowRoot?.querySelector('.search'); const searchField = search?.querySelector('.search-field'); if (!search || !searchField) return; // Reset to flex centering search.style.justifyContent = 'center'; searchField.style.marginLeft = ''; requestAnimationFrame(() => { const searchRect = search.getBoundingClientRect(); const fieldRect = searchField.getBoundingClientRect(); // Calculate how far from the left of search container the field currently is const currentOffset = fieldRect.left - searchRect.left; // Lock position: switch to flex-start and use fixed margin search.style.justifyContent = 'flex-start'; searchField.style.marginLeft = `${currentOffset}px`; // Mark as locked so pagination changes don't shift the search this._searchPositionLocked = true; }); } // ---------------------------------------------------------------------------- // Columns // ---------------------------------------------------------------------------- _toggleColumnPicker() { this._columnPickerOpen = !this._columnPickerOpen; } _toggleColumn(columnId) { if (this._model.displayedColumns.includes(columnId)) { this._model.displayedColumns = this._model.displayedColumns.filter(id => id !== columnId); } else { this._model.displayedColumns = [...this._model.displayedColumns, columnId]; } this.requestUpdate(); } // Clear any existing text selection on mousedown so we only detect // selections made during this click gesture, not stale selections from elsewhere _handleRowMouseDown() { if (!this._model.rowClickable && !this._model.rowHref) { return; } window.getSelection()?.removeAllRanges(); } _handleRowClick(e, row, rowIndex) { if (!this._model.rowClickable && !this._model.rowHref) { return; } const selection = window.getSelection(); if (selection && selection.toString().length > 0) { e.preventDefault(); return; } this.dispatchEvent(new CustomEvent('row-click', { detail: { row, rowIndex }, bubbles: true, composed: true })); } // When a user toggles a column on via the column picker, it gets appended // to _displayedColumns. By mapping over _displayedColumns (not def.columns), // the new column appears at the right edge of the table instead of jumping // back to its original position in the column definition. // Actions columns are always moved to the end. getDisplayedColumns() { return this._model.displayedColumns .map(id => this._model.columns.find(col => col.id === id)) .sort((a, b) => { if (a.type === 'actions' && b.type !== 'actions') return 1; if (a.type !== 'actions' && b.type === 'actions') return -1; return 0; }); } // ---------------------------------------------------------------------------- // Scrolling // ---------------------------------------------------------------------------- /** * Scroll event handler that updates scroll flags in real-time as user scrolls. * Updates shadow indicators to show if more content exists left/right. */ _handleScroll(e) { const container = e.target; this._canScrollLeft = container.scrollLeft > 0; this._canScrollRight = container.scrollLeft < container.scrollWidth - container.clientWidth - 1; } /** * Updates scroll state flags for the table content container. * - _canScrollLeft: true if scrolled right (can scroll back left) * - _canScrollRight: true if more content exists to the right * - _canScrollHorizontal: true if content is wider than container * These flags control scroll shadow indicators and CSS classes. */ _updateScrollFlags() { const container = this.shadowRoot?.querySelector('.content'); if (container) { this._canScrollLeft = container.scrollLeft > 0; this._canScrollRight = container.scrollWidth > container.clientWidth && container.scrollLeft < container.scrollWidth - container.clientWidth - 1; this._canScrollHorizontal = container.scrollWidth > container.clientWidth; } this.classList.toggle('kr-table--scroll-left-available', this._canScrollLeft); this.classList.toggle('kr-table--scroll-right-available', this._canScrollRight); this.classList.toggle('kr-table--scroll-horizontal-available', this._canScrollHorizontal); this.classList.toggle('kr-table--sticky-left', this.getDisplayedColumns().some(c => c.sticky === 'left')); this.classList.toggle('kr-table--sticky-right', this.getDisplayedColumns().some(c => c.sticky === 'right')); } // ---------------------------------------------------------------------------- // Column Resizing // ---------------------------------------------------------------------------- _handleResizeStart(e, columnId) { e.preventDefault(); const headerCell = this.shadowRoot?.querySelector(`.header-cell[data-column-id=\"${columnId}\"]`); this._resizing = { columnId, startX: e.clientX, startWidth: headerCell?.offsetWidth || 200 }; document.addEventListener('mousemove', this._handleResizeMove); document.addEventListener('mouseup', this._handleResizeEnd); } // ---------------------------------------------------------------------------- // Sorting // ---------------------------------------------------------------------------- _handleSortClick(e, column) { if (e.shiftKey) { // Multi-sort: add or cycle existing const existingIndex = this._sorts.findIndex(s => s.sortBy === column.id); if (existingIndex === -1) { this._sorts.push({ sortBy: column.id, sortDirection: 'asc' }); } else { const existing = this._sorts[existingIndex]; if (existing.sortDirection === 'asc') { existing.sortDirection = 'desc'; } else { // on third click, remove sorting for the column this._sorts.splice(existingIndex, 1); } } this.requestUpdate(); } else { // Single sort: replace all let existing = null; if (this._sorts.length === 1) { existing = this._sorts.find(s => s.sortBy === column.id); } if (!existing) { this._sorts = [{ sortBy: column.id, sortDirection: 'asc' }]; } else if (existing.sortDirection === 'asc') { this._sorts = [{ sortBy: column.id, sortDirection: 'desc' }]; } else { this._sorts = []; } } this._page = 1; this._fetch(); } _renderSortIndicator(column) { if (!column.sortable) { return A; } const sortIndex = this._sorts.findIndex(s => s.sortBy === column.id); if (sortIndex === -1) { // Ghost arrow: visible only on hover via CSS return b ` <span class=\"header-cell__sort\" @click=${(e) => this._handleSortClick(e, column)}> <svg class=\"header-cell__sort-arrow header-cell__sort-arrow--ghost\" viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z\"/> </svg> </span> `; } let arrowStyle = {}; if (this._sorts[sortIndex].sortDirection === 'desc') { arrowStyle = { transform: 'rotate(180deg)' }; } return b ` <span class=\"header-cell__sort\" @click=${(e) => this._handleSortClick(e, column)}> <svg class=\"header-cell__sort-arrow\" viewBox=\"0 0 24 24\" fill=\"currentColor\" style=${o$1(arrowStyle)}> <path d=\"M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z\"/> </svg> ${this._sorts.length > 1 ? b ` <span class=\"header-cell__sort-priority\">${sortIndex + 1}</span> ` : A} </span> `; } // ---------------------------------------------------------------------------- // Header // ---------------------------------------------------------------------------- _handleAction(action) { if (action.href) { return; } this.dispatchEvent(new CustomEvent('action', { detail: { action: action.id }, bubbles: true, composed: true })); } // ---------------------------------------------------------------------------- // Filter Handlers // ---------------------------------------------------------------------------- _handleKqlChange(e, column) { const kql = e.target.value.trim(); if (!kql) { column.filter.clear(); this.requestUpdate(); } else { column.filter.setKql(kql); this.requestUpdate(); if (!column.filter.isValid()) { return; } } this._page = 1; this._fetch(); } _handleFilterPanelToggle(e, column) { e.stopPropagation(); if (this._filterPanelOpened === column.id) { this._filterPanelOpened = null; } else { const rect = e.currentTarget.getBoundingClientRect(); let left = rect.left; if (left + 328 > window.innerWidth) { left = window.innerWidth - 328; } this._filterPanelPos = { top: rect.bottom + 4, left }; this._filterPanelOpened = column.id; if (column.facetable) { this._filterPanelTab = 'counts'; } else { this._filterPanelTab = 'filter'; } } } _handleKqlClear(column) { column.filter.clear(); this._page = 1; this._fetch(); } _handleFilterClear() { const column = this._model.columns.find(c => c.id === this._filterPanelOpened); if (column) { column.filter.clear(); if (column.facetable && !column.filterable) { column.filter.operator = 'in'; column.filter.value = []; } } this._filterPanelOpened = null; this._page = 1; this._fetch(); } _handleFilterTextKeydown(e, column) { if (e.key === 'Enter') { e.preventDefault(); this._handleFilterApply(); } } _handleOperatorChange(e, column) { column.filter.setOperator(e.target.value); this.requestUpdate(); } _handleFilterStringChange(e, column) { column.filter.setValue(e.target.value); this.requestUpdate(); } _handleFilterNumberChange(e, column) { column.filter.setValue(Number(e.target.value)); this.requestUpdate(); } _handleFilterDateChange(e, column) { column.filter.setValue(new Date(e.target.value), 'day'); this.requestUpdate(); } _handleFilterBooleanChange(e, column) { column.filter.setValue(e.target.value === 'true'); this.requestUpdate(); } _handleFilterDateStartChange(e, column) { column.filter.setStart(new Date(e.target.value), 'day'); this.requestUpdate(); } _handleFilterDateEndChange(e, column) { column.filter.setEnd(new Date(e.target.value), 'day'); this.requestUpdate(); } _handleFilterNumberStartChange(e, column) { column.filter.setStart(Number(e.target.value)); this.requestUpdate(); } _handleFilterNumberEndChange(e, column) { column.filter.setEnd(Number(e.target.value)); this.requestUpdate(); } _handleFilterListChange(e, column) { const items = e.target.value.split(',').map((v) => v.trim()).filter((v) => v !== ''); if (column.type === 'number') { column.filter.setValue(items.map((v) => Number(v))); } else { column.filter.setValue(items); } this.requestUpdate(); } _handleFilterApply() { this._filterPanelOpened = null; this._page = 1; this._fetch(); } _handleFilterPanelTabChange(e) { this._filterPanelTab = e.detail.activeTabId; } _handleBucketToggle(e, column, bucket) { column.filter.toggle(bucket.val); this._page = 1; this._fetch(); } // ---------------------------------------------------------------------------- // Rendering // ---------------------------------------------------------------------------- _renderCellContent(column, row, rowIndex) { const value = row[column.id]; if (column.render) { // Use slot to project content from light DOM so external styles apply return b `<slot name=\"cell-${rowIndex}-${column.id}\"></slot>`; } if (value === null || value === undefined) { return ''; } switch (column.type) { case 'number': if (column.format === 'currency' && typeof value === 'number') { return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' }); } return String(value); case 'date': { let date; if (value instanceof Date) { date = value; } else if (typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}/.test(value)) { // MySQL datetime format (UTC): \"2026-01-28 01:33:44:517\" // Replace last colon before ms with dot, append Z for UTC const isoString = value.replace(/(\\d{2}:\\d{2}:\\d{2}):(\\d+)$/, '$1.$2').replace(' ', 'T') + 'Z'; date = new Date(isoString); } else { date = new Date(value); } // Show date and time for datetime values in UTC return date.toLocaleString(undefined, { year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit', timeZone: 'UTC' }); } case 'boolean': if (value === true) return 'Yes'; if (value === false) return 'No'; return ''; default: return String(value); } } /** * Returns CSS classes for a header cell based on column config. */ _getHeaderCellClasses(column, index) { return { 'header-cell': true, 'header-cell--sortable': !!column.sortable, 'header-cell--align-center': column.align === 'center', 'header-cell--align-right': column.align === 'right', 'header-cell--sticky-left': column.sticky === 'left', 'header-cell--sticky-left-last': column.sticky === 'left' && !this.getDisplayedColumns().slice(index + 1).some(c => c.sticky === 'left'), 'header-cell--sticky-right': column.sticky === 'right', 'header-cell--sticky-right-first': column.sticky === 'right' && !this.getDisplayedColumns().slice(0, index).some(c => c.sticky === 'right') }; } /** * Returns CSS classes for a table cell based on column config: * - Alignment (center, right) * - Sticky positioning (left, right) * - Border classes for the last left-sticky or first right-sticky column */ _getCellClasses(column, index) { return { 'cell': true, 'cell--actions': column.type === 'actions', 'cell--align-center': column.align === 'center', 'cell--align-right': column.align === 'right', 'cell--sticky-left': column.sticky === 'left', 'cell--sticky-left-last': column.sticky === 'left' && !this.getDisplayedColumns().slice(index + 1).some(c => c.sticky === 'left'), 'cell--sticky-right': column.sticky === 'right', 'cell--sticky-right-first': column.sticky === 'right' && !this.getDisplayedColumns().slice(0, index).some(c => c.sticky === 'right') }; } /** * Returns inline styles for a table cell: * - Width (from column config or default 150px) * - Min-width (if specified) * - Left/right offset for sticky columns (calculated from widths of preceding sticky columns) */ _getCellStyle(column, index) { const styles = {}; if (column.sticky === 'left') { let leftOffset = 0; for (let i = 0; i < index; i++) { const col = this.getDisplayedColumns()[i]; if (col.sticky === 'left') { leftOffset += parseInt(col.width || '0', 10); } } styles.left = `${leftOffset}px`; } if (column.sticky === 'right') { let rightOffset = 0; for (let i = index + 1; i < this.getDisplayedColumns().length; i++) { const col = this.getDisplayedColumns()[i]; if (col.sticky === 'right') { rightOffset += parseInt(col.width || '0', 10); } } styles.right = `${rightOffset}px`; } return styles; } /** * Renders the pagination controls: * - Previous page arrow (disabled on first page) * - Range text showing \"1-50 of 150\" format * - Next page arrow (disabled on last page) * * Hidden when there's no data or all data fits on one page. */ _renderPagination() { const start = (this._page - 1) * this._pageSize + 1; const end = Math.min(this._page * this._pageSize, this._totalItems); return b ` <div class=\"pagination\"> <span class=\"pagination-icon ${this._page === 1 ? 'pagination-icon--disabled' : ''}\" @click=${this.goToPrevPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z\"/></svg> </span> <span class=\"pagination-info\">${start}-${end} of ${this._totalItems}</span> <span class=\"pagination-icon ${this._page === this._totalPages ? 'pagination-icon--disabled' : ''}\" @click=${this.goToNextPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z\"/></svg> </span> </div> `; } /** Renders the card title block (title + description) above the toolbar in card mode. */ _renderCardHeader() { if (this.variant !== 'card') return A; if (!this._model.title && !this._model.description) return A; return b ` <div class=\"card-header\"> ${this._model.title ? b `<h2 class=\"card-header__title\">${this._model.title}</h2>` : A} ${this._model.description ? b `<p class=\"card-header__description\">${this._model.description}</p>` : A} </div> `; } /** * Renders the header toolbar containing: * - Title (left, default variant only) * - Search bar with view selector dropdown (center, or left-aligned in card variant) * - Tools (right): page navigation, refresh button, column visibility picker, actions dropdown * * Hidden when there's no title, no actions, and data fits on one page. */ _renderHeader() { if (!this._model.title && !this._model.actions?.length && this._totalPages <= 1) { return A; } return b ` <div class=\"header\"> ${this._model.title && this.variant !== 'card' ? b `<div class=\"title\">${this._model.title}</div>` : A} ${this._model.dataSource?.mode === 'db' && !this._model.columns.some(col => col.searchable) ? b `<div class=\"search\"></div>` : b ` <div class=\"search\"> <!-- TODO: Saved views dropdown <div class=\"views\"> <span>Default View</span> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z\"/></svg> </div> --> <div class=\"search-field\"> <svg class=\"search-icon\" viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z\"/></svg> <input type=\"text\" class=\"search-input\" placeholder=\"Search...\" .value=${this._searchQuery} @input=${this._handleSearch} /> </div> </div> `} <div class=\"tools\"> ${this._renderPagination()} <span class=\"refresh\" title=\"Refresh\" @click=${() => this.refresh()}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M480-160q-134 0-227-93t-93-227q0-134 93-227t227-93q69 0 132 28.5T720-690v-110h80v280H520v-80h168q-32-56-87.5-88T480-720q-100 0-170 70t-70 170q0 100 70 170t170 70q77 0 139-44t87-116h84q-28 106-114 173t-196 67Z\"/></svg> </span> <div class=\"column-picker-wrapper\"> <span class=\"header-icon\" title=\"Columns\" @click=${this._toggleColumnPicker}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M121-280v-400q0-33 23.5-56.5T201-760h559q33 0 56.5 23.5T840-680v400q0 33-23.5 56.5T760-200H201q-33 0-56.5-23.5T121-280Zm79 0h133v-400H200v400Zm213 0h133v-400H413v400Zm213 0h133v-400H626v400Z\"/></svg> </span> <div class=\"column-picker ${this._columnPickerOpen ? 'open' : ''}\"> ${[...this._model.columns].filter(col => col.type !== 'actions').sort((a, b) => (a.label ?? a.id).localeCompare(b.label ?? b.id)).map(col => b ` <div class=\"column-picker-item\" @click=${() => this._toggleColumn(col.id)}> <div class=\"column-picker-checkbox ${this._model.displayedColumns.includes(col.id) ? 'checked' : ''}\"> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/></svg> </div> <span class=\"column-picker-label\">${col.label ?? col.id}</span> </div> `)} </div> </div> ${this._model.actions?.length === 1 ? b ` <kr-button class=\"actions\" .href=${this._model.actions[0].href} .target=${this._model.actions[0].target} @click=${() => this._handleAction(this._model.actions[0])} > ${this._model.actions[0].label} </kr-button> ` : this._model.actions?.length ? b ` <kr-button class=\"actions\" .options=${this._model.actions.map(a => ({ id: a.id, label: a.label }))} @option-select=${(e) => this._handleAction({ id: e.detail.id, label: e.detail.label })} > Actions </kr-button> ` : A} </div> </div> `; } /** Renders status message (loading, error, empty) */ _renderStatus() { if (this._dataState === 'loading' && this._data.length === 0) { return b `<div class=\"status\">Loading...</div>`; } if (this._dataState === 'error' && this._data.length === 0) { return b `<div class=\"status status--error\">Error loading data</div>`; } if (this._data.length === 0) { return b `<div class=\"status\">No data available</div>`; } return A; } _renderFilterPanel() { if (!this._filterPanelOpened) { return A; } const column = this._model.columns.find(c => c.id === this._filterPanelOpened); // Build filter content (operator + value input) let valueInput = b ``; if (column.filter.operator === 'empty' || column.filter.operator === 'n_empty') { valueInput = b ` <input type=\"text\" class=\"filter-panel__input\" disabled .value=${column.filter.text} /> `; } else if (column.filter.operator === 'between' && column.type === 'date') { valueInput = b ` <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${column.filter.value?.start ?? null} @change=${(e) => this._handleFilterDateStartChange(e, column)} /> <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${column.filter.value?.end ?? null} @change=${(e) => this._handleFilterDateEndChange(e, column)} /> `; } else if (column.filter.operator === 'between' && column.type === 'number') { valueInput = b ` <input type=\"number\" class=\"filter-panel__input\" placeholder=\"Start\" .value=${column.filter.value?.start ?? ''} @input=${(e) => this._handleFilterNumberStartChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} /> <input type=\"number\" class=\"filter-panel__input\" placeholder=\"End\" .value=${column.filter.value?.end ?? ''} @input=${(e) => this._handleFilterNumberEndChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} /> `; } else if (column.filter.operator === 'in' || column.filter.operator === 'n_in') { valueInput = b ` <textarea class=\"filter-panel__textarea\" rows=\"3\" placeholder=\"Values (comma-separated)\" .value=${column.filter.text} @input=${(e) => this._handleFilterListChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} ></textarea> `; } else if (column.type === 'boolean') { valueInput = b ` <kr-select-field placeholder=\"Value\" .value=${String(column.filter.value ?? '')} @change=${(e) => this._handleFilterBooleanChange(e, column)} > <kr-select-option value=\"true\">Yes</kr-select-option> <kr-select-option value=\"false\">No</kr-select-option> </kr-select-field> `; } else if (column.type === 'date') { valueInput = b ` <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${column.filter.value} @change=${(e) => this._handleFilterDateChange(e, column)} /> `; } else if (column.type === 'number') { valueInput = b ` <input type=\"number\" class=\"filter-panel__input\" placeholder=\"Value\" min=\"0\" .value=${column.filter.text} @input=${(e) => this._handleFilterNumberChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} /> `; } else { valueInput = b ` <input type=\"text\" class=\"filter-panel__input\" placeholder=\"Value\" .value=${column.filter.text} @input=${(e) => this._handleFilterStringChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} /> `; } const filterContent = b ` <div class=\"filter-panel__content\"> <kr-select-field .value=${column.filter.operator} @change=${(e) => this._handleOperatorChange(e, column)} > ${getOperatorsForType(column.type).map(op => b ` <kr-select-option value=${op.key}>${op.label}</kr-select-option> `)} </kr-select-field> ${valueInput} </div> `; // Build bucket list content const buckets = this._buckets.get(column.id) || []; let bucketContent; if (!buckets.length) { bucketContent = b `<div class=\"bucket-empty\">No data</div>`; } else { bucketContent = b ` <div class=\"buckets\"> ${buckets.map(bucket => { let bucketLabel = '(Empty)'; if (bucket.val !== null && bucket.val !== undefined) { if (column.type === 'boolean') { if (bucket.val === true || bucket.val === 'true') { bucketLabel = 'Yes'; } else { bucketLabel = 'No'; } } else { bucketLabel = String(bucket.val); } } // When using n_in, the user sees all buckets checked by default and unchecks // the ones they want to hide. Under the hood, has() returns true for values // in the exclusion list, so we invert the check state for n_in. let checked = column.filter.has(bucket.val); if (column.filter.operator === 'n_in') { checked = !checked; } let checkIcon = A; if (checked) { checkIcon = b ` <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/> </svg> `; } return b ` <div class=\"bucket\" @click=${(e) => this._handleBucketToggle(e, column, bucket)} > <div class=${e$1({ 'bucket__checkbox': true, 'bucket__checkbox--checked': checked })}> ${checkIcon} </div> <span class=\"bucket__label\">${bucketLabel}</span> <span class=\"bucket__count\">${bucket.count}</span> </div> `; })} </div> `; } // Build panel body — tabs if both filterable+facetable, otherwise just the relevant content let panelBody; if (column.facetable && column.filterable) { panelBody = b ` <kr-tab-group size=\"small\" active-tab-id=${this._filterPanelTab} @tab-change=${(e) => this._handleFilterPanelTabChange(e)} > <kr-tab id=\"filter\" label=\"Filter\"> ${filterContent} </kr-tab> <kr-tab id=\"counts\" label=\"Counts\"> ${bucketContent} </kr-tab> </kr-tab-group> `; } else if (column.facetable) { panelBody = bucketContent; } else { panelBody = filterContent; } return b ` <div class=\"filter-panel\" style=${o$1({ top: this._filterPanelPos.top + 'px', left: this._filterPanelPos.left + 'px' })} > ${panelBody} <div class=\"filter-panel__actions\"> <kr-button variant=\"outline\" color=\"secondary\" size=\"small\" @click=${this._handleFilterClear}> Clear </kr-button> <kr-button size=\"small\" @click=${this._handleFilterApply}> Apply </kr-button> </div> </div> `; } /** * Renders filter row below column headers. * Only displays for columns with filterable: true. */ _renderFilterRow() { const columns = this.getDisplayedColumns(); if (!columns.some(col => col.filterable || col.facetable)) { return A; } return b ` <div class=\"filter-row\"> ${columns.map((col, i) => { if (!col.filterable && !col.facetable) { return b `<div class=${e$1({ 'filter-cell': true, 'filter-cell--sticky-left': col.sticky === 'left', 'filter-cell--sticky-right': col.sticky === 'right', 'filter-cell--sticky-right-first': col.sticky === 'right' && !columns.slice(0, i).some((c) => c.sticky === 'right') })} style=${o$1(this._getCellStyle(col, i))} ></div>`; } return b ` <div class=${e$1({ 'filter-cell': true, 'filter-cell--sticky-left': col.sticky === 'left', 'filter-cell--sticky-right': col.sticky === 'right', 'filter-cell--sticky-right-first': col.sticky === 'right' && !columns.slice(0, i).some((c) => c.sticky === 'right') })} style=${o$1(this._getCellStyle(col, i))} > <div class=\"filter-cell__wrapper\"> <input type=\"text\" class=${e$1({ 'filter-cell__input': true, 'filter-cell__input--invalid': !col.filter.isValid() })} .value=${col.filter.kql} @change=${(e) => this._handleKqlChange(e, col)} /> ${col.filter?.kql?.length > 0 ? b ` <button class=\"filter-cell__clear\" @click=${() => this._handleKqlClear(col)} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/> </svg> </button> ` : A} <button class=${e$1({ 'filter-cell__advanced': true, 'filter-cell__advanced--opened': this._filterPanelOpened === col.id })} @click=${(e) => this._handleFilterPanelToggle(e, col)} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z\"/> </svg> </button> </div> </div> `; })} </div> `; } /** Renders the scrollable data grid with column headers and rows. */ _renderTable() { return b ` <div class=\"wrapper\"> <div class=\"overlay-left\"></div> <div class=\"overlay-right\"></div> ${this._renderStatus()} <div class=\"content\" @scroll=${this._handleScroll}> <div class=\"table\" style=\"grid-template-columns: ${this._getGridTemplateColumns()}\"> <div class=\"header-row\"> ${this.getDisplayedColumns().map((col, i) => b ` <div class=${e$1(this._getHeaderCellClasses(col, i))} style=${o$1(this._getCellStyle(col, i))} data-column-id=${col.id} > <span class=\"header-cell__label\">${col.label ?? col.id}</span> ${this._renderSortIndicator(col)} ${col.resizable !== false ? b `<div class=\"header-cell__resize\" @mousedown=${(e) => this._handleResizeStart(e, col.id)} ></div>` : A} </div> `)} </div> ${this._renderFilterRow()} ${this._data.map((row, rowIndex) => { const cells = this.getDisplayedColumns().map((col, i) => b ` <div class=${e$1(this._getCellClasses(col, i))} style=${o$1(this._getCellStyle(col, i))} data-column-id=${col.id} > ${this._renderCellContent(col, row, rowIndex)} </div> `); if (this._model.rowHref) { return b ` <a href=${this._model.rowHref(row)} draggable=\"false\" class=${e$1({ 'row': true, 'row--clickable': true, 'row--link': true })} @mousedown=${() => this._handleRowMouseDown()} @click=${(e) => this._handleRowClick(e, row, rowIndex)} >${cells}</a> `; } return b ` <div class=${e$1({ 'row': true, 'row--clickable': !!this._model.rowClickable })} @mousedown=${() => this._handleRowMouseDown()} @click=${(e) => this._handleRowClick(e, row, rowIndex)} >${cells}</div> `; })} </div> </div> </div> `; } /** * Renders a data table with: * - Header bar with title, search input with view selector, and tools (pagination, refresh, column visibility, actions dropdown) * - Scrollable grid with sticky header row and optional sticky left/right columns * - Loading, error message, or empty state when no data */ render() { if (!this._model.columns.length) { return b `<slot></slot>`; } return b ` ${this._renderCardHeader()} ${this._renderHeader()} ${this._renderTable()} ${this._renderFilterPanel()} `; } }"
|
|
620
|
+
},
|
|
608
621
|
{
|
|
609
622
|
"kind": "variable",
|
|
610
623
|
"name": "KRSpinner",
|
|
@@ -784,6 +797,14 @@
|
|
|
784
797
|
"module": "dist/krubble-components.bundled.js"
|
|
785
798
|
}
|
|
786
799
|
},
|
|
800
|
+
{
|
|
801
|
+
"kind": "js",
|
|
802
|
+
"name": "KRGrid",
|
|
803
|
+
"declaration": {
|
|
804
|
+
"name": "KRGrid",
|
|
805
|
+
"module": "dist/krubble-components.bundled.js"
|
|
806
|
+
}
|
|
807
|
+
},
|
|
787
808
|
{
|
|
788
809
|
"kind": "js",
|
|
789
810
|
"name": "KRProgressBar",
|
|
@@ -922,32 +943,32 @@
|
|
|
922
943
|
{
|
|
923
944
|
"kind": "variable",
|
|
924
945
|
"name": "ne",
|
|
925
|
-
"default": "
|
|
946
|
+
"default": "o` :host, *, *::before, *::after { box-sizing: border-box; } :host { /* Primary */ --kr-primary: rgb(22, 48, 82); --kr-primary-hover: rgb(16, 36, 62); --kr-primary-text: #ffffff; /* Accent */ --kr-accent: #BEEA4E; --kr-accent-hover: #a8d43a; --kr-accent-text: #000000; /* Text */ --kr-text: #000000; --kr-text-muted: #4b5563; --kr-text-disabled: #9ca3af; /* Borders */ --kr-border: #e5e7eb; } `"
|
|
926
947
|
},
|
|
927
948
|
{
|
|
928
949
|
"kind": "variable",
|
|
929
950
|
"name": "be",
|
|
930
|
-
"default": "class extends
|
|
951
|
+
"default": "class extends le{constructor(){super(...arguments),this.header=\"\",this.expanded=!1}toggle(){this.expanded=!this.expanded}render(){return j` <div class=\"header\" @click=${this.toggle}> <span class=\"header__title\">${this.header}</span> <svg class=\"header__icon\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <path d=\"M6 9l6 6 6-6\"/> </svg> </div> <div class=\"content\"> <div class=\"content__inner\"> <div class=\"content__body\"> <slot></slot> </div> </div> </div> `}}"
|
|
931
952
|
},
|
|
932
953
|
{
|
|
933
954
|
"kind": "variable",
|
|
934
955
|
"name": "Ce",
|
|
935
|
-
"default": "class extends
|
|
956
|
+
"default": "class extends le{constructor(){super(...arguments),this.type=\"info\",this.title=\"\",this.dismissible=!1,this.visible=!0}_handleDismiss(){this.visible=!1,this.dispatchEvent(new CustomEvent(\"dismiss\",{bubbles:!0,composed:!0}))}render(){const e={info:j`<svg class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7-4a1 1 0 11-2 0 1 1 0 012 0zM9 9a1 1 0 000 2v3a1 1 0 001 1h1a1 1 0 100-2v-3a1 1 0 00-1-1H9z\" clip-rule=\"evenodd\"/></svg>`,success:j`<svg class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zm3.707-9.293a1 1 0 00-1.414-1.414L9 10.586 7.707 9.293a1 1 0 00-1.414 1.414l2 2a1 1 0 001.414 0l4-4z\" clip-rule=\"evenodd\"/></svg>`,warning:j`<svg class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z\" clip-rule=\"evenodd\"/></svg>`,error:j`<svg class=\"icon\" viewBox=\"0 0 20 20\" fill=\"currentColor\"><path fill-rule=\"evenodd\" d=\"M10 18a8 8 0 100-16 8 8 0 000 16zM8.707 7.293a1 1 0 00-1.414 1.414L8.586 10l-1.293 1.293a1 1 0 101.414 1.414L10 11.414l1.293 1.293a1 1 0 001.414-1.414L11.414 10l1.293-1.293a1 1 0 00-1.414-1.414L10 8.586 8.707 7.293z\" clip-rule=\"evenodd\"/></svg>`};return j` <div class=${we({alert:!0,[\"alert--\"+this.type]:!0,\"alert--has-header\":!!this.title,\"alert--hidden\":!this.visible})} role=\"alert\" > ${e[this.type]} <div class=\"content\"> ${this.title?j`<h4 class=\"header\">${this.title}</h4>`:F} <div class=\"message\"> <slot></slot> </div> </div> ${this.dismissible?j` <button class=\"dismiss\" type=\"button\" aria-label=\"Dismiss alert\" @click=${this._handleDismiss} > <svg viewBox=\"0 0 20 20\" fill=\"currentColor\" width=\"16\" height=\"16\"> <path fill-rule=\"evenodd\" d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\" clip-rule=\"evenodd\"/> </svg> </button> `:F} </div> `}}"
|
|
936
957
|
},
|
|
937
958
|
{
|
|
938
959
|
"kind": "variable",
|
|
939
|
-
"name": "
|
|
940
|
-
"default": "class extends
|
|
960
|
+
"name": "ze",
|
|
961
|
+
"default": "class extends le{constructor(){super(...arguments),this.variant=\"flat\",this.color=\"primary\",this.size=\"medium\",this.disabled=!1,this.options=[],this.iconPosition=\"left\",this.split=!1,this._state=\"idle\",this._stateText=\"\",this._dropdownOpened=!1,this._handleHostClick=e=>{this.split&&this.options.length||this.options.length&&(e.stopPropagation(),this._toggleDropdown())},this._handleKeydown=e=>{if(\"Escape\"===e.key&&this._dropdownOpened)this._dropdownOpened=!1;else{if(\"Enter\"===e.key||\" \"===e.key){if(e.preventDefault(),this.split&&this.options.length)return void this.dispatchEvent(new MouseEvent(\"click\",{bubbles:!0,composed:!0}));this.options.length?this._toggleDropdown():this.click()}this.split&&this.options.length&&\"ArrowDown\"===e.key&&(e.preventDefault(),this._dropdownOpened||this._toggleDropdown())}},this._handleClickOutside=e=>{this._dropdownOpened&&!this.contains(e.target)&&(this._dropdownOpened=!1)}}connectedCallback(){super.connectedCallback(),this.setAttribute(\"role\",this.href?\"link\":\"button\"),this.setAttribute(\"tabindex\",\"0\"),this.addEventListener(\"keydown\",this._handleKeydown),this.addEventListener(\"click\",this._handleHostClick),document.addEventListener(\"click\",this._handleClickOutside)}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener(\"keydown\",this._handleKeydown),this.removeEventListener(\"click\",this._handleHostClick),document.removeEventListener(\"click\",this._handleClickOutside)}_handleSplitPrimaryClick(e){e.stopPropagation(),this._dropdownOpened&&(this._dropdownOpened=!1),this.dispatchEvent(new MouseEvent(\"click\",{bubbles:!0,composed:!0}))}_handleSplitTriggerClick(e){e.stopPropagation(),this._toggleDropdown()}_toggleDropdown(){this._dropdownOpened=!this._dropdownOpened,this._dropdownOpened&&requestAnimationFrame((()=>{const e=this.shadowRoot?.querySelector(\".dropdown\");if(e){const t=this.getBoundingClientRect();e.style.top=t.bottom+4+\"px\",e.style.bottom=\"\",e.style.left=t.left+\"px\",e.style.right=\"\",e.style.minWidth=t.width+\"px\",e.style.transformOrigin=\"top left\",e.style.maxHeight=\"\",e.style.overflowY=\"\";const i=e.getBoundingClientRect();i.height>window.innerHeight-t.bottom-8&&t.top>window.innerHeight-t.bottom?(e.style.top=\"\",e.style.bottom=window.innerHeight-t.top+4+\"px\",e.style.transformOrigin=\"bottom left\",e.classList.add(\"dropdown--above\"),i.height>t.top-8&&(e.style.maxHeight=t.top-8+\"px\",e.style.overflowY=\"auto\")):(e.classList.remove(\"dropdown--above\"),i.height>window.innerHeight-t.bottom-8&&(e.style.maxHeight=window.innerHeight-t.bottom-8+\"px\",e.style.overflowY=\"auto\")),i.right>window.innerWidth&&(e.style.left=\"\",e.style.right=window.innerWidth-t.right+\"px\",i.bottom>window.innerHeight?e.style.transformOrigin=\"bottom right\":e.style.transformOrigin=\"top right\")}}))}_handleOptionClick(e,t){t.stopPropagation(),this._dropdownOpened=!1,this.dispatchEvent(new CustomEvent(\"option-select\",{detail:{id:e.id,label:e.label},bubbles:!0,composed:!0}))}showLoading(){this._clearStateTimeout(),this._state=\"loading\",this._stateText=\"\"}showSuccess(e=\"Success\",t=2e3){this._clearStateTimeout(),this._state=\"success\",this._stateText=e,t>0&&(this._stateTimeout=window.setTimeout((()=>this.reset()),t))}showError(e=\"Error\",t=2e3){this._clearStateTimeout(),this._state=\"error\",this._stateText=e,t>0&&(this._stateTimeout=window.setTimeout((()=>this.reset()),t))}isLoading(){return\"loading\"===this._state}reset(){this._clearStateTimeout(),this._state=\"idle\",this._stateText=\"\"}_clearStateTimeout(){this._stateTimeout&&(clearTimeout(this._stateTimeout),this._stateTimeout=void 0)}updated(e){this.classList.toggle(\"kr-button--loading\",\"loading\"===this._state),this.classList.toggle(\"kr-button--success\",\"success\"===this._state),this.classList.toggle(\"kr-button--error\",\"error\"===this._state),this.classList.toggle(`kr-button--${this.variant}`,!0),this.classList.toggle(`kr-button--${this.color}`,!0),this.classList.toggle(\"kr-button--small\",\"small\"===this.size),this.classList.toggle(\"kr-button--large\",\"large\"===this.size),this.classList.toggle(\"kr-button--split\",this.split&&!!this.options.length)}render(){if(this.split&&this.options.length)return j` <div class=\"split-primary\" @click=${e=>this._handleSplitPrimaryClick(e)}> <span class=\"content\"> <slot name=\"icon\"></slot> <slot></slot> </span> ${\"idle\"!==this._state?j`<span class=\"state-overlay\"> ${\"loading\"===this._state?j`<span class=\"spinner\"></span>`:this._stateText} </span>`:F} </div> <div class=\"split-divider\"></div> <div class=\"split-trigger\" @click=${e=>this._handleSplitTriggerClick(e)}> <svg class=\"caret\" xmlns=\"http://www.w3.org/2000/svg\" height=\"20\" width=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z\"/></svg> </div> <div class=\"dropdown ${this._dropdownOpened?\"dropdown--opened\":\"\"}\"> ${this.options.map((e=>j` <button class=\"dropdown-item\" @click=${t=>this._handleOptionClick(e,t)} >${e.label}</button> `))} </div> `;const e=j` <span class=\"content\"> <slot name=\"icon\"></slot> <slot></slot> </span> ${this.options.length?j`<svg class=\"caret\" xmlns=\"http://www.w3.org/2000/svg\" height=\"20\" width=\"20\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z\"/></svg>`:F} ${\"idle\"!==this._state?j`<span class=\"state-overlay\"> ${\"loading\"===this._state?j`<span class=\"spinner\"></span>`:this._stateText} </span>`:F} ${this.options.length?j` <div class=\"dropdown ${this._dropdownOpened?\"dropdown--opened\":\"\"}\"> ${this.options.map((e=>j` <button class=\"dropdown-item\" @click=${t=>this._handleOptionClick(e,t)} >${e.label}</button> `))} </div> `:F} `;return this.href?j`<a class=\"link\" href=${this.href} target=${this.target||F}>${e}</a>`:e}}"
|
|
941
962
|
},
|
|
942
963
|
{
|
|
943
964
|
"kind": "variable",
|
|
944
965
|
"name": "De",
|
|
945
|
-
"default": "class extends
|
|
966
|
+
"default": "class extends le{constructor(){super(...arguments),this.language=\"html\",this.code=\"\",this.activeTab=\"preview\",this.copied=!1,this.highlightedCode=\"\"}connectedCallback(){super.connectedCallback(),requestAnimationFrame((()=>{this.code||(this.code=this.innerHTML.trim().replace(/=\"\"(?=[\\s>])/g,\"\")),this.querySelectorAll(\"script\").forEach((e=>{const t=document.createElement(\"script\");t.textContent=e.textContent,e.replaceWith(t)})),this.code&&window.hljs&&window.hljs.getLanguage(this.language)?this.highlightedCode=window.hljs.highlight(this.code,{language:this.language}).value:this.highlightedCode=this.code.replace(/&/g,\"&\").replace(/</g,\"<\").replace(/>/g,\">\")}))}activateTab(e){this.activeTab=e}copyCode(){this.code&&navigator.clipboard.writeText(this.code).then((()=>{this.copied=!0,setTimeout((()=>{this.copied=!1}),2e3)}))}render(){return j` <div class=\"tabs\"> <button class=${we({tab:!0,\"tab--active\":\"preview\"===this.activeTab})} @click=${()=>this.activateTab(\"preview\")} > Preview </button> <button class=${we({tab:!0,\"tab--active\":\"code\"===this.activeTab})} @click=${()=>this.activateTab(\"code\")} > Code </button> <button class=${we({copy:!0,\"copy--success\":this.copied})} @click=${this.copyCode} title=${this.copied?\"Copied!\":\"Copy code\"} > ${this.copied?j`<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><polyline points=\"20 6 9 17 4 12\"></polyline></svg>`:j`<svg width=\"18\" height=\"18\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"><rect x=\"9\" y=\"9\" width=\"13\" height=\"13\" rx=\"2\" ry=\"2\"></rect><path d=\"M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1\"></path></svg>`} </button> </div> <div class=${we({panel:!0,\"panel--active\":\"preview\"===this.activeTab,\"panel--preview\":!0})}> <slot></slot> </div> <div class=${we({panel:!0,\"panel--active\":\"code\"===this.activeTab,\"panel--code\":!0})}> <pre class=\"code\"><code>${Oe(this.highlightedCode)}</code></pre> </div> `}}"
|
|
946
967
|
},
|
|
947
968
|
{
|
|
948
969
|
"kind": "variable",
|
|
949
|
-
"name": "
|
|
950
|
-
"default": "class extends
|
|
970
|
+
"name": "Ae",
|
|
971
|
+
"default": "class extends le{constructor(){super(...arguments),this.items=[],this.resolvePromise=null,this.boundHandleOutsideClick=this.handleOutsideClick.bind(this),this.boundHandleKeyDown=this.handleKeyDown.bind(this)}static async open(e){const t=document.querySelector(\"kr-context-menu\");t&&t.remove();const i=document.createElement(\"kr-context-menu\");return document.body.appendChild(i),i.show(e)}async show(e){this.items=e.items,this.style.left=`${e.x}px`,this.style.top=`${e.y}px`,await this.updateComplete;const t=this.getBoundingClientRect();return t.right>window.innerWidth&&(this.style.left=e.x-t.width+\"px\"),t.bottom>window.innerHeight&&(this.style.top=e.y-t.height+\"px\"),requestAnimationFrame((()=>{document.addEventListener(\"click\",this.boundHandleOutsideClick),document.addEventListener(\"contextmenu\",this.boundHandleOutsideClick),document.addEventListener(\"keydown\",this.boundHandleKeyDown)})),new Promise((e=>{this.resolvePromise=e}))}handleOutsideClick(e){this.contains(e.target)||this.close(null)}handleKeyDown(e){\"Escape\"===e.key&&this.close(null)}handleItemClick(e){e.disabled||e.divider||this.close(e)}close(e){document.removeEventListener(\"click\",this.boundHandleOutsideClick),document.removeEventListener(\"contextmenu\",this.boundHandleOutsideClick),document.removeEventListener(\"keydown\",this.boundHandleKeyDown),this.resolvePromise&&(this.resolvePromise(e),this.resolvePromise=null),this.remove()}render(){return j` <div class=\"menu\"> ${this.items.map((e=>e.divider?j`<div class=\"menu__divider\"></div>`:j` <button class=\"menu__item\" ?disabled=${e.disabled} @click=${()=>this.handleItemClick(e)} > ${e.icon?j`<span class=\"menu__item-icon\">${e.icon}</span>`:null} ${e.label} </button> `))} </div> `}}"
|
|
951
972
|
},
|
|
952
973
|
{
|
|
953
974
|
"kind": "class",
|
|
@@ -1002,12 +1023,12 @@
|
|
|
1002
1023
|
{
|
|
1003
1024
|
"kind": "variable",
|
|
1004
1025
|
"name": "Be",
|
|
1005
|
-
"default": "class extends
|
|
1026
|
+
"default": "class extends le{constructor(){super(...arguments),this._dialogRef=null,this._contentElement=null,this.opened=!1,this.label=\"\",this.width=\"560px\",this._handleDocumentKeyDown=e=>{\"Escape\"===e.key&&this.close()}}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener(\"keydown\",this._handleDocumentKeyDown)}updated(e){super.updated(e),e.has(\"opened\")&&(this.opened?document.addEventListener(\"keydown\",this._handleDocumentKeyDown):document.removeEventListener(\"keydown\",this._handleDocumentKeyDown))}open(){this.opened=!0}close(){this._dialogRef?this._dialogRef.close(void 0):(this.opened=!1,this.dispatchEvent(new CustomEvent(\"close\",{bubbles:!0,composed:!0})))}static open(e,t){document.querySelectorAll(\"kr-dialog\").forEach((e=>{e._dialogRef&&e.remove()}));const i=new je,s=document.createElement(\"kr-dialog\");i.setDialogElement(s),s._dialogRef=i;const r=new e;return r.dialogRef=i,t?.data&&(r.data=t.data),t?.label&&(s.label=t.label),t?.width&&(s.width=t.width),s._contentElement=r,s.opened=!0,document.body.appendChild(s),i}_handleBackdropClick(e){e.target.classList.contains(\"backdrop\")&&this.close()}render(){return j` <div class=\"backdrop\" @click=${this._handleBackdropClick}></div> <div class=\"dialog\" style=${Le({width:this.width})}> ${this.label?j`<div class=\"dialog__header\"><div class=\"dialog__header-label\">${this.label}</div></div>`:\"\"} <div class=\"dialog__body\">${this._contentElement?this._contentElement:j`<slot></slot>`}</div> </div> `}}"
|
|
1006
1027
|
},
|
|
1007
1028
|
{
|
|
1008
1029
|
"kind": "variable",
|
|
1009
|
-
"name": "
|
|
1010
|
-
"default": "class extends
|
|
1030
|
+
"name": "Ue",
|
|
1031
|
+
"default": "class extends le{constructor(){super(...arguments),this.relativeOptions=[{key:\"last-5-minutes\",amount:5,unit:\"minute\",type:\"relative\"},{key:\"last-30-minutes\",amount:30,unit:\"minute\",type:\"relative\"},{key:\"last-1-hour\",amount:1,unit:\"hour\",type:\"relative\"},{key:\"last-6-hours\",amount:6,unit:\"hour\",type:\"relative\"},{key:\"last-1-day\",amount:1,unit:\"day\",type:\"relative\"},{key:\"last-7-days\",amount:7,unit:\"day\",type:\"relative\"},{key:\"last-30-days\",amount:30,unit:\"day\",type:\"relative\"}],this.disabled=!1,this.invalid=!1,this.placeholder=\"Select a date range\",this.startDate=\"\",this.endDate=\"\",this._isOpen=!1,this._activeTab=\"relative\",this._tempStartDate=\"\",this._tempEndDate=\"\",this._handleClickOutside=e=>{e.composedPath().includes(this)||(this._isOpen=!1)}}connectedCallback(){super.connectedCallback(),document.addEventListener(\"click\",this._handleClickOutside),this.startDate&&(this._tempStartDate=this.startDate),this.endDate&&(this._tempEndDate=this.endDate),\"relative\"===this.mode?this._activeTab=\"relative\":\"absolute\"===this.mode&&(this._activeTab=\"absolute\")}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener(\"click\",this._handleClickOutside)}_handleTriggerClick(){this.disabled||(this._isOpen=!this._isOpen)}_handleTabClick(e){this._activeTab=e}_handleRelativeSelect(e){this.value={type:\"relative\",amount:e.amount,unit:e.unit},this._isOpen=!1,this.dispatchEvent(new CustomEvent(\"change\",{detail:{value:this.value},bubbles:!0,composed:!0}))}_handleApplyAbsolute(){this._tempStartDate&&this._tempEndDate&&(this._tempStartDate>=this._tempEndDate||(this.value={type:\"absolute\",startDate:this._tempStartDate,endDate:this._tempEndDate},this.startDate=this._tempStartDate,this.endDate=this._tempEndDate,this._isOpen=!1,this.dispatchEvent(new CustomEvent(\"change\",{detail:{value:this.value},bubbles:!0,composed:!0}))))}_handleCancel(){this._isOpen=!1,this._tempStartDate=this.startDate,this._tempEndDate=this.endDate}_formatRelativeOption(e){if(0===e.amount)return\"day\"===e.unit?\"Today\":`This ${e.unit}`;const t={second:1===e.amount?\"second\":\"seconds\",minute:1===e.amount?\"minute\":\"minutes\",hour:1===e.amount?\"hour\":\"hours\",day:1===e.amount?\"day\":\"days\",week:1===e.amount?\"week\":\"weeks\",month:1===e.amount?\"month\":\"months\",year:1===e.amount?\"year\":\"years\"};return`Last ${e.amount} ${t[e.unit]}`}_getDisplayValue(){return this.value?\"relative\"===this.value.type&&void 0!==this.value.amount&&this.value.unit?this._formatRelativeOption({key:\"\",amount:this.value.amount,unit:this.value.unit,type:\"relative\"}):\"absolute\"===this.value.type&&this.value.startDate&&this.value.endDate?`${this.value.startDate} - ${this.value.endDate}`:\"\":\"\"}_renderTriggerText(){const e=this._getDisplayValue();return e?j`${e}`:j`<span class=\"trigger-placeholder\">${this.placeholder}</span>`}_renderContent(){return\"relative\"===this.mode?this._renderRelativeContent():\"absolute\"===this.mode?this._renderAbsoluteContent():\"relative\"===this._activeTab?this._renderRelativeContent():this._renderAbsoluteContent()}_renderRelativeContent(){return j` <div class=\"relative-options\"> ${this.relativeOptions.map((e=>j` <button class=${we({\"relative-option\":!0,\"relative-option--selected\":\"relative\"===this.value?.type&&this.value?.amount===e.amount&&this.value?.unit===e.unit})} type=\"button\" @click=${()=>this._handleRelativeSelect(e)} > ${this._formatRelativeOption(e)} </button> `))} </div> `}_renderAbsoluteContent(){return j` <div class=\"absolute\"> <div class=\"date-row\"> <span class=\"date-label\">Start</span> <input class=\"date-input\" type=\"date\" .value=${this._tempStartDate} @change=${this._handleStartDateChange} /> </div> <div class=\"date-row\"> <span class=\"date-label\">End</span> <input class=\"date-input\" type=\"date\" .value=${this._tempEndDate} @change=${this._handleEndDateChange} /> </div> </div> `}_renderFooter(){return\"absolute\"===this.mode?j` <div class=\"footer\"> <kr-button variant=\"outline\" size=\"small\" @click=${this._handleCancel}> Cancel </kr-button> <kr-button variant=\"primary\" size=\"small\" ?disabled=${!this._tempStartDate||!this._tempEndDate} @click=${this._handleApplyAbsolute} > Apply </kr-button> </div> `:\"relative\"===this.mode?F:\"absolute\"===this._activeTab?j` <div class=\"footer\"> <kr-button variant=\"outline\" size=\"small\" @click=${this._handleCancel}> Cancel </kr-button> <kr-button variant=\"primary\" size=\"small\" ?disabled=${!this._tempStartDate||!this._tempEndDate} @click=${this._handleApplyAbsolute} > Apply </kr-button> </div> `:F}_handleStartDateChange(e){this._tempStartDate=e.target.value}_handleEndDateChange(e){this._tempEndDate=e.target.value}render(){return j` <button part=\"trigger\" class=${we({trigger:!0,\"trigger--invalid\":this.invalid})} type=\"button\" ?disabled=${this.disabled} @click=${this._handleTriggerClick} > <svg class=\"icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"> <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z\" /> </svg> <span class=\"trigger-text\"> ${this._renderTriggerText()} </span> <svg class=\"icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\"> <path stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M19 9l-7 7-7-7\" /> </svg> </button> <div part=\"dropdown\" class=${we({dropdown:!0,\"dropdown--open\":this._isOpen})}> ${this.mode?F:j` <div class=\"tabs\"> <button class=${we({tab:!0,\"tab--active\":\"relative\"===this._activeTab})} type=\"button\" @click=${()=>this._handleTabClick(\"relative\")} > Relative </button> <button class=${we({tab:!0,\"tab--active\":\"absolute\"===this._activeTab})} type=\"button\" @click=${()=>this._handleTabClick(\"absolute\")} > Absolute </button> </div> `} <div class=\"content\"> ${this._renderContent()} </div> ${this._renderFooter()} </div> `}}"
|
|
1011
1032
|
},
|
|
1012
1033
|
{
|
|
1013
1034
|
"kind": "variable",
|
|
@@ -1016,22 +1037,22 @@
|
|
|
1016
1037
|
{
|
|
1017
1038
|
"kind": "variable",
|
|
1018
1039
|
"name": "Ye",
|
|
1019
|
-
"default": "class extends
|
|
1040
|
+
"default": "class extends le{constructor(){super(...arguments),this.justified=!1,this.size=\"medium\"}updated(e){e.has(\"activeTabId\")&&this._updateActiveTab()}firstUpdated(){this._updateActiveTab()}_getTabs(){return Array.from(this.querySelectorAll(\"kr-tab\"))}_updateActiveTab(){const e=this._getTabs();0!==e.length&&(this.activeTabId||(this.activeTabId=e[0]?.id),e.forEach((e=>{e.active=e.id===this.activeTabId})),this.requestUpdate())}_handleTabClick(e){e.disabled||(this.activeTabId=e.id,this.dispatchEvent(new CustomEvent(\"tab-change\",{detail:{activeTabId:e.id},bubbles:!0,composed:!0})))}_handleTabDismiss(e,t){t.stopPropagation(),this.dispatchEvent(new CustomEvent(\"tab-dismiss\",{detail:{tabId:e.id},bubbles:!0,composed:!0}))}_handleKeyDown(e){const t=this._getTabs().filter((e=>!e.disabled)),i=t.findIndex((e=>e.id===this.activeTabId));let s=-1;switch(e.key){case\"ArrowLeft\":s=i>0?i-1:t.length-1;break;case\"ArrowRight\":s=i<t.length-1?i+1:0;break;case\"Home\":s=0;break;case\"End\":s=t.length-1}if(s>=0){e.preventDefault();const i=t[s];this.activeTabId=i.id,this.dispatchEvent(new CustomEvent(\"tab-change\",{detail:{activeTabId:i.id},bubbles:!0,composed:!0}));const r=this.shadowRoot?.querySelectorAll(\".label\"),o=Array.from(r||[]).find((e=>e.getAttribute(\"data-tab-id\")===i.id));o?.focus()}}_renderTabIcon(e){const t=e.getIconElement();if(!t)return F;const i=t.cloneNode(!0);return i.removeAttribute(\"slot\"),j`<span class=\"label-icon\">${i}</span>`}render(){return j` <div class=\"header\" role=\"tablist\" @keydown=${this._handleKeyDown}> ${this._getTabs().map((e=>j` <button class=${we({label:!0,\"label--active\":e.id===this.activeTabId,\"label--justified\":this.justified})} role=\"tab\" data-tab-id=${e.id} aria-selected=${e.id===this.activeTabId} aria-controls=${`panel-${e.id}`} tabindex=${e.id===this.activeTabId?0:-1} ?disabled=${e.disabled} @click=${()=>this._handleTabClick(e)} > ${this._renderTabIcon(e)} <span>${e.label}</span> ${e.badge?j`<span class=\"label-badge\" style=${Le({backgroundColor:e.badgeBackground,color:e.badgeColor})}>${e.badge}</span>`:F} ${e.dismissible?j` <button class=\"label-dismiss\" type=\"button\" aria-label=\"Close tab\" @click=${t=>this._handleTabDismiss(e,t)} > <svg viewBox=\"0 0 20 20\" fill=\"currentColor\" width=\"12\" height=\"12\"><path fill-rule=\"evenodd\" d=\"M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z\" clip-rule=\"evenodd\"/></svg> </button> `:F} </button> `))} </div> <div class=\"content\" role=\"tabpanel\" aria-labelledby=${this.activeTabId||\"\"}> <slot @slotchange=${this._updateActiveTab}></slot> </div> `}}"
|
|
1020
1041
|
},
|
|
1021
1042
|
{
|
|
1022
1043
|
"kind": "variable",
|
|
1023
1044
|
"name": "Qe",
|
|
1024
|
-
"default": "class extends
|
|
1045
|
+
"default": "class extends le{constructor(){super(...arguments),this.id=\"\",this.label=\"\",this.badge=\"\",this.badgeBackground=\"\",this.badgeColor=\"\",this.disabled=!1,this.dismissible=!1,this.active=!1}getIconElement(){return this.querySelector('[slot=\"icon\"]')}updated(){const e=this.closest(\"kr-tab-group\");e&&e.requestUpdate()}render(){return j`<slot></slot>`}}"
|
|
1025
1046
|
},
|
|
1026
1047
|
{
|
|
1027
1048
|
"kind": "variable",
|
|
1028
1049
|
"name": "Je",
|
|
1029
|
-
"default": "class extends
|
|
1050
|
+
"default": "class extends le{constructor(){super(),this.label=\"\",this.name=\"\",this.value=\"\",this.placeholder=\"Select an option\",this.disabled=!1,this.required=!1,this.readonly=!1,this.hint=\"\",this._isOpen=!1,this._highlightedIndex=-1,this._touched=!1,this._handleInvalid=e=>{e.preventDefault(),this._touched=!0},this._handleOutsideClick=e=>{e.composedPath().includes(this)||this._close()},this._handleKeyDown=e=>{if(!this._isOpen)return;const t=Array.from(this.querySelectorAll(\"kr-select-option\"));switch(e.key){case\"Escape\":this._close(),this._triggerElement?.focus();break;case\"ArrowDown\":if(e.preventDefault(),t.some((e=>!e.disabled))){let e=this._highlightedIndex+1;for(;e<t.length&&t[e]?.disabled;)e++;e<t.length&&(this._highlightedIndex=e)}break;case\"ArrowUp\":e.preventDefault();{let e=this._highlightedIndex-1;for(;e>=0&&t[e]?.disabled;)e--;e>=0&&(this._highlightedIndex=e)}break;case\"Enter\":e.preventDefault(),this._highlightedIndex>=0&&this._highlightedIndex<t.length&&this._selectOption(t[this._highlightedIndex])}},this._internals=this.attachInternals()}get form(){return this._internals.form}get validity(){return this._internals.validity}get validationMessage(){return this._internals.validationMessage}get willValidate(){return this._internals.willValidate}checkValidity(){return this._internals.checkValidity()}reportValidity(){return this._internals.reportValidity()}formResetCallback(){this.value=\"\",this._touched=!1,this._internals.setFormValue(\"\"),this._internals.setValidity({})}formStateRestoreCallback(e){this.value=e}connectedCallback(){super.connectedCallback(),document.addEventListener(\"click\",this._handleOutsideClick),document.addEventListener(\"keydown\",this._handleKeyDown),this.addEventListener(\"invalid\",this._handleInvalid)}firstUpdated(){this._updateValidity()}updated(e){(e.has(\"required\")||e.has(\"value\"))&&this._updateValidity()}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener(\"click\",this._handleOutsideClick),document.removeEventListener(\"keydown\",this._handleKeyDown),this.removeEventListener(\"invalid\",this._handleInvalid)}_toggle(){if(!this.disabled&&!this.readonly)if(this._isOpen)this._close();else{this._isOpen=!0;const e=Array.from(this.querySelectorAll(\"kr-select-option\"));this._highlightedIndex=e.findIndex((e=>e.value===this.value)),requestAnimationFrame((()=>{const e=this.shadowRoot?.querySelector(\".select-dropdown\");if(e){const t=this._triggerElement.getBoundingClientRect(),i=window.innerHeight-t.bottom-4-8;e.style.top=t.bottom+4+\"px\",e.style.left=t.left+\"px\",e.style.width=t.width+\"px\",e.style.maxHeight=i+\"px\"}}))}}_close(){this._isOpen=!1,this._highlightedIndex=-1}_selectOption(e){e.disabled||(this.value=e.value,this._internals.setFormValue(this.value),this._updateValidity(),this.dispatchEvent(new Event(\"change\",{bubbles:!0,composed:!0})),this._close(),this._triggerElement?.focus())}_handleBlur(){this._touched=!0,this._updateValidity()}_updateValidity(){this.required&&!this.value?this._internals.setValidity({valueMissing:!0},\"Please select an option\",this._triggerElement):this._internals.setValidity({})}render(){const e=Array.from(this.querySelectorAll(\"kr-select-option\")),t=e.find((e=>e.value===this.value))?.label;return j` <div class=\"wrapper\"> ${this.label?j` <label> ${this.label} ${this.required?j`<span class=\"required\" aria-hidden=\"true\">*</span>`:\"\"} </label> `:F} <div class=\"select-wrapper\"> <button class=${we({\"select-trigger\":!0,\"select-trigger--open\":this._isOpen,\"select-trigger--invalid\":this._touched&&this.required&&!this.value})} type=\"button\" ?disabled=${this.disabled} aria-haspopup=\"listbox\" aria-expanded=${this._isOpen} @click=${this._toggle} @blur=${this._handleBlur} > <span class=${we({\"select-value\":!0,\"select-placeholder\":!t})}> ${t||this.placeholder} </span> <svg class=${we({\"chevron-icon\":!0,\"select-icon\":!0,\"select-icon--open\":this._isOpen})} viewBox=\"0 0 24 24\" fill=\"currentColor\" > <path d=\"M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6z\"/> </svg> </button> <div class=${we({\"select-dropdown\":!0,hidden:!this._isOpen})} role=\"listbox\"> <div class=\"select-options\"> ${0===e.length?j`<div class=\"select-empty\">No options available</div>`:e.map(((e,t)=>{const i=e.value===this.value;return j` <div class=${we({\"select-option\":!0,\"select-option--selected\":i,\"select-option--disabled\":e.disabled,\"select-option--highlighted\":t===this._highlightedIndex})} role=\"option\" aria-selected=${i} @click=${()=>this._selectOption(e)} @mouseenter=${()=>this._highlightedIndex=t} > ${e.label} </div> `}))} </div> </div> </div> ${this._touched&&this.required&&!this.value?j`<div class=\"validation-message\">Please select an option</div>`:this.hint?j`<div class=\"hint\">${this.hint}</div>`:\"\"} </div> <div class=\"options-slot\"> <slot @slotchange=${()=>this.requestUpdate()}></slot> </div> `}focus(){this._triggerElement?.focus()}blur(){this._triggerElement?.blur()}}"
|
|
1030
1051
|
},
|
|
1031
1052
|
{
|
|
1032
1053
|
"kind": "variable",
|
|
1033
1054
|
"name": "tt",
|
|
1034
|
-
"default": "class extends
|
|
1055
|
+
"default": "class extends le{constructor(){super(...arguments),this.value=\"\",this.disabled=!1}get label(){return this.textContent?.trim()||\"\"}render(){return j`<slot></slot>`}}"
|
|
1035
1056
|
},
|
|
1036
1057
|
{
|
|
1037
1058
|
"kind": "variable",
|
|
@@ -1243,56 +1264,61 @@
|
|
|
1243
1264
|
{
|
|
1244
1265
|
"kind": "variable",
|
|
1245
1266
|
"name": "ft",
|
|
1246
|
-
"default": "class extends ae{constructor(){super(...arguments),this._scrollStyle=\"edge\",this._data=[],this._dataState=\"idle\",this._page=1,this._pageSize=50,this._totalItems=0,this._totalPages=0,this._searchQuery=\"\",this._canScrollLeft=!1,this._canScrollRight=!1,this._canScrollHorizontal=!1,this._columnPickerOpen=!1,this._filterPanelOpened=null,this._filterPanelTab=\"filter\",this._buckets=new Map,this._filterPanelPos={top:0,left:0},this._sorts=[],this._resizing=null,this._resizeObserver=null,this._searchPositionLocked=!1,this._columnWidthsLocked=!1,this._model=new ut,this.def={columns:[]},this.variant=\"default\",this._handleClickOutside=e=>{const t=e.composedPath();if(this._columnPickerOpen){const e=this.shadowRoot?.querySelector(\".column-picker-wrapper\");e&&!t.includes(e)&&(this._columnPickerOpen=!1)}this._filterPanelOpened&&(t.some((e=>e.classList?.contains(\"filter-panel\")))||this._handleFilterApply())},this._handleResizeMove=e=>{if(!this._resizing)return;const t=this._model.columns.find((e=>e.id===this._resizing.columnId));if(t){const i=this._resizing.startWidth+(e.clientX-this._resizing.startX);t.width=`${Math.min(900,Math.max(50,i))}px`,this.requestUpdate()}},this._handleResizeEnd=()=>{this._resizing=null,document.removeEventListener(\"mousemove\",this._handleResizeMove),document.removeEventListener(\"mouseup\",this._handleResizeEnd)}}connectedCallback(){super.connectedCallback(),this.classList.toggle(\"kr-table--scroll-overlay\",\"overlay\"===this._scrollStyle),this.classList.toggle(\"kr-table--scroll-edge\",\"edge\"===this._scrollStyle),this._fetch(),this._initRefresh(),document.addEventListener(\"click\",this._handleClickOutside),this._resizeObserver=new ResizeObserver((()=>{this._searchPositionLocked=!1,this._updateSearchPosition()})),this._resizeObserver.observe(this)}disconnectedCallback(){super.disconnectedCallback(),clearInterval(this._refreshTimer),document.removeEventListener(\"click\",this._handleClickOutside),this._resizeObserver?.disconnect()}willUpdate(e){e.has(\"def\")&&(this._columnWidthsLocked=!1,this._model=new ut,this.def.title&&(this._model.title=this.def.title),this.def.description&&(this._model.description=this.def.description),this.def.actions&&(this._model.actions=this.def.actions),this.def.data&&(this._model.data=this.def.data),this.def.dataSource&&(this._model.dataSource=this.def.dataSource),\"number\"==typeof this.def.refreshInterval&&(this._model.refreshInterval=this.def.refreshInterval),\"number\"==typeof this.def.pageSize&&(this._model.pageSize=this.def.pageSize,this._pageSize=this.def.pageSize),this.def.rowClickable&&(this._model.rowClickable=this.def.rowClickable),this.def.rowHref&&(this._model.rowHref=this.def.rowHref),this._sorts=[],this._model.columns=this.def.columns.map((e=>{const t={...e,filter:null};return t.type||(t.type=\"string\"),e.sort&&this._sorts.push({sortBy:e.id,sortDirection:e.sort}),\"actions\"===t.type?(t.label=e.label??\"\",t.sticky=\"right\",t.resizable=!1,t):((e.filterable||e.facetable)&&(t.filter=new ct,t.filter.field=e.id,t.filter.type=t.type,e.filter?(t.filter.setOperator(e.filter.operator),t.filter.setValue(e.filter.value)):e.facetable&&!e.filterable?(t.filter.operator=\"in\",t.filter.value=[]):\"string\"===t.filter.type&&(t.filter.operator=\"contains\")),t)})),this.def.displayedColumns?this._model.displayedColumns=this.def.displayedColumns:this._model.displayedColumns=this._model.columns.map((e=>e.id)),this._fetch(),this._initRefresh())}updated(e){this.classList.toggle(\"kr-table--card\",\"card\"===this.variant),this._updateScrollFlags(),this._syncSlottedContent(),this._lockColumnWidths()}_lockColumnWidths(){if(this._columnWidthsLocked||0===this._data.length)return;const e=this.shadowRoot?.querySelectorAll(\".header-row > .header-cell\");if(!e)return;const t=this.getDisplayedColumns();e.forEach(((e,i)=>{const s=e.offsetWidth;i<t.length&&!t[i].width&&\"actions\"!==t[i].type&&s>0&&(t[i].width=`${s}px`,this._columnWidthsLocked=!0)}))}_syncSlottedContent(){const e=this.getDisplayedColumns().filter((e=>e.render));e.length&&(this.querySelectorAll('[slot^=\"cell-\"]').forEach((e=>e.remove())),this._data.forEach(((t,i)=>{e.forEach((e=>{const s=e.render(t);if(!s)return;const o=document.createElement(\"span\");o.slot=`cell-${i}-${e.id}`,\"actions\"===e.type&&(o.style.display=\"flex\",o.style.gap=\"8px\"),\"string\"==typeof s?o.innerHTML=s:oe(s,o),this.appendChild(o)}))})))}refresh(){this._fetch()}goToPrevPage(){this._page>1&&(this._page--,this._fetch())}goToNextPage(){this._page<this._totalPages&&(this._page++,this._fetch())}goToPage(e){e>=1&&e<=this._totalPages&&(this._page=e,this._fetch())}_toSolrData(){const e={page:this._page-1,size:this._pageSize,sorts:this._sorts,filterFields:[],queryFields:[],facetFields:[]};for(const t of this._model.columns){if(!t.filter||t.filter.isEmpty()||!t.filter.isValid())continue;const i=t.filter.toSolrData();!t.facetable||\"in\"!==t.filter.operator&&\"n_in\"!==t.filter.operator||(i.tagged=!0),e.filterFields.push(i)}for(const t of this._model.columns)t.facetable&&e.facetFields.push({name:t.id,type:\"FIELD\",limit:100,sort:\"count\",minimumCount:1});return this._searchQuery?.trim().length&&e.queryFields.push({name:\"_text_\",operation:\"IS\",value:at(this._searchQuery,!1)}),e}_toDbParams(){const e={page:this._page-1,size:this._pageSize,sorts:this._sorts,filterFields:[],queryFields:[],facetFields:[]};for(const t of this._model.columns)t.filter&&!t.filter.isEmpty()&&t.filter.isValid()&&e.filterFields.push(t.filter.toDbParams());return this._searchQuery?.trim().length&&this._model.columns.filter((e=>e.searchable)).forEach((t=>{e.queryFields.push({name:t.id,operation:\"CONTAINS\",value:this._searchQuery,and:!1})})),e}_fetch(){if(this._model.data)return this._data=this._model.data,this._totalItems=this._model.data.length,this._totalPages=Math.ceil(this._model.data.length/this._pageSize),void(this._dataState=\"success\");if(!this._model.dataSource)return;let e;this._dataState=\"loading\",e=\"db\"===this._model.dataSource.mode?this._toDbParams():this._toSolrData(),this._model.dataSource.fetch(e).then((e=>{switch(this._model.dataSource?.mode){case\"opensearch\":throw Error(\"Opensearch not supported yet\");case\"db\":{const t=e;this._data=t.data.content,this._totalItems=t.data.totalElements,this._totalPages=t.data.totalPages,this._pageSize=t.data.size;break}default:{const t=e;this._data=t.data.content,this._totalItems=t.data.totalElements,this._totalPages=t.data.totalPages,this._pageSize=t.data.size,this._parseFacetResults(t)}}this._dataState=\"success\",this._updateSearchPosition()})).catch((e=>{this._dataState=\"error\",Ke.show({message:e instanceof Error?e.message:\"Failed to load data\",type:\"error\"})}))}_parseFacetResults(e){if(e.data.facetFields){for(const t of this._model.columns){if(!t.facetable)continue;const i=e.data.facetFields[t.id];if(!i){this._buckets.set(t.id,[]);continue}const s=[];for(const e of i){let i=e.name;\"boolean\"===t.type&&\"string\"==typeof e.name&&(\"true\"===e.name?i=!0:\"false\"===e.name&&(i=!1)),null===e.name&&e.count>0&&s.unshift({val:null,count:e.count}),null!==e.name&&s.push({val:i,count:e.count})}if(t.filter&&(\"in\"===t.filter.operator||\"n_in\"===t.filter.operator)&&Array.isArray(t.filter.value))for(const e of t.filter.value)s.some((t=>t.val===e))||s.push({val:e,count:0});this._buckets.set(t.id,s)}this._buckets=new Map(this._buckets)}}_initRefresh(){clearInterval(this._refreshTimer),this._model.refreshInterval&&this._model.refreshInterval>0&&(this._refreshTimer=window.setInterval((()=>{this._fetch()}),this._model.refreshInterval))}_handleSearch(e){const t=e.target;this._searchQuery=t.value,this._page=1,this._fetch()}_getGridTemplateColumns(){return this.getDisplayedColumns().map((e=>e.width?e.width:\"actions\"===e.type?\"max-content\":\"minmax(80px, auto)\")).join(\" \")}_updateSearchPosition(){if(this._searchPositionLocked)return;if(\"card\"===this.variant)return;const e=this.shadowRoot?.querySelector(\".search\"),t=e?.querySelector(\".search-field\");e&&t&&(e.style.justifyContent=\"center\",t.style.marginLeft=\"\",requestAnimationFrame((()=>{const i=e.getBoundingClientRect(),s=t.getBoundingClientRect().left-i.left;e.style.justifyContent=\"flex-start\",t.style.marginLeft=`${s}px`,this._searchPositionLocked=!0})))}_toggleColumnPicker(){this._columnPickerOpen=!this._columnPickerOpen}_toggleColumn(e){this._model.displayedColumns.includes(e)?this._model.displayedColumns=this._model.displayedColumns.filter((t=>t!==e)):this._model.displayedColumns=[...this._model.displayedColumns,e],this.requestUpdate()}_handleRowMouseDown(){(this._model.rowClickable||this._model.rowHref)&&window.getSelection()?.removeAllRanges()}_handleRowClick(e,t,i){if(!this._model.rowClickable&&!this._model.rowHref)return;const s=window.getSelection();s&&s.toString().length>0?e.preventDefault():this.dispatchEvent(new CustomEvent(\"row-click\",{detail:{row:t,rowIndex:i},bubbles:!0,composed:!0}))}getDisplayedColumns(){return this._model.displayedColumns.map((e=>this._model.columns.find((t=>t.id===e)))).sort(((e,t)=>\"actions\"===e.type&&\"actions\"!==t.type?1:\"actions\"!==e.type&&\"actions\"===t.type?-1:0))}_handleScroll(e){const t=e.target;this._canScrollLeft=t.scrollLeft>0,this._canScrollRight=t.scrollLeft<t.scrollWidth-t.clientWidth-1}_updateScrollFlags(){const e=this.shadowRoot?.querySelector(\".content\");e&&(this._canScrollLeft=e.scrollLeft>0,this._canScrollRight=e.scrollWidth>e.clientWidth&&e.scrollLeft<e.scrollWidth-e.clientWidth-1,this._canScrollHorizontal=e.scrollWidth>e.clientWidth),this.classList.toggle(\"kr-table--scroll-left-available\",this._canScrollLeft),this.classList.toggle(\"kr-table--scroll-right-available\",this._canScrollRight),this.classList.toggle(\"kr-table--scroll-horizontal-available\",this._canScrollHorizontal),this.classList.toggle(\"kr-table--sticky-left\",this.getDisplayedColumns().some((e=>\"left\"===e.sticky))),this.classList.toggle(\"kr-table--sticky-right\",this.getDisplayedColumns().some((e=>\"right\"===e.sticky)))}_handleResizeStart(e,t){e.preventDefault();const i=this.shadowRoot?.querySelector(`.header-cell[data-column-id=\"${t}\"]`);this._resizing={columnId:t,startX:e.clientX,startWidth:i?.offsetWidth||200},document.addEventListener(\"mousemove\",this._handleResizeMove),document.addEventListener(\"mouseup\",this._handleResizeEnd)}_handleSortClick(e,t){if(e.shiftKey){const e=this._sorts.findIndex((e=>e.sortBy===t.id));if(-1===e)this._sorts.push({sortBy:t.id,sortDirection:\"asc\"});else{const t=this._sorts[e];\"asc\"===t.sortDirection?t.sortDirection=\"desc\":this._sorts.splice(e,1)}this.requestUpdate()}else{let e=null;1===this._sorts.length&&(e=this._sorts.find((e=>e.sortBy===t.id))),e?\"asc\"===e.sortDirection?this._sorts=[{sortBy:t.id,sortDirection:\"desc\"}]:this._sorts=[]:this._sorts=[{sortBy:t.id,sortDirection:\"asc\"}]}this._page=1,this._fetch()}_renderSortIndicator(e){if(!e.sortable)return U;const t=this._sorts.findIndex((t=>t.sortBy===e.id));if(-1===t)return j` <span class=\"header-cell__sort\" @click=${t=>this._handleSortClick(t,e)}> <svg class=\"header-cell__sort-arrow header-cell__sort-arrow--ghost\" viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z\"/> </svg> </span> `;let i={};return\"desc\"===this._sorts[t].sortDirection&&(i={transform:\"rotate(180deg)\"}),j` <span class=\"header-cell__sort\" @click=${t=>this._handleSortClick(t,e)}> <svg class=\"header-cell__sort-arrow\" viewBox=\"0 0 24 24\" fill=\"currentColor\" style=${Re(i)}> <path d=\"M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z\"/> </svg> ${this._sorts.length>1?j` <span class=\"header-cell__sort-priority\">${t+1}</span> `:U} </span> `}_handleAction(e){e.href||this.dispatchEvent(new CustomEvent(\"action\",{detail:{action:e.id},bubbles:!0,composed:!0}))}_handleKqlChange(e,t){const i=e.target.value.trim();if(i){if(t.filter.setKql(i),this.requestUpdate(),!t.filter.isValid())return}else t.filter.clear(),this.requestUpdate();this._page=1,this._fetch()}_handleFilterPanelToggle(e,t){if(e.stopPropagation(),this._filterPanelOpened===t.id)this._filterPanelOpened=null;else{const i=e.currentTarget.getBoundingClientRect();let s=i.left;s+328>window.innerWidth&&(s=window.innerWidth-328),this._filterPanelPos={top:i.bottom+4,left:s},this._filterPanelOpened=t.id,t.facetable?this._filterPanelTab=\"counts\":this._filterPanelTab=\"filter\"}}_handleKqlClear(e){e.filter.clear(),this._page=1,this._fetch()}_handleFilterClear(){const e=this._model.columns.find((e=>e.id===this._filterPanelOpened));e&&(e.filter.clear(),e.facetable&&!e.filterable&&(e.filter.operator=\"in\",e.filter.value=[])),this._filterPanelOpened=null,this._page=1,this._fetch()}_handleFilterTextKeydown(e,t){\"Enter\"===e.key&&(e.preventDefault(),this._handleFilterApply())}_handleOperatorChange(e,t){t.filter.setOperator(e.target.value),this.requestUpdate()}_handleFilterStringChange(e,t){t.filter.setValue(e.target.value),this.requestUpdate()}_handleFilterNumberChange(e,t){t.filter.setValue(Number(e.target.value)),this.requestUpdate()}_handleFilterDateChange(e,t){t.filter.setValue(new Date(e.target.value),\"day\"),this.requestUpdate()}_handleFilterBooleanChange(e,t){t.filter.setValue(\"true\"===e.target.value),this.requestUpdate()}_handleFilterDateStartChange(e,t){t.filter.setStart(new Date(e.target.value),\"day\"),this.requestUpdate()}_handleFilterDateEndChange(e,t){t.filter.setEnd(new Date(e.target.value),\"day\"),this.requestUpdate()}_handleFilterNumberStartChange(e,t){t.filter.setStart(Number(e.target.value)),this.requestUpdate()}_handleFilterNumberEndChange(e,t){t.filter.setEnd(Number(e.target.value)),this.requestUpdate()}_handleFilterListChange(e,t){const i=e.target.value.split(\",\").map((e=>e.trim())).filter((e=>\"\"!==e));\"number\"===t.type?t.filter.setValue(i.map((e=>Number(e)))):t.filter.setValue(i),this.requestUpdate()}_handleFilterApply(){this._filterPanelOpened=null,this._page=1,this._fetch()}_handleFilterPanelTabChange(e){this._filterPanelTab=e.detail.activeTabId}_handleBucketToggle(e,t,i){t.filter.toggle(i.val),this._page=1,this._fetch()}_renderCellContent(e,t,i){const s=t[e.id];if(e.render)return j`<slot name=\"cell-${i}-${e.id}\"></slot>`;if(null==s)return\"\";switch(e.type){case\"number\":return\"currency\"===e.format&&\"number\"==typeof s?s.toLocaleString(\"en-US\",{style:\"currency\",currency:\"USD\"}):String(s);case\"date\":{let e;if(s instanceof Date)e=s;else if(\"string\"==typeof s&&/^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}/.test(s)){const t=s.replace(/(\\d{2}:\\d{2}:\\d{2}):(\\d+)$/,\"$1.$2\").replace(\" \",\"T\")+\"Z\";e=new Date(t)}else e=new Date(s);return e.toLocaleString(void 0,{year:\"numeric\",month:\"short\",day:\"numeric\",hour:\"numeric\",minute:\"2-digit\",timeZone:\"UTC\"})}case\"boolean\":return!0===s?\"Yes\":!1===s?\"No\":\"\";default:return String(s)}}_getHeaderCellClasses(e,t){return{\"header-cell\":!0,\"header-cell--sortable\":!!e.sortable,\"header-cell--align-center\":\"center\"===e.align,\"header-cell--align-right\":\"right\"===e.align,\"header-cell--sticky-left\":\"left\"===e.sticky,\"header-cell--sticky-left-last\":\"left\"===e.sticky&&!this.getDisplayedColumns().slice(t+1).some((e=>\"left\"===e.sticky)),\"header-cell--sticky-right\":\"right\"===e.sticky,\"header-cell--sticky-right-first\":\"right\"===e.sticky&&!this.getDisplayedColumns().slice(0,t).some((e=>\"right\"===e.sticky))}}_getCellClasses(e,t){return{cell:!0,\"cell--actions\":\"actions\"===e.type,\"cell--align-center\":\"center\"===e.align,\"cell--align-right\":\"right\"===e.align,\"cell--sticky-left\":\"left\"===e.sticky,\"cell--sticky-left-last\":\"left\"===e.sticky&&!this.getDisplayedColumns().slice(t+1).some((e=>\"left\"===e.sticky)),\"cell--sticky-right\":\"right\"===e.sticky,\"cell--sticky-right-first\":\"right\"===e.sticky&&!this.getDisplayedColumns().slice(0,t).some((e=>\"right\"===e.sticky))}}_getCellStyle(e,t){const i={};if(\"left\"===e.sticky){let e=0;for(let i=0;i<t;i++){const t=this.getDisplayedColumns()[i];\"left\"===t.sticky&&(e+=parseInt(t.width||\"0\",10))}i.left=`${e}px`}if(\"right\"===e.sticky){let e=0;for(let i=t+1;i<this.getDisplayedColumns().length;i++){const t=this.getDisplayedColumns()[i];\"right\"===t.sticky&&(e+=parseInt(t.width||\"0\",10))}i.right=`${e}px`}return i}_renderPagination(){const e=(this._page-1)*this._pageSize+1,t=Math.min(this._page*this._pageSize,this._totalItems);return j` <div class=\"pagination\"> <span class=\"pagination-icon ${1===this._page?\"pagination-icon--disabled\":\"\"}\" @click=${this.goToPrevPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z\"/></svg> </span> <span class=\"pagination-info\">${e}-${t} of ${this._totalItems}</span> <span class=\"pagination-icon ${this._page===this._totalPages?\"pagination-icon--disabled\":\"\"}\" @click=${this.goToNextPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z\"/></svg> </span> </div> `}_renderCardHeader(){return\"card\"!==this.variant?U:this._model.title||this._model.description?j` <div class=\"card-header\"> ${this._model.title?j`<h2 class=\"card-header__title\">${this._model.title}</h2>`:U} ${this._model.description?j`<p class=\"card-header__description\">${this._model.description}</p>`:U} </div> `:U}_renderHeader(){return!this._model.title&&!this._model.actions?.length&&this._totalPages<=1?U:j` <div class=\"header\"> ${this._model.title&&\"card\"!==this.variant?j`<div class=\"title\">${this._model.title}</div>`:U} ${\"db\"!==this._model.dataSource?.mode||this._model.columns.some((e=>e.searchable))?j` <div class=\"search\"> <!-- TODO: Saved views dropdown <div class=\"views\"> <span>Default View</span> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z\"/></svg> </div> --> <div class=\"search-field\"> <svg class=\"search-icon\" viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z\"/></svg> <input type=\"text\" class=\"search-input\" placeholder=\"Search...\" .value=${this._searchQuery} @input=${this._handleSearch} /> </div> </div> `:j`<div class=\"search\"></div>`} <div class=\"tools\"> ${this._renderPagination()} <span class=\"refresh\" title=\"Refresh\" @click=${()=>this.refresh()}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M480-160q-134 0-227-93t-93-227q0-134 93-227t227-93q69 0 132 28.5T720-690v-110h80v280H520v-80h168q-32-56-87.5-88T480-720q-100 0-170 70t-70 170q0 100 70 170t170 70q77 0 139-44t87-116h84q-28 106-114 173t-196 67Z\"/></svg> </span> <div class=\"column-picker-wrapper\"> <span class=\"header-icon\" title=\"Columns\" @click=${this._toggleColumnPicker}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M121-280v-400q0-33 23.5-56.5T201-760h559q33 0 56.5 23.5T840-680v400q0 33-23.5 56.5T760-200H201q-33 0-56.5-23.5T121-280Zm79 0h133v-400H200v400Zm213 0h133v-400H413v400Zm213 0h133v-400H626v400Z\"/></svg> </span> <div class=\"column-picker ${this._columnPickerOpen?\"open\":\"\"}\"> ${[...this._model.columns].filter((e=>\"actions\"!==e.type)).sort(((e,t)=>(e.label??e.id).localeCompare(t.label??t.id))).map((e=>j` <div class=\"column-picker-item\" @click=${()=>this._toggleColumn(e.id)}> <div class=\"column-picker-checkbox ${this._model.displayedColumns.includes(e.id)?\"checked\":\"\"}\"> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/></svg> </div> <span class=\"column-picker-label\">${e.label??e.id}</span> </div> `))} </div> </div> ${1===this._model.actions?.length?j` <kr-button class=\"actions\" .href=${this._model.actions[0].href} .target=${this._model.actions[0].target} @click=${()=>this._handleAction(this._model.actions[0])} > ${this._model.actions[0].label} </kr-button> `:this._model.actions?.length?j` <kr-button class=\"actions\" .options=${this._model.actions.map((e=>({id:e.id,label:e.label})))} @option-select=${e=>this._handleAction({id:e.detail.id,label:e.detail.label})} > Actions </kr-button> `:U} </div> </div> `}_renderStatus(){return\"loading\"===this._dataState&&0===this._data.length?j`<div class=\"status\">Loading...</div>`:\"error\"===this._dataState&&0===this._data.length?j`<div class=\"status status--error\">Error loading data</div>`:0===this._data.length?j`<div class=\"status\">No data available</div>`:U}_renderFilterPanel(){if(!this._filterPanelOpened)return U;const e=this._model.columns.find((e=>e.id===this._filterPanelOpened));let t=j``;t=\"empty\"===e.filter.operator||\"n_empty\"===e.filter.operator?j` <input type=\"text\" class=\"filter-panel__input\" disabled .value=${e.filter.text} /> `:\"between\"===e.filter.operator&&\"date\"===e.type?j` <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${e.filter.value?.start??null} @change=${t=>this._handleFilterDateStartChange(t,e)} /> <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${e.filter.value?.end??null} @change=${t=>this._handleFilterDateEndChange(t,e)} /> `:\"between\"===e.filter.operator&&\"number\"===e.type?j` <input type=\"number\" class=\"filter-panel__input\" placeholder=\"Start\" .value=${e.filter.value?.start??\"\"} @input=${t=>this._handleFilterNumberStartChange(t,e)} @keydown=${t=>this._handleFilterTextKeydown(t,e)} /> <input type=\"number\" class=\"filter-panel__input\" placeholder=\"End\" .value=${e.filter.value?.end??\"\"} @input=${t=>this._handleFilterNumberEndChange(t,e)} @keydown=${t=>this._handleFilterTextKeydown(t,e)} /> `:\"in\"===e.filter.operator||\"n_in\"===e.filter.operator?j` <textarea class=\"filter-panel__textarea\" rows=\"3\" placeholder=\"Values (comma-separated)\" .value=${e.filter.text} @input=${t=>this._handleFilterListChange(t,e)} @keydown=${t=>this._handleFilterTextKeydown(t,e)} ></textarea> `:\"boolean\"===e.type?j` <kr-select-field placeholder=\"Value\" .value=${String(e.filter.value??\"\")} @change=${t=>this._handleFilterBooleanChange(t,e)} > <kr-select-option value=\"true\">Yes</kr-select-option> <kr-select-option value=\"false\">No</kr-select-option> </kr-select-field> `:\"date\"===e.type?j` <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${e.filter.value} @change=${t=>this._handleFilterDateChange(t,e)} /> `:\"number\"===e.type?j` <input type=\"number\" class=\"filter-panel__input\" placeholder=\"Value\" min=\"0\" .value=${e.filter.text} @input=${t=>this._handleFilterNumberChange(t,e)} @keydown=${t=>this._handleFilterTextKeydown(t,e)} /> `:j` <input type=\"text\" class=\"filter-panel__input\" placeholder=\"Value\" .value=${e.filter.text} @input=${t=>this._handleFilterStringChange(t,e)} @keydown=${t=>this._handleFilterTextKeydown(t,e)} /> `;const i=j` <div class=\"filter-panel__content\"> <kr-select-field .value=${e.filter.operator} @change=${t=>this._handleOperatorChange(t,e)} > ${st(e.type).map((e=>j` <kr-select-option value=${e.key}>${e.label}</kr-select-option> `))} </kr-select-field> ${t} </div> `,s=this._buckets.get(e.id)||[];let o,r;return o=s.length?j` <div class=\"buckets\"> ${s.map((t=>{let i=\"(Empty)\";null!==t.val&&void 0!==t.val&&(i=\"boolean\"===e.type?!0===t.val||\"true\"===t.val?\"Yes\":\"No\":String(t.val));let s=e.filter.has(t.val);\"n_in\"===e.filter.operator&&(s=!s);let o=U;return s&&(o=j` <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/> </svg> `),j` <div class=\"bucket\" @click=${i=>this._handleBucketToggle(i,e,t)} > <div class=${we({bucket__checkbox:!0,\"bucket__checkbox--checked\":s})}> ${o} </div> <span class=\"bucket__label\">${i}</span> <span class=\"bucket__count\">${t.count}</span> </div> `}))} </div> `:j`<div class=\"bucket-empty\">No data</div>`,r=e.facetable&&e.filterable?j` <kr-tab-group size=\"small\" active-tab-id=${this._filterPanelTab} @tab-change=${e=>this._handleFilterPanelTabChange(e)} > <kr-tab id=\"filter\" label=\"Filter\"> ${i} </kr-tab> <kr-tab id=\"counts\" label=\"Counts\"> ${o} </kr-tab> </kr-tab-group> `:e.facetable?o:i,j` <div class=\"filter-panel\" style=${Re({top:this._filterPanelPos.top+\"px\",left:this._filterPanelPos.left+\"px\"})} > ${r} <div class=\"filter-panel__actions\"> <kr-button variant=\"outline\" color=\"secondary\" size=\"small\" @click=${this._handleFilterClear}> Clear </kr-button> <kr-button size=\"small\" @click=${this._handleFilterApply}> Apply </kr-button> </div> </div> `}_renderFilterRow(){const e=this.getDisplayedColumns();return e.some((e=>e.filterable||e.facetable))?j` <div class=\"filter-row\"> ${e.map(((t,i)=>t.filterable||t.facetable?j` <div class=${we({\"filter-cell\":!0,\"filter-cell--sticky-left\":\"left\"===t.sticky,\"filter-cell--sticky-right\":\"right\"===t.sticky,\"filter-cell--sticky-right-first\":\"right\"===t.sticky&&!e.slice(0,i).some((e=>\"right\"===e.sticky))})} style=${Re(this._getCellStyle(t,i))} > <div class=\"filter-cell__wrapper\"> <input type=\"text\" class=${we({\"filter-cell__input\":!0,\"filter-cell__input--invalid\":!t.filter.isValid()})} .value=${t.filter.kql} @change=${e=>this._handleKqlChange(e,t)} /> ${t.filter?.kql?.length>0?j` <button class=\"filter-cell__clear\" @click=${()=>this._handleKqlClear(t)} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/> </svg> </button> `:U} <button class=${we({\"filter-cell__advanced\":!0,\"filter-cell__advanced--opened\":this._filterPanelOpened===t.id})} @click=${e=>this._handleFilterPanelToggle(e,t)} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z\"/> </svg> </button> </div> </div> `:j`<div class=${we({\"filter-cell\":!0,\"filter-cell--sticky-left\":\"left\"===t.sticky,\"filter-cell--sticky-right\":\"right\"===t.sticky,\"filter-cell--sticky-right-first\":\"right\"===t.sticky&&!e.slice(0,i).some((e=>\"right\"===e.sticky))})} style=${Re(this._getCellStyle(t,i))} ></div>`))} </div> `:U}_renderTable(){return j` <div class=\"wrapper\"> <div class=\"overlay-left\"></div> <div class=\"overlay-right\"></div> ${this._renderStatus()} <div class=\"content\" @scroll=${this._handleScroll}> <div class=\"table\" style=\"grid-template-columns: ${this._getGridTemplateColumns()}\"> <div class=\"header-row\"> ${this.getDisplayedColumns().map(((e,t)=>j` <div class=${we(this._getHeaderCellClasses(e,t))} style=${Re(this._getCellStyle(e,t))} data-column-id=${e.id} > <span class=\"header-cell__label\">${e.label??e.id}</span> ${this._renderSortIndicator(e)} ${!1!==e.resizable?j`<div class=\"header-cell__resize\" @mousedown=${t=>this._handleResizeStart(t,e.id)} ></div>`:U} </div> `))} </div> ${this._renderFilterRow()} ${this._data.map(((e,t)=>{const i=this.getDisplayedColumns().map(((i,s)=>j` <div class=${we(this._getCellClasses(i,s))} style=${Re(this._getCellStyle(i,s))} data-column-id=${i.id} > ${this._renderCellContent(i,e,t)} </div> `));return this._model.rowHref?j` <a href=${this._model.rowHref(e)} draggable=\"false\" class=${we({row:!0,\"row--clickable\":!0,\"row--link\":!0})} @mousedown=${()=>this._handleRowMouseDown()} @click=${i=>this._handleRowClick(i,e,t)} >${i}</a> `:j` <div class=${we({row:!0,\"row--clickable\":!!this._model.rowClickable})} @mousedown=${()=>this._handleRowMouseDown()} @click=${i=>this._handleRowClick(i,e,t)} >${i}</div> `}))} </div> </div> </div> `}render(){return this._model.columns.length?j` ${this._renderCardHeader()} ${this._renderHeader()} ${this._renderTable()} ${this._renderFilterPanel()} `:j`<slot></slot>`}}"
|
|
1267
|
+
"default": "class extends le{constructor(){super(...arguments),this._scrollStyle=\"edge\",this._data=[],this._dataState=\"idle\",this._page=1,this._pageSize=50,this._totalItems=0,this._totalPages=0,this._searchQuery=\"\",this._canScrollLeft=!1,this._canScrollRight=!1,this._canScrollHorizontal=!1,this._columnPickerOpen=!1,this._filterPanelOpened=null,this._filterPanelTab=\"filter\",this._buckets=new Map,this._filterPanelPos={top:0,left:0},this._sorts=[],this._resizing=null,this._resizeObserver=null,this._searchPositionLocked=!1,this._columnWidthsLocked=!1,this._model=new ut,this.def={columns:[]},this.variant=\"default\",this._handleClickOutside=e=>{const t=e.composedPath();if(this._columnPickerOpen){const e=this.shadowRoot?.querySelector(\".column-picker-wrapper\");e&&!t.includes(e)&&(this._columnPickerOpen=!1)}this._filterPanelOpened&&(t.some((e=>e.classList?.contains(\"filter-panel\")))||this._handleFilterApply())},this._handleResizeMove=e=>{if(!this._resizing)return;const t=this._model.columns.find((e=>e.id===this._resizing.columnId));if(t){const i=this._resizing.startWidth+(e.clientX-this._resizing.startX);t.width=`${Math.min(900,Math.max(50,i))}px`,this.requestUpdate()}},this._handleResizeEnd=()=>{this._resizing=null,document.removeEventListener(\"mousemove\",this._handleResizeMove),document.removeEventListener(\"mouseup\",this._handleResizeEnd)}}connectedCallback(){super.connectedCallback(),this.classList.toggle(\"kr-table--scroll-overlay\",\"overlay\"===this._scrollStyle),this.classList.toggle(\"kr-table--scroll-edge\",\"edge\"===this._scrollStyle),this._fetch(),this._initRefresh(),document.addEventListener(\"click\",this._handleClickOutside),this._resizeObserver=new ResizeObserver((()=>{this._searchPositionLocked=!1,this._updateSearchPosition()})),this._resizeObserver.observe(this)}disconnectedCallback(){super.disconnectedCallback(),clearInterval(this._refreshTimer),document.removeEventListener(\"click\",this._handleClickOutside),this._resizeObserver?.disconnect()}willUpdate(e){e.has(\"def\")&&(this._columnWidthsLocked=!1,this._model=new ut,this.def.title&&(this._model.title=this.def.title),this.def.description&&(this._model.description=this.def.description),this.def.actions&&(this._model.actions=this.def.actions),this.def.data&&(this._model.data=this.def.data),this.def.dataSource&&(this._model.dataSource=this.def.dataSource),\"number\"==typeof this.def.refreshInterval&&(this._model.refreshInterval=this.def.refreshInterval),\"number\"==typeof this.def.pageSize&&(this._model.pageSize=this.def.pageSize,this._pageSize=this.def.pageSize),this.def.rowClickable&&(this._model.rowClickable=this.def.rowClickable),this.def.rowHref&&(this._model.rowHref=this.def.rowHref),this._sorts=[],this._model.columns=this.def.columns.map((e=>{const t={...e,filter:null};return t.type||(t.type=\"string\"),e.sort&&this._sorts.push({sortBy:e.id,sortDirection:e.sort}),\"actions\"===t.type?(t.label=e.label??\"\",t.sticky=\"right\",t.resizable=!1,t):((e.filterable||e.facetable)&&(t.filter=new ct,t.filter.field=e.id,t.filter.type=t.type,e.filter?(t.filter.setOperator(e.filter.operator),t.filter.setValue(e.filter.value)):e.facetable&&!e.filterable?(t.filter.operator=\"in\",t.filter.value=[]):\"string\"===t.filter.type&&(t.filter.operator=\"contains\")),t)})),this.def.displayedColumns?this._model.displayedColumns=this.def.displayedColumns:this._model.displayedColumns=this._model.columns.map((e=>e.id)),this._fetch(),this._initRefresh())}updated(e){this.classList.toggle(\"kr-table--card\",\"card\"===this.variant),this._updateScrollFlags(),this._syncSlottedContent(),this._lockColumnWidths()}_lockColumnWidths(){if(this._columnWidthsLocked||0===this._data.length)return;const e=this.shadowRoot?.querySelectorAll(\".header-row > .header-cell\");if(!e)return;const t=this.getDisplayedColumns();e.forEach(((e,i)=>{const s=e.offsetWidth;i<t.length&&!t[i].width&&\"actions\"!==t[i].type&&s>0&&(t[i].width=`${s}px`,this._columnWidthsLocked=!0)}))}_syncSlottedContent(){const e=this.getDisplayedColumns().filter((e=>e.render));e.length&&(this.querySelectorAll('[slot^=\"cell-\"]').forEach((e=>e.remove())),this._data.forEach(((t,i)=>{e.forEach((e=>{const s=e.render(t);if(!s)return;const r=document.createElement(\"span\");r.slot=`cell-${i}-${e.id}`,\"actions\"===e.type&&(r.style.display=\"flex\",r.style.gap=\"8px\"),\"string\"==typeof s?r.innerHTML=s:re(s,r),this.appendChild(r)}))})))}refresh(){this._fetch()}goToPrevPage(){this._page>1&&(this._page--,this._fetch())}goToNextPage(){this._page<this._totalPages&&(this._page++,this._fetch())}goToPage(e){e>=1&&e<=this._totalPages&&(this._page=e,this._fetch())}_toSolrData(){const e={page:this._page-1,size:this._pageSize,sorts:this._sorts,filterFields:[],queryFields:[],facetFields:[]};for(const t of this._model.columns){if(!t.filter||t.filter.isEmpty()||!t.filter.isValid())continue;const i=t.filter.toSolrData();!t.facetable||\"in\"!==t.filter.operator&&\"n_in\"!==t.filter.operator||(i.tagged=!0),e.filterFields.push(i)}for(const t of this._model.columns)t.facetable&&e.facetFields.push({name:t.id,type:\"FIELD\",limit:100,sort:\"count\",minimumCount:1});return this._searchQuery?.trim().length&&e.queryFields.push({name:\"_text_\",operation:\"IS\",value:lt(this._searchQuery,!1)}),e}_toDbParams(){const e={page:this._page-1,size:this._pageSize,sorts:this._sorts,filterFields:[],queryFields:[],facetFields:[]};for(const t of this._model.columns)t.filter&&!t.filter.isEmpty()&&t.filter.isValid()&&e.filterFields.push(t.filter.toDbParams());return this._searchQuery?.trim().length&&this._model.columns.filter((e=>e.searchable)).forEach((t=>{e.queryFields.push({name:t.id,operation:\"CONTAINS\",value:this._searchQuery,and:!1})})),e}_fetch(){if(this._model.data)return this._data=this._model.data,this._totalItems=this._model.data.length,this._totalPages=Math.ceil(this._model.data.length/this._pageSize),void(this._dataState=\"success\");if(!this._model.dataSource)return;let e;this._dataState=\"loading\",e=\"db\"===this._model.dataSource.mode?this._toDbParams():this._toSolrData(),this._model.dataSource.fetch(e).then((e=>{switch(this._model.dataSource?.mode){case\"opensearch\":throw Error(\"Opensearch not supported yet\");case\"db\":{const t=e;this._data=t.data.content,this._totalItems=t.data.totalElements,this._totalPages=t.data.totalPages,this._pageSize=t.data.size;break}default:{const t=e;this._data=t.data.content,this._totalItems=t.data.totalElements,this._totalPages=t.data.totalPages,this._pageSize=t.data.size,this._parseFacetResults(t)}}this._dataState=\"success\",this._updateSearchPosition()})).catch((e=>{this._dataState=\"error\",Ke.show({message:e instanceof Error?e.message:\"Failed to load data\",type:\"error\"})}))}_parseFacetResults(e){if(e.data.facetFields){for(const t of this._model.columns){if(!t.facetable)continue;const i=e.data.facetFields[t.id];if(!i){this._buckets.set(t.id,[]);continue}const s=[];for(const e of i){let i=e.name;\"boolean\"===t.type&&\"string\"==typeof e.name&&(\"true\"===e.name?i=!0:\"false\"===e.name&&(i=!1)),null===e.name&&e.count>0&&s.unshift({val:null,count:e.count}),null!==e.name&&s.push({val:i,count:e.count})}if(t.filter&&(\"in\"===t.filter.operator||\"n_in\"===t.filter.operator)&&Array.isArray(t.filter.value))for(const e of t.filter.value)s.some((t=>t.val===e))||s.push({val:e,count:0});this._buckets.set(t.id,s)}this._buckets=new Map(this._buckets)}}_initRefresh(){clearInterval(this._refreshTimer),this._model.refreshInterval&&this._model.refreshInterval>0&&(this._refreshTimer=window.setInterval((()=>{this._fetch()}),this._model.refreshInterval))}_handleSearch(e){const t=e.target;this._searchQuery=t.value,this._page=1,this._fetch()}_getGridTemplateColumns(){return this.getDisplayedColumns().map((e=>e.width?e.width:\"actions\"===e.type?\"max-content\":\"minmax(80px, auto)\")).join(\" \")}_updateSearchPosition(){if(this._searchPositionLocked)return;if(\"card\"===this.variant)return;const e=this.shadowRoot?.querySelector(\".search\"),t=e?.querySelector(\".search-field\");e&&t&&(e.style.justifyContent=\"center\",t.style.marginLeft=\"\",requestAnimationFrame((()=>{const i=e.getBoundingClientRect(),s=t.getBoundingClientRect().left-i.left;e.style.justifyContent=\"flex-start\",t.style.marginLeft=`${s}px`,this._searchPositionLocked=!0})))}_toggleColumnPicker(){this._columnPickerOpen=!this._columnPickerOpen}_toggleColumn(e){this._model.displayedColumns.includes(e)?this._model.displayedColumns=this._model.displayedColumns.filter((t=>t!==e)):this._model.displayedColumns=[...this._model.displayedColumns,e],this.requestUpdate()}_handleRowMouseDown(){(this._model.rowClickable||this._model.rowHref)&&window.getSelection()?.removeAllRanges()}_handleRowClick(e,t,i){if(!this._model.rowClickable&&!this._model.rowHref)return;const s=window.getSelection();s&&s.toString().length>0?e.preventDefault():this.dispatchEvent(new CustomEvent(\"row-click\",{detail:{row:t,rowIndex:i},bubbles:!0,composed:!0}))}getDisplayedColumns(){return this._model.displayedColumns.map((e=>this._model.columns.find((t=>t.id===e)))).sort(((e,t)=>\"actions\"===e.type&&\"actions\"!==t.type?1:\"actions\"!==e.type&&\"actions\"===t.type?-1:0))}_handleScroll(e){const t=e.target;this._canScrollLeft=t.scrollLeft>0,this._canScrollRight=t.scrollLeft<t.scrollWidth-t.clientWidth-1}_updateScrollFlags(){const e=this.shadowRoot?.querySelector(\".content\");e&&(this._canScrollLeft=e.scrollLeft>0,this._canScrollRight=e.scrollWidth>e.clientWidth&&e.scrollLeft<e.scrollWidth-e.clientWidth-1,this._canScrollHorizontal=e.scrollWidth>e.clientWidth),this.classList.toggle(\"kr-table--scroll-left-available\",this._canScrollLeft),this.classList.toggle(\"kr-table--scroll-right-available\",this._canScrollRight),this.classList.toggle(\"kr-table--scroll-horizontal-available\",this._canScrollHorizontal),this.classList.toggle(\"kr-table--sticky-left\",this.getDisplayedColumns().some((e=>\"left\"===e.sticky))),this.classList.toggle(\"kr-table--sticky-right\",this.getDisplayedColumns().some((e=>\"right\"===e.sticky)))}_handleResizeStart(e,t){e.preventDefault();const i=this.shadowRoot?.querySelector(`.header-cell[data-column-id=\"${t}\"]`);this._resizing={columnId:t,startX:e.clientX,startWidth:i?.offsetWidth||200},document.addEventListener(\"mousemove\",this._handleResizeMove),document.addEventListener(\"mouseup\",this._handleResizeEnd)}_handleSortClick(e,t){if(e.shiftKey){const e=this._sorts.findIndex((e=>e.sortBy===t.id));if(-1===e)this._sorts.push({sortBy:t.id,sortDirection:\"asc\"});else{const t=this._sorts[e];\"asc\"===t.sortDirection?t.sortDirection=\"desc\":this._sorts.splice(e,1)}this.requestUpdate()}else{let e=null;1===this._sorts.length&&(e=this._sorts.find((e=>e.sortBy===t.id))),e?\"asc\"===e.sortDirection?this._sorts=[{sortBy:t.id,sortDirection:\"desc\"}]:this._sorts=[]:this._sorts=[{sortBy:t.id,sortDirection:\"asc\"}]}this._page=1,this._fetch()}_renderSortIndicator(e){if(!e.sortable)return F;const t=this._sorts.findIndex((t=>t.sortBy===e.id));if(-1===t)return j` <span class=\"header-cell__sort\" @click=${t=>this._handleSortClick(t,e)}> <svg class=\"header-cell__sort-arrow header-cell__sort-arrow--ghost\" viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z\"/> </svg> </span> `;let i={};return\"desc\"===this._sorts[t].sortDirection&&(i={transform:\"rotate(180deg)\"}),j` <span class=\"header-cell__sort\" @click=${t=>this._handleSortClick(t,e)}> <svg class=\"header-cell__sort-arrow\" viewBox=\"0 0 24 24\" fill=\"currentColor\" style=${Le(i)}> <path d=\"M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z\"/> </svg> ${this._sorts.length>1?j` <span class=\"header-cell__sort-priority\">${t+1}</span> `:F} </span> `}_handleAction(e){e.href||this.dispatchEvent(new CustomEvent(\"action\",{detail:{action:e.id},bubbles:!0,composed:!0}))}_handleKqlChange(e,t){const i=e.target.value.trim();if(i){if(t.filter.setKql(i),this.requestUpdate(),!t.filter.isValid())return}else t.filter.clear(),this.requestUpdate();this._page=1,this._fetch()}_handleFilterPanelToggle(e,t){if(e.stopPropagation(),this._filterPanelOpened===t.id)this._filterPanelOpened=null;else{const i=e.currentTarget.getBoundingClientRect();let s=i.left;s+328>window.innerWidth&&(s=window.innerWidth-328),this._filterPanelPos={top:i.bottom+4,left:s},this._filterPanelOpened=t.id,t.facetable?this._filterPanelTab=\"counts\":this._filterPanelTab=\"filter\"}}_handleKqlClear(e){e.filter.clear(),this._page=1,this._fetch()}_handleFilterClear(){const e=this._model.columns.find((e=>e.id===this._filterPanelOpened));e&&(e.filter.clear(),e.facetable&&!e.filterable&&(e.filter.operator=\"in\",e.filter.value=[])),this._filterPanelOpened=null,this._page=1,this._fetch()}_handleFilterTextKeydown(e,t){\"Enter\"===e.key&&(e.preventDefault(),this._handleFilterApply())}_handleOperatorChange(e,t){t.filter.setOperator(e.target.value),this.requestUpdate()}_handleFilterStringChange(e,t){t.filter.setValue(e.target.value),this.requestUpdate()}_handleFilterNumberChange(e,t){t.filter.setValue(Number(e.target.value)),this.requestUpdate()}_handleFilterDateChange(e,t){t.filter.setValue(new Date(e.target.value),\"day\"),this.requestUpdate()}_handleFilterBooleanChange(e,t){t.filter.setValue(\"true\"===e.target.value),this.requestUpdate()}_handleFilterDateStartChange(e,t){t.filter.setStart(new Date(e.target.value),\"day\"),this.requestUpdate()}_handleFilterDateEndChange(e,t){t.filter.setEnd(new Date(e.target.value),\"day\"),this.requestUpdate()}_handleFilterNumberStartChange(e,t){t.filter.setStart(Number(e.target.value)),this.requestUpdate()}_handleFilterNumberEndChange(e,t){t.filter.setEnd(Number(e.target.value)),this.requestUpdate()}_handleFilterListChange(e,t){const i=e.target.value.split(\",\").map((e=>e.trim())).filter((e=>\"\"!==e));\"number\"===t.type?t.filter.setValue(i.map((e=>Number(e)))):t.filter.setValue(i),this.requestUpdate()}_handleFilterApply(){this._filterPanelOpened=null,this._page=1,this._fetch()}_handleFilterPanelTabChange(e){this._filterPanelTab=e.detail.activeTabId}_handleBucketToggle(e,t,i){t.filter.toggle(i.val),this._page=1,this._fetch()}_renderCellContent(e,t,i){const s=t[e.id];if(e.render)return j`<slot name=\"cell-${i}-${e.id}\"></slot>`;if(null==s)return\"\";switch(e.type){case\"number\":return\"currency\"===e.format&&\"number\"==typeof s?s.toLocaleString(\"en-US\",{style:\"currency\",currency:\"USD\"}):String(s);case\"date\":{let e;if(s instanceof Date)e=s;else if(\"string\"==typeof s&&/^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}/.test(s)){const t=s.replace(/(\\d{2}:\\d{2}:\\d{2}):(\\d+)$/,\"$1.$2\").replace(\" \",\"T\")+\"Z\";e=new Date(t)}else e=new Date(s);return e.toLocaleString(void 0,{year:\"numeric\",month:\"short\",day:\"numeric\",hour:\"numeric\",minute:\"2-digit\",timeZone:\"UTC\"})}case\"boolean\":return!0===s?\"Yes\":!1===s?\"No\":\"\";default:return String(s)}}_getHeaderCellClasses(e,t){return{\"header-cell\":!0,\"header-cell--sortable\":!!e.sortable,\"header-cell--align-center\":\"center\"===e.align,\"header-cell--align-right\":\"right\"===e.align,\"header-cell--sticky-left\":\"left\"===e.sticky,\"header-cell--sticky-left-last\":\"left\"===e.sticky&&!this.getDisplayedColumns().slice(t+1).some((e=>\"left\"===e.sticky)),\"header-cell--sticky-right\":\"right\"===e.sticky,\"header-cell--sticky-right-first\":\"right\"===e.sticky&&!this.getDisplayedColumns().slice(0,t).some((e=>\"right\"===e.sticky))}}_getCellClasses(e,t){return{cell:!0,\"cell--actions\":\"actions\"===e.type,\"cell--align-center\":\"center\"===e.align,\"cell--align-right\":\"right\"===e.align,\"cell--sticky-left\":\"left\"===e.sticky,\"cell--sticky-left-last\":\"left\"===e.sticky&&!this.getDisplayedColumns().slice(t+1).some((e=>\"left\"===e.sticky)),\"cell--sticky-right\":\"right\"===e.sticky,\"cell--sticky-right-first\":\"right\"===e.sticky&&!this.getDisplayedColumns().slice(0,t).some((e=>\"right\"===e.sticky))}}_getCellStyle(e,t){const i={};if(\"left\"===e.sticky){let e=0;for(let i=0;i<t;i++){const t=this.getDisplayedColumns()[i];\"left\"===t.sticky&&(e+=parseInt(t.width||\"0\",10))}i.left=`${e}px`}if(\"right\"===e.sticky){let e=0;for(let i=t+1;i<this.getDisplayedColumns().length;i++){const t=this.getDisplayedColumns()[i];\"right\"===t.sticky&&(e+=parseInt(t.width||\"0\",10))}i.right=`${e}px`}return i}_renderPagination(){const e=(this._page-1)*this._pageSize+1,t=Math.min(this._page*this._pageSize,this._totalItems);return j` <div class=\"pagination\"> <span class=\"pagination-icon ${1===this._page?\"pagination-icon--disabled\":\"\"}\" @click=${this.goToPrevPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z\"/></svg> </span> <span class=\"pagination-info\">${e}-${t} of ${this._totalItems}</span> <span class=\"pagination-icon ${this._page===this._totalPages?\"pagination-icon--disabled\":\"\"}\" @click=${this.goToNextPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z\"/></svg> </span> </div> `}_renderCardHeader(){return\"card\"!==this.variant?F:this._model.title||this._model.description?j` <div class=\"card-header\"> ${this._model.title?j`<h2 class=\"card-header__title\">${this._model.title}</h2>`:F} ${this._model.description?j`<p class=\"card-header__description\">${this._model.description}</p>`:F} </div> `:F}_renderHeader(){return!this._model.title&&!this._model.actions?.length&&this._totalPages<=1?F:j` <div class=\"header\"> ${this._model.title&&\"card\"!==this.variant?j`<div class=\"title\">${this._model.title}</div>`:F} ${\"db\"!==this._model.dataSource?.mode||this._model.columns.some((e=>e.searchable))?j` <div class=\"search\"> <!-- TODO: Saved views dropdown <div class=\"views\"> <span>Default View</span> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z\"/></svg> </div> --> <div class=\"search-field\"> <svg class=\"search-icon\" viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z\"/></svg> <input type=\"text\" class=\"search-input\" placeholder=\"Search...\" .value=${this._searchQuery} @input=${this._handleSearch} /> </div> </div> `:j`<div class=\"search\"></div>`} <div class=\"tools\"> ${this._renderPagination()} <span class=\"refresh\" title=\"Refresh\" @click=${()=>this.refresh()}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M480-160q-134 0-227-93t-93-227q0-134 93-227t227-93q69 0 132 28.5T720-690v-110h80v280H520v-80h168q-32-56-87.5-88T480-720q-100 0-170 70t-70 170q0 100 70 170t170 70q77 0 139-44t87-116h84q-28 106-114 173t-196 67Z\"/></svg> </span> <div class=\"column-picker-wrapper\"> <span class=\"header-icon\" title=\"Columns\" @click=${this._toggleColumnPicker}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M121-280v-400q0-33 23.5-56.5T201-760h559q33 0 56.5 23.5T840-680v400q0 33-23.5 56.5T760-200H201q-33 0-56.5-23.5T121-280Zm79 0h133v-400H200v400Zm213 0h133v-400H413v400Zm213 0h133v-400H626v400Z\"/></svg> </span> <div class=\"column-picker ${this._columnPickerOpen?\"open\":\"\"}\"> ${[...this._model.columns].filter((e=>\"actions\"!==e.type)).sort(((e,t)=>(e.label??e.id).localeCompare(t.label??t.id))).map((e=>j` <div class=\"column-picker-item\" @click=${()=>this._toggleColumn(e.id)}> <div class=\"column-picker-checkbox ${this._model.displayedColumns.includes(e.id)?\"checked\":\"\"}\"> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/></svg> </div> <span class=\"column-picker-label\">${e.label??e.id}</span> </div> `))} </div> </div> ${1===this._model.actions?.length?j` <kr-button class=\"actions\" .href=${this._model.actions[0].href} .target=${this._model.actions[0].target} @click=${()=>this._handleAction(this._model.actions[0])} > ${this._model.actions[0].label} </kr-button> `:this._model.actions?.length?j` <kr-button class=\"actions\" .options=${this._model.actions.map((e=>({id:e.id,label:e.label})))} @option-select=${e=>this._handleAction({id:e.detail.id,label:e.detail.label})} > Actions </kr-button> `:F} </div> </div> `}_renderStatus(){return\"loading\"===this._dataState&&0===this._data.length?j`<div class=\"status\">Loading...</div>`:\"error\"===this._dataState&&0===this._data.length?j`<div class=\"status status--error\">Error loading data</div>`:0===this._data.length?j`<div class=\"status\">No data available</div>`:F}_renderFilterPanel(){if(!this._filterPanelOpened)return F;const e=this._model.columns.find((e=>e.id===this._filterPanelOpened));let t=j``;t=\"empty\"===e.filter.operator||\"n_empty\"===e.filter.operator?j` <input type=\"text\" class=\"filter-panel__input\" disabled .value=${e.filter.text} /> `:\"between\"===e.filter.operator&&\"date\"===e.type?j` <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${e.filter.value?.start??null} @change=${t=>this._handleFilterDateStartChange(t,e)} /> <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${e.filter.value?.end??null} @change=${t=>this._handleFilterDateEndChange(t,e)} /> `:\"between\"===e.filter.operator&&\"number\"===e.type?j` <input type=\"number\" class=\"filter-panel__input\" placeholder=\"Start\" .value=${e.filter.value?.start??\"\"} @input=${t=>this._handleFilterNumberStartChange(t,e)} @keydown=${t=>this._handleFilterTextKeydown(t,e)} /> <input type=\"number\" class=\"filter-panel__input\" placeholder=\"End\" .value=${e.filter.value?.end??\"\"} @input=${t=>this._handleFilterNumberEndChange(t,e)} @keydown=${t=>this._handleFilterTextKeydown(t,e)} /> `:\"in\"===e.filter.operator||\"n_in\"===e.filter.operator?j` <textarea class=\"filter-panel__textarea\" rows=\"3\" placeholder=\"Values (comma-separated)\" .value=${e.filter.text} @input=${t=>this._handleFilterListChange(t,e)} @keydown=${t=>this._handleFilterTextKeydown(t,e)} ></textarea> `:\"boolean\"===e.type?j` <kr-select-field placeholder=\"Value\" .value=${String(e.filter.value??\"\")} @change=${t=>this._handleFilterBooleanChange(t,e)} > <kr-select-option value=\"true\">Yes</kr-select-option> <kr-select-option value=\"false\">No</kr-select-option> </kr-select-field> `:\"date\"===e.type?j` <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${e.filter.value} @change=${t=>this._handleFilterDateChange(t,e)} /> `:\"number\"===e.type?j` <input type=\"number\" class=\"filter-panel__input\" placeholder=\"Value\" min=\"0\" .value=${e.filter.text} @input=${t=>this._handleFilterNumberChange(t,e)} @keydown=${t=>this._handleFilterTextKeydown(t,e)} /> `:j` <input type=\"text\" class=\"filter-panel__input\" placeholder=\"Value\" .value=${e.filter.text} @input=${t=>this._handleFilterStringChange(t,e)} @keydown=${t=>this._handleFilterTextKeydown(t,e)} /> `;const i=j` <div class=\"filter-panel__content\"> <kr-select-field .value=${e.filter.operator} @change=${t=>this._handleOperatorChange(t,e)} > ${st(e.type).map((e=>j` <kr-select-option value=${e.key}>${e.label}</kr-select-option> `))} </kr-select-field> ${t} </div> `,s=this._buckets.get(e.id)||[];let r,o;return r=s.length?j` <div class=\"buckets\"> ${s.map((t=>{let i=\"(Empty)\";null!==t.val&&void 0!==t.val&&(i=\"boolean\"===e.type?!0===t.val||\"true\"===t.val?\"Yes\":\"No\":String(t.val));let s=e.filter.has(t.val);\"n_in\"===e.filter.operator&&(s=!s);let r=F;return s&&(r=j` <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/> </svg> `),j` <div class=\"bucket\" @click=${i=>this._handleBucketToggle(i,e,t)} > <div class=${we({bucket__checkbox:!0,\"bucket__checkbox--checked\":s})}> ${r} </div> <span class=\"bucket__label\">${i}</span> <span class=\"bucket__count\">${t.count}</span> </div> `}))} </div> `:j`<div class=\"bucket-empty\">No data</div>`,o=e.facetable&&e.filterable?j` <kr-tab-group size=\"small\" active-tab-id=${this._filterPanelTab} @tab-change=${e=>this._handleFilterPanelTabChange(e)} > <kr-tab id=\"filter\" label=\"Filter\"> ${i} </kr-tab> <kr-tab id=\"counts\" label=\"Counts\"> ${r} </kr-tab> </kr-tab-group> `:e.facetable?r:i,j` <div class=\"filter-panel\" style=${Le({top:this._filterPanelPos.top+\"px\",left:this._filterPanelPos.left+\"px\"})} > ${o} <div class=\"filter-panel__actions\"> <kr-button variant=\"outline\" color=\"secondary\" size=\"small\" @click=${this._handleFilterClear}> Clear </kr-button> <kr-button size=\"small\" @click=${this._handleFilterApply}> Apply </kr-button> </div> </div> `}_renderFilterRow(){const e=this.getDisplayedColumns();return e.some((e=>e.filterable||e.facetable))?j` <div class=\"filter-row\"> ${e.map(((t,i)=>t.filterable||t.facetable?j` <div class=${we({\"filter-cell\":!0,\"filter-cell--sticky-left\":\"left\"===t.sticky,\"filter-cell--sticky-right\":\"right\"===t.sticky,\"filter-cell--sticky-right-first\":\"right\"===t.sticky&&!e.slice(0,i).some((e=>\"right\"===e.sticky))})} style=${Le(this._getCellStyle(t,i))} > <div class=\"filter-cell__wrapper\"> <input type=\"text\" class=${we({\"filter-cell__input\":!0,\"filter-cell__input--invalid\":!t.filter.isValid()})} .value=${t.filter.kql} @change=${e=>this._handleKqlChange(e,t)} /> ${t.filter?.kql?.length>0?j` <button class=\"filter-cell__clear\" @click=${()=>this._handleKqlClear(t)} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/> </svg> </button> `:F} <button class=${we({\"filter-cell__advanced\":!0,\"filter-cell__advanced--opened\":this._filterPanelOpened===t.id})} @click=${e=>this._handleFilterPanelToggle(e,t)} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z\"/> </svg> </button> </div> </div> `:j`<div class=${we({\"filter-cell\":!0,\"filter-cell--sticky-left\":\"left\"===t.sticky,\"filter-cell--sticky-right\":\"right\"===t.sticky,\"filter-cell--sticky-right-first\":\"right\"===t.sticky&&!e.slice(0,i).some((e=>\"right\"===e.sticky))})} style=${Le(this._getCellStyle(t,i))} ></div>`))} </div> `:F}_renderTable(){return j` <div class=\"wrapper\"> <div class=\"overlay-left\"></div> <div class=\"overlay-right\"></div> ${this._renderStatus()} <div class=\"content\" @scroll=${this._handleScroll}> <div class=\"table\" style=\"grid-template-columns: ${this._getGridTemplateColumns()}\"> <div class=\"header-row\"> ${this.getDisplayedColumns().map(((e,t)=>j` <div class=${we(this._getHeaderCellClasses(e,t))} style=${Le(this._getCellStyle(e,t))} data-column-id=${e.id} > <span class=\"header-cell__label\">${e.label??e.id}</span> ${this._renderSortIndicator(e)} ${!1!==e.resizable?j`<div class=\"header-cell__resize\" @mousedown=${t=>this._handleResizeStart(t,e.id)} ></div>`:F} </div> `))} </div> ${this._renderFilterRow()} ${this._data.map(((e,t)=>{const i=this.getDisplayedColumns().map(((i,s)=>j` <div class=${we(this._getCellClasses(i,s))} style=${Le(this._getCellStyle(i,s))} data-column-id=${i.id} > ${this._renderCellContent(i,e,t)} </div> `));return this._model.rowHref?j` <a href=${this._model.rowHref(e)} draggable=\"false\" class=${we({row:!0,\"row--clickable\":!0,\"row--link\":!0})} @mousedown=${()=>this._handleRowMouseDown()} @click=${i=>this._handleRowClick(i,e,t)} >${i}</a> `:j` <div class=${we({row:!0,\"row--clickable\":!!this._model.rowClickable})} @mousedown=${()=>this._handleRowMouseDown()} @click=${i=>this._handleRowClick(i,e,t)} >${i}</div> `}))} </div> </div> </div> `}render(){return this._model.columns.length?j` ${this._renderCardHeader()} ${this._renderHeader()} ${this._renderTable()} ${this._renderFilterPanel()} `:j`<slot></slot>`}}"
|
|
1247
1268
|
},
|
|
1248
1269
|
{
|
|
1249
1270
|
"kind": "variable",
|
|
1250
|
-
"name": "
|
|
1251
|
-
"default": "class extends ae{constructor(){super(...arguments),this.size=\"md\",this.color=\"dark\"}render(){var e=\"\",t=\"\";return e=\"sm\"==this.size?\"16px\":\"md\"==this.size?\"24px\":\"lg\"==this.size?\"32px\":\"xl\"==this.size?\"48px\":this.size,t=\"dark\"==this.color?\"#163052\":\"light\"==this.color?\"#ffffff\":this.color,j` <svg class=\"spinner\" style=${`width: ${e}; height: ${e}; color: ${t}`} viewBox=\"0 0 44 44\" role=\"status\" aria-label=\"Loading\" > <circle class=\"circle\" cx=\"22\" cy=\"22\" r=\"20\" fill=\"none\" stroke-width=\"4\" /> </svg> `}}"
|
|
1271
|
+
"name": "vt",
|
|
1272
|
+
"default": "class extends le{constructor(){super(...arguments),this._scrollStyle=\"edge\",this._data=[],this._dataState=\"idle\",this._page=1,this._pageSize=50,this._totalItems=0,this._totalPages=0,this._searchQuery=\"\",this._canScrollLeft=!1,this._canScrollRight=!1,this._canScrollHorizontal=!1,this._columnPickerOpen=!1,this._filterPanelOpened=null,this._filterPanelTab=\"filter\",this._buckets=new Map,this._filterPanelPos={top:0,left:0},this._sorts=[],this._resizing=null,this._resizeObserver=null,this._searchPositionLocked=!1,this._columnWidthsLocked=!1,this._model=new bt,this.def={columns:[]},this.variant=\"default\",this._handleClickOutside=e=>{const t=e.composedPath();if(this._columnPickerOpen){const e=this.shadowRoot?.querySelector(\".column-picker-wrapper\");e&&!t.includes(e)&&(this._columnPickerOpen=!1)}this._filterPanelOpened&&(t.some((e=>e.classList?.contains(\"filter-panel\")))||this._handleFilterApply())},this._handleResizeMove=e=>{if(!this._resizing)return;const t=this._model.columns.find((e=>e.id===this._resizing.columnId));if(t){const i=this._resizing.startWidth+(e.clientX-this._resizing.startX);t.width=`${Math.min(900,Math.max(50,i))}px`,this.requestUpdate()}},this._handleResizeEnd=()=>{this._resizing=null,document.removeEventListener(\"mousemove\",this._handleResizeMove),document.removeEventListener(\"mouseup\",this._handleResizeEnd)}}connectedCallback(){super.connectedCallback(),this.classList.toggle(\"kr-table--scroll-overlay\",\"overlay\"===this._scrollStyle),this.classList.toggle(\"kr-table--scroll-edge\",\"edge\"===this._scrollStyle),this._fetch(),this._initRefresh(),document.addEventListener(\"click\",this._handleClickOutside),this._resizeObserver=new ResizeObserver((()=>{this._searchPositionLocked=!1,this._updateSearchPosition()})),this._resizeObserver.observe(this)}disconnectedCallback(){super.disconnectedCallback(),clearInterval(this._refreshTimer),document.removeEventListener(\"click\",this._handleClickOutside),this._resizeObserver?.disconnect()}willUpdate(e){e.has(\"def\")&&(this._columnWidthsLocked=!1,this._model=new bt,this.def.title&&(this._model.title=this.def.title),this.def.description&&(this._model.description=this.def.description),this.def.actions&&(this._model.actions=this.def.actions),this.def.data&&(this._model.data=this.def.data),this.def.dataSource&&(this._model.dataSource=this.def.dataSource),\"number\"==typeof this.def.refreshInterval&&(this._model.refreshInterval=this.def.refreshInterval),\"number\"==typeof this.def.pageSize&&(this._model.pageSize=this.def.pageSize,this._pageSize=this.def.pageSize),this.def.rowClickable&&(this._model.rowClickable=this.def.rowClickable),this.def.rowHref&&(this._model.rowHref=this.def.rowHref),this._sorts=[],this._model.columns=this.def.columns.map((e=>{const t={...e,filter:null};return t.type||(t.type=\"string\"),e.sort&&this._sorts.push({sortBy:e.id,sortDirection:e.sort}),\"actions\"===t.type?(t.label=e.label??\"\",t.sticky=\"right\",t.resizable=!1,t):((e.filterable||e.facetable)&&(t.filter=new ct,t.filter.field=e.id,t.filter.type=t.type,e.filter?(t.filter.setOperator(e.filter.operator),t.filter.setValue(e.filter.value)):e.facetable&&!e.filterable?(t.filter.operator=\"in\",t.filter.value=[]):\"string\"===t.filter.type&&(t.filter.operator=\"contains\")),t)})),this.def.displayedColumns?this._model.displayedColumns=this.def.displayedColumns:this._model.displayedColumns=this._model.columns.map((e=>e.id)),this._fetch(),this._initRefresh())}updated(e){this.classList.toggle(\"kr-table--card\",\"card\"===this.variant),this._updateScrollFlags(),this._syncSlottedContent(),this._lockColumnWidths()}_lockColumnWidths(){if(this._columnWidthsLocked||0===this._data.length)return;const e=this.shadowRoot?.querySelectorAll(\".header-row > .header-cell\");if(!e)return;const t=this.getDisplayedColumns();e.forEach(((e,i)=>{const s=e.offsetWidth;i<t.length&&!t[i].width&&\"actions\"!==t[i].type&&s>0&&(t[i].width=`${s}px`,this._columnWidthsLocked=!0)}))}_syncSlottedContent(){const e=this.getDisplayedColumns().filter((e=>e.render));e.length&&(this.querySelectorAll('[slot^=\"cell-\"]').forEach((e=>e.remove())),this._data.forEach(((t,i)=>{e.forEach((e=>{const s=e.render(t);if(!s)return;const r=document.createElement(\"span\");r.slot=`cell-${i}-${e.id}`,\"actions\"===e.type&&(r.style.display=\"flex\",r.style.gap=\"8px\"),\"string\"==typeof s?r.innerHTML=s:re(s,r),this.appendChild(r)}))})))}refresh(){this._fetch()}goToPrevPage(){this._page>1&&(this._page--,this._fetch())}goToNextPage(){this._page<this._totalPages&&(this._page++,this._fetch())}goToPage(e){e>=1&&e<=this._totalPages&&(this._page=e,this._fetch())}_toSolrData(){const e={page:this._page-1,size:this._pageSize,sorts:this._sorts,filterFields:[],queryFields:[],facetFields:[]};for(const t of this._model.columns){if(!t.filter||t.filter.isEmpty()||!t.filter.isValid())continue;const i=t.filter.toSolrData();!t.facetable||\"in\"!==t.filter.operator&&\"n_in\"!==t.filter.operator||(i.tagged=!0),e.filterFields.push(i)}for(const t of this._model.columns)t.facetable&&e.facetFields.push({name:t.id,type:\"FIELD\",limit:100,sort:\"count\",minimumCount:1});return this._searchQuery?.trim().length&&e.queryFields.push({name:\"_text_\",operation:\"IS\",value:lt(this._searchQuery,!1)}),e}_toDbParams(){const e={page:this._page-1,size:this._pageSize,sorts:this._sorts,filterFields:[],queryFields:[],facetFields:[]};for(const t of this._model.columns)t.filter&&!t.filter.isEmpty()&&t.filter.isValid()&&e.filterFields.push(t.filter.toDbParams());return this._searchQuery?.trim().length&&this._model.columns.filter((e=>e.searchable)).forEach((t=>{e.queryFields.push({name:t.id,operation:\"CONTAINS\",value:this._searchQuery,and:!1})})),e}_fetch(){if(this._model.data)return this._data=this._model.data,this._totalItems=this._model.data.length,this._totalPages=Math.ceil(this._model.data.length/this._pageSize),void(this._dataState=\"success\");if(!this._model.dataSource)return;let e;this._dataState=\"loading\",e=\"db\"===this._model.dataSource.mode?this._toDbParams():this._toSolrData(),this._model.dataSource.fetch(e).then((e=>{switch(this._model.dataSource?.mode){case\"opensearch\":throw Error(\"Opensearch not supported yet\");case\"db\":{const t=e;this._data=t.data.content,this._totalItems=t.data.totalElements,this._totalPages=t.data.totalPages,this._pageSize=t.data.size;break}default:{const t=e;this._data=t.data.content,this._totalItems=t.data.totalElements,this._totalPages=t.data.totalPages,this._pageSize=t.data.size,this._parseFacetResults(t)}}this._dataState=\"success\",this._updateSearchPosition()})).catch((e=>{this._dataState=\"error\",Ke.show({message:e instanceof Error?e.message:\"Failed to load data\",type:\"error\"})}))}_parseFacetResults(e){if(e.data.facetFields){for(const t of this._model.columns){if(!t.facetable)continue;const i=e.data.facetFields[t.id];if(!i){this._buckets.set(t.id,[]);continue}const s=[];for(const e of i){let i=e.name;\"boolean\"===t.type&&\"string\"==typeof e.name&&(\"true\"===e.name?i=!0:\"false\"===e.name&&(i=!1)),null===e.name&&e.count>0&&s.unshift({val:null,count:e.count}),null!==e.name&&s.push({val:i,count:e.count})}if(t.filter&&(\"in\"===t.filter.operator||\"n_in\"===t.filter.operator)&&Array.isArray(t.filter.value))for(const e of t.filter.value)s.some((t=>t.val===e))||s.push({val:e,count:0});this._buckets.set(t.id,s)}this._buckets=new Map(this._buckets)}}_initRefresh(){clearInterval(this._refreshTimer),this._model.refreshInterval&&this._model.refreshInterval>0&&(this._refreshTimer=window.setInterval((()=>{this._fetch()}),this._model.refreshInterval))}_handleSearch(e){const t=e.target;this._searchQuery=t.value,this._page=1,this._fetch()}_getGridTemplateColumns(){return this.getDisplayedColumns().map((e=>e.width?e.width:\"actions\"===e.type?\"max-content\":\"minmax(80px, auto)\")).join(\" \")}_updateSearchPosition(){if(this._searchPositionLocked)return;if(\"card\"===this.variant)return;const e=this.shadowRoot?.querySelector(\".search\"),t=e?.querySelector(\".search-field\");e&&t&&(e.style.justifyContent=\"center\",t.style.marginLeft=\"\",requestAnimationFrame((()=>{const i=e.getBoundingClientRect(),s=t.getBoundingClientRect().left-i.left;e.style.justifyContent=\"flex-start\",t.style.marginLeft=`${s}px`,this._searchPositionLocked=!0})))}_toggleColumnPicker(){this._columnPickerOpen=!this._columnPickerOpen}_toggleColumn(e){this._model.displayedColumns.includes(e)?this._model.displayedColumns=this._model.displayedColumns.filter((t=>t!==e)):this._model.displayedColumns=[...this._model.displayedColumns,e],this.requestUpdate()}_handleRowMouseDown(){(this._model.rowClickable||this._model.rowHref)&&window.getSelection()?.removeAllRanges()}_handleRowClick(e,t,i){if(!this._model.rowClickable&&!this._model.rowHref)return;const s=window.getSelection();s&&s.toString().length>0?e.preventDefault():this.dispatchEvent(new CustomEvent(\"row-click\",{detail:{row:t,rowIndex:i},bubbles:!0,composed:!0}))}getDisplayedColumns(){return this._model.displayedColumns.map((e=>this._model.columns.find((t=>t.id===e)))).sort(((e,t)=>\"actions\"===e.type&&\"actions\"!==t.type?1:\"actions\"!==e.type&&\"actions\"===t.type?-1:0))}_handleScroll(e){const t=e.target;this._canScrollLeft=t.scrollLeft>0,this._canScrollRight=t.scrollLeft<t.scrollWidth-t.clientWidth-1}_updateScrollFlags(){const e=this.shadowRoot?.querySelector(\".content\");e&&(this._canScrollLeft=e.scrollLeft>0,this._canScrollRight=e.scrollWidth>e.clientWidth&&e.scrollLeft<e.scrollWidth-e.clientWidth-1,this._canScrollHorizontal=e.scrollWidth>e.clientWidth),this.classList.toggle(\"kr-table--scroll-left-available\",this._canScrollLeft),this.classList.toggle(\"kr-table--scroll-right-available\",this._canScrollRight),this.classList.toggle(\"kr-table--scroll-horizontal-available\",this._canScrollHorizontal),this.classList.toggle(\"kr-table--sticky-left\",this.getDisplayedColumns().some((e=>\"left\"===e.sticky))),this.classList.toggle(\"kr-table--sticky-right\",this.getDisplayedColumns().some((e=>\"right\"===e.sticky)))}_handleResizeStart(e,t){e.preventDefault();const i=this.shadowRoot?.querySelector(`.header-cell[data-column-id=\"${t}\"]`);this._resizing={columnId:t,startX:e.clientX,startWidth:i?.offsetWidth||200},document.addEventListener(\"mousemove\",this._handleResizeMove),document.addEventListener(\"mouseup\",this._handleResizeEnd)}_handleSortClick(e,t){if(e.shiftKey){const e=this._sorts.findIndex((e=>e.sortBy===t.id));if(-1===e)this._sorts.push({sortBy:t.id,sortDirection:\"asc\"});else{const t=this._sorts[e];\"asc\"===t.sortDirection?t.sortDirection=\"desc\":this._sorts.splice(e,1)}this.requestUpdate()}else{let e=null;1===this._sorts.length&&(e=this._sorts.find((e=>e.sortBy===t.id))),e?\"asc\"===e.sortDirection?this._sorts=[{sortBy:t.id,sortDirection:\"desc\"}]:this._sorts=[]:this._sorts=[{sortBy:t.id,sortDirection:\"asc\"}]}this._page=1,this._fetch()}_renderSortIndicator(e){if(!e.sortable)return F;const t=this._sorts.findIndex((t=>t.sortBy===e.id));if(-1===t)return j` <span class=\"header-cell__sort\" @click=${t=>this._handleSortClick(t,e)}> <svg class=\"header-cell__sort-arrow header-cell__sort-arrow--ghost\" viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z\"/> </svg> </span> `;let i={};return\"desc\"===this._sorts[t].sortDirection&&(i={transform:\"rotate(180deg)\"}),j` <span class=\"header-cell__sort\" @click=${t=>this._handleSortClick(t,e)}> <svg class=\"header-cell__sort-arrow\" viewBox=\"0 0 24 24\" fill=\"currentColor\" style=${Le(i)}> <path d=\"M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z\"/> </svg> ${this._sorts.length>1?j` <span class=\"header-cell__sort-priority\">${t+1}</span> `:F} </span> `}_handleAction(e){e.href||this.dispatchEvent(new CustomEvent(\"action\",{detail:{action:e.id},bubbles:!0,composed:!0}))}_handleKqlChange(e,t){const i=e.target.value.trim();if(i){if(t.filter.setKql(i),this.requestUpdate(),!t.filter.isValid())return}else t.filter.clear(),this.requestUpdate();this._page=1,this._fetch()}_handleFilterPanelToggle(e,t){if(e.stopPropagation(),this._filterPanelOpened===t.id)this._filterPanelOpened=null;else{const i=e.currentTarget.getBoundingClientRect();let s=i.left;s+328>window.innerWidth&&(s=window.innerWidth-328),this._filterPanelPos={top:i.bottom+4,left:s},this._filterPanelOpened=t.id,t.facetable?this._filterPanelTab=\"counts\":this._filterPanelTab=\"filter\"}}_handleKqlClear(e){e.filter.clear(),this._page=1,this._fetch()}_handleFilterClear(){const e=this._model.columns.find((e=>e.id===this._filterPanelOpened));e&&(e.filter.clear(),e.facetable&&!e.filterable&&(e.filter.operator=\"in\",e.filter.value=[])),this._filterPanelOpened=null,this._page=1,this._fetch()}_handleFilterTextKeydown(e,t){\"Enter\"===e.key&&(e.preventDefault(),this._handleFilterApply())}_handleOperatorChange(e,t){t.filter.setOperator(e.target.value),this.requestUpdate()}_handleFilterStringChange(e,t){t.filter.setValue(e.target.value),this.requestUpdate()}_handleFilterNumberChange(e,t){t.filter.setValue(Number(e.target.value)),this.requestUpdate()}_handleFilterDateChange(e,t){t.filter.setValue(new Date(e.target.value),\"day\"),this.requestUpdate()}_handleFilterBooleanChange(e,t){t.filter.setValue(\"true\"===e.target.value),this.requestUpdate()}_handleFilterDateStartChange(e,t){t.filter.setStart(new Date(e.target.value),\"day\"),this.requestUpdate()}_handleFilterDateEndChange(e,t){t.filter.setEnd(new Date(e.target.value),\"day\"),this.requestUpdate()}_handleFilterNumberStartChange(e,t){t.filter.setStart(Number(e.target.value)),this.requestUpdate()}_handleFilterNumberEndChange(e,t){t.filter.setEnd(Number(e.target.value)),this.requestUpdate()}_handleFilterListChange(e,t){const i=e.target.value.split(\",\").map((e=>e.trim())).filter((e=>\"\"!==e));\"number\"===t.type?t.filter.setValue(i.map((e=>Number(e)))):t.filter.setValue(i),this.requestUpdate()}_handleFilterApply(){this._filterPanelOpened=null,this._page=1,this._fetch()}_handleFilterPanelTabChange(e){this._filterPanelTab=e.detail.activeTabId}_handleBucketToggle(e,t,i){t.filter.toggle(i.val),this._page=1,this._fetch()}_renderCellContent(e,t,i){const s=t[e.id];if(e.render)return j`<slot name=\"cell-${i}-${e.id}\"></slot>`;if(null==s)return\"\";switch(e.type){case\"number\":return\"currency\"===e.format&&\"number\"==typeof s?s.toLocaleString(\"en-US\",{style:\"currency\",currency:\"USD\"}):String(s);case\"date\":{let e;if(s instanceof Date)e=s;else if(\"string\"==typeof s&&/^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}/.test(s)){const t=s.replace(/(\\d{2}:\\d{2}:\\d{2}):(\\d+)$/,\"$1.$2\").replace(\" \",\"T\")+\"Z\";e=new Date(t)}else e=new Date(s);return e.toLocaleString(void 0,{year:\"numeric\",month:\"short\",day:\"numeric\",hour:\"numeric\",minute:\"2-digit\",timeZone:\"UTC\"})}case\"boolean\":return!0===s?\"Yes\":!1===s?\"No\":\"\";default:return String(s)}}_getHeaderCellClasses(e,t){return{\"header-cell\":!0,\"header-cell--sortable\":!!e.sortable,\"header-cell--align-center\":\"center\"===e.align,\"header-cell--align-right\":\"right\"===e.align,\"header-cell--sticky-left\":\"left\"===e.sticky,\"header-cell--sticky-left-last\":\"left\"===e.sticky&&!this.getDisplayedColumns().slice(t+1).some((e=>\"left\"===e.sticky)),\"header-cell--sticky-right\":\"right\"===e.sticky,\"header-cell--sticky-right-first\":\"right\"===e.sticky&&!this.getDisplayedColumns().slice(0,t).some((e=>\"right\"===e.sticky))}}_getCellClasses(e,t){return{cell:!0,\"cell--actions\":\"actions\"===e.type,\"cell--align-center\":\"center\"===e.align,\"cell--align-right\":\"right\"===e.align,\"cell--sticky-left\":\"left\"===e.sticky,\"cell--sticky-left-last\":\"left\"===e.sticky&&!this.getDisplayedColumns().slice(t+1).some((e=>\"left\"===e.sticky)),\"cell--sticky-right\":\"right\"===e.sticky,\"cell--sticky-right-first\":\"right\"===e.sticky&&!this.getDisplayedColumns().slice(0,t).some((e=>\"right\"===e.sticky))}}_getCellStyle(e,t){const i={};if(\"left\"===e.sticky){let e=0;for(let i=0;i<t;i++){const t=this.getDisplayedColumns()[i];\"left\"===t.sticky&&(e+=parseInt(t.width||\"0\",10))}i.left=`${e}px`}if(\"right\"===e.sticky){let e=0;for(let i=t+1;i<this.getDisplayedColumns().length;i++){const t=this.getDisplayedColumns()[i];\"right\"===t.sticky&&(e+=parseInt(t.width||\"0\",10))}i.right=`${e}px`}return i}_renderPagination(){const e=(this._page-1)*this._pageSize+1,t=Math.min(this._page*this._pageSize,this._totalItems);return j` <div class=\"pagination\"> <span class=\"pagination-icon ${1===this._page?\"pagination-icon--disabled\":\"\"}\" @click=${this.goToPrevPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z\"/></svg> </span> <span class=\"pagination-info\">${e}-${t} of ${this._totalItems}</span> <span class=\"pagination-icon ${this._page===this._totalPages?\"pagination-icon--disabled\":\"\"}\" @click=${this.goToNextPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z\"/></svg> </span> </div> `}_renderCardHeader(){return\"card\"!==this.variant?F:this._model.title||this._model.description?j` <div class=\"card-header\"> ${this._model.title?j`<h2 class=\"card-header__title\">${this._model.title}</h2>`:F} ${this._model.description?j`<p class=\"card-header__description\">${this._model.description}</p>`:F} </div> `:F}_renderHeader(){return!this._model.title&&!this._model.actions?.length&&this._totalPages<=1?F:j` <div class=\"header\"> ${this._model.title&&\"card\"!==this.variant?j`<div class=\"title\">${this._model.title}</div>`:F} ${\"db\"!==this._model.dataSource?.mode||this._model.columns.some((e=>e.searchable))?j` <div class=\"search\"> <!-- TODO: Saved views dropdown <div class=\"views\"> <span>Default View</span> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z\"/></svg> </div> --> <div class=\"search-field\"> <svg class=\"search-icon\" viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z\"/></svg> <input type=\"text\" class=\"search-input\" placeholder=\"Search...\" .value=${this._searchQuery} @input=${this._handleSearch} /> </div> </div> `:j`<div class=\"search\"></div>`} <div class=\"tools\"> ${this._renderPagination()} <span class=\"refresh\" title=\"Refresh\" @click=${()=>this.refresh()}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M480-160q-134 0-227-93t-93-227q0-134 93-227t227-93q69 0 132 28.5T720-690v-110h80v280H520v-80h168q-32-56-87.5-88T480-720q-100 0-170 70t-70 170q0 100 70 170t170 70q77 0 139-44t87-116h84q-28 106-114 173t-196 67Z\"/></svg> </span> <div class=\"column-picker-wrapper\"> <span class=\"header-icon\" title=\"Columns\" @click=${this._toggleColumnPicker}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M121-280v-400q0-33 23.5-56.5T201-760h559q33 0 56.5 23.5T840-680v400q0 33-23.5 56.5T760-200H201q-33 0-56.5-23.5T121-280Zm79 0h133v-400H200v400Zm213 0h133v-400H413v400Zm213 0h133v-400H626v400Z\"/></svg> </span> <div class=\"column-picker ${this._columnPickerOpen?\"open\":\"\"}\"> ${[...this._model.columns].filter((e=>\"actions\"!==e.type)).sort(((e,t)=>(e.label??e.id).localeCompare(t.label??t.id))).map((e=>j` <div class=\"column-picker-item\" @click=${()=>this._toggleColumn(e.id)}> <div class=\"column-picker-checkbox ${this._model.displayedColumns.includes(e.id)?\"checked\":\"\"}\"> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/></svg> </div> <span class=\"column-picker-label\">${e.label??e.id}</span> </div> `))} </div> </div> ${1===this._model.actions?.length?j` <kr-button class=\"actions\" .href=${this._model.actions[0].href} .target=${this._model.actions[0].target} @click=${()=>this._handleAction(this._model.actions[0])} > ${this._model.actions[0].label} </kr-button> `:this._model.actions?.length?j` <kr-button class=\"actions\" .options=${this._model.actions.map((e=>({id:e.id,label:e.label})))} @option-select=${e=>this._handleAction({id:e.detail.id,label:e.detail.label})} > Actions </kr-button> `:F} </div> </div> `}_renderStatus(){return\"loading\"===this._dataState&&0===this._data.length?j`<div class=\"status\">Loading...</div>`:\"error\"===this._dataState&&0===this._data.length?j`<div class=\"status status--error\">Error loading data</div>`:0===this._data.length?j`<div class=\"status\">No data available</div>`:F}_renderFilterPanel(){if(!this._filterPanelOpened)return F;const e=this._model.columns.find((e=>e.id===this._filterPanelOpened));let t=j``;t=\"empty\"===e.filter.operator||\"n_empty\"===e.filter.operator?j` <input type=\"text\" class=\"filter-panel__input\" disabled .value=${e.filter.text} /> `:\"between\"===e.filter.operator&&\"date\"===e.type?j` <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${e.filter.value?.start??null} @change=${t=>this._handleFilterDateStartChange(t,e)} /> <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${e.filter.value?.end??null} @change=${t=>this._handleFilterDateEndChange(t,e)} /> `:\"between\"===e.filter.operator&&\"number\"===e.type?j` <input type=\"number\" class=\"filter-panel__input\" placeholder=\"Start\" .value=${e.filter.value?.start??\"\"} @input=${t=>this._handleFilterNumberStartChange(t,e)} @keydown=${t=>this._handleFilterTextKeydown(t,e)} /> <input type=\"number\" class=\"filter-panel__input\" placeholder=\"End\" .value=${e.filter.value?.end??\"\"} @input=${t=>this._handleFilterNumberEndChange(t,e)} @keydown=${t=>this._handleFilterTextKeydown(t,e)} /> `:\"in\"===e.filter.operator||\"n_in\"===e.filter.operator?j` <textarea class=\"filter-panel__textarea\" rows=\"3\" placeholder=\"Values (comma-separated)\" .value=${e.filter.text} @input=${t=>this._handleFilterListChange(t,e)} @keydown=${t=>this._handleFilterTextKeydown(t,e)} ></textarea> `:\"boolean\"===e.type?j` <kr-select-field placeholder=\"Value\" .value=${String(e.filter.value??\"\")} @change=${t=>this._handleFilterBooleanChange(t,e)} > <kr-select-option value=\"true\">Yes</kr-select-option> <kr-select-option value=\"false\">No</kr-select-option> </kr-select-field> `:\"date\"===e.type?j` <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${e.filter.value} @change=${t=>this._handleFilterDateChange(t,e)} /> `:\"number\"===e.type?j` <input type=\"number\" class=\"filter-panel__input\" placeholder=\"Value\" min=\"0\" .value=${e.filter.text} @input=${t=>this._handleFilterNumberChange(t,e)} @keydown=${t=>this._handleFilterTextKeydown(t,e)} /> `:j` <input type=\"text\" class=\"filter-panel__input\" placeholder=\"Value\" .value=${e.filter.text} @input=${t=>this._handleFilterStringChange(t,e)} @keydown=${t=>this._handleFilterTextKeydown(t,e)} /> `;const i=j` <div class=\"filter-panel__content\"> <kr-select-field .value=${e.filter.operator} @change=${t=>this._handleOperatorChange(t,e)} > ${st(e.type).map((e=>j` <kr-select-option value=${e.key}>${e.label}</kr-select-option> `))} </kr-select-field> ${t} </div> `,s=this._buckets.get(e.id)||[];let r,o;return r=s.length?j` <div class=\"buckets\"> ${s.map((t=>{let i=\"(Empty)\";null!==t.val&&void 0!==t.val&&(i=\"boolean\"===e.type?!0===t.val||\"true\"===t.val?\"Yes\":\"No\":String(t.val));let s=e.filter.has(t.val);\"n_in\"===e.filter.operator&&(s=!s);let r=F;return s&&(r=j` <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/> </svg> `),j` <div class=\"bucket\" @click=${i=>this._handleBucketToggle(i,e,t)} > <div class=${we({bucket__checkbox:!0,\"bucket__checkbox--checked\":s})}> ${r} </div> <span class=\"bucket__label\">${i}</span> <span class=\"bucket__count\">${t.count}</span> </div> `}))} </div> `:j`<div class=\"bucket-empty\">No data</div>`,o=e.facetable&&e.filterable?j` <kr-tab-group size=\"small\" active-tab-id=${this._filterPanelTab} @tab-change=${e=>this._handleFilterPanelTabChange(e)} > <kr-tab id=\"filter\" label=\"Filter\"> ${i} </kr-tab> <kr-tab id=\"counts\" label=\"Counts\"> ${r} </kr-tab> </kr-tab-group> `:e.facetable?r:i,j` <div class=\"filter-panel\" style=${Le({top:this._filterPanelPos.top+\"px\",left:this._filterPanelPos.left+\"px\"})} > ${o} <div class=\"filter-panel__actions\"> <kr-button variant=\"outline\" color=\"secondary\" size=\"small\" @click=${this._handleFilterClear}> Clear </kr-button> <kr-button size=\"small\" @click=${this._handleFilterApply}> Apply </kr-button> </div> </div> `}_renderFilterRow(){const e=this.getDisplayedColumns();return e.some((e=>e.filterable||e.facetable))?j` <div class=\"filter-row\"> ${e.map(((t,i)=>t.filterable||t.facetable?j` <div class=${we({\"filter-cell\":!0,\"filter-cell--sticky-left\":\"left\"===t.sticky,\"filter-cell--sticky-right\":\"right\"===t.sticky,\"filter-cell--sticky-right-first\":\"right\"===t.sticky&&!e.slice(0,i).some((e=>\"right\"===e.sticky))})} style=${Le(this._getCellStyle(t,i))} > <div class=\"filter-cell__wrapper\"> <input type=\"text\" class=${we({\"filter-cell__input\":!0,\"filter-cell__input--invalid\":!t.filter.isValid()})} .value=${t.filter.kql} @change=${e=>this._handleKqlChange(e,t)} /> ${t.filter?.kql?.length>0?j` <button class=\"filter-cell__clear\" @click=${()=>this._handleKqlClear(t)} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/> </svg> </button> `:F} <button class=${we({\"filter-cell__advanced\":!0,\"filter-cell__advanced--opened\":this._filterPanelOpened===t.id})} @click=${e=>this._handleFilterPanelToggle(e,t)} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z\"/> </svg> </button> </div> </div> `:j`<div class=${we({\"filter-cell\":!0,\"filter-cell--sticky-left\":\"left\"===t.sticky,\"filter-cell--sticky-right\":\"right\"===t.sticky,\"filter-cell--sticky-right-first\":\"right\"===t.sticky&&!e.slice(0,i).some((e=>\"right\"===e.sticky))})} style=${Le(this._getCellStyle(t,i))} ></div>`))} </div> `:F}_renderTable(){return j` <div class=\"wrapper\"> <div class=\"overlay-left\"></div> <div class=\"overlay-right\"></div> ${this._renderStatus()} <div class=\"content\" @scroll=${this._handleScroll}> <div class=\"table\" style=\"grid-template-columns: ${this._getGridTemplateColumns()}\"> <div class=\"header-row\"> ${this.getDisplayedColumns().map(((e,t)=>j` <div class=${we(this._getHeaderCellClasses(e,t))} style=${Le(this._getCellStyle(e,t))} data-column-id=${e.id} > <span class=\"header-cell__label\">${e.label??e.id}</span> ${this._renderSortIndicator(e)} ${!1!==e.resizable?j`<div class=\"header-cell__resize\" @mousedown=${t=>this._handleResizeStart(t,e.id)} ></div>`:F} </div> `))} </div> ${this._renderFilterRow()} ${this._data.map(((e,t)=>{const i=this.getDisplayedColumns().map(((i,s)=>j` <div class=${we(this._getCellClasses(i,s))} style=${Le(this._getCellStyle(i,s))} data-column-id=${i.id} > ${this._renderCellContent(i,e,t)} </div> `));return this._model.rowHref?j` <a href=${this._model.rowHref(e)} draggable=\"false\" class=${we({row:!0,\"row--clickable\":!0,\"row--link\":!0})} @mousedown=${()=>this._handleRowMouseDown()} @click=${i=>this._handleRowClick(i,e,t)} >${i}</a> `:j` <div class=${we({row:!0,\"row--clickable\":!!this._model.rowClickable})} @mousedown=${()=>this._handleRowMouseDown()} @click=${i=>this._handleRowClick(i,e,t)} >${i}</div> `}))} </div> </div> </div> `}render(){return this._model.columns.length?j` ${this._renderCardHeader()} ${this._renderHeader()} ${this._renderTable()} ${this._renderFilterPanel()} `:j`<slot></slot>`}}"
|
|
1252
1273
|
},
|
|
1253
1274
|
{
|
|
1254
1275
|
"kind": "variable",
|
|
1255
|
-
"name": "
|
|
1256
|
-
"default": "class extends
|
|
1276
|
+
"name": "mt",
|
|
1277
|
+
"default": "class extends le{constructor(){super(...arguments),this.size=\"md\",this.color=\"dark\"}render(){var e=\"\",t=\"\";return e=\"sm\"==this.size?\"16px\":\"md\"==this.size?\"24px\":\"lg\"==this.size?\"32px\":\"xl\"==this.size?\"48px\":this.size,t=\"dark\"==this.color?\"#163052\":\"light\"==this.color?\"#ffffff\":this.color,j` <svg class=\"spinner\" style=${`width: ${e}; height: ${e}; color: ${t}`} viewBox=\"0 0 44 44\" role=\"status\" aria-label=\"Loading\" > <circle class=\"circle\" cx=\"22\" cy=\"22\" r=\"20\" fill=\"none\" stroke-width=\"4\" /> </svg> `}}"
|
|
1257
1278
|
},
|
|
1258
1279
|
{
|
|
1259
1280
|
"kind": "variable",
|
|
1260
|
-
"name": "xt"
|
|
1281
|
+
"name": "xt",
|
|
1282
|
+
"default": "class extends le{constructor(){super(...arguments),this.color=\"dark\"}render(){let e=\"\",t=\"\";return e=\"dark\"===this.color?\"#163052\":\"light\"===this.color?\"#ffffff\":this.color,t=this.trackColor?this.trackColor:\"light\"===this.color?\"#ffffff4d\":\"#0000001a\",j` <div class=\"progress-bar\" style=${`background: ${t}`} role=\"status\" aria-label=\"Loading\" > <div class=\"fill\" style=${`background: ${e}`}></div> </div> `}}"
|
|
1261
1283
|
},
|
|
1262
1284
|
{
|
|
1263
1285
|
"kind": "variable",
|
|
1264
|
-
"name": "
|
|
1265
|
-
"default": "class extends ae{constructor(){super(...arguments),this.files=[],this.emptyMessage=\"No files\"}_handleFileClick(e){if(this.dispatchEvent(new CustomEvent(\"file-click\",{bubbles:!0,composed:!0,detail:{file:e}})),e.url){xt.open({src:e.url,name:e.name}).addEventListener(\"download\",(()=>{this._handleDownload(e)}))}}_handleDownload(e){this.dispatchEvent(new CustomEvent(\"download\",{bubbles:!0,composed:!0,detail:{file:e}}))}_handleDelete(e){this.dispatchEvent(new CustomEvent(\"delete\",{bubbles:!0,composed:!0,detail:{file:e}}))}_getExtension(e){return e.split(\".\").pop()?.toLowerCase()||\"\"}_getExtClass(e){return[\"pdf\"].includes(e)?\"file-list__ext--pdf\":[\"doc\",\"docx\",\"rtf\",\"txt\"].includes(e)?\"file-list__ext--doc\":[\"xls\",\"xlsx\",\"csv\"].includes(e)?\"file-list__ext--xls\":[\"zip\",\"rar\",\"7z\",\"gz\",\"tar\"].includes(e)?\"file-list__ext--zip\":[\"jpg\",\"jpeg\",\"png\",\"gif\",\"webp\",\"svg\",\"bmp\"].includes(e)?\"file-list__ext--img\":\"file-list__ext--default\"}_getExtIcon(e){return[\"jpg\",\"jpeg\",\"png\",\"gif\",\"webp\",\"svg\",\"bmp\"].includes(e)?j`<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-4.86 8.86-3 3.87L9 13.14 6 17h12l-3.86-5.14z\"/></svg>`:[\"pdf\"].includes(e)?j`<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M20 2H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-8.5 7.5c0 .83-.67 1.5-1.5 1.5H9v2H7.5V7H10c.83 0 1.5.67 1.5 1.5v1zm5 2c0 .83-.67 1.5-1.5 1.5h-2.5V7H15c.83 0 1.5.67 1.5 1.5v3zm4-3H19v1h1.5V11H19v2h-1.5V7h3v1.5zM9 9.5h1v-1H9v1zM4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6zm10 5.5h1v-3h-1v3z\"/></svg>`:[\"doc\",\"docx\",\"rtf\",\"txt\"].includes(e)?j`<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zM6 20V4h7v5h5v11H6zm2-6h8v2H8v-2zm0-4h8v2H8v-2zm0 8h5v2H8v-2z\"/></svg>`:[\"xls\",\"xlsx\",\"csv\"].includes(e)?j`<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 2v3H5V5h14zm0 5v4H5v-4h14zM5 19v-3h14v3H5zm2-8h4v2H7v-2zm0 5h4v2H7v-2z\"/></svg>`:[\"zip\",\"rar\",\"7z\",\"gz\",\"tar\"].includes(e)?j`<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M20 6h-8l-2-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 12H4V6h5.17l2 2H20v10zm-8-4h2v2h-2v-2zm0-4h2v2h-2v-2zm-2 2h2v2h-2v-2z\"/></svg>`:j`<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11z\"/></svg>`}render(){return this.files.length?j` <div class=\"file-list\"> ${this.files.map((e=>{const t=this._getExtension(e.name),i=e.meta||e.date||\"\";return j` <div class=\"file-list__item\"> <div class=\"file-list__ext ${this._getExtClass(t)}\">${this._getExtIcon(t)}</div> <div class=\"file-list__info\"> <a class=\"file-list__name\" @click=${()=>this._handleFileClick(e)}>${e.name}</a> ${i?j`<div class=\"file-list__meta\">${i}</div>`:\"\"} </div> <div class=\"file-list__actions\"> <svg class=\"file-list__action\" @click=${()=>this._handleDownload(e)} xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" title=\"Download\"><path d=\"M19 9h-4V3H9v6H5l7 7 7-7zm-8 2V5h2v6h1.17L12 13.17 9.83 11H11zm-6 7h14v2H5v-2z\"/></svg> <svg class=\"file-list__action file-list__action--delete\" @click=${()=>this._handleDelete(e)} xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" title=\"Delete\"><path d=\"M16 9v10H8V9h8m-1.5-6h-5l-1 1H5v2h14V4h-3.5l-1-1zM18 7H6v12c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7z\"/></svg> </div> </div> `}))} </div> `:j`<div class=\"file-list__empty\">${this.emptyMessage}</div>`}}"
|
|
1286
|
+
"name": "$t"
|
|
1266
1287
|
},
|
|
1267
1288
|
{
|
|
1268
1289
|
"kind": "variable",
|
|
1269
|
-
"name": "
|
|
1270
|
-
"default": "class extends
|
|
1290
|
+
"name": "St",
|
|
1291
|
+
"default": "class extends le{constructor(){super(...arguments),this.files=[],this.emptyMessage=\"No files\"}_handleFileClick(e){if(this.dispatchEvent(new CustomEvent(\"file-click\",{bubbles:!0,composed:!0,detail:{file:e}})),e.url){$t.open({src:e.url,name:e.name}).addEventListener(\"download\",(()=>{this._handleDownload(e)}))}}_handleDownload(e){this.dispatchEvent(new CustomEvent(\"download\",{bubbles:!0,composed:!0,detail:{file:e}}))}_handleDelete(e){this.dispatchEvent(new CustomEvent(\"delete\",{bubbles:!0,composed:!0,detail:{file:e}}))}_getExtension(e){return e.split(\".\").pop()?.toLowerCase()||\"\"}_getExtClass(e){return[\"pdf\"].includes(e)?\"file-list__ext--pdf\":[\"doc\",\"docx\",\"rtf\",\"txt\"].includes(e)?\"file-list__ext--doc\":[\"xls\",\"xlsx\",\"csv\"].includes(e)?\"file-list__ext--xls\":[\"zip\",\"rar\",\"7z\",\"gz\",\"tar\"].includes(e)?\"file-list__ext--zip\":[\"jpg\",\"jpeg\",\"png\",\"gif\",\"webp\",\"svg\",\"bmp\"].includes(e)?\"file-list__ext--img\":\"file-list__ext--default\"}_getExtIcon(e){return[\"jpg\",\"jpeg\",\"png\",\"gif\",\"webp\",\"svg\",\"bmp\"].includes(e)?j`<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-4.86 8.86-3 3.87L9 13.14 6 17h12l-3.86-5.14z\"/></svg>`:[\"pdf\"].includes(e)?j`<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M20 2H8c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-8.5 7.5c0 .83-.67 1.5-1.5 1.5H9v2H7.5V7H10c.83 0 1.5.67 1.5 1.5v1zm5 2c0 .83-.67 1.5-1.5 1.5h-2.5V7H15c.83 0 1.5.67 1.5 1.5v3zm4-3H19v1h1.5V11H19v2h-1.5V7h3v1.5zM9 9.5h1v-1H9v1zM4 6H2v14c0 1.1.9 2 2 2h14v-2H4V6zm10 5.5h1v-3h-1v3z\"/></svg>`:[\"doc\",\"docx\",\"rtf\",\"txt\"].includes(e)?j`<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zM6 20V4h7v5h5v11H6zm2-6h8v2H8v-2zm0-4h8v2H8v-2zm0 8h5v2H8v-2z\"/></svg>`:[\"xls\",\"xlsx\",\"csv\"].includes(e)?j`<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm0 2v3H5V5h14zm0 5v4H5v-4h14zM5 19v-3h14v3H5zm2-8h4v2H7v-2zm0 5h4v2H7v-2z\"/></svg>`:[\"zip\",\"rar\",\"7z\",\"gz\",\"tar\"].includes(e)?j`<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M20 6h-8l-2-2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 12H4V6h5.17l2 2H20v10zm-8-4h2v2h-2v-2zm0-4h2v2h-2v-2zm-2 2h2v2h-2v-2z\"/></svg>`:j`<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11z\"/></svg>`}render(){return this.files.length?j` <div class=\"file-list\"> ${this.files.map((e=>{const t=this._getExtension(e.name),i=e.meta||e.date||\"\";return j` <div class=\"file-list__item\"> <div class=\"file-list__ext ${this._getExtClass(t)}\">${this._getExtIcon(t)}</div> <div class=\"file-list__info\"> <a class=\"file-list__name\" @click=${()=>this._handleFileClick(e)}>${e.name}</a> ${i?j`<div class=\"file-list__meta\">${i}</div>`:\"\"} </div> <div class=\"file-list__actions\"> <svg class=\"file-list__action\" @click=${()=>this._handleDownload(e)} xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" title=\"Download\"><path d=\"M19 9h-4V3H9v6H5l7 7 7-7zm-8 2V5h2v6h1.17L12 13.17 9.83 11H11zm-6 7h14v2H5v-2z\"/></svg> <svg class=\"file-list__action file-list__action--delete\" @click=${()=>this._handleDelete(e)} xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 24 24\" title=\"Delete\"><path d=\"M16 9v10H8V9h8m-1.5-6h-5l-1 1H5v2h14V4h-3.5l-1-1zM18 7H6v12c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7z\"/></svg> </div> </div> `}))} </div> `:j`<div class=\"file-list__empty\">${this.emptyMessage}</div>`}}"
|
|
1271
1292
|
},
|
|
1272
1293
|
{
|
|
1273
1294
|
"kind": "variable",
|
|
1274
|
-
"name": "
|
|
1275
|
-
"default": "class extends
|
|
1295
|
+
"name": "Dt",
|
|
1296
|
+
"default": "class extends le{constructor(){super(),this.label=\"\",this.name=\"\",this.value=\"\",this.placeholder=\"\",this.type=\"text\",this.required=!1,this.disabled=!1,this.readonly=!1,this.autocomplete=\"\",this.hint=\"\",this._touched=!1,this._dirty=!1,this._handleInvalid=e=>{e.preventDefault(),this._touched=!0},this._internals=this.attachInternals()}get form(){return this._internals.form}get validity(){return this._internals.validity}get validationMessage(){return this._internals.validationMessage}get willValidate(){return this._internals.willValidate}checkValidity(){return this._internals.checkValidity()}reportValidity(){return this._internals.reportValidity()}formResetCallback(){this.value=\"\",this._touched=!1,this._dirty=!1,this._internals.setFormValue(\"\"),this._internals.setValidity({})}formStateRestoreCallback(e){this.value=e}connectedCallback(){super.connectedCallback(),this.addEventListener(\"invalid\",this._handleInvalid)}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener(\"invalid\",this._handleInvalid)}firstUpdated(){this._updateValidity()}updated(e){(e.has(\"required\")||e.has(\"value\"))&&this._updateValidity()}_updateValidity(){this._input&&this._internals.setValidity(this._input.validity,this._input.validationMessage)}_handleInput(e){this.value=e.target.value,this._dirty=!0,this._internals.setFormValue(this.value),this._internals.setValidity(this._input.validity,this._input.validationMessage)}_handleChange(e){this.value=e.target.value,this._internals.setFormValue(this.value)}_handleBlur(){this._touched=!0,this._internals.setValidity(this._input.validity,this._input.validationMessage)}render(){let e=\"\";return this._touched&&this._input&&!this._input.validity.valid&&(e=this._input.validationMessage),j` <div class=\"wrapper\"> ${this.label?j` <label for=\"input\"> ${this.label} ${this.required?j`<span class=\"required\" aria-hidden=\"true\">*</span>`:\"\"} </label> `:\"\"} <input id=\"input\" class=${we({\"input--invalid\":this._touched&&this._input&&!this._input.validity.valid})} type=${this.type} name=${this.name} .value=${Ot(this.value)} placeholder=${this.placeholder} ?required=${this.required} ?disabled=${this.disabled} ?readonly=${this.readonly} minlength=${zt(this.minlength)} maxlength=${zt(this.maxlength)} pattern=${zt(this.pattern)} autocomplete=${zt(this.autocomplete||void 0)} @input=${this._handleInput} @change=${this._handleChange} @blur=${this._handleBlur} /> ${e?j`<div class=\"validation-message\">${e}</div>`:this.hint?j`<div class=\"hint\">${this.hint}</div>`:\"\"} </div> `}focus(){this._input?.focus()}blur(){this._input?.blur()}select(){this._input?.select()}}"
|
|
1276
1297
|
},
|
|
1277
1298
|
{
|
|
1278
1299
|
"kind": "variable",
|
|
1279
|
-
"name": "
|
|
1280
|
-
"default": "class extends
|
|
1300
|
+
"name": "At",
|
|
1301
|
+
"default": "class extends le{constructor(){super(),this.label=\"\",this.name=\"\",this.value=\"\",this.placeholder=\"\",this.required=!1,this.disabled=!1,this.readonly=!1,this.rows=3,this.autocomplete=\"\",this.hint=\"\",this._touched=!1,this._dirty=!1,this._handleInvalid=e=>{e.preventDefault(),this._touched=!0},this._internals=this.attachInternals()}get form(){return this._internals.form}get validity(){return this._internals.validity}get validationMessage(){return this._internals.validationMessage}get willValidate(){return this._internals.willValidate}checkValidity(){return this._internals.checkValidity()}reportValidity(){return this._internals.reportValidity()}formResetCallback(){this.value=\"\",this._touched=!1,this._dirty=!1,this._internals.setFormValue(\"\"),this._internals.setValidity({})}formStateRestoreCallback(e){this.value=e}connectedCallback(){super.connectedCallback(),this.addEventListener(\"invalid\",this._handleInvalid)}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener(\"invalid\",this._handleInvalid)}firstUpdated(){this._updateValidity()}updated(e){(e.has(\"required\")||e.has(\"value\"))&&this._updateValidity()}_updateValidity(){this._textarea&&this._internals.setValidity(this._textarea.validity,this._textarea.validationMessage)}_handleInput(e){this.value=e.target.value,this._dirty=!0,this._internals.setFormValue(this.value),this._internals.setValidity(this._textarea.validity,this._textarea.validationMessage)}_handleChange(e){this.value=e.target.value,this._internals.setFormValue(this.value)}_handleBlur(){this._touched=!0,this._internals.setValidity(this._textarea.validity,this._textarea.validationMessage)}render(){let e=\"\";return this._touched&&this._textarea&&!this._textarea.validity.valid&&(e=this._textarea.validationMessage),j` <div class=\"wrapper\"> ${this.label?j` <label for=\"textarea\"> ${this.label} ${this.required?j`<span class=\"required\" aria-hidden=\"true\">*</span>`:F} </label> `:F} <textarea id=\"textarea\" class=${we({\"textarea--invalid\":this._touched&&this._textarea&&!this._textarea.validity.valid})} name=${this.name} .value=${Ot(this.value)} placeholder=${this.placeholder} ?required=${this.required} ?disabled=${this.disabled} ?readonly=${this.readonly} rows=${this.rows} cols=${zt(this.cols)} minlength=${zt(this.minlength)} maxlength=${zt(this.maxlength)} autocomplete=${zt(this.autocomplete||void 0)} @input=${this._handleInput} @change=${this._handleChange} @blur=${this._handleBlur} ></textarea> ${e?j`<div class=\"validation-message\">${e}</div>`:this.hint?j`<div class=\"hint\">${this.hint}</div>`:F} </div> `}focus(){this._textarea?.focus()}blur(){this._textarea?.blur()}select(){this._textarea?.select()}}"
|
|
1281
1302
|
},
|
|
1282
1303
|
{
|
|
1283
1304
|
"kind": "variable",
|
|
1284
1305
|
"name": "Rt",
|
|
1285
|
-
"default": "class extends
|
|
1306
|
+
"default": "class extends le{constructor(){super(),this._requestId=0,this._handleDocumentClick=e=>{e.composedPath().includes(this)||(this._isOpen=!1)},this.label=\"\",this.name=\"\",this.value=\"\",this.placeholder=\"\",this.disabled=!1,this.readonly=!1,this.required=!1,this.hint=\"\",this.options=[],this.fetch=null,this._isOpen=!1,this._highlightedIndex=-1,this._touched=!1,this._handleInvalid=e=>{e.preventDefault(),this._touched=!0},this._internals=this.attachInternals()}connectedCallback(){super.connectedCallback(),document.addEventListener(\"click\",this._handleDocumentClick),this.addEventListener(\"invalid\",this._handleInvalid)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener(\"click\",this._handleDocumentClick),this.removeEventListener(\"invalid\",this._handleInvalid)}firstUpdated(){this._updateValidity()}updated(e){(e.has(\"required\")||e.has(\"value\"))&&this._updateValidity(),e.has(\"options\")&&this._isOpen&&this._positionDropdown()}get form(){return this._internals.form}get validity(){return this._internals.validity}get validationMessage(){return this._internals.validationMessage}checkValidity(){return this._internals.checkValidity()}reportValidity(){return this._internals.reportValidity()}formResetCallback(){this.value=\"\",this._touched=!1,this._isOpen=!1,this._highlightedIndex=-1,this._internals.setFormValue(\"\"),this._internals.setValidity({})}formStateRestoreCallback(e){this.value=e}_updateValidity(){this._input&&this._internals.setValidity(this._input.validity,this._input.validationMessage)}_fetch(){if(!this.fetch)return;this._requestId++;const e=this._requestId;this.fetch(this.value).then((t=>{e===this._requestId&&(this.options=t)})).catch((e=>{console.error(\"kr-auto-suggest: fetch failed\",e)}))}_handleInput(e){this.value=e.target.value,this._isOpen=!0,this._highlightedIndex=-1,this._positionDropdown(),this._internals.setFormValue(this.value),this._internals.setValidity(this._input.validity,this._input.validationMessage),this.dispatchEvent(new Event(\"change\",{bubbles:!0,composed:!0})),this._fetch()}_positionDropdown(){requestAnimationFrame((()=>{const e=this.shadowRoot?.querySelector(\".dropdown\");if(!e)return;const t=this._input.getBoundingClientRect(),i=window.innerHeight-t.bottom-4-8,s=t.top-4-8;e.style.left=t.left+\"px\",e.style.width=t.width+\"px\",s>i?(e.style.top=\"\",e.style.bottom=window.innerHeight-t.top+4+\"px\",e.style.maxHeight=s+\"px\"):(e.style.bottom=\"\",e.style.top=t.bottom+4+\"px\",e.style.maxHeight=i+\"px\")}))}_handleFocus(){this._isOpen=!0,this._positionDropdown(),this._fetch()}_handleBlur(){this._touched=!0,this._internals.setValidity(this._input.validity,this._input.validationMessage),setTimeout((()=>{this._isOpen=!1,this._highlightedIndex=-1}),200)}_handleKeyDown(e){switch(e.key){case\"ArrowDown\":e.preventDefault(),this._isOpen=!0,this._highlightedIndex=Math.min(this._highlightedIndex+1,this.options.length-1),this._scrollToHighlighted();break;case\"ArrowUp\":e.preventDefault(),-1===this._highlightedIndex?(this._isOpen=!0,this._highlightedIndex=this.options.length-1):this._highlightedIndex=Math.max(this._highlightedIndex-1,0),this._scrollToHighlighted();break;case\"Enter\":this._highlightedIndex>=0&&this.options[this._highlightedIndex]&&(e.preventDefault(),this._selectOption(this.options[this._highlightedIndex]));break;case\"Escape\":e.preventDefault(),this._isOpen=!1,this._highlightedIndex=-1;break;case\"Tab\":this._isOpen=!1,this._highlightedIndex=-1}}_scrollToHighlighted(){this.updateComplete.then((()=>{const e=this.shadowRoot?.querySelector(\".dropdown\"),t=this.shadowRoot?.querySelector(\".option--highlighted\");if(e&&t){const i=e.getBoundingClientRect(),s=t.getBoundingClientRect();(s.bottom>i.bottom||s.top<i.top)&&t.scrollIntoView({block:\"nearest\"})}}))}_selectOption(e){e.disabled||(this.value=e.value,this._isOpen=!1,this._highlightedIndex=-1,this._internals.setFormValue(this.value),this.dispatchEvent(new CustomEvent(\"select\",{detail:{value:e.value,option:e},bubbles:!0,composed:!0})),this.dispatchEvent(new Event(\"change\",{bubbles:!0,composed:!0})))}_handleClear(){this.value=\"\",this._internals.setFormValue(this.value),this.dispatchEvent(new Event(\"change\",{bubbles:!0,composed:!0})),this._input?.focus()}_handleOptionMouseEnter(e,t){this._highlightedIndex=t}_renderOption(e,t){return j` <button class=${we({option:!0,\"option--highlighted\":t===this._highlightedIndex})} type=\"button\" role=\"option\" aria-selected=${t===this._highlightedIndex} ?disabled=${e.disabled} @click=${t=>this._selectOption(e)} @mouseenter=${e=>this._handleOptionMouseEnter(e,t)} > ${e.label||e.value} </button> `}render(){let e=F;return this._touched&&this._input&&!this._input.validity.valid?e=j`<div class=\"validation-message\">${this._input.validationMessage}</div>`:this.hint&&(e=j`<div class=\"hint\">${this.hint}</div>`),j` <div class=\"wrapper\"> ${this.label?j` <label> ${this.label} ${this.required?j`<span class=\"required\">*</span>`:F} </label> `:F} <div class=\"input-wrapper\"> <input type=\"text\" .value=${Ot(this.value)} placeholder=${this.placeholder} ?disabled=${this.disabled} ?readonly=${this.readonly} ?required=${this.required} name=${this.name} autocomplete=\"off\" role=\"combobox\" aria-autocomplete=\"list\" aria-expanded=${this._isOpen} aria-controls=\"dropdown\" class=${we({\"input--invalid\":this._touched&&this._input&&!this._input.validity.valid})} @input=${this._handleInput} @blur=${this._handleBlur} @focus=${this._handleFocus} @keydown=${this._handleKeyDown} /> <div class=\"icon-wrapper\"> ${!this.value||this.disabled||this.readonly?F:j` <svg class=\"clear\" viewBox=\"0 0 24 24\" fill=\"currentColor\" aria-label=\"Clear\" @click=${this._handleClear}> <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/> </svg> `} ${this.value||this.disabled||this.readonly?F:j` <svg class=\"search-icon\" viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z\"/> </svg> `} </div> </div> <div id=\"dropdown\" role=\"listbox\" class=${we({dropdown:!0,\"dropdown--open\":this._isOpen&&this.options.length>0})} > ${this.options.map(((e,t)=>this._renderOption(e,t)))} </div> ${e} </div> `}}"
|
|
1286
1307
|
},
|
|
1287
1308
|
{
|
|
1288
1309
|
"kind": "variable",
|
|
1289
|
-
"name": "
|
|
1290
|
-
"default": "class extends
|
|
1310
|
+
"name": "Ht",
|
|
1311
|
+
"default": "class extends le{constructor(){super(),this._requestId=0,this._selectedOption=null,this._handleDocumentClick=e=>{e.composedPath().includes(this)||this._close()},this.label=\"\",this.name=\"\",this.value=\"\",this.placeholder=\"Select an option\",this.disabled=!1,this.readonly=!1,this.required=!1,this.hint=\"\",this.optionValue=\"value\",this.optionLabel=\"label\",this.options=[],this.fetch=null,this.fetchSelection=null,this._isOpen=!1,this._highlightedIndex=-1,this._touched=!1,this._searchQuery=\"\",this._loading=!1,this._handleInvalid=e=>{e.preventDefault(),this._touched=!0},this._internals=this.attachInternals()}connectedCallback(){super.connectedCallback(),document.addEventListener(\"click\",this._handleDocumentClick),this.addEventListener(\"invalid\",this._handleInvalid)}disconnectedCallback(){super.disconnectedCallback(),document.removeEventListener(\"click\",this._handleDocumentClick),this.removeEventListener(\"invalid\",this._handleInvalid)}firstUpdated(){this._updateValidity(),this.value&&this.fetchSelection&&this._resolveSelection()}updated(e){(e.has(\"required\")||e.has(\"value\"))&&this._updateValidity(),e.has(\"value\")&&(this.value?this._selectedOption&&this._getOptionValue(this._selectedOption)===this.value||this._resolveSelection():this._selectedOption=null),e.has(\"options\")&&this._isOpen&&this._positionDropdown()}get form(){return this._internals.form}get validity(){return this._internals.validity}get validationMessage(){return this._internals.validationMessage}checkValidity(){return this._internals.checkValidity()}reportValidity(){return this._internals.reportValidity()}formResetCallback(){this.value=\"\",this._selectedOption=null,this._touched=!1,this._isOpen=!1,this._highlightedIndex=-1,this._searchQuery=\"\",this._internals.setFormValue(\"\"),this._internals.setValidity({})}formStateRestoreCallback(e){this.value=e}focus(){this._isOpen||this._open()}blur(){this._triggerElement?.blur()}_updateValidity(){this.required&&!this.value?this._internals.setValidity({valueMissing:!0},\"Please select an option\",this._triggerElement):this._internals.setValidity({})}_handleTriggerClick(){this.disabled||this.readonly||(this._isOpen?this._close():this._open())}_open(){this._isOpen=!0,this._searchQuery=\"\",this._highlightedIndex=-1,this._fetch(),this.updateComplete.then((()=>{this._positionDropdown(),this._searchInput&&this._searchInput.focus()}))}_close(){this._isOpen=!1,this._highlightedIndex=-1,this._searchQuery=\"\"}_positionDropdown(){requestAnimationFrame((()=>{const e=this.shadowRoot?.querySelector(\".dropdown\");if(!e)return;const t=this._triggerElement.getBoundingClientRect(),i=window.innerHeight-t.bottom-4-8,s=t.top-4-8;e.style.left=t.left+\"px\",e.style.width=t.width+\"px\",i<200&&s>i?(e.style.top=\"\",e.style.bottom=window.innerHeight-t.top+4+\"px\",e.style.maxHeight=s+\"px\"):(e.style.bottom=\"\",e.style.top=t.bottom+4+\"px\",e.style.maxHeight=i+\"px\")}))}_fetch(){if(!this.fetch)return;this._loading=!0,this._requestId++;const e=this._requestId;this.fetch(this._searchQuery).then((t=>{e===this._requestId&&(this.options=t,this._loading=!1)})).catch((e=>{console.error(\"kr-combo-box: fetch failed\",e),this._loading=!1}))}_handleSearchInput(e){this._searchQuery=e.target.value,this._highlightedIndex=-1,this._fetch()}_handleSearchKeyDown(e){switch(e.key){case\"ArrowDown\":e.preventDefault(),this._highlightedIndex=Math.min(this._highlightedIndex+1,this.options.length-1),this._scrollToHighlighted();break;case\"ArrowUp\":e.preventDefault(),-1===this._highlightedIndex?this._highlightedIndex=this.options.length-1:this._highlightedIndex=Math.max(this._highlightedIndex-1,0),this._scrollToHighlighted();break;case\"Enter\":e.preventDefault(),this._highlightedIndex>=0&&this.options[this._highlightedIndex]&&this._selectOption(this.options[this._highlightedIndex]);break;case\"Escape\":e.preventDefault(),this._close(),this._triggerElement?.focus();break;case\"Tab\":this._close()}}_handleTriggerKeyDown(e){\"ArrowDown\"!==e.key&&\"ArrowUp\"!==e.key&&\"Enter\"!==e.key&&\" \"!==e.key||(e.preventDefault(),this._isOpen||this._open())}_handleTriggerBlur(){this._touched=!0,this._updateValidity()}_scrollToHighlighted(){this.updateComplete.then((()=>{const e=this.shadowRoot?.querySelector(\".options\"),t=this.shadowRoot?.querySelector(\".option--highlighted\");if(e&&t){const i=e.getBoundingClientRect(),s=t.getBoundingClientRect();(s.bottom>i.bottom||s.top<i.top)&&t.scrollIntoView({block:\"nearest\"})}}))}_getOptionValue(e){return\"function\"==typeof this.optionValue?this.optionValue(e):e[this.optionValue]}_getOptionLabel(e){let t;return t=\"function\"==typeof this.optionLabel?this.optionLabel(e):e[this.optionLabel],t||this._getOptionValue(e)}_resolveSelection(){if(!this.fetchSelection)return;const e=this.value;this.fetchSelection(this.value).then((t=>{this.value===e&&t&&(this._selectedOption=t,this.requestUpdate())})).catch((e=>{console.error(\"kr-combo-box: fetchSelection failed\",e)}))}_selectOption(e){e.disabled||(this.value=this._getOptionValue(e),this._selectedOption=e,this._close(),this._internals.setFormValue(this.value),this._updateValidity(),this.dispatchEvent(new CustomEvent(\"select\",{detail:{option:e},bubbles:!0,composed:!0})),this.dispatchEvent(new Event(\"change\",{bubbles:!0,composed:!0})),this._triggerElement?.focus())}_handleOptionMouseEnter(e,t){this._highlightedIndex=t}_renderOption(e,t){const i=this._getOptionValue(e);return j` <button class=${we({option:!0,\"option--highlighted\":t===this._highlightedIndex,\"option--selected\":i===this.value})} type=\"button\" role=\"option\" aria-selected=${i===this.value} ?disabled=${e.disabled} @click=${t=>this._selectOption(e)} @mouseenter=${e=>this._handleOptionMouseEnter(e,t)} > ${this._getOptionLabel(e)} </button> `}render(){let e=F;return this._touched&&this.required&&!this.value?e=j`<div class=\"validation-message\">Please select an option</div>`:this.hint&&(e=j`<div class=\"hint\">${this.hint}</div>`),j` <div class=\"wrapper\"> ${this.label?j` <label> ${this.label} ${this.required?j`<span class=\"required\">*</span>`:F} </label> `:F} <button class=${we({trigger:!0,\"trigger--open\":this._isOpen,\"trigger--invalid\":this._touched&&this.required&&!this.value})} type=\"button\" ?disabled=${this.disabled} aria-haspopup=\"listbox\" aria-expanded=${this._isOpen} @click=${this._handleTriggerClick} @keydown=${this._handleTriggerKeyDown} @blur=${this._handleTriggerBlur} > <span class=${we({trigger__value:!0,trigger__placeholder:!this._selectedOption})}> ${this._selectedOption?this._getOptionLabel(this._selectedOption):this.placeholder} </span> <svg class=${we({trigger__icon:!0,\"trigger__icon--open\":this._isOpen})} viewBox=\"0 0 24 24\" fill=\"currentColor\" > <path d=\"M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6z\"/> </svg> </button> <div role=\"listbox\" class=${we({dropdown:!0,\"dropdown--open\":this._isOpen})} > <div class=\"search\"> <div class=\"search__field\"> <input class=\"search__input\" type=\"text\" placeholder=\"Search...\" .value=${this._searchQuery} @input=${this._handleSearchInput} @keydown=${this._handleSearchKeyDown} /> <svg class=\"search__icon\" viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z\"/> </svg> </div> </div> <div class=\"options\"> ${this._loading?j`<div class=\"empty\">Loading...</div>`:0===this.options.length?j`<div class=\"empty\">No options found</div>`:this.options.map(((e,t)=>this._renderOption(e,t)))} </div> </div> ${e} </div> `}}"
|
|
1291
1312
|
},
|
|
1292
1313
|
{
|
|
1293
1314
|
"kind": "variable",
|
|
1294
|
-
"name": "
|
|
1295
|
-
"default": "class extends
|
|
1315
|
+
"name": "jt",
|
|
1316
|
+
"default": "class extends le{constructor(){super(),this._focusedIndex=-1,this.label=\"\",this.name=\"\",this.value=\"\",this.options=[],this.disabled=!1,this.required=!1,this.hint=\"\",this.direction=\"row\",this._touched=!1,this._handleInvalid=e=>{e.preventDefault(),this._touched=!0},this._internals=this.attachInternals()}get form(){return this._internals.form}get validity(){return this._internals.validity}get validationMessage(){return this._internals.validationMessage}get willValidate(){return this._internals.willValidate}checkValidity(){return this._internals.checkValidity()}reportValidity(){return this._internals.reportValidity()}formResetCallback(){this.value=\"\",this._touched=!1,this._internals.setFormValue(\"\"),this._internals.setValidity({})}formStateRestoreCallback(e){this.value=e}connectedCallback(){super.connectedCallback(),this.addEventListener(\"invalid\",this._handleInvalid)}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener(\"invalid\",this._handleInvalid)}firstUpdated(){this._updateValidity()}updated(e){(e.has(\"required\")||e.has(\"value\"))&&this._updateValidity()}_updateValidity(){this.required&&!this.value?this._internals.setValidity({valueMissing:!0},\"Please select an option\"):this._internals.setValidity({})}_handleCardClick(e,t){this.disabled||t.disabled||(this.value=t.value,this._touched=!0,this._internals.setFormValue(this.value),this._updateValidity(),this.dispatchEvent(new Event(\"change\",{bubbles:!0,composed:!0})))}_handleKeyDown(e,t){if(this.disabled)return;if(\" \"===e.key||\"Enter\"===e.key)return e.preventDefault(),void(this.options[t].disabled||this._handleCardClick(e,this.options[t]));let i=-1;if(\"row\"===this.direction?\"ArrowRight\"===e.key?i=this._findNextEnabledIndex(t,1):\"ArrowLeft\"===e.key&&(i=this._findNextEnabledIndex(t,-1)):\"ArrowDown\"===e.key?i=this._findNextEnabledIndex(t,1):\"ArrowUp\"===e.key&&(i=this._findNextEnabledIndex(t,-1)),i>=0){e.preventDefault(),this._focusedIndex=i;const t=this.shadowRoot?.querySelectorAll(\".card\");t[i]&&t[i].focus()}}_findNextEnabledIndex(e,t){let i=e+t;for(;i>=0&&i<this.options.length;){if(!this.options[i].disabled)return i;i+=t}return-1}render(){return j` <div class=\"wrapper\"> ${this.label?j` <label> ${this.label} ${this.required?j`<span class=\"required\" aria-hidden=\"true\">*</span>`:F} </label> `:F} <div class=${we({cards:!0,\"cards--row\":\"row\"===this.direction,\"cards--column\":\"column\"===this.direction})} role=\"radiogroup\" aria-label=${this.label} > ${this.options.map(((e,t)=>{const i=e.value===this.value,s=this.disabled||!!e.disabled;return j` <div class=${we({card:!0,\"card--selected\":i,\"card--disabled\":s})} role=\"radio\" aria-checked=${i} aria-disabled=${s} tabindex=${s?-1:0} @click=${t=>this._handleCardClick(t,e)} @keydown=${e=>this._handleKeyDown(e,t)} > <div class=\"card__radio\"> ${i?j`<div class=\"card__radio-dot\"></div>`:F} </div> <div class=\"card__content\"> <div class=\"card__label\">${e.label}</div> ${e.description?j`<div class=\"card__description\">${e.description}</div>`:F} </div> </div> `}))} </div> ${this._touched&&this.required&&!this.value?j`<div class=\"validation-message\">Please select an option</div>`:this.hint?j`<div class=\"hint\">${this.hint}</div>`:F} </div> `}}"
|
|
1317
|
+
},
|
|
1318
|
+
{
|
|
1319
|
+
"kind": "variable",
|
|
1320
|
+
"name": "Ft",
|
|
1321
|
+
"default": "class extends le{constructor(){super(),this.label=\"\",this.name=\"\",this.value=\"on\",this.checked=!1,this.disabled=!1,this.required=!1,this.hint=\"\",this._touched=!1,this._handleInvalid=e=>{e.preventDefault(),this._touched=!0},this._internals=this.attachInternals()}get form(){return this._internals.form}get validity(){return this._internals.validity}get validationMessage(){return this._internals.validationMessage}get willValidate(){return this._internals.willValidate}checkValidity(){return this._internals.checkValidity()}reportValidity(){return this._internals.reportValidity()}formResetCallback(){this.checked=!1,this._touched=!1,this._internals.setFormValue(\"\"),this._internals.setValidity({})}formStateRestoreCallback(e){this.checked=e===this.value}connectedCallback(){super.connectedCallback(),this.addEventListener(\"invalid\",this._handleInvalid)}disconnectedCallback(){super.disconnectedCallback(),this.removeEventListener(\"invalid\",this._handleInvalid)}firstUpdated(){this._syncFormValue(),this._updateValidity()}updated(e){(e.has(\"checked\")||e.has(\"value\"))&&this._syncFormValue(),(e.has(\"required\")||e.has(\"checked\"))&&this._updateValidity()}_syncFormValue(){this.checked?this._internals.setFormValue(this.value):this._internals.setFormValue(\"\")}_updateValidity(){this.required&&!this.checked?this._internals.setValidity({valueMissing:!0},\"This field is required\"):this._internals.setValidity({})}_handleClick(e){this.disabled||(this.checked=!this.checked,this._touched=!0,this.dispatchEvent(new Event(\"change\",{bubbles:!0,composed:!0})))}_handleKeyDown(e){this.disabled||\" \"!==e.key&&\"Enter\"!==e.key||(e.preventDefault(),this._handleClick(e))}render(){return j` <div class=\"wrapper\"> <div class=${we({checkbox:!0,\"checkbox--disabled\":this.disabled})} role=\"checkbox\" aria-checked=${this.checked} aria-disabled=${this.disabled} aria-label=${this.label} tabindex=${this.disabled?-1:0} @click=${this._handleClick} @keydown=${this._handleKeyDown} > <div class=${we({checkbox__box:!0,\"checkbox__box--checked\":this.checked,\"checkbox__box--invalid\":this._touched&&this.required&&!this.checked})}> <svg class=${we({checkbox__check:!0,\"checkbox__check--hidden\":!this.checked})} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\"> <polyline points=\"20 6 9 17 4 12\"></polyline> </svg> </div> ${this.label?j` <span class=\"checkbox__label\"> ${this.label} ${this.required?j`<span class=\"required\" aria-hidden=\"true\">*</span>`:F} </span> `:F} </div> ${this._touched&&this.required&&!this.checked?j`<div class=\"validation-message\">This field is required</div>`:this.hint?j`<div class=\"hint\">${this.hint}</div>`:F} </div> `}focus(){this.shadowRoot?.querySelector(\".checkbox\")?.focus()}blur(){this.shadowRoot?.querySelector(\".checkbox\")?.blur()}}"
|
|
1296
1322
|
}
|
|
1297
1323
|
],
|
|
1298
1324
|
"exports": [
|
|
@@ -1332,7 +1358,7 @@
|
|
|
1332
1358
|
"kind": "js",
|
|
1333
1359
|
"name": "KRAutoSuggest",
|
|
1334
1360
|
"declaration": {
|
|
1335
|
-
"name": "
|
|
1361
|
+
"name": "Rt",
|
|
1336
1362
|
"module": "dist/krubble-components.bundled.min.js"
|
|
1337
1363
|
}
|
|
1338
1364
|
},
|
|
@@ -1340,7 +1366,7 @@
|
|
|
1340
1366
|
"kind": "js",
|
|
1341
1367
|
"name": "KRButton",
|
|
1342
1368
|
"declaration": {
|
|
1343
|
-
"name": "
|
|
1369
|
+
"name": "ze",
|
|
1344
1370
|
"module": "dist/krubble-components.bundled.min.js"
|
|
1345
1371
|
}
|
|
1346
1372
|
},
|
|
@@ -1348,7 +1374,7 @@
|
|
|
1348
1374
|
"kind": "js",
|
|
1349
1375
|
"name": "KRCheckbox",
|
|
1350
1376
|
"declaration": {
|
|
1351
|
-
"name": "
|
|
1377
|
+
"name": "Ft",
|
|
1352
1378
|
"module": "dist/krubble-components.bundled.min.js"
|
|
1353
1379
|
}
|
|
1354
1380
|
},
|
|
@@ -1364,7 +1390,7 @@
|
|
|
1364
1390
|
"kind": "js",
|
|
1365
1391
|
"name": "KRComboBox",
|
|
1366
1392
|
"declaration": {
|
|
1367
|
-
"name": "
|
|
1393
|
+
"name": "Ht",
|
|
1368
1394
|
"module": "dist/krubble-components.bundled.min.js"
|
|
1369
1395
|
}
|
|
1370
1396
|
},
|
|
@@ -1372,7 +1398,7 @@
|
|
|
1372
1398
|
"kind": "js",
|
|
1373
1399
|
"name": "KRContextMenu",
|
|
1374
1400
|
"declaration": {
|
|
1375
|
-
"name": "
|
|
1401
|
+
"name": "Ae",
|
|
1376
1402
|
"module": "dist/krubble-components.bundled.min.js"
|
|
1377
1403
|
}
|
|
1378
1404
|
},
|
|
@@ -1380,7 +1406,7 @@
|
|
|
1380
1406
|
"kind": "js",
|
|
1381
1407
|
"name": "KRDateRangePicker",
|
|
1382
1408
|
"declaration": {
|
|
1383
|
-
"name": "
|
|
1409
|
+
"name": "Ue",
|
|
1384
1410
|
"module": "dist/krubble-components.bundled.min.js"
|
|
1385
1411
|
}
|
|
1386
1412
|
},
|
|
@@ -1404,7 +1430,7 @@
|
|
|
1404
1430
|
"kind": "js",
|
|
1405
1431
|
"name": "KRFileList",
|
|
1406
1432
|
"declaration": {
|
|
1407
|
-
"name": "
|
|
1433
|
+
"name": "St",
|
|
1408
1434
|
"module": "dist/krubble-components.bundled.min.js"
|
|
1409
1435
|
}
|
|
1410
1436
|
},
|
|
@@ -1412,7 +1438,15 @@
|
|
|
1412
1438
|
"kind": "js",
|
|
1413
1439
|
"name": "KRFilePreview",
|
|
1414
1440
|
"declaration": {
|
|
1415
|
-
"name": "
|
|
1441
|
+
"name": "$t",
|
|
1442
|
+
"module": "dist/krubble-components.bundled.min.js"
|
|
1443
|
+
}
|
|
1444
|
+
},
|
|
1445
|
+
{
|
|
1446
|
+
"kind": "js",
|
|
1447
|
+
"name": "KRGrid",
|
|
1448
|
+
"declaration": {
|
|
1449
|
+
"name": "vt",
|
|
1416
1450
|
"module": "dist/krubble-components.bundled.min.js"
|
|
1417
1451
|
}
|
|
1418
1452
|
},
|
|
@@ -1420,7 +1454,7 @@
|
|
|
1420
1454
|
"kind": "js",
|
|
1421
1455
|
"name": "KRProgressBar",
|
|
1422
1456
|
"declaration": {
|
|
1423
|
-
"name": "
|
|
1457
|
+
"name": "xt",
|
|
1424
1458
|
"module": "dist/krubble-components.bundled.min.js"
|
|
1425
1459
|
}
|
|
1426
1460
|
},
|
|
@@ -1436,7 +1470,7 @@
|
|
|
1436
1470
|
"kind": "js",
|
|
1437
1471
|
"name": "KRRadioCards",
|
|
1438
1472
|
"declaration": {
|
|
1439
|
-
"name": "
|
|
1473
|
+
"name": "jt",
|
|
1440
1474
|
"module": "dist/krubble-components.bundled.min.js"
|
|
1441
1475
|
}
|
|
1442
1476
|
},
|
|
@@ -1468,7 +1502,7 @@
|
|
|
1468
1502
|
"kind": "js",
|
|
1469
1503
|
"name": "KRSpinner",
|
|
1470
1504
|
"declaration": {
|
|
1471
|
-
"name": "
|
|
1505
|
+
"name": "mt",
|
|
1472
1506
|
"module": "dist/krubble-components.bundled.min.js"
|
|
1473
1507
|
}
|
|
1474
1508
|
},
|
|
@@ -1500,7 +1534,7 @@
|
|
|
1500
1534
|
"kind": "js",
|
|
1501
1535
|
"name": "KRTextField",
|
|
1502
1536
|
"declaration": {
|
|
1503
|
-
"name": "
|
|
1537
|
+
"name": "Dt",
|
|
1504
1538
|
"module": "dist/krubble-components.bundled.min.js"
|
|
1505
1539
|
}
|
|
1506
1540
|
},
|
|
@@ -1508,7 +1542,7 @@
|
|
|
1508
1542
|
"kind": "js",
|
|
1509
1543
|
"name": "KRTextareaField",
|
|
1510
1544
|
"declaration": {
|
|
1511
|
-
"name": "
|
|
1545
|
+
"name": "At",
|
|
1512
1546
|
"module": "dist/krubble-components.bundled.min.js"
|
|
1513
1547
|
}
|
|
1514
1548
|
},
|
|
@@ -1772,6 +1806,14 @@
|
|
|
1772
1806
|
"module": "./table/table.js"
|
|
1773
1807
|
}
|
|
1774
1808
|
},
|
|
1809
|
+
{
|
|
1810
|
+
"kind": "js",
|
|
1811
|
+
"name": "KRGrid",
|
|
1812
|
+
"declaration": {
|
|
1813
|
+
"name": "KRGrid",
|
|
1814
|
+
"module": "./grid/grid.js"
|
|
1815
|
+
}
|
|
1816
|
+
},
|
|
1775
1817
|
{
|
|
1776
1818
|
"kind": "js",
|
|
1777
1819
|
"name": "KRQuery",
|
|
@@ -2386,6 +2428,27 @@
|
|
|
2386
2428
|
}
|
|
2387
2429
|
]
|
|
2388
2430
|
},
|
|
2431
|
+
{
|
|
2432
|
+
"kind": "javascript-module",
|
|
2433
|
+
"path": "dist/grid/grid.js",
|
|
2434
|
+
"declarations": [
|
|
2435
|
+
{
|
|
2436
|
+
"kind": "variable",
|
|
2437
|
+
"name": "KRGrid",
|
|
2438
|
+
"default": "class KRGrid extends LitElement { constructor() { super(...arguments); /** * Internal flag to switch between scroll edge modes: * - 'overlay': Fixed padding with overlay elements that hide content at edges (scrollbar at viewport edge) * - 'edge': Padding scrolls with content, allowing table to reach edges when scrolling */ this._scrollStyle = 'edge'; this._data = []; this._dataState = 'idle'; this._page = 1; this._pageSize = 50; this._totalItems = 0; this._totalPages = 0; this._searchQuery = ''; this._canScrollLeft = false; this._canScrollRight = false; this._canScrollHorizontal = false; this._columnPickerOpen = false; this._filterPanelOpened = null; this._filterPanelTab = 'filter'; this._buckets = new Map(); this._filterPanelPos = { top: 0, left: 0 }; this._sorts = []; this._resizing = null; this._resizeObserver = null; this._searchPositionLocked = false; this._columnWidthsLocked = false; this._model = new KRGridModel(); this.def = { columns: [] }; /** * Table layout variant. * - 'default': Full-page table that fills parent height with centered search. * - 'card': Embedded table that sizes itself to content, left-aligns search, and * reserves space for pageSize rows to prevent layout shift. */ this.variant = 'default'; this._handleClickOutside = (e) => { const path = e.composedPath(); if (this._columnPickerOpen) { const picker = this.shadowRoot?.querySelector('.column-picker-wrapper'); if (picker && !path.includes(picker)) { this._columnPickerOpen = false; } } if (this._filterPanelOpened) { if (!path.some((el) => el.classList?.contains('filter-panel'))) { this._handleFilterApply(); } } }; this._handleResizeMove = (e) => { if (!this._resizing) return; const col = this._model.columns.find(c => c.id === this._resizing.columnId); if (col) { const newWidth = this._resizing.startWidth + (e.clientX - this._resizing.startX); col.width = `${Math.min(900, Math.max(50, newWidth))}px`; this.requestUpdate(); } }; this._handleResizeEnd = () => { this._resizing = null; document.removeEventListener('mousemove', this._handleResizeMove); document.removeEventListener('mouseup', this._handleResizeEnd); }; } connectedCallback() { super.connectedCallback(); this.classList.toggle('kr-table--scroll-overlay', this._scrollStyle === 'overlay'); this.classList.toggle('kr-table--scroll-edge', this._scrollStyle === 'edge'); this._fetch(); this._initRefresh(); document.addEventListener('click', this._handleClickOutside); this._resizeObserver = new ResizeObserver(() => { // Unlock and recalculate on resize since layout changes this._searchPositionLocked = false; this._updateSearchPosition(); }); this._resizeObserver.observe(this); } disconnectedCallback() { super.disconnectedCallback(); clearInterval(this._refreshTimer); document.removeEventListener('click', this._handleClickOutside); this._resizeObserver?.disconnect(); } willUpdate(changedProperties) { if (changedProperties.has('def')) { // Build internal model from user-provided def this._columnWidthsLocked = false; this._model = new KRGridModel(); if (this.def.title) { this._model.title = this.def.title; } if (this.def.description) { this._model.description = this.def.description; } if (this.def.actions) { this._model.actions = this.def.actions; } if (this.def.data) { this._model.data = this.def.data; } if (this.def.dataSource) { this._model.dataSource = this.def.dataSource; } if (typeof this.def.refreshInterval === 'number') { this._model.refreshInterval = this.def.refreshInterval; } if (typeof this.def.pageSize === 'number') { this._model.pageSize = this.def.pageSize; this._pageSize = this.def.pageSize; } if (this.def.rowClickable) { this._model.rowClickable = this.def.rowClickable; } if (this.def.rowHref) { this._model.rowHref = this.def.rowHref; } this._sorts = []; this._model.columns = this.def.columns.map(col => { const column = { ...col, filter: null }; if (!column.type) { column.type = 'string'; } if (col.sort) { this._sorts.push({ sortBy: col.id, sortDirection: col.sort }); } if (column.type === 'actions') { column.label = col.label ?? ''; column.sticky = 'right'; column.resizable = false; return column; } if (col.filterable || col.facetable) { column.filter = new KRQuery(); column.filter.field = col.id; column.filter.type = column.type; if (col.filter) { column.filter.setOperator(col.filter.operator); column.filter.setValue(col.filter.value); } else if (col.facetable && !col.filterable) { column.filter.operator = 'in'; column.filter.value = []; } else if (column.filter.type === 'string') { column.filter.operator = 'contains'; } } return column; }); if (this.def.displayedColumns) { this._model.displayedColumns = this.def.displayedColumns; } else { this._model.displayedColumns = this._model.columns.map(c => c.id); } this._fetch(); this._initRefresh(); } } updated(changedProperties) { this.classList.toggle('kr-table--card', this.variant === 'card'); this._updateScrollFlags(); this._syncSlottedContent(); this._lockColumnWidths(); } /** Measures header cell widths and locks them to prevent column shift on subsequent data changes. */ _lockColumnWidths() { if (this._columnWidthsLocked || this._data.length === 0) return; const headerCells = this.shadowRoot?.querySelectorAll('.header-row > .header-cell'); if (!headerCells) return; const cols = this.getDisplayedColumns(); headerCells.forEach((cell, i) => { const cellWidth = cell.offsetWidth; if (i < cols.length && !cols[i].width && cols[i].type !== 'actions' && cellWidth > 0) { cols[i].width = `${cellWidth}px`; this._columnWidthsLocked = true; } }); } /** Syncs light DOM content for cells with custom render functions */ _syncSlottedContent() { const columns = this.getDisplayedColumns().filter(col => col.render); if (!columns.length) return; // Clear old slotted content this.querySelectorAll('[slot^=\"cell-\"]').forEach(el => el.remove()); // Create new slotted content this._data.forEach((row, rowIndex) => { columns.forEach(col => { const result = col.render(row); if (!result) return; const el = document.createElement('span'); el.slot = `cell-${rowIndex}-${col.id}`; if (col.type === 'actions') { el.style.display = 'flex'; el.style.gap = '8px'; } if (typeof result === 'string') { el.innerHTML = result; } else { render(result, el); } this.appendChild(el); }); }); } // ---------------------------------------------------------------------------- // Public Interface // ---------------------------------------------------------------------------- refresh() { this._fetch(); } goToPrevPage() { if (this._page > 1) { this._page--; this._fetch(); } } goToNextPage() { if (this._page < this._totalPages) { this._page++; this._fetch(); } } goToPage(page) { if (page >= 1 && page <= this._totalPages) { this._page = page; this._fetch(); } } // ---------------------------------------------------------------------------- // Data Fetching // ---------------------------------------------------------------------------- _toSolrData() { const request = { page: this._page - 1, size: this._pageSize, sorts: this._sorts, filterFields: [], queryFields: [], facetFields: [] }; for (const col of this._model.columns) { if (!col.filter || col.filter.isEmpty() || !col.filter.isValid()) { continue; } const filterData = col.filter.toSolrData(); if (col.facetable && (col.filter.operator === 'in' || col.filter.operator === 'n_in')) { filterData.tagged = true; } request.filterFields.push(filterData); } for (const col of this._model.columns) { if (!col.facetable) { continue; } request.facetFields.push({ name: col.id, type: 'FIELD', limit: 100, sort: 'count', minimumCount: 1 }); } if (this._searchQuery?.trim().length) { request.queryFields.push({ name: '_text_', operation: 'IS', value: termify(this._searchQuery, false) }); } return request; } _toDbParams() { const request = { page: this._page - 1, size: this._pageSize, sorts: this._sorts, filterFields: [], queryFields: [], facetFields: [] }; for (const col of this._model.columns) { if (!col.filter || col.filter.isEmpty() || !col.filter.isValid()) { continue; } request.filterFields.push(col.filter.toDbParams()); } if (this._searchQuery?.trim().length) { this._model.columns.filter(col => col.searchable).forEach(col => { request.queryFields.push({ name: col.id, operation: 'CONTAINS', value: this._searchQuery, and: false }); }); } return request; } /** * Fetches data from the API and updates the table. * Shows a loading spinner while fetching, then displays rows on success * or an error snackbar on failure. * Request/response format depends on dataSource.mode (solr, opensearch, db). */ _fetch() { if (this._model.data) { this._data = this._model.data; this._totalItems = this._model.data.length; this._totalPages = Math.ceil(this._model.data.length / this._pageSize); this._dataState = 'success'; return; } if (!this._model.dataSource) return; this._dataState = 'loading'; let request; if (this._model.dataSource.mode === 'db') { request = this._toDbParams(); } else { request = this._toSolrData(); } this._model.dataSource.fetch(request) .then(response => { // Parse response based on mode switch (this._model.dataSource?.mode) { case 'opensearch': { throw Error('Opensearch not supported yet'); break; } case 'db': { const res = response; this._data = res.data.content; this._totalItems = res.data.totalElements; this._totalPages = res.data.totalPages; this._pageSize = res.data.size; break; } default: { // solr const res = response; this._data = res.data.content; this._totalItems = res.data.totalElements; this._totalPages = res.data.totalPages; this._pageSize = res.data.size; this._parseFacetResults(res); } } this._dataState = 'success'; this._updateSearchPosition(); }) .catch(err => { this._dataState = 'error'; KRSnackbar.show({ message: err instanceof Error ? err.message : 'Failed to load data', type: 'error' }); }); } _parseFacetResults(response) { if (!response.data.facetFields) { return; } for (const col of this._model.columns) { if (!col.facetable) { continue; } const rawBuckets = response.data.facetFields[col.id]; if (!rawBuckets) { this._buckets.set(col.id, []); continue; } const buckets = []; for (const raw of rawBuckets) { // Solr returns boolean facet values as strings — coerce to actual booleans // so they match the filter values stored by toggle(). let val = raw.name; if (col.type === 'boolean' && typeof raw.name === 'string') { if (raw.name === 'true') { val = true; } else if (raw.name === 'false') { val = false; } } if (raw.name === null && raw.count > 0) { buckets.unshift({ val: null, count: raw.count }); } if (raw.name !== null) { buckets.push({ val: val, count: raw.count }); } } // Bucket sync: ensure selected values appear even with 0 results if (col.filter && (col.filter.operator === 'in' || col.filter.operator === 'n_in') && Array.isArray(col.filter.value)) { for (const selectedVal of col.filter.value) { if (!buckets.some(b => b.val === selectedVal)) { buckets.push({ val: selectedVal, count: 0 }); } } } this._buckets.set(col.id, buckets); } // Trigger re-render since Map mutation doesn't trigger Lit updates this._buckets = new Map(this._buckets); } /** * Sets up auto-refresh so the table automatically fetches fresh data * at a regular interval (useful for dashboards, monitoring views). * Configured via def.refreshInterval in milliseconds. */ _initRefresh() { clearInterval(this._refreshTimer); if (this._model.refreshInterval && this._model.refreshInterval > 0) { this._refreshTimer = window.setInterval(() => { this._fetch(); }, this._model.refreshInterval); } } _handleSearch(e) { const input = e.target; this._searchQuery = input.value; this._page = 1; this._fetch(); } _getGridTemplateColumns() { const cols = this.getDisplayedColumns(); return cols.map((col) => { // If column has explicit width, use it if (col.width) { return col.width; } // Actions columns: fit content without minimum if (col.type === 'actions') { return 'max-content'; } // No width specified - use content-based sizing with minimum return 'minmax(80px, auto)'; }).join(' '); } /** * Updates search position to be centered with equal gaps from title and tools. * On first call: resets to flex centering, measures position, then locks with fixed margin. * Subsequent calls are ignored unless _searchPositionLocked is reset (e.g., on resize). */ _updateSearchPosition() { // Skip if already locked (prevents shifts on pagination changes) if (this._searchPositionLocked) return; // In card mode, search is left-aligned via CSS — no position locking needed if (this.variant === 'card') return; const search = this.shadowRoot?.querySelector('.search'); const searchField = search?.querySelector('.search-field'); if (!search || !searchField) return; // Reset to flex centering search.style.justifyContent = 'center'; searchField.style.marginLeft = ''; requestAnimationFrame(() => { const searchRect = search.getBoundingClientRect(); const fieldRect = searchField.getBoundingClientRect(); // Calculate how far from the left of search container the field currently is const currentOffset = fieldRect.left - searchRect.left; // Lock position: switch to flex-start and use fixed margin search.style.justifyContent = 'flex-start'; searchField.style.marginLeft = `${currentOffset}px`; // Mark as locked so pagination changes don't shift the search this._searchPositionLocked = true; }); } // ---------------------------------------------------------------------------- // Columns // ---------------------------------------------------------------------------- _toggleColumnPicker() { this._columnPickerOpen = !this._columnPickerOpen; } _toggleColumn(columnId) { if (this._model.displayedColumns.includes(columnId)) { this._model.displayedColumns = this._model.displayedColumns.filter(id => id !== columnId); } else { this._model.displayedColumns = [...this._model.displayedColumns, columnId]; } this.requestUpdate(); } // Clear any existing text selection on mousedown so we only detect // selections made during this click gesture, not stale selections from elsewhere _handleRowMouseDown() { if (!this._model.rowClickable && !this._model.rowHref) { return; } window.getSelection()?.removeAllRanges(); } _handleRowClick(e, row, rowIndex) { if (!this._model.rowClickable && !this._model.rowHref) { return; } const selection = window.getSelection(); if (selection && selection.toString().length > 0) { e.preventDefault(); return; } this.dispatchEvent(new CustomEvent('row-click', { detail: { row, rowIndex }, bubbles: true, composed: true })); } // When a user toggles a column on via the column picker, it gets appended // to _displayedColumns. By mapping over _displayedColumns (not def.columns), // the new column appears at the right edge of the table instead of jumping // back to its original position in the column definition. // Actions columns are always moved to the end. getDisplayedColumns() { return this._model.displayedColumns .map(id => this._model.columns.find(col => col.id === id)) .sort((a, b) => { if (a.type === 'actions' && b.type !== 'actions') return 1; if (a.type !== 'actions' && b.type === 'actions') return -1; return 0; }); } // ---------------------------------------------------------------------------- // Scrolling // ---------------------------------------------------------------------------- /** * Scroll event handler that updates scroll flags in real-time as user scrolls. * Updates shadow indicators to show if more content exists left/right. */ _handleScroll(e) { const container = e.target; this._canScrollLeft = container.scrollLeft > 0; this._canScrollRight = container.scrollLeft < container.scrollWidth - container.clientWidth - 1; } /** * Updates scroll state flags for the table content container. * - _canScrollLeft: true if scrolled right (can scroll back left) * - _canScrollRight: true if more content exists to the right * - _canScrollHorizontal: true if content is wider than container * These flags control scroll shadow indicators and CSS classes. */ _updateScrollFlags() { const container = this.shadowRoot?.querySelector('.content'); if (container) { this._canScrollLeft = container.scrollLeft > 0; this._canScrollRight = container.scrollWidth > container.clientWidth && container.scrollLeft < container.scrollWidth - container.clientWidth - 1; this._canScrollHorizontal = container.scrollWidth > container.clientWidth; } this.classList.toggle('kr-table--scroll-left-available', this._canScrollLeft); this.classList.toggle('kr-table--scroll-right-available', this._canScrollRight); this.classList.toggle('kr-table--scroll-horizontal-available', this._canScrollHorizontal); this.classList.toggle('kr-table--sticky-left', this.getDisplayedColumns().some(c => c.sticky === 'left')); this.classList.toggle('kr-table--sticky-right', this.getDisplayedColumns().some(c => c.sticky === 'right')); } // ---------------------------------------------------------------------------- // Column Resizing // ---------------------------------------------------------------------------- _handleResizeStart(e, columnId) { e.preventDefault(); const headerCell = this.shadowRoot?.querySelector(`.header-cell[data-column-id=\"${columnId}\"]`); this._resizing = { columnId, startX: e.clientX, startWidth: headerCell?.offsetWidth || 200 }; document.addEventListener('mousemove', this._handleResizeMove); document.addEventListener('mouseup', this._handleResizeEnd); } // ---------------------------------------------------------------------------- // Sorting // ---------------------------------------------------------------------------- _handleSortClick(e, column) { if (e.shiftKey) { // Multi-sort: add or cycle existing const existingIndex = this._sorts.findIndex(s => s.sortBy === column.id); if (existingIndex === -1) { this._sorts.push({ sortBy: column.id, sortDirection: 'asc' }); } else { const existing = this._sorts[existingIndex]; if (existing.sortDirection === 'asc') { existing.sortDirection = 'desc'; } else { // on third click, remove sorting for the column this._sorts.splice(existingIndex, 1); } } this.requestUpdate(); } else { // Single sort: replace all let existing = null; if (this._sorts.length === 1) { existing = this._sorts.find(s => s.sortBy === column.id); } if (!existing) { this._sorts = [{ sortBy: column.id, sortDirection: 'asc' }]; } else if (existing.sortDirection === 'asc') { this._sorts = [{ sortBy: column.id, sortDirection: 'desc' }]; } else { this._sorts = []; } } this._page = 1; this._fetch(); } _renderSortIndicator(column) { if (!column.sortable) { return nothing; } const sortIndex = this._sorts.findIndex(s => s.sortBy === column.id); if (sortIndex === -1) { // Ghost arrow: visible only on hover via CSS return html ` <span class=\"header-cell__sort\" @click=${(e) => this._handleSortClick(e, column)}> <svg class=\"header-cell__sort-arrow header-cell__sort-arrow--ghost\" viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z\"/> </svg> </span> `; } let arrowStyle = {}; if (this._sorts[sortIndex].sortDirection === 'desc') { arrowStyle = { transform: 'rotate(180deg)' }; } return html ` <span class=\"header-cell__sort\" @click=${(e) => this._handleSortClick(e, column)}> <svg class=\"header-cell__sort-arrow\" viewBox=\"0 0 24 24\" fill=\"currentColor\" style=${styleMap(arrowStyle)}> <path d=\"M4 12l1.41 1.41L11 7.83V20h2V7.83l5.58 5.59L20 12l-8-8-8 8z\"/> </svg> ${this._sorts.length > 1 ? html ` <span class=\"header-cell__sort-priority\">${sortIndex + 1}</span> ` : nothing} </span> `; } // ---------------------------------------------------------------------------- // Header // ---------------------------------------------------------------------------- _handleAction(action) { if (action.href) { return; } this.dispatchEvent(new CustomEvent('action', { detail: { action: action.id }, bubbles: true, composed: true })); } // ---------------------------------------------------------------------------- // Filter Handlers // ---------------------------------------------------------------------------- _handleKqlChange(e, column) { const kql = e.target.value.trim(); if (!kql) { column.filter.clear(); this.requestUpdate(); } else { column.filter.setKql(kql); this.requestUpdate(); if (!column.filter.isValid()) { return; } } this._page = 1; this._fetch(); } _handleFilterPanelToggle(e, column) { e.stopPropagation(); if (this._filterPanelOpened === column.id) { this._filterPanelOpened = null; } else { const rect = e.currentTarget.getBoundingClientRect(); let left = rect.left; if (left + 328 > window.innerWidth) { left = window.innerWidth - 328; } this._filterPanelPos = { top: rect.bottom + 4, left }; this._filterPanelOpened = column.id; if (column.facetable) { this._filterPanelTab = 'counts'; } else { this._filterPanelTab = 'filter'; } } } _handleKqlClear(column) { column.filter.clear(); this._page = 1; this._fetch(); } _handleFilterClear() { const column = this._model.columns.find(c => c.id === this._filterPanelOpened); if (column) { column.filter.clear(); if (column.facetable && !column.filterable) { column.filter.operator = 'in'; column.filter.value = []; } } this._filterPanelOpened = null; this._page = 1; this._fetch(); } _handleFilterTextKeydown(e, column) { if (e.key === 'Enter') { e.preventDefault(); this._handleFilterApply(); } } _handleOperatorChange(e, column) { column.filter.setOperator(e.target.value); this.requestUpdate(); } _handleFilterStringChange(e, column) { column.filter.setValue(e.target.value); this.requestUpdate(); } _handleFilterNumberChange(e, column) { column.filter.setValue(Number(e.target.value)); this.requestUpdate(); } _handleFilterDateChange(e, column) { column.filter.setValue(new Date(e.target.value), 'day'); this.requestUpdate(); } _handleFilterBooleanChange(e, column) { column.filter.setValue(e.target.value === 'true'); this.requestUpdate(); } _handleFilterDateStartChange(e, column) { column.filter.setStart(new Date(e.target.value), 'day'); this.requestUpdate(); } _handleFilterDateEndChange(e, column) { column.filter.setEnd(new Date(e.target.value), 'day'); this.requestUpdate(); } _handleFilterNumberStartChange(e, column) { column.filter.setStart(Number(e.target.value)); this.requestUpdate(); } _handleFilterNumberEndChange(e, column) { column.filter.setEnd(Number(e.target.value)); this.requestUpdate(); } _handleFilterListChange(e, column) { const items = e.target.value.split(',').map((v) => v.trim()).filter((v) => v !== ''); if (column.type === 'number') { column.filter.setValue(items.map((v) => Number(v))); } else { column.filter.setValue(items); } this.requestUpdate(); } _handleFilterApply() { this._filterPanelOpened = null; this._page = 1; this._fetch(); } _handleFilterPanelTabChange(e) { this._filterPanelTab = e.detail.activeTabId; } _handleBucketToggle(e, column, bucket) { column.filter.toggle(bucket.val); this._page = 1; this._fetch(); } // ---------------------------------------------------------------------------- // Rendering // ---------------------------------------------------------------------------- _renderCellContent(column, row, rowIndex) { const value = row[column.id]; if (column.render) { // Use slot to project content from light DOM so external styles apply return html `<slot name=\"cell-${rowIndex}-${column.id}\"></slot>`; } if (value === null || value === undefined) { return ''; } switch (column.type) { case 'number': if (column.format === 'currency' && typeof value === 'number') { return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' }); } return String(value); case 'date': { let date; if (value instanceof Date) { date = value; } else if (typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}/.test(value)) { // MySQL datetime format (UTC): \"2026-01-28 01:33:44:517\" // Replace last colon before ms with dot, append Z for UTC const isoString = value.replace(/(\\d{2}:\\d{2}:\\d{2}):(\\d+)$/, '$1.$2').replace(' ', 'T') + 'Z'; date = new Date(isoString); } else { date = new Date(value); } // Show date and time for datetime values in UTC return date.toLocaleString(undefined, { year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit', timeZone: 'UTC' }); } case 'boolean': if (value === true) return 'Yes'; if (value === false) return 'No'; return ''; default: return String(value); } } /** * Returns CSS classes for a header cell based on column config. */ _getHeaderCellClasses(column, index) { return { 'header-cell': true, 'header-cell--sortable': !!column.sortable, 'header-cell--align-center': column.align === 'center', 'header-cell--align-right': column.align === 'right', 'header-cell--sticky-left': column.sticky === 'left', 'header-cell--sticky-left-last': column.sticky === 'left' && !this.getDisplayedColumns().slice(index + 1).some(c => c.sticky === 'left'), 'header-cell--sticky-right': column.sticky === 'right', 'header-cell--sticky-right-first': column.sticky === 'right' && !this.getDisplayedColumns().slice(0, index).some(c => c.sticky === 'right') }; } /** * Returns CSS classes for a table cell based on column config: * - Alignment (center, right) * - Sticky positioning (left, right) * - Border classes for the last left-sticky or first right-sticky column */ _getCellClasses(column, index) { return { 'cell': true, 'cell--actions': column.type === 'actions', 'cell--align-center': column.align === 'center', 'cell--align-right': column.align === 'right', 'cell--sticky-left': column.sticky === 'left', 'cell--sticky-left-last': column.sticky === 'left' && !this.getDisplayedColumns().slice(index + 1).some(c => c.sticky === 'left'), 'cell--sticky-right': column.sticky === 'right', 'cell--sticky-right-first': column.sticky === 'right' && !this.getDisplayedColumns().slice(0, index).some(c => c.sticky === 'right') }; } /** * Returns inline styles for a table cell: * - Width (from column config or default 150px) * - Min-width (if specified) * - Left/right offset for sticky columns (calculated from widths of preceding sticky columns) */ _getCellStyle(column, index) { const styles = {}; if (column.sticky === 'left') { let leftOffset = 0; for (let i = 0; i < index; i++) { const col = this.getDisplayedColumns()[i]; if (col.sticky === 'left') { leftOffset += parseInt(col.width || '0', 10); } } styles.left = `${leftOffset}px`; } if (column.sticky === 'right') { let rightOffset = 0; for (let i = index + 1; i < this.getDisplayedColumns().length; i++) { const col = this.getDisplayedColumns()[i]; if (col.sticky === 'right') { rightOffset += parseInt(col.width || '0', 10); } } styles.right = `${rightOffset}px`; } return styles; } /** * Renders the pagination controls: * - Previous page arrow (disabled on first page) * - Range text showing \"1-50 of 150\" format * - Next page arrow (disabled on last page) * * Hidden when there's no data or all data fits on one page. */ _renderPagination() { const start = (this._page - 1) * this._pageSize + 1; const end = Math.min(this._page * this._pageSize, this._totalItems); return html ` <div class=\"pagination\"> <span class=\"pagination-icon ${this._page === 1 ? 'pagination-icon--disabled' : ''}\" @click=${this.goToPrevPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z\"/></svg> </span> <span class=\"pagination-info\">${start}-${end} of ${this._totalItems}</span> <span class=\"pagination-icon ${this._page === this._totalPages ? 'pagination-icon--disabled' : ''}\" @click=${this.goToNextPage} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z\"/></svg> </span> </div> `; } /** Renders the card title block (title + description) above the toolbar in card mode. */ _renderCardHeader() { if (this.variant !== 'card') return nothing; if (!this._model.title && !this._model.description) return nothing; return html ` <div class=\"card-header\"> ${this._model.title ? html `<h2 class=\"card-header__title\">${this._model.title}</h2>` : nothing} ${this._model.description ? html `<p class=\"card-header__description\">${this._model.description}</p>` : nothing} </div> `; } /** * Renders the header toolbar containing: * - Title (left, default variant only) * - Search bar with view selector dropdown (center, or left-aligned in card variant) * - Tools (right): page navigation, refresh button, column visibility picker, actions dropdown * * Hidden when there's no title, no actions, and data fits on one page. */ _renderHeader() { if (!this._model.title && !this._model.actions?.length && this._totalPages <= 1) { return nothing; } return html ` <div class=\"header\"> ${this._model.title && this.variant !== 'card' ? html `<div class=\"title\">${this._model.title}</div>` : nothing} ${this._model.dataSource?.mode === 'db' && !this._model.columns.some(col => col.searchable) ? html `<div class=\"search\"></div>` : html ` <div class=\"search\"> <!-- TODO: Saved views dropdown <div class=\"views\"> <span>Default View</span> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M7.41 8.59L12 13.17l4.59-4.58L18 10l-6 6-6-6 1.41-1.41z\"/></svg> </div> --> <div class=\"search-field\"> <svg class=\"search-icon\" viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M784-120 532-372q-30 24-69 38t-83 14q-109 0-184.5-75.5T120-580q0-109 75.5-184.5T380-840q109 0 184.5 75.5T640-580q0 44-14 83t-38 69l252 252-56 56ZM380-400q75 0 127.5-52.5T560-580q0-75-52.5-127.5T380-760q-75 0-127.5 52.5T200-580q0 75 52.5 127.5T380-400Z\"/></svg> <input type=\"text\" class=\"search-input\" placeholder=\"Search...\" .value=${this._searchQuery} @input=${this._handleSearch} /> </div> </div> `} <div class=\"tools\"> ${this._renderPagination()} <span class=\"refresh\" title=\"Refresh\" @click=${() => this.refresh()}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M480-160q-134 0-227-93t-93-227q0-134 93-227t227-93q69 0 132 28.5T720-690v-110h80v280H520v-80h168q-32-56-87.5-88T480-720q-100 0-170 70t-70 170q0 100 70 170t170 70q77 0 139-44t87-116h84q-28 106-114 173t-196 67Z\"/></svg> </span> <div class=\"column-picker-wrapper\"> <span class=\"header-icon\" title=\"Columns\" @click=${this._toggleColumnPicker}> <svg viewBox=\"0 -960 960 960\" fill=\"currentColor\"><path d=\"M121-280v-400q0-33 23.5-56.5T201-760h559q33 0 56.5 23.5T840-680v400q0 33-23.5 56.5T760-200H201q-33 0-56.5-23.5T121-280Zm79 0h133v-400H200v400Zm213 0h133v-400H413v400Zm213 0h133v-400H626v400Z\"/></svg> </span> <div class=\"column-picker ${this._columnPickerOpen ? 'open' : ''}\"> ${[...this._model.columns].filter(col => col.type !== 'actions').sort((a, b) => (a.label ?? a.id).localeCompare(b.label ?? b.id)).map(col => html ` <div class=\"column-picker-item\" @click=${() => this._toggleColumn(col.id)}> <div class=\"column-picker-checkbox ${this._model.displayedColumns.includes(col.id) ? 'checked' : ''}\"> <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"><path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/></svg> </div> <span class=\"column-picker-label\">${col.label ?? col.id}</span> </div> `)} </div> </div> ${this._model.actions?.length === 1 ? html ` <kr-button class=\"actions\" .href=${this._model.actions[0].href} .target=${this._model.actions[0].target} @click=${() => this._handleAction(this._model.actions[0])} > ${this._model.actions[0].label} </kr-button> ` : this._model.actions?.length ? html ` <kr-button class=\"actions\" .options=${this._model.actions.map(a => ({ id: a.id, label: a.label }))} @option-select=${(e) => this._handleAction({ id: e.detail.id, label: e.detail.label })} > Actions </kr-button> ` : nothing} </div> </div> `; } /** Renders status message (loading, error, empty) */ _renderStatus() { if (this._dataState === 'loading' && this._data.length === 0) { return html `<div class=\"status\">Loading...</div>`; } if (this._dataState === 'error' && this._data.length === 0) { return html `<div class=\"status status--error\">Error loading data</div>`; } if (this._data.length === 0) { return html `<div class=\"status\">No data available</div>`; } return nothing; } _renderFilterPanel() { if (!this._filterPanelOpened) { return nothing; } const column = this._model.columns.find(c => c.id === this._filterPanelOpened); // Build filter content (operator + value input) let valueInput = html ``; if (column.filter.operator === 'empty' || column.filter.operator === 'n_empty') { valueInput = html ` <input type=\"text\" class=\"filter-panel__input\" disabled .value=${column.filter.text} /> `; } else if (column.filter.operator === 'between' && column.type === 'date') { valueInput = html ` <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${column.filter.value?.start ?? null} @change=${(e) => this._handleFilterDateStartChange(e, column)} /> <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${column.filter.value?.end ?? null} @change=${(e) => this._handleFilterDateEndChange(e, column)} /> `; } else if (column.filter.operator === 'between' && column.type === 'number') { valueInput = html ` <input type=\"number\" class=\"filter-panel__input\" placeholder=\"Start\" .value=${column.filter.value?.start ?? ''} @input=${(e) => this._handleFilterNumberStartChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} /> <input type=\"number\" class=\"filter-panel__input\" placeholder=\"End\" .value=${column.filter.value?.end ?? ''} @input=${(e) => this._handleFilterNumberEndChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} /> `; } else if (column.filter.operator === 'in' || column.filter.operator === 'n_in') { valueInput = html ` <textarea class=\"filter-panel__textarea\" rows=\"3\" placeholder=\"Values (comma-separated)\" .value=${column.filter.text} @input=${(e) => this._handleFilterListChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} ></textarea> `; } else if (column.type === 'boolean') { valueInput = html ` <kr-select-field placeholder=\"Value\" .value=${String(column.filter.value ?? '')} @change=${(e) => this._handleFilterBooleanChange(e, column)} > <kr-select-option value=\"true\">Yes</kr-select-option> <kr-select-option value=\"false\">No</kr-select-option> </kr-select-field> `; } else if (column.type === 'date') { valueInput = html ` <input type=\"date\" class=\"filter-panel__input\" .valueAsDate=${column.filter.value} @change=${(e) => this._handleFilterDateChange(e, column)} /> `; } else if (column.type === 'number') { valueInput = html ` <input type=\"number\" class=\"filter-panel__input\" placeholder=\"Value\" min=\"0\" .value=${column.filter.text} @input=${(e) => this._handleFilterNumberChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} /> `; } else { valueInput = html ` <input type=\"text\" class=\"filter-panel__input\" placeholder=\"Value\" .value=${column.filter.text} @input=${(e) => this._handleFilterStringChange(e, column)} @keydown=${(e) => this._handleFilterTextKeydown(e, column)} /> `; } const filterContent = html ` <div class=\"filter-panel__content\"> <kr-select-field .value=${column.filter.operator} @change=${(e) => this._handleOperatorChange(e, column)} > ${getOperatorsForType(column.type).map(op => html ` <kr-select-option value=${op.key}>${op.label}</kr-select-option> `)} </kr-select-field> ${valueInput} </div> `; // Build bucket list content const buckets = this._buckets.get(column.id) || []; let bucketContent; if (!buckets.length) { bucketContent = html `<div class=\"bucket-empty\">No data</div>`; } else { bucketContent = html ` <div class=\"buckets\"> ${buckets.map(bucket => { let bucketLabel = '(Empty)'; if (bucket.val !== null && bucket.val !== undefined) { if (column.type === 'boolean') { if (bucket.val === true || bucket.val === 'true') { bucketLabel = 'Yes'; } else { bucketLabel = 'No'; } } else { bucketLabel = String(bucket.val); } } // When using n_in, the user sees all buckets checked by default and unchecks // the ones they want to hide. Under the hood, has() returns true for values // in the exclusion list, so we invert the check state for n_in. let checked = column.filter.has(bucket.val); if (column.filter.operator === 'n_in') { checked = !checked; } let checkIcon = nothing; if (checked) { checkIcon = html ` <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M9 16.17L4.83 12l-1.42 1.41L9 19 21 7l-1.41-1.41z\"/> </svg> `; } return html ` <div class=\"bucket\" @click=${(e) => this._handleBucketToggle(e, column, bucket)} > <div class=${classMap({ 'bucket__checkbox': true, 'bucket__checkbox--checked': checked })}> ${checkIcon} </div> <span class=\"bucket__label\">${bucketLabel}</span> <span class=\"bucket__count\">${bucket.count}</span> </div> `; })} </div> `; } // Build panel body — tabs if both filterable+facetable, otherwise just the relevant content let panelBody; if (column.facetable && column.filterable) { panelBody = html ` <kr-tab-group size=\"small\" active-tab-id=${this._filterPanelTab} @tab-change=${(e) => this._handleFilterPanelTabChange(e)} > <kr-tab id=\"filter\" label=\"Filter\"> ${filterContent} </kr-tab> <kr-tab id=\"counts\" label=\"Counts\"> ${bucketContent} </kr-tab> </kr-tab-group> `; } else if (column.facetable) { panelBody = bucketContent; } else { panelBody = filterContent; } return html ` <div class=\"filter-panel\" style=${styleMap({ top: this._filterPanelPos.top + 'px', left: this._filterPanelPos.left + 'px' })} > ${panelBody} <div class=\"filter-panel__actions\"> <kr-button variant=\"outline\" color=\"secondary\" size=\"small\" @click=${this._handleFilterClear}> Clear </kr-button> <kr-button size=\"small\" @click=${this._handleFilterApply}> Apply </kr-button> </div> </div> `; } /** * Renders filter row below column headers. * Only displays for columns with filterable: true. */ _renderFilterRow() { const columns = this.getDisplayedColumns(); if (!columns.some(col => col.filterable || col.facetable)) { return nothing; } return html ` <div class=\"filter-row\"> ${columns.map((col, i) => { if (!col.filterable && !col.facetable) { return html `<div class=${classMap({ 'filter-cell': true, 'filter-cell--sticky-left': col.sticky === 'left', 'filter-cell--sticky-right': col.sticky === 'right', 'filter-cell--sticky-right-first': col.sticky === 'right' && !columns.slice(0, i).some((c) => c.sticky === 'right') })} style=${styleMap(this._getCellStyle(col, i))} ></div>`; } return html ` <div class=${classMap({ 'filter-cell': true, 'filter-cell--sticky-left': col.sticky === 'left', 'filter-cell--sticky-right': col.sticky === 'right', 'filter-cell--sticky-right-first': col.sticky === 'right' && !columns.slice(0, i).some((c) => c.sticky === 'right') })} style=${styleMap(this._getCellStyle(col, i))} > <div class=\"filter-cell__wrapper\"> <input type=\"text\" class=${classMap({ 'filter-cell__input': true, 'filter-cell__input--invalid': !col.filter.isValid() })} .value=${col.filter.kql} @change=${(e) => this._handleKqlChange(e, col)} /> ${col.filter?.kql?.length > 0 ? html ` <button class=\"filter-cell__clear\" @click=${() => this._handleKqlClear(col)} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z\"/> </svg> </button> ` : nothing} <button class=${classMap({ 'filter-cell__advanced': true, 'filter-cell__advanced--opened': this._filterPanelOpened === col.id })} @click=${(e) => this._handleFilterPanelToggle(e, col)} > <svg viewBox=\"0 0 24 24\" fill=\"currentColor\"> <path d=\"M10 18h4v-2h-4v2zM3 6v2h18V6H3zm3 7h12v-2H6v2z\"/> </svg> </button> </div> </div> `; })} </div> `; } /** Renders the scrollable data grid with column headers and rows. */ _renderTable() { return html ` <div class=\"wrapper\"> <div class=\"overlay-left\"></div> <div class=\"overlay-right\"></div> ${this._renderStatus()} <div class=\"content\" @scroll=${this._handleScroll}> <div class=\"table\" style=\"grid-template-columns: ${this._getGridTemplateColumns()}\"> <div class=\"header-row\"> ${this.getDisplayedColumns().map((col, i) => html ` <div class=${classMap(this._getHeaderCellClasses(col, i))} style=${styleMap(this._getCellStyle(col, i))} data-column-id=${col.id} > <span class=\"header-cell__label\">${col.label ?? col.id}</span> ${this._renderSortIndicator(col)} ${col.resizable !== false ? html `<div class=\"header-cell__resize\" @mousedown=${(e) => this._handleResizeStart(e, col.id)} ></div>` : nothing} </div> `)} </div> ${this._renderFilterRow()} ${this._data.map((row, rowIndex) => { const cells = this.getDisplayedColumns().map((col, i) => html ` <div class=${classMap(this._getCellClasses(col, i))} style=${styleMap(this._getCellStyle(col, i))} data-column-id=${col.id} > ${this._renderCellContent(col, row, rowIndex)} </div> `); if (this._model.rowHref) { return html ` <a href=${this._model.rowHref(row)} draggable=\"false\" class=${classMap({ 'row': true, 'row--clickable': true, 'row--link': true })} @mousedown=${() => this._handleRowMouseDown()} @click=${(e) => this._handleRowClick(e, row, rowIndex)} >${cells}</a> `; } return html ` <div class=${classMap({ 'row': true, 'row--clickable': !!this._model.rowClickable })} @mousedown=${() => this._handleRowMouseDown()} @click=${(e) => this._handleRowClick(e, row, rowIndex)} >${cells}</div> `; })} </div> </div> </div> `; } /** * Renders a data table with: * - Header bar with title, search input with view selector, and tools (pagination, refresh, column visibility, actions dropdown) * - Scrollable grid with sticky header row and optional sticky left/right columns * - Loading, error message, or empty state when no data */ render() { if (!this._model.columns.length) { return html `<slot></slot>`; } return html ` ${this._renderCardHeader()} ${this._renderHeader()} ${this._renderTable()} ${this._renderFilterPanel()} `; } }"
|
|
2439
|
+
}
|
|
2440
|
+
],
|
|
2441
|
+
"exports": [
|
|
2442
|
+
{
|
|
2443
|
+
"kind": "js",
|
|
2444
|
+
"name": "KRGrid",
|
|
2445
|
+
"declaration": {
|
|
2446
|
+
"name": "KRGrid",
|
|
2447
|
+
"module": "dist/grid/grid.js"
|
|
2448
|
+
}
|
|
2449
|
+
}
|
|
2450
|
+
]
|
|
2451
|
+
},
|
|
2389
2452
|
{
|
|
2390
2453
|
"kind": "javascript-module",
|
|
2391
2454
|
"path": "dist/monaco/monaco.js",
|
|
@@ -5070,6 +5133,1005 @@
|
|
|
5070
5133
|
}
|
|
5071
5134
|
]
|
|
5072
5135
|
},
|
|
5136
|
+
{
|
|
5137
|
+
"kind": "javascript-module",
|
|
5138
|
+
"path": "src/grid/grid.ts",
|
|
5139
|
+
"declarations": [
|
|
5140
|
+
{
|
|
5141
|
+
"kind": "class",
|
|
5142
|
+
"description": "",
|
|
5143
|
+
"name": "KRGrid",
|
|
5144
|
+
"members": [
|
|
5145
|
+
{
|
|
5146
|
+
"kind": "field",
|
|
5147
|
+
"name": "_scrollStyle",
|
|
5148
|
+
"type": {
|
|
5149
|
+
"text": "'overlay' | 'edge'"
|
|
5150
|
+
},
|
|
5151
|
+
"privacy": "private",
|
|
5152
|
+
"default": "'edge'",
|
|
5153
|
+
"description": "Internal flag to switch between scroll edge modes:\n- 'overlay': Fixed padding with overlay elements that hide content at edges (scrollbar at viewport edge)\n- 'edge': Padding scrolls with content, allowing table to reach edges when scrolling"
|
|
5154
|
+
},
|
|
5155
|
+
{
|
|
5156
|
+
"kind": "field",
|
|
5157
|
+
"name": "_refreshTimer",
|
|
5158
|
+
"type": {
|
|
5159
|
+
"text": "number | undefined"
|
|
5160
|
+
},
|
|
5161
|
+
"privacy": "private"
|
|
5162
|
+
},
|
|
5163
|
+
{
|
|
5164
|
+
"kind": "field",
|
|
5165
|
+
"name": "_data",
|
|
5166
|
+
"type": {
|
|
5167
|
+
"text": "Record<string, any>[]"
|
|
5168
|
+
},
|
|
5169
|
+
"privacy": "private",
|
|
5170
|
+
"default": "[]"
|
|
5171
|
+
},
|
|
5172
|
+
{
|
|
5173
|
+
"kind": "field",
|
|
5174
|
+
"name": "_dataState",
|
|
5175
|
+
"type": {
|
|
5176
|
+
"text": "'idle' | 'loading' | 'success' | 'error'"
|
|
5177
|
+
},
|
|
5178
|
+
"privacy": "private",
|
|
5179
|
+
"default": "'idle'"
|
|
5180
|
+
},
|
|
5181
|
+
{
|
|
5182
|
+
"kind": "field",
|
|
5183
|
+
"name": "_page",
|
|
5184
|
+
"type": {
|
|
5185
|
+
"text": "number"
|
|
5186
|
+
},
|
|
5187
|
+
"privacy": "private",
|
|
5188
|
+
"default": "1"
|
|
5189
|
+
},
|
|
5190
|
+
{
|
|
5191
|
+
"kind": "field",
|
|
5192
|
+
"name": "_pageSize",
|
|
5193
|
+
"type": {
|
|
5194
|
+
"text": "number"
|
|
5195
|
+
},
|
|
5196
|
+
"privacy": "private",
|
|
5197
|
+
"default": "50"
|
|
5198
|
+
},
|
|
5199
|
+
{
|
|
5200
|
+
"kind": "field",
|
|
5201
|
+
"name": "_totalItems",
|
|
5202
|
+
"type": {
|
|
5203
|
+
"text": "number"
|
|
5204
|
+
},
|
|
5205
|
+
"privacy": "private",
|
|
5206
|
+
"default": "0"
|
|
5207
|
+
},
|
|
5208
|
+
{
|
|
5209
|
+
"kind": "field",
|
|
5210
|
+
"name": "_totalPages",
|
|
5211
|
+
"type": {
|
|
5212
|
+
"text": "number"
|
|
5213
|
+
},
|
|
5214
|
+
"privacy": "private",
|
|
5215
|
+
"default": "0"
|
|
5216
|
+
},
|
|
5217
|
+
{
|
|
5218
|
+
"kind": "field",
|
|
5219
|
+
"name": "_searchQuery",
|
|
5220
|
+
"type": {
|
|
5221
|
+
"text": "string"
|
|
5222
|
+
},
|
|
5223
|
+
"privacy": "private",
|
|
5224
|
+
"default": "''"
|
|
5225
|
+
},
|
|
5226
|
+
{
|
|
5227
|
+
"kind": "field",
|
|
5228
|
+
"name": "_canScrollLeft",
|
|
5229
|
+
"type": {
|
|
5230
|
+
"text": "boolean"
|
|
5231
|
+
},
|
|
5232
|
+
"privacy": "private",
|
|
5233
|
+
"default": "false"
|
|
5234
|
+
},
|
|
5235
|
+
{
|
|
5236
|
+
"kind": "field",
|
|
5237
|
+
"name": "_canScrollRight",
|
|
5238
|
+
"type": {
|
|
5239
|
+
"text": "boolean"
|
|
5240
|
+
},
|
|
5241
|
+
"privacy": "private",
|
|
5242
|
+
"default": "false"
|
|
5243
|
+
},
|
|
5244
|
+
{
|
|
5245
|
+
"kind": "field",
|
|
5246
|
+
"name": "_canScrollHorizontal",
|
|
5247
|
+
"type": {
|
|
5248
|
+
"text": "boolean"
|
|
5249
|
+
},
|
|
5250
|
+
"privacy": "private",
|
|
5251
|
+
"default": "false"
|
|
5252
|
+
},
|
|
5253
|
+
{
|
|
5254
|
+
"kind": "field",
|
|
5255
|
+
"name": "_columnPickerOpen",
|
|
5256
|
+
"type": {
|
|
5257
|
+
"text": "boolean"
|
|
5258
|
+
},
|
|
5259
|
+
"privacy": "private",
|
|
5260
|
+
"default": "false"
|
|
5261
|
+
},
|
|
5262
|
+
{
|
|
5263
|
+
"kind": "field",
|
|
5264
|
+
"name": "_filterPanelOpened",
|
|
5265
|
+
"type": {
|
|
5266
|
+
"text": "string | null"
|
|
5267
|
+
},
|
|
5268
|
+
"privacy": "private",
|
|
5269
|
+
"default": "null"
|
|
5270
|
+
},
|
|
5271
|
+
{
|
|
5272
|
+
"kind": "field",
|
|
5273
|
+
"name": "_filterPanelTab",
|
|
5274
|
+
"type": {
|
|
5275
|
+
"text": "'filter' | 'counts'"
|
|
5276
|
+
},
|
|
5277
|
+
"privacy": "private",
|
|
5278
|
+
"default": "'filter'"
|
|
5279
|
+
},
|
|
5280
|
+
{
|
|
5281
|
+
"kind": "field",
|
|
5282
|
+
"name": "_buckets",
|
|
5283
|
+
"type": {
|
|
5284
|
+
"text": "Map<string, KRBucket[]>"
|
|
5285
|
+
},
|
|
5286
|
+
"privacy": "private",
|
|
5287
|
+
"default": "new Map()"
|
|
5288
|
+
},
|
|
5289
|
+
{
|
|
5290
|
+
"kind": "field",
|
|
5291
|
+
"name": "_filterPanelPos",
|
|
5292
|
+
"type": {
|
|
5293
|
+
"text": "object"
|
|
5294
|
+
},
|
|
5295
|
+
"privacy": "private",
|
|
5296
|
+
"default": "{ top: 0, left: 0 }"
|
|
5297
|
+
},
|
|
5298
|
+
{
|
|
5299
|
+
"kind": "field",
|
|
5300
|
+
"name": "_sorts",
|
|
5301
|
+
"type": {
|
|
5302
|
+
"text": "KRSolrSort[]"
|
|
5303
|
+
},
|
|
5304
|
+
"privacy": "private",
|
|
5305
|
+
"default": "[]"
|
|
5306
|
+
},
|
|
5307
|
+
{
|
|
5308
|
+
"kind": "field",
|
|
5309
|
+
"name": "_resizing",
|
|
5310
|
+
"type": {
|
|
5311
|
+
"text": "{ columnId: string; startX: number; startWidth: number } | null"
|
|
5312
|
+
},
|
|
5313
|
+
"privacy": "private",
|
|
5314
|
+
"default": "null"
|
|
5315
|
+
},
|
|
5316
|
+
{
|
|
5317
|
+
"kind": "field",
|
|
5318
|
+
"name": "_resizeObserver",
|
|
5319
|
+
"type": {
|
|
5320
|
+
"text": "ResizeObserver | null"
|
|
5321
|
+
},
|
|
5322
|
+
"privacy": "private",
|
|
5323
|
+
"default": "null"
|
|
5324
|
+
},
|
|
5325
|
+
{
|
|
5326
|
+
"kind": "field",
|
|
5327
|
+
"name": "_searchPositionLocked",
|
|
5328
|
+
"type": {
|
|
5329
|
+
"text": "boolean"
|
|
5330
|
+
},
|
|
5331
|
+
"privacy": "private",
|
|
5332
|
+
"default": "false"
|
|
5333
|
+
},
|
|
5334
|
+
{
|
|
5335
|
+
"kind": "field",
|
|
5336
|
+
"name": "_columnWidthsLocked",
|
|
5337
|
+
"type": {
|
|
5338
|
+
"text": "boolean"
|
|
5339
|
+
},
|
|
5340
|
+
"privacy": "private",
|
|
5341
|
+
"default": "false"
|
|
5342
|
+
},
|
|
5343
|
+
{
|
|
5344
|
+
"kind": "field",
|
|
5345
|
+
"name": "_model",
|
|
5346
|
+
"privacy": "private",
|
|
5347
|
+
"default": "new KRGridModel()"
|
|
5348
|
+
},
|
|
5349
|
+
{
|
|
5350
|
+
"kind": "field",
|
|
5351
|
+
"name": "def",
|
|
5352
|
+
"type": {
|
|
5353
|
+
"text": "KRTableDef"
|
|
5354
|
+
},
|
|
5355
|
+
"default": "{ columns: [] }",
|
|
5356
|
+
"attribute": "def"
|
|
5357
|
+
},
|
|
5358
|
+
{
|
|
5359
|
+
"kind": "field",
|
|
5360
|
+
"name": "variant",
|
|
5361
|
+
"type": {
|
|
5362
|
+
"text": "'default' | 'card'"
|
|
5363
|
+
},
|
|
5364
|
+
"default": "'default'",
|
|
5365
|
+
"description": "Table layout variant.\n- 'default': Full-page table that fills parent height with centered search.\n- 'card': Embedded table that sizes itself to content, left-aligns search, and\n reserves space for pageSize rows to prevent layout shift.",
|
|
5366
|
+
"attribute": "variant",
|
|
5367
|
+
"reflects": true
|
|
5368
|
+
},
|
|
5369
|
+
{
|
|
5370
|
+
"kind": "method",
|
|
5371
|
+
"name": "_lockColumnWidths",
|
|
5372
|
+
"privacy": "private",
|
|
5373
|
+
"description": "Measures header cell widths and locks them to prevent column shift on subsequent data changes."
|
|
5374
|
+
},
|
|
5375
|
+
{
|
|
5376
|
+
"kind": "method",
|
|
5377
|
+
"name": "_syncSlottedContent",
|
|
5378
|
+
"privacy": "private",
|
|
5379
|
+
"description": "Syncs light DOM content for cells with custom render functions"
|
|
5380
|
+
},
|
|
5381
|
+
{
|
|
5382
|
+
"kind": "method",
|
|
5383
|
+
"name": "refresh"
|
|
5384
|
+
},
|
|
5385
|
+
{
|
|
5386
|
+
"kind": "method",
|
|
5387
|
+
"name": "goToPrevPage"
|
|
5388
|
+
},
|
|
5389
|
+
{
|
|
5390
|
+
"kind": "method",
|
|
5391
|
+
"name": "goToNextPage"
|
|
5392
|
+
},
|
|
5393
|
+
{
|
|
5394
|
+
"kind": "method",
|
|
5395
|
+
"name": "goToPage",
|
|
5396
|
+
"parameters": [
|
|
5397
|
+
{
|
|
5398
|
+
"name": "page",
|
|
5399
|
+
"type": {
|
|
5400
|
+
"text": "number"
|
|
5401
|
+
}
|
|
5402
|
+
}
|
|
5403
|
+
]
|
|
5404
|
+
},
|
|
5405
|
+
{
|
|
5406
|
+
"kind": "method",
|
|
5407
|
+
"name": "_toSolrData",
|
|
5408
|
+
"privacy": "private"
|
|
5409
|
+
},
|
|
5410
|
+
{
|
|
5411
|
+
"kind": "method",
|
|
5412
|
+
"name": "_toDbParams",
|
|
5413
|
+
"privacy": "private"
|
|
5414
|
+
},
|
|
5415
|
+
{
|
|
5416
|
+
"kind": "method",
|
|
5417
|
+
"name": "_fetch",
|
|
5418
|
+
"privacy": "private",
|
|
5419
|
+
"description": "Fetches data from the API and updates the table.\nShows a loading spinner while fetching, then displays rows on success\nor an error snackbar on failure.\nRequest/response format depends on dataSource.mode (solr, opensearch, db)."
|
|
5420
|
+
},
|
|
5421
|
+
{
|
|
5422
|
+
"kind": "method",
|
|
5423
|
+
"name": "_parseFacetResults",
|
|
5424
|
+
"privacy": "private",
|
|
5425
|
+
"parameters": [
|
|
5426
|
+
{
|
|
5427
|
+
"name": "response",
|
|
5428
|
+
"type": {
|
|
5429
|
+
"text": "KRSolrResponse"
|
|
5430
|
+
}
|
|
5431
|
+
}
|
|
5432
|
+
]
|
|
5433
|
+
},
|
|
5434
|
+
{
|
|
5435
|
+
"kind": "method",
|
|
5436
|
+
"name": "_initRefresh",
|
|
5437
|
+
"privacy": "private",
|
|
5438
|
+
"description": "Sets up auto-refresh so the table automatically fetches fresh data\nat a regular interval (useful for dashboards, monitoring views).\nConfigured via def.refreshInterval in milliseconds."
|
|
5439
|
+
},
|
|
5440
|
+
{
|
|
5441
|
+
"kind": "method",
|
|
5442
|
+
"name": "_handleSearch",
|
|
5443
|
+
"privacy": "private",
|
|
5444
|
+
"parameters": [
|
|
5445
|
+
{
|
|
5446
|
+
"name": "e",
|
|
5447
|
+
"type": {
|
|
5448
|
+
"text": "Event"
|
|
5449
|
+
}
|
|
5450
|
+
}
|
|
5451
|
+
]
|
|
5452
|
+
},
|
|
5453
|
+
{
|
|
5454
|
+
"kind": "method",
|
|
5455
|
+
"name": "_getGridTemplateColumns",
|
|
5456
|
+
"privacy": "private",
|
|
5457
|
+
"return": {
|
|
5458
|
+
"type": {
|
|
5459
|
+
"text": "string"
|
|
5460
|
+
}
|
|
5461
|
+
}
|
|
5462
|
+
},
|
|
5463
|
+
{
|
|
5464
|
+
"kind": "method",
|
|
5465
|
+
"name": "_updateSearchPosition",
|
|
5466
|
+
"privacy": "private",
|
|
5467
|
+
"description": "Updates search position to be centered with equal gaps from title and tools.\nOn first call: resets to flex centering, measures position, then locks with fixed margin.\nSubsequent calls are ignored unless _searchPositionLocked is reset (e.g., on resize)."
|
|
5468
|
+
},
|
|
5469
|
+
{
|
|
5470
|
+
"kind": "method",
|
|
5471
|
+
"name": "_toggleColumnPicker",
|
|
5472
|
+
"privacy": "private"
|
|
5473
|
+
},
|
|
5474
|
+
{
|
|
5475
|
+
"kind": "method",
|
|
5476
|
+
"name": "_toggleColumn",
|
|
5477
|
+
"privacy": "private",
|
|
5478
|
+
"parameters": [
|
|
5479
|
+
{
|
|
5480
|
+
"name": "columnId",
|
|
5481
|
+
"type": {
|
|
5482
|
+
"text": "string"
|
|
5483
|
+
}
|
|
5484
|
+
}
|
|
5485
|
+
]
|
|
5486
|
+
},
|
|
5487
|
+
{
|
|
5488
|
+
"kind": "method",
|
|
5489
|
+
"name": "_handleRowMouseDown",
|
|
5490
|
+
"privacy": "private"
|
|
5491
|
+
},
|
|
5492
|
+
{
|
|
5493
|
+
"kind": "method",
|
|
5494
|
+
"name": "_handleRowClick",
|
|
5495
|
+
"privacy": "private",
|
|
5496
|
+
"parameters": [
|
|
5497
|
+
{
|
|
5498
|
+
"name": "e",
|
|
5499
|
+
"type": {
|
|
5500
|
+
"text": "MouseEvent"
|
|
5501
|
+
}
|
|
5502
|
+
},
|
|
5503
|
+
{
|
|
5504
|
+
"name": "row",
|
|
5505
|
+
"type": {
|
|
5506
|
+
"text": "Record<string, any>"
|
|
5507
|
+
}
|
|
5508
|
+
},
|
|
5509
|
+
{
|
|
5510
|
+
"name": "rowIndex",
|
|
5511
|
+
"type": {
|
|
5512
|
+
"text": "number"
|
|
5513
|
+
}
|
|
5514
|
+
}
|
|
5515
|
+
]
|
|
5516
|
+
},
|
|
5517
|
+
{
|
|
5518
|
+
"kind": "field",
|
|
5519
|
+
"name": "_handleClickOutside",
|
|
5520
|
+
"privacy": "private"
|
|
5521
|
+
},
|
|
5522
|
+
{
|
|
5523
|
+
"kind": "method",
|
|
5524
|
+
"name": "getDisplayedColumns",
|
|
5525
|
+
"return": {
|
|
5526
|
+
"type": {
|
|
5527
|
+
"text": "KRTableColumn[]"
|
|
5528
|
+
}
|
|
5529
|
+
}
|
|
5530
|
+
},
|
|
5531
|
+
{
|
|
5532
|
+
"kind": "method",
|
|
5533
|
+
"name": "_handleScroll",
|
|
5534
|
+
"privacy": "private",
|
|
5535
|
+
"parameters": [
|
|
5536
|
+
{
|
|
5537
|
+
"name": "e",
|
|
5538
|
+
"type": {
|
|
5539
|
+
"text": "Event"
|
|
5540
|
+
}
|
|
5541
|
+
}
|
|
5542
|
+
],
|
|
5543
|
+
"description": "Scroll event handler that updates scroll flags in real-time as user scrolls.\nUpdates shadow indicators to show if more content exists left/right."
|
|
5544
|
+
},
|
|
5545
|
+
{
|
|
5546
|
+
"kind": "method",
|
|
5547
|
+
"name": "_updateScrollFlags",
|
|
5548
|
+
"privacy": "private",
|
|
5549
|
+
"description": "Updates scroll state flags for the table content container.\n- _canScrollLeft: true if scrolled right (can scroll back left)\n- _canScrollRight: true if more content exists to the right\n- _canScrollHorizontal: true if content is wider than container\nThese flags control scroll shadow indicators and CSS classes."
|
|
5550
|
+
},
|
|
5551
|
+
{
|
|
5552
|
+
"kind": "method",
|
|
5553
|
+
"name": "_handleResizeStart",
|
|
5554
|
+
"privacy": "private",
|
|
5555
|
+
"parameters": [
|
|
5556
|
+
{
|
|
5557
|
+
"name": "e",
|
|
5558
|
+
"type": {
|
|
5559
|
+
"text": "MouseEvent"
|
|
5560
|
+
}
|
|
5561
|
+
},
|
|
5562
|
+
{
|
|
5563
|
+
"name": "columnId",
|
|
5564
|
+
"type": {
|
|
5565
|
+
"text": "string"
|
|
5566
|
+
}
|
|
5567
|
+
}
|
|
5568
|
+
]
|
|
5569
|
+
},
|
|
5570
|
+
{
|
|
5571
|
+
"kind": "field",
|
|
5572
|
+
"name": "_handleResizeMove",
|
|
5573
|
+
"privacy": "private"
|
|
5574
|
+
},
|
|
5575
|
+
{
|
|
5576
|
+
"kind": "field",
|
|
5577
|
+
"name": "_handleResizeEnd",
|
|
5578
|
+
"privacy": "private"
|
|
5579
|
+
},
|
|
5580
|
+
{
|
|
5581
|
+
"kind": "method",
|
|
5582
|
+
"name": "_handleSortClick",
|
|
5583
|
+
"privacy": "private",
|
|
5584
|
+
"parameters": [
|
|
5585
|
+
{
|
|
5586
|
+
"name": "e",
|
|
5587
|
+
"type": {
|
|
5588
|
+
"text": "MouseEvent"
|
|
5589
|
+
}
|
|
5590
|
+
},
|
|
5591
|
+
{
|
|
5592
|
+
"name": "column",
|
|
5593
|
+
"type": {
|
|
5594
|
+
"text": "KRTableColumn"
|
|
5595
|
+
}
|
|
5596
|
+
}
|
|
5597
|
+
]
|
|
5598
|
+
},
|
|
5599
|
+
{
|
|
5600
|
+
"kind": "method",
|
|
5601
|
+
"name": "_renderSortIndicator",
|
|
5602
|
+
"privacy": "private",
|
|
5603
|
+
"parameters": [
|
|
5604
|
+
{
|
|
5605
|
+
"name": "column",
|
|
5606
|
+
"type": {
|
|
5607
|
+
"text": "KRTableColumn"
|
|
5608
|
+
}
|
|
5609
|
+
}
|
|
5610
|
+
]
|
|
5611
|
+
},
|
|
5612
|
+
{
|
|
5613
|
+
"kind": "method",
|
|
5614
|
+
"name": "_handleAction",
|
|
5615
|
+
"privacy": "private",
|
|
5616
|
+
"parameters": [
|
|
5617
|
+
{
|
|
5618
|
+
"name": "action",
|
|
5619
|
+
"type": {
|
|
5620
|
+
"text": "KRTableAction"
|
|
5621
|
+
}
|
|
5622
|
+
}
|
|
5623
|
+
]
|
|
5624
|
+
},
|
|
5625
|
+
{
|
|
5626
|
+
"kind": "method",
|
|
5627
|
+
"name": "_handleKqlChange",
|
|
5628
|
+
"privacy": "private",
|
|
5629
|
+
"parameters": [
|
|
5630
|
+
{
|
|
5631
|
+
"name": "e",
|
|
5632
|
+
"type": {
|
|
5633
|
+
"text": "Event"
|
|
5634
|
+
}
|
|
5635
|
+
},
|
|
5636
|
+
{
|
|
5637
|
+
"name": "column",
|
|
5638
|
+
"type": {
|
|
5639
|
+
"text": "KRTableColumn"
|
|
5640
|
+
}
|
|
5641
|
+
}
|
|
5642
|
+
]
|
|
5643
|
+
},
|
|
5644
|
+
{
|
|
5645
|
+
"kind": "method",
|
|
5646
|
+
"name": "_handleFilterPanelToggle",
|
|
5647
|
+
"privacy": "private",
|
|
5648
|
+
"parameters": [
|
|
5649
|
+
{
|
|
5650
|
+
"name": "e",
|
|
5651
|
+
"type": {
|
|
5652
|
+
"text": "Event"
|
|
5653
|
+
}
|
|
5654
|
+
},
|
|
5655
|
+
{
|
|
5656
|
+
"name": "column",
|
|
5657
|
+
"type": {
|
|
5658
|
+
"text": "KRTableColumn"
|
|
5659
|
+
}
|
|
5660
|
+
}
|
|
5661
|
+
]
|
|
5662
|
+
},
|
|
5663
|
+
{
|
|
5664
|
+
"kind": "method",
|
|
5665
|
+
"name": "_handleKqlClear",
|
|
5666
|
+
"privacy": "private",
|
|
5667
|
+
"parameters": [
|
|
5668
|
+
{
|
|
5669
|
+
"name": "column",
|
|
5670
|
+
"type": {
|
|
5671
|
+
"text": "KRTableColumn"
|
|
5672
|
+
}
|
|
5673
|
+
}
|
|
5674
|
+
]
|
|
5675
|
+
},
|
|
5676
|
+
{
|
|
5677
|
+
"kind": "method",
|
|
5678
|
+
"name": "_handleFilterClear",
|
|
5679
|
+
"privacy": "private"
|
|
5680
|
+
},
|
|
5681
|
+
{
|
|
5682
|
+
"kind": "method",
|
|
5683
|
+
"name": "_handleFilterTextKeydown",
|
|
5684
|
+
"privacy": "private",
|
|
5685
|
+
"parameters": [
|
|
5686
|
+
{
|
|
5687
|
+
"name": "e",
|
|
5688
|
+
"type": {
|
|
5689
|
+
"text": "KeyboardEvent"
|
|
5690
|
+
}
|
|
5691
|
+
},
|
|
5692
|
+
{
|
|
5693
|
+
"name": "column",
|
|
5694
|
+
"type": {
|
|
5695
|
+
"text": "KRTableColumn"
|
|
5696
|
+
}
|
|
5697
|
+
}
|
|
5698
|
+
]
|
|
5699
|
+
},
|
|
5700
|
+
{
|
|
5701
|
+
"kind": "method",
|
|
5702
|
+
"name": "_handleOperatorChange",
|
|
5703
|
+
"privacy": "private",
|
|
5704
|
+
"parameters": [
|
|
5705
|
+
{
|
|
5706
|
+
"name": "e",
|
|
5707
|
+
"type": {
|
|
5708
|
+
"text": "Event"
|
|
5709
|
+
}
|
|
5710
|
+
},
|
|
5711
|
+
{
|
|
5712
|
+
"name": "column",
|
|
5713
|
+
"type": {
|
|
5714
|
+
"text": "KRTableColumn"
|
|
5715
|
+
}
|
|
5716
|
+
}
|
|
5717
|
+
]
|
|
5718
|
+
},
|
|
5719
|
+
{
|
|
5720
|
+
"kind": "method",
|
|
5721
|
+
"name": "_handleFilterStringChange",
|
|
5722
|
+
"privacy": "private",
|
|
5723
|
+
"parameters": [
|
|
5724
|
+
{
|
|
5725
|
+
"name": "e",
|
|
5726
|
+
"type": {
|
|
5727
|
+
"text": "Event"
|
|
5728
|
+
}
|
|
5729
|
+
},
|
|
5730
|
+
{
|
|
5731
|
+
"name": "column",
|
|
5732
|
+
"type": {
|
|
5733
|
+
"text": "KRTableColumn"
|
|
5734
|
+
}
|
|
5735
|
+
}
|
|
5736
|
+
]
|
|
5737
|
+
},
|
|
5738
|
+
{
|
|
5739
|
+
"kind": "method",
|
|
5740
|
+
"name": "_handleFilterNumberChange",
|
|
5741
|
+
"privacy": "private",
|
|
5742
|
+
"parameters": [
|
|
5743
|
+
{
|
|
5744
|
+
"name": "e",
|
|
5745
|
+
"type": {
|
|
5746
|
+
"text": "Event"
|
|
5747
|
+
}
|
|
5748
|
+
},
|
|
5749
|
+
{
|
|
5750
|
+
"name": "column",
|
|
5751
|
+
"type": {
|
|
5752
|
+
"text": "KRTableColumn"
|
|
5753
|
+
}
|
|
5754
|
+
}
|
|
5755
|
+
]
|
|
5756
|
+
},
|
|
5757
|
+
{
|
|
5758
|
+
"kind": "method",
|
|
5759
|
+
"name": "_handleFilterDateChange",
|
|
5760
|
+
"privacy": "private",
|
|
5761
|
+
"parameters": [
|
|
5762
|
+
{
|
|
5763
|
+
"name": "e",
|
|
5764
|
+
"type": {
|
|
5765
|
+
"text": "Event"
|
|
5766
|
+
}
|
|
5767
|
+
},
|
|
5768
|
+
{
|
|
5769
|
+
"name": "column",
|
|
5770
|
+
"type": {
|
|
5771
|
+
"text": "KRTableColumn"
|
|
5772
|
+
}
|
|
5773
|
+
}
|
|
5774
|
+
]
|
|
5775
|
+
},
|
|
5776
|
+
{
|
|
5777
|
+
"kind": "method",
|
|
5778
|
+
"name": "_handleFilterBooleanChange",
|
|
5779
|
+
"privacy": "private",
|
|
5780
|
+
"parameters": [
|
|
5781
|
+
{
|
|
5782
|
+
"name": "e",
|
|
5783
|
+
"type": {
|
|
5784
|
+
"text": "Event"
|
|
5785
|
+
}
|
|
5786
|
+
},
|
|
5787
|
+
{
|
|
5788
|
+
"name": "column",
|
|
5789
|
+
"type": {
|
|
5790
|
+
"text": "KRTableColumn"
|
|
5791
|
+
}
|
|
5792
|
+
}
|
|
5793
|
+
]
|
|
5794
|
+
},
|
|
5795
|
+
{
|
|
5796
|
+
"kind": "method",
|
|
5797
|
+
"name": "_handleFilterDateStartChange",
|
|
5798
|
+
"privacy": "private",
|
|
5799
|
+
"parameters": [
|
|
5800
|
+
{
|
|
5801
|
+
"name": "e",
|
|
5802
|
+
"type": {
|
|
5803
|
+
"text": "Event"
|
|
5804
|
+
}
|
|
5805
|
+
},
|
|
5806
|
+
{
|
|
5807
|
+
"name": "column",
|
|
5808
|
+
"type": {
|
|
5809
|
+
"text": "KRTableColumn"
|
|
5810
|
+
}
|
|
5811
|
+
}
|
|
5812
|
+
]
|
|
5813
|
+
},
|
|
5814
|
+
{
|
|
5815
|
+
"kind": "method",
|
|
5816
|
+
"name": "_handleFilterDateEndChange",
|
|
5817
|
+
"privacy": "private",
|
|
5818
|
+
"parameters": [
|
|
5819
|
+
{
|
|
5820
|
+
"name": "e",
|
|
5821
|
+
"type": {
|
|
5822
|
+
"text": "Event"
|
|
5823
|
+
}
|
|
5824
|
+
},
|
|
5825
|
+
{
|
|
5826
|
+
"name": "column",
|
|
5827
|
+
"type": {
|
|
5828
|
+
"text": "KRTableColumn"
|
|
5829
|
+
}
|
|
5830
|
+
}
|
|
5831
|
+
]
|
|
5832
|
+
},
|
|
5833
|
+
{
|
|
5834
|
+
"kind": "method",
|
|
5835
|
+
"name": "_handleFilterNumberStartChange",
|
|
5836
|
+
"privacy": "private",
|
|
5837
|
+
"parameters": [
|
|
5838
|
+
{
|
|
5839
|
+
"name": "e",
|
|
5840
|
+
"type": {
|
|
5841
|
+
"text": "Event"
|
|
5842
|
+
}
|
|
5843
|
+
},
|
|
5844
|
+
{
|
|
5845
|
+
"name": "column",
|
|
5846
|
+
"type": {
|
|
5847
|
+
"text": "KRTableColumn"
|
|
5848
|
+
}
|
|
5849
|
+
}
|
|
5850
|
+
]
|
|
5851
|
+
},
|
|
5852
|
+
{
|
|
5853
|
+
"kind": "method",
|
|
5854
|
+
"name": "_handleFilterNumberEndChange",
|
|
5855
|
+
"privacy": "private",
|
|
5856
|
+
"parameters": [
|
|
5857
|
+
{
|
|
5858
|
+
"name": "e",
|
|
5859
|
+
"type": {
|
|
5860
|
+
"text": "Event"
|
|
5861
|
+
}
|
|
5862
|
+
},
|
|
5863
|
+
{
|
|
5864
|
+
"name": "column",
|
|
5865
|
+
"type": {
|
|
5866
|
+
"text": "KRTableColumn"
|
|
5867
|
+
}
|
|
5868
|
+
}
|
|
5869
|
+
]
|
|
5870
|
+
},
|
|
5871
|
+
{
|
|
5872
|
+
"kind": "method",
|
|
5873
|
+
"name": "_handleFilterListChange",
|
|
5874
|
+
"privacy": "private",
|
|
5875
|
+
"parameters": [
|
|
5876
|
+
{
|
|
5877
|
+
"name": "e",
|
|
5878
|
+
"type": {
|
|
5879
|
+
"text": "Event"
|
|
5880
|
+
}
|
|
5881
|
+
},
|
|
5882
|
+
{
|
|
5883
|
+
"name": "column",
|
|
5884
|
+
"type": {
|
|
5885
|
+
"text": "KRTableColumn"
|
|
5886
|
+
}
|
|
5887
|
+
}
|
|
5888
|
+
]
|
|
5889
|
+
},
|
|
5890
|
+
{
|
|
5891
|
+
"kind": "method",
|
|
5892
|
+
"name": "_handleFilterApply",
|
|
5893
|
+
"privacy": "private"
|
|
5894
|
+
},
|
|
5895
|
+
{
|
|
5896
|
+
"kind": "method",
|
|
5897
|
+
"name": "_handleFilterPanelTabChange",
|
|
5898
|
+
"privacy": "private",
|
|
5899
|
+
"parameters": [
|
|
5900
|
+
{
|
|
5901
|
+
"name": "e",
|
|
5902
|
+
"type": {
|
|
5903
|
+
"text": "CustomEvent"
|
|
5904
|
+
}
|
|
5905
|
+
}
|
|
5906
|
+
]
|
|
5907
|
+
},
|
|
5908
|
+
{
|
|
5909
|
+
"kind": "method",
|
|
5910
|
+
"name": "_handleBucketToggle",
|
|
5911
|
+
"privacy": "private",
|
|
5912
|
+
"parameters": [
|
|
5913
|
+
{
|
|
5914
|
+
"name": "e",
|
|
5915
|
+
"type": {
|
|
5916
|
+
"text": "Event"
|
|
5917
|
+
}
|
|
5918
|
+
},
|
|
5919
|
+
{
|
|
5920
|
+
"name": "column",
|
|
5921
|
+
"type": {
|
|
5922
|
+
"text": "KRTableColumn"
|
|
5923
|
+
}
|
|
5924
|
+
},
|
|
5925
|
+
{
|
|
5926
|
+
"name": "bucket",
|
|
5927
|
+
"type": {
|
|
5928
|
+
"text": "KRBucket"
|
|
5929
|
+
}
|
|
5930
|
+
}
|
|
5931
|
+
]
|
|
5932
|
+
},
|
|
5933
|
+
{
|
|
5934
|
+
"kind": "method",
|
|
5935
|
+
"name": "_renderCellContent",
|
|
5936
|
+
"privacy": "private",
|
|
5937
|
+
"parameters": [
|
|
5938
|
+
{
|
|
5939
|
+
"name": "column",
|
|
5940
|
+
"type": {
|
|
5941
|
+
"text": "KRTableColumn"
|
|
5942
|
+
}
|
|
5943
|
+
},
|
|
5944
|
+
{
|
|
5945
|
+
"name": "row",
|
|
5946
|
+
"type": {
|
|
5947
|
+
"text": "Record<string, any>"
|
|
5948
|
+
}
|
|
5949
|
+
},
|
|
5950
|
+
{
|
|
5951
|
+
"name": "rowIndex",
|
|
5952
|
+
"type": {
|
|
5953
|
+
"text": "number"
|
|
5954
|
+
}
|
|
5955
|
+
}
|
|
5956
|
+
]
|
|
5957
|
+
},
|
|
5958
|
+
{
|
|
5959
|
+
"kind": "method",
|
|
5960
|
+
"name": "_getHeaderCellClasses",
|
|
5961
|
+
"privacy": "private",
|
|
5962
|
+
"return": {
|
|
5963
|
+
"type": {
|
|
5964
|
+
"text": "Record<string, boolean>"
|
|
5965
|
+
}
|
|
5966
|
+
},
|
|
5967
|
+
"parameters": [
|
|
5968
|
+
{
|
|
5969
|
+
"name": "column",
|
|
5970
|
+
"type": {
|
|
5971
|
+
"text": "KRTableColumn"
|
|
5972
|
+
}
|
|
5973
|
+
},
|
|
5974
|
+
{
|
|
5975
|
+
"name": "index",
|
|
5976
|
+
"type": {
|
|
5977
|
+
"text": "number"
|
|
5978
|
+
}
|
|
5979
|
+
}
|
|
5980
|
+
],
|
|
5981
|
+
"description": "Returns CSS classes for a header cell based on column config."
|
|
5982
|
+
},
|
|
5983
|
+
{
|
|
5984
|
+
"kind": "method",
|
|
5985
|
+
"name": "_getCellClasses",
|
|
5986
|
+
"privacy": "private",
|
|
5987
|
+
"return": {
|
|
5988
|
+
"type": {
|
|
5989
|
+
"text": "Record<string, boolean>"
|
|
5990
|
+
}
|
|
5991
|
+
},
|
|
5992
|
+
"parameters": [
|
|
5993
|
+
{
|
|
5994
|
+
"name": "column",
|
|
5995
|
+
"type": {
|
|
5996
|
+
"text": "KRTableColumn"
|
|
5997
|
+
}
|
|
5998
|
+
},
|
|
5999
|
+
{
|
|
6000
|
+
"name": "index",
|
|
6001
|
+
"type": {
|
|
6002
|
+
"text": "number"
|
|
6003
|
+
}
|
|
6004
|
+
}
|
|
6005
|
+
],
|
|
6006
|
+
"description": "Returns CSS classes for a table cell based on column config:\n- Alignment (center, right)\n- Sticky positioning (left, right)\n- Border classes for the last left-sticky or first right-sticky column"
|
|
6007
|
+
},
|
|
6008
|
+
{
|
|
6009
|
+
"kind": "method",
|
|
6010
|
+
"name": "_getCellStyle",
|
|
6011
|
+
"privacy": "private",
|
|
6012
|
+
"return": {
|
|
6013
|
+
"type": {
|
|
6014
|
+
"text": "Record<string, string>"
|
|
6015
|
+
}
|
|
6016
|
+
},
|
|
6017
|
+
"parameters": [
|
|
6018
|
+
{
|
|
6019
|
+
"name": "column",
|
|
6020
|
+
"type": {
|
|
6021
|
+
"text": "KRTableColumn"
|
|
6022
|
+
}
|
|
6023
|
+
},
|
|
6024
|
+
{
|
|
6025
|
+
"name": "index",
|
|
6026
|
+
"type": {
|
|
6027
|
+
"text": "number"
|
|
6028
|
+
}
|
|
6029
|
+
}
|
|
6030
|
+
],
|
|
6031
|
+
"description": "Returns inline styles for a table cell:\n- Width (from column config or default 150px)\n- Min-width (if specified)\n- Left/right offset for sticky columns (calculated from widths of preceding sticky columns)"
|
|
6032
|
+
},
|
|
6033
|
+
{
|
|
6034
|
+
"kind": "method",
|
|
6035
|
+
"name": "_renderPagination",
|
|
6036
|
+
"privacy": "private",
|
|
6037
|
+
"description": "Renders the pagination controls:\n- Previous page arrow (disabled on first page)\n- Range text showing \"1-50 of 150\" format\n- Next page arrow (disabled on last page)\n\nHidden when there's no data or all data fits on one page."
|
|
6038
|
+
},
|
|
6039
|
+
{
|
|
6040
|
+
"kind": "method",
|
|
6041
|
+
"name": "_renderCardHeader",
|
|
6042
|
+
"privacy": "private",
|
|
6043
|
+
"description": "Renders the card title block (title + description) above the toolbar in card mode."
|
|
6044
|
+
},
|
|
6045
|
+
{
|
|
6046
|
+
"kind": "method",
|
|
6047
|
+
"name": "_renderHeader",
|
|
6048
|
+
"privacy": "private",
|
|
6049
|
+
"description": "Renders the header toolbar containing:\n- Title (left, default variant only)\n- Search bar with view selector dropdown (center, or left-aligned in card variant)\n- Tools (right): page navigation, refresh button, column visibility picker, actions dropdown\n\nHidden when there's no title, no actions, and data fits on one page."
|
|
6050
|
+
},
|
|
6051
|
+
{
|
|
6052
|
+
"kind": "method",
|
|
6053
|
+
"name": "_renderStatus",
|
|
6054
|
+
"privacy": "private",
|
|
6055
|
+
"description": "Renders status message (loading, error, empty)"
|
|
6056
|
+
},
|
|
6057
|
+
{
|
|
6058
|
+
"kind": "method",
|
|
6059
|
+
"name": "_renderFilterPanel",
|
|
6060
|
+
"privacy": "private"
|
|
6061
|
+
},
|
|
6062
|
+
{
|
|
6063
|
+
"kind": "method",
|
|
6064
|
+
"name": "_renderFilterRow",
|
|
6065
|
+
"privacy": "private",
|
|
6066
|
+
"description": "Renders filter row below column headers.\nOnly displays for columns with filterable: true."
|
|
6067
|
+
},
|
|
6068
|
+
{
|
|
6069
|
+
"kind": "method",
|
|
6070
|
+
"name": "_renderTable",
|
|
6071
|
+
"privacy": "private",
|
|
6072
|
+
"description": "Renders the scrollable data grid with column headers and rows."
|
|
6073
|
+
}
|
|
6074
|
+
],
|
|
6075
|
+
"events": [
|
|
6076
|
+
{
|
|
6077
|
+
"name": "row-click",
|
|
6078
|
+
"type": {
|
|
6079
|
+
"text": "CustomEvent"
|
|
6080
|
+
}
|
|
6081
|
+
},
|
|
6082
|
+
{
|
|
6083
|
+
"name": "action",
|
|
6084
|
+
"type": {
|
|
6085
|
+
"text": "CustomEvent"
|
|
6086
|
+
}
|
|
6087
|
+
}
|
|
6088
|
+
],
|
|
6089
|
+
"attributes": [
|
|
6090
|
+
{
|
|
6091
|
+
"name": "def",
|
|
6092
|
+
"type": {
|
|
6093
|
+
"text": "KRTableDef"
|
|
6094
|
+
},
|
|
6095
|
+
"default": "{ columns: [] }",
|
|
6096
|
+
"fieldName": "def"
|
|
6097
|
+
},
|
|
6098
|
+
{
|
|
6099
|
+
"name": "variant",
|
|
6100
|
+
"type": {
|
|
6101
|
+
"text": "'default' | 'card'"
|
|
6102
|
+
},
|
|
6103
|
+
"default": "'default'",
|
|
6104
|
+
"description": "Table layout variant.\n- 'default': Full-page table that fills parent height with centered search.\n- 'card': Embedded table that sizes itself to content, left-aligns search, and\n reserves space for pageSize rows to prevent layout shift.",
|
|
6105
|
+
"fieldName": "variant"
|
|
6106
|
+
}
|
|
6107
|
+
],
|
|
6108
|
+
"superclass": {
|
|
6109
|
+
"name": "LitElement",
|
|
6110
|
+
"package": "lit"
|
|
6111
|
+
},
|
|
6112
|
+
"tagName": "kr-grid",
|
|
6113
|
+
"customElement": true
|
|
6114
|
+
}
|
|
6115
|
+
],
|
|
6116
|
+
"exports": [
|
|
6117
|
+
{
|
|
6118
|
+
"kind": "js",
|
|
6119
|
+
"name": "KRGrid",
|
|
6120
|
+
"declaration": {
|
|
6121
|
+
"name": "KRGrid",
|
|
6122
|
+
"module": "src/grid/grid.ts"
|
|
6123
|
+
}
|
|
6124
|
+
},
|
|
6125
|
+
{
|
|
6126
|
+
"kind": "custom-element-definition",
|
|
6127
|
+
"name": "kr-grid",
|
|
6128
|
+
"declaration": {
|
|
6129
|
+
"name": "KRGrid",
|
|
6130
|
+
"module": "src/grid/grid.ts"
|
|
6131
|
+
}
|
|
6132
|
+
}
|
|
6133
|
+
]
|
|
6134
|
+
},
|
|
5073
6135
|
{
|
|
5074
6136
|
"kind": "javascript-module",
|
|
5075
6137
|
"path": "src/monaco/monaco.ts",
|