Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/web/docs/.vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@ export default defineConfig({
text: "Integration",
items: [
{ text: "Component Libraries", link: "/featured/libraries" },
{
text: "AG Grid (No Adapter)",
link: "/featured/ag-grid-no-adapter",
},
{ text: "Web Components", link: "/featured/web-components" },
{ text: "JSX Support", link: "/featured/jsx" },
{ text: "Vue Templates", link: "/featured/vue-templates" },
Expand Down
97 changes: 97 additions & 0 deletions docs/web/docs/featured/ag-grid-no-adapter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
---
title: AG Grid (No Adapter)
description: Integrate AG Grid directly in Inglorious Web without a dedicated adapter package.
---

# AG Grid (No Adapter)

If your team prefers zero abstraction, you can mount AG Grid directly from an Inglorious Web type.

## When this is enough

- You only have one or two grid screens.
- You want full direct access to AG Grid API and options.
- You do not need a reusable adapter layer.

## Minimal direct integration

```js
import { html, ref } from "@inglorious/web"
import {
AllCommunityModule,
createGrid,
ModuleRegistry,
} from "ag-grid-community"

ModuleRegistry.registerModules([AllCommunityModule])

const gridInstances = new Map()

export const gridType = {
create(entity) {
entity.themeClass ??= "ag-theme-quartz"
entity.height ??= 520
entity.rowData ??= []
entity.columnDefs ??= []
},

render(entity) {
const height =
typeof entity.height === "number" ? `${entity.height}px` : entity.height

return html`
<div
class="${entity.themeClass}"
style="width: 100%; height: ${height};"
${ref((el) => {
if (!el) return

const current = gridInstances.get(entity.id)
if (!current) {
const api = createGrid(el, {
rowData: entity.rowData,
columnDefs: entity.columnDefs,
})
gridInstances.set(entity.id, { api, el })
return
}

if (current.el !== el) {
current.api.destroy()
const api = createGrid(el, {
rowData: entity.rowData,
columnDefs: entity.columnDefs,
})
gridInstances.set(entity.id, { api, el })
return
}

current.api.updateGridOptions({
rowData: entity.rowData,
columnDefs: entity.columnDefs,
})
})}
></div>
`
},

destroy(entity) {
const current = gridInstances.get(entity.id)
if (!current) return
current.api.destroy()
gridInstances.delete(entity.id)
},
}
```

## CSS imports

```js
import "ag-grid-community/styles/ag-grid.css"
import "ag-grid-community/styles/ag-theme-quartz.css"
```

## Trade-off vs adapter package

- Direct recipe: less code upfront, maximum control.
- Adapter package: reusable lifecycle patterns and consistent event surface across apps.
2 changes: 2 additions & 0 deletions docs/web/docs/featured/overview.md
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,10 @@ Inglorious Web plays nicely with:
- **Web Components** — Shoelace, Material Web Components, etc.
- **Design Systems** — Any CSS framework
- **Specialized Libraries** — Date pickers, rich editors, etc.
- **Data Grids** — AG Grid can be integrated directly (no adapter required)

**[Learn more →](./web-components.md)**
**[AG Grid recipe (no adapter) →](./ag-grid-no-adapter.md)**

## Ecosystem Packages

Expand Down
1 change: 1 addition & 0 deletions examples/apps/web-ag-grid/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "@inglorious/eslint-config/browser"
14 changes: 14 additions & 0 deletions examples/apps/web-ag-grid/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>web-ag-grid</title>
<link rel="stylesheet" href="./src/style.css" />
<script type="module" src="/src/main.js"></script>
</head>
<body>
<div id="root"></div>
</body>
</html>
27 changes: 27 additions & 0 deletions examples/apps/web-ag-grid/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
{
"name": "web-ag-grid",
"private": true,
"version": "0.1.0",
"type": "module",
"author": "IceOnFire <antony.mistretta@gmail.com> (https://ingloriouscoderz.it)",
"license": "MIT",
"scripts": {
"format": "prettier --write .",
"lint": "eslint .",
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"dependencies": {
"@inglorious/ag-grid": "workspace:*",
"@inglorious/web": "workspace:*",
"ag-grid-community": "^34.3.1"
},
"devDependencies": {
"@inglorious/eslint-config": "workspace:*",
"eslint": "^9.39.1",
"prettier": "^3.6.2",
"rollup-plugin-minify-template-literals": "^1.1.7",
"vite": "^7.1.6"
}
}
1 change: 1 addition & 0 deletions examples/apps/web-ag-grid/public/vite.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 42 additions & 0 deletions examples/apps/web-ag-grid/src/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { html } from "@inglorious/web"

export const app = {
render(api) {
const grid = api.getEntity("agGrid")

return html`
<div class="app-shell">
<header class="app-header">
<h1>AG Grid Demo (Inglorious)</h1>
<p>
The app re-renders often, but the grid instance stays alive and only
receives incremental updates.
</p>
</header>

<section class="controls">
<button @click=${() => api.notify("#agGrid:tick")}>
Force App Re-render
</button>
<button @click=${() => api.notify("#agGrid:shuffleRows")}>
Shuffle Rows
</button>
<button @click=${() => api.notify("#agGrid:bumpPrices")}>
Bump Prices
</button>
<button @click=${() => api.notify("#agGrid:addRow")}>Add Row</button>
</section>

<main class="demo-main">
<div class="iw-ag-grid-meta">
<span><b>Entity:</b> ${grid.id}</span>
<span><b>Render Tick:</b> ${grid.tickCount}</span>
<span><b>Grid API ID:</b> ${grid.gridApiId ?? "pending"}</span>
<span><b>Status:</b> ${grid.gridStatus}</span>
</div>
${api.render("agGrid")}
</main>
</div>
`
},
}
22 changes: 22 additions & 0 deletions examples/apps/web-ag-grid/src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import "ag-grid-community/styles/ag-grid.css"
import "ag-grid-community/styles/ag-theme-quartz.css"

import { configureAgGrid } from "@inglorious/ag-grid"
import { mount } from "@inglorious/web"
import {
AllCommunityModule,
createGrid,
ModuleRegistry,
} from "ag-grid-community"

import { app } from "./app.js"
import { store } from "./store/index.js"

configureAgGrid({
createGrid,
registerModules() {
ModuleRegistry.registerModules([AllCommunityModule])
},
})

mount(store, app.render, document.getElementById("root"))
104 changes: 104 additions & 0 deletions examples/apps/web-ag-grid/src/store/entities.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
class MyCellComponent {
eGui
eButton
eventListener

init(params) {
this.eGui = document.createElement("div")
this.eGui.innerHTML =
`
<button>+</button>
` + params.value
this.eButton = this.eGui.querySelector("button")
this.eventListener = () => alert(`Value: ${params.value}`)
this.eButton.addEventListener("click", this.eventListener)
}

getGui() {
return this.eGui
}

refresh() {
return true
}

destroy() {
this.eButton.removeEventListener("click", this.eventListener)
}
}

export const entities = {
agGrid: {
type: "grid",
title: "Sales Data",
tickCount: 0,
rowIdField: "id",
themeClass: "ag-theme-quartz",
height: 520,
columnDefs: [
{ field: "id", maxWidth: 100 },
{ field: "product", cellRenderer: MyCellComponent },
{ field: "category" },
{ field: "country" },
{
field: "revenue",
valueFormatter: (p) => "€" + p.value.toLocaleString(),
},
{ field: "price", valueFormatter: (p) => "€" + p.value.toLocaleString() },
{ field: "rating" },
{ field: "growth", valueFormatter: ({ value }) => `${value}%` },
],
rowData: [
{
id: 1,
product: "Forge Cloud",
category: "Software",
country: "Italy",
revenue: 120000,
price: 120,
rating: 4.7,
growth: 8.1,
},
{
id: 2,
product: "Forge Beam",
category: "Hardware",
country: "Brazil",
revenue: 98000,
price: 98,
rating: 4.4,
growth: 5.4,
},
{
id: 3,
product: "Forge Shield",
category: "Software",
country: "United States",
revenue: 154000,
price: 154,
rating: 4.9,
growth: 10.2,
},
{
id: 4,
product: "Forge Arc",
category: "Hardware",
country: "Germany",
revenue: 76000,
price: 76,
rating: 4.1,
growth: 3.6,
},
{
id: 5,
product: "Forge Loop",
category: "Software",
country: "Japan",
revenue: 143000,
price: 143,
rating: 4.8,
growth: 9.4,
},
],
},
}
12 changes: 12 additions & 0 deletions examples/apps/web-ag-grid/src/store/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { agGrid } from "@inglorious/ag-grid"
import { createStore } from "@inglorious/web"

import { gridDemo } from "../types/grid-demo/index.js"
import { entities } from "./entities.js"
import { middlewares } from "./middlewares.js"

export const store = createStore({
types: { grid: [agGrid, gridDemo] },
entities,
middlewares,
})
7 changes: 7 additions & 0 deletions examples/apps/web-ag-grid/src/store/middlewares.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { createDevtools } from "@inglorious/web"

export const middlewares = []

if (import.meta.env.DEV) {
middlewares.push(createDevtools().middleware)
}
Loading