@toolbox-web/grid 2.0.0-rc.1 → 2.0.0-rc.3

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 (110) hide show
  1. package/README.md +23 -6
  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/diagnostics.d.ts +9 -1
  7. package/lib/core/internal/sorting.d.ts +4 -0
  8. package/lib/core/plugin/base-plugin.d.ts +31 -0
  9. package/lib/core/plugin/plugin-manager.d.ts +4 -1
  10. package/lib/core/plugin/types.d.ts +2 -0
  11. package/lib/core/types.d.ts +20 -1
  12. package/lib/features/registry.js.map +1 -1
  13. package/lib/plugins/clipboard/ClipboardPlugin.d.ts +8 -1
  14. package/lib/plugins/clipboard/index.js +1 -1
  15. package/lib/plugins/clipboard/index.js.map +1 -1
  16. package/lib/plugins/column-virtualization/index.js +1 -1
  17. package/lib/plugins/column-virtualization/index.js.map +1 -1
  18. package/lib/plugins/context-menu/index.js +1 -1
  19. package/lib/plugins/context-menu/index.js.map +1 -1
  20. package/lib/plugins/editing/index.js +1 -1
  21. package/lib/plugins/editing/index.js.map +1 -1
  22. package/lib/plugins/export/ExportPlugin.d.ts +8 -1
  23. package/lib/plugins/export/index.js +1 -1
  24. package/lib/plugins/export/index.js.map +1 -1
  25. package/lib/plugins/filtering/index.js +1 -1
  26. package/lib/plugins/filtering/index.js.map +1 -1
  27. package/lib/plugins/grouping-columns/index.js +1 -1
  28. package/lib/plugins/grouping-columns/index.js.map +1 -1
  29. package/lib/plugins/grouping-rows/GroupingRowsPlugin.d.ts +46 -22
  30. package/lib/plugins/grouping-rows/grouping-rows.d.ts +15 -1
  31. package/lib/plugins/grouping-rows/index.js +2 -2
  32. package/lib/plugins/grouping-rows/index.js.map +1 -1
  33. package/lib/plugins/grouping-rows/types.d.ts +7 -35
  34. package/lib/plugins/master-detail/MasterDetailPlugin.d.ts +30 -0
  35. package/lib/plugins/master-detail/index.js +1 -1
  36. package/lib/plugins/master-detail/index.js.map +1 -1
  37. package/lib/plugins/multi-sort/index.js +1 -1
  38. package/lib/plugins/multi-sort/index.js.map +1 -1
  39. package/lib/plugins/pinned-columns/index.js +1 -1
  40. package/lib/plugins/pinned-columns/index.js.map +1 -1
  41. package/lib/plugins/pinned-rows/index.js +1 -1
  42. package/lib/plugins/pinned-rows/index.js.map +1 -1
  43. package/lib/plugins/pivot/PivotPlugin.d.ts +10 -0
  44. package/lib/plugins/pivot/index.js +1 -1
  45. package/lib/plugins/pivot/index.js.map +1 -1
  46. package/lib/plugins/print/index.js +1 -1
  47. package/lib/plugins/print/index.js.map +1 -1
  48. package/lib/plugins/reorder-columns/index.js +1 -1
  49. package/lib/plugins/reorder-columns/index.js.map +1 -1
  50. package/lib/plugins/reorder-rows/RowReorderPlugin.d.ts +3 -0
  51. package/lib/plugins/reorder-rows/index.js +1 -1
  52. package/lib/plugins/reorder-rows/index.js.map +1 -1
  53. package/lib/plugins/responsive/index.js +1 -1
  54. package/lib/plugins/responsive/index.js.map +1 -1
  55. package/lib/plugins/selection/index.js +1 -1
  56. package/lib/plugins/selection/index.js.map +1 -1
  57. package/lib/plugins/server-side/ServerSidePlugin.d.ts +48 -14
  58. package/lib/plugins/server-side/datasource-types.d.ts +189 -0
  59. package/lib/plugins/server-side/datasource.d.ts +5 -5
  60. package/lib/plugins/server-side/index.d.ts +1 -1
  61. package/lib/plugins/server-side/index.js +1 -1
  62. package/lib/plugins/server-side/index.js.map +1 -1
  63. package/lib/plugins/server-side/types.d.ts +8 -82
  64. package/lib/plugins/tooltip/index.js +1 -1
  65. package/lib/plugins/tooltip/index.js.map +1 -1
  66. package/lib/plugins/tree/TreePlugin.d.ts +26 -4
  67. package/lib/plugins/tree/index.js +1 -1
  68. package/lib/plugins/tree/index.js.map +1 -1
  69. package/lib/plugins/tree/tree-datasource.d.ts +13 -0
  70. package/lib/plugins/tree/types.d.ts +19 -0
  71. package/lib/plugins/undo-redo/index.js +1 -1
  72. package/lib/plugins/undo-redo/index.js.map +1 -1
  73. package/lib/plugins/visibility/index.js +1 -1
  74. package/lib/plugins/visibility/index.js.map +1 -1
  75. package/package.json +1 -1
  76. package/public.d.ts +3 -0
  77. package/umd/grid.all.umd.js +1 -1
  78. package/umd/grid.all.umd.js.map +1 -1
  79. package/umd/grid.umd.js +1 -1
  80. package/umd/grid.umd.js.map +1 -1
  81. package/umd/plugins/clipboard.umd.js +1 -1
  82. package/umd/plugins/clipboard.umd.js.map +1 -1
  83. package/umd/plugins/context-menu.umd.js +1 -1
  84. package/umd/plugins/context-menu.umd.js.map +1 -1
  85. package/umd/plugins/editing.umd.js +1 -1
  86. package/umd/plugins/editing.umd.js.map +1 -1
  87. package/umd/plugins/export.umd.js +1 -1
  88. package/umd/plugins/export.umd.js.map +1 -1
  89. package/umd/plugins/filtering.umd.js +1 -1
  90. package/umd/plugins/filtering.umd.js.map +1 -1
  91. package/umd/plugins/grouping-rows.umd.js +1 -1
  92. package/umd/plugins/grouping-rows.umd.js.map +1 -1
  93. package/umd/plugins/master-detail.umd.js +1 -1
  94. package/umd/plugins/master-detail.umd.js.map +1 -1
  95. package/umd/plugins/multi-sort.umd.js +1 -1
  96. package/umd/plugins/multi-sort.umd.js.map +1 -1
  97. package/umd/plugins/pinned-columns.umd.js +1 -1
  98. package/umd/plugins/pinned-columns.umd.js.map +1 -1
  99. package/umd/plugins/pivot.umd.js +1 -1
  100. package/umd/plugins/pivot.umd.js.map +1 -1
  101. package/umd/plugins/reorder-rows.umd.js +1 -1
  102. package/umd/plugins/reorder-rows.umd.js.map +1 -1
  103. package/umd/plugins/selection.umd.js +1 -1
  104. package/umd/plugins/selection.umd.js.map +1 -1
  105. package/umd/plugins/server-side.umd.js +1 -1
  106. package/umd/plugins/server-side.umd.js.map +1 -1
  107. package/umd/plugins/tooltip.umd.js +1 -1
  108. package/umd/plugins/tooltip.umd.js.map +1 -1
  109. package/umd/plugins/tree.umd.js +1 -1
  110. package/umd/plugins/tree.umd.js.map +1 -1
@@ -1,10 +1,12 @@
1
- import { BaseGridPlugin, ScrollEvent, PluginManifest } from '../../core/plugin/base-plugin';
2
- import { ServerSideConfig, ServerSideDataSource } from './types';
1
+ import { BaseGridPlugin, ScrollEvent, PluginManifest, PluginQuery } from '../../core/plugin/base-plugin';
2
+ import { ServerSideDataSource } from './datasource-types';
3
+ import { ServerSideConfig } from './types';
3
4
  /**
4
5
  * Server-Side Data Plugin for tbw-grid
5
6
  *
6
- * Enables lazy loading of data from a remote server with caching and block-based fetching.
7
- * Ideal for large datasets where loading all data upfront is impractical.
7
+ * Central data orchestrator for the grid. Manages fetch, cache, and row-model for
8
+ * server-side data loading. Structural plugins (Tree, GroupingRows) can claim data
9
+ * via events; the core grid uses it as flat rows when unclaimed.
8
10
  *
9
11
  * ## Installation
10
12
  *
@@ -17,6 +19,7 @@ import { ServerSideConfig, ServerSideDataSource } from './types';
17
19
  * ```ts
18
20
  * interface ServerSideDataSource {
19
21
  * getRows(params: GetRowsParams): Promise<GetRowsResult>;
22
+ * getChildRows?(params: GetChildRowsParams): Promise<GetChildRowsResult>;
20
23
  * }
21
24
  * ```
22
25
  *
@@ -28,10 +31,10 @@ import { ServerSideConfig, ServerSideDataSource } from './types';
28
31
  * const dataSource = {
29
32
  * async getRows(params) {
30
33
  * const response = await fetch(
31
- * `/api/data?start=${params.startRow}&end=${params.endRow}`
34
+ * `/api/data?start=${params.startNode}&end=${params.endNode}`
32
35
  * );
33
36
  * const data = await response.json();
34
- * return { rows: data.rows, totalRowCount: data.total };
37
+ * return { rows: data.rows, totalNodeCount: data.total };
35
38
  * },
36
39
  * };
37
40
  *
@@ -51,7 +54,7 @@ import { ServerSideConfig, ServerSideDataSource } from './types';
51
54
  */
52
55
  export declare class ServerSidePlugin extends BaseGridPlugin<ServerSideConfig> {
53
56
  /**
54
- * Plugin manifest declaring incompatibilities with other plugins.
57
+ * Plugin manifest declaring capabilities, hooks, events, and queries.
55
58
  * @internal
56
59
  */
57
60
  static readonly manifest: PluginManifest;
@@ -60,15 +63,31 @@ export declare class ServerSidePlugin extends BaseGridPlugin<ServerSideConfig> {
60
63
  /** @internal */
61
64
  protected get defaultConfig(): Partial<ServerSideConfig>;
62
65
  private dataSource;
63
- private totalRowCount;
66
+ private totalNodeCount;
64
67
  private loadedBlocks;
65
68
  private loadingBlocks;
66
69
  private lastRequestId;
67
70
  private scrollDebounceTimer?;
68
- /** Persistent row array with stable placeholder references to avoid unnecessary DOM rebuilds. */
69
- private managedRows;
71
+ /** Persistent node array with stable placeholder references to avoid unnecessary DOM rebuilds. */
72
+ private managedNodes;
73
+ /** @internal */
74
+ attach(grid: import('../../core/plugin/base-plugin').GridElement): void;
70
75
  /** @internal */
71
76
  detach(): void;
77
+ /**
78
+ * Build enrichment params by querying sort/filter models from loaded plugins.
79
+ */
80
+ private getEnrichmentParams;
81
+ /**
82
+ * Translate visible viewport indices to node-space indices via structural plugins.
83
+ * Falls back to 1:1 mapping (flat data) when no structural plugin responds.
84
+ */
85
+ private getViewportMapping;
86
+ /**
87
+ * Handle sort or filter model changes.
88
+ * Purge cache and refetch current viewport with new enrichment params.
89
+ */
90
+ private onModelChange;
72
91
  /**
73
92
  * Check current viewport and load any missing blocks.
74
93
  */
@@ -77,13 +96,20 @@ export declare class ServerSidePlugin extends BaseGridPlugin<ServerSideConfig> {
77
96
  processRows(rows: readonly unknown[]): unknown[];
78
97
  /** @internal */
79
98
  onScroll(event: ScrollEvent): void;
99
+ /** @internal */
100
+ handleQuery(query: PluginQuery): unknown;
101
+ /**
102
+ * Fetch child rows via the datasource and broadcast the result.
103
+ */
104
+ private fetchChildren;
80
105
  /**
81
106
  * Set the data source for server-side loading.
82
- * @param dataSource - Data source implementing the getRows method
107
+ * @param dataSource - Data source implementing the getRows method (and optionally getChildRows)
83
108
  */
84
109
  setDataSource(dataSource: ServerSideDataSource): void;
85
110
  /**
86
111
  * Refresh all data from the server.
112
+ * Purges cache and refetches from block 0.
87
113
  */
88
114
  refresh(): void;
89
115
  /**
@@ -91,12 +117,20 @@ export declare class ServerSidePlugin extends BaseGridPlugin<ServerSideConfig> {
91
117
  */
92
118
  purgeCache(): void;
93
119
  /**
94
- * Get the total row count from the server.
120
+ * Get the total node count from the server.
121
+ */
122
+ getTotalNodeCount(): number;
123
+ /**
124
+ * @deprecated Use {@link getTotalNodeCount} instead. Will be removed in a future version.
95
125
  */
96
126
  getTotalRowCount(): number;
97
127
  /**
98
- * Check if a specific row is loaded in the cache.
99
- * @param rowIndex - Row index to check
128
+ * Check if a specific node is loaded in the cache.
129
+ * @param nodeIndex - Node index to check
130
+ */
131
+ isNodeLoaded(nodeIndex: number): boolean;
132
+ /**
133
+ * @deprecated Use {@link isNodeLoaded} instead. Will be removed in a future version.
100
134
  */
101
135
  isRowLoaded(rowIndex: number): boolean;
102
136
  /**
@@ -0,0 +1,189 @@
1
+ /** Sort/filter state passed through to the server. */
2
+ export interface DataRequestModel {
3
+ /** Active sort columns, in priority order. Empty array when unsorted. */
4
+ sortModel?: Array<{
5
+ field: string;
6
+ direction: 'asc' | 'desc';
7
+ }>;
8
+ /** Active filter model keyed by field name. Empty object when no filters are applied. */
9
+ filterModel?: Record<string, unknown>;
10
+ }
11
+ /**
12
+ * Parameters passed to {@link ServerSideDataSource.getRows} for each data request.
13
+ *
14
+ * Pagination is in **node space** — one node equals one atomic pagination unit.
15
+ * For flat data, a node is a row. For tree data, a node is a top-level tree node.
16
+ * For grouped data, a node is a group definition.
17
+ *
18
+ * The grid enriches these params with the current sort/filter state from loaded plugins
19
+ * (MultiSort, Filtering) so the server can apply them remotely.
20
+ */
21
+ export interface GetRowsParams extends DataRequestModel {
22
+ /** Zero-based index of the first node to fetch (inclusive). */
23
+ startNode: number;
24
+ /** Zero-based index of the last node to fetch (exclusive). `endNode - startNode` equals the block size. */
25
+ endNode: number;
26
+ }
27
+ /**
28
+ * Result returned from {@link ServerSideDataSource.getRows}.
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * // Known total (pagination-style)
33
+ * return { rows: pageData, totalNodeCount: 5000 };
34
+ *
35
+ * // Infinite scroll — set lastNode when the final page is reached
36
+ * return { rows: pageData, totalNodeCount: -1, lastNode: absoluteLastIndex };
37
+ * ```
38
+ */
39
+ export interface GetRowsResult<TRow = unknown> {
40
+ /** The fetched top-level node objects for the requested range. */
41
+ rows: TRow[];
42
+ /**
43
+ * Total number of top-level nodes available on the server.
44
+ * Use `-1` if unknown (infinite scroll mode).
45
+ */
46
+ totalNodeCount: number;
47
+ /**
48
+ * The absolute index of the last available node.
49
+ * Only needed for **infinite scroll** when `totalNodeCount` is `-1`.
50
+ * Once the server returns the final page, set this so the grid knows
51
+ * scrolling has reached the end and stops requesting further blocks.
52
+ */
53
+ lastNode?: number;
54
+ }
55
+ /**
56
+ * Parameters for fetching child rows of a parent node.
57
+ *
58
+ * The `context` is opaque — provided by the requesting plugin and passed through
59
+ * to the user's `getChildRows` callback verbatim. Each plugin sets a `source`
60
+ * discriminator so listeners can filter incoming child events.
61
+ *
62
+ * Known context shapes:
63
+ * - Tree: `{ source: 'tree', parentNode: TreeRow, nodePath: string[] }`
64
+ * - GroupingRows: `{ source: 'grouping-rows', group: GroupDefinition, groupPath: string[] }`
65
+ * - MasterDetail: `{ source: 'master-detail', row: TRow, rowIndex: number }`
66
+ *
67
+ * Child rows are fetched as a single batch — no pagination.
68
+ */
69
+ export interface GetChildRowsParams extends DataRequestModel {
70
+ /**
71
+ * Opaque context from the requesting plugin.
72
+ * Contains a `source` discriminator string and plugin-specific fields.
73
+ * ServerSide does not interpret this object.
74
+ */
75
+ context: {
76
+ source: string;
77
+ [key: string]: unknown;
78
+ };
79
+ }
80
+ /**
81
+ * Result returned from {@link ServerSideDataSource.getChildRows}.
82
+ * All children are returned in a single batch (no pagination).
83
+ */
84
+ export interface GetChildRowsResult<TRow = unknown> {
85
+ rows: TRow[];
86
+ }
87
+ /**
88
+ * Unified data source contract for server-side data loading.
89
+ *
90
+ * Implement `getRows` to supply root-level rows from a remote API, database,
91
+ * or any asynchronous provider. The grid calls `getRows()` whenever it needs
92
+ * a new block of rows (on initial load, scroll, sort change, or filter change).
93
+ *
94
+ * Optionally implement `getChildRows` for on-demand child data (tree children,
95
+ * group rows, detail panels, etc.). If child data is already embedded in
96
+ * parent rows (e.g. tree nodes with inline `children` arrays), this method
97
+ * is not needed.
98
+ *
99
+ * @example
100
+ * ```typescript
101
+ * const dataSource: ServerSideDataSource = {
102
+ * async getRows(params) {
103
+ * const res = await fetch(`/api/data?start=${params.startNode}&end=${params.endNode}`);
104
+ * const data = await res.json();
105
+ * return { rows: data.items, totalNodeCount: data.total };
106
+ * },
107
+ * async getChildRows(params) {
108
+ * const { source, parentId } = params.context;
109
+ * const res = await fetch(`/api/data/${parentId}/children`);
110
+ * return { rows: await res.json() };
111
+ * }
112
+ * };
113
+ * ```
114
+ */
115
+ export interface ServerSideDataSource<TRow = unknown> {
116
+ /**
117
+ * Fetch a page/block of root-level nodes.
118
+ * Called on initial load and on scroll/page events.
119
+ *
120
+ * Before calling this, ServerSide queries loaded plugins for their
121
+ * current state (sort model, filter model, etc.) and passes it
122
+ * through in the params.
123
+ */
124
+ getRows(params: GetRowsParams): Promise<GetRowsResult<TRow>>;
125
+ /**
126
+ * Fetch child rows for a parent context.
127
+ * Called when a plugin queries `datasource:fetch-children`.
128
+ *
129
+ * Child rows are fetched as a single batch — no pagination.
130
+ * If the dataset is too large, the server should limit the response.
131
+ *
132
+ * This method is optional. When not provided and a plugin queries
133
+ * for children, ServerSide emits a `TBW142` diagnostic warning.
134
+ */
135
+ getChildRows?(params: GetChildRowsParams): Promise<GetChildRowsResult<TRow>>;
136
+ }
137
+ /** Detail for `datasource:data` broadcast events. */
138
+ export interface DataSourceDataDetail<TRow = unknown> {
139
+ rows: TRow[];
140
+ totalNodeCount: number;
141
+ startNode: number;
142
+ endNode: number;
143
+ /** Mutable flag — structural plugins set this to `true` when they consume the data. */
144
+ claimed: boolean;
145
+ }
146
+ /** Detail for `datasource:children` broadcast events. */
147
+ export interface DataSourceChildrenDetail<TRow = unknown> {
148
+ rows: TRow[];
149
+ context: {
150
+ source: string;
151
+ [key: string]: unknown;
152
+ };
153
+ /** Mutable flag — the requesting plugin sets this to `true` when it consumes the data. */
154
+ claimed: boolean;
155
+ }
156
+ /** Detail for `datasource:loading` broadcast events. */
157
+ export interface DataSourceLoadingDetail {
158
+ loading: boolean;
159
+ context?: {
160
+ source: string;
161
+ [key: string]: unknown;
162
+ };
163
+ }
164
+ /** Detail for `datasource:error` broadcast events. */
165
+ export interface DataSourceErrorDetail {
166
+ error: Error;
167
+ context?: {
168
+ source: string;
169
+ [key: string]: unknown;
170
+ };
171
+ }
172
+ /** Context for `datasource:viewport-mapping` query. */
173
+ export interface ViewportMappingQuery {
174
+ viewportStart: number;
175
+ viewportEnd: number;
176
+ }
177
+ /** Response from `datasource:viewport-mapping` query. */
178
+ export interface ViewportMappingResponse {
179
+ startNode: number;
180
+ endNode: number;
181
+ totalLoadedNodes: number;
182
+ }
183
+ /** Context for `datasource:fetch-children` query. */
184
+ export interface FetchChildrenQuery {
185
+ context: {
186
+ source: string;
187
+ [key: string]: unknown;
188
+ };
189
+ }
@@ -1,11 +1,11 @@
1
- import { ServerSideDataSource, GetRowsParams, GetRowsResult } from './types';
2
- export declare function getBlockNumber(rowIndex: number, blockSize: number): number;
1
+ import { GetRowsParams, GetRowsResult, ServerSideDataSource } from './datasource-types';
2
+ export declare function getBlockNumber(nodeIndex: number, blockSize: number): number;
3
3
  export declare function getBlockRange(blockNumber: number, blockSize: number): {
4
4
  start: number;
5
5
  end: number;
6
6
  };
7
- export declare function getRequiredBlocks(startRow: number, endRow: number, blockSize: number): number[];
7
+ export declare function getRequiredBlocks(startNode: number, endNode: number, blockSize: number): number[];
8
8
  export declare function loadBlock(dataSource: ServerSideDataSource, blockNumber: number, blockSize: number, params: Partial<GetRowsParams>): Promise<GetRowsResult>;
9
- export declare function getRowFromCache(rowIndex: number, blockSize: number, loadedBlocks: Map<number, any[]>): any | undefined;
10
- export declare function isBlockLoaded(blockNumber: number, loadedBlocks: Map<number, any[]>): boolean;
9
+ export declare function getRowFromCache(nodeIndex: number, blockSize: number, loadedBlocks: Map<number, unknown[]>): unknown | undefined;
10
+ export declare function isBlockLoaded(blockNumber: number, loadedBlocks: Map<number, unknown[]>): boolean;
11
11
  export declare function isBlockLoading(blockNumber: number, loadingBlocks: Set<number>): boolean;
@@ -5,4 +5,4 @@
5
5
  * @module Plugins/Server-Side
6
6
  */
7
7
  export { ServerSidePlugin } from './ServerSidePlugin';
8
- export type { GetRowsParams, GetRowsResult, ServerSideConfig, ServerSideDataSource } from './types';
8
+ export type { DataRequestModel, DataSourceChildrenDetail, DataSourceDataDetail, DataSourceErrorDetail, DataSourceLoadingDetail, FetchChildrenQuery, GetChildRowsParams, GetChildRowsResult, GetRowsParams, GetRowsResult, ServerSideConfig, ServerSideDataSource, ViewportMappingQuery, ViewportMappingResponse, } from './types';
@@ -1,2 +1,2 @@
1
- function e(e,t){return`[tbw-grid${e?`#${e}`:""}${t?`:${t}`:""}]`}function t(t,o,r,s){return`${e(r,s)} ${t}: ${o}\n\n → More info: ${function(e){return`https://toolboxjs.com/grid/errors#${e.toLowerCase()}`}(t)}`}["__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 o=/* @__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"]),r=/^on\w+$/i,s=/* @__PURE__ */new Set(["href","src","action","formaction","data","srcdoc","xlink:href","poster","srcset"]),i=/^\s*(javascript|vbscript|data|blob):/i;function n(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=[],n=e.querySelectorAll("*");for(const a of n){const e=a.tagName.toLowerCase();if(o.has(e)){t.push(a);continue}if("svg"===e||"http://www.w3.org/2000/svg"===a.namespaceURI){if(Array.from(a.attributes).some(e=>r.test(e.name)||"href"===e.name||"xlink:href"===e.name)){t.push(a);continue}}const n=[];for(const t of a.attributes){const e=t.name.toLowerCase();r.test(e)?n.push(t.name):(s.has(e)&&i.test(t.value)||"style"===e&&/expression\s*\(|javascript:|behavior\s*:/i.test(t.value))&&n.push(t.name)}n.forEach(e=>a.removeAttribute(e))}t.forEach(e=>e.remove())}(t.content),t.innerHTML}const a='<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:a,filterActive:a,print:"🖨️"};class c{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 o=new CustomEvent(e,{detail:t,bubbles:!0,cancelable:!0});return this.grid?.dispatchEvent?.(o),o.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(),o=parseInt(t,10);if(!isNaN(o))return o}return 200}setIcon(e,t,o){e.dataset.icon=t.replace(/([A-Z])/g,"-$1").toLowerCase(),"collapse"===t?e.dataset.expanded="":"expand"===t&&delete e.dataset.expanded;const r=this.#t(t,o);void 0!==r?"string"==typeof r?e.innerHTML=n(r):r instanceof HTMLElement&&(e.innerHTML="",e.appendChild(r.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 o=document.createElement("span");o.setAttribute("part","sort-indicator"),o.className="sort-indicator",t?(e.setAttribute("aria-sort","asc"===t?"ascending":"descending"),e.setAttribute("data-sort",t),this.setIcon(o,"asc"===t?"sortAsc":"sortDesc")):(e.setAttribute("aria-sort","none"),e.removeAttribute("data-sort"),this.setIcon(o,"sortNone"));const r=e.querySelector(".tbw-filter-btn")??e.querySelector(".resize-handle");return r?e.insertBefore(o,r):e.appendChild(o),o}warn(o,r){void 0!==r?console.warn(t(o,r,this.gridElement.id,this.name)):console.warn(`${e(this.gridElement.id,this.name)} ${o}`)}throwDiagnostic(e,o){throw new Error(t(e,o,this.gridElement.id,this.name))}}function d(e,t){return Math.floor(e/t)}async function u(e,t,o,r){const s=function(e,t){return{start:e*t,end:(e+1)*t}}(t,o);return e.getRows({startRow:s.start,endRow:s.end,sortModel:r.sortModel,filterModel:r.filterModel})}function h(e,t,o){const r=d(e,t),s=o.get(r);if(!s)return;return s[e%t]}class g extends c{static manifest={incompatibleWith:[{name:"tree",reason:"TreePlugin requires the full hierarchy to flatten and manage expansion state. ServerSidePlugin lazy-loads rows in blocks and cannot provide nested children on demand. Server-side tree would require lazy child loading as nodes expand."},{name:"pivot",reason:"PivotPlugin requires the full dataset to compute aggregations. ServerSidePlugin lazy-loads rows in blocks, so pivot aggregation cannot be performed client-side."}]};name="serverSide";get defaultConfig(){return{pageSize:100,cacheBlockSize:100,maxConcurrentRequests:2}}dataSource=null;totalRowCount=0;loadedBlocks=/* @__PURE__ */new Map;loadingBlocks=/* @__PURE__ */new Set;lastRequestId=0;scrollDebounceTimer;managedRows=[];detach(){this.dataSource=null,this.totalRowCount=0,this.loadedBlocks.clear(),this.loadingBlocks.clear(),this.managedRows=[],this.lastRequestId=0,this.scrollDebounceTimer&&(clearTimeout(this.scrollDebounceTimer),this.scrollDebounceTimer=void 0)}loadRequiredBlocks(){if(!this.dataSource)return;const e=this.grid,t=this.config.cacheBlockSize??100,o={startRow:e._virtualization.start,endRow:e._virtualization.end},r=function(e,t,o){const r=d(e,o),s=d(t-1,o),i=[];for(let n=r;n<=s;n++)i.push(n);return i}(o.startRow,o.endRow,t);for(const s of r)if(!this.loadedBlocks.has(s)&&!this.loadingBlocks.has(s)){if(this.loadingBlocks.size>=(this.config.maxConcurrentRequests??2))break;this.loadingBlocks.add(s),u(this.dataSource,s,t,{}).then(e=>{this.loadedBlocks.set(s,e.rows),this.totalRowCount=e.totalRowCount,this.loadingBlocks.delete(s);const o=s*t;for(let t=0;t<e.rows.length;t++)o+t<this.managedRows.length&&(this.managedRows[o+t]=e.rows[t]);this.requestVirtualRefresh(),this.loadRequiredBlocks()}).catch(()=>{this.loadingBlocks.delete(s)})}}processRows(e){if(!this.dataSource)return[...e];const t=this.config.cacheBlockSize??100;for(;this.managedRows.length<this.totalRowCount;){const e=this.managedRows.length;this.managedRows.push({__loading:!0,__index:e})}this.managedRows.length=this.totalRowCount;for(let o=0;o<this.totalRowCount;o++){const e=h(o,t,this.loadedBlocks);e&&(this.managedRows[o]=e)}return this.managedRows}onScroll(e){this.dataSource&&(this.loadRequiredBlocks(),this.scrollDebounceTimer&&clearTimeout(this.scrollDebounceTimer),this.scrollDebounceTimer=setTimeout(()=>{this.loadRequiredBlocks()},100))}setDataSource(e){this.dataSource=e,this.loadedBlocks.clear(),this.loadingBlocks.clear(),this.managedRows=[];u(e,0,this.config.cacheBlockSize??100,{}).then(e=>{this.loadedBlocks.set(0,e.rows),this.totalRowCount=e.totalRowCount,this.requestRender()})}refresh(){this.dataSource&&(this.loadedBlocks.clear(),this.loadingBlocks.clear(),this.managedRows=[],this.requestRender())}purgeCache(){this.loadedBlocks.clear(),this.managedRows=[]}getTotalRowCount(){return this.totalRowCount}isRowLoaded(e){const t=d(e,this.config.cacheBlockSize??100);return this.loadedBlocks.has(t)}getLoadedBlockCount(){return this.loadedBlocks.size}}export{g as ServerSidePlugin};
1
+ function t(t,e){return`[tbw-grid${t?`#${t}`:""}${e?`:${e}`:""}]`}const e="TBW140";function o(e,o,r,s){return`${t(r,s)} ${e}: ${o}\n\n → More info: ${function(t){return`https://toolboxjs.com/grid/errors#${t.toLowerCase()}`}(e)}`}function r(t,e,r,s){console.debug(o(t,e,r,s))}function s(t,e,r,s){console.error(o(t,e,r,s))}["__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 i=/* @__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"]),n=/^on\w+$/i,a=/* @__PURE__ */new Set(["href","src","action","formaction","data","srcdoc","xlink:href","poster","srcset"]),d=/^\s*(javascript|vbscript|data|blob):/i;function c(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=[],o=t.querySelectorAll("*");for(const r of o){const t=r.tagName.toLowerCase();if(i.has(t)){e.push(r);continue}if("svg"===t||"http://www.w3.org/2000/svg"===r.namespaceURI){if(Array.from(r.attributes).some(t=>n.test(t.name)||"href"===t.name||"xlink:href"===t.name)){e.push(r);continue}}const o=[];for(const e of r.attributes){const t=e.name.toLowerCase();n.test(t)?o.push(e.name):(a.has(t)&&d.test(e.value)||"style"===t&&/expression\s*\(|javascript:|behavior\s*:/i.test(e.value))&&o.push(e.name)}o.forEach(t=>r.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>',u={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 o=new CustomEvent(t,{detail:e,bubbles:!0,cancelable:!0});return this.grid?.dispatchEvent?.(o),o.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)}broadcast(t,e){this.emitPluginEvent(t,e),this.emit(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{...u,...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(),o=parseInt(e,10);if(!isNaN(o))return o}return 200}setIcon(t,e,o){t.dataset.icon=e.replace(/([A-Z])/g,"-$1").toLowerCase(),"collapse"===e?t.dataset.expanded="":"expand"===e&&delete t.dataset.expanded;const r=this.#e(e,o);void 0!==r?"string"==typeof r?t.innerHTML=c(r):r instanceof HTMLElement&&(t.innerHTML="",t.appendChild(r.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 o=document.createElement("span");o.setAttribute("part","sort-indicator"),o.className="sort-indicator",e?(t.setAttribute("aria-sort","asc"===e?"ascending":"descending"),t.setAttribute("data-sort",e),this.setIcon(o,"asc"===e?"sortAsc":"sortDesc")):(t.setAttribute("aria-sort","none"),t.removeAttribute("data-sort"),this.setIcon(o,"sortNone"));const r=t.querySelector(".tbw-filter-btn")??t.querySelector(".resize-handle");return r?t.insertBefore(o,r):t.appendChild(o),o}warn(e,r){void 0!==r?console.warn(o(e,r,this.gridElement.id,this.name)):console.warn(`${t(this.gridElement.id,this.name)} ${e}`)}throwDiagnostic(t,e){throw new Error(o(t,e,this.gridElement.id,this.name))}}function g(t,e){return Math.floor(t/e)}async function f(t,e,o,r){const s=function(t,e){return{start:t*e,end:(t+1)*e}}(e,o);return t.getRows({startNode:s.start,endNode:s.end,sortModel:r.sortModel,filterModel:r.filterModel})}function m(t,e,o){const r=g(t,e),s=o.get(r);if(!s)return;return s[t%e]}class p extends h{static manifest={modifiesRowStructure:!0,hookPriority:{processRows:-10},incompatibleWith:[{name:"pivot",reason:"PivotPlugin requires the full dataset to compute aggregations. ServerSidePlugin lazy-loads rows in blocks, so pivot aggregation cannot be performed client-side."}],events:[{type:"datasource:data",description:"Root data page/block loaded"},{type:"datasource:children",description:"Child data loaded for a parent context"},{type:"datasource:loading",description:"Loading state changed"},{type:"datasource:error",description:"Fetch operation failed"}],queries:[{type:"datasource:fetch-children",description:"Request child rows for a parent context"},{type:"datasource:is-active",description:"Check if ServerSide plugin has an active data source"}]};name="serverSide";get defaultConfig(){return{pageSize:100,cacheBlockSize:100,maxConcurrentRequests:2}}dataSource=null;totalNodeCount=0;loadedBlocks=/* @__PURE__ */new Map;loadingBlocks=/* @__PURE__ */new Set;lastRequestId=0;scrollDebounceTimer;managedNodes=[];attach(t){super.attach(t),this.on("sort-change",()=>this.onModelChange()),this.on("filter-change",()=>this.onModelChange())}detach(){this.dataSource=null,this.totalNodeCount=0,this.loadedBlocks.clear(),this.loadingBlocks.clear(),this.managedNodes=[],this.lastRequestId=0,this.scrollDebounceTimer&&(clearTimeout(this.scrollDebounceTimer),this.scrollDebounceTimer=void 0)}getEnrichmentParams(){const t=this.grid?.query?.("sort:get-model",null),e=this.grid?.query?.("filter:get-model",null);return{sortModel:t?.[0],filterModel:e?.[0]}}getViewportMapping(t,e){const o={viewportStart:t,viewportEnd:e},r=this.grid?.query?.("datasource:viewport-mapping",o);return r?.[0]?r[0]:{startNode:t,endNode:e,totalLoadedNodes:this.totalNodeCount}}onModelChange(){this.dataSource&&(this.loadedBlocks.clear(),this.loadingBlocks.clear(),this.managedNodes=[],this.totalNodeCount=0,this.requestRender())}loadRequiredBlocks(){if(!this.dataSource)return;const t=this.grid,o=this.config.cacheBlockSize??100,i=this.getViewportMapping(t._virtualization.start,t._virtualization.end),n=function(t,e,o){const r=g(t,o),s=g(e-1,o),i=[];for(let n=r;n<=s;n++)i.push(n);return i}(i.startNode,i.endNode,o),a=this.getEnrichmentParams(),d=this.grid?.getAttribute?.("id")??void 0;for(const c of n)if(!this.loadedBlocks.has(c)&&!this.loadingBlocks.has(c)){if(this.loadingBlocks.size>=(this.config.maxConcurrentRequests??2)){r("TBW143","Concurrent request limit reached, deferring block load",d);break}this.loadingBlocks.add(c),this.broadcast("datasource:loading",{loading:!0}),f(this.dataSource,c,o,a).then(t=>{this.loadedBlocks.set(c,t.rows),this.totalNodeCount=t.totalNodeCount,this.loadingBlocks.delete(c);const e=c*o;for(let o=0;o<t.rows.length;o++)e+o<this.managedNodes.length&&(this.managedNodes[e+o]=t.rows[o]);const r={rows:t.rows,totalNodeCount:t.totalNodeCount,startNode:e,endNode:e+t.rows.length,claimed:!1};this.broadcast("datasource:data",r),0===this.loadingBlocks.size&&this.broadcast("datasource:loading",{loading:!1}),this.requestVirtualRefresh(),this.loadRequiredBlocks()}).catch(t=>{this.loadingBlocks.delete(c);const o=t instanceof Error?t:new Error(String(t));s(e,`getRows() failed: ${o.message}`,d),this.broadcast("datasource:error",{error:o}),0===this.loadingBlocks.size&&this.broadcast("datasource:loading",{loading:!1})})}}processRows(t){if(!this.dataSource)return[...t];const e=this.config.cacheBlockSize??100,o=Number.isFinite(this.totalNodeCount)&&this.totalNodeCount>=0?this.totalNodeCount:0;for(;this.managedNodes.length<o;){const t=this.managedNodes.length;this.managedNodes.push({__loading:!0,__index:t})}this.managedNodes.length=o;for(let r=0;r<o;r++){const t=m(r,e,this.loadedBlocks);t&&(this.managedNodes[r]=t)}return this.managedNodes}onScroll(t){this.dataSource&&(this.loadRequiredBlocks(),this.scrollDebounceTimer&&clearTimeout(this.scrollDebounceTimer),this.scrollDebounceTimer=setTimeout(()=>{this.loadRequiredBlocks()},100))}handleQuery(t){switch(t.type){case"datasource:is-active":return null!=this.dataSource;case"datasource:fetch-children":{const{context:e}=t.context;return void this.fetchChildren(e)}}}fetchChildren(t){if(!this.dataSource)return;const e=this.grid?.getAttribute?.("id")??void 0;if(!this.dataSource.getChildRows)return void function(t,e,r,s){console.warn(o(t,e,r,s))}("TBW142",`Plugin "${t.source}" requested child rows but getChildRows() is not implemented on the dataSource`,e);const r=this.getEnrichmentParams();this.broadcast("datasource:loading",{loading:!0,context:t}),this.dataSource.getChildRows({context:t,sortModel:r.sortModel,filterModel:r.filterModel}).then(e=>{const o={rows:e.rows,context:t,claimed:!1};this.broadcast("datasource:children",o),this.broadcast("datasource:loading",{loading:!1,context:t})}).catch(o=>{const r=o instanceof Error?o:new Error(String(o));s("TBW141",`getChildRows() failed: ${r.message}`,e),this.broadcast("datasource:error",{error:r,context:t}),this.broadcast("datasource:loading",{loading:!1,context:t})})}setDataSource(t){this.dataSource=t,this.loadedBlocks.clear(),this.loadingBlocks.clear(),this.managedNodes=[],this.totalNodeCount=0;const o=this.config.cacheBlockSize??100,r=this.getEnrichmentParams(),i=this.grid?.getAttribute?.("id")??void 0;this.broadcast("datasource:loading",{loading:!0}),f(t,0,o,r).then(t=>{this.loadedBlocks.set(0,t.rows),this.totalNodeCount=t.totalNodeCount;const e={rows:t.rows,totalNodeCount:t.totalNodeCount,startNode:0,endNode:t.rows.length,claimed:!1};this.broadcast("datasource:data",e),this.broadcast("datasource:loading",{loading:!1}),this.requestRender()}).catch(t=>{const o=t instanceof Error?t:new Error(String(t));s(e,`getRows() failed: ${o.message}`,i),this.broadcast("datasource:error",{error:o}),this.broadcast("datasource:loading",{loading:!1})})}refresh(){if(!this.dataSource)return;const t=this.dataSource;this.loadedBlocks.clear(),this.loadingBlocks.clear(),this.managedNodes=[],this.totalNodeCount=0,this.setDataSource(t)}purgeCache(){this.loadedBlocks.clear(),this.managedNodes=[]}getTotalNodeCount(){return this.totalNodeCount}getTotalRowCount(){return this.totalNodeCount}isNodeLoaded(t){const e=g(t,this.config.cacheBlockSize??100);return this.loadedBlocks.has(e)}isRowLoaded(t){return this.isNodeLoaded(t)}getLoadedBlockCount(){return this.loadedBlocks.size}}export{p as ServerSidePlugin};
2
2
  //# sourceMappingURL=index.js.map