@toolbox-web/grid 1.30.2 → 1.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/README.md +1 -1
  2. package/all.js +2 -2
  3. package/all.js.map +1 -1
  4. package/index.js +1 -1
  5. package/index.js.map +1 -1
  6. package/lib/core/internal/dom-builder.d.ts +3 -3
  7. package/lib/core/plugin/base-plugin.d.ts +31 -8
  8. package/lib/core/plugin/plugin-manager.d.ts +2 -2
  9. package/lib/core/types.d.ts +16 -1
  10. package/lib/plugins/clipboard/index.js +1 -1
  11. package/lib/plugins/clipboard/index.js.map +1 -1
  12. package/lib/plugins/column-virtualization/index.js +1 -1
  13. package/lib/plugins/column-virtualization/index.js.map +1 -1
  14. package/lib/plugins/context-menu/index.js +1 -1
  15. package/lib/plugins/context-menu/index.js.map +1 -1
  16. package/lib/plugins/editing/index.js +1 -1
  17. package/lib/plugins/editing/index.js.map +1 -1
  18. package/lib/plugins/export/index.js +1 -1
  19. package/lib/plugins/export/index.js.map +1 -1
  20. package/lib/plugins/filtering/index.js +1 -1
  21. package/lib/plugins/filtering/index.js.map +1 -1
  22. package/lib/plugins/grouping-columns/index.js +1 -1
  23. package/lib/plugins/grouping-columns/index.js.map +1 -1
  24. package/lib/plugins/grouping-rows/index.js +2 -2
  25. package/lib/plugins/grouping-rows/index.js.map +1 -1
  26. package/lib/plugins/master-detail/index.js +1 -1
  27. package/lib/plugins/master-detail/index.js.map +1 -1
  28. package/lib/plugins/multi-sort/MultiSortPlugin.d.ts +8 -1
  29. package/lib/plugins/multi-sort/index.js +1 -1
  30. package/lib/plugins/multi-sort/index.js.map +1 -1
  31. package/lib/plugins/pinned-columns/index.js +1 -1
  32. package/lib/plugins/pinned-columns/index.js.map +1 -1
  33. package/lib/plugins/pinned-rows/index.js +1 -1
  34. package/lib/plugins/pinned-rows/index.js.map +1 -1
  35. package/lib/plugins/pivot/PivotPlugin.d.ts +43 -1
  36. package/lib/plugins/pivot/index.d.ts +1 -1
  37. package/lib/plugins/pivot/index.js +1 -1
  38. package/lib/plugins/pivot/index.js.map +1 -1
  39. package/lib/plugins/pivot/pivot-engine.d.ts +21 -2
  40. package/lib/plugins/pivot/pivot-model.d.ts +6 -3
  41. package/lib/plugins/pivot/pivot-panel.d.ts +8 -3
  42. package/lib/plugins/pivot/pivot-rows.d.ts +3 -3
  43. package/lib/plugins/pivot/types.d.ts +121 -8
  44. package/lib/plugins/print/index.js +1 -1
  45. package/lib/plugins/print/index.js.map +1 -1
  46. package/lib/plugins/reorder-columns/index.js +1 -1
  47. package/lib/plugins/reorder-columns/index.js.map +1 -1
  48. package/lib/plugins/reorder-rows/index.js +1 -1
  49. package/lib/plugins/reorder-rows/index.js.map +1 -1
  50. package/lib/plugins/responsive/index.js +1 -1
  51. package/lib/plugins/responsive/index.js.map +1 -1
  52. package/lib/plugins/selection/index.js +1 -1
  53. package/lib/plugins/selection/index.js.map +1 -1
  54. package/lib/plugins/server-side/index.js +1 -1
  55. package/lib/plugins/server-side/index.js.map +1 -1
  56. package/lib/plugins/tooltip/index.js +1 -1
  57. package/lib/plugins/tooltip/index.js.map +1 -1
  58. package/lib/plugins/tree/index.js +1 -1
  59. package/lib/plugins/tree/index.js.map +1 -1
  60. package/lib/plugins/undo-redo/index.js +1 -1
  61. package/lib/plugins/undo-redo/index.js.map +1 -1
  62. package/lib/plugins/visibility/index.js +1 -1
  63. package/lib/plugins/visibility/index.js.map +1 -1
  64. package/package.json +1 -1
  65. package/themes/dg-theme-bootstrap.css +8 -1
  66. package/themes/dg-theme-large.css +3 -1
  67. package/themes/dg-theme-material.css +3 -1
  68. package/themes/dg-theme-standard.css +5 -0
  69. package/themes/dg-theme-vibrant.css +5 -0
  70. package/umd/grid.all.umd.js +1 -1
  71. package/umd/grid.all.umd.js.map +1 -1
  72. package/umd/grid.umd.js +1 -1
  73. package/umd/grid.umd.js.map +1 -1
  74. package/umd/plugins/context-menu.umd.js +1 -1
  75. package/umd/plugins/context-menu.umd.js.map +1 -1
  76. package/umd/plugins/editing.umd.js +1 -1
  77. package/umd/plugins/editing.umd.js.map +1 -1
  78. package/umd/plugins/filtering.umd.js +1 -1
  79. package/umd/plugins/filtering.umd.js.map +1 -1
  80. package/umd/plugins/grouping-rows.umd.js +1 -1
  81. package/umd/plugins/grouping-rows.umd.js.map +1 -1
  82. package/umd/plugins/master-detail.umd.js +1 -1
  83. package/umd/plugins/master-detail.umd.js.map +1 -1
  84. package/umd/plugins/multi-sort.umd.js +1 -1
  85. package/umd/plugins/multi-sort.umd.js.map +1 -1
  86. package/umd/plugins/pivot.umd.js +1 -1
  87. package/umd/plugins/pivot.umd.js.map +1 -1
  88. package/umd/plugins/print.umd.js +1 -1
  89. package/umd/plugins/print.umd.js.map +1 -1
  90. package/umd/plugins/reorder-rows.umd.js +1 -1
  91. package/umd/plugins/reorder-rows.umd.js.map +1 -1
  92. package/umd/plugins/tree.umd.js +1 -1
  93. package/umd/plugins/tree.umd.js.map +1 -1
  94. package/umd/plugins/visibility.umd.js +1 -1
  95. package/umd/plugins/visibility.umd.js.map +1 -1
@@ -1,4 +1,4 @@
1
- import { PivotConfig, PivotResult, PivotRow, PivotValueField } from './types';
1
+ import { PivotConfig, PivotResult, PivotRow, PivotSortConfig, PivotSortDir, PivotValueField } from './types';
2
2
  export type PivotDataRow = Record<string, unknown>;
3
3
  /**
4
4
  * Build a hierarchical pivot result from flat data.
@@ -8,7 +8,7 @@ export declare function buildPivot(rows: PivotDataRow[], config: PivotConfig): P
8
8
  /**
9
9
  * Get unique column key combinations from the data.
10
10
  */
11
- export declare function getUniqueColumnKeys(rows: PivotDataRow[], columnFields: string[]): string[];
11
+ export declare function getUniqueColumnKeys(rows: PivotDataRow[], columnFields: string[], sortDir?: PivotSortDir): string[];
12
12
  /**
13
13
  * Group rows by a single field.
14
14
  */
@@ -47,3 +47,22 @@ export declare function flattenPivotRows(rows: PivotRow[], expandedKeys?: Set<st
47
47
  * Get all group keys from pivot rows (for expand all / collapse all).
48
48
  */
49
49
  export declare function getAllGroupKeys(rows: PivotRow[]): string[];
50
+ /**
51
+ * Recursively sort pivot rows at each level.
52
+ */
53
+ export declare function sortPivotRows(rows: PivotRow[], sortConfig: PivotSortConfig, valueFields: PivotValueField[]): void;
54
+ /**
55
+ * Sort pivot rows by multiple criteria (from MultiSort's sort model).
56
+ * Each criterion is a PivotSortConfig; earlier entries take precedence.
57
+ * Maintains hierarchy by sorting children recursively at each level.
58
+ */
59
+ export declare function sortPivotMulti(rows: PivotRow[], configs: PivotSortConfig[], valueFields: PivotValueField[]): void;
60
+ /**
61
+ * Resolve `defaultExpanded` config to a set of keys, similar to grouping-rows.
62
+ */
63
+ export declare function resolveDefaultExpanded(value: boolean | number | string | string[] | undefined, allGroupKeys: string[]): Set<string>;
64
+ /**
65
+ * Calculate column totals (sum of all leaf row values per column key).
66
+ * Used for percentage-of-column calculations.
67
+ */
68
+ export declare function getColumnTotals(rows: PivotRow[], columnKeys: string[], valueFields: PivotValueField[]): Record<string, number>;
@@ -1,5 +1,8 @@
1
- import { getValueAggregator } from '../../core/internal/aggregators';
2
- import { PivotConfig } from './types';
3
- export declare const getPivotAggregator: typeof getValueAggregator;
1
+ import { AggFunc, PivotConfig } from './types';
2
+ /**
3
+ * Resolve an AggFunc to an executable function.
4
+ * Supports both built-in string names and custom functions.
5
+ */
6
+ export declare function getPivotAggregator(aggFunc: AggFunc): (values: number[]) => number;
4
7
  export declare function validatePivotConfig(config: PivotConfig): string[];
5
8
  export declare function createValueKey(columnValues: string[], valueField: string): string;
@@ -1,6 +1,8 @@
1
- import { AggFunc, PivotConfig } from './types';
2
- /** All available aggregation functions */
3
- export declare const AGG_FUNCS: AggFunc[];
1
+ import { AggFunc, CustomAggFunc, PivotConfig } from './types';
2
+ /** Built-in aggregation function names (excludes custom functions) */
3
+ type BuiltInAggFunc = Exclude<AggFunc, CustomAggFunc>;
4
+ /** All available built-in aggregation functions for the panel UI */
5
+ export declare const AGG_FUNCS: BuiltInAggFunc[];
4
6
  /** Field info for available fields */
5
7
  export interface FieldInfo {
6
8
  field: string;
@@ -11,6 +13,8 @@ export interface PanelCallbacks {
11
13
  onTogglePivot: (enabled: boolean) => void;
12
14
  onAddFieldToZone: (field: string, zone: 'rowGroups' | 'columnGroups') => void;
13
15
  onRemoveFieldFromZone: (field: string, zone: 'rowGroups' | 'columnGroups') => void;
16
+ onReorderFieldInZone: (field: string, zone: 'rowGroups' | 'columnGroups', newIndex: number) => void;
17
+ onMoveFieldBetweenZones: (field: string, fromZone: 'rowGroups' | 'columnGroups', toZone: 'rowGroups' | 'columnGroups') => void;
14
18
  onAddValueField: (field: string, aggFunc: AggFunc) => void;
15
19
  onRemoveValueField: (field: string) => void;
16
20
  onUpdateValueAggFunc: (field: string, aggFunc: AggFunc) => void;
@@ -22,3 +26,4 @@ export interface PanelCallbacks {
22
26
  * Returns a cleanup function that removes all event listeners and DOM elements.
23
27
  */
24
28
  export declare function renderPivotPanel(container: HTMLElement, config: PivotConfig, isActive: boolean, callbacks: PanelCallbacks): () => void;
29
+ export {};
@@ -1,4 +1,4 @@
1
- import { ColumnConfig, IconValue } from '../../core/types';
1
+ import { ColumnConfig, GridIcons } from '../../core/types';
2
2
  /** Row data with pivot metadata */
3
3
  export interface PivotRowData {
4
4
  __pivotRowKey?: string;
@@ -16,8 +16,7 @@ export interface RowRenderContext {
16
16
  columns: ColumnConfig[];
17
17
  rowIndex: number;
18
18
  onToggle: (key: string) => void;
19
- resolveIcon: (iconKey: 'expand' | 'collapse') => IconValue;
20
- setIcon: (element: HTMLElement, icon: IconValue) => void;
19
+ setIcon: (element: HTMLElement, iconKey: keyof GridIcons) => void;
21
20
  }
22
21
  /**
23
22
  * Render a pivot group row (has children, can expand/collapse).
@@ -29,5 +28,6 @@ export declare function renderPivotGroupRow(row: PivotRowData, rowEl: HTMLElemen
29
28
  export declare function renderPivotLeafRow(row: PivotRowData, rowEl: HTMLElement, columns: ColumnConfig[], rowIndex: number): boolean;
30
29
  /**
31
30
  * Render the grand total row.
31
+ * Used both for the sticky footer and for in-row-model rendering.
32
32
  */
33
33
  export declare function renderPivotGrandTotalRow(row: PivotRowData, rowEl: HTMLElement, columns: ColumnConfig[]): boolean;
@@ -1,5 +1,18 @@
1
1
  import { ExpandCollapseAnimation } from '../../core/types';
2
2
  export type { ExpandCollapseAnimation } from '../../core/types';
3
+ /**
4
+ * Custom aggregation function that receives an array of numeric values
5
+ * and returns a single aggregated result.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const weightedAvg: CustomAggFunc = (values) => {
10
+ * const total = values.reduce((a, b) => a + b, 0);
11
+ * return total / values.length;
12
+ * };
13
+ * ```
14
+ */
15
+ export type CustomAggFunc = (values: number[]) => number;
3
16
  /**
4
17
  * Built-in aggregation functions for pivot value fields.
5
18
  *
@@ -15,16 +28,43 @@ export type { ExpandCollapseAnimation } from '../../core/types';
15
28
  * | `'first'` | Value from the first row in the group | May be `undefined` if group is empty |
16
29
  * | `'last'` | Value from the last row in the group | May be `undefined` if group is empty |
17
30
  *
18
- * @example
31
+ * You can also provide a custom function:
19
32
  * ```typescript
20
33
  * const valueFields: PivotValueField[] = [
21
34
  * { field: 'revenue', aggFunc: 'sum', header: 'Total Revenue' },
22
- * { field: 'revenue', aggFunc: 'avg', header: 'Avg Revenue' },
23
- * { field: 'orders', aggFunc: 'count', header: '# Orders' },
35
+ * { field: 'margin', aggFunc: (values) => values.reduce((a, b) => a + b, 0) / values.length },
24
36
  * ];
25
37
  * ```
26
38
  */
27
- export type AggFunc = 'sum' | 'avg' | 'count' | 'min' | 'max' | 'first' | 'last';
39
+ export type AggFunc = 'sum' | 'avg' | 'count' | 'min' | 'max' | 'first' | 'last' | CustomAggFunc;
40
+ /** Sort direction for pivot rows or columns. */
41
+ export type PivotSortDir = 'asc' | 'desc';
42
+ /** Configuration for sorting pivot row groups. */
43
+ export interface PivotSortConfig {
44
+ /** Sort by `'label'` (group name) or `'value'` (aggregate value). Default: `'label'` */
45
+ by?: 'label' | 'value';
46
+ /** Sort direction. Default: `'asc'` */
47
+ direction?: PivotSortDir;
48
+ /** When `by: 'value'`, which value field to sort by (defaults to first value field). */
49
+ valueField?: string;
50
+ }
51
+ /**
52
+ * Value display mode for pivot cells.
53
+ * - `'raw'` — Show raw aggregated value (default)
54
+ * - `'percentOfRow'` — Show as percentage of row total
55
+ * - `'percentOfColumn'` — Show as percentage of column total
56
+ * - `'percentOfGrandTotal'` — Show as percentage of grand total
57
+ */
58
+ export type PivotValueDisplayMode = 'raw' | 'percentOfRow' | 'percentOfColumn' | 'percentOfGrandTotal';
59
+ /**
60
+ * Value that determines which groups are expanded by default.
61
+ * - `true` — Expand all groups
62
+ * - `false` — Collapse all groups
63
+ * - `number` — Expand group at this index
64
+ * - `string` — Expand group with this key
65
+ * - `string[]` — Expand groups matching these keys
66
+ */
67
+ export type PivotDefaultExpandedValue = boolean | number | string | string[];
28
68
  /**
29
69
  * Configuration for the pivot plugin.
30
70
  *
@@ -55,8 +95,15 @@ export interface PivotConfig {
55
95
  valueFields?: PivotValueField[];
56
96
  showTotals?: boolean;
57
97
  showGrandTotal?: boolean;
58
- /** Whether groups are expanded by default (default: true) */
59
- defaultExpanded?: boolean;
98
+ /**
99
+ * Which groups are expanded by default.
100
+ * - `true` — expand all (default)
101
+ * - `false` — collapse all
102
+ * - `number` — expand group at index
103
+ * - `string` — expand group with key
104
+ * - `string[]` — expand groups matching keys
105
+ */
106
+ defaultExpanded?: PivotDefaultExpandedValue;
60
107
  /** Indent width per depth level in pixels (default: 20) */
61
108
  indentWidth?: number;
62
109
  /** Whether to show the pivot configuration tool panel (default: true) */
@@ -69,6 +116,32 @@ export interface PivotConfig {
69
116
  * @default 'slide'
70
117
  */
71
118
  animation?: ExpandCollapseAnimation;
119
+ /**
120
+ * Sort configuration for row groups.
121
+ * When set, groups at each level are sorted by label or aggregate value.
122
+ */
123
+ sortRows?: PivotSortConfig;
124
+ /**
125
+ * Sort direction for column keys. Default: `'asc'` (alphabetical).
126
+ * Set to `'desc'` for reverse order.
127
+ */
128
+ sortColumns?: PivotSortDir;
129
+ /**
130
+ * Include the grand total row in the row model (so it's included in exports/copy).
131
+ * When `false` (default), grand total is rendered as a separate sticky footer.
132
+ * @default false
133
+ */
134
+ grandTotalInRowModel?: boolean;
135
+ /**
136
+ * Display mode for aggregated values.
137
+ * @default 'raw'
138
+ */
139
+ valueDisplayMode?: PivotValueDisplayMode;
140
+ /**
141
+ * Whether to show subtotal rows at each group level in multi-level grouping.
142
+ * @default false
143
+ */
144
+ showSubtotals?: boolean;
72
145
  }
73
146
  /**
74
147
  * Defines a value field in the pivot table — which data field to aggregate
@@ -80,10 +153,20 @@ export interface PivotConfig {
80
153
  export interface PivotValueField {
81
154
  /** The row data field to aggregate (must exist on the source row objects). */
82
155
  field: string;
83
- /** Aggregation function to apply (see {@link AggFunc} for options). */
156
+ /** Aggregation function a built-in name or a custom function. */
84
157
  aggFunc: AggFunc;
85
158
  /** Custom column header label. Defaults to `"field (aggFunc)"` if omitted. */
86
159
  header?: string;
160
+ /**
161
+ * Format function for display values. Receives the aggregated number and returns a string.
162
+ * When omitted, the original column's `format` is used if available, otherwise raw `String(value)`.
163
+ *
164
+ * @example
165
+ * ```typescript
166
+ * { field: 'revenue', aggFunc: 'sum', format: (v) => `$${v.toLocaleString()}` }
167
+ * ```
168
+ */
169
+ format?: (value: number) => string;
87
170
  }
88
171
  export interface PivotState {
89
172
  isActive: boolean;
@@ -117,13 +200,43 @@ export interface PivotRow {
117
200
  values: Record<string, number | null>;
118
201
  /** Row total across all columns */
119
202
  total?: number;
120
- /** Whether this row has children (is a group header) */
203
+ /**
204
+ * Whether this row has sub-groups (i.e. `remainingFields.length > 0` in the engine).
205
+ * NOTE: With a single `rowGroupFields`, grouped rows have `isGroup: false` because
206
+ * there are no further levels to expand. Use multi-level grouping when testing
207
+ * group-related logic like `getAllGroupKeys()`.
208
+ */
121
209
  isGroup: boolean;
122
210
  /** Child rows (for hierarchical grouping) */
123
211
  children?: PivotRow[];
124
212
  /** Number of data rows in this group */
125
213
  rowCount?: number;
126
214
  }
215
+ /** Detail for `pivot-toggle` event. Fired when a group is expanded/collapsed. */
216
+ export interface PivotToggleDetail {
217
+ /** The pivot row key that was toggled. */
218
+ key: string;
219
+ /** Whether the group is now expanded. */
220
+ expanded: boolean;
221
+ /** The display label of the group. */
222
+ label: string;
223
+ /** The depth level of the group. */
224
+ depth: number;
225
+ }
226
+ /** Detail for `pivot-state-change` event. Fired when pivot is enabled or disabled. */
227
+ export interface PivotStateChangeDetail {
228
+ /** Whether pivot is now active. */
229
+ active: boolean;
230
+ }
231
+ /** Detail for `pivot-config-change` event. Fired when pivot configuration changes via the panel. */
232
+ export interface PivotConfigChangeDetail {
233
+ /** The configuration property that changed. */
234
+ property: string;
235
+ /** The field that was affected (if applicable). */
236
+ field?: string;
237
+ /** The zone that was affected (if applicable). */
238
+ zone?: 'rowGroups' | 'columnGroups' | 'values';
239
+ }
127
240
  declare module '../../core/types' {
128
241
  interface PluginNameMap {
129
242
  pivot: import('./PivotPlugin').PivotPlugin;
@@ -1,2 +1,2 @@
1
- function t(t,e){return`[tbw-grid${t?`#${t}`:""}${e?`:${e}`:""}]`}function e(e,i,n,r){return`${t(n,r)} ${e}: ${i}\n\n → More info: ${function(t){return`https://toolboxjs.com/grid/errors#${t.toLowerCase()}`}(e)}`}const i="tbw-print-isolation-style";async function n(t,n={}){const{orientation:r="landscape"}=n,o=t.id;document.querySelectorAll(`#${CSS.escape(o)}`).length>1&&function(t,i,n,r){console.warn(e(t,i,n,r))}("TBW093",`Multiple elements found with id="${o}". Print isolation may not work correctly. Ensure each grid has a unique ID.`,o,"print"),document.getElementById(i)?.remove();const s=function(t,e){const n=document.createElement("style");return n.id=i,n.textContent=`\n /* Print isolation: hide everything except the target grid */\n @media print {\n /* Hide all body children by default */\n body > *:not(#${t}) {\n display: none !important;\n }\n\n /* But show the grid and ensure it's not hidden by ancestor rules */\n #${t} {\n display: block !important;\n position: static !important;\n visibility: visible !important;\n opacity: 1 !important;\n overflow: visible !important;\n height: auto !important;\n width: 100% !important;\n max-height: none !important;\n margin: 0 !important;\n padding: 0 !important;\n transform: none !important;\n }\n\n /* If grid is nested, we need to show its ancestors too */\n #${t},\n #${t} * {\n visibility: visible !important;\n }\n\n /* Walk up the DOM and show all ancestors of the grid */\n body *:has(> #${t}),\n body *:has(#${t}) {\n display: block !important;\n visibility: visible !important;\n opacity: 1 !important;\n overflow: visible !important;\n height: auto !important;\n position: static !important;\n transform: none !important;\n background: transparent !important;\n border: none !important;\n padding: 0 !important;\n margin: 0 !important;\n }\n\n /* Hide siblings of ancestors (everything that's not in the path to the grid) */\n body *:has(#${t}) > *:not(:has(#${t})):not(#${t}) {\n display: none !important;\n }\n\n /* Page settings */\n @page {\n size: ${e};\n margin: 1cm;\n }\n\n /* Ensure proper print styling */\n body {\n margin: 0 !important;\n padding: 0 !important;\n background: white !important;\n color-scheme: light !important;\n }\n }\n\n /* Screen: also apply isolation for print preview */\n @media screen {\n /* When this stylesheet is active, we're about to print */\n /* No screen-specific rules needed - isolation only applies to print */\n }\n `,n}(o,r);return document.head.appendChild(s),new Promise(t=>{const e=()=>{window.removeEventListener("afterprint",e),document.getElementById(i)?.remove(),t()};window.addEventListener("afterprint",e),window.print(),setTimeout(()=>{window.removeEventListener("afterprint",e),document.getElementById(i)?.remove(),t()},5e3)})}const r=/* @__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"]),o=/^on\w+$/i,s=/* @__PURE__ */new Set(["href","src","action","formaction","data","srcdoc","xlink:href","poster","srcset"]),a=/^\s*(javascript|vbscript|data|blob):/i;function d(t){if(!t||"string"!=typeof t)return"";if(-1===t.indexOf("<"))return t;const e=document.createElement("template");return e.innerHTML=t,function(t){const e=[],i=t.querySelectorAll("*");for(const n of i){const t=n.tagName.toLowerCase();if(r.has(t)){e.push(n);continue}if("svg"===t||"http://www.w3.org/2000/svg"===n.namespaceURI){if(Array.from(n.attributes).some(t=>o.test(t.name)||"href"===t.name||"xlink:href"===t.name)){e.push(n);continue}}const i=[];for(const e of n.attributes){const t=e.name.toLowerCase();o.test(t)?i.push(e.name):(s.has(t)&&a.test(e.value)||"style"===t&&/expression\s*\(|javascript:|behavior\s*:/i.test(e.value))&&i.push(e.name)}i.forEach(t=>n.removeAttribute(t))}e.forEach(t=>t.remove())}(e.content),e.innerHTML}const l='<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>',p={expand:"▶",collapse:"▼",sortAsc:"▲",sortDesc:"▼",sortNone:"⇅",submenuArrow:"▶",dragHandle:"⋮⋮",toolPanel:"☰",filter:l,filterActive:l,print:"🖨️"};class h{static dependencies;static manifest;aliases;version="undefined"!=typeof __GRID_VERSION__?__GRID_VERSION__:"dev";styles;cellRenderers;headerRenderers;cellEditors;grid;config;userConfig;#t;get defaultConfig(){return{}}constructor(t={}){this.userConfig=t}attach(t){this.#t?.abort(),this.#t=new AbortController,this.grid=t,this.config={...this.defaultConfig,...this.userConfig}}detach(){this.#t?.abort(),this.#t=void 0}getPlugin(t){return this.grid?.getPlugin(t)}emit(t,e){this.grid?.dispatchEvent?.(new CustomEvent(t,{detail:e,bubbles:!0}))}emitCancelable(t,e){const i=new CustomEvent(t,{detail:e,bubbles:!0,cancelable:!0});return this.grid?.dispatchEvent?.(i),i.defaultPrevented}on(t,e){this.grid?._pluginManager?.subscribe(this,t,e)}off(t){this.grid?._pluginManager?.unsubscribe(this,t)}emitPluginEvent(t,e){this.grid?._pluginManager?.emitPluginEvent(t,e)}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.#t?.signal??this.grid?.disconnectSignal}get gridIcons(){const t=this.grid?.gridConfig?.icons??{};return{...p,...t}}get isAnimationEnabled(){const t=this.grid?.effectiveConfig?.animation?.mode??"reduced-motion";if(!1===t||"off"===t)return!1;if(!0===t||"on"===t)return!0;const e=this.gridElement;if(e){return"0"!==getComputedStyle(e).getPropertyValue("--tbw-animation-enabled").trim()}return!0}get animationDuration(){const t=this.gridElement;if(t){const e=getComputedStyle(t).getPropertyValue("--tbw-animation-duration").trim(),i=parseInt(e,10);if(!isNaN(i))return i}return 200}resolveIcon(t,e){return void 0!==e?e:this.gridIcons[t]}setIcon(t,e){"string"==typeof e?t.innerHTML=d(e):e instanceof HTMLElement&&(t.innerHTML="",t.appendChild(e.cloneNode(!0)))}warn(i,n){void 0!==n?console.warn(e(i,n,this.gridElement.id,this.name)):console.warn(`${t(this.gridElement.id,this.name)} ${i}`)}throwDiagnostic(t,i){throw new Error(e(t,i,this.gridElement.id,this.name))}}const m={button:!1,orientation:"landscape",warnThreshold:500,maxRows:0,includeTitle:!0,includeTimestamp:!0,title:"",isolate:!1};class c extends h{name="print";version="1.0.0";styles=".tbw-print-header,.tbw-print-footer{display:none}@media print{tbw-grid{overflow:visible!important;height:auto!important;border:none!important;border-radius:0!important;color-scheme:light only;-webkit-print-color-adjust:exact;print-color-adjust:exact}tbw-grid .tbw-grid-content{overflow:visible!important;height:auto!important;max-height:none!important}tbw-grid .tbw-scroll-area{overflow:visible!important;height:auto!important;max-height:none!important}tbw-grid .rows-body{overflow:visible!important;height:auto!important;max-height:none!important}tbw-grid .rows-container,tbw-grid .rows-viewport,tbw-grid .rows{overflow:visible!important;height:auto!important;max-height:none!important;transform:none!important}tbw-grid .rows-viewport .rows{position:static!important}tbw-grid .resize-handle,tbw-grid [part=sort-indicator],tbw-grid .tbw-filter-btn,tbw-grid .tool-panel,tbw-grid .tool-panel-content,tbw-grid .tbw-shell-header,tbw-grid .shell-toolbar,tbw-grid .tool-panel-toggle,tbw-grid [data-print-hide],tbw-grid .expander-cell,tbw-grid .tree-toggle,tbw-grid .context-menu,tbw-grid .faux-vscroll{display:none!important}tbw-grid .tbw-print-header{display:flex;justify-content:space-between;align-items:baseline;padding:var(--tbw-spacing-md, .5em) 0;margin-bottom:var(--tbw-spacing-md, .5em);border-bottom:2px solid var(--tbw-print-border, var(--tbw-color-border-strong));font-family:inherit}.tbw-print-header-title{font-size:1.25em;font-weight:700}.tbw-print-header-timestamp{font-size:var(--tbw-font-size-sm, .875em);color:var(--tbw-print-muted, var(--tbw-color-fg-muted))}tbw-grid .tbw-print-footer{display:block;margin-top:var(--tbw-spacing-md, .5em);padding-top:var(--tbw-spacing-md, .5em);border-top:1px solid var(--tbw-print-border, var(--tbw-color-border));font-size:var(--tbw-font-size-xs, .75em);color:var(--tbw-print-muted, var(--tbw-color-fg-muted));text-align:end}tbw-grid .data-grid-row{break-inside:avoid;page-break-inside:avoid}tbw-grid .cell{border:1px solid var(--tbw-print-cell-border, var(--tbw-color-border))!important}tbw-grid .header-row,tbw-grid .data-grid-row{padding-inline-end:1px}tbw-grid .data-grid-row:hover,tbw-grid .cell:hover{background:inherit!important}@page{margin:1cm}@page{tbw-grid.print-landscape{size:landscape}}@page{tbw-grid.print-portrait{size:portrait}}}";#e=!1;#i=null;#n=null;#r=null;#o=null;#s=null;#a=null;get#d(){return this.grid}isPrinting(){return this.#e}async print(t){if(this.#e)return void this.warn("TBW090","Print already in progress");const i=this.gridElement;if(!i)return void this.warn("TBW091","Grid not available");const n={...m,...this.config,...t},r=this.rows.length;let o=r,s=!1;if(n.warnThreshold>0&&r>n.warnThreshold){const t=n.maxRows>0?`\n\nNote: Output will be limited to ${n.maxRows.toLocaleString()} rows.`:"";if(!confirm(`This grid has ${r.toLocaleString()} rows. Printing large datasets may cause performance issues or browser slowdowns.${t}\n\nClick OK to continue, or Cancel to abort.`))return}n.maxRows>0&&r>n.maxRows&&(o=n.maxRows,s=!0),this.#e=!0;const a=performance.now();this.emit("print-start",{rowCount:o,limitApplied:s,originalRowCount:r});try{const t=this.#d;this.#n={bypassThreshold:t._virtualization?.bypassThreshold??24},this.#l(),s&&(this.#r=this.sourceRows,this.grid.rows=this.sourceRows.slice(0,o),await new Promise(t=>setTimeout(t,50))),(n.includeTitle||n.includeTimestamp)&&this.#p(n),await this.#h(),await new Promise(t=>requestAnimationFrame(t)),await new Promise(t=>requestAnimationFrame(t)),i.classList.add(`print-${n.orientation}`),await new Promise(t=>requestAnimationFrame(t)),await new Promise(t=>requestAnimationFrame(t)),n.isolate?await this.#m(n):await this.#c(),this.emit("print-complete",{success:!0,rowCount:o,duration:Math.round(performance.now()-a)})}catch(c){d="TBW092",l=`Print failed: ${c}`,p=this.gridElement?.id,h=this.name,console.error(e(d,l,p,h)),this.emit("print-complete",{success:!1,rowCount:0,duration:Math.round(performance.now()-a)})}finally{this.#u(),this.#e=!1}var d,l,p,h}#p(t){const e=this.gridElement;if(e){if(this.#o=document.createElement("div"),this.#o.className="tbw-print-header",t.includeTitle){const e=t.title||this.grid.effectiveConfig?.shell?.header?.title||"Grid Data",i=document.createElement("div");i.className="tbw-print-header-title",i.textContent=e,this.#o.appendChild(i)}if(t.includeTimestamp){const t=document.createElement("div");t.className="tbw-print-header-timestamp",t.textContent=`Printed: ${/* @__PURE__ */(new Date).toLocaleString()}`,this.#o.appendChild(t)}e.insertBefore(this.#o,e.firstChild),this.#s=document.createElement("div"),this.#s.className="tbw-print-footer",this.#s.textContent=`Page generated from ${window.location.hostname}`,e.appendChild(this.#s)}}async#h(){const t=this.#d;if(!t._virtualization)return;const e=this.rows.length;t._virtualization.bypassThreshold=e+100,t.refreshVirtualWindow(!0),await new Promise(t=>setTimeout(t,100))}async#c(){return new Promise(t=>{const e=()=>{window.removeEventListener("afterprint",e),t()};window.addEventListener("afterprint",e),window.print(),setTimeout(()=>{"undefined"!=typeof window&&window.removeEventListener("afterprint",e),t()},1e3)})}async#m(t){const e=this.gridElement;e&&await n(e,{orientation:t.orientation})}#l(){const t=this.columns;if(t){this.#i=/* @__PURE__ */new Map;for(const e of t)e.printHidden&&e.field&&(this.#i.set(e.field,!e.hidden),this.grid.setColumnVisible(e.field,!1))}}#g(){if(this.#i){for(const[t,e]of this.#i)this.grid.setColumnVisible(t,e);this.#i=null}}#u(){const t=this.gridElement;if(!t)return;this.#g(),t.classList.remove("print-portrait","print-landscape"),null!==this.#a&&(t.style.transform="",t.style.transformOrigin="",t.style.width="",this.#a=null),this.#o&&(this.#o.remove(),this.#o=null),this.#s&&(this.#s.remove(),this.#s=null);const e=this.#d;this.#n&&e._virtualization&&(e._virtualization.bypassThreshold=this.#n.bypassThreshold,e.refreshVirtualWindow(!0),this.#n=null),null!==this.#r&&(this.grid.rows=this.#r,this.#r=null)}afterRender(){this.config?.button&&!this.#w&&(this.#b(),this.#w=!0)}#w=!1;#b(){const t=this.#d;t.registerToolbarContent?.({id:"print-button",order:900,render:t=>{const e=document.createElement("button");e.className="tbw-toolbar-btn tbw-print-btn",e.title="Print grid",e.type="button";const i=this.resolveIcon("print")||"🖨️";this.setIcon(e,i),e.addEventListener("click",()=>{this.print()},{signal:this.disconnectSignal}),t.appendChild(e)}})}}export{c as PrintPlugin,n as printGridIsolated};
1
+ function t(t,e){return`[tbw-grid${t?`#${t}`:""}${e?`:${e}`:""}]`}function e(e,i,n,r){return`${t(n,r)} ${e}: ${i}\n\n → More info: ${function(t){return`https://toolboxjs.com/grid/errors#${t.toLowerCase()}`}(e)}`}const i="tbw-print-isolation-style";async function n(t,n={}){const{orientation:r="landscape"}=n,o=t.id;document.querySelectorAll(`#${CSS.escape(o)}`).length>1&&function(t,i,n,r){console.warn(e(t,i,n,r))}("TBW093",`Multiple elements found with id="${o}". Print isolation may not work correctly. Ensure each grid has a unique ID.`,o,"print"),document.getElementById(i)?.remove();const s=function(t,e){const n=document.createElement("style");return n.id=i,n.textContent=`\n /* Print isolation: hide everything except the target grid */\n @media print {\n /* Hide all body children by default */\n body > *:not(#${t}) {\n display: none !important;\n }\n\n /* But show the grid and ensure it's not hidden by ancestor rules */\n #${t} {\n display: block !important;\n position: static !important;\n visibility: visible !important;\n opacity: 1 !important;\n overflow: visible !important;\n height: auto !important;\n width: 100% !important;\n max-height: none !important;\n margin: 0 !important;\n padding: 0 !important;\n transform: none !important;\n }\n\n /* If grid is nested, we need to show its ancestors too */\n #${t},\n #${t} * {\n visibility: visible !important;\n }\n\n /* Walk up the DOM and show all ancestors of the grid */\n body *:has(> #${t}),\n body *:has(#${t}) {\n display: block !important;\n visibility: visible !important;\n opacity: 1 !important;\n overflow: visible !important;\n height: auto !important;\n position: static !important;\n transform: none !important;\n background: transparent !important;\n border: none !important;\n padding: 0 !important;\n margin: 0 !important;\n }\n\n /* Hide siblings of ancestors (everything that's not in the path to the grid) */\n body *:has(#${t}) > *:not(:has(#${t})):not(#${t}) {\n display: none !important;\n }\n\n /* Page settings */\n @page {\n size: ${e};\n margin: 1cm;\n }\n\n /* Ensure proper print styling */\n body {\n margin: 0 !important;\n padding: 0 !important;\n background: white !important;\n color-scheme: light !important;\n }\n }\n\n /* Screen: also apply isolation for print preview */\n @media screen {\n /* When this stylesheet is active, we're about to print */\n /* No screen-specific rules needed - isolation only applies to print */\n }\n `,n}(o,r);return document.head.appendChild(s),new Promise(t=>{const e=()=>{window.removeEventListener("afterprint",e),document.getElementById(i)?.remove(),t()};window.addEventListener("afterprint",e),window.print(),setTimeout(()=>{window.removeEventListener("afterprint",e),document.getElementById(i)?.remove(),t()},5e3)})}["__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(t=>t.split("").reverse().join(""));const r=/* @__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"]),o=/^on\w+$/i,s=/* @__PURE__ */new Set(["href","src","action","formaction","data","srcdoc","xlink:href","poster","srcset"]),a=/^\s*(javascript|vbscript|data|blob):/i;function d(t){if(!t||"string"!=typeof t)return"";if(-1===t.indexOf("<"))return t;const e=document.createElement("template");return e.innerHTML=t,function(t){const e=[],i=t.querySelectorAll("*");for(const n of i){const t=n.tagName.toLowerCase();if(r.has(t)){e.push(n);continue}if("svg"===t||"http://www.w3.org/2000/svg"===n.namespaceURI){if(Array.from(n.attributes).some(t=>o.test(t.name)||"href"===t.name||"xlink:href"===t.name)){e.push(n);continue}}const i=[];for(const e of n.attributes){const t=e.name.toLowerCase();o.test(t)?i.push(e.name):(s.has(t)&&a.test(e.value)||"style"===t&&/expression\s*\(|javascript:|behavior\s*:/i.test(e.value))&&i.push(e.name)}i.forEach(t=>n.removeAttribute(t))}e.forEach(t=>t.remove())}(e.content),e.innerHTML}const l='<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>',c={expand:"▶",collapse:"▼",sortAsc:"▲",sortDesc:"▼",sortNone:"⇅",submenuArrow:"▶",dragHandle:"⋮⋮",toolPanel:"☰",filter:l,filterActive:l,print:"🖨️"};class p{static dependencies;static manifest;aliases;version="undefined"!=typeof __GRID_VERSION__?__GRID_VERSION__:"dev";styles;cellRenderers;headerRenderers;cellEditors;grid;config;userConfig;#t;get defaultConfig(){return{}}constructor(t={}){this.userConfig=t}attach(t){this.#t?.abort(),this.#t=new AbortController,this.grid=t,this.config={...this.defaultConfig,...this.userConfig}}detach(){this.#t?.abort(),this.#t=void 0}getPlugin(t){return this.grid?.getPlugin(t)}emit(t,e){this.grid?.dispatchEvent?.(new CustomEvent(t,{detail:e,bubbles:!0}))}emitCancelable(t,e){const i=new CustomEvent(t,{detail:e,bubbles:!0,cancelable:!0});return this.grid?.dispatchEvent?.(i),i.defaultPrevented}on(t,e){this.grid?._pluginManager?.subscribe(this,t,e)}off(t){this.grid?._pluginManager?.unsubscribe(this,t)}emitPluginEvent(t,e){this.grid?._pluginManager?.emitPluginEvent(t,e)}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.#t?.signal??this.grid?.disconnectSignal}get gridIcons(){const t=this.grid?.gridConfig?.icons??{};return{...c,...t}}get isAnimationEnabled(){const t=this.grid?.effectiveConfig?.animation?.mode??"reduced-motion";if(!1===t||"off"===t)return!1;if(!0===t||"on"===t)return!0;const e=this.gridElement;if(e){return"0"!==getComputedStyle(e).getPropertyValue("--tbw-animation-enabled").trim()}return!0}get animationDuration(){const t=this.gridElement;if(t){const e=getComputedStyle(t).getPropertyValue("--tbw-animation-duration").trim(),i=parseInt(e,10);if(!isNaN(i))return i}return 200}resolveIcon(t,e){return void 0!==e?e:this.gridIcons[t]}setIcon(t,e,i){t.dataset.icon=e.replace(/([A-Z])/g,"-$1").toLowerCase(),"collapse"===e?t.dataset.expanded="":"expand"===e&&delete t.dataset.expanded;const n=this.#e(e,i);void 0!==n?"string"==typeof n?t.innerHTML=d(n):n instanceof HTMLElement&&(t.innerHTML="",t.appendChild(n.cloneNode(!0))):t.innerHTML=""}#e(t,e){return void 0!==e?e:this.grid?.gridConfig?.icons?.[t]}updateSortIndicator(t,e){t.querySelector('[part~="sort-indicator"], .sort-indicator')?.remove();const i=document.createElement("span");i.setAttribute("part","sort-indicator"),i.className="sort-indicator",e?(t.setAttribute("aria-sort","asc"===e?"ascending":"descending"),t.setAttribute("data-sort",e),this.setIcon(i,"asc"===e?"sortAsc":"sortDesc")):(t.setAttribute("aria-sort","none"),t.removeAttribute("data-sort"),this.setIcon(i,"sortNone"));const n=t.querySelector(".tbw-filter-btn")??t.querySelector(".resize-handle");return n?t.insertBefore(i,n):t.appendChild(i),i}warn(i,n){void 0!==n?console.warn(e(i,n,this.gridElement.id,this.name)):console.warn(`${t(this.gridElement.id,this.name)} ${i}`)}throwDiagnostic(t,i){throw new Error(e(t,i,this.gridElement.id,this.name))}}const m={button:!1,orientation:"landscape",warnThreshold:500,maxRows:0,includeTitle:!0,includeTimestamp:!0,title:"",isolate:!1};class h extends p{name="print";version="1.0.0";styles=".tbw-print-header,.tbw-print-footer{display:none}@media print{tbw-grid{overflow:visible!important;height:auto!important;border:none!important;border-radius:0!important;color-scheme:light only;-webkit-print-color-adjust:exact;print-color-adjust:exact}tbw-grid .tbw-grid-content{overflow:visible!important;height:auto!important;max-height:none!important}tbw-grid .tbw-scroll-area{overflow:visible!important;height:auto!important;max-height:none!important}tbw-grid .rows-body{overflow:visible!important;height:auto!important;max-height:none!important}tbw-grid .rows-container,tbw-grid .rows-viewport,tbw-grid .rows{overflow:visible!important;height:auto!important;max-height:none!important;transform:none!important}tbw-grid .rows-viewport .rows{position:static!important}tbw-grid .resize-handle,tbw-grid [part=sort-indicator],tbw-grid .tbw-filter-btn,tbw-grid .tool-panel,tbw-grid .tool-panel-content,tbw-grid .tbw-shell-header,tbw-grid .shell-toolbar,tbw-grid .tool-panel-toggle,tbw-grid [data-print-hide],tbw-grid .expander-cell,tbw-grid .tree-toggle,tbw-grid .context-menu,tbw-grid .faux-vscroll{display:none!important}tbw-grid .tbw-print-header{display:flex;justify-content:space-between;align-items:baseline;padding:var(--tbw-spacing-md, .5em) 0;margin-bottom:var(--tbw-spacing-md, .5em);border-bottom:2px solid var(--tbw-print-border, var(--tbw-color-border-strong));font-family:inherit}.tbw-print-header-title{font-size:1.25em;font-weight:700}.tbw-print-header-timestamp{font-size:var(--tbw-font-size-sm, .875em);color:var(--tbw-print-muted, var(--tbw-color-fg-muted))}tbw-grid .tbw-print-footer{display:block;margin-top:var(--tbw-spacing-md, .5em);padding-top:var(--tbw-spacing-md, .5em);border-top:1px solid var(--tbw-print-border, var(--tbw-color-border));font-size:var(--tbw-font-size-xs, .75em);color:var(--tbw-print-muted, var(--tbw-color-fg-muted));text-align:end}tbw-grid .data-grid-row{break-inside:avoid;page-break-inside:avoid}tbw-grid .cell{border:1px solid var(--tbw-print-cell-border, var(--tbw-color-border))!important}tbw-grid .header-row,tbw-grid .data-grid-row{padding-inline-end:1px}tbw-grid .data-grid-row:hover,tbw-grid .cell:hover{background:inherit!important}@page{margin:1cm}@page{tbw-grid.print-landscape{size:landscape}}@page{tbw-grid.print-portrait{size:portrait}}}";#i=!1;#n=null;#r=null;#o=null;#s=null;#a=null;#d=null;get#l(){return this.grid}isPrinting(){return this.#i}async print(t){if(this.#i)return void this.warn("TBW090","Print already in progress");const i=this.gridElement;if(!i)return void this.warn("TBW091","Grid not available");const n={...m,...this.config,...t},r=this.rows.length;let o=r,s=!1;if(n.warnThreshold>0&&r>n.warnThreshold){const t=n.maxRows>0?`\n\nNote: Output will be limited to ${n.maxRows.toLocaleString()} rows.`:"";if(!confirm(`This grid has ${r.toLocaleString()} rows. Printing large datasets may cause performance issues or browser slowdowns.${t}\n\nClick OK to continue, or Cancel to abort.`))return}n.maxRows>0&&r>n.maxRows&&(o=n.maxRows,s=!0),this.#i=!0;const a=performance.now();this.emit("print-start",{rowCount:o,limitApplied:s,originalRowCount:r});try{const t=this.#l;this.#r={bypassThreshold:t._virtualization?.bypassThreshold??24},this.#c(),s&&(this.#o=this.sourceRows,this.grid.rows=this.sourceRows.slice(0,o),await new Promise(t=>setTimeout(t,50))),(n.includeTitle||n.includeTimestamp)&&this.#p(n),await this.#m(),await new Promise(t=>requestAnimationFrame(t)),await new Promise(t=>requestAnimationFrame(t)),i.classList.add(`print-${n.orientation}`),await new Promise(t=>requestAnimationFrame(t)),await new Promise(t=>requestAnimationFrame(t)),n.isolate?await this.#h(n):await this.#u(),this.emit("print-complete",{success:!0,rowCount:o,duration:Math.round(performance.now()-a)})}catch(h){d="TBW092",l=`Print failed: ${h}`,c=this.gridElement?.id,p=this.name,console.error(e(d,l,c,p)),this.emit("print-complete",{success:!1,rowCount:0,duration:Math.round(performance.now()-a)})}finally{this.#g(),this.#i=!1}var d,l,c,p}#p(t){const e=this.gridElement;if(e){if(this.#s=document.createElement("div"),this.#s.className="tbw-print-header",t.includeTitle){const e=t.title||this.grid.effectiveConfig?.shell?.header?.title||"Grid Data",i=document.createElement("div");i.className="tbw-print-header-title",i.textContent=e,this.#s.appendChild(i)}if(t.includeTimestamp){const t=document.createElement("div");t.className="tbw-print-header-timestamp",t.textContent=`Printed: ${/* @__PURE__ */(new Date).toLocaleString()}`,this.#s.appendChild(t)}e.insertBefore(this.#s,e.firstChild),this.#a=document.createElement("div"),this.#a.className="tbw-print-footer",this.#a.textContent=`Page generated from ${window.location.hostname}`,e.appendChild(this.#a)}}async#m(){const t=this.#l;if(!t._virtualization)return;const e=this.rows.length;t._virtualization.bypassThreshold=e+100,t.refreshVirtualWindow(!0),await new Promise(t=>setTimeout(t,100))}async#u(){return new Promise(t=>{const e=()=>{window.removeEventListener("afterprint",e),t()};window.addEventListener("afterprint",e),window.print(),setTimeout(()=>{"undefined"!=typeof window&&window.removeEventListener("afterprint",e),t()},1e3)})}async#h(t){const e=this.gridElement;e&&await n(e,{orientation:t.orientation})}#c(){const t=this.columns;if(t){this.#n=/* @__PURE__ */new Map;for(const e of t)e.printHidden&&e.field&&(this.#n.set(e.field,!e.hidden),this.grid.setColumnVisible(e.field,!1))}}#w(){if(this.#n){for(const[t,e]of this.#n)this.grid.setColumnVisible(t,e);this.#n=null}}#g(){const t=this.gridElement;if(!t)return;this.#w(),t.classList.remove("print-portrait","print-landscape"),null!==this.#d&&(t.style.transform="",t.style.transformOrigin="",t.style.width="",this.#d=null),this.#s&&(this.#s.remove(),this.#s=null),this.#a&&(this.#a.remove(),this.#a=null);const e=this.#l;this.#r&&e._virtualization&&(e._virtualization.bypassThreshold=this.#r.bypassThreshold,e.refreshVirtualWindow(!0),this.#r=null),null!==this.#o&&(this.grid.rows=this.#o,this.#o=null)}afterRender(){this.config?.button&&!this.#b&&(this.#f(),this.#b=!0)}#b=!1;#f(){const t=this.#l;t.registerToolbarContent?.({id:"print-button",order:900,render:t=>{const e=document.createElement("button");e.className="tbw-toolbar-btn tbw-print-btn",e.title="Print grid",e.type="button",this.setIcon(e,"print"),e.addEventListener("click",()=>{this.print()},{signal:this.disconnectSignal}),t.appendChild(e)}})}}export{h as PrintPlugin,n as printGridIsolated};
2
2
  //# sourceMappingURL=index.js.map