@gridstorm/angular 0.1.2 → 0.1.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.
- package/LICENSE.md +21 -0
- package/README.md +203 -203
- package/dist/index.cjs +11 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +11 -1
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/__tests__/angular-adapter.test.ts +379 -0
- package/src/gridstorm.component.ts +10 -1
package/LICENSE.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 GridStorm Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,203 +1,203 @@
|
|
|
1
|
-
# @gridstorm/angular
|
|
2
|
-
|
|
3
|
-
Angular adapter for [GridStorm](https://grid-data-analytics-explorer.vercel.app/) -- a high-performance, headless data grid engine.
|
|
4
|
-
|
|
5
|
-
Provides a standalone Angular component (`<gridstorm>`) that wraps the GridStorm core engine and DOM renderer. Requires Angular 16+ (standalone component support).
|
|
6
|
-
|
|
7
|
-
## Installation
|
|
8
|
-
|
|
9
|
-
```bash
|
|
10
|
-
npm install @gridstorm/angular @gridstorm/core @gridstorm/dom-renderer
|
|
11
|
-
# or
|
|
12
|
-
pnpm add @gridstorm/angular @gridstorm/core @gridstorm/dom-renderer
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
## Quick Start
|
|
16
|
-
|
|
17
|
-
Import the standalone component directly in your Angular component:
|
|
18
|
-
|
|
19
|
-
```typescript
|
|
20
|
-
import { Component } from '@angular/core';
|
|
21
|
-
import { GridStormComponent } from '@gridstorm/angular';
|
|
22
|
-
import { sortingPlugin } from '@gridstorm/plugin-sorting';
|
|
23
|
-
import type { GridApi, ColumnDef } from '@gridstorm/angular';
|
|
24
|
-
|
|
25
|
-
@Component({
|
|
26
|
-
selector: 'app-employees',
|
|
27
|
-
standalone: true,
|
|
28
|
-
imports: [GridStormComponent],
|
|
29
|
-
template: `
|
|
30
|
-
<gridstorm
|
|
31
|
-
[columns]="columns"
|
|
32
|
-
[rowData]="rowData"
|
|
33
|
-
[plugins]="plugins"
|
|
34
|
-
[rowHeight]="40"
|
|
35
|
-
[theme]="'dark'"
|
|
36
|
-
[density]="'normal'"
|
|
37
|
-
(gridReady)="onGridReady($event)"
|
|
38
|
-
(selectionChanged)="onSelectionChanged($event)"
|
|
39
|
-
style="height: 600px; width: 100%;"
|
|
40
|
-
></gridstorm>
|
|
41
|
-
`,
|
|
42
|
-
})
|
|
43
|
-
export class EmployeesComponent {
|
|
44
|
-
columns: ColumnDef[] = [
|
|
45
|
-
{ field: 'name', headerName: 'Name', sortable: true },
|
|
46
|
-
{ field: 'department', headerName: 'Department', sortable: true },
|
|
47
|
-
{ field: 'salary', headerName: 'Salary', width: 120 },
|
|
48
|
-
];
|
|
49
|
-
|
|
50
|
-
rowData = [
|
|
51
|
-
{ name: 'Alice', department: 'Engineering', salary: 95000 },
|
|
52
|
-
{ name: 'Bob', department: 'Marketing', salary: 72000 },
|
|
53
|
-
{ name: 'Charlie', department: 'Engineering', salary: 110000 },
|
|
54
|
-
];
|
|
55
|
-
|
|
56
|
-
plugins = [sortingPlugin()];
|
|
57
|
-
|
|
58
|
-
private gridApi: GridApi | null = null;
|
|
59
|
-
|
|
60
|
-
onGridReady(api: GridApi) {
|
|
61
|
-
this.gridApi = api;
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
onSelectionChanged(event: any) {
|
|
65
|
-
console.log('Selection changed:', event);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
## Inputs
|
|
71
|
-
|
|
72
|
-
| Input | Type | Default | Description |
|
|
73
|
-
| ------------------- | --------------------------- | ---------- | ----------------------------------------------- |
|
|
74
|
-
| `columns` | `ColumnDef[]` | `[]` | Column definitions |
|
|
75
|
-
| `rowData` | `any[]` | `[]` | Row data array |
|
|
76
|
-
| `plugins` | `GridPlugin[]` | `[]` | Plugins to install |
|
|
77
|
-
| `getRowId` | `(params) => string` | `undefined`| Custom row ID generator |
|
|
78
|
-
| `rowHeight` | `number` | `40` | Row height in pixels |
|
|
79
|
-
| `theme` | `string` | `'light'` | Theme name (`'light'`, `'dark'`, or custom) |
|
|
80
|
-
| `density` | `string` | `'normal'` | Density mode (`'compact'`, `'normal'`, etc.) |
|
|
81
|
-
| `defaultColDef` | `Partial<ColumnDef>` | `undefined`| Default column config applied to all columns |
|
|
82
|
-
| `paginationPageSize`| `number` | `undefined`| Rows per page (when pagination enabled) |
|
|
83
|
-
| `headerHeight` | `number` | `undefined`| Header row height in pixels |
|
|
84
|
-
| `domLayout` | `'normal' \| 'autoHeight'` | `undefined`| DOM layout mode |
|
|
85
|
-
| `rowSelection` | `'single' \| 'multiple'` | `undefined`| Row selection mode |
|
|
86
|
-
| `pagination` | `boolean` | `undefined`| Enable client-side pagination |
|
|
87
|
-
| `ariaLabel` | `string` | `undefined`| ARIA label for accessibility |
|
|
88
|
-
|
|
89
|
-
## Outputs
|
|
90
|
-
|
|
91
|
-
| Output | Payload | Description |
|
|
92
|
-
| ------------------- | --------------------------- | ----------------------------------------------- |
|
|
93
|
-
| `gridReady` | `GridApi` | Grid initialized, API is ready |
|
|
94
|
-
| `rowDataChanged` | `{ rowData: any[] }` | Row data was replaced |
|
|
95
|
-
| `selectionChanged` | `{ selectedNodes, source }` | Row selection changed |
|
|
96
|
-
| `sortChanged` | `{ sortModel }` | Sort model changed |
|
|
97
|
-
| `filterChanged` | `{ filterModel }` | Filter model changed |
|
|
98
|
-
| `cellValueChanged` | `{ node, colId, ... }` | Cell value edited |
|
|
99
|
-
| `cellClicked` | `{ node, colId, value }` | Cell was clicked |
|
|
100
|
-
| `cellDoubleClicked` | `{ node, colId, value }` | Cell was double-clicked |
|
|
101
|
-
| `rowClicked` | `{ node, event }` | Row was clicked |
|
|
102
|
-
| `paginationChanged` | `{ currentPage, ... }` | Pagination state changed |
|
|
103
|
-
| `columnResized` | `{ column, ... }` | Column was resized |
|
|
104
|
-
|
|
105
|
-
## GridStormService
|
|
106
|
-
|
|
107
|
-
An injectable service for managing multiple grid instances across your application:
|
|
108
|
-
|
|
109
|
-
```typescript
|
|
110
|
-
import { Component, OnDestroy } from '@angular/core';
|
|
111
|
-
import { GridStormComponent, GridStormService } from '@gridstorm/angular';
|
|
112
|
-
import type { GridApi } from '@gridstorm/angular';
|
|
113
|
-
|
|
114
|
-
@Component({
|
|
115
|
-
selector: 'app-dashboard',
|
|
116
|
-
standalone: true,
|
|
117
|
-
imports: [GridStormComponent],
|
|
118
|
-
template: `
|
|
119
|
-
<gridstorm
|
|
120
|
-
[columns]="columns"
|
|
121
|
-
[rowData]="rowData"
|
|
122
|
-
(gridReady)="onGridReady($event)"
|
|
123
|
-
></gridstorm>
|
|
124
|
-
`,
|
|
125
|
-
})
|
|
126
|
-
export class DashboardComponent implements OnDestroy {
|
|
127
|
-
// ... columns, rowData ...
|
|
128
|
-
|
|
129
|
-
constructor(private gridService: GridStormService) {}
|
|
130
|
-
|
|
131
|
-
onGridReady(api: GridApi) {
|
|
132
|
-
this.gridService.registerApi('dashboard-grid', api);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
ngOnDestroy() {
|
|
136
|
-
this.gridService.removeApi('dashboard-grid');
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
Access from another component:
|
|
142
|
-
|
|
143
|
-
```typescript
|
|
144
|
-
export class ToolbarComponent {
|
|
145
|
-
constructor(private gridService: GridStormService) {}
|
|
146
|
-
|
|
147
|
-
exportSelected() {
|
|
148
|
-
const api = this.gridService.getApi('dashboard-grid');
|
|
149
|
-
if (api) {
|
|
150
|
-
const rows = api.getSelectedRows();
|
|
151
|
-
// ... export logic
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
## Build Notes
|
|
158
|
-
|
|
159
|
-
This package ships TypeScript source files alongside the tsup-compiled output. Since Angular decorators require the Angular compiler for AOT (ahead-of-time) compilation in production builds, there are two integration approaches:
|
|
160
|
-
|
|
161
|
-
### Development / JIT Mode
|
|
162
|
-
|
|
163
|
-
Import directly from the package -- the compiled ESM/CJS output works with Angular's JIT compiler:
|
|
164
|
-
|
|
165
|
-
```typescript
|
|
166
|
-
import { GridStormComponent, GridStormService } from '@gridstorm/angular';
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
### Production / AOT Builds
|
|
170
|
-
|
|
171
|
-
For production AOT builds, you may need to use `ngPackagr` or include the source files in your Angular project's compilation. The raw `.ts` source files are included in the published package under `src/` for this purpose.
|
|
172
|
-
|
|
173
|
-
## Theming
|
|
174
|
-
|
|
175
|
-
Apply the `@gridstorm/theme-default` stylesheet and use the `theme` and `density` inputs:
|
|
176
|
-
|
|
177
|
-
```typescript
|
|
178
|
-
// In your angular.json styles array:
|
|
179
|
-
// "node_modules/@gridstorm/theme-default/dist/index.css"
|
|
180
|
-
|
|
181
|
-
@Component({
|
|
182
|
-
template: `
|
|
183
|
-
<gridstorm
|
|
184
|
-
[columns]="columns"
|
|
185
|
-
[rowData]="rowData"
|
|
186
|
-
[theme]="currentTheme"
|
|
187
|
-
[density]="currentDensity"
|
|
188
|
-
></gridstorm>
|
|
189
|
-
`,
|
|
190
|
-
})
|
|
191
|
-
export class ThemedGridComponent {
|
|
192
|
-
currentTheme = 'dark';
|
|
193
|
-
currentDensity = 'compact';
|
|
194
|
-
|
|
195
|
-
toggleTheme() {
|
|
196
|
-
this.currentTheme = this.currentTheme === 'light' ? 'dark' : 'light';
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
## License
|
|
202
|
-
|
|
203
|
-
MIT
|
|
1
|
+
# @gridstorm/angular
|
|
2
|
+
|
|
3
|
+
Angular adapter for [GridStorm](https://grid-data-analytics-explorer.vercel.app/) -- a high-performance, headless data grid engine.
|
|
4
|
+
|
|
5
|
+
Provides a standalone Angular component (`<gridstorm>`) that wraps the GridStorm core engine and DOM renderer. Requires Angular 16+ (standalone component support).
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @gridstorm/angular @gridstorm/core @gridstorm/dom-renderer
|
|
11
|
+
# or
|
|
12
|
+
pnpm add @gridstorm/angular @gridstorm/core @gridstorm/dom-renderer
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
Import the standalone component directly in your Angular component:
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { Component } from '@angular/core';
|
|
21
|
+
import { GridStormComponent } from '@gridstorm/angular';
|
|
22
|
+
import { sortingPlugin } from '@gridstorm/plugin-sorting';
|
|
23
|
+
import type { GridApi, ColumnDef } from '@gridstorm/angular';
|
|
24
|
+
|
|
25
|
+
@Component({
|
|
26
|
+
selector: 'app-employees',
|
|
27
|
+
standalone: true,
|
|
28
|
+
imports: [GridStormComponent],
|
|
29
|
+
template: `
|
|
30
|
+
<gridstorm
|
|
31
|
+
[columns]="columns"
|
|
32
|
+
[rowData]="rowData"
|
|
33
|
+
[plugins]="plugins"
|
|
34
|
+
[rowHeight]="40"
|
|
35
|
+
[theme]="'dark'"
|
|
36
|
+
[density]="'normal'"
|
|
37
|
+
(gridReady)="onGridReady($event)"
|
|
38
|
+
(selectionChanged)="onSelectionChanged($event)"
|
|
39
|
+
style="height: 600px; width: 100%;"
|
|
40
|
+
></gridstorm>
|
|
41
|
+
`,
|
|
42
|
+
})
|
|
43
|
+
export class EmployeesComponent {
|
|
44
|
+
columns: ColumnDef[] = [
|
|
45
|
+
{ field: 'name', headerName: 'Name', sortable: true },
|
|
46
|
+
{ field: 'department', headerName: 'Department', sortable: true },
|
|
47
|
+
{ field: 'salary', headerName: 'Salary', width: 120 },
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
rowData = [
|
|
51
|
+
{ name: 'Alice', department: 'Engineering', salary: 95000 },
|
|
52
|
+
{ name: 'Bob', department: 'Marketing', salary: 72000 },
|
|
53
|
+
{ name: 'Charlie', department: 'Engineering', salary: 110000 },
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
plugins = [sortingPlugin()];
|
|
57
|
+
|
|
58
|
+
private gridApi: GridApi | null = null;
|
|
59
|
+
|
|
60
|
+
onGridReady(api: GridApi) {
|
|
61
|
+
this.gridApi = api;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
onSelectionChanged(event: any) {
|
|
65
|
+
console.log('Selection changed:', event);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
## Inputs
|
|
71
|
+
|
|
72
|
+
| Input | Type | Default | Description |
|
|
73
|
+
| ------------------- | --------------------------- | ---------- | ----------------------------------------------- |
|
|
74
|
+
| `columns` | `ColumnDef[]` | `[]` | Column definitions |
|
|
75
|
+
| `rowData` | `any[]` | `[]` | Row data array |
|
|
76
|
+
| `plugins` | `GridPlugin[]` | `[]` | Plugins to install |
|
|
77
|
+
| `getRowId` | `(params) => string` | `undefined`| Custom row ID generator |
|
|
78
|
+
| `rowHeight` | `number` | `40` | Row height in pixels |
|
|
79
|
+
| `theme` | `string` | `'light'` | Theme name (`'light'`, `'dark'`, or custom) |
|
|
80
|
+
| `density` | `string` | `'normal'` | Density mode (`'compact'`, `'normal'`, etc.) |
|
|
81
|
+
| `defaultColDef` | `Partial<ColumnDef>` | `undefined`| Default column config applied to all columns |
|
|
82
|
+
| `paginationPageSize`| `number` | `undefined`| Rows per page (when pagination enabled) |
|
|
83
|
+
| `headerHeight` | `number` | `undefined`| Header row height in pixels |
|
|
84
|
+
| `domLayout` | `'normal' \| 'autoHeight'` | `undefined`| DOM layout mode |
|
|
85
|
+
| `rowSelection` | `'single' \| 'multiple'` | `undefined`| Row selection mode |
|
|
86
|
+
| `pagination` | `boolean` | `undefined`| Enable client-side pagination |
|
|
87
|
+
| `ariaLabel` | `string` | `undefined`| ARIA label for accessibility |
|
|
88
|
+
|
|
89
|
+
## Outputs
|
|
90
|
+
|
|
91
|
+
| Output | Payload | Description |
|
|
92
|
+
| ------------------- | --------------------------- | ----------------------------------------------- |
|
|
93
|
+
| `gridReady` | `GridApi` | Grid initialized, API is ready |
|
|
94
|
+
| `rowDataChanged` | `{ rowData: any[] }` | Row data was replaced |
|
|
95
|
+
| `selectionChanged` | `{ selectedNodes, source }` | Row selection changed |
|
|
96
|
+
| `sortChanged` | `{ sortModel }` | Sort model changed |
|
|
97
|
+
| `filterChanged` | `{ filterModel }` | Filter model changed |
|
|
98
|
+
| `cellValueChanged` | `{ node, colId, ... }` | Cell value edited |
|
|
99
|
+
| `cellClicked` | `{ node, colId, value }` | Cell was clicked |
|
|
100
|
+
| `cellDoubleClicked` | `{ node, colId, value }` | Cell was double-clicked |
|
|
101
|
+
| `rowClicked` | `{ node, event }` | Row was clicked |
|
|
102
|
+
| `paginationChanged` | `{ currentPage, ... }` | Pagination state changed |
|
|
103
|
+
| `columnResized` | `{ column, ... }` | Column was resized |
|
|
104
|
+
|
|
105
|
+
## GridStormService
|
|
106
|
+
|
|
107
|
+
An injectable service for managing multiple grid instances across your application:
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
import { Component, OnDestroy } from '@angular/core';
|
|
111
|
+
import { GridStormComponent, GridStormService } from '@gridstorm/angular';
|
|
112
|
+
import type { GridApi } from '@gridstorm/angular';
|
|
113
|
+
|
|
114
|
+
@Component({
|
|
115
|
+
selector: 'app-dashboard',
|
|
116
|
+
standalone: true,
|
|
117
|
+
imports: [GridStormComponent],
|
|
118
|
+
template: `
|
|
119
|
+
<gridstorm
|
|
120
|
+
[columns]="columns"
|
|
121
|
+
[rowData]="rowData"
|
|
122
|
+
(gridReady)="onGridReady($event)"
|
|
123
|
+
></gridstorm>
|
|
124
|
+
`,
|
|
125
|
+
})
|
|
126
|
+
export class DashboardComponent implements OnDestroy {
|
|
127
|
+
// ... columns, rowData ...
|
|
128
|
+
|
|
129
|
+
constructor(private gridService: GridStormService) {}
|
|
130
|
+
|
|
131
|
+
onGridReady(api: GridApi) {
|
|
132
|
+
this.gridService.registerApi('dashboard-grid', api);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
ngOnDestroy() {
|
|
136
|
+
this.gridService.removeApi('dashboard-grid');
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Access from another component:
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
export class ToolbarComponent {
|
|
145
|
+
constructor(private gridService: GridStormService) {}
|
|
146
|
+
|
|
147
|
+
exportSelected() {
|
|
148
|
+
const api = this.gridService.getApi('dashboard-grid');
|
|
149
|
+
if (api) {
|
|
150
|
+
const rows = api.getSelectedRows();
|
|
151
|
+
// ... export logic
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Build Notes
|
|
158
|
+
|
|
159
|
+
This package ships TypeScript source files alongside the tsup-compiled output. Since Angular decorators require the Angular compiler for AOT (ahead-of-time) compilation in production builds, there are two integration approaches:
|
|
160
|
+
|
|
161
|
+
### Development / JIT Mode
|
|
162
|
+
|
|
163
|
+
Import directly from the package -- the compiled ESM/CJS output works with Angular's JIT compiler:
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
import { GridStormComponent, GridStormService } from '@gridstorm/angular';
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
### Production / AOT Builds
|
|
170
|
+
|
|
171
|
+
For production AOT builds, you may need to use `ngPackagr` or include the source files in your Angular project's compilation. The raw `.ts` source files are included in the published package under `src/` for this purpose.
|
|
172
|
+
|
|
173
|
+
## Theming
|
|
174
|
+
|
|
175
|
+
Apply the `@gridstorm/theme-default` stylesheet and use the `theme` and `density` inputs:
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
// In your angular.json styles array:
|
|
179
|
+
// "node_modules/@gridstorm/theme-default/dist/index.css"
|
|
180
|
+
|
|
181
|
+
@Component({
|
|
182
|
+
template: `
|
|
183
|
+
<gridstorm
|
|
184
|
+
[columns]="columns"
|
|
185
|
+
[rowData]="rowData"
|
|
186
|
+
[theme]="currentTheme"
|
|
187
|
+
[density]="currentDensity"
|
|
188
|
+
></gridstorm>
|
|
189
|
+
`,
|
|
190
|
+
})
|
|
191
|
+
export class ThemedGridComponent {
|
|
192
|
+
currentTheme = 'dark';
|
|
193
|
+
currentDensity = 'compact';
|
|
194
|
+
|
|
195
|
+
toggleTheme() {
|
|
196
|
+
this.currentTheme = this.currentTheme === 'light' ? 'dark' : 'light';
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## License
|
|
202
|
+
|
|
203
|
+
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -33,6 +33,7 @@ exports.GridStormComponent = class GridStormComponent {
|
|
|
33
33
|
this.rowClicked = new core.EventEmitter();
|
|
34
34
|
this.paginationChanged = new core.EventEmitter();
|
|
35
35
|
this.columnResized = new core.EventEmitter();
|
|
36
|
+
this.gridError = new core.EventEmitter();
|
|
36
37
|
// ── Internal state ──
|
|
37
38
|
this.engine = null;
|
|
38
39
|
this.renderer = null;
|
|
@@ -40,7 +41,13 @@ exports.GridStormComponent = class GridStormComponent {
|
|
|
40
41
|
}
|
|
41
42
|
// ── Lifecycle ──
|
|
42
43
|
ngOnInit() {
|
|
43
|
-
|
|
44
|
+
try {
|
|
45
|
+
this.initGrid();
|
|
46
|
+
} catch (err) {
|
|
47
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
48
|
+
console.error("[GridStorm Angular] Initialization error:", error);
|
|
49
|
+
this.gridError.emit(error);
|
|
50
|
+
}
|
|
44
51
|
}
|
|
45
52
|
ngOnChanges(changes) {
|
|
46
53
|
if (!this.engine) return;
|
|
@@ -208,6 +215,9 @@ __decorateClass([
|
|
|
208
215
|
__decorateClass([
|
|
209
216
|
core.Output()
|
|
210
217
|
], exports.GridStormComponent.prototype, "columnResized", 2);
|
|
218
|
+
__decorateClass([
|
|
219
|
+
core.Output()
|
|
220
|
+
], exports.GridStormComponent.prototype, "gridError", 2);
|
|
211
221
|
__decorateClass([
|
|
212
222
|
core.ViewChild("gridContainer", { static: true })
|
|
213
223
|
], exports.GridStormComponent.prototype, "gridContainerRef", 2);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/gridstorm.component.ts","../src/gridstorm.service.ts"],"names":["GridStormComponent","EventEmitter","createGrid","DomRenderer","Input","Output","ViewChild","Component","GridStormService","Injectable"],"mappings":"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","file":"index.cjs","sourcesContent":["// ─── GridStorm Angular Component ───\n// Standalone Angular component wrapping the headless core engine + DOM renderer.\n// Uses ElementRef + ViewChild to mount the DomRenderer into the template container.\n\nimport {\n Component,\n Input,\n Output,\n EventEmitter,\n ElementRef,\n OnInit,\n OnDestroy,\n OnChanges,\n SimpleChanges,\n ViewChild,\n} from '@angular/core';\nimport { createGrid } from '@gridstorm/core';\nimport { DomRenderer } from '@gridstorm/dom-renderer';\nimport type { GridConfig, GridApi, GridEngine, ColumnDef, GridPlugin } from '@gridstorm/core';\n\n@Component({\n selector: 'gridstorm',\n standalone: true,\n template: `\n <div\n #gridContainer\n class=\"gridstorm-wrapper\"\n [attr.data-theme]=\"theme\"\n [attr.data-density]=\"density\"\n style=\"width:100%;height:100%\"\n ></div>\n `,\n})\nexport class GridStormComponent implements OnInit, OnDestroy, OnChanges {\n // ── Inputs ──\n\n /** Column definitions describing each column's structure and behavior. */\n @Input() columns: ColumnDef[] = [];\n\n /** Client-side row data array. */\n @Input() rowData: any[] = [];\n\n /** Array of plugins to install during grid initialization. */\n @Input() plugins: GridPlugin[] = [];\n\n /** Callback to generate a unique string ID for each row. */\n @Input() getRowId?: (params: any) => string;\n\n /** Height of each data row in pixels. */\n @Input() rowHeight = 40;\n\n /** Theme identifier: 'light', 'dark', or custom theme name. */\n @Input() theme = 'light';\n\n /** Density mode: 'compact', 'normal', or 'comfortable'. */\n @Input() density = 'normal';\n\n /** Default column definition applied to all columns as fallback. */\n @Input() defaultColDef?: Partial<ColumnDef>;\n\n /** Number of rows per page when pagination is enabled. */\n @Input() paginationPageSize?: number;\n\n /** Height of the header row in pixels. */\n @Input() headerHeight?: number;\n\n /** Controls how the grid's DOM height is determined. */\n @Input() domLayout?: 'normal' | 'autoHeight' | 'print';\n\n /** Row selection mode: 'single', 'multiple', or false (disabled). */\n @Input() rowSelection?: 'single' | 'multiple' | false;\n\n /** When true, enables client-side pagination. */\n @Input() pagination?: boolean;\n\n /** ARIA label for the grid root element (screen reader accessibility). */\n @Input() ariaLabel?: string;\n\n // ── Outputs ──\n\n /** Emitted when the grid engine is fully initialized and the API is ready. */\n @Output() gridReady = new EventEmitter<GridApi>();\n\n /** Emitted when row data changes. */\n @Output() rowDataChanged = new EventEmitter<any>();\n\n /** Emitted when the selection state changes. */\n @Output() selectionChanged = new EventEmitter<any>();\n\n /** Emitted when the sort model changes. */\n @Output() sortChanged = new EventEmitter<any>();\n\n /** Emitted when the filter model changes. */\n @Output() filterChanged = new EventEmitter<any>();\n\n /** Emitted when a cell value is changed through editing. */\n @Output() cellValueChanged = new EventEmitter<any>();\n\n /** Emitted when a cell is clicked. */\n @Output() cellClicked = new EventEmitter<any>();\n\n /** Emitted when a cell is double-clicked. */\n @Output() cellDoubleClicked = new EventEmitter<any>();\n\n /** Emitted when a row is clicked. */\n @Output() rowClicked = new EventEmitter<any>();\n\n /** Emitted when pagination state changes. */\n @Output() paginationChanged = new EventEmitter<any>();\n\n /** Emitted when a column is resized. */\n @Output() columnResized = new EventEmitter<any>();\n\n // ── Template reference ──\n\n @ViewChild('gridContainer', { static: true })\n private gridContainerRef!: ElementRef<HTMLElement>;\n\n // ── Internal state ──\n\n private engine: GridEngine | null = null;\n private renderer: DomRenderer | null = null;\n private eventUnsubscribers: Array<() => void> = [];\n\n // ── Lifecycle ──\n\n ngOnInit(): void {\n this.initGrid();\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (!this.engine) return;\n\n // Sync rowData changes to the engine\n if (changes['rowData'] && !changes['rowData'].firstChange) {\n this.engine.api.setRowData(this.rowData);\n }\n\n // Sync column definition changes to the engine\n if (changes['columns'] && !changes['columns'].firstChange) {\n this.engine.api.setColumnDefs(this.columns);\n }\n\n // Sync pagination page size\n if (changes['paginationPageSize'] && !changes['paginationPageSize'].firstChange) {\n if (this.paginationPageSize != null) {\n this.engine.api.setGridOption('paginationPageSize', this.paginationPageSize);\n }\n }\n }\n\n ngOnDestroy(): void {\n this.destroyGrid();\n }\n\n // ── Public API ──\n\n /**\n * Returns the underlying GridApi instance, or null if the grid\n * has not been initialized yet.\n */\n getApi(): GridApi | null {\n return this.engine?.api ?? null;\n }\n\n /**\n * Returns the underlying GridEngine instance, or null if the grid\n * has not been initialized yet.\n */\n getEngine(): GridEngine | null {\n return this.engine;\n }\n\n // ── Initialization ──\n\n private initGrid(): void {\n const container = this.gridContainerRef.nativeElement;\n if (!container) return;\n\n // Build core config from inputs\n const config: GridConfig = {\n columns: this.columns,\n rowData: this.rowData,\n plugins: this.plugins,\n getRowId: this.getRowId,\n rowHeight: this.rowHeight,\n headerHeight: this.headerHeight,\n defaultColDef: this.defaultColDef,\n domLayout: this.domLayout,\n rowSelection: this.rowSelection,\n pagination: this.pagination,\n paginationPageSize: this.paginationPageSize,\n ariaLabel: this.ariaLabel,\n theme: this.theme,\n };\n\n // Create the headless grid engine\n this.engine = createGrid(config);\n\n // Create and mount the DOM renderer\n this.renderer = new DomRenderer({\n container,\n engine: this.engine,\n });\n this.renderer.mount();\n\n // Wire up event bridge: core events -> Angular EventEmitters\n this.setupEventBridge();\n\n // Emit gridReady\n this.gridReady.emit(this.engine.api);\n }\n\n private setupEventBridge(): void {\n if (!this.engine) return;\n\n const eb = this.engine.eventBus;\n\n this.eventUnsubscribers = [\n eb.on('rowData:changed', (e) => this.rowDataChanged.emit(e)),\n eb.on('selection:changed', (e) => this.selectionChanged.emit(e)),\n eb.on('column:sort:changed', (e) => this.sortChanged.emit(e)),\n eb.on('filter:changed', (e) => this.filterChanged.emit(e)),\n eb.on('cell:valueChanged', (e) => this.cellValueChanged.emit(e)),\n eb.on('cell:clicked', (e) => this.cellClicked.emit(e)),\n eb.on('cell:doubleClicked', (e) => this.cellDoubleClicked.emit(e)),\n eb.on('row:clicked', (e) => this.rowClicked.emit(e)),\n eb.on('pagination:changed', (e) => this.paginationChanged.emit(e)),\n eb.on('column:resized', (e) => this.columnResized.emit(e)),\n ];\n }\n\n private destroyGrid(): void {\n // Unsubscribe from all core events\n for (const unsub of this.eventUnsubscribers) {\n unsub();\n }\n this.eventUnsubscribers = [];\n\n // Destroy the DOM renderer\n if (this.renderer) {\n this.renderer.destroy();\n this.renderer = null;\n }\n\n // Destroy the grid engine\n if (this.engine) {\n this.engine.destroy();\n this.engine = null;\n }\n }\n}\n","// ─── GridStorm Service ───\n// Injectable service for managing multiple GridStorm instances.\n// Allows Angular components to access grid APIs by a unique identifier,\n// useful in applications with multiple grids or cross-component communication.\n\nimport { Injectable } from '@angular/core';\nimport type { GridApi } from '@gridstorm/core';\n\n/**\n * Service for registering and retrieving GridStorm API instances.\n *\n * Use this service when you have multiple grids in your application\n * and need to access their APIs from different components or services.\n *\n * @example\n * ```typescript\n * // In a component that hosts the grid:\n * constructor(private gridService: GridStormService) {}\n *\n * onGridReady(api: GridApi) {\n * this.gridService.registerApi('employees', api);\n * }\n *\n * // In another component that needs to interact with the grid:\n * constructor(private gridService: GridStormService) {}\n *\n * exportData() {\n * const api = this.gridService.getApi('employees');\n * if (api) {\n * const rows = api.getSelectedRows();\n * // ... do something with rows\n * }\n * }\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class GridStormService {\n private apiMap = new Map<string, GridApi>();\n\n /**\n * Registers a GridApi instance under a unique identifier.\n *\n * Call this from the `(gridReady)` output handler of the `<gridstorm>` component.\n * If an API with the same ID already exists, it will be replaced.\n *\n * @param id - A unique string identifier for this grid instance.\n * @param api - The GridApi instance to register.\n */\n registerApi(id: string, api: GridApi): void {\n this.apiMap.set(id, api);\n }\n\n /**\n * Retrieves a previously registered GridApi by its identifier.\n *\n * @param id - The unique identifier used during registration.\n * @returns The GridApi instance, or `undefined` if not found.\n */\n getApi(id: string): GridApi | undefined {\n return this.apiMap.get(id);\n }\n\n /**\n * Removes a registered GridApi by its identifier.\n *\n * Call this when a grid component is destroyed to prevent memory leaks.\n *\n * @param id - The unique identifier of the API to remove.\n */\n removeApi(id: string): void {\n this.apiMap.delete(id);\n }\n\n /**\n * Returns all registered grid API identifiers.\n *\n * @returns An array of registered grid IDs.\n */\n getRegisteredIds(): string[] {\n return Array.from(this.apiMap.keys());\n }\n\n /**\n * Checks whether a grid API is registered under the given identifier.\n *\n * @param id - The unique identifier to check.\n * @returns `true` if an API is registered with that ID.\n */\n hasApi(id: string): boolean {\n return this.apiMap.has(id);\n }\n\n /**\n * Removes all registered grid APIs.\n *\n * Useful during application teardown or testing.\n */\n clear(): void {\n this.apiMap.clear();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/gridstorm.component.ts","../src/gridstorm.service.ts"],"names":["GridStormComponent","EventEmitter","createGrid","DomRenderer","Input","Output","ViewChild","Component","GridStormService","Injectable"],"mappings":"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","file":"index.cjs","sourcesContent":["// ─── GridStorm Angular Component ───\r\n// Standalone Angular component wrapping the headless core engine + DOM renderer.\r\n// Uses ElementRef + ViewChild to mount the DomRenderer into the template container.\r\n\r\nimport {\r\n Component,\r\n Input,\r\n Output,\r\n EventEmitter,\r\n ElementRef,\r\n OnInit,\r\n OnDestroy,\r\n OnChanges,\r\n SimpleChanges,\r\n ViewChild,\r\n} from '@angular/core';\r\nimport { createGrid } from '@gridstorm/core';\r\nimport { DomRenderer } from '@gridstorm/dom-renderer';\r\nimport type { GridConfig, GridApi, GridEngine, ColumnDef, GridPlugin } from '@gridstorm/core';\r\n\r\n@Component({\r\n selector: 'gridstorm',\r\n standalone: true,\r\n template: `\r\n <div\r\n #gridContainer\r\n class=\"gridstorm-wrapper\"\r\n [attr.data-theme]=\"theme\"\r\n [attr.data-density]=\"density\"\r\n style=\"width:100%;height:100%\"\r\n ></div>\r\n `,\r\n})\r\nexport class GridStormComponent implements OnInit, OnDestroy, OnChanges {\r\n // ── Inputs ──\r\n\r\n /** Column definitions describing each column's structure and behavior. */\r\n @Input() columns: ColumnDef[] = [];\r\n\r\n /** Client-side row data array. */\r\n @Input() rowData: any[] = [];\r\n\r\n /** Array of plugins to install during grid initialization. */\r\n @Input() plugins: GridPlugin[] = [];\r\n\r\n /** Callback to generate a unique string ID for each row. */\r\n @Input() getRowId?: (params: any) => string;\r\n\r\n /** Height of each data row in pixels. */\r\n @Input() rowHeight = 40;\r\n\r\n /** Theme identifier: 'light', 'dark', or custom theme name. */\r\n @Input() theme = 'light';\r\n\r\n /** Density mode: 'compact', 'normal', or 'comfortable'. */\r\n @Input() density = 'normal';\r\n\r\n /** Default column definition applied to all columns as fallback. */\r\n @Input() defaultColDef?: Partial<ColumnDef>;\r\n\r\n /** Number of rows per page when pagination is enabled. */\r\n @Input() paginationPageSize?: number;\r\n\r\n /** Height of the header row in pixels. */\r\n @Input() headerHeight?: number;\r\n\r\n /** Controls how the grid's DOM height is determined. */\r\n @Input() domLayout?: 'normal' | 'autoHeight' | 'print';\r\n\r\n /** Row selection mode: 'single', 'multiple', or false (disabled). */\r\n @Input() rowSelection?: 'single' | 'multiple' | false;\r\n\r\n /** When true, enables client-side pagination. */\r\n @Input() pagination?: boolean;\r\n\r\n /** ARIA label for the grid root element (screen reader accessibility). */\r\n @Input() ariaLabel?: string;\r\n\r\n // ── Outputs ──\r\n\r\n /** Emitted when the grid engine is fully initialized and the API is ready. */\r\n @Output() gridReady = new EventEmitter<GridApi>();\r\n\r\n /** Emitted when row data changes. */\r\n @Output() rowDataChanged = new EventEmitter<any>();\r\n\r\n /** Emitted when the selection state changes. */\r\n @Output() selectionChanged = new EventEmitter<any>();\r\n\r\n /** Emitted when the sort model changes. */\r\n @Output() sortChanged = new EventEmitter<any>();\r\n\r\n /** Emitted when the filter model changes. */\r\n @Output() filterChanged = new EventEmitter<any>();\r\n\r\n /** Emitted when a cell value is changed through editing. */\r\n @Output() cellValueChanged = new EventEmitter<any>();\r\n\r\n /** Emitted when a cell is clicked. */\r\n @Output() cellClicked = new EventEmitter<any>();\r\n\r\n /** Emitted when a cell is double-clicked. */\r\n @Output() cellDoubleClicked = new EventEmitter<any>();\r\n\r\n /** Emitted when a row is clicked. */\r\n @Output() rowClicked = new EventEmitter<any>();\r\n\r\n /** Emitted when pagination state changes. */\r\n @Output() paginationChanged = new EventEmitter<any>();\r\n\r\n /** Emitted when a column is resized. */\r\n @Output() columnResized = new EventEmitter<any>();\r\n\r\n /** Emitted when an error occurs during grid initialization or operation. */\r\n @Output() gridError = new EventEmitter<Error>();\r\n\r\n // ── Template reference ──\r\n\r\n @ViewChild('gridContainer', { static: true })\r\n private gridContainerRef!: ElementRef<HTMLElement>;\r\n\r\n // ── Internal state ──\r\n\r\n private engine: GridEngine | null = null;\r\n private renderer: DomRenderer | null = null;\r\n private eventUnsubscribers: Array<() => void> = [];\r\n\r\n // ── Lifecycle ──\r\n\r\n ngOnInit(): void {\r\n try {\r\n this.initGrid();\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error(String(err));\r\n console.error('[GridStorm Angular] Initialization error:', error);\r\n this.gridError.emit(error);\r\n }\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if (!this.engine) return;\r\n\r\n // Sync rowData changes to the engine\r\n if (changes['rowData'] && !changes['rowData'].firstChange) {\r\n this.engine.api.setRowData(this.rowData);\r\n }\r\n\r\n // Sync column definition changes to the engine\r\n if (changes['columns'] && !changes['columns'].firstChange) {\r\n this.engine.api.setColumnDefs(this.columns);\r\n }\r\n\r\n // Sync pagination page size\r\n if (changes['paginationPageSize'] && !changes['paginationPageSize'].firstChange) {\r\n if (this.paginationPageSize != null) {\r\n this.engine.api.setGridOption('paginationPageSize', this.paginationPageSize);\r\n }\r\n }\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.destroyGrid();\r\n }\r\n\r\n // ── Public API ──\r\n\r\n /**\r\n * Returns the underlying GridApi instance, or null if the grid\r\n * has not been initialized yet.\r\n */\r\n getApi(): GridApi | null {\r\n return this.engine?.api ?? null;\r\n }\r\n\r\n /**\r\n * Returns the underlying GridEngine instance, or null if the grid\r\n * has not been initialized yet.\r\n */\r\n getEngine(): GridEngine | null {\r\n return this.engine;\r\n }\r\n\r\n // ── Initialization ──\r\n\r\n private initGrid(): void {\r\n const container = this.gridContainerRef.nativeElement;\r\n if (!container) return;\r\n\r\n // Build core config from inputs\r\n const config: GridConfig = {\r\n columns: this.columns,\r\n rowData: this.rowData,\r\n plugins: this.plugins,\r\n getRowId: this.getRowId,\r\n rowHeight: this.rowHeight,\r\n headerHeight: this.headerHeight,\r\n defaultColDef: this.defaultColDef,\r\n domLayout: this.domLayout,\r\n rowSelection: this.rowSelection,\r\n pagination: this.pagination,\r\n paginationPageSize: this.paginationPageSize,\r\n ariaLabel: this.ariaLabel,\r\n theme: this.theme,\r\n };\r\n\r\n // Create the headless grid engine\r\n this.engine = createGrid(config);\r\n\r\n // Create and mount the DOM renderer\r\n this.renderer = new DomRenderer({\r\n container,\r\n engine: this.engine,\r\n });\r\n this.renderer.mount();\r\n\r\n // Wire up event bridge: core events -> Angular EventEmitters\r\n this.setupEventBridge();\r\n\r\n // Emit gridReady\r\n this.gridReady.emit(this.engine.api);\r\n }\r\n\r\n private setupEventBridge(): void {\r\n if (!this.engine) return;\r\n\r\n const eb = this.engine.eventBus;\r\n\r\n this.eventUnsubscribers = [\r\n eb.on('rowData:changed', (e) => this.rowDataChanged.emit(e)),\r\n eb.on('selection:changed', (e) => this.selectionChanged.emit(e)),\r\n eb.on('column:sort:changed', (e) => this.sortChanged.emit(e)),\r\n eb.on('filter:changed', (e) => this.filterChanged.emit(e)),\r\n eb.on('cell:valueChanged', (e) => this.cellValueChanged.emit(e)),\r\n eb.on('cell:clicked', (e) => this.cellClicked.emit(e)),\r\n eb.on('cell:doubleClicked', (e) => this.cellDoubleClicked.emit(e)),\r\n eb.on('row:clicked', (e) => this.rowClicked.emit(e)),\r\n eb.on('pagination:changed', (e) => this.paginationChanged.emit(e)),\r\n eb.on('column:resized', (e) => this.columnResized.emit(e)),\r\n ];\r\n }\r\n\r\n private destroyGrid(): void {\r\n // Unsubscribe from all core events\r\n for (const unsub of this.eventUnsubscribers) {\r\n unsub();\r\n }\r\n this.eventUnsubscribers = [];\r\n\r\n // Destroy the DOM renderer\r\n if (this.renderer) {\r\n this.renderer.destroy();\r\n this.renderer = null;\r\n }\r\n\r\n // Destroy the grid engine\r\n if (this.engine) {\r\n this.engine.destroy();\r\n this.engine = null;\r\n }\r\n }\r\n}\r\n","// ─── GridStorm Service ───\r\n// Injectable service for managing multiple GridStorm instances.\r\n// Allows Angular components to access grid APIs by a unique identifier,\r\n// useful in applications with multiple grids or cross-component communication.\r\n\r\nimport { Injectable } from '@angular/core';\r\nimport type { GridApi } from '@gridstorm/core';\r\n\r\n/**\r\n * Service for registering and retrieving GridStorm API instances.\r\n *\r\n * Use this service when you have multiple grids in your application\r\n * and need to access their APIs from different components or services.\r\n *\r\n * @example\r\n * ```typescript\r\n * // In a component that hosts the grid:\r\n * constructor(private gridService: GridStormService) {}\r\n *\r\n * onGridReady(api: GridApi) {\r\n * this.gridService.registerApi('employees', api);\r\n * }\r\n *\r\n * // In another component that needs to interact with the grid:\r\n * constructor(private gridService: GridStormService) {}\r\n *\r\n * exportData() {\r\n * const api = this.gridService.getApi('employees');\r\n * if (api) {\r\n * const rows = api.getSelectedRows();\r\n * // ... do something with rows\r\n * }\r\n * }\r\n * ```\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class GridStormService {\r\n private apiMap = new Map<string, GridApi>();\r\n\r\n /**\r\n * Registers a GridApi instance under a unique identifier.\r\n *\r\n * Call this from the `(gridReady)` output handler of the `<gridstorm>` component.\r\n * If an API with the same ID already exists, it will be replaced.\r\n *\r\n * @param id - A unique string identifier for this grid instance.\r\n * @param api - The GridApi instance to register.\r\n */\r\n registerApi(id: string, api: GridApi): void {\r\n this.apiMap.set(id, api);\r\n }\r\n\r\n /**\r\n * Retrieves a previously registered GridApi by its identifier.\r\n *\r\n * @param id - The unique identifier used during registration.\r\n * @returns The GridApi instance, or `undefined` if not found.\r\n */\r\n getApi(id: string): GridApi | undefined {\r\n return this.apiMap.get(id);\r\n }\r\n\r\n /**\r\n * Removes a registered GridApi by its identifier.\r\n *\r\n * Call this when a grid component is destroyed to prevent memory leaks.\r\n *\r\n * @param id - The unique identifier of the API to remove.\r\n */\r\n removeApi(id: string): void {\r\n this.apiMap.delete(id);\r\n }\r\n\r\n /**\r\n * Returns all registered grid API identifiers.\r\n *\r\n * @returns An array of registered grid IDs.\r\n */\r\n getRegisteredIds(): string[] {\r\n return Array.from(this.apiMap.keys());\r\n }\r\n\r\n /**\r\n * Checks whether a grid API is registered under the given identifier.\r\n *\r\n * @param id - The unique identifier to check.\r\n * @returns `true` if an API is registered with that ID.\r\n */\r\n hasApi(id: string): boolean {\r\n return this.apiMap.has(id);\r\n }\r\n\r\n /**\r\n * Removes all registered grid APIs.\r\n *\r\n * Useful during application teardown or testing.\r\n */\r\n clear(): void {\r\n this.apiMap.clear();\r\n }\r\n}\r\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -53,6 +53,8 @@ declare class GridStormComponent implements OnInit, OnDestroy, OnChanges {
|
|
|
53
53
|
paginationChanged: EventEmitter<any>;
|
|
54
54
|
/** Emitted when a column is resized. */
|
|
55
55
|
columnResized: EventEmitter<any>;
|
|
56
|
+
/** Emitted when an error occurs during grid initialization or operation. */
|
|
57
|
+
gridError: EventEmitter<Error>;
|
|
56
58
|
private gridContainerRef;
|
|
57
59
|
private engine;
|
|
58
60
|
private renderer;
|
package/dist/index.d.ts
CHANGED
|
@@ -53,6 +53,8 @@ declare class GridStormComponent implements OnInit, OnDestroy, OnChanges {
|
|
|
53
53
|
paginationChanged: EventEmitter<any>;
|
|
54
54
|
/** Emitted when a column is resized. */
|
|
55
55
|
columnResized: EventEmitter<any>;
|
|
56
|
+
/** Emitted when an error occurs during grid initialization or operation. */
|
|
57
|
+
gridError: EventEmitter<Error>;
|
|
56
58
|
private gridContainerRef;
|
|
57
59
|
private engine;
|
|
58
60
|
private renderer;
|
package/dist/index.js
CHANGED
|
@@ -31,6 +31,7 @@ var GridStormComponent = class {
|
|
|
31
31
|
this.rowClicked = new EventEmitter();
|
|
32
32
|
this.paginationChanged = new EventEmitter();
|
|
33
33
|
this.columnResized = new EventEmitter();
|
|
34
|
+
this.gridError = new EventEmitter();
|
|
34
35
|
// ── Internal state ──
|
|
35
36
|
this.engine = null;
|
|
36
37
|
this.renderer = null;
|
|
@@ -38,7 +39,13 @@ var GridStormComponent = class {
|
|
|
38
39
|
}
|
|
39
40
|
// ── Lifecycle ──
|
|
40
41
|
ngOnInit() {
|
|
41
|
-
|
|
42
|
+
try {
|
|
43
|
+
this.initGrid();
|
|
44
|
+
} catch (err) {
|
|
45
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
46
|
+
console.error("[GridStorm Angular] Initialization error:", error);
|
|
47
|
+
this.gridError.emit(error);
|
|
48
|
+
}
|
|
42
49
|
}
|
|
43
50
|
ngOnChanges(changes) {
|
|
44
51
|
if (!this.engine) return;
|
|
@@ -206,6 +213,9 @@ __decorateClass([
|
|
|
206
213
|
__decorateClass([
|
|
207
214
|
Output()
|
|
208
215
|
], GridStormComponent.prototype, "columnResized", 2);
|
|
216
|
+
__decorateClass([
|
|
217
|
+
Output()
|
|
218
|
+
], GridStormComponent.prototype, "gridError", 2);
|
|
209
219
|
__decorateClass([
|
|
210
220
|
ViewChild("gridContainer", { static: true })
|
|
211
221
|
], GridStormComponent.prototype, "gridContainerRef", 2);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/gridstorm.component.ts","../src/gridstorm.service.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// ─── GridStorm Angular Component ───\n// Standalone Angular component wrapping the headless core engine + DOM renderer.\n// Uses ElementRef + ViewChild to mount the DomRenderer into the template container.\n\nimport {\n Component,\n Input,\n Output,\n EventEmitter,\n ElementRef,\n OnInit,\n OnDestroy,\n OnChanges,\n SimpleChanges,\n ViewChild,\n} from '@angular/core';\nimport { createGrid } from '@gridstorm/core';\nimport { DomRenderer } from '@gridstorm/dom-renderer';\nimport type { GridConfig, GridApi, GridEngine, ColumnDef, GridPlugin } from '@gridstorm/core';\n\n@Component({\n selector: 'gridstorm',\n standalone: true,\n template: `\n <div\n #gridContainer\n class=\"gridstorm-wrapper\"\n [attr.data-theme]=\"theme\"\n [attr.data-density]=\"density\"\n style=\"width:100%;height:100%\"\n ></div>\n `,\n})\nexport class GridStormComponent implements OnInit, OnDestroy, OnChanges {\n // ── Inputs ──\n\n /** Column definitions describing each column's structure and behavior. */\n @Input() columns: ColumnDef[] = [];\n\n /** Client-side row data array. */\n @Input() rowData: any[] = [];\n\n /** Array of plugins to install during grid initialization. */\n @Input() plugins: GridPlugin[] = [];\n\n /** Callback to generate a unique string ID for each row. */\n @Input() getRowId?: (params: any) => string;\n\n /** Height of each data row in pixels. */\n @Input() rowHeight = 40;\n\n /** Theme identifier: 'light', 'dark', or custom theme name. */\n @Input() theme = 'light';\n\n /** Density mode: 'compact', 'normal', or 'comfortable'. */\n @Input() density = 'normal';\n\n /** Default column definition applied to all columns as fallback. */\n @Input() defaultColDef?: Partial<ColumnDef>;\n\n /** Number of rows per page when pagination is enabled. */\n @Input() paginationPageSize?: number;\n\n /** Height of the header row in pixels. */\n @Input() headerHeight?: number;\n\n /** Controls how the grid's DOM height is determined. */\n @Input() domLayout?: 'normal' | 'autoHeight' | 'print';\n\n /** Row selection mode: 'single', 'multiple', or false (disabled). */\n @Input() rowSelection?: 'single' | 'multiple' | false;\n\n /** When true, enables client-side pagination. */\n @Input() pagination?: boolean;\n\n /** ARIA label for the grid root element (screen reader accessibility). */\n @Input() ariaLabel?: string;\n\n // ── Outputs ──\n\n /** Emitted when the grid engine is fully initialized and the API is ready. */\n @Output() gridReady = new EventEmitter<GridApi>();\n\n /** Emitted when row data changes. */\n @Output() rowDataChanged = new EventEmitter<any>();\n\n /** Emitted when the selection state changes. */\n @Output() selectionChanged = new EventEmitter<any>();\n\n /** Emitted when the sort model changes. */\n @Output() sortChanged = new EventEmitter<any>();\n\n /** Emitted when the filter model changes. */\n @Output() filterChanged = new EventEmitter<any>();\n\n /** Emitted when a cell value is changed through editing. */\n @Output() cellValueChanged = new EventEmitter<any>();\n\n /** Emitted when a cell is clicked. */\n @Output() cellClicked = new EventEmitter<any>();\n\n /** Emitted when a cell is double-clicked. */\n @Output() cellDoubleClicked = new EventEmitter<any>();\n\n /** Emitted when a row is clicked. */\n @Output() rowClicked = new EventEmitter<any>();\n\n /** Emitted when pagination state changes. */\n @Output() paginationChanged = new EventEmitter<any>();\n\n /** Emitted when a column is resized. */\n @Output() columnResized = new EventEmitter<any>();\n\n // ── Template reference ──\n\n @ViewChild('gridContainer', { static: true })\n private gridContainerRef!: ElementRef<HTMLElement>;\n\n // ── Internal state ──\n\n private engine: GridEngine | null = null;\n private renderer: DomRenderer | null = null;\n private eventUnsubscribers: Array<() => void> = [];\n\n // ── Lifecycle ──\n\n ngOnInit(): void {\n this.initGrid();\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (!this.engine) return;\n\n // Sync rowData changes to the engine\n if (changes['rowData'] && !changes['rowData'].firstChange) {\n this.engine.api.setRowData(this.rowData);\n }\n\n // Sync column definition changes to the engine\n if (changes['columns'] && !changes['columns'].firstChange) {\n this.engine.api.setColumnDefs(this.columns);\n }\n\n // Sync pagination page size\n if (changes['paginationPageSize'] && !changes['paginationPageSize'].firstChange) {\n if (this.paginationPageSize != null) {\n this.engine.api.setGridOption('paginationPageSize', this.paginationPageSize);\n }\n }\n }\n\n ngOnDestroy(): void {\n this.destroyGrid();\n }\n\n // ── Public API ──\n\n /**\n * Returns the underlying GridApi instance, or null if the grid\n * has not been initialized yet.\n */\n getApi(): GridApi | null {\n return this.engine?.api ?? null;\n }\n\n /**\n * Returns the underlying GridEngine instance, or null if the grid\n * has not been initialized yet.\n */\n getEngine(): GridEngine | null {\n return this.engine;\n }\n\n // ── Initialization ──\n\n private initGrid(): void {\n const container = this.gridContainerRef.nativeElement;\n if (!container) return;\n\n // Build core config from inputs\n const config: GridConfig = {\n columns: this.columns,\n rowData: this.rowData,\n plugins: this.plugins,\n getRowId: this.getRowId,\n rowHeight: this.rowHeight,\n headerHeight: this.headerHeight,\n defaultColDef: this.defaultColDef,\n domLayout: this.domLayout,\n rowSelection: this.rowSelection,\n pagination: this.pagination,\n paginationPageSize: this.paginationPageSize,\n ariaLabel: this.ariaLabel,\n theme: this.theme,\n };\n\n // Create the headless grid engine\n this.engine = createGrid(config);\n\n // Create and mount the DOM renderer\n this.renderer = new DomRenderer({\n container,\n engine: this.engine,\n });\n this.renderer.mount();\n\n // Wire up event bridge: core events -> Angular EventEmitters\n this.setupEventBridge();\n\n // Emit gridReady\n this.gridReady.emit(this.engine.api);\n }\n\n private setupEventBridge(): void {\n if (!this.engine) return;\n\n const eb = this.engine.eventBus;\n\n this.eventUnsubscribers = [\n eb.on('rowData:changed', (e) => this.rowDataChanged.emit(e)),\n eb.on('selection:changed', (e) => this.selectionChanged.emit(e)),\n eb.on('column:sort:changed', (e) => this.sortChanged.emit(e)),\n eb.on('filter:changed', (e) => this.filterChanged.emit(e)),\n eb.on('cell:valueChanged', (e) => this.cellValueChanged.emit(e)),\n eb.on('cell:clicked', (e) => this.cellClicked.emit(e)),\n eb.on('cell:doubleClicked', (e) => this.cellDoubleClicked.emit(e)),\n eb.on('row:clicked', (e) => this.rowClicked.emit(e)),\n eb.on('pagination:changed', (e) => this.paginationChanged.emit(e)),\n eb.on('column:resized', (e) => this.columnResized.emit(e)),\n ];\n }\n\n private destroyGrid(): void {\n // Unsubscribe from all core events\n for (const unsub of this.eventUnsubscribers) {\n unsub();\n }\n this.eventUnsubscribers = [];\n\n // Destroy the DOM renderer\n if (this.renderer) {\n this.renderer.destroy();\n this.renderer = null;\n }\n\n // Destroy the grid engine\n if (this.engine) {\n this.engine.destroy();\n this.engine = null;\n }\n }\n}\n","// ─── GridStorm Service ───\n// Injectable service for managing multiple GridStorm instances.\n// Allows Angular components to access grid APIs by a unique identifier,\n// useful in applications with multiple grids or cross-component communication.\n\nimport { Injectable } from '@angular/core';\nimport type { GridApi } from '@gridstorm/core';\n\n/**\n * Service for registering and retrieving GridStorm API instances.\n *\n * Use this service when you have multiple grids in your application\n * and need to access their APIs from different components or services.\n *\n * @example\n * ```typescript\n * // In a component that hosts the grid:\n * constructor(private gridService: GridStormService) {}\n *\n * onGridReady(api: GridApi) {\n * this.gridService.registerApi('employees', api);\n * }\n *\n * // In another component that needs to interact with the grid:\n * constructor(private gridService: GridStormService) {}\n *\n * exportData() {\n * const api = this.gridService.getApi('employees');\n * if (api) {\n * const rows = api.getSelectedRows();\n * // ... do something with rows\n * }\n * }\n * ```\n */\n@Injectable({ providedIn: 'root' })\nexport class GridStormService {\n private apiMap = new Map<string, GridApi>();\n\n /**\n * Registers a GridApi instance under a unique identifier.\n *\n * Call this from the `(gridReady)` output handler of the `<gridstorm>` component.\n * If an API with the same ID already exists, it will be replaced.\n *\n * @param id - A unique string identifier for this grid instance.\n * @param api - The GridApi instance to register.\n */\n registerApi(id: string, api: GridApi): void {\n this.apiMap.set(id, api);\n }\n\n /**\n * Retrieves a previously registered GridApi by its identifier.\n *\n * @param id - The unique identifier used during registration.\n * @returns The GridApi instance, or `undefined` if not found.\n */\n getApi(id: string): GridApi | undefined {\n return this.apiMap.get(id);\n }\n\n /**\n * Removes a registered GridApi by its identifier.\n *\n * Call this when a grid component is destroyed to prevent memory leaks.\n *\n * @param id - The unique identifier of the API to remove.\n */\n removeApi(id: string): void {\n this.apiMap.delete(id);\n }\n\n /**\n * Returns all registered grid API identifiers.\n *\n * @returns An array of registered grid IDs.\n */\n getRegisteredIds(): string[] {\n return Array.from(this.apiMap.keys());\n }\n\n /**\n * Checks whether a grid API is registered under the given identifier.\n *\n * @param id - The unique identifier to check.\n * @returns `true` if an API is registered with that ID.\n */\n hasApi(id: string): boolean {\n return this.apiMap.has(id);\n }\n\n /**\n * Removes all registered grid APIs.\n *\n * Useful during application teardown or testing.\n */\n clear(): void {\n this.apiMap.clear();\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/gridstorm.component.ts","../src/gridstorm.service.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// ─── GridStorm Angular Component ───\r\n// Standalone Angular component wrapping the headless core engine + DOM renderer.\r\n// Uses ElementRef + ViewChild to mount the DomRenderer into the template container.\r\n\r\nimport {\r\n Component,\r\n Input,\r\n Output,\r\n EventEmitter,\r\n ElementRef,\r\n OnInit,\r\n OnDestroy,\r\n OnChanges,\r\n SimpleChanges,\r\n ViewChild,\r\n} from '@angular/core';\r\nimport { createGrid } from '@gridstorm/core';\r\nimport { DomRenderer } from '@gridstorm/dom-renderer';\r\nimport type { GridConfig, GridApi, GridEngine, ColumnDef, GridPlugin } from '@gridstorm/core';\r\n\r\n@Component({\r\n selector: 'gridstorm',\r\n standalone: true,\r\n template: `\r\n <div\r\n #gridContainer\r\n class=\"gridstorm-wrapper\"\r\n [attr.data-theme]=\"theme\"\r\n [attr.data-density]=\"density\"\r\n style=\"width:100%;height:100%\"\r\n ></div>\r\n `,\r\n})\r\nexport class GridStormComponent implements OnInit, OnDestroy, OnChanges {\r\n // ── Inputs ──\r\n\r\n /** Column definitions describing each column's structure and behavior. */\r\n @Input() columns: ColumnDef[] = [];\r\n\r\n /** Client-side row data array. */\r\n @Input() rowData: any[] = [];\r\n\r\n /** Array of plugins to install during grid initialization. */\r\n @Input() plugins: GridPlugin[] = [];\r\n\r\n /** Callback to generate a unique string ID for each row. */\r\n @Input() getRowId?: (params: any) => string;\r\n\r\n /** Height of each data row in pixels. */\r\n @Input() rowHeight = 40;\r\n\r\n /** Theme identifier: 'light', 'dark', or custom theme name. */\r\n @Input() theme = 'light';\r\n\r\n /** Density mode: 'compact', 'normal', or 'comfortable'. */\r\n @Input() density = 'normal';\r\n\r\n /** Default column definition applied to all columns as fallback. */\r\n @Input() defaultColDef?: Partial<ColumnDef>;\r\n\r\n /** Number of rows per page when pagination is enabled. */\r\n @Input() paginationPageSize?: number;\r\n\r\n /** Height of the header row in pixels. */\r\n @Input() headerHeight?: number;\r\n\r\n /** Controls how the grid's DOM height is determined. */\r\n @Input() domLayout?: 'normal' | 'autoHeight' | 'print';\r\n\r\n /** Row selection mode: 'single', 'multiple', or false (disabled). */\r\n @Input() rowSelection?: 'single' | 'multiple' | false;\r\n\r\n /** When true, enables client-side pagination. */\r\n @Input() pagination?: boolean;\r\n\r\n /** ARIA label for the grid root element (screen reader accessibility). */\r\n @Input() ariaLabel?: string;\r\n\r\n // ── Outputs ──\r\n\r\n /** Emitted when the grid engine is fully initialized and the API is ready. */\r\n @Output() gridReady = new EventEmitter<GridApi>();\r\n\r\n /** Emitted when row data changes. */\r\n @Output() rowDataChanged = new EventEmitter<any>();\r\n\r\n /** Emitted when the selection state changes. */\r\n @Output() selectionChanged = new EventEmitter<any>();\r\n\r\n /** Emitted when the sort model changes. */\r\n @Output() sortChanged = new EventEmitter<any>();\r\n\r\n /** Emitted when the filter model changes. */\r\n @Output() filterChanged = new EventEmitter<any>();\r\n\r\n /** Emitted when a cell value is changed through editing. */\r\n @Output() cellValueChanged = new EventEmitter<any>();\r\n\r\n /** Emitted when a cell is clicked. */\r\n @Output() cellClicked = new EventEmitter<any>();\r\n\r\n /** Emitted when a cell is double-clicked. */\r\n @Output() cellDoubleClicked = new EventEmitter<any>();\r\n\r\n /** Emitted when a row is clicked. */\r\n @Output() rowClicked = new EventEmitter<any>();\r\n\r\n /** Emitted when pagination state changes. */\r\n @Output() paginationChanged = new EventEmitter<any>();\r\n\r\n /** Emitted when a column is resized. */\r\n @Output() columnResized = new EventEmitter<any>();\r\n\r\n /** Emitted when an error occurs during grid initialization or operation. */\r\n @Output() gridError = new EventEmitter<Error>();\r\n\r\n // ── Template reference ──\r\n\r\n @ViewChild('gridContainer', { static: true })\r\n private gridContainerRef!: ElementRef<HTMLElement>;\r\n\r\n // ── Internal state ──\r\n\r\n private engine: GridEngine | null = null;\r\n private renderer: DomRenderer | null = null;\r\n private eventUnsubscribers: Array<() => void> = [];\r\n\r\n // ── Lifecycle ──\r\n\r\n ngOnInit(): void {\r\n try {\r\n this.initGrid();\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error(String(err));\r\n console.error('[GridStorm Angular] Initialization error:', error);\r\n this.gridError.emit(error);\r\n }\r\n }\r\n\r\n ngOnChanges(changes: SimpleChanges): void {\r\n if (!this.engine) return;\r\n\r\n // Sync rowData changes to the engine\r\n if (changes['rowData'] && !changes['rowData'].firstChange) {\r\n this.engine.api.setRowData(this.rowData);\r\n }\r\n\r\n // Sync column definition changes to the engine\r\n if (changes['columns'] && !changes['columns'].firstChange) {\r\n this.engine.api.setColumnDefs(this.columns);\r\n }\r\n\r\n // Sync pagination page size\r\n if (changes['paginationPageSize'] && !changes['paginationPageSize'].firstChange) {\r\n if (this.paginationPageSize != null) {\r\n this.engine.api.setGridOption('paginationPageSize', this.paginationPageSize);\r\n }\r\n }\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this.destroyGrid();\r\n }\r\n\r\n // ── Public API ──\r\n\r\n /**\r\n * Returns the underlying GridApi instance, or null if the grid\r\n * has not been initialized yet.\r\n */\r\n getApi(): GridApi | null {\r\n return this.engine?.api ?? null;\r\n }\r\n\r\n /**\r\n * Returns the underlying GridEngine instance, or null if the grid\r\n * has not been initialized yet.\r\n */\r\n getEngine(): GridEngine | null {\r\n return this.engine;\r\n }\r\n\r\n // ── Initialization ──\r\n\r\n private initGrid(): void {\r\n const container = this.gridContainerRef.nativeElement;\r\n if (!container) return;\r\n\r\n // Build core config from inputs\r\n const config: GridConfig = {\r\n columns: this.columns,\r\n rowData: this.rowData,\r\n plugins: this.plugins,\r\n getRowId: this.getRowId,\r\n rowHeight: this.rowHeight,\r\n headerHeight: this.headerHeight,\r\n defaultColDef: this.defaultColDef,\r\n domLayout: this.domLayout,\r\n rowSelection: this.rowSelection,\r\n pagination: this.pagination,\r\n paginationPageSize: this.paginationPageSize,\r\n ariaLabel: this.ariaLabel,\r\n theme: this.theme,\r\n };\r\n\r\n // Create the headless grid engine\r\n this.engine = createGrid(config);\r\n\r\n // Create and mount the DOM renderer\r\n this.renderer = new DomRenderer({\r\n container,\r\n engine: this.engine,\r\n });\r\n this.renderer.mount();\r\n\r\n // Wire up event bridge: core events -> Angular EventEmitters\r\n this.setupEventBridge();\r\n\r\n // Emit gridReady\r\n this.gridReady.emit(this.engine.api);\r\n }\r\n\r\n private setupEventBridge(): void {\r\n if (!this.engine) return;\r\n\r\n const eb = this.engine.eventBus;\r\n\r\n this.eventUnsubscribers = [\r\n eb.on('rowData:changed', (e) => this.rowDataChanged.emit(e)),\r\n eb.on('selection:changed', (e) => this.selectionChanged.emit(e)),\r\n eb.on('column:sort:changed', (e) => this.sortChanged.emit(e)),\r\n eb.on('filter:changed', (e) => this.filterChanged.emit(e)),\r\n eb.on('cell:valueChanged', (e) => this.cellValueChanged.emit(e)),\r\n eb.on('cell:clicked', (e) => this.cellClicked.emit(e)),\r\n eb.on('cell:doubleClicked', (e) => this.cellDoubleClicked.emit(e)),\r\n eb.on('row:clicked', (e) => this.rowClicked.emit(e)),\r\n eb.on('pagination:changed', (e) => this.paginationChanged.emit(e)),\r\n eb.on('column:resized', (e) => this.columnResized.emit(e)),\r\n ];\r\n }\r\n\r\n private destroyGrid(): void {\r\n // Unsubscribe from all core events\r\n for (const unsub of this.eventUnsubscribers) {\r\n unsub();\r\n }\r\n this.eventUnsubscribers = [];\r\n\r\n // Destroy the DOM renderer\r\n if (this.renderer) {\r\n this.renderer.destroy();\r\n this.renderer = null;\r\n }\r\n\r\n // Destroy the grid engine\r\n if (this.engine) {\r\n this.engine.destroy();\r\n this.engine = null;\r\n }\r\n }\r\n}\r\n","// ─── GridStorm Service ───\r\n// Injectable service for managing multiple GridStorm instances.\r\n// Allows Angular components to access grid APIs by a unique identifier,\r\n// useful in applications with multiple grids or cross-component communication.\r\n\r\nimport { Injectable } from '@angular/core';\r\nimport type { GridApi } from '@gridstorm/core';\r\n\r\n/**\r\n * Service for registering and retrieving GridStorm API instances.\r\n *\r\n * Use this service when you have multiple grids in your application\r\n * and need to access their APIs from different components or services.\r\n *\r\n * @example\r\n * ```typescript\r\n * // In a component that hosts the grid:\r\n * constructor(private gridService: GridStormService) {}\r\n *\r\n * onGridReady(api: GridApi) {\r\n * this.gridService.registerApi('employees', api);\r\n * }\r\n *\r\n * // In another component that needs to interact with the grid:\r\n * constructor(private gridService: GridStormService) {}\r\n *\r\n * exportData() {\r\n * const api = this.gridService.getApi('employees');\r\n * if (api) {\r\n * const rows = api.getSelectedRows();\r\n * // ... do something with rows\r\n * }\r\n * }\r\n * ```\r\n */\r\n@Injectable({ providedIn: 'root' })\r\nexport class GridStormService {\r\n private apiMap = new Map<string, GridApi>();\r\n\r\n /**\r\n * Registers a GridApi instance under a unique identifier.\r\n *\r\n * Call this from the `(gridReady)` output handler of the `<gridstorm>` component.\r\n * If an API with the same ID already exists, it will be replaced.\r\n *\r\n * @param id - A unique string identifier for this grid instance.\r\n * @param api - The GridApi instance to register.\r\n */\r\n registerApi(id: string, api: GridApi): void {\r\n this.apiMap.set(id, api);\r\n }\r\n\r\n /**\r\n * Retrieves a previously registered GridApi by its identifier.\r\n *\r\n * @param id - The unique identifier used during registration.\r\n * @returns The GridApi instance, or `undefined` if not found.\r\n */\r\n getApi(id: string): GridApi | undefined {\r\n return this.apiMap.get(id);\r\n }\r\n\r\n /**\r\n * Removes a registered GridApi by its identifier.\r\n *\r\n * Call this when a grid component is destroyed to prevent memory leaks.\r\n *\r\n * @param id - The unique identifier of the API to remove.\r\n */\r\n removeApi(id: string): void {\r\n this.apiMap.delete(id);\r\n }\r\n\r\n /**\r\n * Returns all registered grid API identifiers.\r\n *\r\n * @returns An array of registered grid IDs.\r\n */\r\n getRegisteredIds(): string[] {\r\n return Array.from(this.apiMap.keys());\r\n }\r\n\r\n /**\r\n * Checks whether a grid API is registered under the given identifier.\r\n *\r\n * @param id - The unique identifier to check.\r\n * @returns `true` if an API is registered with that ID.\r\n */\r\n hasApi(id: string): boolean {\r\n return this.apiMap.has(id);\r\n }\r\n\r\n /**\r\n * Removes all registered grid APIs.\r\n *\r\n * Useful during application teardown or testing.\r\n */\r\n clear(): void {\r\n this.apiMap.clear();\r\n }\r\n}\r\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gridstorm/angular",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "GridStorm Angular adapter — standalone component for Angular 16+",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -35,12 +35,12 @@
|
|
|
35
35
|
"@gridstorm/dom-renderer": "workspace:*"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
|
-
"@angular/core": ">=
|
|
39
|
-
"@angular/common": ">=
|
|
38
|
+
"@angular/core": ">=21.2.6",
|
|
39
|
+
"@angular/common": ">=21.2.6"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@angular/core": ">=
|
|
43
|
-
"@angular/common": ">=
|
|
42
|
+
"@angular/core": ">=21.2.6",
|
|
43
|
+
"@angular/common": ">=21.2.6",
|
|
44
44
|
"tsup": "^8.2.0",
|
|
45
45
|
"typescript": "^5.5.0"
|
|
46
46
|
},
|
|
@@ -65,10 +65,10 @@
|
|
|
65
65
|
"bugs": {
|
|
66
66
|
"url": "https://github.com/007krcs/grid-data/issues"
|
|
67
67
|
},
|
|
68
|
-
"homepage": "https://
|
|
68
|
+
"homepage": "https://gridstorm.tekivex.com",
|
|
69
69
|
"author": {
|
|
70
70
|
"name": "GridStorm",
|
|
71
|
-
"url": "https://
|
|
71
|
+
"url": "https://gridstorm.tekivex.com/"
|
|
72
72
|
},
|
|
73
73
|
"funding": {
|
|
74
74
|
"type": "github",
|
|
@@ -0,0 +1,379 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest';
|
|
2
|
+
import { GridStormComponent } from '../gridstorm.component';
|
|
3
|
+
import { GridStormService } from '../gridstorm.service';
|
|
4
|
+
import type { GridStormInputs, GridStormOutputs, GridRegistration } from '../types';
|
|
5
|
+
|
|
6
|
+
// ─── GridStormComponent Structure ───
|
|
7
|
+
|
|
8
|
+
describe('GridStormComponent', () => {
|
|
9
|
+
it('can be instantiated', () => {
|
|
10
|
+
const component = new GridStormComponent();
|
|
11
|
+
expect(component).toBeDefined();
|
|
12
|
+
expect(component).toBeInstanceOf(GridStormComponent);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it('has default values for columns and rowData inputs', () => {
|
|
16
|
+
const component = new GridStormComponent();
|
|
17
|
+
expect(component.columns).toEqual([]);
|
|
18
|
+
expect(component.rowData).toEqual([]);
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('has default values for plugins', () => {
|
|
22
|
+
const component = new GridStormComponent();
|
|
23
|
+
expect(component.plugins).toEqual([]);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('has default rowHeight of 40', () => {
|
|
27
|
+
const component = new GridStormComponent();
|
|
28
|
+
expect(component.rowHeight).toBe(40);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('has default theme of light', () => {
|
|
32
|
+
const component = new GridStormComponent();
|
|
33
|
+
expect(component.theme).toBe('light');
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('has default density of normal', () => {
|
|
37
|
+
const component = new GridStormComponent();
|
|
38
|
+
expect(component.density).toBe('normal');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('has optional inputs that default to undefined', () => {
|
|
42
|
+
const component = new GridStormComponent();
|
|
43
|
+
expect(component.getRowId).toBeUndefined();
|
|
44
|
+
expect(component.defaultColDef).toBeUndefined();
|
|
45
|
+
expect(component.paginationPageSize).toBeUndefined();
|
|
46
|
+
expect(component.headerHeight).toBeUndefined();
|
|
47
|
+
expect(component.domLayout).toBeUndefined();
|
|
48
|
+
expect(component.rowSelection).toBeUndefined();
|
|
49
|
+
expect(component.pagination).toBeUndefined();
|
|
50
|
+
expect(component.ariaLabel).toBeUndefined();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('allows setting input properties', () => {
|
|
54
|
+
const component = new GridStormComponent();
|
|
55
|
+
const testColumns = [{ field: 'name' }, { field: 'age' }];
|
|
56
|
+
const testData = [{ name: 'Alice', age: 30 }];
|
|
57
|
+
|
|
58
|
+
component.columns = testColumns as any;
|
|
59
|
+
component.rowData = testData;
|
|
60
|
+
component.rowHeight = 50;
|
|
61
|
+
component.theme = 'dark';
|
|
62
|
+
component.density = 'compact';
|
|
63
|
+
|
|
64
|
+
expect(component.columns).toBe(testColumns);
|
|
65
|
+
expect(component.rowData).toBe(testData);
|
|
66
|
+
expect(component.rowHeight).toBe(50);
|
|
67
|
+
expect(component.theme).toBe('dark');
|
|
68
|
+
expect(component.density).toBe('compact');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('has EventEmitter outputs', () => {
|
|
72
|
+
const component = new GridStormComponent();
|
|
73
|
+
// All output EventEmitters should be defined and have an emit method
|
|
74
|
+
expect(component.gridReady).toBeDefined();
|
|
75
|
+
expect(typeof component.gridReady.emit).toBe('function');
|
|
76
|
+
|
|
77
|
+
expect(component.rowDataChanged).toBeDefined();
|
|
78
|
+
expect(typeof component.rowDataChanged.emit).toBe('function');
|
|
79
|
+
|
|
80
|
+
expect(component.selectionChanged).toBeDefined();
|
|
81
|
+
expect(typeof component.selectionChanged.emit).toBe('function');
|
|
82
|
+
|
|
83
|
+
expect(component.sortChanged).toBeDefined();
|
|
84
|
+
expect(typeof component.sortChanged.emit).toBe('function');
|
|
85
|
+
|
|
86
|
+
expect(component.filterChanged).toBeDefined();
|
|
87
|
+
expect(typeof component.filterChanged.emit).toBe('function');
|
|
88
|
+
|
|
89
|
+
expect(component.cellValueChanged).toBeDefined();
|
|
90
|
+
expect(typeof component.cellValueChanged.emit).toBe('function');
|
|
91
|
+
|
|
92
|
+
expect(component.cellClicked).toBeDefined();
|
|
93
|
+
expect(typeof component.cellClicked.emit).toBe('function');
|
|
94
|
+
|
|
95
|
+
expect(component.cellDoubleClicked).toBeDefined();
|
|
96
|
+
expect(typeof component.cellDoubleClicked.emit).toBe('function');
|
|
97
|
+
|
|
98
|
+
expect(component.rowClicked).toBeDefined();
|
|
99
|
+
expect(typeof component.rowClicked.emit).toBe('function');
|
|
100
|
+
|
|
101
|
+
expect(component.paginationChanged).toBeDefined();
|
|
102
|
+
expect(typeof component.paginationChanged.emit).toBe('function');
|
|
103
|
+
|
|
104
|
+
expect(component.columnResized).toBeDefined();
|
|
105
|
+
expect(typeof component.columnResized.emit).toBe('function');
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('has getApi method that returns null before initialization', () => {
|
|
109
|
+
const component = new GridStormComponent();
|
|
110
|
+
expect(component.getApi()).toBeNull();
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('has getEngine method that returns null before initialization', () => {
|
|
114
|
+
const component = new GridStormComponent();
|
|
115
|
+
expect(component.getEngine()).toBeNull();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
it('has lifecycle methods defined', () => {
|
|
119
|
+
const component = new GridStormComponent();
|
|
120
|
+
expect(typeof component.ngOnInit).toBe('function');
|
|
121
|
+
expect(typeof component.ngOnDestroy).toBe('function');
|
|
122
|
+
expect(typeof component.ngOnChanges).toBe('function');
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('ngOnChanges is safe to call before engine is initialized', () => {
|
|
126
|
+
const component = new GridStormComponent();
|
|
127
|
+
// Should not throw when engine is null
|
|
128
|
+
expect(() => {
|
|
129
|
+
component.ngOnChanges({
|
|
130
|
+
rowData: {
|
|
131
|
+
currentValue: [{ id: 1 }],
|
|
132
|
+
previousValue: [],
|
|
133
|
+
firstChange: false,
|
|
134
|
+
isFirstChange: () => false,
|
|
135
|
+
},
|
|
136
|
+
});
|
|
137
|
+
}).not.toThrow();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('ngOnChanges ignores first change events', () => {
|
|
141
|
+
const component = new GridStormComponent();
|
|
142
|
+
// Should not throw even with firstChange=true
|
|
143
|
+
expect(() => {
|
|
144
|
+
component.ngOnChanges({
|
|
145
|
+
rowData: {
|
|
146
|
+
currentValue: [{ id: 1 }],
|
|
147
|
+
previousValue: undefined,
|
|
148
|
+
firstChange: true,
|
|
149
|
+
isFirstChange: () => true,
|
|
150
|
+
},
|
|
151
|
+
});
|
|
152
|
+
}).not.toThrow();
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
// ─── GridStormService ───
|
|
157
|
+
|
|
158
|
+
describe('GridStormService', () => {
|
|
159
|
+
it('can be instantiated', () => {
|
|
160
|
+
const service = new GridStormService();
|
|
161
|
+
expect(service).toBeDefined();
|
|
162
|
+
expect(service).toBeInstanceOf(GridStormService);
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
it('starts with no registered APIs', () => {
|
|
166
|
+
const service = new GridStormService();
|
|
167
|
+
expect(service.getRegisteredIds()).toEqual([]);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('registers and retrieves an API by id', () => {
|
|
171
|
+
const service = new GridStormService();
|
|
172
|
+
const mockApi = { getSelectedRows: () => [] } as any;
|
|
173
|
+
|
|
174
|
+
service.registerApi('employees', mockApi);
|
|
175
|
+
expect(service.getApi('employees')).toBe(mockApi);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
it('returns undefined for unregistered ids', () => {
|
|
179
|
+
const service = new GridStormService();
|
|
180
|
+
expect(service.getApi('nonexistent')).toBeUndefined();
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('reports whether an API is registered via hasApi', () => {
|
|
184
|
+
const service = new GridStormService();
|
|
185
|
+
const mockApi = {} as any;
|
|
186
|
+
|
|
187
|
+
expect(service.hasApi('grid1')).toBe(false);
|
|
188
|
+
service.registerApi('grid1', mockApi);
|
|
189
|
+
expect(service.hasApi('grid1')).toBe(true);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it('removes a registered API', () => {
|
|
193
|
+
const service = new GridStormService();
|
|
194
|
+
const mockApi = {} as any;
|
|
195
|
+
|
|
196
|
+
service.registerApi('grid1', mockApi);
|
|
197
|
+
expect(service.hasApi('grid1')).toBe(true);
|
|
198
|
+
|
|
199
|
+
service.removeApi('grid1');
|
|
200
|
+
expect(service.hasApi('grid1')).toBe(false);
|
|
201
|
+
expect(service.getApi('grid1')).toBeUndefined();
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('removeApi is safe to call with unregistered id', () => {
|
|
205
|
+
const service = new GridStormService();
|
|
206
|
+
expect(() => service.removeApi('nonexistent')).not.toThrow();
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('lists all registered IDs', () => {
|
|
210
|
+
const service = new GridStormService();
|
|
211
|
+
const mockApi1 = {} as any;
|
|
212
|
+
const mockApi2 = {} as any;
|
|
213
|
+
|
|
214
|
+
service.registerApi('grid-a', mockApi1);
|
|
215
|
+
service.registerApi('grid-b', mockApi2);
|
|
216
|
+
|
|
217
|
+
const ids = service.getRegisteredIds();
|
|
218
|
+
expect(ids).toContain('grid-a');
|
|
219
|
+
expect(ids).toContain('grid-b');
|
|
220
|
+
expect(ids).toHaveLength(2);
|
|
221
|
+
});
|
|
222
|
+
|
|
223
|
+
it('replaces an existing API when registering with the same id', () => {
|
|
224
|
+
const service = new GridStormService();
|
|
225
|
+
const mockApi1 = { version: 1 } as any;
|
|
226
|
+
const mockApi2 = { version: 2 } as any;
|
|
227
|
+
|
|
228
|
+
service.registerApi('grid', mockApi1);
|
|
229
|
+
expect(service.getApi('grid')).toBe(mockApi1);
|
|
230
|
+
|
|
231
|
+
service.registerApi('grid', mockApi2);
|
|
232
|
+
expect(service.getApi('grid')).toBe(mockApi2);
|
|
233
|
+
// Should still only be one entry
|
|
234
|
+
expect(service.getRegisteredIds()).toHaveLength(1);
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('clears all registered APIs', () => {
|
|
238
|
+
const service = new GridStormService();
|
|
239
|
+
service.registerApi('a', {} as any);
|
|
240
|
+
service.registerApi('b', {} as any);
|
|
241
|
+
service.registerApi('c', {} as any);
|
|
242
|
+
|
|
243
|
+
expect(service.getRegisteredIds()).toHaveLength(3);
|
|
244
|
+
|
|
245
|
+
service.clear();
|
|
246
|
+
expect(service.getRegisteredIds()).toHaveLength(0);
|
|
247
|
+
expect(service.getApi('a')).toBeUndefined();
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('clear is safe to call when no APIs are registered', () => {
|
|
251
|
+
const service = new GridStormService();
|
|
252
|
+
expect(() => service.clear()).not.toThrow();
|
|
253
|
+
expect(service.getRegisteredIds()).toEqual([]);
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
// ─── Exported Types ───
|
|
258
|
+
|
|
259
|
+
describe('exported types', () => {
|
|
260
|
+
it('GridStormInputs type is usable', () => {
|
|
261
|
+
// Verify the type compiles and can be used in a type annotation
|
|
262
|
+
const inputs: GridStormInputs = {
|
|
263
|
+
columns: [],
|
|
264
|
+
rowData: [],
|
|
265
|
+
plugins: [],
|
|
266
|
+
rowHeight: 40,
|
|
267
|
+
theme: 'light',
|
|
268
|
+
density: 'normal',
|
|
269
|
+
};
|
|
270
|
+
expect(inputs.columns).toEqual([]);
|
|
271
|
+
expect(inputs.rowHeight).toBe(40);
|
|
272
|
+
expect(inputs.theme).toBe('light');
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
it('GridStormInputs supports optional properties', () => {
|
|
276
|
+
const inputs: GridStormInputs = {
|
|
277
|
+
columns: [],
|
|
278
|
+
rowData: [],
|
|
279
|
+
plugins: [],
|
|
280
|
+
rowHeight: 40,
|
|
281
|
+
theme: 'light',
|
|
282
|
+
density: 'normal',
|
|
283
|
+
pagination: true,
|
|
284
|
+
paginationPageSize: 25,
|
|
285
|
+
headerHeight: 48,
|
|
286
|
+
domLayout: 'autoHeight',
|
|
287
|
+
rowSelection: 'multiple',
|
|
288
|
+
ariaLabel: 'Data grid',
|
|
289
|
+
};
|
|
290
|
+
expect(inputs.pagination).toBe(true);
|
|
291
|
+
expect(inputs.paginationPageSize).toBe(25);
|
|
292
|
+
expect(inputs.domLayout).toBe('autoHeight');
|
|
293
|
+
expect(inputs.rowSelection).toBe('multiple');
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('GridStormOutputs type is usable', () => {
|
|
297
|
+
const outputs: Partial<GridStormOutputs> = {
|
|
298
|
+
rowDataChanged: { rowData: [{ id: 1 }] },
|
|
299
|
+
selectionChanged: { selectedNodes: [], source: 'api' },
|
|
300
|
+
sortChanged: { sortModel: [] },
|
|
301
|
+
filterChanged: { filterModel: {} },
|
|
302
|
+
cellValueChanged: { node: null, colId: 'name', oldValue: 'a', newValue: 'b' },
|
|
303
|
+
};
|
|
304
|
+
expect(outputs.rowDataChanged?.rowData).toHaveLength(1);
|
|
305
|
+
expect(outputs.selectionChanged?.source).toBe('api');
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('GridRegistration type is usable', () => {
|
|
309
|
+
const reg: GridRegistration = {
|
|
310
|
+
id: 'my-grid',
|
|
311
|
+
api: {} as any,
|
|
312
|
+
};
|
|
313
|
+
expect(reg.id).toBe('my-grid');
|
|
314
|
+
expect(reg.api).toBeDefined();
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
// ─── Event Emission Mapping ───
|
|
319
|
+
|
|
320
|
+
describe('event emission mapping', () => {
|
|
321
|
+
it('component has all expected event outputs for the documented core events', () => {
|
|
322
|
+
const component = new GridStormComponent();
|
|
323
|
+
// These correspond to the core event bus events bridged in setupEventBridge
|
|
324
|
+
const expectedOutputs = [
|
|
325
|
+
'gridReady',
|
|
326
|
+
'rowDataChanged',
|
|
327
|
+
'selectionChanged',
|
|
328
|
+
'sortChanged',
|
|
329
|
+
'filterChanged',
|
|
330
|
+
'cellValueChanged',
|
|
331
|
+
'cellClicked',
|
|
332
|
+
'cellDoubleClicked',
|
|
333
|
+
'rowClicked',
|
|
334
|
+
'paginationChanged',
|
|
335
|
+
'columnResized',
|
|
336
|
+
];
|
|
337
|
+
|
|
338
|
+
for (const outputName of expectedOutputs) {
|
|
339
|
+
const emitter = (component as any)[outputName];
|
|
340
|
+
expect(emitter).toBeDefined();
|
|
341
|
+
expect(typeof emitter.emit).toBe('function');
|
|
342
|
+
expect(typeof emitter.subscribe).toBe('function');
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
it('EventEmitters can be subscribed to and receive values', () => {
|
|
347
|
+
const component = new GridStormComponent();
|
|
348
|
+
const received: any[] = [];
|
|
349
|
+
|
|
350
|
+
component.cellClicked.subscribe((val: any) => received.push(val));
|
|
351
|
+
component.cellClicked.emit({ rowIndex: 0, colId: 'name' });
|
|
352
|
+
|
|
353
|
+
expect(received).toHaveLength(1);
|
|
354
|
+
expect(received[0]).toEqual({ rowIndex: 0, colId: 'name' });
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
|
|
358
|
+
// ─── Cleanup on Destroy ───
|
|
359
|
+
|
|
360
|
+
describe('cleanup on destroy', () => {
|
|
361
|
+
it('ngOnDestroy does not throw when called before initialization', () => {
|
|
362
|
+
const component = new GridStormComponent();
|
|
363
|
+
// Engine and renderer are null, should handle gracefully
|
|
364
|
+
expect(() => component.ngOnDestroy()).not.toThrow();
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it('getApi returns null after destroy is called', () => {
|
|
368
|
+
const component = new GridStormComponent();
|
|
369
|
+
// Even without initialization, calling destroy then getApi should be safe
|
|
370
|
+
component.ngOnDestroy();
|
|
371
|
+
expect(component.getApi()).toBeNull();
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it('getEngine returns null after destroy is called', () => {
|
|
375
|
+
const component = new GridStormComponent();
|
|
376
|
+
component.ngOnDestroy();
|
|
377
|
+
expect(component.getEngine()).toBeNull();
|
|
378
|
+
});
|
|
379
|
+
});
|
|
@@ -111,6 +111,9 @@ export class GridStormComponent implements OnInit, OnDestroy, OnChanges {
|
|
|
111
111
|
/** Emitted when a column is resized. */
|
|
112
112
|
@Output() columnResized = new EventEmitter<any>();
|
|
113
113
|
|
|
114
|
+
/** Emitted when an error occurs during grid initialization or operation. */
|
|
115
|
+
@Output() gridError = new EventEmitter<Error>();
|
|
116
|
+
|
|
114
117
|
// ── Template reference ──
|
|
115
118
|
|
|
116
119
|
@ViewChild('gridContainer', { static: true })
|
|
@@ -125,7 +128,13 @@ export class GridStormComponent implements OnInit, OnDestroy, OnChanges {
|
|
|
125
128
|
// ── Lifecycle ──
|
|
126
129
|
|
|
127
130
|
ngOnInit(): void {
|
|
128
|
-
|
|
131
|
+
try {
|
|
132
|
+
this.initGrid();
|
|
133
|
+
} catch (err) {
|
|
134
|
+
const error = err instanceof Error ? err : new Error(String(err));
|
|
135
|
+
console.error('[GridStorm Angular] Initialization error:', error);
|
|
136
|
+
this.gridError.emit(error);
|
|
137
|
+
}
|
|
129
138
|
}
|
|
130
139
|
|
|
131
140
|
ngOnChanges(changes: SimpleChanges): void {
|