@gridstorm/angular 0.1.2
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/README.md +203 -0
- package/dist/index.cjs +294 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +237 -0
- package/dist/index.d.ts +237 -0
- package/dist/index.js +294 -0
- package/dist/index.js.map +1 -0
- package/package.json +80 -0
- package/src/gridstorm.component.ts +252 -0
- package/src/gridstorm.service.ts +101 -0
- package/src/index.ts +23 -0
- package/src/types.ts +94 -0
package/README.md
ADDED
|
@@ -0,0 +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
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var core = require('@angular/core');
|
|
4
|
+
var core$1 = require('@gridstorm/core');
|
|
5
|
+
var domRenderer = require('@gridstorm/dom-renderer');
|
|
6
|
+
|
|
7
|
+
var __defProp = Object.defineProperty;
|
|
8
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
9
|
+
var __decorateClass = (decorators, target, key, kind) => {
|
|
10
|
+
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
|
|
11
|
+
for (var i = decorators.length - 1, decorator; i >= 0; i--)
|
|
12
|
+
if (decorator = decorators[i])
|
|
13
|
+
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
|
|
14
|
+
if (kind && result) __defProp(target, key, result);
|
|
15
|
+
return result;
|
|
16
|
+
};
|
|
17
|
+
exports.GridStormComponent = class GridStormComponent {
|
|
18
|
+
constructor() {
|
|
19
|
+
this.columns = [];
|
|
20
|
+
this.rowData = [];
|
|
21
|
+
this.plugins = [];
|
|
22
|
+
this.rowHeight = 40;
|
|
23
|
+
this.theme = "light";
|
|
24
|
+
this.density = "normal";
|
|
25
|
+
this.gridReady = new core.EventEmitter();
|
|
26
|
+
this.rowDataChanged = new core.EventEmitter();
|
|
27
|
+
this.selectionChanged = new core.EventEmitter();
|
|
28
|
+
this.sortChanged = new core.EventEmitter();
|
|
29
|
+
this.filterChanged = new core.EventEmitter();
|
|
30
|
+
this.cellValueChanged = new core.EventEmitter();
|
|
31
|
+
this.cellClicked = new core.EventEmitter();
|
|
32
|
+
this.cellDoubleClicked = new core.EventEmitter();
|
|
33
|
+
this.rowClicked = new core.EventEmitter();
|
|
34
|
+
this.paginationChanged = new core.EventEmitter();
|
|
35
|
+
this.columnResized = new core.EventEmitter();
|
|
36
|
+
// ── Internal state ──
|
|
37
|
+
this.engine = null;
|
|
38
|
+
this.renderer = null;
|
|
39
|
+
this.eventUnsubscribers = [];
|
|
40
|
+
}
|
|
41
|
+
// ── Lifecycle ──
|
|
42
|
+
ngOnInit() {
|
|
43
|
+
this.initGrid();
|
|
44
|
+
}
|
|
45
|
+
ngOnChanges(changes) {
|
|
46
|
+
if (!this.engine) return;
|
|
47
|
+
if (changes["rowData"] && !changes["rowData"].firstChange) {
|
|
48
|
+
this.engine.api.setRowData(this.rowData);
|
|
49
|
+
}
|
|
50
|
+
if (changes["columns"] && !changes["columns"].firstChange) {
|
|
51
|
+
this.engine.api.setColumnDefs(this.columns);
|
|
52
|
+
}
|
|
53
|
+
if (changes["paginationPageSize"] && !changes["paginationPageSize"].firstChange) {
|
|
54
|
+
if (this.paginationPageSize != null) {
|
|
55
|
+
this.engine.api.setGridOption("paginationPageSize", this.paginationPageSize);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
ngOnDestroy() {
|
|
60
|
+
this.destroyGrid();
|
|
61
|
+
}
|
|
62
|
+
// ── Public API ──
|
|
63
|
+
/**
|
|
64
|
+
* Returns the underlying GridApi instance, or null if the grid
|
|
65
|
+
* has not been initialized yet.
|
|
66
|
+
*/
|
|
67
|
+
getApi() {
|
|
68
|
+
return this.engine?.api ?? null;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Returns the underlying GridEngine instance, or null if the grid
|
|
72
|
+
* has not been initialized yet.
|
|
73
|
+
*/
|
|
74
|
+
getEngine() {
|
|
75
|
+
return this.engine;
|
|
76
|
+
}
|
|
77
|
+
// ── Initialization ──
|
|
78
|
+
initGrid() {
|
|
79
|
+
const container = this.gridContainerRef.nativeElement;
|
|
80
|
+
if (!container) return;
|
|
81
|
+
const config = {
|
|
82
|
+
columns: this.columns,
|
|
83
|
+
rowData: this.rowData,
|
|
84
|
+
plugins: this.plugins,
|
|
85
|
+
getRowId: this.getRowId,
|
|
86
|
+
rowHeight: this.rowHeight,
|
|
87
|
+
headerHeight: this.headerHeight,
|
|
88
|
+
defaultColDef: this.defaultColDef,
|
|
89
|
+
domLayout: this.domLayout,
|
|
90
|
+
rowSelection: this.rowSelection,
|
|
91
|
+
pagination: this.pagination,
|
|
92
|
+
paginationPageSize: this.paginationPageSize,
|
|
93
|
+
ariaLabel: this.ariaLabel,
|
|
94
|
+
theme: this.theme
|
|
95
|
+
};
|
|
96
|
+
this.engine = core$1.createGrid(config);
|
|
97
|
+
this.renderer = new domRenderer.DomRenderer({
|
|
98
|
+
container,
|
|
99
|
+
engine: this.engine
|
|
100
|
+
});
|
|
101
|
+
this.renderer.mount();
|
|
102
|
+
this.setupEventBridge();
|
|
103
|
+
this.gridReady.emit(this.engine.api);
|
|
104
|
+
}
|
|
105
|
+
setupEventBridge() {
|
|
106
|
+
if (!this.engine) return;
|
|
107
|
+
const eb = this.engine.eventBus;
|
|
108
|
+
this.eventUnsubscribers = [
|
|
109
|
+
eb.on("rowData:changed", (e) => this.rowDataChanged.emit(e)),
|
|
110
|
+
eb.on("selection:changed", (e) => this.selectionChanged.emit(e)),
|
|
111
|
+
eb.on("column:sort:changed", (e) => this.sortChanged.emit(e)),
|
|
112
|
+
eb.on("filter:changed", (e) => this.filterChanged.emit(e)),
|
|
113
|
+
eb.on("cell:valueChanged", (e) => this.cellValueChanged.emit(e)),
|
|
114
|
+
eb.on("cell:clicked", (e) => this.cellClicked.emit(e)),
|
|
115
|
+
eb.on("cell:doubleClicked", (e) => this.cellDoubleClicked.emit(e)),
|
|
116
|
+
eb.on("row:clicked", (e) => this.rowClicked.emit(e)),
|
|
117
|
+
eb.on("pagination:changed", (e) => this.paginationChanged.emit(e)),
|
|
118
|
+
eb.on("column:resized", (e) => this.columnResized.emit(e))
|
|
119
|
+
];
|
|
120
|
+
}
|
|
121
|
+
destroyGrid() {
|
|
122
|
+
for (const unsub of this.eventUnsubscribers) {
|
|
123
|
+
unsub();
|
|
124
|
+
}
|
|
125
|
+
this.eventUnsubscribers = [];
|
|
126
|
+
if (this.renderer) {
|
|
127
|
+
this.renderer.destroy();
|
|
128
|
+
this.renderer = null;
|
|
129
|
+
}
|
|
130
|
+
if (this.engine) {
|
|
131
|
+
this.engine.destroy();
|
|
132
|
+
this.engine = null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
__decorateClass([
|
|
137
|
+
core.Input()
|
|
138
|
+
], exports.GridStormComponent.prototype, "columns", 2);
|
|
139
|
+
__decorateClass([
|
|
140
|
+
core.Input()
|
|
141
|
+
], exports.GridStormComponent.prototype, "rowData", 2);
|
|
142
|
+
__decorateClass([
|
|
143
|
+
core.Input()
|
|
144
|
+
], exports.GridStormComponent.prototype, "plugins", 2);
|
|
145
|
+
__decorateClass([
|
|
146
|
+
core.Input()
|
|
147
|
+
], exports.GridStormComponent.prototype, "getRowId", 2);
|
|
148
|
+
__decorateClass([
|
|
149
|
+
core.Input()
|
|
150
|
+
], exports.GridStormComponent.prototype, "rowHeight", 2);
|
|
151
|
+
__decorateClass([
|
|
152
|
+
core.Input()
|
|
153
|
+
], exports.GridStormComponent.prototype, "theme", 2);
|
|
154
|
+
__decorateClass([
|
|
155
|
+
core.Input()
|
|
156
|
+
], exports.GridStormComponent.prototype, "density", 2);
|
|
157
|
+
__decorateClass([
|
|
158
|
+
core.Input()
|
|
159
|
+
], exports.GridStormComponent.prototype, "defaultColDef", 2);
|
|
160
|
+
__decorateClass([
|
|
161
|
+
core.Input()
|
|
162
|
+
], exports.GridStormComponent.prototype, "paginationPageSize", 2);
|
|
163
|
+
__decorateClass([
|
|
164
|
+
core.Input()
|
|
165
|
+
], exports.GridStormComponent.prototype, "headerHeight", 2);
|
|
166
|
+
__decorateClass([
|
|
167
|
+
core.Input()
|
|
168
|
+
], exports.GridStormComponent.prototype, "domLayout", 2);
|
|
169
|
+
__decorateClass([
|
|
170
|
+
core.Input()
|
|
171
|
+
], exports.GridStormComponent.prototype, "rowSelection", 2);
|
|
172
|
+
__decorateClass([
|
|
173
|
+
core.Input()
|
|
174
|
+
], exports.GridStormComponent.prototype, "pagination", 2);
|
|
175
|
+
__decorateClass([
|
|
176
|
+
core.Input()
|
|
177
|
+
], exports.GridStormComponent.prototype, "ariaLabel", 2);
|
|
178
|
+
__decorateClass([
|
|
179
|
+
core.Output()
|
|
180
|
+
], exports.GridStormComponent.prototype, "gridReady", 2);
|
|
181
|
+
__decorateClass([
|
|
182
|
+
core.Output()
|
|
183
|
+
], exports.GridStormComponent.prototype, "rowDataChanged", 2);
|
|
184
|
+
__decorateClass([
|
|
185
|
+
core.Output()
|
|
186
|
+
], exports.GridStormComponent.prototype, "selectionChanged", 2);
|
|
187
|
+
__decorateClass([
|
|
188
|
+
core.Output()
|
|
189
|
+
], exports.GridStormComponent.prototype, "sortChanged", 2);
|
|
190
|
+
__decorateClass([
|
|
191
|
+
core.Output()
|
|
192
|
+
], exports.GridStormComponent.prototype, "filterChanged", 2);
|
|
193
|
+
__decorateClass([
|
|
194
|
+
core.Output()
|
|
195
|
+
], exports.GridStormComponent.prototype, "cellValueChanged", 2);
|
|
196
|
+
__decorateClass([
|
|
197
|
+
core.Output()
|
|
198
|
+
], exports.GridStormComponent.prototype, "cellClicked", 2);
|
|
199
|
+
__decorateClass([
|
|
200
|
+
core.Output()
|
|
201
|
+
], exports.GridStormComponent.prototype, "cellDoubleClicked", 2);
|
|
202
|
+
__decorateClass([
|
|
203
|
+
core.Output()
|
|
204
|
+
], exports.GridStormComponent.prototype, "rowClicked", 2);
|
|
205
|
+
__decorateClass([
|
|
206
|
+
core.Output()
|
|
207
|
+
], exports.GridStormComponent.prototype, "paginationChanged", 2);
|
|
208
|
+
__decorateClass([
|
|
209
|
+
core.Output()
|
|
210
|
+
], exports.GridStormComponent.prototype, "columnResized", 2);
|
|
211
|
+
__decorateClass([
|
|
212
|
+
core.ViewChild("gridContainer", { static: true })
|
|
213
|
+
], exports.GridStormComponent.prototype, "gridContainerRef", 2);
|
|
214
|
+
exports.GridStormComponent = __decorateClass([
|
|
215
|
+
core.Component({
|
|
216
|
+
selector: "gridstorm",
|
|
217
|
+
standalone: true,
|
|
218
|
+
template: `
|
|
219
|
+
<div
|
|
220
|
+
#gridContainer
|
|
221
|
+
class="gridstorm-wrapper"
|
|
222
|
+
[attr.data-theme]="theme"
|
|
223
|
+
[attr.data-density]="density"
|
|
224
|
+
style="width:100%;height:100%"
|
|
225
|
+
></div>
|
|
226
|
+
`
|
|
227
|
+
})
|
|
228
|
+
], exports.GridStormComponent);
|
|
229
|
+
exports.GridStormService = class GridStormService {
|
|
230
|
+
constructor() {
|
|
231
|
+
this.apiMap = /* @__PURE__ */ new Map();
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Registers a GridApi instance under a unique identifier.
|
|
235
|
+
*
|
|
236
|
+
* Call this from the `(gridReady)` output handler of the `<gridstorm>` component.
|
|
237
|
+
* If an API with the same ID already exists, it will be replaced.
|
|
238
|
+
*
|
|
239
|
+
* @param id - A unique string identifier for this grid instance.
|
|
240
|
+
* @param api - The GridApi instance to register.
|
|
241
|
+
*/
|
|
242
|
+
registerApi(id, api) {
|
|
243
|
+
this.apiMap.set(id, api);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Retrieves a previously registered GridApi by its identifier.
|
|
247
|
+
*
|
|
248
|
+
* @param id - The unique identifier used during registration.
|
|
249
|
+
* @returns The GridApi instance, or `undefined` if not found.
|
|
250
|
+
*/
|
|
251
|
+
getApi(id) {
|
|
252
|
+
return this.apiMap.get(id);
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Removes a registered GridApi by its identifier.
|
|
256
|
+
*
|
|
257
|
+
* Call this when a grid component is destroyed to prevent memory leaks.
|
|
258
|
+
*
|
|
259
|
+
* @param id - The unique identifier of the API to remove.
|
|
260
|
+
*/
|
|
261
|
+
removeApi(id) {
|
|
262
|
+
this.apiMap.delete(id);
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Returns all registered grid API identifiers.
|
|
266
|
+
*
|
|
267
|
+
* @returns An array of registered grid IDs.
|
|
268
|
+
*/
|
|
269
|
+
getRegisteredIds() {
|
|
270
|
+
return Array.from(this.apiMap.keys());
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Checks whether a grid API is registered under the given identifier.
|
|
274
|
+
*
|
|
275
|
+
* @param id - The unique identifier to check.
|
|
276
|
+
* @returns `true` if an API is registered with that ID.
|
|
277
|
+
*/
|
|
278
|
+
hasApi(id) {
|
|
279
|
+
return this.apiMap.has(id);
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Removes all registered grid APIs.
|
|
283
|
+
*
|
|
284
|
+
* Useful during application teardown or testing.
|
|
285
|
+
*/
|
|
286
|
+
clear() {
|
|
287
|
+
this.apiMap.clear();
|
|
288
|
+
}
|
|
289
|
+
};
|
|
290
|
+
exports.GridStormService = __decorateClass([
|
|
291
|
+
core.Injectable({ providedIn: "root" })
|
|
292
|
+
], exports.GridStormService);
|
|
293
|
+
//# sourceMappingURL=index.cjs.map
|
|
294
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +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"]}
|