@toolbox-web/grid 2.0.0-alpha → 2.0.0-alpha.1
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.js +2 -2
- package/all.js.map +1 -1
- package/index.js +1 -1
- package/index.js.map +1 -1
- package/lib/plugins/export/excel-styles.d.ts +45 -0
- package/lib/plugins/export/index.d.ts +1 -1
- package/lib/plugins/export/index.js +1 -1
- package/lib/plugins/export/index.js.map +1 -1
- package/lib/plugins/export/types.d.ts +68 -0
- package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts +91 -2
- package/lib/plugins/grouping-rows/grouping-rows.d.ts +29 -1
- package/lib/plugins/grouping-rows/index.d.ts +1 -1
- package/lib/plugins/grouping-rows/index.js +2 -2
- package/lib/plugins/grouping-rows/index.js.map +1 -1
- package/lib/plugins/grouping-rows/types.d.ts +104 -0
- package/lib/plugins/server-side/index.js +1 -1
- package/lib/plugins/server-side/index.js.map +1 -1
- package/package.json +1 -1
- package/umd/grid.all.umd.js +1 -1
- package/umd/grid.all.umd.js.map +1 -1
- package/umd/plugins/export.umd.js +1 -1
- package/umd/plugins/export.umd.js.map +1 -1
- package/umd/plugins/grouping-rows.umd.js +1 -1
- package/umd/plugins/grouping-rows.umd.js.map +1 -1
- package/umd/plugins/server-side.umd.js +1 -1
- package/umd/plugins/server-side.umd.js.map +1 -1
|
@@ -30,6 +30,16 @@ export interface ExportParams {
|
|
|
30
30
|
format: ExportFormat;
|
|
31
31
|
/** File name for the export (without extension) */
|
|
32
32
|
fileName?: string;
|
|
33
|
+
/**
|
|
34
|
+
* Override the file extension for Excel export.
|
|
35
|
+
*
|
|
36
|
+
* Defaults to `'.xls'` so the file opens in Excel on most operating systems.
|
|
37
|
+
* Set to `'.xml'` to avoid Excel's "format mismatch" warning — but note
|
|
38
|
+
* that `.xml` files open in a browser by default on most systems.
|
|
39
|
+
*
|
|
40
|
+
* Only applies to Excel format exports.
|
|
41
|
+
*/
|
|
42
|
+
fileExtension?: string;
|
|
33
43
|
/** Specific column fields to export */
|
|
34
44
|
columns?: string[];
|
|
35
45
|
/** Specific row indices to export */
|
|
@@ -40,6 +50,64 @@ export interface ExportParams {
|
|
|
40
50
|
processCell?: (value: any, field: string, row: any) => any;
|
|
41
51
|
/** Custom header processor */
|
|
42
52
|
processHeader?: (header: string, field: string) => string;
|
|
53
|
+
/** Excel style configuration (only applies to Excel export) */
|
|
54
|
+
excelStyles?: ExcelStyleConfig;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Configuration for styled Excel export.
|
|
58
|
+
*
|
|
59
|
+
* Controls header styles, per-column and per-cell formatting,
|
|
60
|
+
* column widths, and auto-fit behavior in Excel XML output.
|
|
61
|
+
*/
|
|
62
|
+
export interface ExcelStyleConfig {
|
|
63
|
+
/** Style applied to all header cells */
|
|
64
|
+
headerStyle?: ExcelCellStyle;
|
|
65
|
+
/** Default style for all data cells */
|
|
66
|
+
defaultStyle?: ExcelCellStyle;
|
|
67
|
+
/** Per-column style overrides (keyed by field name) */
|
|
68
|
+
columnStyles?: Record<string, ExcelCellStyle>;
|
|
69
|
+
/** Callback for per-cell dynamic styling */
|
|
70
|
+
cellStyle?: (value: unknown, field: string, row: unknown) => ExcelCellStyle | undefined;
|
|
71
|
+
/** Column width overrides in characters (keyed by field name) */
|
|
72
|
+
columnWidths?: Record<string, number>;
|
|
73
|
+
/** Auto-fit column widths based on content (default: false) */
|
|
74
|
+
autoFitColumns?: boolean;
|
|
75
|
+
}
|
|
76
|
+
/** Style definition for an Excel cell. */
|
|
77
|
+
export interface ExcelCellStyle {
|
|
78
|
+
/** Font configuration */
|
|
79
|
+
font?: {
|
|
80
|
+
name?: string;
|
|
81
|
+
size?: number;
|
|
82
|
+
bold?: boolean;
|
|
83
|
+
italic?: boolean;
|
|
84
|
+
color?: string;
|
|
85
|
+
};
|
|
86
|
+
/** Fill / background color */
|
|
87
|
+
fill?: {
|
|
88
|
+
color: string;
|
|
89
|
+
pattern?: 'Solid' | 'None';
|
|
90
|
+
};
|
|
91
|
+
/** Number format string (Excel format codes) */
|
|
92
|
+
numberFormat?: string;
|
|
93
|
+
/** Text alignment */
|
|
94
|
+
alignment?: {
|
|
95
|
+
horizontal?: 'Left' | 'Center' | 'Right';
|
|
96
|
+
vertical?: 'Top' | 'Center' | 'Bottom';
|
|
97
|
+
wrapText?: boolean;
|
|
98
|
+
};
|
|
99
|
+
/** Cell borders */
|
|
100
|
+
borders?: {
|
|
101
|
+
top?: ExcelBorder;
|
|
102
|
+
bottom?: ExcelBorder;
|
|
103
|
+
left?: ExcelBorder;
|
|
104
|
+
right?: ExcelBorder;
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
/** Border definition for an Excel cell edge. */
|
|
108
|
+
export interface ExcelBorder {
|
|
109
|
+
style: 'Thin' | 'Medium' | 'Thick';
|
|
110
|
+
color?: string;
|
|
43
111
|
}
|
|
44
112
|
/** Internal state managed by the export plugin */
|
|
45
113
|
export interface ExportState {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BaseGridPlugin, CellClickEvent, PluginManifest, PluginQuery } from '../../core/plugin/base-plugin';
|
|
2
|
-
import { GroupingRowsConfig, RenderRow } from './types';
|
|
2
|
+
import { GroupDefinition, GroupingRowsConfig, RenderRow } from './types';
|
|
3
3
|
/**
|
|
4
4
|
* Group state information returned by getGroupState()
|
|
5
5
|
*/
|
|
@@ -90,6 +90,16 @@ export declare class GroupingRowsPlugin extends BaseGridPlugin<GroupingRowsConfi
|
|
|
90
90
|
private keysToAnimate;
|
|
91
91
|
/** Track if initial defaultExpanded has been applied */
|
|
92
92
|
private hasAppliedDefaultExpanded;
|
|
93
|
+
/** Pre-defined group definitions (server-side mode) */
|
|
94
|
+
private preDefinedGroups;
|
|
95
|
+
/** Lazily loaded row data keyed by group key */
|
|
96
|
+
private groupRowsMap;
|
|
97
|
+
/** Groups currently in a loading state */
|
|
98
|
+
private loadingGroups;
|
|
99
|
+
/** Whether an async groups fetch is currently in progress */
|
|
100
|
+
private groupsFetchInFlight;
|
|
101
|
+
/** Group keys with an in-flight rows fetch */
|
|
102
|
+
private rowsFetchInFlight;
|
|
93
103
|
/**
|
|
94
104
|
* Get expand/collapse animation style from plugin config.
|
|
95
105
|
* Uses base class isAnimationEnabled to respect grid-level settings.
|
|
@@ -128,12 +138,39 @@ export declare class GroupingRowsPlugin extends BaseGridPlugin<GroupingRowsConfi
|
|
|
128
138
|
/** @internal */
|
|
129
139
|
onKeyDown(event: KeyboardEvent): boolean | void;
|
|
130
140
|
/**
|
|
131
|
-
* Render a row. Returns true if we handled the row (group row), false otherwise.
|
|
141
|
+
* Render a row. Returns true if we handled the row (group row or loading placeholder), false otherwise.
|
|
132
142
|
* @internal
|
|
133
143
|
*/
|
|
134
144
|
renderRow(row: any, rowEl: HTMLElement, _rowIndex: number): boolean;
|
|
135
145
|
/** @internal */
|
|
136
146
|
afterRender(): void;
|
|
147
|
+
/**
|
|
148
|
+
* Build the row model from pre-defined group definitions.
|
|
149
|
+
* Used when `groups` config or `setGroups()` provides external group structure.
|
|
150
|
+
*/
|
|
151
|
+
private processPreDefinedGroups;
|
|
152
|
+
/**
|
|
153
|
+
* Fetch group definitions from an async callback.
|
|
154
|
+
* Sets `preDefinedGroups` when resolved and triggers re-render.
|
|
155
|
+
*/
|
|
156
|
+
private fetchGroupsAsync;
|
|
157
|
+
/**
|
|
158
|
+
* Fetch rows for a group using the `rows` callback and update state.
|
|
159
|
+
* Manages loading indicator automatically. Guards against duplicate in-flight fetches.
|
|
160
|
+
*/
|
|
161
|
+
private fetchGroupRowsAsync;
|
|
162
|
+
/**
|
|
163
|
+
* Collect all group keys from a pre-defined group tree.
|
|
164
|
+
*/
|
|
165
|
+
private collectGroupKeys;
|
|
166
|
+
/**
|
|
167
|
+
* Get the active group definitions (pre-defined or empty).
|
|
168
|
+
*/
|
|
169
|
+
private getActiveGroups;
|
|
170
|
+
/**
|
|
171
|
+
* Find a group definition by key in the pre-defined group tree.
|
|
172
|
+
*/
|
|
173
|
+
private findGroupDefinition;
|
|
137
174
|
/**
|
|
138
175
|
* Create a toggle button for expanding/collapsing a group.
|
|
139
176
|
*/
|
|
@@ -209,4 +246,56 @@ export declare class GroupingRowsPlugin extends BaseGridPlugin<GroupingRowsConfi
|
|
|
209
246
|
* @param fn - The groupOn function or undefined to disable
|
|
210
247
|
*/
|
|
211
248
|
setGroupOn(fn: ((row: any) => any[] | any | null | false) | undefined): void;
|
|
249
|
+
/**
|
|
250
|
+
* Replace auto-detected groups with an externally provided group structure.
|
|
251
|
+
*
|
|
252
|
+
* When groups are set, the plugin switches to pre-defined mode — `groupOn`
|
|
253
|
+
* is ignored and the plugin renders the provided group headers instead.
|
|
254
|
+
* Row data for each group must be populated via {@link setGroupRows}.
|
|
255
|
+
*
|
|
256
|
+
* @param groups - Array of group definitions, or empty array to clear
|
|
257
|
+
*/
|
|
258
|
+
setGroups(groups: GroupDefinition[]): void;
|
|
259
|
+
/**
|
|
260
|
+
* Get the current pre-defined group structure.
|
|
261
|
+
*
|
|
262
|
+
* Returns the groups set via {@link setGroups} or the resolved `groups` config.
|
|
263
|
+
* Returns an empty array when using `groupOn`-based grouping or while
|
|
264
|
+
* an async `groups` callback is still in flight.
|
|
265
|
+
*
|
|
266
|
+
* @returns Current group definitions
|
|
267
|
+
*/
|
|
268
|
+
getGroups(): GroupDefinition[];
|
|
269
|
+
/**
|
|
270
|
+
* Populate row data for an expanded group.
|
|
271
|
+
*
|
|
272
|
+
* Call this in response to a `group-expand` event after fetching rows
|
|
273
|
+
* from the server. The plugin will re-render to show the rows.
|
|
274
|
+
*
|
|
275
|
+
* If the {@link GroupingRowsConfig.rows | rows} callback is configured,
|
|
276
|
+
* this is called automatically — you only need this for the imperative API.
|
|
277
|
+
*
|
|
278
|
+
* @param groupKey - The group key to populate
|
|
279
|
+
* @param rows - The row data for this group
|
|
280
|
+
*/
|
|
281
|
+
setGroupRows(groupKey: string, rows: unknown[]): void;
|
|
282
|
+
/**
|
|
283
|
+
* Toggle loading indicator for a group.
|
|
284
|
+
*
|
|
285
|
+
* When loading is true, the group shows a loading spinner instead of row data.
|
|
286
|
+
* Call with `false` after rows are loaded (also cleared by {@link setGroupRows}).
|
|
287
|
+
*
|
|
288
|
+
* @param groupKey - The group key
|
|
289
|
+
* @param loading - Whether the group is loading
|
|
290
|
+
*/
|
|
291
|
+
setGroupLoading(groupKey: string, loading: boolean): void;
|
|
292
|
+
/**
|
|
293
|
+
* Clear cached row data for one or all groups.
|
|
294
|
+
*
|
|
295
|
+
* Use when the server data has changed and groups need to be re-fetched
|
|
296
|
+
* on next expand.
|
|
297
|
+
*
|
|
298
|
+
* @param groupKey - Specific group key to clear, or omit to clear all
|
|
299
|
+
*/
|
|
300
|
+
clearGroupRows(groupKey?: string): void;
|
|
212
301
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DefaultExpandedValue, GroupingRowsConfig, RenderRow } from './types';
|
|
1
|
+
import { DefaultExpandedValue, GroupDefinition, GroupingRowsConfig, RenderRow } from './types';
|
|
2
2
|
interface BuildGroupingArgs {
|
|
3
3
|
rows: any[];
|
|
4
4
|
config: GroupingRowsConfig;
|
|
@@ -58,4 +58,32 @@ export declare function getGroupKeys(rows: RenderRow[]): string[];
|
|
|
58
58
|
* @returns Total row count
|
|
59
59
|
*/
|
|
60
60
|
export declare function getGroupRowCount(groupRow: RenderRow): number;
|
|
61
|
+
interface PreDefinedGroupModelArgs {
|
|
62
|
+
groups: GroupDefinition[];
|
|
63
|
+
expanded: Set<string>;
|
|
64
|
+
groupRows: Map<string, unknown[]>;
|
|
65
|
+
loadingGroups: Set<string>;
|
|
66
|
+
parentPath?: string[];
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Build a flattened render model from pre-defined group definitions.
|
|
70
|
+
*
|
|
71
|
+
* Unlike `buildGroupedRowModel`, this does not analyze row data — groups
|
|
72
|
+
* are provided externally (e.g. from a server). Row data for each group
|
|
73
|
+
* is populated lazily via the `groupRows` map.
|
|
74
|
+
*
|
|
75
|
+
* @param args - Pre-defined grouping arguments
|
|
76
|
+
* @returns Flattened array of render rows (groups + data rows)
|
|
77
|
+
*/
|
|
78
|
+
export declare function buildPreDefinedGroupModel({ groups, expanded, groupRows, loadingGroups, parentPath, }: PreDefinedGroupModelArgs): RenderRow[];
|
|
79
|
+
/**
|
|
80
|
+
* Compute the group path (array of ancestor keys) for a given group key
|
|
81
|
+
* within a pre-defined group structure.
|
|
82
|
+
*
|
|
83
|
+
* @param groups - The group definitions to search
|
|
84
|
+
* @param targetKey - The key to find
|
|
85
|
+
* @param parentPath - Accumulated path (used for recursion)
|
|
86
|
+
* @returns Array of group keys from root to target, or empty array if not found
|
|
87
|
+
*/
|
|
88
|
+
export declare function getGroupPath(groups: GroupDefinition[], targetKey: string, parentPath?: string[]): string[];
|
|
61
89
|
export {};
|
|
@@ -6,4 +6,4 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export { GroupingRowsPlugin } from './GroupingRowsPlugin';
|
|
8
8
|
export type { GroupState } from './GroupingRowsPlugin';
|
|
9
|
-
export type { AggregatorMap, DataRowModelItem, DefaultExpandedValue, GroupRowModelItem, GroupRowRenderParams, GroupToggleDetail,
|
|
9
|
+
export type { AggregatorMap, DataRowModelItem, DefaultExpandedValue, GroupCollapseDetail, GroupDefinition, GroupExpandDetail, GroupingRowsConfig, GroupRowModelItem, GroupRowRenderParams, GroupToggleDetail, RenderRow, } from './types';
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
const e="expanded",t="group-toggle",r="group-label",n="group-count",o={sum:(e,t)=>{let r=0;for(let n=0;n<e.length;n++)r+=Number(e[n][t])||0;return r},avg:(e,t)=>{if(!e.length)return 0;let r=0;for(let n=0;n<e.length;n++)r+=Number(e[n][t])||0;return r/e.length},count:e=>e.length,min:(e,t)=>{if(!e.length)return 0;let r=1/0;for(let n=0;n<e.length;n++){const o=Number(e[n][t]);o<r&&(r=o)}return r},max:(e,t)=>{if(!e.length)return 0;let r=-1/0;for(let n=0;n<e.length;n++){const o=Number(e[n][t]);o>r&&(r=o)}return r},first:(e,t)=>e[0]?.[t],last:(e,t)=>e[e.length-1]?.[t]},i=/* @__PURE__ */new Map,s={register(e,t){i.set(e,t)},unregister(e){i.delete(e)},get(e){if(void 0!==e)return"function"==typeof e?e:i.get(e)??o[e]},run(e,t,r,n){const o=this.get(e);return o?o(t,r,n):void 0},has:e=>i.has(e)||e in o,list:()=>[...Object.keys(o),...i.keys()]},a={sortApplied:(e,t)=>`Sorted by ${e}, ${t}`,sortCleared:()=>"Sort cleared",filterApplied:e=>`Filter applied on ${e}`,filterCleared:e=>`Filter cleared from ${e}`,allFiltersCleared:()=>"All filters cleared",groupExpanded:(e,t)=>`Group ${e} expanded, ${t} rows`,groupCollapsed:e=>`Group ${e} collapsed`,selectionChanged:e=>`${e} rows selected`,editingStarted:e=>`Editing row ${e+1}`,editingCommitted:e=>`Row ${e+1} saved`,dataLoaded:e=>`${e} rows loaded`},d='<svg viewBox="0 0 16 16" width="12" height="12"><path fill="currentColor" d="M6 10.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"/></svg>',l={expand:"▶",collapse:"▼",sortAsc:"▲",sortDesc:"▼",sortNone:"⇅",submenuArrow:"▶",dragHandle:"⋮⋮",toolPanel:"☰",filter:d,filterActive:d,print:"🖨️"};function u(e,t){if(!e)return;const r="effectiveConfig"in e?e.effectiveConfig:void 0;if(!1===r?.a11y?.announcements)return;const n=e.querySelector?.(".tbw-sr-only");n&&(n.textContent="",requestAnimationFrame(()=>{n.textContent=t}))}function g(e,t,...r){const n=e&&"effectiveConfig"in e?e.effectiveConfig:void 0,o=n?.a11y?.messages?.[t];return o?o(...r):a[t](...r)}function p(e,t){return`[tbw-grid${e?`#${e}`:""}${t?`:${t}`:""}]`}function c(e,t,r,n){return`${p(r,n)} ${e}: ${t}\n\n → More info: ${function(e){return`https://toolboxjs.com/grid/errors#${e.toLowerCase()}`}(e)}`}["__otorp__","__retteGenifed__","__retteSenifed__","rotcurtsnoc","wodniw","sihTlabolg","labolg","ssecorp","noitcnuF","tropmi","lave","tcelfeR","yxorP","rorrE","stnemugra","tnemucod","noitacol","eikooc","egarotSlacol","egarotSnoisses","BDdexedni","hctef","tseuqeRpttHLMX","tekcoSbeW","rekroW","rekroWderahS","rekroWecivreS","renepo","tnerap","pot","semarf","fles"].map(e=>e.split("").reverse().join(""));const h=/* @__PURE__ */new Set(["script","iframe","object","embed","form","input","button","textarea","select","link","meta","base","style","template","slot","portal","frame","frameset","applet","noscript","noembed","plaintext","xmp","listing"]),f=/^on\w+$/i,w=/* @__PURE__ */new Set(["href","src","action","formaction","data","srcdoc","xlink:href","poster","srcset"]),m=/^\s*(javascript|vbscript|data|blob):/i;function b(e){if(!e||"string"!=typeof e)return"";if(-1===e.indexOf("<"))return e;const t=document.createElement("template");return t.innerHTML=e,function(e){const t=[],r=e.querySelectorAll("*");for(const n of r){const e=n.tagName.toLowerCase();if(h.has(e)){t.push(n);continue}if("svg"===e||"http://www.w3.org/2000/svg"===n.namespaceURI){if(Array.from(n.attributes).some(e=>f.test(e.name)||"href"===e.name||"xlink:href"===e.name)){t.push(n);continue}}const r=[];for(const t of n.attributes){const e=t.name.toLowerCase();f.test(e)?r.push(t.name):(w.has(e)&&m.test(t.value)||"style"===e&&/expression\s*\(|javascript:|behavior\s*:/i.test(t.value))&&r.push(t.name)}r.forEach(e=>n.removeAttribute(e))}t.forEach(e=>e.remove())}(t.content),t.innerHTML}class y{static dependencies;static manifest;aliases;version="undefined"!=typeof __GRID_VERSION__?__GRID_VERSION__:"dev";styles;cellRenderers;headerRenderers;cellEditors;grid;config;userConfig;#e;get defaultConfig(){return{}}constructor(e={}){this.userConfig=e}attach(e){this.#e?.abort(),this.#e=new AbortController,this.grid=e,this.config={...this.defaultConfig,...this.userConfig}}detach(){this.#e?.abort(),this.#e=void 0}getPlugin(e){return this.grid?.getPlugin(e)}emit(e,t){this.grid?.dispatchEvent?.(new CustomEvent(e,{detail:t,bubbles:!0}))}emitCancelable(e,t){const r=new CustomEvent(e,{detail:t,bubbles:!0,cancelable:!0});return this.grid?.dispatchEvent?.(r),r.defaultPrevented}on(e,t){this.grid?._pluginManager?.subscribe(this,e,t)}off(e){this.grid?._pluginManager?.unsubscribe(this,e)}emitPluginEvent(e,t){this.grid?._pluginManager?.emitPluginEvent(e,t)}requestRender(){this.grid?.requestRender?.()}requestColumnsRender(){this.grid?.requestColumnsRender?.()}requestRenderWithFocus(){this.grid?.requestRenderWithFocus?.()}requestAfterRender(){this.grid?.requestAfterRender?.()}requestVirtualRefresh(){this.grid?.requestVirtualRefresh?.()}get rows(){return this.grid?.rows??[]}get sourceRows(){return this.grid?.sourceRows??[]}get columns(){return this.grid?.columns??[]}get visibleColumns(){return this.grid?._visibleColumns??[]}get gridElement(){return this.grid?._hostElement}get disconnectSignal(){return this.#e?.signal??this.grid?.disconnectSignal}get gridIcons(){const e=this.grid?.gridConfig?.icons??{};return{...l,...e}}get isAnimationEnabled(){const e=this.grid?.effectiveConfig?.animation?.mode??"reduced-motion";if(!1===e||"off"===e)return!1;if(!0===e||"on"===e)return!0;const t=this.gridElement;if(t){return"0"!==getComputedStyle(t).getPropertyValue("--tbw-animation-enabled").trim()}return!0}get animationDuration(){const e=this.gridElement;if(e){const t=getComputedStyle(e).getPropertyValue("--tbw-animation-duration").trim(),r=parseInt(t,10);if(!isNaN(r))return r}return 200}setIcon(e,t,r){e.dataset.icon=t.replace(/([A-Z])/g,"-$1").toLowerCase(),"collapse"===t?e.dataset.expanded="":"expand"===t&&delete e.dataset.expanded;const n=this.#t(t,r);void 0!==n?"string"==typeof n?e.innerHTML=b(n):n instanceof HTMLElement&&(e.innerHTML="",e.appendChild(n.cloneNode(!0))):e.innerHTML=""}#t(e,t){return void 0!==t?t:this.grid?.gridConfig?.icons?.[e]}updateSortIndicator(e,t){e.querySelector('[part~="sort-indicator"], .sort-indicator')?.remove();const r=document.createElement("span");r.setAttribute("part","sort-indicator"),r.className="sort-indicator",t?(e.setAttribute("aria-sort","asc"===t?"ascending":"descending"),e.setAttribute("data-sort",t),this.setIcon(r,"asc"===t?"sortAsc":"sortDesc")):(e.setAttribute("aria-sort","none"),e.removeAttribute("data-sort"),this.setIcon(r,"sortNone"));const n=e.querySelector(".tbw-filter-btn")??e.querySelector(".resize-handle");return n?e.insertBefore(r,n):e.appendChild(r),r}warn(e,t){void 0!==t?console.warn(c(e,t,this.gridElement.id,this.name)):console.warn(`${p(this.gridElement.id,this.name)} ${e}`)}throwDiagnostic(e,t){throw new Error(c(e,t,this.gridElement.id,this.name))}}function v({rows:e,config:t,expanded:r,initialExpanded:n}){const o=t.groupOn;if("function"!=typeof o)return[];const i={key:"__root__",value:null,depth:-1,rows:[],children:/* @__PURE__ */new Map};if(e.forEach(e=>{let t=o(e);null==t||!1===t?t=["__ungrouped__"]:Array.isArray(t)||(t=[t]);let r=i;t.forEach((t,n)=>{const o=null==t?"∅":String(t),i="__root__"===r.key?o:r.key+"||"+o;let s=r.children.get(o);s||(s={key:i,value:t,depth:n,rows:[],children:/* @__PURE__ */new Map,parent:r},r.children.set(o,s)),s.rows.push(e),r=s})}),1===i.children.size&&i.children.has("__ungrouped__")){if(i.children.get("__ungrouped__").rows.length===e.length)return[]}const s=/* @__PURE__ */new Map;for(let u=0;u<e.length;u++)s.set(e[u],u);const a=/* @__PURE__ */new Set([...r,...n??[]]),d=[],l=e=>{if(e===i)return void e.children.forEach(e=>l(e));const t=a.has(e.key);d.push({kind:"group",key:e.key,value:e.value,depth:e.depth,rows:e.rows,expanded:t}),t&&(e.children.size?e.children.forEach(e=>l(e)):e.rows.forEach(e=>d.push({kind:"data",row:e,rowIndex:s.get(e)??-1})))};return l(i),d}class _ extends y{static manifest={incompatibleWith:[{name:"tree",reason:"Both plugins transform the entire row model. TreePlugin flattens nested hierarchies while GroupingRowsPlugin groups flat rows with synthetic headers. Use one approach per grid."},{name:"pivot",reason:"PivotPlugin creates its own aggregated row and column structure. Row grouping cannot be applied on top of pivot-generated rows."},{name:"serverSide",reason:"Row grouping requires the full dataset to compute group boundaries. ServerSidePlugin lazy-loads rows in blocks, so groups cannot be built client-side."}],events:[{type:"grouping-state-change",description:"Emitted when groups are expanded/collapsed. Subscribers can react to row visibility changes."}],queries:[{type:"canMoveRow",description:"Returns false for group header rows (cannot be reordered)"}],configRules:[{id:"groupingRows/accordion-defaultExpanded",severity:"warn",message:'"accordion: true" and "defaultExpanded" (non-false) are used together.\n → In accordion mode, only one group can be open at a time.\n → Using defaultExpanded with multiple groups will collapse to one on first toggle.\n → Consider using "defaultExpanded: false" or a single group key/index with accordion mode.',check:e=>!0===e.accordion&&!1!==e.defaultExpanded&&void 0!==e.defaultExpanded&&!("number"==typeof e.defaultExpanded)&&!("string"==typeof e.defaultExpanded)&&(!0===e.defaultExpanded||Array.isArray(e.defaultExpanded)&&e.defaultExpanded.length>1)}]};name="groupingRows";styles="@layer tbw-plugins{.group-row{display:grid;grid-template-columns:var(--tbw-column-template);background:var(--tbw-grouping-rows-bg, var(--tbw-color-panel-bg));font-weight:500;border-bottom:var(--tbw-row-divider);min-height:var(--tbw-row-height)}.group-row .cell{display:flex;align-items:center;padding:var(--tbw-cell-padding, .125rem .5rem)}@media(hover:hover){.group-row:hover{background:var(--tbw-grouping-rows-bg-hover, var(--tbw-color-row-hover))}}.group-toggle{cursor:pointer;-webkit-user-select:none;user-select:none;display:inline-flex;align-items:center;justify-content:center;width:var(--tbw-toggle-size, 1.25rem);height:var(--tbw-toggle-size, 1.25rem);margin-right:.25rem;background:none;border:0;font:inherit}.group-toggle:hover{background:var(--tbw-grouping-rows-toggle-hover, var(--tbw-color-row-hover));border-radius:var(--tbw-border-radius, .125rem)}.group-label{display:inline-flex;align-items:center;gap:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem))}.group-count{color:var(--tbw-grouping-rows-count-color, var(--tbw-color-fg-muted));font-size:var(--tbw-font-size-xs, .85em);font-weight:400}.group-aggregates{display:inline-flex;align-items:center;gap:var(--tbw-spacing-lg, 1rem);margin-left:var(--tbw-spacing-lg, 1rem);font-weight:400;font-size:var(--tbw-font-size-sm, .875em);color:var(--tbw-grouping-rows-aggregate-color, var(--tbw-color-fg-muted))}.group-aggregate{white-space:nowrap}.group-row{padding-left:calc(var(--tbw-group-depth, 0) * var(--tbw-group-indent-width, 1.25em))}.data-grid-row.tbw-group-slide-in{animation:tbw-group-slide-in var(--tbw-animation-duration, .2s) var(--tbw-animation-easing, ease-out) forwards}@keyframes tbw-group-slide-in{0%{opacity:0;transform:translate(-8px)}to{opacity:1;transform:translate(0)}}.data-grid-row.tbw-group-fade-in{animation:tbw-group-fade-in var(--tbw-animation-duration, .2s) var(--tbw-animation-easing, ease-out) forwards}@keyframes tbw-group-fade-in{0%{opacity:0}to{opacity:1}}}";get defaultConfig(){return{defaultExpanded:!1,showRowCount:!0,indentWidth:20,aggregators:{},animation:"slide",accordion:!1}}expandedKeys=/* @__PURE__ */new Set;flattenedRows=[];isActive=!1;previousVisibleKeys=/* @__PURE__ */new Set;keysToAnimate=/* @__PURE__ */new Set;hasAppliedDefaultExpanded=!1;get animationStyle(){return!!this.isAnimationEnabled&&(this.config.animation??"slide")}detach(){this.expandedKeys.clear(),this.flattenedRows=[],this.isActive=!1,this.previousVisibleKeys.clear(),this.keysToAnimate.clear(),this.hasAppliedDefaultExpanded=!1}getRowHeight(e,t){if(null!=this.config.groupRowHeight)return!0===e.__isGroupRow?this.config.groupRowHeight:void 0}handleQuery(e){if("canMoveRow"===e.type){const t=e.context;if(!0===t?.__isGroupRow)return!1}}static detect(e,t){return"function"==typeof t?.groupOn||"boolean"==typeof t?.enableRowGrouping}processRows(e){const t=this.config;if("function"!=typeof t.groupOn)return this.isActive=!1,this.flattenedRows=[],[...e];const r=v({rows:[...e],config:t,expanded:/* @__PURE__ */new Set});if(0===r.length)return this.isActive=!1,this.flattenedRows=[],[...e];let n;if(!this.hasAppliedDefaultExpanded&&0===this.expandedKeys.size&&!1!==t.defaultExpanded){const e=function(e){return e.filter(e=>"group"===e.kind).map(e=>e.key)}(r);n=function(e,t){if(!0===e)return new Set(t);if(!1===e||null==e)/* @__PURE__ */
|
|
2
|
-
return new Set;if("number"==typeof e){const r=t[e];return r?/* @__PURE__ */new Set([r]):/* @__PURE__ */new Set}return"string"==typeof e?/* @__PURE__ */new Set([e]):Array.isArray(e)?new Set(e):/* @__PURE__ */new Set}(t.defaultExpanded??!1,e),n.size>0&&(this.expandedKeys=new Set(n),this.hasAppliedDefaultExpanded=!0)}const o=v({rows:[...e],config:t,expanded:this.expandedKeys,initialExpanded:n});this.isActive=!0,this.flattenedRows=o,this.keysToAnimate.clear();const i=/* @__PURE__ */new Set;return o.forEach((e,t)=>{if("data"===e.kind){const e=`data-${t}`;i.add(e),this.previousVisibleKeys.has(e)||this.keysToAnimate.add(e)}}),this.previousVisibleKeys=i,o.map(e=>{return"group"===e.kind?{__isGroupRow:!0,__groupKey:e.key,__groupValue:e.value,__groupDepth:e.depth,__groupRows:e.rows,__groupExpanded:e.expanded,__groupRowCount:(t=e,"group"!==t.kind?0:t.rows.length),__rowCacheKey:`group:${e.key}`}:e.row;var t})}onCellClick(e){const r=e.row;if(r?.__isGroupRow){const n=e.originalEvent.target;if(n?.closest(`.${t}`))return this.toggle(r.__groupKey),!0}}onKeyDown(e){if(" "!==e.key)return;const t=this.grid._focusRow,r=this.rows[t];return r?.__isGroupRow?(e.preventDefault(),this.toggle(r.__groupKey),this.requestRenderWithFocus(),!0):void 0}renderRow(e,t,r){if(!e?.__isGroupRow)return!1;const n=this.config;if(n.groupRowRenderer){const r=()=>{this.toggle(e.__groupKey)},o=n.groupRowRenderer({key:e.__groupKey,value:e.__groupValue,depth:e.__groupDepth,rows:e.__groupRows,expanded:e.__groupExpanded,toggleExpand:r});if(o)return t.className="data-grid-row group-row",t.__isCustomRow=!0,t.setAttribute("data-group-depth",String(e.__groupDepth)),"string"==typeof o?t.innerHTML=o:(t.innerHTML="",t.appendChild(o)),!0}const o=()=>{this.toggle(e.__groupKey)};t.className="data-grid-row group-row",t.__isCustomRow=!0,t.setAttribute("data-group-depth",String(e.__groupDepth)),t.setAttribute("role","row"),t.setAttribute("aria-expanded",String(e.__groupExpanded)),t.style.setProperty("--tbw-group-depth",String(e.__groupDepth||0)),void 0!==n.indentWidth&&t.style.setProperty("--tbw-group-indent-width",`${n.indentWidth}px`),t.style.height="",t.innerHTML="";return!1!==n.fullWidth?this.renderFullWidthGroupRow(e,t,o):this.renderPerColumnGroupRow(e,t,o),!0}afterRender(){const e=this.animationStyle;if(!1===e||0===this.keysToAnimate.size)return;const t=this.gridElement?.querySelector(".rows");if(!t)return;const r="fade"===e?"tbw-group-fade-in":"tbw-group-slide-in";for(const n of t.querySelectorAll(".data-grid-row:not(.group-row)")){const e=n.querySelector(".cell[data-row]"),t=e?parseInt(e.getAttribute("data-row")??"-1",10):-1,o=this.flattenedRows[t],i="data"===o?.kind?`data-${t}`:void 0;i&&this.keysToAnimate.has(i)&&(n.classList.add(r),n.addEventListener("animationend",()=>n.classList.remove(r),{once:!0}))}this.keysToAnimate.clear()}createToggleButton(r,n){const o=document.createElement("button");return o.type="button",o.className=`${t}${r?` ${e}`:""}`,o.setAttribute("aria-label",r?"Collapse group":"Expand group"),this.setIcon(o,r?"collapse":"expand"),o.addEventListener("click",e=>{e.stopPropagation(),n()}),o}getGroupLabelText(e,t,r){const n=this.config;return n.formatLabel?n.formatLabel(e,t,r):String(e)}renderFullWidthGroupRow(e,t,o){const i=this.config,a=i.aggregators??{},d=e.__groupRows??[],l=document.createElement("div");l.className="cell group-full",l.style.gridColumn="1 / -1",l.setAttribute("role","gridcell"),l.setAttribute("data-col","0"),l.appendChild(this.createToggleButton(e.__groupExpanded,o));const u=document.createElement("span");if(u.className=r,u.textContent=this.getGroupLabelText(e.__groupValue,e.__groupDepth||0,e.__groupKey),l.appendChild(u),!1!==i.showRowCount){const t=document.createElement("span");t.className=n,t.textContent=`(${e.__groupRowCount??e.__groupRows?.length??0})`,l.appendChild(t)}const g=Object.entries(a);if(g.length>0){const e=document.createElement("span");e.className="group-aggregates";for(const[t,r]of g){const n=this.columns.find(e=>e.field===t),o=s.run(r,d,t,n);if(null!=o){const r=document.createElement("span");r.className="group-aggregate",r.setAttribute("data-field",t);const i=n?.header??t;r.textContent=`${i}: ${o}`,e.appendChild(r)}}e.children.length>0&&l.appendChild(e)}t.appendChild(l)}renderPerColumnGroupRow(e,t,r){const o=this.config,i=o.aggregators??{},a=this.columns,d=e.__groupRows??[],l=this.gridElement?.querySelector(".body"),u=l?.style.gridTemplateColumns||"";u&&(t.style.display="grid",t.style.gridTemplateColumns=u);let g=!1;a.forEach((a,l)=>{const u=document.createElement("div");if(u.className="cell group-cell",u.setAttribute("data-col",String(l)),u.setAttribute("role","gridcell"),"__tbw_expander"===a.field)return u.setAttribute("data-field",a.field),void t.appendChild(u);if(g){const e=i[a.field];if(e){const t=s.run(e,d,a.field,a);u.textContent=null!=t?String(t):""}else u.textContent=""}else{g=!0,u.appendChild(this.createToggleButton(e.__groupExpanded,r));const t=document.createElement("span"),l=i[a.field];if(l){const r=s.run(l,d,a.field,a);t.textContent=String(null!=r?r:e.__groupValue)}else t.textContent=this.getGroupLabelText(e.__groupValue,e.__groupDepth||0,e.__groupKey);if(u.appendChild(t),!1!==o.showRowCount){const e=document.createElement("span");e.className=n,e.textContent=` (${d.length})`,u.appendChild(e)}}t.appendChild(u)})}expandAll(){this.expandedKeys=function(e){const t=/* @__PURE__ */new Set;for(const r of e)"group"===r.kind&&t.add(r.key);return t}(this.flattenedRows),this.emitPluginEvent("grouping-state-change",{expandedKeys:[...this.expandedKeys]}),this.requestRender()}collapseAll(){this.expandedKeys=/* @__PURE__ */new Set,this.emitPluginEvent("grouping-state-change",{expandedKeys:[...this.expandedKeys]}),this.requestRender()}toggle(e){const t=!this.expandedKeys.has(e),r=this.config,n=this.flattenedRows.find(t=>"group"===t.kind&&t.key===e);if(r.accordion&&t&&n){const t=/* @__PURE__ */new Set;for(const r of this.expandedKeys)if(e.startsWith(r+"||")||r.startsWith(e+"||"))e.startsWith(r+"||")&&t.add(r);else{const e=this.flattenedRows.find(e=>"group"===e.kind&&e.key===r);e&&e.depth!==n.depth&&t.add(r)}t.add(e),this.expandedKeys=t}else this.expandedKeys=function(e,t){const r=new Set(e);return r.has(t)?r.delete(t):r.add(t),r}(this.expandedKeys,e);this.emit("group-toggle",{key:e,expanded:this.expandedKeys.has(e),value:n?.value,depth:n?.depth??0});const o=this.expandedKeys.has(e),i=null!=n?.value?String(n.value):e;if(o){const e=n?.rows?.length??0;u(this.gridElement,g(this.gridElement,"groupExpanded",i,e))}else u(this.gridElement,g(this.gridElement,"groupCollapsed",i));this.emitPluginEvent("grouping-state-change",{expandedKeys:[...this.expandedKeys]}),this.requestRender()}isExpanded(e){return this.expandedKeys.has(e)}expand(e){this.expandedKeys.has(e)||(this.expandedKeys=/* @__PURE__ */new Set([...this.expandedKeys,e]),this.requestRender())}collapse(e){if(this.expandedKeys.has(e)){const t=new Set(this.expandedKeys);t.delete(e),this.expandedKeys=t,this.requestRender()}}getGroupState(){const e=this.flattenedRows.filter(e=>"group"===e.kind);return{isActive:this.isActive,expandedCount:this.expandedKeys.size,totalGroups:e.length,expandedKeys:[...this.expandedKeys]}}getRowCount(){return this.flattenedRows.length}refreshGroups(){this.requestRender()}getExpandedGroups(){return[...this.expandedKeys]}getFlattenedRows(){return this.flattenedRows}isGroupingActive(){return this.isActive}setGroupOn(e){this.config.groupOn=e,this.requestRender()}}export{_ as GroupingRowsPlugin};
|
|
1
|
+
const e="expanded",t="group-toggle",r="group-label",n="group-count",o={sum:(e,t)=>{let r=0;for(let n=0;n<e.length;n++)r+=Number(e[n][t])||0;return r},avg:(e,t)=>{if(!e.length)return 0;let r=0;for(let n=0;n<e.length;n++)r+=Number(e[n][t])||0;return r/e.length},count:e=>e.length,min:(e,t)=>{if(!e.length)return 0;let r=1/0;for(let n=0;n<e.length;n++){const o=Number(e[n][t]);o<r&&(r=o)}return r},max:(e,t)=>{if(!e.length)return 0;let r=-1/0;for(let n=0;n<e.length;n++){const o=Number(e[n][t]);o>r&&(r=o)}return r},first:(e,t)=>e[0]?.[t],last:(e,t)=>e[e.length-1]?.[t]},i=/* @__PURE__ */new Map,s={register(e,t){i.set(e,t)},unregister(e){i.delete(e)},get(e){if(void 0!==e)return"function"==typeof e?e:i.get(e)??o[e]},run(e,t,r,n){const o=this.get(e);return o?o(t,r,n):void 0},has:e=>i.has(e)||e in o,list:()=>[...Object.keys(o),...i.keys()]},a={sortApplied:(e,t)=>`Sorted by ${e}, ${t}`,sortCleared:()=>"Sort cleared",filterApplied:e=>`Filter applied on ${e}`,filterCleared:e=>`Filter cleared from ${e}`,allFiltersCleared:()=>"All filters cleared",groupExpanded:(e,t)=>`Group ${e} expanded, ${t} rows`,groupCollapsed:e=>`Group ${e} collapsed`,selectionChanged:e=>`${e} rows selected`,editingStarted:e=>`Editing row ${e+1}`,editingCommitted:e=>`Row ${e+1} saved`,dataLoaded:e=>`${e} rows loaded`},d='<svg viewBox="0 0 16 16" width="12" height="12"><path fill="currentColor" d="M6 10.5a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zm-2-3a.5.5 0 0 1 .5-.5h11a.5.5 0 0 1 0 1h-11a.5.5 0 0 1-.5-.5z"/></svg>',l={expand:"▶",collapse:"▼",sortAsc:"▲",sortDesc:"▼",sortNone:"⇅",submenuArrow:"▶",dragHandle:"⋮⋮",toolPanel:"☰",filter:d,filterActive:d,print:"🖨️"};function u(e,t){if(!e)return;const r="effectiveConfig"in e?e.effectiveConfig:void 0;if(!1===r?.a11y?.announcements)return;const n=e.querySelector?.(".tbw-sr-only");n&&(n.textContent="",requestAnimationFrame(()=>{n.textContent=t}))}function p(e,t,...r){const n=e&&"effectiveConfig"in e?e.effectiveConfig:void 0,o=n?.a11y?.messages?.[t];return o?o(...r):a[t](...r)}function g(e,t){return`[tbw-grid${e?`#${e}`:""}${t?`:${t}`:""}]`}function h(e,t,r,n){return`${g(r,n)} ${e}: ${t}\n\n → More info: ${function(e){return`https://toolboxjs.com/grid/errors#${e.toLowerCase()}`}(e)}`}["__otorp__","__retteGenifed__","__retteSenifed__","rotcurtsnoc","wodniw","sihTlabolg","labolg","ssecorp","noitcnuF","tropmi","lave","tcelfeR","yxorP","rorrE","stnemugra","tnemucod","noitacol","eikooc","egarotSlacol","egarotSnoisses","BDdexedni","hctef","tseuqeRpttHLMX","tekcoSbeW","rekroW","rekroWderahS","rekroWecivreS","renepo","tnerap","pot","semarf","fles"].map(e=>e.split("").reverse().join(""));const c=/* @__PURE__ */new Set(["script","iframe","object","embed","form","input","button","textarea","select","link","meta","base","style","template","slot","portal","frame","frameset","applet","noscript","noembed","plaintext","xmp","listing"]),f=/^on\w+$/i,w=/* @__PURE__ */new Set(["href","src","action","formaction","data","srcdoc","xlink:href","poster","srcset"]),m=/^\s*(javascript|vbscript|data|blob):/i;function y(e){if(!e||"string"!=typeof e)return"";if(-1===e.indexOf("<"))return e;const t=document.createElement("template");return t.innerHTML=e,function(e){const t=[],r=e.querySelectorAll("*");for(const n of r){const e=n.tagName.toLowerCase();if(c.has(e)){t.push(n);continue}if("svg"===e||"http://www.w3.org/2000/svg"===n.namespaceURI){if(Array.from(n.attributes).some(e=>f.test(e.name)||"href"===e.name||"xlink:href"===e.name)){t.push(n);continue}}const r=[];for(const t of n.attributes){const e=t.name.toLowerCase();f.test(e)?r.push(t.name):(w.has(e)&&m.test(t.value)||"style"===e&&/expression\s*\(|javascript:|behavior\s*:/i.test(t.value))&&r.push(t.name)}r.forEach(e=>n.removeAttribute(e))}t.forEach(e=>e.remove())}(t.content),t.innerHTML}class b{static dependencies;static manifest;aliases;version="undefined"!=typeof __GRID_VERSION__?__GRID_VERSION__:"dev";styles;cellRenderers;headerRenderers;cellEditors;grid;config;userConfig;#e;get defaultConfig(){return{}}constructor(e={}){this.userConfig=e}attach(e){this.#e?.abort(),this.#e=new AbortController,this.grid=e,this.config={...this.defaultConfig,...this.userConfig}}detach(){this.#e?.abort(),this.#e=void 0}getPlugin(e){return this.grid?.getPlugin(e)}emit(e,t){this.grid?.dispatchEvent?.(new CustomEvent(e,{detail:t,bubbles:!0}))}emitCancelable(e,t){const r=new CustomEvent(e,{detail:t,bubbles:!0,cancelable:!0});return this.grid?.dispatchEvent?.(r),r.defaultPrevented}on(e,t){this.grid?._pluginManager?.subscribe(this,e,t)}off(e){this.grid?._pluginManager?.unsubscribe(this,e)}emitPluginEvent(e,t){this.grid?._pluginManager?.emitPluginEvent(e,t)}requestRender(){this.grid?.requestRender?.()}requestColumnsRender(){this.grid?.requestColumnsRender?.()}requestRenderWithFocus(){this.grid?.requestRenderWithFocus?.()}requestAfterRender(){this.grid?.requestAfterRender?.()}requestVirtualRefresh(){this.grid?.requestVirtualRefresh?.()}get rows(){return this.grid?.rows??[]}get sourceRows(){return this.grid?.sourceRows??[]}get columns(){return this.grid?.columns??[]}get visibleColumns(){return this.grid?._visibleColumns??[]}get gridElement(){return this.grid?._hostElement}get disconnectSignal(){return this.#e?.signal??this.grid?.disconnectSignal}get gridIcons(){const e=this.grid?.gridConfig?.icons??{};return{...l,...e}}get isAnimationEnabled(){const e=this.grid?.effectiveConfig?.animation?.mode??"reduced-motion";if(!1===e||"off"===e)return!1;if(!0===e||"on"===e)return!0;const t=this.gridElement;if(t){return"0"!==getComputedStyle(t).getPropertyValue("--tbw-animation-enabled").trim()}return!0}get animationDuration(){const e=this.gridElement;if(e){const t=getComputedStyle(e).getPropertyValue("--tbw-animation-duration").trim(),r=parseInt(t,10);if(!isNaN(r))return r}return 200}setIcon(e,t,r){e.dataset.icon=t.replace(/([A-Z])/g,"-$1").toLowerCase(),"collapse"===t?e.dataset.expanded="":"expand"===t&&delete e.dataset.expanded;const n=this.#t(t,r);void 0!==n?"string"==typeof n?e.innerHTML=y(n):n instanceof HTMLElement&&(e.innerHTML="",e.appendChild(n.cloneNode(!0))):e.innerHTML=""}#t(e,t){return void 0!==t?t:this.grid?.gridConfig?.icons?.[e]}updateSortIndicator(e,t){e.querySelector('[part~="sort-indicator"], .sort-indicator')?.remove();const r=document.createElement("span");r.setAttribute("part","sort-indicator"),r.className="sort-indicator",t?(e.setAttribute("aria-sort","asc"===t?"ascending":"descending"),e.setAttribute("data-sort",t),this.setIcon(r,"asc"===t?"sortAsc":"sortDesc")):(e.setAttribute("aria-sort","none"),e.removeAttribute("data-sort"),this.setIcon(r,"sortNone"));const n=e.querySelector(".tbw-filter-btn")??e.querySelector(".resize-handle");return n?e.insertBefore(r,n):e.appendChild(r),r}warn(e,t){void 0!==t?console.warn(h(e,t,this.gridElement.id,this.name)):console.warn(`${g(this.gridElement.id,this.name)} ${e}`)}throwDiagnostic(e,t){throw new Error(h(e,t,this.gridElement.id,this.name))}}function _({rows:e,config:t,expanded:r,initialExpanded:n}){const o=t.groupOn;if("function"!=typeof o)return[];const i={key:"__root__",value:null,depth:-1,rows:[],children:/* @__PURE__ */new Map};if(e.forEach(e=>{let t=o(e);null==t||!1===t?t=["__ungrouped__"]:Array.isArray(t)||(t=[t]);let r=i;t.forEach((t,n)=>{const o=null==t?"∅":String(t),i="__root__"===r.key?o:r.key+"||"+o;let s=r.children.get(o);s||(s={key:i,value:t,depth:n,rows:[],children:/* @__PURE__ */new Map,parent:r},r.children.set(o,s)),s.rows.push(e),r=s})}),1===i.children.size&&i.children.has("__ungrouped__")){if(i.children.get("__ungrouped__").rows.length===e.length)return[]}const s=/* @__PURE__ */new Map;for(let u=0;u<e.length;u++)s.set(e[u],u);const a=/* @__PURE__ */new Set([...r,...n??[]]),d=[],l=e=>{if(e===i)return void e.children.forEach(e=>l(e));const t=a.has(e.key);d.push({kind:"group",key:e.key,value:e.value,depth:e.depth,rows:e.rows,expanded:t}),t&&(e.children.size?e.children.forEach(e=>l(e)):e.rows.forEach(e=>d.push({kind:"data",row:e,rowIndex:s.get(e)??-1})))};return l(i),d}function v(e,t){if(!0===e)return new Set(t);if(!1===e||null==e)/* @__PURE__ */
|
|
2
|
+
return new Set;if("number"==typeof e){const r=t[e];return r?/* @__PURE__ */new Set([r]):/* @__PURE__ */new Set}return"string"==typeof e?/* @__PURE__ */new Set([e]):Array.isArray(e)?new Set(e):/* @__PURE__ */new Set}function x({groups:e,expanded:t,groupRows:r,loadingGroups:n,parentPath:o=[]}){const i=[],s=o.length;for(const a of e){const e=[...o,a.key],d=t.has(a.key),l=r.get(a.key)??[],u=n.has(a.key);if(i.push({kind:"group",key:a.key,value:a.value,depth:s,rows:l,expanded:d}),d)if(a.children?.length){const o=x({groups:a.children,expanded:t,groupRows:r,loadingGroups:n,parentPath:e});i.push(...o)}else u?i.push({kind:"data",row:{__loading:!0,__groupKey:a.key},rowIndex:-1}):l.forEach((e,t)=>{i.push({kind:"data",row:e,rowIndex:t})})}return i}function R(e,t,r=[]){for(const n of e){const e=[...r,n.key];if(n.key===t)return e;if(n.children?.length){const r=R(n.children,t,e);if(r.length>0)return r}}return[]}class E extends b{static manifest={incompatibleWith:[{name:"tree",reason:"Both plugins transform the entire row model. TreePlugin flattens nested hierarchies while GroupingRowsPlugin groups flat rows with synthetic headers. Use one approach per grid."},{name:"pivot",reason:"PivotPlugin creates its own aggregated row and column structure. Row grouping cannot be applied on top of pivot-generated rows."}],events:[{type:"grouping-state-change",description:"Emitted when groups are expanded/collapsed. Subscribers can react to row visibility changes."},{type:"group-expand",description:"Emitted when a pre-defined group is expanded. Use to lazily load group row data."},{type:"group-collapse",description:"Emitted when a pre-defined group is collapsed."}],queries:[{type:"canMoveRow",description:"Returns false for group header rows (cannot be reordered)"}],configRules:[{id:"groupingRows/accordion-defaultExpanded",severity:"warn",message:'"accordion: true" and "defaultExpanded" (non-false) are used together.\n → In accordion mode, only one group can be open at a time.\n → Using defaultExpanded with multiple groups will collapse to one on first toggle.\n → Consider using "defaultExpanded: false" or a single group key/index with accordion mode.',check:e=>!0===e.accordion&&!1!==e.defaultExpanded&&void 0!==e.defaultExpanded&&!("number"==typeof e.defaultExpanded)&&!("string"==typeof e.defaultExpanded)&&(!0===e.defaultExpanded||Array.isArray(e.defaultExpanded)&&e.defaultExpanded.length>1)}]};name="groupingRows";styles="@layer tbw-plugins{.group-row{display:grid;grid-template-columns:var(--tbw-column-template);background:var(--tbw-grouping-rows-bg, var(--tbw-color-panel-bg));font-weight:500;border-bottom:var(--tbw-row-divider);min-height:var(--tbw-row-height)}.group-row .cell{display:flex;align-items:center;padding:var(--tbw-cell-padding, .125rem .5rem)}@media(hover:hover){.group-row:hover{background:var(--tbw-grouping-rows-bg-hover, var(--tbw-color-row-hover))}}.group-toggle{cursor:pointer;-webkit-user-select:none;user-select:none;display:inline-flex;align-items:center;justify-content:center;width:var(--tbw-toggle-size, 1.25rem);height:var(--tbw-toggle-size, 1.25rem);margin-right:.25rem;background:none;border:0;font:inherit}.group-toggle:hover{background:var(--tbw-grouping-rows-toggle-hover, var(--tbw-color-row-hover));border-radius:var(--tbw-border-radius, .125rem)}.group-label{display:inline-flex;align-items:center;gap:var(--tbw-panel-gap, var(--tbw-spacing-md, .5rem))}.group-count{color:var(--tbw-grouping-rows-count-color, var(--tbw-color-fg-muted));font-size:var(--tbw-font-size-xs, .85em);font-weight:400}.group-aggregates{display:inline-flex;align-items:center;gap:var(--tbw-spacing-lg, 1rem);margin-left:var(--tbw-spacing-lg, 1rem);font-weight:400;font-size:var(--tbw-font-size-sm, .875em);color:var(--tbw-grouping-rows-aggregate-color, var(--tbw-color-fg-muted))}.group-aggregate{white-space:nowrap}.group-row{padding-left:calc(var(--tbw-group-depth, 0) * var(--tbw-group-indent-width, 1.25em))}.data-grid-row.tbw-group-slide-in{animation:tbw-group-slide-in var(--tbw-animation-duration, .2s) var(--tbw-animation-easing, ease-out) forwards}@keyframes tbw-group-slide-in{0%{opacity:0;transform:translate(-8px)}to{opacity:1;transform:translate(0)}}.data-grid-row.tbw-group-fade-in{animation:tbw-group-fade-in var(--tbw-animation-duration, .2s) var(--tbw-animation-easing, ease-out) forwards}@keyframes tbw-group-fade-in{0%{opacity:0}to{opacity:1}}}";get defaultConfig(){return{defaultExpanded:!1,showRowCount:!0,indentWidth:20,aggregators:{},animation:"slide",accordion:!1}}expandedKeys=/* @__PURE__ */new Set;flattenedRows=[];isActive=!1;previousVisibleKeys=/* @__PURE__ */new Set;keysToAnimate=/* @__PURE__ */new Set;hasAppliedDefaultExpanded=!1;preDefinedGroups=[];groupRowsMap=/* @__PURE__ */new Map;loadingGroups=/* @__PURE__ */new Set;groupsFetchInFlight=!1;rowsFetchInFlight=/* @__PURE__ */new Set;get animationStyle(){return!!this.isAnimationEnabled&&(this.config.animation??"slide")}detach(){this.expandedKeys.clear(),this.flattenedRows=[],this.isActive=!1,this.previousVisibleKeys.clear(),this.keysToAnimate.clear(),this.hasAppliedDefaultExpanded=!1,this.preDefinedGroups=[],this.groupRowsMap.clear(),this.loadingGroups.clear(),this.groupsFetchInFlight=!1,this.rowsFetchInFlight.clear()}getRowHeight(e,t){if(null!=this.config.groupRowHeight)return!0===e.__isGroupRow?this.config.groupRowHeight:void 0}handleQuery(e){if("canMoveRow"===e.type){const t=e.context;if(!0===t?.__isGroupRow)return!1}}static detect(e,t){return"function"==typeof t?.groupOn||"boolean"==typeof t?.enableRowGrouping||Array.isArray(t?.groups)||"function"==typeof t?.groups}processRows(e){if(this.preDefinedGroups.length>0||null!=this.config.groups)return"function"!=typeof this.config.groups||0!==this.preDefinedGroups.length||this.groupsFetchInFlight?this.preDefinedGroups.length>0||Array.isArray(this.config.groups)&&this.config.groups.length>0?this.processPreDefinedGroups():(this.isActive="function"==typeof this.config.groups,this.flattenedRows=[],[]):(this.fetchGroupsAsync(this.config.groups),this.isActive=!0,this.flattenedRows=[],[]);const t=this.config;if("function"!=typeof t.groupOn)return this.isActive=!1,this.flattenedRows=[],[...e];const r=_({rows:[...e],config:t,expanded:/* @__PURE__ */new Set});if(0===r.length)return this.isActive=!1,this.flattenedRows=[],[...e];let n;if(!this.hasAppliedDefaultExpanded&&0===this.expandedKeys.size&&!1!==t.defaultExpanded){const e=function(e){return e.filter(e=>"group"===e.kind).map(e=>e.key)}(r);n=v(t.defaultExpanded??!1,e),n.size>0&&(this.expandedKeys=new Set(n),this.hasAppliedDefaultExpanded=!0)}const o=_({rows:[...e],config:t,expanded:this.expandedKeys,initialExpanded:n});this.isActive=!0,this.flattenedRows=o,this.keysToAnimate.clear();const i=/* @__PURE__ */new Set;return o.forEach((e,t)=>{if("data"===e.kind){const e=`data-${t}`;i.add(e),this.previousVisibleKeys.has(e)||this.keysToAnimate.add(e)}}),this.previousVisibleKeys=i,o.map(e=>{return"group"===e.kind?{__isGroupRow:!0,__groupKey:e.key,__groupValue:e.value,__groupDepth:e.depth,__groupRows:e.rows,__groupExpanded:e.expanded,__groupRowCount:(t=e,"group"!==t.kind?0:t.rows.length),__rowCacheKey:`group:${e.key}`}:e.row;var t})}onCellClick(e){const r=e.row;if(r?.__isGroupRow){const n=e.originalEvent.target;if(n?.closest(`.${t}`))return this.toggle(r.__groupKey),!0}}onKeyDown(e){if(" "!==e.key)return;const t=this.grid._focusRow,r=this.rows[t];return r?.__isGroupRow?(e.preventDefault(),this.toggle(r.__groupKey),this.requestRenderWithFocus(),!0):void 0}renderRow(e,t,r){if(!0===e?.__loading&&e?.__groupKey){t.className="data-grid-row",t.__isCustomRow=!0,t.innerHTML="";const e=document.createElement("div");return e.className="cell",e.style.gridColumn="1 / -1",e.setAttribute("role","gridcell"),e.textContent=" ",t.appendChild(e),function(e){if(e.classList.add("tbw-row-loading"),e.setAttribute("aria-busy","true"),!e.querySelector(".tbw-row-loading-overlay")){const t=document.createElement("div");t.className="tbw-row-loading-overlay",t.setAttribute("aria-hidden","true");const r=document.createElement("div");r.className="tbw-row-loading-spinner",t.appendChild(r),e.appendChild(t)}}(t),!0}if(!e?.__isGroupRow)return!1;const n=this.config;if(n.groupRowRenderer){const r=()=>{this.toggle(e.__groupKey)},o=n.groupRowRenderer({key:e.__groupKey,value:e.__groupValue,depth:e.__groupDepth,rows:e.__groupRows,expanded:e.__groupExpanded,toggleExpand:r});if(o)return t.className="data-grid-row group-row",t.__isCustomRow=!0,t.setAttribute("data-group-depth",String(e.__groupDepth)),"string"==typeof o?t.innerHTML=o:(t.innerHTML="",t.appendChild(o)),!0}const o=()=>{this.toggle(e.__groupKey)};t.className="data-grid-row group-row",t.__isCustomRow=!0,t.setAttribute("data-group-depth",String(e.__groupDepth)),t.setAttribute("role","row"),t.setAttribute("aria-expanded",String(e.__groupExpanded)),t.style.setProperty("--tbw-group-depth",String(e.__groupDepth||0)),void 0!==n.indentWidth&&t.style.setProperty("--tbw-group-indent-width",`${n.indentWidth}px`),t.style.height="",t.innerHTML="";return!1!==n.fullWidth?this.renderFullWidthGroupRow(e,t,o):this.renderPerColumnGroupRow(e,t,o),!0}afterRender(){const e=this.animationStyle;if(!1===e||0===this.keysToAnimate.size)return;const t=this.gridElement?.querySelector(".rows");if(!t)return;const r="fade"===e?"tbw-group-fade-in":"tbw-group-slide-in";for(const n of t.querySelectorAll(".data-grid-row:not(.group-row)")){const e=n.querySelector(".cell[data-row]"),t=e?parseInt(e.getAttribute("data-row")??"-1",10):-1,o=this.flattenedRows[t],i="data"===o?.kind?`data-${t}`:void 0;i&&this.keysToAnimate.has(i)&&(n.classList.add(r),n.addEventListener("animationend",()=>n.classList.remove(r),{once:!0}))}this.keysToAnimate.clear()}processPreDefinedGroups(){const e=this.preDefinedGroups.length>0?this.preDefinedGroups:Array.isArray(this.config.groups)?this.config.groups:[];if(0===e.length)return this.isActive=!1,this.flattenedRows=[],[];if(!this.hasAppliedDefaultExpanded&&0===this.expandedKeys.size&&!1!==this.config.defaultExpanded){const t=this.collectGroupKeys(e),r=v(this.config.defaultExpanded??!1,t);r.size>0&&(this.expandedKeys=new Set(r),this.hasAppliedDefaultExpanded=!0)}const t=x({groups:e,expanded:this.expandedKeys,groupRows:this.groupRowsMap,loadingGroups:this.loadingGroups});this.isActive=!0,this.flattenedRows=t,this.keysToAnimate.clear();const r=/* @__PURE__ */new Set;return t.forEach((e,t)=>{if("data"===e.kind){const e=`data-${t}`;r.add(e),this.previousVisibleKeys.has(e)||this.keysToAnimate.add(e)}}),this.previousVisibleKeys=r,t.map(t=>{if("group"===t.kind){const r=this.findGroupDefinition(e,t.key),n=r?.rowCount??t.rows.length;return{__isGroupRow:!0,__groupKey:t.key,__groupValue:t.value,__groupDepth:t.depth,__groupRows:t.rows,__groupExpanded:t.expanded,__groupRowCount:n,__rowCacheKey:`group:${t.key}`}}return t.row})}fetchGroupsAsync(e){this.groupsFetchInFlight=!0,e().then(e=>{this.groupsFetchInFlight=!1,this.preDefinedGroups=e,this.requestRender()},()=>{this.groupsFetchInFlight=!1})}fetchGroupRowsAsync(e,t){const r=this.config.rows;r&&!this.rowsFetchInFlight.has(e)&&(this.rowsFetchInFlight.add(e),this.loadingGroups.add(e),this.requestRender(),r(t).then(t=>{this.rowsFetchInFlight.delete(e),this.groupRowsMap.set(e,t),this.loadingGroups.delete(e),this.requestRender()},()=>{this.rowsFetchInFlight.delete(e),this.loadingGroups.delete(e),this.requestRender()}))}collectGroupKeys(e){const t=[];for(const r of e)t.push(r.key),r.children?.length&&t.push(...this.collectGroupKeys(r.children));return t}getActiveGroups(){return this.preDefinedGroups.length>0?this.preDefinedGroups:Array.isArray(this.config.groups)?this.config.groups:[]}findGroupDefinition(e,t){for(const r of e){if(r.key===t)return r;if(r.children?.length){const e=this.findGroupDefinition(r.children,t);if(e)return e}}}createToggleButton(r,n){const o=document.createElement("button");return o.type="button",o.className=`${t}${r?` ${e}`:""}`,o.setAttribute("aria-label",r?"Collapse group":"Expand group"),this.setIcon(o,r?"collapse":"expand"),o.addEventListener("click",e=>{e.stopPropagation(),n()}),o}getGroupLabelText(e,t,r){const n=this.config;return n.formatLabel?n.formatLabel(e,t,r):String(e)}renderFullWidthGroupRow(e,t,o){const i=this.config,a=i.aggregators??{},d=e.__groupRows??[],l=document.createElement("div");l.className="cell group-full",l.style.gridColumn="1 / -1",l.setAttribute("role","gridcell"),l.setAttribute("data-col","0"),l.appendChild(this.createToggleButton(e.__groupExpanded,o));const u=document.createElement("span");if(u.className=r,u.textContent=this.getGroupLabelText(e.__groupValue,e.__groupDepth||0,e.__groupKey),l.appendChild(u),!1!==i.showRowCount){const t=document.createElement("span");t.className=n,t.textContent=`(${e.__groupRowCount??e.__groupRows?.length??0})`,l.appendChild(t)}const p=Object.entries(a);if(p.length>0){const e=document.createElement("span");e.className="group-aggregates";for(const[t,r]of p){const n=this.columns.find(e=>e.field===t),o=s.run(r,d,t,n);if(null!=o){const r=document.createElement("span");r.className="group-aggregate",r.setAttribute("data-field",t);const i=n?.header??t;r.textContent=`${i}: ${o}`,e.appendChild(r)}}e.children.length>0&&l.appendChild(e)}t.appendChild(l)}renderPerColumnGroupRow(e,t,r){const o=this.config,i=o.aggregators??{},a=this.columns,d=e.__groupRows??[],l=this.gridElement?.querySelector(".body"),u=l?.style.gridTemplateColumns||"";u&&(t.style.display="grid",t.style.gridTemplateColumns=u);let p=!1;a.forEach((a,l)=>{const u=document.createElement("div");if(u.className="cell group-cell",u.setAttribute("data-col",String(l)),u.setAttribute("role","gridcell"),"__tbw_expander"===a.field)return u.setAttribute("data-field",a.field),void t.appendChild(u);if(p){const e=i[a.field];if(e){const t=s.run(e,d,a.field,a);u.textContent=null!=t?String(t):""}else u.textContent=""}else{p=!0,u.appendChild(this.createToggleButton(e.__groupExpanded,r));const t=document.createElement("span"),l=i[a.field];if(l){const r=s.run(l,d,a.field,a);t.textContent=String(null!=r?r:e.__groupValue)}else t.textContent=this.getGroupLabelText(e.__groupValue,e.__groupDepth||0,e.__groupKey);if(u.appendChild(t),!1!==o.showRowCount){const e=document.createElement("span");e.className=n,e.textContent=` (${d.length})`,u.appendChild(e)}}t.appendChild(u)})}expandAll(){this.expandedKeys=function(e){const t=/* @__PURE__ */new Set;for(const r of e)"group"===r.kind&&t.add(r.key);return t}(this.flattenedRows),this.emitPluginEvent("grouping-state-change",{expandedKeys:[...this.expandedKeys]}),this.requestRender()}collapseAll(){this.expandedKeys=/* @__PURE__ */new Set,this.emitPluginEvent("grouping-state-change",{expandedKeys:[...this.expandedKeys]}),this.requestRender()}toggle(e){const t=!this.expandedKeys.has(e),r=this.config,n=this.flattenedRows.find(t=>"group"===t.kind&&t.key===e);if(r.accordion&&t&&n){const t=/* @__PURE__ */new Set;for(const r of this.expandedKeys)if(e.startsWith(r+"||")||r.startsWith(e+"||"))e.startsWith(r+"||")&&t.add(r);else{const e=this.flattenedRows.find(e=>"group"===e.kind&&e.key===r);e&&e.depth!==n.depth&&t.add(r)}t.add(e),this.expandedKeys=t}else this.expandedKeys=function(e,t){const r=new Set(e);return r.has(t)?r.delete(t):r.add(t),r}(this.expandedKeys,e);this.emit("group-toggle",{key:e,expanded:this.expandedKeys.has(e),value:n?.value,depth:n?.depth??0});const o=this.getActiveGroups();if(o.length>0){const n=R(o,e);if(t){if(this.emit("group-expand",{groupKey:e,groupPath:n}),r.rows&&!this.groupRowsMap.has(e)){const t=this.findGroupDefinition(o,e);t&&this.fetchGroupRowsAsync(e,t)}}else this.emit("group-collapse",{groupKey:e,groupPath:n})}const i=this.expandedKeys.has(e),s=null!=n?.value?String(n.value):e;if(i){const e=n?.rows?.length??0;u(this.gridElement,p(this.gridElement,"groupExpanded",s,e))}else u(this.gridElement,p(this.gridElement,"groupCollapsed",s));this.emitPluginEvent("grouping-state-change",{expandedKeys:[...this.expandedKeys]}),this.requestRender()}isExpanded(e){return this.expandedKeys.has(e)}expand(e){this.expandedKeys.has(e)||(this.expandedKeys=/* @__PURE__ */new Set([...this.expandedKeys,e]),this.requestRender())}collapse(e){if(this.expandedKeys.has(e)){const t=new Set(this.expandedKeys);t.delete(e),this.expandedKeys=t,this.requestRender()}}getGroupState(){const e=this.flattenedRows.filter(e=>"group"===e.kind);return{isActive:this.isActive,expandedCount:this.expandedKeys.size,totalGroups:e.length,expandedKeys:[...this.expandedKeys]}}getRowCount(){return this.flattenedRows.length}refreshGroups(){this.requestRender()}getExpandedGroups(){return[...this.expandedKeys]}getFlattenedRows(){return this.flattenedRows}isGroupingActive(){return this.isActive}setGroupOn(e){this.config.groupOn=e,this.requestRender()}setGroups(e){this.preDefinedGroups=e,this.groupRowsMap.clear(),this.loadingGroups.clear(),this.rowsFetchInFlight.clear(),this.expandedKeys.clear(),this.hasAppliedDefaultExpanded=!1,this.requestRender()}getGroups(){return this.preDefinedGroups.length>0?[...this.preDefinedGroups]:Array.isArray(this.config.groups)?[...this.config.groups]:[]}setGroupRows(e,t){this.groupRowsMap.set(e,t),this.loadingGroups.delete(e),this.requestRender()}setGroupLoading(e,t){t?this.loadingGroups.add(e):this.loadingGroups.delete(e),this.requestRender()}clearGroupRows(e){null!=e?(this.groupRowsMap.delete(e),this.rowsFetchInFlight.delete(e)):(this.groupRowsMap.clear(),this.rowsFetchInFlight.clear()),this.requestRender()}}export{E as GroupingRowsPlugin};
|
|
3
3
|
//# sourceMappingURL=index.js.map
|