@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/dist/index.js ADDED
@@ -0,0 +1,294 @@
1
+ import { Input, Output, ViewChild, Component, Injectable, EventEmitter } from '@angular/core';
2
+ import { createGrid } from '@gridstorm/core';
3
+ import { DomRenderer } from '@gridstorm/dom-renderer';
4
+
5
+ var __defProp = Object.defineProperty;
6
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
+ var __decorateClass = (decorators, target, key, kind) => {
8
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
9
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
10
+ if (decorator = decorators[i])
11
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
12
+ if (kind && result) __defProp(target, key, result);
13
+ return result;
14
+ };
15
+ var GridStormComponent = class {
16
+ constructor() {
17
+ this.columns = [];
18
+ this.rowData = [];
19
+ this.plugins = [];
20
+ this.rowHeight = 40;
21
+ this.theme = "light";
22
+ this.density = "normal";
23
+ this.gridReady = new EventEmitter();
24
+ this.rowDataChanged = new EventEmitter();
25
+ this.selectionChanged = new EventEmitter();
26
+ this.sortChanged = new EventEmitter();
27
+ this.filterChanged = new EventEmitter();
28
+ this.cellValueChanged = new EventEmitter();
29
+ this.cellClicked = new EventEmitter();
30
+ this.cellDoubleClicked = new EventEmitter();
31
+ this.rowClicked = new EventEmitter();
32
+ this.paginationChanged = new EventEmitter();
33
+ this.columnResized = new EventEmitter();
34
+ // ── Internal state ──
35
+ this.engine = null;
36
+ this.renderer = null;
37
+ this.eventUnsubscribers = [];
38
+ }
39
+ // ── Lifecycle ──
40
+ ngOnInit() {
41
+ this.initGrid();
42
+ }
43
+ ngOnChanges(changes) {
44
+ if (!this.engine) return;
45
+ if (changes["rowData"] && !changes["rowData"].firstChange) {
46
+ this.engine.api.setRowData(this.rowData);
47
+ }
48
+ if (changes["columns"] && !changes["columns"].firstChange) {
49
+ this.engine.api.setColumnDefs(this.columns);
50
+ }
51
+ if (changes["paginationPageSize"] && !changes["paginationPageSize"].firstChange) {
52
+ if (this.paginationPageSize != null) {
53
+ this.engine.api.setGridOption("paginationPageSize", this.paginationPageSize);
54
+ }
55
+ }
56
+ }
57
+ ngOnDestroy() {
58
+ this.destroyGrid();
59
+ }
60
+ // ── Public API ──
61
+ /**
62
+ * Returns the underlying GridApi instance, or null if the grid
63
+ * has not been initialized yet.
64
+ */
65
+ getApi() {
66
+ return this.engine?.api ?? null;
67
+ }
68
+ /**
69
+ * Returns the underlying GridEngine instance, or null if the grid
70
+ * has not been initialized yet.
71
+ */
72
+ getEngine() {
73
+ return this.engine;
74
+ }
75
+ // ── Initialization ──
76
+ initGrid() {
77
+ const container = this.gridContainerRef.nativeElement;
78
+ if (!container) return;
79
+ const config = {
80
+ columns: this.columns,
81
+ rowData: this.rowData,
82
+ plugins: this.plugins,
83
+ getRowId: this.getRowId,
84
+ rowHeight: this.rowHeight,
85
+ headerHeight: this.headerHeight,
86
+ defaultColDef: this.defaultColDef,
87
+ domLayout: this.domLayout,
88
+ rowSelection: this.rowSelection,
89
+ pagination: this.pagination,
90
+ paginationPageSize: this.paginationPageSize,
91
+ ariaLabel: this.ariaLabel,
92
+ theme: this.theme
93
+ };
94
+ this.engine = createGrid(config);
95
+ this.renderer = new DomRenderer({
96
+ container,
97
+ engine: this.engine
98
+ });
99
+ this.renderer.mount();
100
+ this.setupEventBridge();
101
+ this.gridReady.emit(this.engine.api);
102
+ }
103
+ setupEventBridge() {
104
+ if (!this.engine) return;
105
+ const eb = this.engine.eventBus;
106
+ this.eventUnsubscribers = [
107
+ eb.on("rowData:changed", (e) => this.rowDataChanged.emit(e)),
108
+ eb.on("selection:changed", (e) => this.selectionChanged.emit(e)),
109
+ eb.on("column:sort:changed", (e) => this.sortChanged.emit(e)),
110
+ eb.on("filter:changed", (e) => this.filterChanged.emit(e)),
111
+ eb.on("cell:valueChanged", (e) => this.cellValueChanged.emit(e)),
112
+ eb.on("cell:clicked", (e) => this.cellClicked.emit(e)),
113
+ eb.on("cell:doubleClicked", (e) => this.cellDoubleClicked.emit(e)),
114
+ eb.on("row:clicked", (e) => this.rowClicked.emit(e)),
115
+ eb.on("pagination:changed", (e) => this.paginationChanged.emit(e)),
116
+ eb.on("column:resized", (e) => this.columnResized.emit(e))
117
+ ];
118
+ }
119
+ destroyGrid() {
120
+ for (const unsub of this.eventUnsubscribers) {
121
+ unsub();
122
+ }
123
+ this.eventUnsubscribers = [];
124
+ if (this.renderer) {
125
+ this.renderer.destroy();
126
+ this.renderer = null;
127
+ }
128
+ if (this.engine) {
129
+ this.engine.destroy();
130
+ this.engine = null;
131
+ }
132
+ }
133
+ };
134
+ __decorateClass([
135
+ Input()
136
+ ], GridStormComponent.prototype, "columns", 2);
137
+ __decorateClass([
138
+ Input()
139
+ ], GridStormComponent.prototype, "rowData", 2);
140
+ __decorateClass([
141
+ Input()
142
+ ], GridStormComponent.prototype, "plugins", 2);
143
+ __decorateClass([
144
+ Input()
145
+ ], GridStormComponent.prototype, "getRowId", 2);
146
+ __decorateClass([
147
+ Input()
148
+ ], GridStormComponent.prototype, "rowHeight", 2);
149
+ __decorateClass([
150
+ Input()
151
+ ], GridStormComponent.prototype, "theme", 2);
152
+ __decorateClass([
153
+ Input()
154
+ ], GridStormComponent.prototype, "density", 2);
155
+ __decorateClass([
156
+ Input()
157
+ ], GridStormComponent.prototype, "defaultColDef", 2);
158
+ __decorateClass([
159
+ Input()
160
+ ], GridStormComponent.prototype, "paginationPageSize", 2);
161
+ __decorateClass([
162
+ Input()
163
+ ], GridStormComponent.prototype, "headerHeight", 2);
164
+ __decorateClass([
165
+ Input()
166
+ ], GridStormComponent.prototype, "domLayout", 2);
167
+ __decorateClass([
168
+ Input()
169
+ ], GridStormComponent.prototype, "rowSelection", 2);
170
+ __decorateClass([
171
+ Input()
172
+ ], GridStormComponent.prototype, "pagination", 2);
173
+ __decorateClass([
174
+ Input()
175
+ ], GridStormComponent.prototype, "ariaLabel", 2);
176
+ __decorateClass([
177
+ Output()
178
+ ], GridStormComponent.prototype, "gridReady", 2);
179
+ __decorateClass([
180
+ Output()
181
+ ], GridStormComponent.prototype, "rowDataChanged", 2);
182
+ __decorateClass([
183
+ Output()
184
+ ], GridStormComponent.prototype, "selectionChanged", 2);
185
+ __decorateClass([
186
+ Output()
187
+ ], GridStormComponent.prototype, "sortChanged", 2);
188
+ __decorateClass([
189
+ Output()
190
+ ], GridStormComponent.prototype, "filterChanged", 2);
191
+ __decorateClass([
192
+ Output()
193
+ ], GridStormComponent.prototype, "cellValueChanged", 2);
194
+ __decorateClass([
195
+ Output()
196
+ ], GridStormComponent.prototype, "cellClicked", 2);
197
+ __decorateClass([
198
+ Output()
199
+ ], GridStormComponent.prototype, "cellDoubleClicked", 2);
200
+ __decorateClass([
201
+ Output()
202
+ ], GridStormComponent.prototype, "rowClicked", 2);
203
+ __decorateClass([
204
+ Output()
205
+ ], GridStormComponent.prototype, "paginationChanged", 2);
206
+ __decorateClass([
207
+ Output()
208
+ ], GridStormComponent.prototype, "columnResized", 2);
209
+ __decorateClass([
210
+ ViewChild("gridContainer", { static: true })
211
+ ], GridStormComponent.prototype, "gridContainerRef", 2);
212
+ GridStormComponent = __decorateClass([
213
+ Component({
214
+ selector: "gridstorm",
215
+ standalone: true,
216
+ template: `
217
+ <div
218
+ #gridContainer
219
+ class="gridstorm-wrapper"
220
+ [attr.data-theme]="theme"
221
+ [attr.data-density]="density"
222
+ style="width:100%;height:100%"
223
+ ></div>
224
+ `
225
+ })
226
+ ], GridStormComponent);
227
+ var GridStormService = class {
228
+ constructor() {
229
+ this.apiMap = /* @__PURE__ */ new Map();
230
+ }
231
+ /**
232
+ * Registers a GridApi instance under a unique identifier.
233
+ *
234
+ * Call this from the `(gridReady)` output handler of the `<gridstorm>` component.
235
+ * If an API with the same ID already exists, it will be replaced.
236
+ *
237
+ * @param id - A unique string identifier for this grid instance.
238
+ * @param api - The GridApi instance to register.
239
+ */
240
+ registerApi(id, api) {
241
+ this.apiMap.set(id, api);
242
+ }
243
+ /**
244
+ * Retrieves a previously registered GridApi by its identifier.
245
+ *
246
+ * @param id - The unique identifier used during registration.
247
+ * @returns The GridApi instance, or `undefined` if not found.
248
+ */
249
+ getApi(id) {
250
+ return this.apiMap.get(id);
251
+ }
252
+ /**
253
+ * Removes a registered GridApi by its identifier.
254
+ *
255
+ * Call this when a grid component is destroyed to prevent memory leaks.
256
+ *
257
+ * @param id - The unique identifier of the API to remove.
258
+ */
259
+ removeApi(id) {
260
+ this.apiMap.delete(id);
261
+ }
262
+ /**
263
+ * Returns all registered grid API identifiers.
264
+ *
265
+ * @returns An array of registered grid IDs.
266
+ */
267
+ getRegisteredIds() {
268
+ return Array.from(this.apiMap.keys());
269
+ }
270
+ /**
271
+ * Checks whether a grid API is registered under the given identifier.
272
+ *
273
+ * @param id - The unique identifier to check.
274
+ * @returns `true` if an API is registered with that ID.
275
+ */
276
+ hasApi(id) {
277
+ return this.apiMap.has(id);
278
+ }
279
+ /**
280
+ * Removes all registered grid APIs.
281
+ *
282
+ * Useful during application teardown or testing.
283
+ */
284
+ clear() {
285
+ this.apiMap.clear();
286
+ }
287
+ };
288
+ GridStormService = __decorateClass([
289
+ Injectable({ providedIn: "root" })
290
+ ], GridStormService);
291
+
292
+ export { GridStormComponent, GridStormService };
293
+ //# sourceMappingURL=index.js.map
294
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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"]}
package/package.json ADDED
@@ -0,0 +1,80 @@
1
+ {
2
+ "name": "@gridstorm/angular",
3
+ "version": "0.1.2",
4
+ "description": "GridStorm Angular adapter — standalone component for Angular 16+",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "source": "./src/index.ts",
10
+ "exports": {
11
+ ".": {
12
+ "import": {
13
+ "types": "./dist/index.d.ts",
14
+ "default": "./dist/index.js"
15
+ },
16
+ "require": {
17
+ "types": "./dist/index.d.cts",
18
+ "default": "./dist/index.cjs"
19
+ }
20
+ }
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "src",
25
+ "LICENSE.md"
26
+ ],
27
+ "scripts": {
28
+ "build": "tsup",
29
+ "dev": "tsup --watch",
30
+ "typecheck": "tsc --noEmit",
31
+ "clean": "rm -rf dist"
32
+ },
33
+ "dependencies": {
34
+ "@gridstorm/core": "workspace:*",
35
+ "@gridstorm/dom-renderer": "workspace:*"
36
+ },
37
+ "peerDependencies": {
38
+ "@angular/core": ">=16.0.0",
39
+ "@angular/common": ">=16.0.0"
40
+ },
41
+ "devDependencies": {
42
+ "@angular/core": ">=16.0.0",
43
+ "@angular/common": ">=16.0.0",
44
+ "tsup": "^8.2.0",
45
+ "typescript": "^5.5.0"
46
+ },
47
+ "sideEffects": false,
48
+ "publishConfig": {
49
+ "access": "public"
50
+ },
51
+ "license": "MIT",
52
+ "keywords": [
53
+ "datagrid",
54
+ "angular",
55
+ "angular-grid",
56
+ "angular-table",
57
+ "gridstorm",
58
+ "standalone-component"
59
+ ],
60
+ "repository": {
61
+ "type": "git",
62
+ "url": "https://github.com/007krcs/grid-data.git",
63
+ "directory": "packages/angular-adapter"
64
+ },
65
+ "bugs": {
66
+ "url": "https://github.com/007krcs/grid-data/issues"
67
+ },
68
+ "homepage": "https://grid-data-analytics-explorer.vercel.app/",
69
+ "author": {
70
+ "name": "GridStorm",
71
+ "url": "https://grid-data-analytics-explorer.vercel.app/"
72
+ },
73
+ "funding": {
74
+ "type": "github",
75
+ "url": "https://github.com/sponsors/gridstorm"
76
+ },
77
+ "engines": {
78
+ "node": ">=18.0.0"
79
+ }
80
+ }
@@ -0,0 +1,252 @@
1
+ // ─── GridStorm Angular Component ───
2
+ // Standalone Angular component wrapping the headless core engine + DOM renderer.
3
+ // Uses ElementRef + ViewChild to mount the DomRenderer into the template container.
4
+
5
+ import {
6
+ Component,
7
+ Input,
8
+ Output,
9
+ EventEmitter,
10
+ ElementRef,
11
+ OnInit,
12
+ OnDestroy,
13
+ OnChanges,
14
+ SimpleChanges,
15
+ ViewChild,
16
+ } from '@angular/core';
17
+ import { createGrid } from '@gridstorm/core';
18
+ import { DomRenderer } from '@gridstorm/dom-renderer';
19
+ import type { GridConfig, GridApi, GridEngine, ColumnDef, GridPlugin } from '@gridstorm/core';
20
+
21
+ @Component({
22
+ selector: 'gridstorm',
23
+ standalone: true,
24
+ template: `
25
+ <div
26
+ #gridContainer
27
+ class="gridstorm-wrapper"
28
+ [attr.data-theme]="theme"
29
+ [attr.data-density]="density"
30
+ style="width:100%;height:100%"
31
+ ></div>
32
+ `,
33
+ })
34
+ export class GridStormComponent implements OnInit, OnDestroy, OnChanges {
35
+ // ── Inputs ──
36
+
37
+ /** Column definitions describing each column's structure and behavior. */
38
+ @Input() columns: ColumnDef[] = [];
39
+
40
+ /** Client-side row data array. */
41
+ @Input() rowData: any[] = [];
42
+
43
+ /** Array of plugins to install during grid initialization. */
44
+ @Input() plugins: GridPlugin[] = [];
45
+
46
+ /** Callback to generate a unique string ID for each row. */
47
+ @Input() getRowId?: (params: any) => string;
48
+
49
+ /** Height of each data row in pixels. */
50
+ @Input() rowHeight = 40;
51
+
52
+ /** Theme identifier: 'light', 'dark', or custom theme name. */
53
+ @Input() theme = 'light';
54
+
55
+ /** Density mode: 'compact', 'normal', or 'comfortable'. */
56
+ @Input() density = 'normal';
57
+
58
+ /** Default column definition applied to all columns as fallback. */
59
+ @Input() defaultColDef?: Partial<ColumnDef>;
60
+
61
+ /** Number of rows per page when pagination is enabled. */
62
+ @Input() paginationPageSize?: number;
63
+
64
+ /** Height of the header row in pixels. */
65
+ @Input() headerHeight?: number;
66
+
67
+ /** Controls how the grid's DOM height is determined. */
68
+ @Input() domLayout?: 'normal' | 'autoHeight' | 'print';
69
+
70
+ /** Row selection mode: 'single', 'multiple', or false (disabled). */
71
+ @Input() rowSelection?: 'single' | 'multiple' | false;
72
+
73
+ /** When true, enables client-side pagination. */
74
+ @Input() pagination?: boolean;
75
+
76
+ /** ARIA label for the grid root element (screen reader accessibility). */
77
+ @Input() ariaLabel?: string;
78
+
79
+ // ── Outputs ──
80
+
81
+ /** Emitted when the grid engine is fully initialized and the API is ready. */
82
+ @Output() gridReady = new EventEmitter<GridApi>();
83
+
84
+ /** Emitted when row data changes. */
85
+ @Output() rowDataChanged = new EventEmitter<any>();
86
+
87
+ /** Emitted when the selection state changes. */
88
+ @Output() selectionChanged = new EventEmitter<any>();
89
+
90
+ /** Emitted when the sort model changes. */
91
+ @Output() sortChanged = new EventEmitter<any>();
92
+
93
+ /** Emitted when the filter model changes. */
94
+ @Output() filterChanged = new EventEmitter<any>();
95
+
96
+ /** Emitted when a cell value is changed through editing. */
97
+ @Output() cellValueChanged = new EventEmitter<any>();
98
+
99
+ /** Emitted when a cell is clicked. */
100
+ @Output() cellClicked = new EventEmitter<any>();
101
+
102
+ /** Emitted when a cell is double-clicked. */
103
+ @Output() cellDoubleClicked = new EventEmitter<any>();
104
+
105
+ /** Emitted when a row is clicked. */
106
+ @Output() rowClicked = new EventEmitter<any>();
107
+
108
+ /** Emitted when pagination state changes. */
109
+ @Output() paginationChanged = new EventEmitter<any>();
110
+
111
+ /** Emitted when a column is resized. */
112
+ @Output() columnResized = new EventEmitter<any>();
113
+
114
+ // ── Template reference ──
115
+
116
+ @ViewChild('gridContainer', { static: true })
117
+ private gridContainerRef!: ElementRef<HTMLElement>;
118
+
119
+ // ── Internal state ──
120
+
121
+ private engine: GridEngine | null = null;
122
+ private renderer: DomRenderer | null = null;
123
+ private eventUnsubscribers: Array<() => void> = [];
124
+
125
+ // ── Lifecycle ──
126
+
127
+ ngOnInit(): void {
128
+ this.initGrid();
129
+ }
130
+
131
+ ngOnChanges(changes: SimpleChanges): void {
132
+ if (!this.engine) return;
133
+
134
+ // Sync rowData changes to the engine
135
+ if (changes['rowData'] && !changes['rowData'].firstChange) {
136
+ this.engine.api.setRowData(this.rowData);
137
+ }
138
+
139
+ // Sync column definition changes to the engine
140
+ if (changes['columns'] && !changes['columns'].firstChange) {
141
+ this.engine.api.setColumnDefs(this.columns);
142
+ }
143
+
144
+ // Sync pagination page size
145
+ if (changes['paginationPageSize'] && !changes['paginationPageSize'].firstChange) {
146
+ if (this.paginationPageSize != null) {
147
+ this.engine.api.setGridOption('paginationPageSize', this.paginationPageSize);
148
+ }
149
+ }
150
+ }
151
+
152
+ ngOnDestroy(): void {
153
+ this.destroyGrid();
154
+ }
155
+
156
+ // ── Public API ──
157
+
158
+ /**
159
+ * Returns the underlying GridApi instance, or null if the grid
160
+ * has not been initialized yet.
161
+ */
162
+ getApi(): GridApi | null {
163
+ return this.engine?.api ?? null;
164
+ }
165
+
166
+ /**
167
+ * Returns the underlying GridEngine instance, or null if the grid
168
+ * has not been initialized yet.
169
+ */
170
+ getEngine(): GridEngine | null {
171
+ return this.engine;
172
+ }
173
+
174
+ // ── Initialization ──
175
+
176
+ private initGrid(): void {
177
+ const container = this.gridContainerRef.nativeElement;
178
+ if (!container) return;
179
+
180
+ // Build core config from inputs
181
+ const config: GridConfig = {
182
+ columns: this.columns,
183
+ rowData: this.rowData,
184
+ plugins: this.plugins,
185
+ getRowId: this.getRowId,
186
+ rowHeight: this.rowHeight,
187
+ headerHeight: this.headerHeight,
188
+ defaultColDef: this.defaultColDef,
189
+ domLayout: this.domLayout,
190
+ rowSelection: this.rowSelection,
191
+ pagination: this.pagination,
192
+ paginationPageSize: this.paginationPageSize,
193
+ ariaLabel: this.ariaLabel,
194
+ theme: this.theme,
195
+ };
196
+
197
+ // Create the headless grid engine
198
+ this.engine = createGrid(config);
199
+
200
+ // Create and mount the DOM renderer
201
+ this.renderer = new DomRenderer({
202
+ container,
203
+ engine: this.engine,
204
+ });
205
+ this.renderer.mount();
206
+
207
+ // Wire up event bridge: core events -> Angular EventEmitters
208
+ this.setupEventBridge();
209
+
210
+ // Emit gridReady
211
+ this.gridReady.emit(this.engine.api);
212
+ }
213
+
214
+ private setupEventBridge(): void {
215
+ if (!this.engine) return;
216
+
217
+ const eb = this.engine.eventBus;
218
+
219
+ this.eventUnsubscribers = [
220
+ eb.on('rowData:changed', (e) => this.rowDataChanged.emit(e)),
221
+ eb.on('selection:changed', (e) => this.selectionChanged.emit(e)),
222
+ eb.on('column:sort:changed', (e) => this.sortChanged.emit(e)),
223
+ eb.on('filter:changed', (e) => this.filterChanged.emit(e)),
224
+ eb.on('cell:valueChanged', (e) => this.cellValueChanged.emit(e)),
225
+ eb.on('cell:clicked', (e) => this.cellClicked.emit(e)),
226
+ eb.on('cell:doubleClicked', (e) => this.cellDoubleClicked.emit(e)),
227
+ eb.on('row:clicked', (e) => this.rowClicked.emit(e)),
228
+ eb.on('pagination:changed', (e) => this.paginationChanged.emit(e)),
229
+ eb.on('column:resized', (e) => this.columnResized.emit(e)),
230
+ ];
231
+ }
232
+
233
+ private destroyGrid(): void {
234
+ // Unsubscribe from all core events
235
+ for (const unsub of this.eventUnsubscribers) {
236
+ unsub();
237
+ }
238
+ this.eventUnsubscribers = [];
239
+
240
+ // Destroy the DOM renderer
241
+ if (this.renderer) {
242
+ this.renderer.destroy();
243
+ this.renderer = null;
244
+ }
245
+
246
+ // Destroy the grid engine
247
+ if (this.engine) {
248
+ this.engine.destroy();
249
+ this.engine = null;
250
+ }
251
+ }
252
+ }