Skip to content

Commit d7ae3e8

Browse files
committed
Refactor ag-grid feature into own adapter package
1 parent 07f16ff commit d7ae3e8

35 files changed

Lines changed: 1098 additions & 248 deletions

docs/web/docs/.vitepress/config.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ export default defineConfig({
7575
text: "Integration",
7676
items: [
7777
{ text: "Component Libraries", link: "/featured/libraries" },
78+
{
79+
text: "AG Grid (No Adapter)",
80+
link: "/featured/ag-grid-no-adapter",
81+
},
7882
{ text: "Web Components", link: "/featured/web-components" },
7983
{ text: "JSX Support", link: "/featured/jsx" },
8084
{ text: "Vue Templates", link: "/featured/vue-templates" },
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
---
2+
title: AG Grid (No Adapter)
3+
description: Integrate AG Grid directly in Inglorious Web without a dedicated adapter package.
4+
---
5+
6+
# AG Grid (No Adapter)
7+
8+
If your team prefers zero abstraction, you can mount AG Grid directly from an Inglorious Web type.
9+
10+
## When this is enough
11+
12+
- You only have one or two grid screens.
13+
- You want full direct access to AG Grid API and options.
14+
- You do not need a reusable adapter layer.
15+
16+
## Minimal direct integration
17+
18+
```js
19+
import { html, ref } from "@inglorious/web"
20+
import {
21+
AllCommunityModule,
22+
createGrid,
23+
ModuleRegistry,
24+
} from "ag-grid-community"
25+
26+
ModuleRegistry.registerModules([AllCommunityModule])
27+
28+
const gridInstances = new Map()
29+
30+
export const gridType = {
31+
create(entity) {
32+
entity.themeClass ??= "ag-theme-quartz"
33+
entity.height ??= 520
34+
entity.rowData ??= []
35+
entity.columnDefs ??= []
36+
},
37+
38+
render(entity) {
39+
const height =
40+
typeof entity.height === "number" ? `${entity.height}px` : entity.height
41+
42+
return html`
43+
<div
44+
class="${entity.themeClass}"
45+
style="width: 100%; height: ${height};"
46+
${ref((el) => {
47+
if (!el) return
48+
49+
const current = gridInstances.get(entity.id)
50+
if (!current) {
51+
const api = createGrid(el, {
52+
rowData: entity.rowData,
53+
columnDefs: entity.columnDefs,
54+
})
55+
gridInstances.set(entity.id, { api, el })
56+
return
57+
}
58+
59+
if (current.el !== el) {
60+
current.api.destroy()
61+
const api = createGrid(el, {
62+
rowData: entity.rowData,
63+
columnDefs: entity.columnDefs,
64+
})
65+
gridInstances.set(entity.id, { api, el })
66+
return
67+
}
68+
69+
current.api.updateGridOptions({
70+
rowData: entity.rowData,
71+
columnDefs: entity.columnDefs,
72+
})
73+
})}
74+
></div>
75+
`
76+
},
77+
78+
destroy(entity) {
79+
const current = gridInstances.get(entity.id)
80+
if (!current) return
81+
current.api.destroy()
82+
gridInstances.delete(entity.id)
83+
},
84+
}
85+
```
86+
87+
## CSS imports
88+
89+
```js
90+
import "ag-grid-community/styles/ag-grid.css"
91+
import "ag-grid-community/styles/ag-theme-quartz.css"
92+
```
93+
94+
## Trade-off vs adapter package
95+
96+
- Direct recipe: less code upfront, maximum control.
97+
- Adapter package: reusable lifecycle patterns and consistent event surface across apps.

docs/web/docs/featured/overview.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,8 +184,10 @@ Inglorious Web plays nicely with:
184184
- **Web Components** — Shoelace, Material Web Components, etc.
185185
- **Design Systems** — Any CSS framework
186186
- **Specialized Libraries** — Date pickers, rich editors, etc.
187+
- **Data Grids** — AG Grid can be integrated directly (no adapter required)
187188
188189
**[Learn more →](./web-components.md)**
190+
**[AG Grid recipe (no adapter) →](./ag-grid-no-adapter.md)**
189191
190192
## Ecosystem Packages
191193

examples/apps/web-ag-grid/package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@
1313
"preview": "vite preview"
1414
},
1515
"dependencies": {
16-
"@inglorious/web": "workspace:*"
16+
"@inglorious/ag-grid": "workspace:*",
17+
"@inglorious/web": "workspace:*",
18+
"ag-grid-community": "^34.3.1"
1719
},
1820
"devDependencies": {
1921
"@inglorious/eslint-config": "workspace:*",

examples/apps/web-ag-grid/src/app.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import { html } from "@inglorious/web"
22

33
export const app = {
44
render(api) {
5+
const grid = api.getEntity("agGrid")
6+
57
return html`
68
<div class="app-shell">
79
<header class="app-header">
@@ -25,7 +27,15 @@ export const app = {
2527
<button @click=${() => api.notify("#agGrid:addRow")}>Add Row</button>
2628
</section>
2729
28-
<main class="demo-main">${api.render("agGrid")}</main>
30+
<main class="demo-main">
31+
<div class="iw-ag-grid-meta">
32+
<span><b>Entity:</b> ${grid.id}</span>
33+
<span><b>Render Tick:</b> ${grid.tickCount}</span>
34+
<span><b>Grid API ID:</b> ${grid.gridApiId ?? "pending"}</span>
35+
<span><b>Status:</b> ${grid.gridStatus}</span>
36+
</div>
37+
${api.render("agGrid")}
38+
</main>
2939
</div>
3040
`
3141
},
Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,22 @@
1+
import "ag-grid-community/styles/ag-grid.css"
2+
import "ag-grid-community/styles/ag-theme-quartz.css"
3+
4+
import { configureAgGrid } from "@inglorious/ag-grid"
15
import { mount } from "@inglorious/web"
2-
import "@inglorious/web/ag-grid/base.css"
3-
import "@inglorious/web/ag-grid/quartz.css"
4-
import "@inglorious/web/ag-grid/theme.css"
6+
import {
7+
AllCommunityModule,
8+
createGrid,
9+
ModuleRegistry,
10+
} from "ag-grid-community"
511

612
import { app } from "./app.js"
713
import { store } from "./store/index.js"
814

15+
configureAgGrid({
16+
createGrid,
17+
registerModules() {
18+
ModuleRegistry.registerModules([AllCommunityModule])
19+
},
20+
})
21+
922
mount(store, app.render, document.getElementById("root"))

examples/apps/web-ag-grid/src/store/entities.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class MyCellComponent {
1818
return this.eGui
1919
}
2020

21-
refresh(params) {
21+
refresh() {
2222
return true
2323
}
2424

@@ -34,6 +34,7 @@ export const entities = {
3434
tickCount: 0,
3535
rowIdField: "id",
3636
themeClass: "ag-theme-quartz",
37+
height: 520,
3738
columnDefs: [
3839
{ field: "id", maxWidth: 100 },
3940
{ field: "product", cellRenderer: MyCellComponent },
Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
import { agGrid, createStore } from "@inglorious/web"
1+
import { agGrid } from "@inglorious/ag-grid"
2+
import { createStore } from "@inglorious/web"
3+
4+
import { gridDemo } from "../types/grid-demo/index.js"
25
import { entities } from "./entities.js"
36
import { middlewares } from "./middlewares.js"
47

58
export const store = createStore({
6-
types: { grid: agGrid },
9+
types: { grid: [agGrid, gridDemo] },
710
entities,
811
middlewares,
912
})

examples/apps/web-ag-grid/src/style.css

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,18 @@ body {
5252
.controls button:hover {
5353
background: #f9fafb;
5454
}
55+
56+
.demo-main {
57+
background: #fff;
58+
border: 1px solid #e5e7eb;
59+
border-radius: 10px;
60+
padding: 12px;
61+
}
62+
63+
.iw-ag-grid-meta {
64+
display: flex;
65+
flex-wrap: wrap;
66+
gap: 16px;
67+
margin-bottom: 10px;
68+
font-size: 14px;
69+
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/* eslint-disable no-magic-numbers */
2+
const PRICE_BUMP = 15
3+
4+
/**
5+
* @typedef {Record<string, any> & {
6+
* tickCount?: number
7+
* rowIdField?: string
8+
* rowData: Record<string, any>[]
9+
* }} GridDemoEntity
10+
*/
11+
12+
/**
13+
* Initializes demo-specific counters.
14+
* @param {GridDemoEntity} entity
15+
*/
16+
export function create(entity) {
17+
entity.tickCount ??= 0
18+
}
19+
20+
/**
21+
* Increments the render tick counter for the demo UI.
22+
* @param {GridDemoEntity} entity
23+
*/
24+
export function tick(entity) {
25+
entity.tickCount += 1
26+
}
27+
28+
/**
29+
* Shuffles rows to showcase incremental row updates.
30+
* @param {GridDemoEntity} entity
31+
*/
32+
export function shuffleRows(entity) {
33+
const nextRows = [...entity.rowData]
34+
for (let i = nextRows.length - 1; i > 0; i -= 1) {
35+
const j = Math.floor(Math.random() * (i + 1))
36+
const current = nextRows[i]
37+
nextRows[i] = nextRows[j]
38+
nextRows[j] = current
39+
}
40+
entity.rowData = nextRows
41+
}
42+
43+
/**
44+
* Applies a simple price/rating mutation used by demo controls.
45+
* @param {GridDemoEntity} entity
46+
*/
47+
export function bumpPrices(entity) {
48+
entity.rowData = entity.rowData.map((row) => ({
49+
...row,
50+
price: typeof row.price === "number" ? row.price + PRICE_BUMP : row.price,
51+
rating:
52+
typeof row.rating === "number"
53+
? Number((row.rating + Math.random()).toFixed(1))
54+
: row.rating,
55+
}))
56+
}
57+
58+
/**
59+
* Appends a synthetic row based on the last row shape.
60+
* @param {GridDemoEntity} entity
61+
*/
62+
export function addRow(entity) {
63+
const idField = entity.rowIdField || "id"
64+
const nextId = entity.rowData.length + 1
65+
const previousRow = entity.rowData.at(-1) || {}
66+
const nextRow = {}
67+
68+
const entries = Object.entries(previousRow)
69+
if (!entries.length) {
70+
nextRow[idField] = nextId
71+
}
72+
73+
for (const [key, value] of entries) {
74+
if (key === idField) {
75+
nextRow[key] = nextId
76+
continue
77+
}
78+
79+
if (typeof value === "number") {
80+
const randomFactor = 0.9 + Math.random() * 0.2
81+
nextRow[key] = Number((value * randomFactor).toFixed(2))
82+
continue
83+
}
84+
85+
if (typeof value === "string") {
86+
nextRow[key] = `${value} ${nextId}`
87+
continue
88+
}
89+
90+
nextRow[key] = value
91+
}
92+
93+
if (!(idField in nextRow)) {
94+
nextRow[idField] = nextId
95+
}
96+
97+
entity.rowData = [...entity.rowData, nextRow]
98+
}

0 commit comments

Comments
 (0)