@toolbox-web/grid 0.2.4 → 0.2.6
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/all.d.ts +61 -23
- package/all.js +841 -809
- package/all.js.map +1 -1
- package/index.d.ts +17 -5
- package/index.js +316 -247
- package/index.js.map +1 -1
- package/lib/plugins/clipboard/index.js +1 -1
- package/lib/plugins/clipboard/index.js.map +1 -1
- package/lib/plugins/column-virtualization/index.js +1 -1
- package/lib/plugins/column-virtualization/index.js.map +1 -1
- package/lib/plugins/context-menu/index.js +1 -1
- package/lib/plugins/context-menu/index.js.map +1 -1
- package/lib/plugins/export/index.js +1 -1
- package/lib/plugins/export/index.js.map +1 -1
- package/lib/plugins/filtering/index.js +1 -1
- package/lib/plugins/filtering/index.js.map +1 -1
- package/lib/plugins/grouping-columns/index.js +46 -45
- package/lib/plugins/grouping-columns/index.js.map +1 -1
- package/lib/plugins/grouping-rows/index.js +1 -1
- package/lib/plugins/grouping-rows/index.js.map +1 -1
- package/lib/plugins/master-detail/index.js +1 -1
- package/lib/plugins/master-detail/index.js.map +1 -1
- package/lib/plugins/multi-sort/index.js +1 -1
- package/lib/plugins/multi-sort/index.js.map +1 -1
- package/lib/plugins/pinned-columns/index.js +1 -1
- package/lib/plugins/pinned-columns/index.js.map +1 -1
- package/lib/plugins/pinned-rows/index.js +55 -47
- package/lib/plugins/pinned-rows/index.js.map +1 -1
- package/lib/plugins/pivot/index.js +243 -241
- package/lib/plugins/pivot/index.js.map +1 -1
- package/lib/plugins/reorder/index.js +87 -67
- package/lib/plugins/reorder/index.js.map +1 -1
- package/lib/plugins/selection/index.js +28 -27
- package/lib/plugins/selection/index.js.map +1 -1
- package/lib/plugins/server-side/index.js +2 -2
- package/lib/plugins/server-side/index.js.map +1 -1
- package/lib/plugins/tree/index.js +70 -70
- package/lib/plugins/tree/index.js.map +1 -1
- package/lib/plugins/undo-redo/index.js +1 -1
- package/lib/plugins/undo-redo/index.js.map +1 -1
- package/lib/plugins/visibility/index.js +1 -1
- package/lib/plugins/visibility/index.js.map +1 -1
- package/package.json +1 -1
- package/themes/dg-theme-bootstrap.css +0 -2
- package/themes/dg-theme-contrast.css +0 -1
- package/themes/dg-theme-large.css +0 -1
- package/themes/dg-theme-material.css +0 -2
- package/themes/dg-theme-standard.css +0 -1
- package/themes/dg-theme-vibrant.css +0 -1
- package/umd/grid.all.umd.js +13 -13
- package/umd/grid.all.umd.js.map +1 -1
- package/umd/grid.umd.js +7 -7
- package/umd/grid.umd.js.map +1 -1
- package/umd/plugins/grouping-columns.umd.js +1 -1
- package/umd/plugins/grouping-columns.umd.js.map +1 -1
- package/umd/plugins/pinned-rows.umd.js +1 -1
- package/umd/plugins/pinned-rows.umd.js.map +1 -1
- package/umd/plugins/pivot.umd.js +1 -1
- package/umd/plugins/pivot.umd.js.map +1 -1
- package/umd/plugins/reorder.umd.js +1 -1
- package/umd/plugins/reorder.umd.js.map +1 -1
- package/umd/plugins/selection.umd.js +1 -1
- package/umd/plugins/selection.umd.js.map +1 -1
- package/umd/plugins/server-side.umd.js +1 -1
- package/umd/plugins/server-side.umd.js.map +1 -1
- package/umd/plugins/tree.umd.js +1 -1
- package/umd/plugins/tree.umd.js.map +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(d,c){typeof exports=="object"&&typeof module<"u"?c(exports,require("../../core/plugin/base-plugin")):typeof define=="function"&&define.amd?define(["exports","../../core/plugin/base-plugin"],c):(d=typeof globalThis<"u"?globalThis:d||self,c(d.TbwGridPlugin_groupingColumns={},d.TbwGrid))})(this,(function(d,c){"use strict";function a(
|
|
1
|
+
(function(d,c){typeof exports=="object"&&typeof module<"u"?c(exports,require("../../core/plugin/base-plugin")):typeof define=="function"&&define.amd?define(["exports","../../core/plugin/base-plugin"],c):(d=typeof globalThis<"u"?globalThis:d||self,c(d.TbwGridPlugin_groupingColumns={},d.TbwGrid))})(this,(function(d,c){"use strict";function a(u){if(!u.length)return[];const r=new Map,e=[],t=(n,i)=>{if(!i.length)return;const l=e[e.length-1];if(l&&l.implicit&&l.firstIndex+l.columns.length===n){l.columns.push(...i);return}e.push({id:"__implicit__"+n,label:void 0,columns:i,firstIndex:n,implicit:!0})};let s=[],o=0;return u.forEach((n,i)=>{const l=n.group;if(!l){s.length===0&&(o=i),s.push(n);return}s.length&&(t(o,s.slice()),s=[]);const p=typeof l=="string"?l:l.id;let g=r.get(p);g||(g={id:p,label:typeof l=="string"?void 0:l.label,columns:[],firstIndex:i},r.set(p,g),e.push(g)),g.columns.push(n)}),s.length&&t(o,s),e.length===1&&e[0].implicit&&e[0].columns.length===u.length?[]:e}function h(u,r,e){if(!r.length||!u)return;const t=new Map;for(const o of r)for(const n of o.columns)n?.field&&t.set(n.field,o.id);const s=Array.from(u.querySelectorAll(".cell[data-field]"));s.forEach(o=>{const n=o.getAttribute("data-field")||"",i=t.get(n);i&&(o.classList.add("grouped"),o.getAttribute("data-group")||o.setAttribute("data-group",i))});for(const o of r){const n=o.columns[o.columns.length-1],i=s.find(l=>l.getAttribute("data-field")===n.field);i&&i.classList.add("group-end")}}function f(u,r){if(u.length===0)return null;const e=document.createElement("div");e.className="header-group-row",e.setAttribute("role","row");for(const t of u){const s=t.firstIndex!=null?t.firstIndex:r.findIndex(l=>t.columns.includes(l)),o=String(t.id).startsWith("__implicit__"),n=o?"":t.label||t.id,i=document.createElement("div");i.className="cell header-group-cell",o&&i.classList.add("implicit-group"),i.setAttribute("data-group",String(t.id)),i.style.gridColumn=`${s+1} / span ${t.columns.length}`,i.textContent=n,e.appendChild(i)}return e}function m(u){return u.some(r=>r.group!=null)}const b=".header-group-row{display:grid;grid-auto-flow:column;background:var(--tbw-grouping-columns-header-bg, var(--tbw-color-header-bg));border-bottom:1px solid var(--tbw-grouping-columns-border, var(--tbw-color-border))}.header-group-cell{display:flex;align-items:center;justify-content:center;padding:4px 8px;font-weight:600;font-size:.9em;text-transform:uppercase;letter-spacing:.5px;border-right:1px solid var(--tbw-grouping-columns-border, var(--tbw-color-border))}.header-group-cell:last-child{border-right:none}.header-row .cell.grouped{border-top:none}.header-row .cell.group-end{border-right:2px solid var(--tbw-grouping-columns-separator, var(--tbw-color-border-strong))}.header-row .cell.group-end:last-child{border-right:none}.header-group-row.no-borders{border-bottom:none}.header-group-row.no-borders .header-group-cell{border-right:none}.header-row.no-group-borders .cell.group-end{border-right:1px solid var(--tbw-color-border)}";class w extends c.BaseGridPlugin{name="groupingColumns";version="1.0.0";get defaultConfig(){return{showGroupBorders:!0}}groups=[];isActive=!1;detach(){this.groups=[],this.isActive=!1}static detect(r,e){const t=e?.columns;return Array.isArray(t)?m(t):!1}processColumns(r){const e=a(r);return e.length===0?(this.isActive=!1,this.groups=[],[...r]):(this.isActive=!0,this.groups=e,[...r])}afterRender(){if(!this.isActive||this.groups.length===0){const n=this.shadowRoot?.querySelector(".header")?.querySelector(".header-group-row");n&&n.remove();return}const r=this.shadowRoot?.querySelector(".header");if(!r)return;const e=r.querySelector(".header-group-row");e&&e.remove();const t=f(this.groups,this.columns);if(t){t.classList.toggle("no-borders",!this.config.showGroupBorders);const o=r.querySelector(".header-row");o?r.insertBefore(t,o):r.appendChild(t)}const s=r.querySelector(".header-row");s&&(s.classList.toggle("no-group-borders",!this.config.showGroupBorders),h(s,this.groups,this.columns))}isGroupingActive(){return this.isActive}getGroups(){return this.groups}getGroupColumns(r){const e=this.groups.find(t=>t.id===r);return e?e.columns:[]}refresh(){this.requestRender()}styles=b}d.GroupingColumnsPlugin=w,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})}));
|
|
2
2
|
//# sourceMappingURL=grouping-columns.umd.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grouping-columns.umd.js","sources":["../../../../../libs/grid/src/lib/plugins/grouping-columns/grouping-columns.ts","../../../../../libs/grid/src/lib/plugins/grouping-columns/GroupingColumnsPlugin.ts"],"sourcesContent":["/**\n * Column Groups Core Logic\n *\n * Pure functions for computing and managing column header groups.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type { ColumnConfig } from '../../core/types';\nimport type { ColumnGroup, ColumnGroupInternal } from './types';\n\n/**\n * Compute column groups from column configuration.\n * Handles explicit groups (via column.group) and creates implicit groups for ungrouped columns.\n *\n * @param columns - Array of column configurations\n * @returns Array of column groups, or empty if no meaningful groups\n */\nexport function computeColumnGroups<T>(columns: ColumnConfig<T>[]): ColumnGroup<T>[] {\n if (!columns.length) return [];\n\n const explicitMap = new Map<string, ColumnGroupInternal<T>>();\n const groupsOrdered: ColumnGroupInternal<T>[] = [];\n\n // Helper to push unnamed implicit group for a run of ungrouped columns\n const pushImplicit = (startIdx: number, cols: ColumnConfig<T>[]) => {\n if (!cols.length) return;\n // Merge with previous implicit group if adjacent to reduce noise\n const prev = groupsOrdered[groupsOrdered.length - 1];\n if (prev && prev.implicit && prev.firstIndex + prev.columns.length === startIdx) {\n prev.columns.push(...cols);\n return;\n }\n groupsOrdered.push({\n id: '__implicit__' + startIdx,\n label: undefined,\n columns: cols,\n firstIndex: startIdx,\n implicit: true,\n });\n };\n\n let run: ColumnConfig<T>[] = [];\n let runStart = 0;\n\n columns.forEach((col, idx) => {\n const g: any = (col as any).group;\n if (!g) {\n if (run.length === 0) runStart = idx;\n run.push(col);\n return;\n }\n // Close any pending implicit run\n if (run.length) {\n pushImplicit(runStart, run.slice());\n run = [];\n }\n const id = typeof g === 'string' ? g : g.id;\n let group = explicitMap.get(id);\n if (!group) {\n group = {\n id,\n label: typeof g === 'string' ? undefined : g.label,\n columns: [],\n firstIndex: idx,\n };\n explicitMap.set(id, group);\n groupsOrdered.push(group);\n }\n group.columns.push(col);\n });\n\n // Trailing implicit run\n if (run.length) pushImplicit(runStart, run);\n\n // If we only have a single implicit group covering all columns, treat as no groups\n if (\n groupsOrdered.length === 1 &&\n groupsOrdered[0].implicit &&\n groupsOrdered[0].columns.length === columns.length\n ) {\n return [];\n }\n\n return groupsOrdered as ColumnGroup<T>[];\n}\n\n/**\n * Apply CSS classes to header cells based on their group membership.\n *\n * @param headerRowEl - The header row element\n * @param groups - The computed column groups\n * @param columns - The column configurations\n */\nexport function applyGroupedHeaderCellClasses(\n headerRowEl: HTMLElement | null,\n groups: ColumnGroup[],\n columns: ColumnConfig<any>[]\n): void {\n if (!groups.length || !headerRowEl) return;\n\n const fieldToGroup = new Map<string, string>();\n for (const g of groups) {\n for (const c of g.columns) {\n if ((c as any)?.field) {\n fieldToGroup.set((c as any).field, g.id);\n }\n }\n }\n\n const headerCells = Array.from(headerRowEl.querySelectorAll('.cell[data-field]')) as HTMLElement[];\n headerCells.forEach((cell) => {\n const f = cell.getAttribute('data-field') || '';\n const gid = fieldToGroup.get(f);\n if (gid) {\n cell.classList.add('grouped');\n if (!cell.getAttribute('data-group')) {\n cell.setAttribute('data-group', gid);\n }\n }\n });\n\n // Mark group end cells for styling\n for (const g of groups) {\n const last = g.columns[g.columns.length - 1];\n const cell = headerCells.find((c) => c.getAttribute('data-field') === (last as any).field);\n if (cell) cell.classList.add('group-end');\n }\n}\n\n/**\n * Build the group header row element.\n *\n * @param groups - The computed column groups\n * @param columns - The column configurations\n * @returns The group header row element, or null if no groups\n */\nexport function buildGroupHeaderRow(\n groups: ColumnGroup[],\n columns: ColumnConfig<any>[]\n): HTMLElement | null {\n if (groups.length === 0) return null;\n\n const groupRow = document.createElement('div');\n groupRow.className = 'header-group-row';\n groupRow.setAttribute('role', 'row');\n\n for (const g of groups) {\n const startIndex =\n g.firstIndex != null\n ? g.firstIndex\n : columns.findIndex((c) => (g.columns as any[]).includes(c));\n\n const isImplicit = String(g.id).startsWith('__implicit__');\n const label = isImplicit ? '' : g.label || g.id;\n\n const cell = document.createElement('div');\n cell.className = 'cell header-group-cell';\n if (isImplicit) cell.classList.add('implicit-group');\n cell.setAttribute('data-group', String(g.id));\n cell.style.gridColumn = `${startIndex + 1} / span ${g.columns.length}`;\n cell.textContent = label;\n groupRow.appendChild(cell);\n }\n\n return groupRow;\n}\n\n/**\n * Check if any columns have group configuration.\n *\n * @param columns - The column configurations\n * @returns True if at least one column has a group\n */\nexport function hasColumnGroups(columns: ColumnConfig<any>[]): boolean {\n return columns.some((col) => (col as any).group != null);\n}\n\n/**\n * Get group ID for a specific column.\n *\n * @param column - The column configuration\n * @returns The group ID, or undefined if not grouped\n */\nexport function getColumnGroupId(column: ColumnConfig<any>): string | undefined {\n const g = (column as any).group;\n if (!g) return undefined;\n return typeof g === 'string' ? g : g.id;\n}\n","/**\n * Column Groups Plugin (Class-based)\n *\n * Enables multi-level column header grouping.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { BaseGridPlugin } from '../../core/plugin/base-plugin';\nimport type { ColumnConfig } from '../../core/types';\nimport {\n applyGroupedHeaderCellClasses,\n buildGroupHeaderRow,\n computeColumnGroups,\n hasColumnGroups,\n} from './grouping-columns';\nimport styles from './grouping-columns.css?inline';\nimport type { ColumnGroup, GroupingColumnsConfig } from './types';\n\n/**\n * Column Groups Plugin for tbw-grid\n *\n * @example\n * ```ts\n * new GroupingColumnsPlugin({\n * enabled: true,\n * showGroupBorders: true,\n * })\n * ```\n */\nexport class GroupingColumnsPlugin extends BaseGridPlugin<GroupingColumnsConfig> {\n readonly name = 'groupingColumns';\n override readonly version = '1.0.0';\n\n protected override get defaultConfig(): Partial<GroupingColumnsConfig> {\n return {\n showGroupBorders: true,\n };\n }\n\n // #region Internal State\n private groups: ColumnGroup[] = [];\n private isActive = false;\n // #endregion\n\n // #region Lifecycle\n\n override detach(): void {\n this.groups = [];\n this.isActive = false;\n }\n // #endregion\n\n // #region Static Detection\n\n /**\n * Auto-detect column groups from column configuration.\n */\n static detect(rows: readonly any[], config: any): boolean {\n const columns = config?.columns;\n if (!Array.isArray(columns)) return false;\n return hasColumnGroups(columns);\n }\n // #endregion\n\n // #region Hooks\n\n override processColumns(columns: readonly ColumnConfig[]): ColumnConfig[] {\n // Compute groups from column definitions\n const groups = computeColumnGroups(columns as ColumnConfig[]);\n\n if (groups.length === 0) {\n this.isActive = false;\n this.groups = [];\n return [...columns];\n }\n\n this.isActive = true;\n this.groups = groups;\n\n // Return columns unchanged - the afterRender hook will add the group header\n return [...columns];\n }\n\n override afterRender(): void {\n if (!this.isActive || this.groups.length === 0) {\n // Remove any existing group header\n const header = this.shadowRoot?.querySelector('.header');\n const existingGroupRow = header?.querySelector('.header-group-row');\n if (existingGroupRow) existingGroupRow.remove();\n return;\n }\n\n const header = this.shadowRoot?.querySelector('.header');\n if (!header) return;\n\n // Remove existing group row if present\n const existingGroupRow = header.querySelector('.header-group-row');\n if (existingGroupRow) existingGroupRow.remove();\n\n // Build and insert group header row\n const groupRow = buildGroupHeaderRow(this.groups, this.columns as ColumnConfig[]);\n if (groupRow) {\n const headerRow = header.querySelector('.header-row');\n if (headerRow) {\n header.insertBefore(groupRow, headerRow);\n } else {\n header.appendChild(groupRow);\n }\n }\n\n // Apply classes to header cells\n const headerRow = header.querySelector('.header-row') as HTMLElement;\n if (headerRow) {\n applyGroupedHeaderCellClasses(headerRow, this.groups, this.columns as ColumnConfig[]);\n }\n }\n // #endregion\n\n // #region Public API\n\n /**\n * Check if column groups are active.\n * @returns Whether grouping is active\n */\n isGroupingActive(): boolean {\n return this.isActive;\n }\n\n /**\n * Get the computed column groups.\n * @returns Array of column groups\n */\n getGroups(): ColumnGroup[] {\n return this.groups;\n }\n\n /**\n * Get columns in a specific group.\n * @param groupId - The group ID to find\n * @returns Array of columns in the group\n */\n getGroupColumns(groupId: string): ColumnConfig[] {\n const group = this.groups.find((g) => g.id === groupId);\n return group ? group.columns : [];\n }\n\n /**\n * Refresh column groups (recompute from current columns).\n */\n refresh(): void {\n this.requestRender();\n }\n // #endregion\n\n // #region Styles\n\n override readonly styles = styles;\n // #endregion\n}\n"],"names":["computeColumnGroups","columns","explicitMap","groupsOrdered","pushImplicit","startIdx","cols","prev","run","runStart","col","idx","g","id","group","applyGroupedHeaderCellClasses","headerRowEl","groups","fieldToGroup","c","headerCells","cell","f","gid","last","buildGroupHeaderRow","groupRow","startIndex","isImplicit","label","hasColumnGroups","GroupingColumnsPlugin","BaseGridPlugin","rows","config","existingGroupRow","header","headerRow","groupId","styles"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"grouping-columns.umd.js","sources":["../../../../../libs/grid/src/lib/plugins/grouping-columns/grouping-columns.ts","../../../../../libs/grid/src/lib/plugins/grouping-columns/GroupingColumnsPlugin.ts"],"sourcesContent":["/**\n * Column Groups Core Logic\n *\n * Pure functions for computing and managing column header groups.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport type { ColumnConfig } from '../../core/types';\nimport type { ColumnGroup, ColumnGroupInternal } from './types';\n\n/**\n * Compute column groups from column configuration.\n * Handles explicit groups (via column.group) and creates implicit groups for ungrouped columns.\n *\n * @param columns - Array of column configurations\n * @returns Array of column groups, or empty if no meaningful groups\n */\nexport function computeColumnGroups<T>(columns: ColumnConfig<T>[]): ColumnGroup<T>[] {\n if (!columns.length) return [];\n\n const explicitMap = new Map<string, ColumnGroupInternal<T>>();\n const groupsOrdered: ColumnGroupInternal<T>[] = [];\n\n // Helper to push unnamed implicit group for a run of ungrouped columns\n const pushImplicit = (startIdx: number, cols: ColumnConfig<T>[]) => {\n if (!cols.length) return;\n // Merge with previous implicit group if adjacent to reduce noise\n const prev = groupsOrdered[groupsOrdered.length - 1];\n if (prev && prev.implicit && prev.firstIndex + prev.columns.length === startIdx) {\n prev.columns.push(...cols);\n return;\n }\n groupsOrdered.push({\n id: '__implicit__' + startIdx,\n label: undefined,\n columns: cols,\n firstIndex: startIdx,\n implicit: true,\n });\n };\n\n let run: ColumnConfig<T>[] = [];\n let runStart = 0;\n\n columns.forEach((col, idx) => {\n const g: any = (col as any).group;\n if (!g) {\n if (run.length === 0) runStart = idx;\n run.push(col);\n return;\n }\n // Close any pending implicit run\n if (run.length) {\n pushImplicit(runStart, run.slice());\n run = [];\n }\n const id = typeof g === 'string' ? g : g.id;\n let group = explicitMap.get(id);\n if (!group) {\n group = {\n id,\n label: typeof g === 'string' ? undefined : g.label,\n columns: [],\n firstIndex: idx,\n };\n explicitMap.set(id, group);\n groupsOrdered.push(group);\n }\n group.columns.push(col);\n });\n\n // Trailing implicit run\n if (run.length) pushImplicit(runStart, run);\n\n // If we only have a single implicit group covering all columns, treat as no groups\n if (\n groupsOrdered.length === 1 &&\n groupsOrdered[0].implicit &&\n groupsOrdered[0].columns.length === columns.length\n ) {\n return [];\n }\n\n return groupsOrdered as ColumnGroup<T>[];\n}\n\n/**\n * Apply CSS classes to header cells based on their group membership.\n *\n * @param headerRowEl - The header row element\n * @param groups - The computed column groups\n * @param columns - The column configurations\n */\nexport function applyGroupedHeaderCellClasses(\n headerRowEl: HTMLElement | null,\n groups: ColumnGroup[],\n columns: ColumnConfig<any>[]\n): void {\n if (!groups.length || !headerRowEl) return;\n\n const fieldToGroup = new Map<string, string>();\n for (const g of groups) {\n for (const c of g.columns) {\n if ((c as any)?.field) {\n fieldToGroup.set((c as any).field, g.id);\n }\n }\n }\n\n const headerCells = Array.from(headerRowEl.querySelectorAll('.cell[data-field]')) as HTMLElement[];\n headerCells.forEach((cell) => {\n const f = cell.getAttribute('data-field') || '';\n const gid = fieldToGroup.get(f);\n if (gid) {\n cell.classList.add('grouped');\n if (!cell.getAttribute('data-group')) {\n cell.setAttribute('data-group', gid);\n }\n }\n });\n\n // Mark group end cells for styling\n for (const g of groups) {\n const last = g.columns[g.columns.length - 1];\n const cell = headerCells.find((c) => c.getAttribute('data-field') === (last as any).field);\n if (cell) cell.classList.add('group-end');\n }\n}\n\n/**\n * Build the group header row element.\n *\n * @param groups - The computed column groups\n * @param columns - The column configurations\n * @returns The group header row element, or null if no groups\n */\nexport function buildGroupHeaderRow(\n groups: ColumnGroup[],\n columns: ColumnConfig<any>[]\n): HTMLElement | null {\n if (groups.length === 0) return null;\n\n const groupRow = document.createElement('div');\n groupRow.className = 'header-group-row';\n groupRow.setAttribute('role', 'row');\n\n for (const g of groups) {\n const startIndex =\n g.firstIndex != null\n ? g.firstIndex\n : columns.findIndex((c) => (g.columns as any[]).includes(c));\n\n const isImplicit = String(g.id).startsWith('__implicit__');\n const label = isImplicit ? '' : g.label || g.id;\n\n const cell = document.createElement('div');\n cell.className = 'cell header-group-cell';\n if (isImplicit) cell.classList.add('implicit-group');\n cell.setAttribute('data-group', String(g.id));\n cell.style.gridColumn = `${startIndex + 1} / span ${g.columns.length}`;\n cell.textContent = label;\n groupRow.appendChild(cell);\n }\n\n return groupRow;\n}\n\n/**\n * Check if any columns have group configuration.\n *\n * @param columns - The column configurations\n * @returns True if at least one column has a group\n */\nexport function hasColumnGroups(columns: ColumnConfig<any>[]): boolean {\n return columns.some((col) => (col as any).group != null);\n}\n\n/**\n * Get group ID for a specific column.\n *\n * @param column - The column configuration\n * @returns The group ID, or undefined if not grouped\n */\nexport function getColumnGroupId(column: ColumnConfig<any>): string | undefined {\n const g = (column as any).group;\n if (!g) return undefined;\n return typeof g === 'string' ? g : g.id;\n}\n","/**\n * Column Groups Plugin (Class-based)\n *\n * Enables multi-level column header grouping.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n\nimport { BaseGridPlugin } from '../../core/plugin/base-plugin';\nimport type { ColumnConfig } from '../../core/types';\nimport {\n applyGroupedHeaderCellClasses,\n buildGroupHeaderRow,\n computeColumnGroups,\n hasColumnGroups,\n} from './grouping-columns';\nimport styles from './grouping-columns.css?inline';\nimport type { ColumnGroup, GroupingColumnsConfig } from './types';\n\n/**\n * Column Groups Plugin for tbw-grid\n *\n * @example\n * ```ts\n * new GroupingColumnsPlugin({\n * enabled: true,\n * showGroupBorders: true,\n * })\n * ```\n */\nexport class GroupingColumnsPlugin extends BaseGridPlugin<GroupingColumnsConfig> {\n readonly name = 'groupingColumns';\n override readonly version = '1.0.0';\n\n protected override get defaultConfig(): Partial<GroupingColumnsConfig> {\n return {\n showGroupBorders: true,\n };\n }\n\n // #region Internal State\n private groups: ColumnGroup[] = [];\n private isActive = false;\n // #endregion\n\n // #region Lifecycle\n\n override detach(): void {\n this.groups = [];\n this.isActive = false;\n }\n // #endregion\n\n // #region Static Detection\n\n /**\n * Auto-detect column groups from column configuration.\n */\n static detect(rows: readonly any[], config: any): boolean {\n const columns = config?.columns;\n if (!Array.isArray(columns)) return false;\n return hasColumnGroups(columns);\n }\n // #endregion\n\n // #region Hooks\n\n override processColumns(columns: readonly ColumnConfig[]): ColumnConfig[] {\n // Compute groups from column definitions\n const groups = computeColumnGroups(columns as ColumnConfig[]);\n\n if (groups.length === 0) {\n this.isActive = false;\n this.groups = [];\n return [...columns];\n }\n\n this.isActive = true;\n this.groups = groups;\n\n // Return columns unchanged - the afterRender hook will add the group header\n return [...columns];\n }\n\n override afterRender(): void {\n if (!this.isActive || this.groups.length === 0) {\n // Remove any existing group header\n const header = this.shadowRoot?.querySelector('.header');\n const existingGroupRow = header?.querySelector('.header-group-row');\n if (existingGroupRow) existingGroupRow.remove();\n return;\n }\n\n const header = this.shadowRoot?.querySelector('.header');\n if (!header) return;\n\n // Remove existing group row if present\n const existingGroupRow = header.querySelector('.header-group-row');\n if (existingGroupRow) existingGroupRow.remove();\n\n // Build and insert group header row\n const groupRow = buildGroupHeaderRow(this.groups, this.columns as ColumnConfig[]);\n if (groupRow) {\n // Toggle border visibility class\n groupRow.classList.toggle('no-borders', !this.config.showGroupBorders);\n\n const headerRow = header.querySelector('.header-row');\n if (headerRow) {\n header.insertBefore(groupRow, headerRow);\n } else {\n header.appendChild(groupRow);\n }\n }\n\n // Apply classes to header cells\n const headerRow = header.querySelector('.header-row') as HTMLElement;\n if (headerRow) {\n // Toggle border visibility on header cells\n headerRow.classList.toggle('no-group-borders', !this.config.showGroupBorders);\n applyGroupedHeaderCellClasses(headerRow, this.groups, this.columns as ColumnConfig[]);\n }\n }\n // #endregion\n\n // #region Public API\n\n /**\n * Check if column groups are active.\n * @returns Whether grouping is active\n */\n isGroupingActive(): boolean {\n return this.isActive;\n }\n\n /**\n * Get the computed column groups.\n * @returns Array of column groups\n */\n getGroups(): ColumnGroup[] {\n return this.groups;\n }\n\n /**\n * Get columns in a specific group.\n * @param groupId - The group ID to find\n * @returns Array of columns in the group\n */\n getGroupColumns(groupId: string): ColumnConfig[] {\n const group = this.groups.find((g) => g.id === groupId);\n return group ? group.columns : [];\n }\n\n /**\n * Refresh column groups (recompute from current columns).\n */\n refresh(): void {\n this.requestRender();\n }\n // #endregion\n\n // #region Styles\n\n override readonly styles = styles;\n // #endregion\n}\n"],"names":["computeColumnGroups","columns","explicitMap","groupsOrdered","pushImplicit","startIdx","cols","prev","run","runStart","col","idx","g","id","group","applyGroupedHeaderCellClasses","headerRowEl","groups","fieldToGroup","c","headerCells","cell","f","gid","last","buildGroupHeaderRow","groupRow","startIndex","isImplicit","label","hasColumnGroups","GroupingColumnsPlugin","BaseGridPlugin","rows","config","existingGroupRow","header","headerRow","groupId","styles"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(d,
|
|
1
|
+
(function(d,h){typeof exports=="object"&&typeof module<"u"?h(exports,require("../../core/plugin/base-plugin"),require("../../core/internal/aggregators")):typeof define=="function"&&define.amd?define(["exports","../../core/plugin/base-plugin","../../core/internal/aggregators"],h):(d=typeof globalThis<"u"?globalThis:d||self,h(d.TbwGridPlugin_pinnedRows={},d.TbwGrid,d.TbwGrid))})(this,(function(d,h,w){"use strict";function v(n){return typeof n=="object"&&n!==null&&"aggFunc"in n}function u(n,t){const o=document.createElement("div");o.className="tbw-pinned-rows",o.setAttribute("role","presentation"),o.setAttribute("aria-live","polite");const r=document.createElement("div");r.className="tbw-pinned-rows-left";const s=document.createElement("div");s.className="tbw-pinned-rows-center";const i=document.createElement("div");if(i.className="tbw-pinned-rows-right",n.showRowCount!==!1){const e=document.createElement("span");e.className="tbw-status-panel tbw-status-panel-row-count",e.textContent=`Total: ${t.totalRows} rows`,r.appendChild(e)}if(n.showFilteredCount&&t.filteredRows!==t.totalRows){const e=document.createElement("span");e.className="tbw-status-panel tbw-status-panel-filtered-count",e.textContent=`Filtered: ${t.filteredRows}`,r.appendChild(e)}if(n.showSelectedCount&&t.selectedRows>0){const e=document.createElement("span");e.className="tbw-status-panel tbw-status-panel-selected-count",e.textContent=`Selected: ${t.selectedRows}`,i.appendChild(e)}if(n.customPanels)for(const e of n.customPanels){const a=A(e,t);switch(e.position){case"left":r.appendChild(a);break;case"center":s.appendChild(a);break;case"right":i.appendChild(a);break}}return o.appendChild(r),o.appendChild(s),o.appendChild(i),o}function m(n){const t=document.createElement("div");return t.className=`tbw-aggregation-rows tbw-aggregation-rows-${n}`,t.setAttribute("role","presentation"),t}function b(n,t,o,r){n.innerHTML="";for(const s of t){const i=document.createElement("div");if(i.className="tbw-aggregation-row",i.setAttribute("role","presentation"),s.id&&i.setAttribute("data-aggregation-id",s.id),s.fullWidth){const e=document.createElement("div");e.className="tbw-aggregation-cell tbw-aggregation-cell-full",e.style.gridColumn="1 / -1",e.textContent=s.label||"",i.appendChild(e)}else for(const e of o){const a=document.createElement("div");a.className="tbw-aggregation-cell",a.setAttribute("data-field",e.field);let l,p;const f=s.aggregators?.[e.field];if(f)if(v(f)){const g=w.getAggregator(f.aggFunc);g&&(l=g(r,e.field,e)),p=f.formatter}else{const g=w.getAggregator(f);g&&(l=g(r,e.field,e))}else if(s.cells&&Object.prototype.hasOwnProperty.call(s.cells,e.field)){const g=s.cells[e.field];typeof g=="function"?l=g(r,e.field,e):l=g}l!=null?a.textContent=p?p(l,e.field,e):String(l):a.textContent="",i.appendChild(a)}n.appendChild(i)}}function A(n,t){const o=document.createElement("div");o.className="tbw-status-panel tbw-status-panel-custom",o.id=`status-panel-${n.id}`;const r=n.render(t);return typeof r=="string"?o.innerHTML=r:o.appendChild(r),o}function C(n,t,o,r,s){return{totalRows:n.length,filteredRows:s?.cachedResult?.length??n.length,selectedRows:r?.selected?.size??0,columns:t,rows:n,grid:o}}const R=".tbw-footer{position:sticky;bottom:0;z-index:var(--tbw-z-layer-pinned-rows, 20);background:var(--tbw-color-panel-bg)}.tbw-pinned-rows{display:flex;align-items:center;justify-content:space-between;padding:8px 12px;background:var(--tbw-pinned-rows-bg, var(--tbw-color-panel-bg));border-top:1px solid var(--tbw-pinned-rows-border, var(--tbw-color-border));font-size:12px;color:var(--tbw-pinned-rows-color, var(--tbw-color-fg-muted));min-height:32px;box-sizing:border-box;min-width:fit-content}.tbw-pinned-rows-left,.tbw-pinned-rows-center,.tbw-pinned-rows-right{display:flex;align-items:center;gap:16px}.tbw-pinned-rows-left{justify-content:flex-start}.tbw-pinned-rows-center{justify-content:center;flex:1}.tbw-pinned-rows-right{justify-content:flex-end}.tbw-status-panel{white-space:nowrap}.tbw-aggregation-rows{min-width:fit-content;background:var(--tbw-aggregation-bg, var(--tbw-color-header-bg))}.tbw-aggregation-rows-top{border-bottom:1px solid var(--tbw-aggregation-border, var(--tbw-color-border))}.tbw-aggregation-rows-bottom{border-top:1px solid var(--tbw-aggregation-border, var(--tbw-color-border))}.tbw-aggregation-row{display:grid;grid-template-columns:var(--tbw-column-template);font-size:var(--tbw-aggregation-font-size, .8em);font-weight:var(--tbw-aggregation-font-weight, 600)}.tbw-aggregation-cell{padding:var(--tbw-cell-padding, 2px 8px);min-height:var(--tbw-row-height, 28px);display:flex;align-items:center;border-right:1px solid var(--tbw-color-border-cell)}.tbw-aggregation-cell:last-child{border-right:0}.tbw-aggregation-cell-full{grid-column:1 / -1;border-right:0}";class E extends h.BaseGridPlugin{name="pinnedRows";version="1.0.0";get defaultConfig(){return{position:"bottom",showRowCount:!0,showSelectedCount:!0,showFilteredCount:!0}}infoBarElement=null;topAggregationContainer=null;bottomAggregationContainer=null;footerWrapper=null;detach(){this.infoBarElement&&(this.infoBarElement.remove(),this.infoBarElement=null),this.topAggregationContainer&&(this.topAggregationContainer.remove(),this.topAggregationContainer=null),this.bottomAggregationContainer&&(this.bottomAggregationContainer.remove(),this.bottomAggregationContainer=null),this.footerWrapper&&(this.footerWrapper.remove(),this.footerWrapper=null)}afterRender(){const t=this.shadowRoot;if(!t)return;const o=t.querySelector(".tbw-scroll-area")??t.querySelector(".tbw-grid-content")??t.children[0];if(!o)return;const r=this.getSelectionState(),s=this.getFilterState(),i=C(this.rows,this.columns,this.grid,r,s),e=this.config.aggregationRows||[],a=e.filter(c=>c.position==="top"),l=e.filter(c=>c.position!=="top");if(a.length>0){if(!this.topAggregationContainer){this.topAggregationContainer=m("top");const c=t.querySelector(".header");c&&c.nextSibling?o.insertBefore(this.topAggregationContainer,c.nextSibling):o.appendChild(this.topAggregationContainer)}b(this.topAggregationContainer,a,this.visibleColumns,this.rows)}else this.topAggregationContainer&&(this.topAggregationContainer.remove(),this.topAggregationContainer=null);const p=this.config.showRowCount!==!1||this.config.showSelectedCount&&i.selectedRows>0||this.config.showFilteredCount&&i.filteredRows!==i.totalRows||this.config.customPanels&&this.config.customPanels.length>0,f=p&&this.config.position!=="top",g=l.length>0||f;if(p&&this.config.position==="top")if(!this.infoBarElement)this.infoBarElement=u(this.config,i),o.insertBefore(this.infoBarElement,o.firstChild);else{const c=u(this.config,i);this.infoBarElement.replaceWith(c),this.infoBarElement=c}else this.config.position==="top"&&this.infoBarElement&&(this.infoBarElement.remove(),this.infoBarElement=null);g?(this.footerWrapper||(this.footerWrapper=document.createElement("div"),this.footerWrapper.className="tbw-footer",o.appendChild(this.footerWrapper)),this.footerWrapper.innerHTML="",l.length>0&&(this.bottomAggregationContainer||(this.bottomAggregationContainer=m("bottom")),this.footerWrapper.appendChild(this.bottomAggregationContainer),b(this.bottomAggregationContainer,l,this.visibleColumns,this.rows)),f&&(this.infoBarElement=u(this.config,i),this.footerWrapper.appendChild(this.infoBarElement))):this.cleanupFooter()}cleanup(){this.infoBarElement&&(this.infoBarElement.remove(),this.infoBarElement=null),this.topAggregationContainer&&(this.topAggregationContainer.remove(),this.topAggregationContainer=null),this.bottomAggregationContainer&&(this.bottomAggregationContainer.remove(),this.bottomAggregationContainer=null),this.footerWrapper&&(this.footerWrapper.remove(),this.footerWrapper=null)}cleanupFooter(){this.footerWrapper&&(this.footerWrapper.remove(),this.footerWrapper=null),this.bottomAggregationContainer&&(this.bottomAggregationContainer.remove(),this.bottomAggregationContainer=null),this.infoBarElement&&this.config.position!=="top"&&(this.infoBarElement.remove(),this.infoBarElement=null)}getSelectionState(){try{return this.grid?.getPluginState?.("selection")??null}catch{return null}}getFilterState(){try{return this.grid?.getPluginState?.("filtering")??null}catch{return null}}refresh(){this.requestRender()}getContext(){const t=this.getSelectionState(),o=this.getFilterState();return C(this.rows,this.columns,this.grid,t,o)}addPanel(t){this.config.customPanels||(this.config.customPanels=[]),this.config.customPanels.push(t),this.requestRender()}removePanel(t){this.config.customPanels&&(this.config.customPanels=this.config.customPanels.filter(o=>o.id!==t),this.requestRender())}addAggregationRow(t){this.config.aggregationRows||(this.config.aggregationRows=[]),this.config.aggregationRows.push(t),this.requestRender()}removeAggregationRow(t){this.config.aggregationRows&&(this.config.aggregationRows=this.config.aggregationRows.filter(o=>o.id!==t),this.requestRender())}styles=R}d.PinnedRowsPlugin=E,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})}));
|
|
2
2
|
//# sourceMappingURL=pinned-rows.umd.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pinned-rows.umd.js","sources":["../../../../../libs/grid/src/lib/plugins/pinned-rows/pinned-rows.ts","../../../../../libs/grid/src/lib/plugins/pinned-rows/PinnedRowsPlugin.ts"],"sourcesContent":["/**\n * Status Bar Rendering Logic\n *\n * Pure functions for creating and updating the status bar UI.\n * Includes both info bar and aggregation row rendering.\n */\n\nimport { getAggregator } from '../../core/internal/aggregators';\nimport type { ColumnConfig } from '../../core/types';\nimport type { AggregationRowConfig, PinnedRowsConfig, PinnedRowsContext, PinnedRowsPanel } from './types';\n\n/**\n * Creates the info bar DOM element with all configured panels.\n *\n * @param config - The status bar configuration\n * @param context - The current grid context for rendering\n * @returns The complete info bar element\n */\nexport function createInfoBarElement(config: PinnedRowsConfig, context: PinnedRowsContext): HTMLElement {\n const pinnedRows = document.createElement('div');\n pinnedRows.className = 'tbw-pinned-rows';\n pinnedRows.setAttribute('role', 'presentation');\n pinnedRows.setAttribute('aria-live', 'polite');\n\n const left = document.createElement('div');\n left.className = 'tbw-pinned-rows-left';\n\n const center = document.createElement('div');\n center.className = 'tbw-pinned-rows-center';\n\n const right = document.createElement('div');\n right.className = 'tbw-pinned-rows-right';\n\n // Default panels - row count\n if (config.showRowCount !== false) {\n const rowCount = document.createElement('span');\n rowCount.className = 'tbw-status-panel tbw-status-panel-row-count';\n rowCount.textContent = `Total: ${context.totalRows} rows`;\n left.appendChild(rowCount);\n }\n\n // Filtered count panel (only shows when filter is active)\n if (config.showFilteredCount && context.filteredRows !== context.totalRows) {\n const filteredCount = document.createElement('span');\n filteredCount.className = 'tbw-status-panel tbw-status-panel-filtered-count';\n filteredCount.textContent = `Filtered: ${context.filteredRows}`;\n left.appendChild(filteredCount);\n }\n\n // Selected count panel (only shows when rows are selected)\n if (config.showSelectedCount && context.selectedRows > 0) {\n const selectedCount = document.createElement('span');\n selectedCount.className = 'tbw-status-panel tbw-status-panel-selected-count';\n selectedCount.textContent = `Selected: ${context.selectedRows}`;\n right.appendChild(selectedCount);\n }\n\n // Render custom panels\n if (config.customPanels) {\n for (const panel of config.customPanels) {\n const panelEl = renderCustomPanel(panel, context);\n switch (panel.position) {\n case 'left':\n left.appendChild(panelEl);\n break;\n case 'center':\n center.appendChild(panelEl);\n break;\n case 'right':\n right.appendChild(panelEl);\n break;\n }\n }\n }\n\n pinnedRows.appendChild(left);\n pinnedRows.appendChild(center);\n pinnedRows.appendChild(right);\n\n return pinnedRows;\n}\n\n/**\n * Creates a container for aggregation rows at top or bottom.\n *\n * @param position - 'top' or 'bottom'\n * @returns The container element\n */\nexport function createAggregationContainer(position: 'top' | 'bottom'): HTMLElement {\n const container = document.createElement('div');\n container.className = `tbw-aggregation-rows tbw-aggregation-rows-${position}`;\n // Use presentation role since aggregation rows are outside the role=\"grid\" element for layout reasons\n container.setAttribute('role', 'presentation');\n return container;\n}\n\n/**\n * Renders aggregation rows into a container.\n *\n * @param container - The container to render into\n * @param rows - Aggregation row configurations\n * @param columns - Current column configuration\n * @param dataRows - Current row data for aggregation calculations\n */\nexport function renderAggregationRows(\n container: HTMLElement,\n rows: AggregationRowConfig[],\n columns: ColumnConfig[],\n dataRows: unknown[],\n): void {\n container.innerHTML = '';\n\n for (const rowConfig of rows) {\n const rowEl = document.createElement('div');\n rowEl.className = 'tbw-aggregation-row';\n // Use presentation role since aggregation rows are outside the role=\"grid\" element\n rowEl.setAttribute('role', 'presentation');\n if (rowConfig.id) {\n rowEl.setAttribute('data-aggregation-id', rowConfig.id);\n }\n\n if (rowConfig.fullWidth) {\n // Full-width mode: single cell spanning all columns\n const cell = document.createElement('div');\n cell.className = 'tbw-aggregation-cell tbw-aggregation-cell-full';\n cell.style.gridColumn = '1 / -1';\n cell.textContent = rowConfig.label || '';\n rowEl.appendChild(cell);\n } else {\n // Per-column mode: one cell per column with aggregated/static values\n for (const col of columns) {\n const cell = document.createElement('div');\n cell.className = 'tbw-aggregation-cell';\n cell.setAttribute('data-field', col.field);\n\n let value: unknown;\n\n // Check for aggregator first\n const aggRef = rowConfig.aggregators?.[col.field];\n if (aggRef) {\n const aggFn = getAggregator(aggRef);\n if (aggFn) {\n value = aggFn(dataRows, col.field, col);\n }\n } else if (rowConfig.cells && Object.prototype.hasOwnProperty.call(rowConfig.cells, col.field)) {\n // Static or computed cell value\n const staticVal = rowConfig.cells[col.field];\n if (typeof staticVal === 'function') {\n value = staticVal(dataRows, col.field, col);\n } else {\n value = staticVal;\n }\n }\n\n cell.textContent = value != null ? String(value) : '';\n rowEl.appendChild(cell);\n }\n }\n\n container.appendChild(rowEl);\n }\n}\n\n/**\n * Renders a custom panel element.\n *\n * @param panel - The panel definition\n * @param context - The current grid context\n * @returns The panel DOM element\n */\nfunction renderCustomPanel(panel: PinnedRowsPanel, context: PinnedRowsContext): HTMLElement {\n const panelEl = document.createElement('div');\n panelEl.className = 'tbw-status-panel tbw-status-panel-custom';\n panelEl.id = `status-panel-${panel.id}`;\n\n const content = panel.render(context);\n\n if (typeof content === 'string') {\n panelEl.innerHTML = content;\n } else {\n panelEl.appendChild(content);\n }\n\n return panelEl;\n}\n\n/**\n * Builds the status bar context from grid state and plugin states.\n *\n * @param rows - Current row data\n * @param columns - Current column configuration\n * @param grid - Grid element reference\n * @param selectionState - Optional selection plugin state\n * @param filterState - Optional filtering plugin state\n * @returns The status bar context\n */\nexport function buildContext(\n rows: unknown[],\n columns: unknown[],\n grid: HTMLElement,\n selectionState?: { selected: Set<number> } | null,\n filterState?: { cachedResult: unknown[] | null } | null,\n): PinnedRowsContext {\n return {\n totalRows: rows.length,\n filteredRows: filterState?.cachedResult?.length ?? rows.length,\n selectedRows: selectionState?.selected?.size ?? 0,\n columns: columns as PinnedRowsContext['columns'],\n rows,\n grid,\n };\n}\n\n// Keep old name as alias for backwards compatibility\nexport const createPinnedRowsElement = createInfoBarElement;\n","/**\n * Pinned Rows Plugin (Class-based)\n *\n * Adds info bars and aggregation rows to the grid.\n * - Info bar: Shows row counts, selection info, and custom panels\n * - Aggregation rows: Footer/header rows with computed values (sum, avg, etc.)\n */\n\nimport { BaseGridPlugin } from '../../core/plugin/base-plugin';\nimport type { ColumnConfig } from '../../core/types';\nimport { buildContext, createAggregationContainer, createInfoBarElement, renderAggregationRows } from './pinned-rows';\nimport styles from './pinned-rows.css?inline';\nimport type { AggregationRowConfig, PinnedRowsConfig, PinnedRowsContext, PinnedRowsPanel } from './types';\n\n/**\n * Pinned Rows Plugin for tbw-grid\n *\n * @example\n * ```ts\n * new PinnedRowsPlugin({\n * enabled: true,\n * position: 'bottom',\n * showRowCount: true,\n * showSelectedCount: true,\n * aggregationRows: [\n * { id: 'totals', position: 'bottom', values: { amount: 'sum' } },\n * ],\n * })\n * ```\n */\nexport class PinnedRowsPlugin extends BaseGridPlugin<PinnedRowsConfig> {\n readonly name = 'pinnedRows';\n override readonly version = '1.0.0';\n\n protected override get defaultConfig(): Partial<PinnedRowsConfig> {\n return {\n position: 'bottom',\n showRowCount: true,\n showSelectedCount: true,\n showFilteredCount: true,\n };\n }\n\n // #region Internal State\n private infoBarElement: HTMLElement | null = null;\n private topAggregationContainer: HTMLElement | null = null;\n private bottomAggregationContainer: HTMLElement | null = null;\n private footerWrapper: HTMLElement | null = null;\n // #endregion\n\n // #region Lifecycle\n override detach(): void {\n if (this.infoBarElement) {\n this.infoBarElement.remove();\n this.infoBarElement = null;\n }\n if (this.topAggregationContainer) {\n this.topAggregationContainer.remove();\n this.topAggregationContainer = null;\n }\n if (this.bottomAggregationContainer) {\n this.bottomAggregationContainer.remove();\n this.bottomAggregationContainer = null;\n }\n if (this.footerWrapper) {\n this.footerWrapper.remove();\n this.footerWrapper = null;\n }\n }\n // #endregion\n\n // #region Hooks\n override afterRender(): void {\n const shadowRoot = this.shadowRoot;\n if (!shadowRoot) return;\n\n // Use .tbw-scroll-area so footer is inside the horizontal scroll area,\n // otherwise fall back to .tbw-grid-content or root container\n const container =\n shadowRoot.querySelector('.tbw-scroll-area') ??\n shadowRoot.querySelector('.tbw-grid-content') ??\n shadowRoot.children[0];\n if (!container) return;\n\n // Build context with plugin states\n const selectionState = this.getSelectionState();\n const filterState = this.getFilterState();\n\n const context = buildContext(\n this.rows as unknown[],\n this.columns as unknown[],\n this.grid as unknown as HTMLElement,\n selectionState,\n filterState,\n );\n\n // #region Handle Aggregation Rows\n const aggregationRows = this.config.aggregationRows || [];\n const topRows = aggregationRows.filter((r) => r.position === 'top');\n const bottomRows = aggregationRows.filter((r) => r.position !== 'top');\n\n // Top aggregation rows\n if (topRows.length > 0) {\n if (!this.topAggregationContainer) {\n this.topAggregationContainer = createAggregationContainer('top');\n const header = shadowRoot.querySelector('.header');\n if (header && header.nextSibling) {\n container.insertBefore(this.topAggregationContainer, header.nextSibling);\n } else {\n container.appendChild(this.topAggregationContainer);\n }\n }\n renderAggregationRows(\n this.topAggregationContainer,\n topRows,\n this.visibleColumns as ColumnConfig[],\n this.rows as unknown[],\n );\n } else if (this.topAggregationContainer) {\n this.topAggregationContainer.remove();\n this.topAggregationContainer = null;\n }\n\n // Handle footer\n const hasInfoContent =\n this.config.showRowCount !== false ||\n (this.config.showSelectedCount && context.selectedRows > 0) ||\n (this.config.showFilteredCount && context.filteredRows !== context.totalRows) ||\n (this.config.customPanels && this.config.customPanels.length > 0);\n const hasBottomInfoBar = hasInfoContent && this.config.position !== 'top';\n const needsFooter = bottomRows.length > 0 || hasBottomInfoBar;\n\n // Handle top info bar\n if (hasInfoContent && this.config.position === 'top') {\n if (!this.infoBarElement) {\n this.infoBarElement = createInfoBarElement(this.config, context);\n container.insertBefore(this.infoBarElement, container.firstChild);\n } else {\n const newInfoBar = createInfoBarElement(this.config, context);\n this.infoBarElement.replaceWith(newInfoBar);\n this.infoBarElement = newInfoBar;\n }\n } else if (this.config.position === 'top' && this.infoBarElement) {\n this.infoBarElement.remove();\n this.infoBarElement = null;\n }\n\n // Create/manage footer wrapper\n if (needsFooter) {\n if (!this.footerWrapper) {\n this.footerWrapper = document.createElement('div');\n this.footerWrapper.className = 'tbw-footer';\n container.appendChild(this.footerWrapper);\n }\n\n this.footerWrapper.innerHTML = '';\n\n if (bottomRows.length > 0) {\n if (!this.bottomAggregationContainer) {\n this.bottomAggregationContainer = createAggregationContainer('bottom');\n }\n this.footerWrapper.appendChild(this.bottomAggregationContainer);\n renderAggregationRows(\n this.bottomAggregationContainer,\n bottomRows,\n this.visibleColumns as ColumnConfig[],\n this.rows as unknown[],\n );\n }\n\n if (hasBottomInfoBar) {\n this.infoBarElement = createInfoBarElement(this.config, context);\n this.footerWrapper.appendChild(this.infoBarElement);\n }\n } else {\n this.cleanupFooter();\n }\n // #endregion\n }\n // #endregion\n\n // #region Private Methods\n private cleanup(): void {\n if (this.infoBarElement) {\n this.infoBarElement.remove();\n this.infoBarElement = null;\n }\n if (this.topAggregationContainer) {\n this.topAggregationContainer.remove();\n this.topAggregationContainer = null;\n }\n if (this.bottomAggregationContainer) {\n this.bottomAggregationContainer.remove();\n this.bottomAggregationContainer = null;\n }\n if (this.footerWrapper) {\n this.footerWrapper.remove();\n this.footerWrapper = null;\n }\n }\n\n private cleanupFooter(): void {\n if (this.footerWrapper) {\n this.footerWrapper.remove();\n this.footerWrapper = null;\n }\n if (this.bottomAggregationContainer) {\n this.bottomAggregationContainer.remove();\n this.bottomAggregationContainer = null;\n }\n if (this.infoBarElement && this.config.position !== 'top') {\n this.infoBarElement.remove();\n this.infoBarElement = null;\n }\n }\n\n private getSelectionState(): { selected: Set<number> } | null {\n // Try to get selection plugin state\n try {\n const grid = this.grid as any;\n return grid?.getPluginState?.('selection') ?? null;\n } catch {\n return null;\n }\n }\n\n private getFilterState(): { cachedResult: unknown[] | null } | null {\n try {\n const grid = this.grid as any;\n return grid?.getPluginState?.('filtering') ?? null;\n } catch {\n return null;\n }\n }\n // #endregion\n\n // #region Public API\n /**\n * Refresh the status bar to reflect current grid state.\n */\n refresh(): void {\n this.requestRender();\n }\n\n /**\n * Get the current status bar context.\n * @returns The context with row counts and other info\n */\n getContext(): PinnedRowsContext {\n const selectionState = this.getSelectionState();\n const filterState = this.getFilterState();\n\n return buildContext(\n this.rows as unknown[],\n this.columns as unknown[],\n this.grid as unknown as HTMLElement,\n selectionState,\n filterState,\n );\n }\n\n /**\n * Add a custom panel to the info bar.\n * @param panel - The panel configuration to add\n */\n addPanel(panel: PinnedRowsPanel): void {\n if (!this.config.customPanels) {\n this.config.customPanels = [];\n }\n this.config.customPanels.push(panel);\n this.requestRender();\n }\n\n /**\n * Remove a custom panel by ID.\n * @param id - The panel ID to remove\n */\n removePanel(id: string): void {\n if (this.config.customPanels) {\n this.config.customPanels = this.config.customPanels.filter((p) => p.id !== id);\n this.requestRender();\n }\n }\n\n /**\n * Add an aggregation row.\n * @param row - The aggregation row configuration\n */\n addAggregationRow(row: AggregationRowConfig): void {\n if (!this.config.aggregationRows) {\n this.config.aggregationRows = [];\n }\n this.config.aggregationRows.push(row);\n this.requestRender();\n }\n\n /**\n * Remove an aggregation row by ID.\n * @param id - The aggregation row ID to remove\n */\n removeAggregationRow(id: string): void {\n if (this.config.aggregationRows) {\n this.config.aggregationRows = this.config.aggregationRows.filter((r) => r.id !== id);\n this.requestRender();\n }\n }\n // #endregion\n\n // #region Styles\n override readonly styles = styles;\n // #endregion\n}\n"],"names":["createInfoBarElement","config","context","pinnedRows","left","center","right","rowCount","filteredCount","selectedCount","panel","panelEl","renderCustomPanel","createAggregationContainer","position","container","renderAggregationRows","rows","columns","dataRows","rowConfig","rowEl","cell","col","value","aggRef","aggFn","getAggregator","staticVal","content","buildContext","grid","selectionState","filterState","PinnedRowsPlugin","BaseGridPlugin","shadowRoot","aggregationRows","topRows","r","bottomRows","header","hasInfoContent","hasBottomInfoBar","needsFooter","newInfoBar","id","p","row","styles"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pinned-rows.umd.js","sources":["../../../../../libs/grid/src/lib/plugins/pinned-rows/pinned-rows.ts","../../../../../libs/grid/src/lib/plugins/pinned-rows/PinnedRowsPlugin.ts"],"sourcesContent":["/**\n * Status Bar Rendering Logic\n *\n * Pure functions for creating and updating the status bar UI.\n * Includes both info bar and aggregation row rendering.\n */\n\nimport { getAggregator } from '../../core/internal/aggregators';\nimport type { ColumnConfig } from '../../core/types';\nimport type {\n AggregationRowConfig,\n AggregatorConfig,\n AggregatorDefinition,\n PinnedRowsConfig,\n PinnedRowsContext,\n PinnedRowsPanel,\n} from './types';\n\n/**\n * Check if an aggregator definition is a full config object (with aggFunc and optional formatter).\n */\nfunction isAggregatorConfig(def: AggregatorDefinition): def is AggregatorConfig {\n return typeof def === 'object' && def !== null && 'aggFunc' in def;\n}\n\n/**\n * Creates the info bar DOM element with all configured panels.\n *\n * @param config - The status bar configuration\n * @param context - The current grid context for rendering\n * @returns The complete info bar element\n */\nexport function createInfoBarElement(config: PinnedRowsConfig, context: PinnedRowsContext): HTMLElement {\n const pinnedRows = document.createElement('div');\n pinnedRows.className = 'tbw-pinned-rows';\n pinnedRows.setAttribute('role', 'presentation');\n pinnedRows.setAttribute('aria-live', 'polite');\n\n const left = document.createElement('div');\n left.className = 'tbw-pinned-rows-left';\n\n const center = document.createElement('div');\n center.className = 'tbw-pinned-rows-center';\n\n const right = document.createElement('div');\n right.className = 'tbw-pinned-rows-right';\n\n // Default panels - row count\n if (config.showRowCount !== false) {\n const rowCount = document.createElement('span');\n rowCount.className = 'tbw-status-panel tbw-status-panel-row-count';\n rowCount.textContent = `Total: ${context.totalRows} rows`;\n left.appendChild(rowCount);\n }\n\n // Filtered count panel (only shows when filter is active)\n if (config.showFilteredCount && context.filteredRows !== context.totalRows) {\n const filteredCount = document.createElement('span');\n filteredCount.className = 'tbw-status-panel tbw-status-panel-filtered-count';\n filteredCount.textContent = `Filtered: ${context.filteredRows}`;\n left.appendChild(filteredCount);\n }\n\n // Selected count panel (only shows when rows are selected)\n if (config.showSelectedCount && context.selectedRows > 0) {\n const selectedCount = document.createElement('span');\n selectedCount.className = 'tbw-status-panel tbw-status-panel-selected-count';\n selectedCount.textContent = `Selected: ${context.selectedRows}`;\n right.appendChild(selectedCount);\n }\n\n // Render custom panels\n if (config.customPanels) {\n for (const panel of config.customPanels) {\n const panelEl = renderCustomPanel(panel, context);\n switch (panel.position) {\n case 'left':\n left.appendChild(panelEl);\n break;\n case 'center':\n center.appendChild(panelEl);\n break;\n case 'right':\n right.appendChild(panelEl);\n break;\n }\n }\n }\n\n pinnedRows.appendChild(left);\n pinnedRows.appendChild(center);\n pinnedRows.appendChild(right);\n\n return pinnedRows;\n}\n\n/**\n * Creates a container for aggregation rows at top or bottom.\n *\n * @param position - 'top' or 'bottom'\n * @returns The container element\n */\nexport function createAggregationContainer(position: 'top' | 'bottom'): HTMLElement {\n const container = document.createElement('div');\n container.className = `tbw-aggregation-rows tbw-aggregation-rows-${position}`;\n // Use presentation role since aggregation rows are outside the role=\"grid\" element for layout reasons\n container.setAttribute('role', 'presentation');\n return container;\n}\n\n/**\n * Renders aggregation rows into a container.\n *\n * @param container - The container to render into\n * @param rows - Aggregation row configurations\n * @param columns - Current column configuration\n * @param dataRows - Current row data for aggregation calculations\n */\nexport function renderAggregationRows(\n container: HTMLElement,\n rows: AggregationRowConfig[],\n columns: ColumnConfig[],\n dataRows: unknown[],\n): void {\n container.innerHTML = '';\n\n for (const rowConfig of rows) {\n const rowEl = document.createElement('div');\n rowEl.className = 'tbw-aggregation-row';\n // Use presentation role since aggregation rows are outside the role=\"grid\" element\n rowEl.setAttribute('role', 'presentation');\n if (rowConfig.id) {\n rowEl.setAttribute('data-aggregation-id', rowConfig.id);\n }\n\n if (rowConfig.fullWidth) {\n // Full-width mode: single cell spanning all columns\n const cell = document.createElement('div');\n cell.className = 'tbw-aggregation-cell tbw-aggregation-cell-full';\n cell.style.gridColumn = '1 / -1';\n cell.textContent = rowConfig.label || '';\n rowEl.appendChild(cell);\n } else {\n // Per-column mode: one cell per column with aggregated/static values\n for (const col of columns) {\n const cell = document.createElement('div');\n cell.className = 'tbw-aggregation-cell';\n cell.setAttribute('data-field', col.field);\n\n let value: unknown;\n let formatter: ((value: unknown, field: string, column?: ColumnConfig) => string) | undefined;\n\n // Check for aggregator first\n const aggDef = rowConfig.aggregators?.[col.field];\n if (aggDef) {\n // Handle both simple ref and full config object\n if (isAggregatorConfig(aggDef)) {\n const aggFn = getAggregator(aggDef.aggFunc);\n if (aggFn) {\n value = aggFn(dataRows, col.field, col);\n }\n formatter = aggDef.formatter;\n } else {\n const aggFn = getAggregator(aggDef);\n if (aggFn) {\n value = aggFn(dataRows, col.field, col);\n }\n }\n } else if (rowConfig.cells && Object.prototype.hasOwnProperty.call(rowConfig.cells, col.field)) {\n // Static or computed cell value\n const staticVal = rowConfig.cells[col.field];\n if (typeof staticVal === 'function') {\n value = staticVal(dataRows, col.field, col);\n } else {\n value = staticVal;\n }\n }\n\n // Apply formatter if provided, otherwise convert to string\n if (value != null) {\n cell.textContent = formatter ? formatter(value, col.field, col) : String(value);\n } else {\n cell.textContent = '';\n }\n rowEl.appendChild(cell);\n }\n }\n\n container.appendChild(rowEl);\n }\n}\n\n/**\n * Renders a custom panel element.\n *\n * @param panel - The panel definition\n * @param context - The current grid context\n * @returns The panel DOM element\n */\nfunction renderCustomPanel(panel: PinnedRowsPanel, context: PinnedRowsContext): HTMLElement {\n const panelEl = document.createElement('div');\n panelEl.className = 'tbw-status-panel tbw-status-panel-custom';\n panelEl.id = `status-panel-${panel.id}`;\n\n const content = panel.render(context);\n\n if (typeof content === 'string') {\n panelEl.innerHTML = content;\n } else {\n panelEl.appendChild(content);\n }\n\n return panelEl;\n}\n\n/**\n * Builds the status bar context from grid state and plugin states.\n *\n * @param rows - Current row data\n * @param columns - Current column configuration\n * @param grid - Grid element reference\n * @param selectionState - Optional selection plugin state\n * @param filterState - Optional filtering plugin state\n * @returns The status bar context\n */\nexport function buildContext(\n rows: unknown[],\n columns: unknown[],\n grid: HTMLElement,\n selectionState?: { selected: Set<number> } | null,\n filterState?: { cachedResult: unknown[] | null } | null,\n): PinnedRowsContext {\n return {\n totalRows: rows.length,\n filteredRows: filterState?.cachedResult?.length ?? rows.length,\n selectedRows: selectionState?.selected?.size ?? 0,\n columns: columns as PinnedRowsContext['columns'],\n rows,\n grid,\n };\n}\n\n// Keep old name as alias for backwards compatibility\nexport const createPinnedRowsElement = createInfoBarElement;\n","/**\n * Pinned Rows Plugin (Class-based)\n *\n * Adds info bars and aggregation rows to the grid.\n * - Info bar: Shows row counts, selection info, and custom panels\n * - Aggregation rows: Footer/header rows with computed values (sum, avg, etc.)\n */\n\nimport { BaseGridPlugin } from '../../core/plugin/base-plugin';\nimport type { ColumnConfig } from '../../core/types';\nimport { buildContext, createAggregationContainer, createInfoBarElement, renderAggregationRows } from './pinned-rows';\nimport styles from './pinned-rows.css?inline';\nimport type { AggregationRowConfig, PinnedRowsConfig, PinnedRowsContext, PinnedRowsPanel } from './types';\n\n/**\n * Pinned Rows Plugin for tbw-grid\n *\n * @example\n * ```ts\n * new PinnedRowsPlugin({\n * enabled: true,\n * position: 'bottom',\n * showRowCount: true,\n * showSelectedCount: true,\n * aggregationRows: [\n * { id: 'totals', position: 'bottom', values: { amount: 'sum' } },\n * ],\n * })\n * ```\n */\nexport class PinnedRowsPlugin extends BaseGridPlugin<PinnedRowsConfig> {\n readonly name = 'pinnedRows';\n override readonly version = '1.0.0';\n\n protected override get defaultConfig(): Partial<PinnedRowsConfig> {\n return {\n position: 'bottom',\n showRowCount: true,\n showSelectedCount: true,\n showFilteredCount: true,\n };\n }\n\n // #region Internal State\n private infoBarElement: HTMLElement | null = null;\n private topAggregationContainer: HTMLElement | null = null;\n private bottomAggregationContainer: HTMLElement | null = null;\n private footerWrapper: HTMLElement | null = null;\n // #endregion\n\n // #region Lifecycle\n override detach(): void {\n if (this.infoBarElement) {\n this.infoBarElement.remove();\n this.infoBarElement = null;\n }\n if (this.topAggregationContainer) {\n this.topAggregationContainer.remove();\n this.topAggregationContainer = null;\n }\n if (this.bottomAggregationContainer) {\n this.bottomAggregationContainer.remove();\n this.bottomAggregationContainer = null;\n }\n if (this.footerWrapper) {\n this.footerWrapper.remove();\n this.footerWrapper = null;\n }\n }\n // #endregion\n\n // #region Hooks\n override afterRender(): void {\n const shadowRoot = this.shadowRoot;\n if (!shadowRoot) return;\n\n // Use .tbw-scroll-area so footer is inside the horizontal scroll area,\n // otherwise fall back to .tbw-grid-content or root container\n const container =\n shadowRoot.querySelector('.tbw-scroll-area') ??\n shadowRoot.querySelector('.tbw-grid-content') ??\n shadowRoot.children[0];\n if (!container) return;\n\n // Build context with plugin states\n const selectionState = this.getSelectionState();\n const filterState = this.getFilterState();\n\n const context = buildContext(\n this.rows as unknown[],\n this.columns as unknown[],\n this.grid as unknown as HTMLElement,\n selectionState,\n filterState,\n );\n\n // #region Handle Aggregation Rows\n const aggregationRows = this.config.aggregationRows || [];\n const topRows = aggregationRows.filter((r) => r.position === 'top');\n const bottomRows = aggregationRows.filter((r) => r.position !== 'top');\n\n // Top aggregation rows\n if (topRows.length > 0) {\n if (!this.topAggregationContainer) {\n this.topAggregationContainer = createAggregationContainer('top');\n const header = shadowRoot.querySelector('.header');\n if (header && header.nextSibling) {\n container.insertBefore(this.topAggregationContainer, header.nextSibling);\n } else {\n container.appendChild(this.topAggregationContainer);\n }\n }\n renderAggregationRows(\n this.topAggregationContainer,\n topRows,\n this.visibleColumns as ColumnConfig[],\n this.rows as unknown[],\n );\n } else if (this.topAggregationContainer) {\n this.topAggregationContainer.remove();\n this.topAggregationContainer = null;\n }\n\n // Handle footer\n const hasInfoContent =\n this.config.showRowCount !== false ||\n (this.config.showSelectedCount && context.selectedRows > 0) ||\n (this.config.showFilteredCount && context.filteredRows !== context.totalRows) ||\n (this.config.customPanels && this.config.customPanels.length > 0);\n const hasBottomInfoBar = hasInfoContent && this.config.position !== 'top';\n const needsFooter = bottomRows.length > 0 || hasBottomInfoBar;\n\n // Handle top info bar\n if (hasInfoContent && this.config.position === 'top') {\n if (!this.infoBarElement) {\n this.infoBarElement = createInfoBarElement(this.config, context);\n container.insertBefore(this.infoBarElement, container.firstChild);\n } else {\n const newInfoBar = createInfoBarElement(this.config, context);\n this.infoBarElement.replaceWith(newInfoBar);\n this.infoBarElement = newInfoBar;\n }\n } else if (this.config.position === 'top' && this.infoBarElement) {\n this.infoBarElement.remove();\n this.infoBarElement = null;\n }\n\n // Create/manage footer wrapper\n if (needsFooter) {\n if (!this.footerWrapper) {\n this.footerWrapper = document.createElement('div');\n this.footerWrapper.className = 'tbw-footer';\n container.appendChild(this.footerWrapper);\n }\n\n this.footerWrapper.innerHTML = '';\n\n if (bottomRows.length > 0) {\n if (!this.bottomAggregationContainer) {\n this.bottomAggregationContainer = createAggregationContainer('bottom');\n }\n this.footerWrapper.appendChild(this.bottomAggregationContainer);\n renderAggregationRows(\n this.bottomAggregationContainer,\n bottomRows,\n this.visibleColumns as ColumnConfig[],\n this.rows as unknown[],\n );\n }\n\n if (hasBottomInfoBar) {\n this.infoBarElement = createInfoBarElement(this.config, context);\n this.footerWrapper.appendChild(this.infoBarElement);\n }\n } else {\n this.cleanupFooter();\n }\n // #endregion\n }\n // #endregion\n\n // #region Private Methods\n private cleanup(): void {\n if (this.infoBarElement) {\n this.infoBarElement.remove();\n this.infoBarElement = null;\n }\n if (this.topAggregationContainer) {\n this.topAggregationContainer.remove();\n this.topAggregationContainer = null;\n }\n if (this.bottomAggregationContainer) {\n this.bottomAggregationContainer.remove();\n this.bottomAggregationContainer = null;\n }\n if (this.footerWrapper) {\n this.footerWrapper.remove();\n this.footerWrapper = null;\n }\n }\n\n private cleanupFooter(): void {\n if (this.footerWrapper) {\n this.footerWrapper.remove();\n this.footerWrapper = null;\n }\n if (this.bottomAggregationContainer) {\n this.bottomAggregationContainer.remove();\n this.bottomAggregationContainer = null;\n }\n if (this.infoBarElement && this.config.position !== 'top') {\n this.infoBarElement.remove();\n this.infoBarElement = null;\n }\n }\n\n private getSelectionState(): { selected: Set<number> } | null {\n // Try to get selection plugin state\n try {\n const grid = this.grid as any;\n return grid?.getPluginState?.('selection') ?? null;\n } catch {\n return null;\n }\n }\n\n private getFilterState(): { cachedResult: unknown[] | null } | null {\n try {\n const grid = this.grid as any;\n return grid?.getPluginState?.('filtering') ?? null;\n } catch {\n return null;\n }\n }\n // #endregion\n\n // #region Public API\n /**\n * Refresh the status bar to reflect current grid state.\n */\n refresh(): void {\n this.requestRender();\n }\n\n /**\n * Get the current status bar context.\n * @returns The context with row counts and other info\n */\n getContext(): PinnedRowsContext {\n const selectionState = this.getSelectionState();\n const filterState = this.getFilterState();\n\n return buildContext(\n this.rows as unknown[],\n this.columns as unknown[],\n this.grid as unknown as HTMLElement,\n selectionState,\n filterState,\n );\n }\n\n /**\n * Add a custom panel to the info bar.\n * @param panel - The panel configuration to add\n */\n addPanel(panel: PinnedRowsPanel): void {\n if (!this.config.customPanels) {\n this.config.customPanels = [];\n }\n this.config.customPanels.push(panel);\n this.requestRender();\n }\n\n /**\n * Remove a custom panel by ID.\n * @param id - The panel ID to remove\n */\n removePanel(id: string): void {\n if (this.config.customPanels) {\n this.config.customPanels = this.config.customPanels.filter((p) => p.id !== id);\n this.requestRender();\n }\n }\n\n /**\n * Add an aggregation row.\n * @param row - The aggregation row configuration\n */\n addAggregationRow(row: AggregationRowConfig): void {\n if (!this.config.aggregationRows) {\n this.config.aggregationRows = [];\n }\n this.config.aggregationRows.push(row);\n this.requestRender();\n }\n\n /**\n * Remove an aggregation row by ID.\n * @param id - The aggregation row ID to remove\n */\n removeAggregationRow(id: string): void {\n if (this.config.aggregationRows) {\n this.config.aggregationRows = this.config.aggregationRows.filter((r) => r.id !== id);\n this.requestRender();\n }\n }\n // #endregion\n\n // #region Styles\n override readonly styles = styles;\n // #endregion\n}\n"],"names":["isAggregatorConfig","def","createInfoBarElement","config","context","pinnedRows","left","center","right","rowCount","filteredCount","selectedCount","panel","panelEl","renderCustomPanel","createAggregationContainer","position","container","renderAggregationRows","rows","columns","dataRows","rowConfig","rowEl","cell","col","value","formatter","aggDef","aggFn","getAggregator","staticVal","content","buildContext","grid","selectionState","filterState","PinnedRowsPlugin","BaseGridPlugin","shadowRoot","aggregationRows","topRows","r","bottomRows","header","hasInfoContent","hasBottomInfoBar","needsFooter","newInfoBar","id","p","row","styles"],"mappings":"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"}
|
package/umd/plugins/pivot.umd.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(h,f){typeof exports=="object"&&typeof module<"u"?f(exports,require("../../core/plugin/base-plugin"),require("../../core/internal/aggregators")):typeof define=="function"&&define.amd?define(["exports","../../core/plugin/base-plugin","../../core/internal/aggregators"],f):(h=typeof globalThis<"u"?globalThis:h||self,f(h.TbwGridPlugin_pivot={},h.TbwGrid,h.TbwGrid))})(this,(function(h,f,_){"use strict";const L=_.getValueAggregator;function P(a){const e=[];return!a.rowGroupFields?.length&&!a.columnGroupFields?.length&&e.push("At least one row or column group field is required"),a.valueFields?.length||e.push("At least one value field is required"),e}function w(a,e){return[...a,e].join("|")}function E(a,e){const n=e.rowGroupFields??[],o=e.columnGroupFields??[],i=e.valueFields??[],t=k(a,o),r=C(a,n,o,t,i,0,""),l=K(r,t,i),s=Object.values(l).reduce((d,c)=>d+c,0);return{rows:r,columnKeys:t,totals:l,grandTotal:s}}function k(a,e){if(e.length===0)return["value"];const n=new Set;for(const o of a){const i=e.map(t=>String(o[t]??"")).join("|");n.add(i)}return[...n].sort()}function N(a,e){const n=new Map;for(const o of a){const i=String(o[e]??""),t=n.get(i);t?t.push(o):n.set(i,[o])}return n}function C(a,e,n,o,i,t,r){const l=[];if(e.length===0){const u=F(a,n,o,i),v=y(u);return l.push({rowKey:r||"all",rowLabel:r||"All",depth:t,values:u,total:v,isGroup:!1,rowCount:a.length}),l}const s=e[0],d=e.slice(1),c=d.length>0,p=N(a,s);for(const[u,v]of p){const A=r?`${r}|${u}`:u,G=F(v,n,o,i),B=y(G);let T;c&&(T=C(v,d,n,o,i,t+1,A)),l.push({rowKey:A,rowLabel:u||"(blank)",depth:t,values:G,total:B,isGroup:c,children:T,rowCount:v.length})}return l}function F(a,e,n,o){const i={};for(const t of n)for(const r of o){const s=(e.length>0?a.filter(u=>e.map(v=>String(u[v]??"")).join("|")===t):a).map(u=>Number(u[r.field])||0),d=L(r.aggFunc),c=s.length>0?d(s):null,p=w([t],r.field);i[p]=c}return i}function y(a){let e=0;for(const n of Object.values(a))e+=n??0;return e}function K(a,e,n){const o={};function i(t){for(const r of t)if(!r.isGroup||!r.children?.length)for(const l of e)for(const s of n){const d=w([l],s.field);o[d]=(o[d]??0)+(r.values[d]??0)}else r.children&&i(r.children)}return i(a),o}function S(a,e,n=!0){const o=[];function i(t){o.push(t);const r=e?e.has(t.rowKey):n;if(t.children&&r)for(const l of t.children)i(l)}for(const t of a)i(t);return o}function m(a){const e=[];function n(o){if(o.isGroup&&e.push(o.rowKey),o.children)for(const i of o.children)n(i)}for(const o of a)n(o);return e}const V=["sum","avg","count","min","max","first","last"];function z(a,e,n,o){const i=new AbortController,t={config:e,callbacks:o,signal:i.signal},r=document.createElement("div");return r.className="tbw-pivot-panel",r.appendChild(b("Options",()=>M(n,t))),r.appendChild(b("Row Groups",()=>R("rowGroups",t))),r.appendChild(b("Column Groups",()=>R("columnGroups",t))),r.appendChild(b("Values",()=>D(t))),r.appendChild(b("Available Fields",()=>q(t))),a.appendChild(r),()=>{i.abort(),r.remove()}}function b(a,e){const n=document.createElement("div");n.className="tbw-pivot-section";const o=document.createElement("div");o.className="tbw-pivot-section-header",o.textContent=a;const i=document.createElement("div");return i.className="tbw-pivot-section-content",i.appendChild(e()),n.appendChild(o),n.appendChild(i),n}function R(a,e){const{config:n,callbacks:o,signal:i}=e,t=document.createElement("div");t.className="tbw-pivot-drop-zone",t.setAttribute("data-zone",a);const r=a==="rowGroups"?n.rowGroupFields??[]:n.columnGroupFields??[];if(r.length===0){const l=document.createElement("div");l.className="tbw-pivot-placeholder",l.textContent="Drag fields here or click to add",t.appendChild(l)}else for(const l of r)t.appendChild(I(l,a,e));return t.addEventListener("dragover",l=>{l.preventDefault(),t.classList.add("drag-over")},{signal:i}),t.addEventListener("dragleave",()=>{t.classList.remove("drag-over")},{signal:i}),t.addEventListener("drop",l=>{l.preventDefault(),t.classList.remove("drag-over");const s=l.dataTransfer?.getData("text/plain");s&&o.onAddFieldToZone(s,a)},{signal:i}),t}function I(a,e,n){const{callbacks:o,signal:i}=n,t=document.createElement("div");t.className="tbw-pivot-field-chip",t.draggable=!0;const r=o.getAvailableFields().find(d=>d.field===a),l=document.createElement("span");l.className="tbw-pivot-chip-label",l.textContent=r?.header??a;const s=document.createElement("button");return s.className="tbw-pivot-chip-remove",s.innerHTML="×",s.title="Remove field",s.addEventListener("click",d=>{d.stopPropagation(),o.onRemoveFieldFromZone(a,e)},{signal:i}),t.appendChild(l),t.appendChild(s),t.addEventListener("dragstart",d=>{d.dataTransfer?.setData("text/plain",a),d.dataTransfer?.setData("source-zone",e),t.classList.add("dragging")},{signal:i}),t.addEventListener("dragend",()=>{t.classList.remove("dragging")},{signal:i}),t}function D(a){const{config:e,callbacks:n,signal:o}=a,i=document.createElement("div");i.className="tbw-pivot-drop-zone tbw-pivot-values-zone",i.setAttribute("data-zone","values");const t=e.valueFields??[];if(t.length===0){const r=document.createElement("div");r.className="tbw-pivot-placeholder",r.textContent="Drag numeric fields here for aggregation",i.appendChild(r)}else for(const r of t)i.appendChild(H(r,a));return i.addEventListener("dragover",r=>{r.preventDefault(),i.classList.add("drag-over")},{signal:o}),i.addEventListener("dragleave",()=>{i.classList.remove("drag-over")},{signal:o}),i.addEventListener("drop",r=>{r.preventDefault(),i.classList.remove("drag-over");const l=r.dataTransfer?.getData("text/plain");l&&n.onAddValueField(l,"sum")},{signal:o}),i}function H(a,e){const{callbacks:n,signal:o}=e,i=document.createElement("div");i.className="tbw-pivot-field-chip tbw-pivot-value-chip";const t=n.getAvailableFields().find(c=>c.field===a.field),r=document.createElement("div");r.className="tbw-pivot-value-label-wrapper";const l=document.createElement("span");l.className="tbw-pivot-chip-label",l.textContent=t?.header??a.field;const s=document.createElement("select");s.className="tbw-pivot-agg-select",s.title="Aggregation function";for(const c of V){const p=document.createElement("option");p.value=c,p.textContent=c.toUpperCase(),p.selected=c===a.aggFunc,s.appendChild(p)}s.addEventListener("change",()=>{n.onUpdateValueAggFunc(a.field,s.value)},{signal:o});const d=document.createElement("button");return d.className="tbw-pivot-chip-remove",d.innerHTML="×",d.title="Remove value field",d.addEventListener("click",c=>{c.stopPropagation(),n.onRemoveValueField(a.field)},{signal:o}),r.appendChild(l),r.appendChild(s),i.appendChild(r),i.appendChild(d),i}function q(a){const{config:e,callbacks:n,signal:o}=a,i=document.createElement("div");i.className="tbw-pivot-available-fields";const t=n.getAvailableFields(),r=new Set([...e.rowGroupFields??[],...e.columnGroupFields??[],...e.valueFields?.map(s=>s.field)??[]]),l=t.filter(s=>!r.has(s.field));if(l.length===0){const s=document.createElement("div");s.className="tbw-pivot-placeholder",s.textContent="All fields are in use",i.appendChild(s)}else for(const s of l){const d=document.createElement("div");d.className="tbw-pivot-field-chip available",d.textContent=s.header,d.draggable=!0,d.title=`Drag to add "${s.field}" to a zone`,d.addEventListener("dragstart",c=>{c.dataTransfer?.setData("text/plain",s.field),d.classList.add("dragging")},{signal:o}),d.addEventListener("dragend",()=>{d.classList.remove("dragging")},{signal:o}),i.appendChild(d)}return i}function M(a,e){const{config:n,callbacks:o,signal:i}=e,t=document.createElement("div");return t.className="tbw-pivot-options",t.appendChild(x("Enable Pivot View",a,r=>{o.onTogglePivot(r)},i)),t.appendChild(x("Show Row Totals",n.showTotals??!0,r=>{o.onOptionChange("showTotals",r)},i)),t.appendChild(x("Show Grand Total",n.showGrandTotal??!0,r=>{o.onOptionChange("showGrandTotal",r)},i)),t}function x(a,e,n,o){const i=document.createElement("label");i.className="tbw-pivot-checkbox";const t=document.createElement("input");t.type="checkbox",t.checked=e,t.addEventListener("change",()=>n(t.checked),{signal:o});const r=document.createElement("span");return r.textContent=a,i.appendChild(t),i.appendChild(r),i}function O(a,e,n){return e.className="pivot-group-row",e.setAttribute("data-pivot-depth",String(a.__pivotDepth??0)),e.setAttribute("role","row"),e.innerHTML="",n.columns.forEach((o,i)=>{const t=document.createElement("div");if(t.className="cell",t.setAttribute("data-col",String(i)),t.setAttribute("role","gridcell"),i===0){const r=Number(a.__pivotIndent)||0;t.style.paddingLeft=`${r}px`;const l=String(a.__pivotRowKey),s=document.createElement("button");s.type="button",s.className="pivot-toggle",s.setAttribute("aria-label",a.__pivotExpanded?"Collapse group":"Expand group"),n.setIcon(s,n.resolveIcon(a.__pivotExpanded?"collapse":"expand")),s.addEventListener("click",p=>{p.stopPropagation(),n.onToggle(l)}),t.appendChild(s);const d=document.createElement("span");d.className="pivot-label",d.textContent=String(a.__pivotLabel??""),t.appendChild(d);const c=document.createElement("span");c.className="pivot-count",c.textContent=` (${Number(a.__pivotRowCount)||0})`,t.appendChild(c)}else{const r=a[o.field];t.textContent=r!=null?String(r):""}e.appendChild(t)}),!0}function Z(a,e,n){return e.className="pivot-leaf-row",e.setAttribute("data-pivot-depth",String(a.__pivotDepth??0)),e.innerHTML="",n.forEach((o,i)=>{const t=document.createElement("div");if(t.className="cell",t.setAttribute("data-col",String(i)),t.setAttribute("role","gridcell"),i===0){const r=Number(a.__pivotIndent)||0;t.style.paddingLeft=`${r+20}px`;const l=document.createElement("span");l.className="pivot-label",l.textContent=String(a.__pivotLabel??""),t.appendChild(l)}else{const r=a[o.field];t.textContent=r!=null?String(r):""}e.appendChild(t)}),!0}function j(a,e,n){return e.className="pivot-grand-total-row",e.setAttribute("role","presentation"),e.innerHTML="",n.forEach((o,i)=>{const t=document.createElement("div");if(t.className="cell",t.setAttribute("data-col",String(i)),i===0){const r=document.createElement("span");r.className="pivot-label",r.textContent="Grand Total",t.appendChild(r)}else{const r=a[o.field];t.textContent=r!=null?String(r):""}e.appendChild(t)}),!0}const $='.pivot-group-row{display:grid;grid-template-columns:var(--tbw-column-template);font-weight:600;background:var(--tbw-pivot-group-bg, var(--tbw-color-row-alt));min-height:var(--tbw-row-height);border-bottom:var(--tbw-row-divider)}.pivot-group-row:hover{background:var(--tbw-pivot-group-hover, var(--tbw-color-row-hover))}.pivot-leaf-row{display:grid;grid-template-columns:var(--tbw-column-template);background:var(--tbw-pivot-leaf-bg, var(--tbw-color-bg));min-height:var(--tbw-row-height);border-bottom:var(--tbw-row-divider)}.pivot-grand-total-row{display:grid;grid-template-columns:var(--tbw-column-template);font-weight:700;background:var(--tbw-pivot-grand-total-bg, var(--tbw-color-header-bg));min-height:var(--tbw-row-height);border-top:2px solid var(--tbw-color-border-strong)}.pivot-grand-total-row>.cell{display:flex;align-items:center;padding:var(--tbw-cell-padding);border-right:1px solid var(--tbw-color-border-cell);overflow:hidden;min-width:0}.pivot-grand-total-row>.cell:last-child{border-right:0}.pivot-grand-total-footer{position:sticky;bottom:0;z-index:var(--tbw-z-layer-pinned-rows, 20);background:var(--tbw-pivot-grand-total-bg, var(--tbw-color-header-bg));min-width:fit-content}.pivot-group-row>.cell,.pivot-leaf-row>.cell{display:flex;align-items:center;padding:var(--tbw-cell-padding);border-right:1px solid var(--tbw-color-border-cell);overflow:hidden;min-width:0}.pivot-group-row>.cell:last-child,.pivot-leaf-row>.cell:last-child{border-right:0}.pivot-toggle{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;margin-right:6px;border:none;background:transparent;cursor:pointer;font-size:10px;color:var(--tbw-pivot-toggle-color, var(--tbw-color-fg-muted));border-radius:var(--tbw-border-radius);transition:background .15s,color .15s}.pivot-toggle:hover{background:var(--tbw-pivot-toggle-hover-bg, var(--tbw-color-row-hover));color:var(--tbw-pivot-toggle-hover-color, var(--tbw-color-fg))}.pivot-toggle:focus{outline:var(--tbw-focus-outline);outline-offset:var(--tbw-focus-outline-offset)}.pivot-label{font-weight:inherit}.pivot-count{color:var(--tbw-pivot-count-color, var(--tbw-color-fg-muted));font-size:.9em;font-weight:400}.pivot-total-row{font-weight:700;border-top:2px solid var(--tbw-pivot-border, var(--tbw-color-border-strong))}[data-pivot-depth="1"]{--tbw-pivot-depth: 1}[data-pivot-depth="2"]{--tbw-pivot-depth: 2}[data-pivot-depth="3"]{--tbw-pivot-depth: 3}[data-pivot-depth="4"]{--tbw-pivot-depth: 4}.tbw-pivot-panel{display:flex;flex-direction:column;gap:12px;padding:12px;height:100%;overflow-y:auto;font-size:13px}.tbw-pivot-section{border:1px solid var(--tbw-pivot-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius);background:var(--tbw-pivot-section-bg, var(--tbw-color-bg))}.tbw-pivot-section-header{padding:8px 12px;font-weight:600;background:var(--tbw-pivot-header-bg, var(--tbw-color-header-bg));border-bottom:1px solid var(--tbw-pivot-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius) var(--tbw-border-radius) 0 0}.tbw-pivot-section-content{padding:8px}.tbw-pivot-toggle-wrapper{display:flex;align-items:center}.tbw-pivot-toggle-label{display:flex;align-items:center;gap:8px;cursor:pointer}.tbw-pivot-toggle-label input{width:16px;height:16px;cursor:pointer}.tbw-pivot-drop-zone{min-height:60px;padding:8px;border:2px dashed var(--tbw-pivot-drop-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius);background:var(--tbw-pivot-drop-bg, var(--tbw-color-row-alt));display:flex;flex-wrap:wrap;gap:6px;align-content:flex-start;transition:all .15s ease}.tbw-pivot-drop-zone.drag-over{border-color:var(--tbw-color-accent);background:var(--tbw-pivot-drop-active, var(--tbw-focus-background))}.tbw-pivot-placeholder{color:var(--tbw-color-fg-muted);font-style:italic;padding:8px;text-align:center;width:100%}.tbw-pivot-field-chip{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;background:var(--tbw-pivot-chip-bg, var(--tbw-color-header-bg));border:1px solid var(--tbw-pivot-chip-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius);cursor:grab;font-size:12px;transition:all .15s ease}.tbw-pivot-field-chip:hover{background:var(--tbw-pivot-chip-hover, var(--tbw-color-row-hover));border-color:var(--tbw-color-accent)}.tbw-pivot-field-chip.available{background:var(--tbw-color-bg)}.tbw-pivot-field-chip.dragging{opacity:.5;cursor:grabbing}.tbw-pivot-chip-label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:120px}.tbw-pivot-chip-remove{display:flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:transparent;color:var(--tbw-color-fg-muted);font-size:14px;font-weight:700;cursor:pointer;border-radius:50%;transition:all .15s ease}.tbw-pivot-chip-remove:hover{background:var(--tbw-pivot-chip-remove-hover-bg, var(--tbw-color-accent));color:var(--tbw-pivot-chip-remove-hover-fg, var(--tbw-color-accent-fg))}.tbw-pivot-value-chip{padding:4px 8px}.tbw-pivot-value-label-wrapper{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.tbw-pivot-agg-select{padding:2px 4px;font-size:11px;border:1px solid var(--tbw-color-border);border-radius:var(--tbw-border-radius);background:var(--tbw-color-bg);cursor:pointer}.tbw-pivot-available-fields{display:flex;flex-wrap:wrap;gap:6px;min-height:40px}.tbw-pivot-options{display:flex;flex-direction:column;gap:8px}.tbw-pivot-checkbox{display:flex;align-items:center;gap:8px;cursor:pointer}.tbw-pivot-checkbox input{width:14px;height:14px;cursor:pointer}';class g extends f.BaseGridPlugin{name="pivot";version="1.0.0";static PANEL_ID="pivot";get defaultConfig(){return{active:!0,showTotals:!0,showGrandTotal:!0}}isActive=!1;hasInitialized=!1;pivotResult=null;fieldHeaderMap=new Map;expandedKeys=new Set;defaultExpanded=!0;originalColumns=[];panelContainer=null;grandTotalFooter=null;hasValidPivotConfig(){return(this.config.valueFields?.length??0)>0}detach(){this.isActive=!1,this.hasInitialized=!1,this.pivotResult=null,this.fieldHeaderMap.clear(),this.originalColumns=[],this.panelContainer=null,this.cleanupGrandTotalFooter()}getToolPanel(){return{id:g.PANEL_ID,title:"Pivot",icon:"⊞",tooltip:"Configure pivot table",order:90,render:e=>this.renderPanel(e)}}processRows(e){if(!this.hasInitialized&&this.config.active!==!1&&this.hasValidPivotConfig()&&(this.hasInitialized=!0,this.isActive=!0),!this.isActive)return[...e];const n=P(this.config);if(n.length>0)return this.warn(`Config errors: ${n.join(", ")}`),[...e];if(this.buildFieldHeaderMap(),this.defaultExpanded=this.config.defaultExpanded??!0,this.expandedKeys.size===0&&this.defaultExpanded&&this.pivotResult){const t=m(this.pivotResult.rows);for(const r of t)this.expandedKeys.add(r)}if(this.pivotResult=E(e,this.config),this.expandedKeys.size===0&&this.defaultExpanded){const t=m(this.pivotResult.rows);for(const r of t)this.expandedKeys.add(r)}const o=this.config.indentWidth??20;return S(this.pivotResult.rows,this.expandedKeys,this.defaultExpanded).map(t=>({__pivotRowKey:t.rowKey,__pivotLabel:t.rowLabel,__pivotDepth:t.depth,__pivotIsGroup:t.isGroup,__pivotHasChildren:!!t.children?.length,__pivotExpanded:this.expandedKeys.has(t.rowKey),__pivotRowCount:t.rowCount??0,__pivotIndent:t.depth*o,__pivotTotal:t.total,...t.values}))}processColumns(e){if(!this.isActive||!this.pivotResult)return[...e];const n=[],o=(this.config.rowGroupFields??[]).map(i=>this.fieldHeaderMap.get(i)??i).join(" / ");n.push({field:"__pivotLabel",header:o||"Group",width:200});for(const i of this.pivotResult.columnKeys)for(const t of this.config.valueFields??[]){const r=w([i],t.field),l=t.header||this.fieldHeaderMap.get(t.field)||t.field;n.push({field:r,header:`${i} - ${l} (${t.aggFunc})`,width:120,type:"number"})}return this.config.showTotals&&n.push({field:"__pivotTotal",header:"Total",width:100,type:"number"}),n}renderRow(e,n){const o=e;return o.__pivotRowKey&&o.__pivotHasChildren?O(o,n,{columns:this.gridColumns,onToggle:i=>this.toggle(i),resolveIcon:i=>this.resolveIcon(i),setIcon:(i,t)=>this.setIcon(i,t)}):o.__pivotRowKey!==void 0&&this.isActive?Z(o,n,this.gridColumns):(this.cleanupPivotStyling(n),!1)}cleanupPivotStyling(e){(e.classList.contains("pivot-group-row")||e.classList.contains("pivot-leaf-row")||e.classList.contains("pivot-grand-total-row"))&&(e.classList.remove("pivot-group-row","pivot-leaf-row","pivot-grand-total-row"),e.classList.add("data-grid-row"),e.removeAttribute("data-pivot-depth"),e.innerHTML="")}afterRender(){this.isActive&&this.config.showGrandTotal&&this.pivotResult?this.renderGrandTotalFooter():this.cleanupGrandTotalFooter()}renderGrandTotalFooter(){if(!this.pivotResult)return;const e=this.shadowRoot;if(!e)return;const n=e.querySelector(".tbw-scroll-area")??e.querySelector(".tbw-grid-content")??e.children[0];if(!n)return;this.grandTotalFooter||(this.grandTotalFooter=document.createElement("div"),this.grandTotalFooter.className="pivot-grand-total-footer",n.appendChild(this.grandTotalFooter));const o={__pivotRowKey:"__grandTotal",__pivotLabel:"Grand Total",__pivotIsGrandTotal:!0,__pivotTotal:this.pivotResult.grandTotal,...this.pivotResult.totals};j(o,this.grandTotalFooter,this.gridColumns)}cleanupGrandTotalFooter(){this.grandTotalFooter&&(this.grandTotalFooter.remove(),this.grandTotalFooter=null)}toggle(e){this.expandedKeys.has(e)?this.expandedKeys.delete(e):this.expandedKeys.add(e),this.requestRender()}expand(e){this.expandedKeys.add(e),this.requestRender()}collapse(e){this.expandedKeys.delete(e),this.requestRender()}expandAll(){if(this.pivotResult){const e=m(this.pivotResult.rows);for(const n of e)this.expandedKeys.add(n);this.requestRender()}}collapseAll(){this.expandedKeys.clear(),this.requestRender()}isExpanded(e){return this.expandedKeys.has(e)}enablePivot(){this.originalColumns.length===0&&this.captureOriginalColumns(),this.isActive=!0,this.requestRender()}disablePivot(){this.isActive=!1,this.pivotResult=null,this.requestRender()}isPivotActive(){return this.isActive}getPivotResult(){return this.pivotResult}setRowGroupFields(e){this.config.rowGroupFields=e,this.requestRender()}setColumnGroupFields(e){this.config.columnGroupFields=e,this.requestRender()}setValueFields(e){this.config.valueFields=e,this.requestRender()}refresh(){this.pivotResult=null,this.requestRender()}showPanel(){this.grid.openToolPanel(g.PANEL_ID)}hidePanel(){this.grid.closeToolPanel()}togglePanel(){this.grid.toggleToolPanel(g.PANEL_ID)}isPanelVisible(){return this.grid.activeToolPanel===g.PANEL_ID}get gridColumns(){return this.grid.columns??[]}buildFieldHeaderMap(){const e=this.getAvailableFields();this.fieldHeaderMap.clear();for(const n of e)this.fieldHeaderMap.set(n.field,n.header)}getAvailableFields(){return this.originalColumns.length>0?this.originalColumns:this.captureOriginalColumns()}captureOriginalColumns(){const e=this.grid;try{const n=e.getAllColumns?.()??e.columns??[];return this.originalColumns=n.filter(o=>!o.field.startsWith("__pivot")).map(o=>({field:o.field,header:o.header??o.field})),this.originalColumns}catch{return[]}}renderPanel(e){this.panelContainer=e,this.originalColumns.length===0&&this.captureOriginalColumns();const n={onTogglePivot:o=>{o?this.enablePivot():this.disablePivot(),this.refreshPanel()},onAddFieldToZone:(o,i)=>this.addFieldToZone(o,i),onRemoveFieldFromZone:(o,i)=>this.removeFieldFromZone(o,i),onAddValueField:(o,i)=>this.addValueField(o,i),onRemoveValueField:o=>this.removeValueField(o),onUpdateValueAggFunc:(o,i)=>this.updateValueAggFunc(o,i),onOptionChange:(o,i)=>{this.config[o]=i,this.isActive&&this.refresh()},getAvailableFields:()=>this.getAvailableFields()};return z(e,this.config,this.isActive,n)}refreshPanel(){this.panelContainer&&(this.panelContainer.innerHTML="",this.renderPanel(this.panelContainer))}addFieldToZone(e,n){if(n==="rowGroups"){const o=this.config.rowGroupFields??[];o.includes(e)||(this.config.rowGroupFields=[...o,e])}else{const o=this.config.columnGroupFields??[];o.includes(e)||(this.config.columnGroupFields=[...o,e])}this.removeFromOtherZones(e,n),this.isActive&&this.refresh(),this.refreshPanel()}removeFieldFromZone(e,n){n==="rowGroups"?this.config.rowGroupFields=(this.config.rowGroupFields??[]).filter(o=>o!==e):this.config.columnGroupFields=(this.config.columnGroupFields??[]).filter(o=>o!==e),this.isActive&&this.refresh(),this.refreshPanel()}removeFromOtherZones(e,n){n!=="rowGroups"&&(this.config.rowGroupFields=(this.config.rowGroupFields??[]).filter(o=>o!==e)),n!=="columnGroups"&&(this.config.columnGroupFields=(this.config.columnGroupFields??[]).filter(o=>o!==e)),n!=="values"&&(this.config.valueFields=(this.config.valueFields??[]).filter(o=>o.field!==e))}addValueField(e,n){const o=this.config.valueFields??[];o.some(i=>i.field===e)||(this.config.valueFields=[...o,{field:e,aggFunc:n}]),this.removeFromOtherZones(e,"values"),this.isActive&&this.refresh(),this.refreshPanel()}removeValueField(e){this.config.valueFields=(this.config.valueFields??[]).filter(n=>n.field!==e),this.isActive&&this.refresh(),this.refreshPanel()}updateValueAggFunc(e,n){const o=this.config.valueFields??[],i=o.findIndex(t=>t.field===e);i>=0&&(o[i]={...o[i],aggFunc:n},this.config.valueFields=[...o]),this.isActive&&this.refresh()}styles=$}h.PivotPlugin=g,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})}));
|
|
1
|
+
(function(h,f){typeof exports=="object"&&typeof module<"u"?f(exports,require("../../core/plugin/base-plugin"),require("../../core/internal/aggregators")):typeof define=="function"&&define.amd?define(["exports","../../core/plugin/base-plugin","../../core/internal/aggregators"],f):(h=typeof globalThis<"u"?globalThis:h||self,f(h.TbwGridPlugin_pivot={},h.TbwGrid,h.TbwGrid))})(this,(function(h,f,_){"use strict";const P=_.getValueAggregator;function L(a){const e=[];return!a.rowGroupFields?.length&&!a.columnGroupFields?.length&&e.push("At least one row or column group field is required"),a.valueFields?.length||e.push("At least one value field is required"),e}function w(a,e){return[...a,e].join("|")}function E(a,e){const n=e.rowGroupFields??[],o=e.columnGroupFields??[],i=e.valueFields??[],t=k(a,o),r=C(a,n,o,t,i,0,""),l=K(r,t,i),s=Object.values(l).reduce((d,c)=>d+c,0);return{rows:r,columnKeys:t,totals:l,grandTotal:s}}function k(a,e){if(e.length===0)return["value"];const n=new Set;for(const o of a){const i=e.map(t=>String(o[t]??"")).join("|");n.add(i)}return[...n].sort()}function N(a,e){const n=new Map;for(const o of a){const i=String(o[e]??""),t=n.get(i);t?t.push(o):n.set(i,[o])}return n}function C(a,e,n,o,i,t,r){const l=[];if(e.length===0){const u=F(a,n,o,i),v=y(u);return l.push({rowKey:r||"all",rowLabel:r||"All",depth:t,values:u,total:v,isGroup:!1,rowCount:a.length}),l}const s=e[0],d=e.slice(1),c=d.length>0,p=N(a,s);for(const[u,v]of p){const T=r?`${r}|${u}`:u,A=F(v,n,o,i),B=y(A);let G;c&&(G=C(v,d,n,o,i,t+1,T)),l.push({rowKey:T,rowLabel:u||"(blank)",depth:t,values:A,total:B,isGroup:c,children:G,rowCount:v.length})}return l}function F(a,e,n,o){const i={};for(const t of n)for(const r of o){const s=(e.length>0?a.filter(u=>e.map(v=>String(u[v]??"")).join("|")===t):a).map(u=>Number(u[r.field])||0),d=P(r.aggFunc),c=s.length>0?d(s):null,p=w([t],r.field);i[p]=c}return i}function y(a){let e=0;for(const n of Object.values(a))e+=n??0;return e}function K(a,e,n){const o={};function i(t){for(const r of t)if(!r.isGroup||!r.children?.length)for(const l of e)for(const s of n){const d=w([l],s.field);o[d]=(o[d]??0)+(r.values[d]??0)}else r.children&&i(r.children)}return i(a),o}function S(a,e,n=!0){const o=[];function i(t){o.push(t);const r=e?e.has(t.rowKey):n;if(t.children&&r)for(const l of t.children)i(l)}for(const t of a)i(t);return o}function m(a){const e=[];function n(o){if(o.isGroup&&e.push(o.rowKey),o.children)for(const i of o.children)n(i)}for(const o of a)n(o);return e}const V=["sum","avg","count","min","max","first","last"];function z(a,e,n,o){const i=new AbortController,t={config:e,callbacks:o,signal:i.signal},r=document.createElement("div");return r.className="tbw-pivot-panel",r.appendChild(b("Options",()=>M(n,t))),r.appendChild(b("Row Groups",()=>R("rowGroups",t))),r.appendChild(b("Column Groups",()=>R("columnGroups",t))),r.appendChild(b("Values",()=>D(t))),r.appendChild(b("Available Fields",()=>q(t))),a.appendChild(r),()=>{i.abort(),r.remove()}}function b(a,e){const n=document.createElement("div");n.className="tbw-pivot-section";const o=document.createElement("div");o.className="tbw-pivot-section-header",o.textContent=a;const i=document.createElement("div");return i.className="tbw-pivot-section-content",i.appendChild(e()),n.appendChild(o),n.appendChild(i),n}function R(a,e){const{config:n,callbacks:o,signal:i}=e,t=document.createElement("div");t.className="tbw-pivot-drop-zone",t.setAttribute("data-zone",a);const r=a==="rowGroups"?n.rowGroupFields??[]:n.columnGroupFields??[];if(r.length===0){const l=document.createElement("div");l.className="tbw-pivot-placeholder",l.textContent="Drag fields here or click to add",t.appendChild(l)}else for(const l of r)t.appendChild(I(l,a,e));return t.addEventListener("dragover",l=>{l.preventDefault(),t.classList.add("drag-over")},{signal:i}),t.addEventListener("dragleave",()=>{t.classList.remove("drag-over")},{signal:i}),t.addEventListener("drop",l=>{l.preventDefault(),t.classList.remove("drag-over");const s=l.dataTransfer?.getData("text/plain");s&&o.onAddFieldToZone(s,a)},{signal:i}),t}function I(a,e,n){const{callbacks:o,signal:i}=n,t=document.createElement("div");t.className="tbw-pivot-field-chip",t.draggable=!0;const r=o.getAvailableFields().find(d=>d.field===a),l=document.createElement("span");l.className="tbw-pivot-chip-label",l.textContent=r?.header??a;const s=document.createElement("button");return s.className="tbw-pivot-chip-remove",s.innerHTML="×",s.title="Remove field",s.addEventListener("click",d=>{d.stopPropagation(),o.onRemoveFieldFromZone(a,e)},{signal:i}),t.appendChild(l),t.appendChild(s),t.addEventListener("dragstart",d=>{d.dataTransfer?.setData("text/plain",a),d.dataTransfer?.setData("source-zone",e),t.classList.add("dragging")},{signal:i}),t.addEventListener("dragend",()=>{t.classList.remove("dragging")},{signal:i}),t}function D(a){const{config:e,callbacks:n,signal:o}=a,i=document.createElement("div");i.className="tbw-pivot-drop-zone tbw-pivot-values-zone",i.setAttribute("data-zone","values");const t=e.valueFields??[];if(t.length===0){const r=document.createElement("div");r.className="tbw-pivot-placeholder",r.textContent="Drag numeric fields here for aggregation",i.appendChild(r)}else for(const r of t)i.appendChild(H(r,a));return i.addEventListener("dragover",r=>{r.preventDefault(),i.classList.add("drag-over")},{signal:o}),i.addEventListener("dragleave",()=>{i.classList.remove("drag-over")},{signal:o}),i.addEventListener("drop",r=>{r.preventDefault(),i.classList.remove("drag-over");const l=r.dataTransfer?.getData("text/plain");l&&n.onAddValueField(l,"sum")},{signal:o}),i}function H(a,e){const{callbacks:n,signal:o}=e,i=document.createElement("div");i.className="tbw-pivot-field-chip tbw-pivot-value-chip";const t=n.getAvailableFields().find(c=>c.field===a.field),r=document.createElement("div");r.className="tbw-pivot-value-label-wrapper";const l=document.createElement("span");l.className="tbw-pivot-chip-label",l.textContent=t?.header??a.field;const s=document.createElement("select");s.className="tbw-pivot-agg-select",s.title="Aggregation function";for(const c of V){const p=document.createElement("option");p.value=c,p.textContent=c.toUpperCase(),p.selected=c===a.aggFunc,s.appendChild(p)}s.addEventListener("change",()=>{n.onUpdateValueAggFunc(a.field,s.value)},{signal:o});const d=document.createElement("button");return d.className="tbw-pivot-chip-remove",d.innerHTML="×",d.title="Remove value field",d.addEventListener("click",c=>{c.stopPropagation(),n.onRemoveValueField(a.field)},{signal:o}),r.appendChild(l),r.appendChild(s),i.appendChild(r),i.appendChild(d),i}function q(a){const{config:e,callbacks:n,signal:o}=a,i=document.createElement("div");i.className="tbw-pivot-available-fields";const t=n.getAvailableFields(),r=new Set([...e.rowGroupFields??[],...e.columnGroupFields??[],...e.valueFields?.map(s=>s.field)??[]]),l=t.filter(s=>!r.has(s.field));if(l.length===0){const s=document.createElement("div");s.className="tbw-pivot-placeholder",s.textContent="All fields are in use",i.appendChild(s)}else for(const s of l){const d=document.createElement("div");d.className="tbw-pivot-field-chip available",d.textContent=s.header,d.draggable=!0,d.title=`Drag to add "${s.field}" to a zone`,d.addEventListener("dragstart",c=>{c.dataTransfer?.setData("text/plain",s.field),d.classList.add("dragging")},{signal:o}),d.addEventListener("dragend",()=>{d.classList.remove("dragging")},{signal:o}),i.appendChild(d)}return i}function M(a,e){const{config:n,callbacks:o,signal:i}=e,t=document.createElement("div");return t.className="tbw-pivot-options",t.appendChild(x("Enable Pivot View",a,r=>{o.onTogglePivot(r)},i)),t.appendChild(x("Show Row Totals",n.showTotals??!0,r=>{o.onOptionChange("showTotals",r)},i)),t.appendChild(x("Show Grand Total",n.showGrandTotal??!0,r=>{o.onOptionChange("showGrandTotal",r)},i)),t}function x(a,e,n,o){const i=document.createElement("label");i.className="tbw-pivot-checkbox";const t=document.createElement("input");t.type="checkbox",t.checked=e,t.addEventListener("change",()=>n(t.checked),{signal:o});const r=document.createElement("span");return r.textContent=a,i.appendChild(t),i.appendChild(r),i}function O(a,e,n){return e.className="pivot-group-row",e.setAttribute("data-pivot-depth",String(a.__pivotDepth??0)),e.setAttribute("role","row"),e.innerHTML="",n.columns.forEach((o,i)=>{const t=document.createElement("div");if(t.className="cell",t.setAttribute("data-col",String(i)),t.setAttribute("role","gridcell"),i===0){const r=Number(a.__pivotIndent)||0;t.style.paddingLeft=`${r}px`;const l=String(a.__pivotRowKey),s=document.createElement("button");s.type="button",s.className="pivot-toggle",s.setAttribute("aria-label",a.__pivotExpanded?"Collapse group":"Expand group"),n.setIcon(s,n.resolveIcon(a.__pivotExpanded?"collapse":"expand")),s.addEventListener("click",p=>{p.stopPropagation(),n.onToggle(l)}),t.appendChild(s);const d=document.createElement("span");d.className="pivot-label",d.textContent=String(a.__pivotLabel??""),t.appendChild(d);const c=document.createElement("span");c.className="pivot-count",c.textContent=` (${Number(a.__pivotRowCount)||0})`,t.appendChild(c)}else{const r=a[o.field];t.textContent=r!=null?String(r):""}e.appendChild(t)}),!0}function Z(a,e,n){return e.className="pivot-leaf-row",e.setAttribute("data-pivot-depth",String(a.__pivotDepth??0)),e.innerHTML="",n.forEach((o,i)=>{const t=document.createElement("div");if(t.className="cell",t.setAttribute("data-col",String(i)),t.setAttribute("role","gridcell"),i===0){const r=Number(a.__pivotIndent)||0;t.style.paddingLeft=`${r+20}px`;const l=document.createElement("span");l.className="pivot-label",l.textContent=String(a.__pivotLabel??""),t.appendChild(l)}else{const r=a[o.field];t.textContent=r!=null?String(r):""}e.appendChild(t)}),!0}function j(a,e,n){return e.className="pivot-grand-total-row",e.setAttribute("role","presentation"),e.innerHTML="",n.forEach((o,i)=>{const t=document.createElement("div");if(t.className="cell",t.setAttribute("data-col",String(i)),i===0){const r=document.createElement("span");r.className="pivot-label",r.textContent="Grand Total",t.appendChild(r)}else{const r=a[o.field];t.textContent=r!=null?String(r):""}e.appendChild(t)}),!0}const $='.pivot-group-row{display:grid;grid-template-columns:var(--tbw-column-template);font-weight:600;background:var(--tbw-pivot-group-bg, var(--tbw-color-row-alt));min-height:var(--tbw-row-height);border-bottom:var(--tbw-row-divider)}.pivot-group-row:hover{background:var(--tbw-pivot-group-hover, var(--tbw-color-row-hover))}.pivot-leaf-row{display:grid;grid-template-columns:var(--tbw-column-template);background:var(--tbw-pivot-leaf-bg, var(--tbw-color-bg));min-height:var(--tbw-row-height);border-bottom:var(--tbw-row-divider)}.pivot-grand-total-row{display:grid;grid-template-columns:var(--tbw-column-template);font-weight:700;background:var(--tbw-pivot-grand-total-bg, var(--tbw-color-header-bg));min-height:var(--tbw-row-height);border-top:2px solid var(--tbw-color-border-strong)}.pivot-grand-total-row>.cell{display:flex;align-items:center;padding:var(--tbw-cell-padding);border-right:1px solid var(--tbw-color-border-cell);overflow:hidden;min-width:0}.pivot-grand-total-row>.cell:last-child{border-right:0}.pivot-grand-total-footer{position:sticky;bottom:0;z-index:var(--tbw-z-layer-pinned-rows, 20);background:var(--tbw-pivot-grand-total-bg, var(--tbw-color-header-bg));min-width:fit-content}.pivot-group-row>.cell,.pivot-leaf-row>.cell{display:flex;align-items:center;padding:var(--tbw-cell-padding);border-right:1px solid var(--tbw-color-border-cell);overflow:hidden;min-width:0}.pivot-group-row>.cell:last-child,.pivot-leaf-row>.cell:last-child{border-right:0}.pivot-toggle{display:inline-flex;align-items:center;justify-content:center;width:18px;height:18px;margin-right:6px;border:none;background:transparent;cursor:pointer;font-size:10px;color:var(--tbw-pivot-toggle-color, var(--tbw-color-fg-muted));border-radius:var(--tbw-border-radius);transition:background .15s,color .15s}.pivot-toggle:hover{background:var(--tbw-pivot-toggle-hover-bg, var(--tbw-color-row-hover));color:var(--tbw-pivot-toggle-hover-color, var(--tbw-color-fg))}.pivot-toggle:focus{outline:var(--tbw-focus-outline);outline-offset:var(--tbw-focus-outline-offset)}.pivot-label{font-weight:inherit}.pivot-count{color:var(--tbw-pivot-count-color, var(--tbw-color-fg-muted));font-size:.9em;font-weight:400}.pivot-total-row{font-weight:700;border-top:2px solid var(--tbw-pivot-border, var(--tbw-color-border-strong))}[data-pivot-depth="1"]{--tbw-pivot-depth: 1}[data-pivot-depth="2"]{--tbw-pivot-depth: 2}[data-pivot-depth="3"]{--tbw-pivot-depth: 3}[data-pivot-depth="4"]{--tbw-pivot-depth: 4}.tbw-pivot-panel{display:flex;flex-direction:column;gap:12px;padding:12px;height:100%;overflow-y:auto;font-size:13px}.tbw-pivot-section{border:1px solid var(--tbw-pivot-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius);background:var(--tbw-pivot-section-bg, var(--tbw-color-bg))}.tbw-pivot-section-header{padding:8px 12px;font-weight:600;background:var(--tbw-pivot-header-bg, var(--tbw-color-header-bg));border-bottom:1px solid var(--tbw-pivot-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius) var(--tbw-border-radius) 0 0}.tbw-pivot-section-content{padding:8px}.tbw-pivot-toggle-wrapper{display:flex;align-items:center}.tbw-pivot-toggle-label{display:flex;align-items:center;gap:8px;cursor:pointer}.tbw-pivot-toggle-label input{width:16px;height:16px;cursor:pointer}.tbw-pivot-drop-zone{min-height:60px;padding:8px;border:2px dashed var(--tbw-pivot-drop-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius);background:var(--tbw-pivot-drop-bg, var(--tbw-color-row-alt));display:flex;flex-wrap:wrap;gap:6px;align-content:flex-start;transition:all .15s ease}.tbw-pivot-drop-zone.drag-over{border-color:var(--tbw-color-accent);background:var(--tbw-pivot-drop-active, var(--tbw-focus-background))}.tbw-pivot-placeholder{color:var(--tbw-color-fg-muted);font-style:italic;padding:8px;text-align:center;width:100%}.tbw-pivot-field-chip{display:inline-flex;align-items:center;gap:6px;padding:4px 8px;background:var(--tbw-pivot-chip-bg, var(--tbw-color-header-bg));border:1px solid var(--tbw-pivot-chip-border, var(--tbw-color-border));border-radius:var(--tbw-border-radius);cursor:grab;font-size:12px;transition:all .15s ease}.tbw-pivot-field-chip:hover{background:var(--tbw-pivot-chip-hover, var(--tbw-color-row-hover));border-color:var(--tbw-color-accent)}.tbw-pivot-field-chip.available{background:var(--tbw-color-bg)}.tbw-pivot-field-chip.dragging{opacity:.5;cursor:grabbing}.tbw-pivot-chip-label{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:120px}.tbw-pivot-chip-remove{display:flex;align-items:center;justify-content:center;width:16px;height:16px;padding:0;border:none;background:transparent;color:var(--tbw-color-fg-muted);font-size:14px;font-weight:700;cursor:pointer;border-radius:50%;transition:all .15s ease}.tbw-pivot-chip-remove:hover{background:var(--tbw-pivot-chip-remove-hover-bg, var(--tbw-color-accent));color:var(--tbw-pivot-chip-remove-hover-fg, var(--tbw-color-accent-fg))}.tbw-pivot-value-chip{padding:4px 8px}.tbw-pivot-value-label-wrapper{display:flex;align-items:center;gap:8px;flex:1;min-width:0}.tbw-pivot-agg-select{padding:2px 4px;font-size:11px;border:1px solid var(--tbw-color-border);border-radius:var(--tbw-border-radius);background:var(--tbw-color-bg);cursor:pointer}.tbw-pivot-available-fields{display:flex;flex-wrap:wrap;gap:6px;min-height:40px}.tbw-pivot-options{display:flex;flex-direction:column;gap:8px}.tbw-pivot-checkbox{display:flex;align-items:center;gap:8px;cursor:pointer}.tbw-pivot-checkbox input{width:14px;height:14px;cursor:pointer}';class g extends f.BaseGridPlugin{name="pivot";version="1.0.0";static PANEL_ID="pivot";get defaultConfig(){return{active:!0,showTotals:!0,showGrandTotal:!0,showToolPanel:!0}}isActive=!1;hasInitialized=!1;pivotResult=null;fieldHeaderMap=new Map;expandedKeys=new Set;defaultExpanded=!0;originalColumns=[];panelContainer=null;grandTotalFooter=null;hasValidPivotConfig(){return(this.config.valueFields?.length??0)>0}detach(){this.isActive=!1,this.hasInitialized=!1,this.pivotResult=null,this.fieldHeaderMap.clear(),this.originalColumns=[],this.panelContainer=null,this.cleanupGrandTotalFooter()}getToolPanel(){if((this.config?.showToolPanel??this.userConfig?.showToolPanel??!0)!==!1)return{id:g.PANEL_ID,title:"Pivot",icon:"⊞",tooltip:"Configure pivot table",order:90,render:n=>this.renderPanel(n)}}processRows(e){if(!this.hasInitialized&&this.config.active!==!1&&this.hasValidPivotConfig()&&(this.hasInitialized=!0,this.isActive=!0),!this.isActive)return[...e];const n=L(this.config);if(n.length>0)return this.warn(`Config errors: ${n.join(", ")}`),[...e];if(this.buildFieldHeaderMap(),this.defaultExpanded=this.config.defaultExpanded??!0,this.expandedKeys.size===0&&this.defaultExpanded&&this.pivotResult){const t=m(this.pivotResult.rows);for(const r of t)this.expandedKeys.add(r)}if(this.pivotResult=E(e,this.config),this.expandedKeys.size===0&&this.defaultExpanded){const t=m(this.pivotResult.rows);for(const r of t)this.expandedKeys.add(r)}const o=this.config.indentWidth??20;return S(this.pivotResult.rows,this.expandedKeys,this.defaultExpanded).map(t=>({__pivotRowKey:t.rowKey,__pivotLabel:t.rowLabel,__pivotDepth:t.depth,__pivotIsGroup:t.isGroup,__pivotHasChildren:!!t.children?.length,__pivotExpanded:this.expandedKeys.has(t.rowKey),__pivotRowCount:t.rowCount??0,__pivotIndent:t.depth*o,__pivotTotal:t.total,...t.values}))}processColumns(e){if(!this.isActive||!this.pivotResult)return[...e];const n=[],o=(this.config.rowGroupFields??[]).map(i=>this.fieldHeaderMap.get(i)??i).join(" / ");n.push({field:"__pivotLabel",header:o||"Group",width:200});for(const i of this.pivotResult.columnKeys)for(const t of this.config.valueFields??[]){const r=w([i],t.field),l=t.header||this.fieldHeaderMap.get(t.field)||t.field;n.push({field:r,header:`${i} - ${l} (${t.aggFunc})`,width:120,type:"number"})}return this.config.showTotals&&n.push({field:"__pivotTotal",header:"Total",width:100,type:"number"}),n}renderRow(e,n){const o=e;return o.__pivotRowKey&&o.__pivotHasChildren?O(o,n,{columns:this.gridColumns,onToggle:i=>this.toggle(i),resolveIcon:i=>this.resolveIcon(i),setIcon:(i,t)=>this.setIcon(i,t)}):o.__pivotRowKey!==void 0&&this.isActive?Z(o,n,this.gridColumns):(this.cleanupPivotStyling(n),!1)}cleanupPivotStyling(e){(e.classList.contains("pivot-group-row")||e.classList.contains("pivot-leaf-row")||e.classList.contains("pivot-grand-total-row"))&&(e.classList.remove("pivot-group-row","pivot-leaf-row","pivot-grand-total-row"),e.classList.add("data-grid-row"),e.removeAttribute("data-pivot-depth"),e.innerHTML="")}afterRender(){this.isActive&&this.config.showGrandTotal&&this.pivotResult?this.renderGrandTotalFooter():this.cleanupGrandTotalFooter()}renderGrandTotalFooter(){if(!this.pivotResult)return;const e=this.shadowRoot;if(!e)return;const n=e.querySelector(".tbw-scroll-area")??e.querySelector(".tbw-grid-content")??e.children[0];if(!n)return;this.grandTotalFooter||(this.grandTotalFooter=document.createElement("div"),this.grandTotalFooter.className="pivot-grand-total-footer",n.appendChild(this.grandTotalFooter));const o={__pivotRowKey:"__grandTotal",__pivotLabel:"Grand Total",__pivotIsGrandTotal:!0,__pivotTotal:this.pivotResult.grandTotal,...this.pivotResult.totals};j(o,this.grandTotalFooter,this.gridColumns)}cleanupGrandTotalFooter(){this.grandTotalFooter&&(this.grandTotalFooter.remove(),this.grandTotalFooter=null)}toggle(e){this.expandedKeys.has(e)?this.expandedKeys.delete(e):this.expandedKeys.add(e),this.requestRender()}expand(e){this.expandedKeys.add(e),this.requestRender()}collapse(e){this.expandedKeys.delete(e),this.requestRender()}expandAll(){if(this.pivotResult){const e=m(this.pivotResult.rows);for(const n of e)this.expandedKeys.add(n);this.requestRender()}}collapseAll(){this.expandedKeys.clear(),this.requestRender()}isExpanded(e){return this.expandedKeys.has(e)}enablePivot(){this.originalColumns.length===0&&this.captureOriginalColumns(),this.isActive=!0,this.requestRender()}disablePivot(){this.isActive=!1,this.pivotResult=null,this.requestRender()}isPivotActive(){return this.isActive}getPivotResult(){return this.pivotResult}setRowGroupFields(e){this.config.rowGroupFields=e,this.requestRender()}setColumnGroupFields(e){this.config.columnGroupFields=e,this.requestRender()}setValueFields(e){this.config.valueFields=e,this.requestRender()}refresh(){this.pivotResult=null,this.requestRender()}showPanel(){this.grid.openToolPanel(g.PANEL_ID)}hidePanel(){this.grid.closeToolPanel()}togglePanel(){this.grid.toggleToolPanel(g.PANEL_ID)}isPanelVisible(){return this.grid.activeToolPanel===g.PANEL_ID}get gridColumns(){return this.grid.columns??[]}buildFieldHeaderMap(){const e=this.getAvailableFields();this.fieldHeaderMap.clear();for(const n of e)this.fieldHeaderMap.set(n.field,n.header)}getAvailableFields(){return this.originalColumns.length>0?this.originalColumns:this.captureOriginalColumns()}captureOriginalColumns(){const e=this.grid;try{const n=e.getAllColumns?.()??e.columns??[];return this.originalColumns=n.filter(o=>!o.field.startsWith("__pivot")).map(o=>({field:o.field,header:o.header??o.field})),this.originalColumns}catch{return[]}}renderPanel(e){this.panelContainer=e,this.originalColumns.length===0&&this.captureOriginalColumns();const n={onTogglePivot:o=>{o?this.enablePivot():this.disablePivot(),this.refreshPanel()},onAddFieldToZone:(o,i)=>this.addFieldToZone(o,i),onRemoveFieldFromZone:(o,i)=>this.removeFieldFromZone(o,i),onAddValueField:(o,i)=>this.addValueField(o,i),onRemoveValueField:o=>this.removeValueField(o),onUpdateValueAggFunc:(o,i)=>this.updateValueAggFunc(o,i),onOptionChange:(o,i)=>{this.config[o]=i,this.isActive&&this.refresh()},getAvailableFields:()=>this.getAvailableFields()};return z(e,this.config,this.isActive,n)}refreshPanel(){this.panelContainer&&(this.panelContainer.innerHTML="",this.renderPanel(this.panelContainer))}addFieldToZone(e,n){if(n==="rowGroups"){const o=this.config.rowGroupFields??[];o.includes(e)||(this.config.rowGroupFields=[...o,e])}else{const o=this.config.columnGroupFields??[];o.includes(e)||(this.config.columnGroupFields=[...o,e])}this.removeFromOtherZones(e,n),this.isActive&&this.refresh(),this.refreshPanel()}removeFieldFromZone(e,n){n==="rowGroups"?this.config.rowGroupFields=(this.config.rowGroupFields??[]).filter(o=>o!==e):this.config.columnGroupFields=(this.config.columnGroupFields??[]).filter(o=>o!==e),this.isActive&&this.refresh(),this.refreshPanel()}removeFromOtherZones(e,n){n!=="rowGroups"&&(this.config.rowGroupFields=(this.config.rowGroupFields??[]).filter(o=>o!==e)),n!=="columnGroups"&&(this.config.columnGroupFields=(this.config.columnGroupFields??[]).filter(o=>o!==e)),n!=="values"&&(this.config.valueFields=(this.config.valueFields??[]).filter(o=>o.field!==e))}addValueField(e,n){const o=this.config.valueFields??[];o.some(i=>i.field===e)||(this.config.valueFields=[...o,{field:e,aggFunc:n}]),this.removeFromOtherZones(e,"values"),this.isActive&&this.refresh(),this.refreshPanel()}removeValueField(e){this.config.valueFields=(this.config.valueFields??[]).filter(n=>n.field!==e),this.isActive&&this.refresh(),this.refreshPanel()}updateValueAggFunc(e,n){const o=this.config.valueFields??[],i=o.findIndex(t=>t.field===e);i>=0&&(o[i]={...o[i],aggFunc:n},this.config.valueFields=[...o]),this.isActive&&this.refresh()}styles=$}h.PivotPlugin=g,Object.defineProperty(h,Symbol.toStringTag,{value:"Module"})}));
|
|
2
2
|
//# sourceMappingURL=pivot.umd.js.map
|