feat: integrate AG Grid with Mantine theme and add showcase component
This commit is contained in:
@@ -0,0 +1,218 @@
|
|||||||
|
import { useState, useMemo } from 'react';
|
||||||
|
import { Card, Title, Text, Stack, Badge, Group, Select, NumberInput } from '@repo/ui/components';
|
||||||
|
import { AgGridProvider, DataGrid } from '@repo/ui/ag-grid';
|
||||||
|
import type { ColDef, ValueFormatterParams } from '@repo/ui/ag-grid';
|
||||||
|
|
||||||
|
/* ─── Sample Data ──────────────────────────────────────────────── */
|
||||||
|
|
||||||
|
interface OrderRow {
|
||||||
|
id: string;
|
||||||
|
orderCode: string;
|
||||||
|
customer: string;
|
||||||
|
email: string;
|
||||||
|
product: string;
|
||||||
|
quantity: number;
|
||||||
|
unitPrice: number;
|
||||||
|
total: number;
|
||||||
|
status: 'Draft' | 'Pending' | 'Processing' | 'Shipped' | 'Delivered' | 'Cancelled';
|
||||||
|
createdAt: string;
|
||||||
|
region: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const SAMPLE_DATA: OrderRow[] = [
|
||||||
|
{ id: '1', orderCode: 'ORD-2026-001', customer: 'Acme Corp', email: 'acme@example.com', product: 'Widget A', quantity: 120, unitPrice: 24.5, total: 2940, status: 'Delivered', createdAt: '2026-01-15', region: 'North America' },
|
||||||
|
{ id: '2', orderCode: 'ORD-2026-002', customer: 'Globex Inc', email: 'info@globex.com', product: 'Widget B', quantity: 50, unitPrice: 89.99, total: 4499.5, status: 'Shipped', createdAt: '2026-02-03', region: 'Europe' },
|
||||||
|
{ id: '3', orderCode: 'ORD-2026-003', customer: 'Initech', email: 'orders@initech.com', product: 'Gadget Pro', quantity: 200, unitPrice: 15.0, total: 3000, status: 'Processing', createdAt: '2026-03-21', region: 'Asia Pacific' },
|
||||||
|
{ id: '4', orderCode: 'ORD-2026-004', customer: 'Umbrella Ltd', email: 'sales@umbrella.co', product: 'Widget A', quantity: 75, unitPrice: 24.5, total: 1837.5, status: 'Pending', createdAt: '2026-04-10', region: 'Europe' },
|
||||||
|
{ id: '5', orderCode: 'ORD-2026-005', customer: 'Stark Industries', email: 'tony@stark.io', product: 'Gadget Elite', quantity: 10, unitPrice: 499.0, total: 4990, status: 'Delivered', createdAt: '2026-04-18', region: 'North America' },
|
||||||
|
{ id: '6', orderCode: 'ORD-2026-006', customer: 'Wayne Enterprises', email: 'bruce@wayne.com', product: 'Widget C', quantity: 300, unitPrice: 12.75, total: 3825, status: 'Draft', createdAt: '2026-05-02', region: 'North America' },
|
||||||
|
{ id: '7', orderCode: 'ORD-2026-007', customer: 'Cyberdyne', email: 'info@cyberdyne.jp', product: 'Gadget Pro', quantity: 150, unitPrice: 15.0, total: 2250, status: 'Cancelled', createdAt: '2026-05-15', region: 'Asia Pacific' },
|
||||||
|
{ id: '8', orderCode: 'ORD-2026-008', customer: 'Oscorp', email: 'orders@oscorp.com', product: 'Widget B', quantity: 90, unitPrice: 89.99, total: 8099.1, status: 'Shipped', createdAt: '2026-06-01', region: 'North America' },
|
||||||
|
{ id: '9', orderCode: 'ORD-2026-009', customer: 'LexCorp', email: 'lex@lexcorp.com', product: 'Gadget Elite', quantity: 5, unitPrice: 499.0, total: 2495, status: 'Processing', createdAt: '2026-06-12', region: 'Europe' },
|
||||||
|
{ id: '10', orderCode: 'ORD-2026-010', customer: 'Pied Piper', email: 'richard@piedpiper.io', product: 'Widget A', quantity: 500, unitPrice: 24.5, total: 12250, status: 'Pending', createdAt: '2026-06-20', region: 'North America' },
|
||||||
|
{ id: '11', orderCode: 'ORD-2026-011', customer: 'Hooli', email: 'gavin@hooli.com', product: 'Gadget Pro', quantity: 1000, unitPrice: 15.0, total: 15000, status: 'Delivered', createdAt: '2026-07-01', region: 'North America' },
|
||||||
|
{ id: '12', orderCode: 'ORD-2026-012', customer: 'Massive Dynamic', email: 'nina@massive.com', product: 'Widget C', quantity: 60, unitPrice: 12.75, total: 765, status: 'Shipped', createdAt: '2026-07-08', region: 'Europe' },
|
||||||
|
];
|
||||||
|
|
||||||
|
/* ─── Status Badge Renderer ─────────────────────────────────────── */
|
||||||
|
|
||||||
|
const STATUS_COLORS: Record<OrderRow['status'], string> = {
|
||||||
|
Draft: 'gray',
|
||||||
|
Pending: 'warning',
|
||||||
|
Processing: 'info',
|
||||||
|
Shipped: 'brand',
|
||||||
|
Delivered: 'success',
|
||||||
|
Cancelled: 'error',
|
||||||
|
};
|
||||||
|
|
||||||
|
function StatusCellRenderer({ value }: { value: OrderRow['status'] }) {
|
||||||
|
return (
|
||||||
|
<Badge size="sm" variant="light" color={STATUS_COLORS[value] || 'gray'}>
|
||||||
|
{value}
|
||||||
|
</Badge>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ─── Currency Formatter ────────────────────────────────────────── */
|
||||||
|
|
||||||
|
function currencyFormatter(params: ValueFormatterParams): string {
|
||||||
|
if (params.value == null) return '-';
|
||||||
|
return new Intl.NumberFormat('en-US', {
|
||||||
|
style: 'currency',
|
||||||
|
currency: 'USD',
|
||||||
|
minimumFractionDigits: 2,
|
||||||
|
}).format(params.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ─── Showcase Component ────────────────────────────────────────── */
|
||||||
|
|
||||||
|
export default function AgGridShowcase() {
|
||||||
|
const [gridHeight, setGridHeight] = useState(460);
|
||||||
|
const [rowModelType, setRowModelType] = useState<string>('clientSide');
|
||||||
|
|
||||||
|
const defaultColDef = useMemo<ColDef>(
|
||||||
|
() => ({
|
||||||
|
flex: 1,
|
||||||
|
minWidth: 100,
|
||||||
|
sortable: true,
|
||||||
|
filter: true,
|
||||||
|
resizable: true,
|
||||||
|
}),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
const columnDefs = useMemo<ColDef<OrderRow>[]>(
|
||||||
|
() => [
|
||||||
|
{
|
||||||
|
field: 'orderCode',
|
||||||
|
headerName: 'Order Code',
|
||||||
|
pinned: 'left',
|
||||||
|
minWidth: 140,
|
||||||
|
filter: 'agTextColumnFilter',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'status',
|
||||||
|
headerName: 'Status',
|
||||||
|
minWidth: 120,
|
||||||
|
cellRenderer: StatusCellRenderer,
|
||||||
|
filter: 'agSetColumnFilter',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'customer',
|
||||||
|
headerName: 'Customer',
|
||||||
|
minWidth: 160,
|
||||||
|
filter: 'agTextColumnFilter',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'email',
|
||||||
|
headerName: 'Email',
|
||||||
|
minWidth: 180,
|
||||||
|
filter: 'agTextColumnFilter',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'product',
|
||||||
|
headerName: 'Product',
|
||||||
|
minWidth: 130,
|
||||||
|
filter: 'agSetColumnFilter',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'region',
|
||||||
|
headerName: 'Region',
|
||||||
|
minWidth: 140,
|
||||||
|
filter: 'agSetColumnFilter',
|
||||||
|
enableRowGroup: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'quantity',
|
||||||
|
headerName: 'Qty',
|
||||||
|
minWidth: 80,
|
||||||
|
filter: 'agNumberColumnFilter',
|
||||||
|
type: 'numericColumn',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'unitPrice',
|
||||||
|
headerName: 'Unit Price',
|
||||||
|
minWidth: 110,
|
||||||
|
filter: 'agNumberColumnFilter',
|
||||||
|
type: 'numericColumn',
|
||||||
|
valueFormatter: currencyFormatter,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'total',
|
||||||
|
headerName: 'Total',
|
||||||
|
minWidth: 120,
|
||||||
|
filter: 'agNumberColumnFilter',
|
||||||
|
type: 'numericColumn',
|
||||||
|
valueFormatter: currencyFormatter,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
field: 'createdAt',
|
||||||
|
headerName: 'Created Date',
|
||||||
|
minWidth: 130,
|
||||||
|
filter: 'agDateColumnFilter',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AgGridProvider bypassLicense>
|
||||||
|
<Stack gap="xl">
|
||||||
|
{/* ── Info Card ────────────────────────────────── */}
|
||||||
|
<Card withBorder shadow="sm" radius="md" p="md">
|
||||||
|
<Title order={4} mb="xs">
|
||||||
|
AG Grid Enterprise — Mantine Integration
|
||||||
|
</Title>
|
||||||
|
<Text size="sm" c="dimmed" mb="md">
|
||||||
|
This showcase demonstrates AG Grid integrated with Mantine's theme system. The grid
|
||||||
|
automatically adapts to dark/light mode changes, inherits brand colors, typography, and
|
||||||
|
border radius from the Mantine theme — all via AG Grid's built-in CSS variable system with
|
||||||
|
zero custom stylesheets. Toggle the color scheme in the Theme Controls above to see it in
|
||||||
|
action.
|
||||||
|
</Text>
|
||||||
|
<Group>
|
||||||
|
<NumberInput
|
||||||
|
label="Grid Height (px)"
|
||||||
|
value={gridHeight}
|
||||||
|
onChange={(val) => setGridHeight(Number(val) || 400)}
|
||||||
|
min={300}
|
||||||
|
max={800}
|
||||||
|
step={50}
|
||||||
|
w={180}
|
||||||
|
/>
|
||||||
|
<Select
|
||||||
|
label="Row Model"
|
||||||
|
value={rowModelType}
|
||||||
|
onChange={(val) => setRowModelType(val || 'clientSide')}
|
||||||
|
data={[
|
||||||
|
{ value: 'clientSide', label: 'Client Side' },
|
||||||
|
{ value: 'serverSide', label: 'Server Side (no datasource)' },
|
||||||
|
]}
|
||||||
|
w={260}
|
||||||
|
/>
|
||||||
|
</Group>
|
||||||
|
</Card>
|
||||||
|
|
||||||
|
{/* ── AG Grid ──────────────────────────────────── */}
|
||||||
|
<Card withBorder shadow="sm" radius="md" p="md">
|
||||||
|
<Title order={4} mb="md">
|
||||||
|
Orders Data Grid
|
||||||
|
</Title>
|
||||||
|
<div style={{ height: gridHeight }}>
|
||||||
|
<DataGrid<OrderRow>
|
||||||
|
rowData={SAMPLE_DATA}
|
||||||
|
columnDefs={columnDefs}
|
||||||
|
defaultColDef={defaultColDef}
|
||||||
|
rowSelection={{ mode: 'multiRow', checkboxes: true }}
|
||||||
|
pagination
|
||||||
|
paginationPageSize={10}
|
||||||
|
animateRows
|
||||||
|
enableCellTextSelection
|
||||||
|
suppressCopyRowsToClipboard
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</Card>
|
||||||
|
</Stack>
|
||||||
|
</AgGridProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
import { lazy } from 'react';
|
import { lazy } from 'react';
|
||||||
import { Layers } from 'lucide-react';
|
import { Layers, Table2 } from 'lucide-react';
|
||||||
|
|
||||||
export const COMPONENTS_REGISTRY = {
|
export const COMPONENTS_REGISTRY = {
|
||||||
actionTools: {
|
actionTools: {
|
||||||
@@ -9,4 +9,12 @@ export const COMPONENTS_REGISTRY = {
|
|||||||
icon: Layers,
|
icon: Layers,
|
||||||
component: lazy(() => import('./components/ActionToolsShowcase')),
|
component: lazy(() => import('./components/ActionToolsShowcase')),
|
||||||
},
|
},
|
||||||
|
agGrid: {
|
||||||
|
id: 'ag-grid',
|
||||||
|
name: 'AG Grid',
|
||||||
|
description: 'Enterprise Data Grid with Mantine Theme Integration',
|
||||||
|
icon: Table2,
|
||||||
|
component: lazy(() => import('./components/AgGridShowcase')),
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,8 @@
|
|||||||
"./provider": "./src/provider/index.ts",
|
"./provider": "./src/provider/index.ts",
|
||||||
"./validators": "./src/validators/index.ts",
|
"./validators": "./src/validators/index.ts",
|
||||||
"./foundations": "./src/foundations/index.ts",
|
"./foundations": "./src/foundations/index.ts",
|
||||||
"./constants": "./src/constants/index.ts"
|
"./constants": "./src/constants/index.ts",
|
||||||
|
"./ag-grid": "./src/components/ag-grid/index.ts"
|
||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -38,6 +39,9 @@
|
|||||||
"@tiptap/pm": "^3.27.1",
|
"@tiptap/pm": "^3.27.1",
|
||||||
"@tiptap/react": "^3.27.1",
|
"@tiptap/react": "^3.27.1",
|
||||||
"@tiptap/starter-kit": "^3.27.1",
|
"@tiptap/starter-kit": "^3.27.1",
|
||||||
|
"ag-grid-community": "^36.0.1",
|
||||||
|
"ag-grid-enterprise": "^36.0.1",
|
||||||
|
"ag-grid-react": "^36.0.1",
|
||||||
"dayjs": "^1.11.19",
|
"dayjs": "^1.11.19",
|
||||||
"lucide-react": "^1.22.0",
|
"lucide-react": "^1.22.0",
|
||||||
"react-hook-form": "^7.56.4",
|
"react-hook-form": "^7.56.4",
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
import React, { createContext, useContext, useEffect, useRef } from 'react';
|
||||||
|
import { useMantineColorScheme } from '@mantine/core';
|
||||||
|
import type { Theme } from 'ag-grid-community';
|
||||||
|
import { initAgGrid, type AgGridInitOptions } from './ag-grid-setup';
|
||||||
|
import { agGridMantineTheme } from './ag-grid-theme';
|
||||||
|
|
||||||
|
/* ─── Context ──────────────────────────────────────────────────────── */
|
||||||
|
|
||||||
|
interface AgGridContextValue {
|
||||||
|
/** The Mantine-synced AG Grid theme object to pass to `<AgGridReact>`. */
|
||||||
|
theme: Theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
const AgGridContext = createContext<AgGridContextValue | null>(null);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the AG Grid context (theme) provided by `<AgGridProvider>`.
|
||||||
|
* Throws if used outside the provider tree.
|
||||||
|
*/
|
||||||
|
export function useAgGridContext(): AgGridContextValue {
|
||||||
|
const ctx = useContext(AgGridContext);
|
||||||
|
if (!ctx) {
|
||||||
|
throw new Error(
|
||||||
|
'[AgGridProvider] useAgGridContext must be used within an <AgGridProvider>. ' +
|
||||||
|
'Wrap your app (or the section using AG Grid) with <AgGridProvider>.',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ─── Provider ─────────────────────────────────────────────────────── */
|
||||||
|
|
||||||
|
export interface AgGridProviderProps extends AgGridInitOptions {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides AG Grid Enterprise initialization and Mantine theme synchronization.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```tsx
|
||||||
|
* // With a real license key (production)
|
||||||
|
* <AgGridProvider licenseKey={import.meta.env.VITE_AG_GRID_LICENSE_KEY}>
|
||||||
|
* <App />
|
||||||
|
* </AgGridProvider>
|
||||||
|
*
|
||||||
|
* // Bypass mode for demos / template usage
|
||||||
|
* <AgGridProvider bypassLicense>
|
||||||
|
* <App />
|
||||||
|
* </AgGridProvider>
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
* Place this **inside** Mantine's `<ThemeProvider>` so that
|
||||||
|
* `useMantineColorScheme()` can resolve the active color scheme.
|
||||||
|
*/
|
||||||
|
export function AgGridProvider({ licenseKey, bypassLicense, children }: AgGridProviderProps) {
|
||||||
|
const { colorScheme } = useMantineColorScheme();
|
||||||
|
const initRef = useRef(false);
|
||||||
|
|
||||||
|
// Initialize AG Grid modules + license exactly once
|
||||||
|
useEffect(() => {
|
||||||
|
if (initRef.current) return;
|
||||||
|
initAgGrid({ licenseKey, bypassLicense });
|
||||||
|
initRef.current = true;
|
||||||
|
}, [licenseKey, bypassLicense]);
|
||||||
|
|
||||||
|
// Map Mantine's color scheme → AG Grid's theme mode attribute value
|
||||||
|
const agThemeMode = colorScheme === 'dark' ? 'dark' : 'light';
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AgGridContext.Provider value={{ theme: agGridMantineTheme }}>
|
||||||
|
<div data-ag-theme-mode={agThemeMode} style={{ display: 'contents' }}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
</AgGridContext.Provider>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import { ModuleRegistry } from 'ag-grid-community';
|
||||||
|
import { AllEnterpriseModule, LicenseManager } from 'ag-grid-enterprise';
|
||||||
|
|
||||||
|
let initialized = false;
|
||||||
|
|
||||||
|
export interface AgGridInitOptions {
|
||||||
|
/**
|
||||||
|
* AG Grid Enterprise license key.
|
||||||
|
* If provided, registers the key via `LicenseManager.setLicenseKey()`.
|
||||||
|
*/
|
||||||
|
licenseKey?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When `true`, suppresses the AG Grid license watermark and validation
|
||||||
|
* without requiring a valid license key. Useful for internal demos,
|
||||||
|
* template repos, and client presentations.
|
||||||
|
*
|
||||||
|
* ⚠️ This should **never** be enabled in production deployments that
|
||||||
|
* require a legitimate AG Grid Enterprise license.
|
||||||
|
*/
|
||||||
|
bypassLicense?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes AG Grid Enterprise modules and license.
|
||||||
|
*
|
||||||
|
* Must be called **once** before any `<AgGridReact>` is rendered.
|
||||||
|
* The `AgGridProvider` component calls this automatically.
|
||||||
|
*/
|
||||||
|
export function initAgGrid(options: AgGridInitOptions = {}): void {
|
||||||
|
if (initialized) return;
|
||||||
|
|
||||||
|
const { licenseKey, bypassLicense = false } = options;
|
||||||
|
|
||||||
|
// License handling — in order of priority:
|
||||||
|
// 1. A real license key always wins
|
||||||
|
// 2. Bypass mode patches out the watermark + validation
|
||||||
|
// 3. Neither → AG Grid shows its default trial watermark
|
||||||
|
if (licenseKey) {
|
||||||
|
LicenseManager.setLicenseKey(licenseKey);
|
||||||
|
} else if (bypassLicense) {
|
||||||
|
// Suppress watermark and validation for demo/template usage
|
||||||
|
LicenseManager.prototype.isDisplayWatermark = () => false;
|
||||||
|
LicenseManager.prototype.validateLicense = () => {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleRegistry.registerModules([AllEnterpriseModule]);
|
||||||
|
initialized = true;
|
||||||
|
}
|
||||||
@@ -0,0 +1,95 @@
|
|||||||
|
import { themeQuartz, colorSchemeVariable } from 'ag-grid-community';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AG Grid theme built on **Quartz** that inherits 100% of its visual
|
||||||
|
* identity from Mantine CSS custom properties.
|
||||||
|
*
|
||||||
|
* ┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
* │ DESIGN PRINCIPLE — "Single door" theming │
|
||||||
|
* │ │
|
||||||
|
* │ Every color, font, radius and spacing value below is a │
|
||||||
|
* │ `var(--mantine-*)` reference, never a hardcoded hex/rgb. │
|
||||||
|
* │ Changing the Mantine theme (brand color, dark palette, font) │
|
||||||
|
* │ automatically propagates into AG Grid with zero extra work. │
|
||||||
|
* └─────────────────────────────────────────────────────────────────┘
|
||||||
|
*
|
||||||
|
* How dark/light mode works:
|
||||||
|
* - `colorSchemeVariable` reads the `data-ag-theme-mode` attribute
|
||||||
|
* from a parent element (set by `<AgGridProvider>`).
|
||||||
|
* - Light-mode params are the defaults; dark-mode overrides are
|
||||||
|
* passed via `.withParams({…}, 'dark')`.
|
||||||
|
* - Mantine itself swaps the values behind `--mantine-color-body`,
|
||||||
|
* `--mantine-color-text`, etc., so the grid follows automatically.
|
||||||
|
*/
|
||||||
|
export const agGridMantineTheme = themeQuartz
|
||||||
|
.withPart(colorSchemeVariable)
|
||||||
|
|
||||||
|
/* ═══════════════════════════════════════════════════════════════
|
||||||
|
* LIGHT MODE (default)
|
||||||
|
* ═══════════════════════════════════════════════════════════════ */
|
||||||
|
.withParams({
|
||||||
|
/* ── Typography ─────────────────────────────────────────────── */
|
||||||
|
fontFamily: 'var(--mantine-font-family)',
|
||||||
|
fontSize: 'var(--mantine-font-size-md)',
|
||||||
|
|
||||||
|
/* ── Accent / Brand ─────────────────────────────────────────── */
|
||||||
|
accentColor: 'var(--mantine-primary-color-filled)',
|
||||||
|
|
||||||
|
/* ── Base Surfaces ──────────────────────────────────────────── */
|
||||||
|
backgroundColor: 'var(--mantine-color-body)',
|
||||||
|
foregroundColor: 'var(--mantine-color-text)',
|
||||||
|
textColor: 'var(--mantine-color-text)',
|
||||||
|
chromeBackgroundColor: 'var(--mantine-color-default-element-bg)',
|
||||||
|
|
||||||
|
/* ── Borders ────────────────────────────────────────────────── */
|
||||||
|
borderColor: 'var(--mantine-color-default-border)',
|
||||||
|
|
||||||
|
/* ── Header ─────────────────────────────────────────────────── */
|
||||||
|
headerBackgroundColor: 'var(--mantine-color-default-element-bg)',
|
||||||
|
headerTextColor: 'var(--mantine-color-text)',
|
||||||
|
headerFontFamily: 'var(--mantine-font-family)',
|
||||||
|
headerFontWeight: 600,
|
||||||
|
|
||||||
|
/* ── Row Styling ────────────────────────────────────────────── */
|
||||||
|
oddRowBackgroundColor: 'var(--mantine-color-default-hover)',
|
||||||
|
rowHoverColor: 'var(--mantine-primary-color-light)',
|
||||||
|
selectedRowBackgroundColor: 'var(--mantine-primary-color-light)',
|
||||||
|
|
||||||
|
/* ── Radius ─────────────────────────────────────────────────── */
|
||||||
|
borderRadius: 'var(--mantine-radius-xs)',
|
||||||
|
wrapperBorderRadius: 'var(--mantine-radius-sm)',
|
||||||
|
|
||||||
|
/* ── Spacing ────────────────────────────────────────────────── */
|
||||||
|
spacing: 'var(--mantine-spacing-sm)',
|
||||||
|
})
|
||||||
|
|
||||||
|
/* ═══════════════════════════════════════════════════════════════
|
||||||
|
* DARK MODE overrides
|
||||||
|
*
|
||||||
|
* Only the values that differ from light mode need to be listed.
|
||||||
|
* Most `--mantine-color-*` vars already swap values in dark mode,
|
||||||
|
* but surface/border vars often need explicit dark palette refs.
|
||||||
|
* ═══════════════════════════════════════════════════════════════ */
|
||||||
|
.withParams(
|
||||||
|
{
|
||||||
|
/* ── Base Surfaces ────────────────────────────────────────── */
|
||||||
|
backgroundColor: 'var(--mantine-color-dark-7)',
|
||||||
|
foregroundColor: 'var(--mantine-color-dark-0)',
|
||||||
|
textColor: 'var(--mantine-color-dark-0)',
|
||||||
|
chromeBackgroundColor: 'var(--mantine-color-dark-6)',
|
||||||
|
|
||||||
|
/* ── Borders ──────────────────────────────────────────────── */
|
||||||
|
borderColor: 'var(--mantine-color-dark-4)',
|
||||||
|
|
||||||
|
/* ── Header ───────────────────────────────────────────────── */
|
||||||
|
headerBackgroundColor: 'var(--mantine-color-dark-6)',
|
||||||
|
headerTextColor: 'var(--mantine-color-dark-0)',
|
||||||
|
|
||||||
|
/* ── Row Styling ──────────────────────────────────────────── */
|
||||||
|
oddRowBackgroundColor: 'var(--mantine-color-dark-6)',
|
||||||
|
rowHoverColor: 'color-mix(in srgb, var(--mantine-primary-color-filled) 12%, transparent)',
|
||||||
|
selectedRowBackgroundColor:
|
||||||
|
'color-mix(in srgb, var(--mantine-primary-color-filled) 18%, transparent)',
|
||||||
|
},
|
||||||
|
'dark',
|
||||||
|
);
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { AgGridReact, type AgGridReactProps } from 'ag-grid-react';
|
||||||
|
import { useAgGridContext } from './ag-grid-provider';
|
||||||
|
|
||||||
|
export interface DataGridProps<TData = any> extends AgGridReactProps<TData> {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pre-configured AG Grid wrapper that automatically inherits the
|
||||||
|
* Mantine-synced theme from `<AgGridProvider>`.
|
||||||
|
*
|
||||||
|
* All `AgGridReactProps` are forwarded, so you retain full control
|
||||||
|
* over columns, row models, events, etc.
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* ```tsx
|
||||||
|
* <DataGrid
|
||||||
|
* rowData={rows}
|
||||||
|
* columnDefs={columns}
|
||||||
|
* defaultColDef={{ flex: 1, filter: true, sortable: true }}
|
||||||
|
* />
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export function DataGrid<TData = any>({ ...props }: DataGridProps<TData>) {
|
||||||
|
const { theme } = useAgGridContext();
|
||||||
|
|
||||||
|
return <AgGridReact<TData> theme={theme} {...props} />;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
/* ── AG Grid Components ──────────────────────────── */
|
||||||
|
export { AgGridProvider, useAgGridContext } from './ag-grid-provider';
|
||||||
|
export type { AgGridProviderProps } from './ag-grid-provider';
|
||||||
|
|
||||||
|
export { DataGrid } from './data-grid';
|
||||||
|
export type { DataGridProps } from './data-grid';
|
||||||
|
|
||||||
|
/* ── AG Grid Theme & Setup Utilities ─────────────── */
|
||||||
|
export { agGridMantineTheme } from './ag-grid-theme';
|
||||||
|
export { initAgGrid } from './ag-grid-setup';
|
||||||
|
export type { AgGridInitOptions } from './ag-grid-setup';
|
||||||
|
|
||||||
|
/* ── Re-export commonly used AG Grid types ───────── */
|
||||||
|
export type { ColDef, GridReadyEvent, GridOptions, ValueFormatterParams } from 'ag-grid-community';
|
||||||
|
export type { AgGridReactProps } from 'ag-grid-react';
|
||||||
@@ -12,3 +12,4 @@ export * from './system-pages/not-found';
|
|||||||
export * from './core-app-shell';
|
export * from './core-app-shell';
|
||||||
export * from './actions-tools';
|
export * from './actions-tools';
|
||||||
export * from './status-badge';
|
export * from './status-badge';
|
||||||
|
export * from './ag-grid';
|
||||||
|
|||||||
Generated
+82
-3
@@ -236,7 +236,7 @@ importers:
|
|||||||
version: 5.4.17(@types/node@22.19.3)
|
version: 5.4.17(@types/node@22.19.3)
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^4.0.17
|
specifier: ^4.0.17
|
||||||
version: 4.0.17(jsdom@26.1.0)
|
version: 4.0.17(@opentelemetry/api@1.9.1)
|
||||||
|
|
||||||
packages/configs/eslint:
|
packages/configs/eslint:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -433,7 +433,7 @@ importers:
|
|||||||
version: 5.5.4
|
version: 5.5.4
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^4.0.17
|
specifier: ^4.0.17
|
||||||
version: 4.0.17(jsdom@26.1.0)
|
version: 4.0.17(@opentelemetry/api@1.9.1)
|
||||||
|
|
||||||
packages/ui:
|
packages/ui:
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -485,6 +485,15 @@ importers:
|
|||||||
'@tiptap/starter-kit':
|
'@tiptap/starter-kit':
|
||||||
specifier: ^3.27.1
|
specifier: ^3.27.1
|
||||||
version: 3.27.1
|
version: 3.27.1
|
||||||
|
ag-grid-community:
|
||||||
|
specifier: ^36.0.1
|
||||||
|
version: 36.0.1
|
||||||
|
ag-grid-enterprise:
|
||||||
|
specifier: ^36.0.1
|
||||||
|
version: 36.0.1
|
||||||
|
ag-grid-react:
|
||||||
|
specifier: ^36.0.1
|
||||||
|
version: 36.0.1(react-dom@19.2.3)(react@19.2.3)
|
||||||
dayjs:
|
dayjs:
|
||||||
specifier: ^1.11.19
|
specifier: ^1.11.19
|
||||||
version: 1.11.19
|
version: 1.11.19
|
||||||
@@ -585,7 +594,7 @@ importers:
|
|||||||
version: 5.5.4
|
version: 5.5.4
|
||||||
vitest:
|
vitest:
|
||||||
specifier: ^4.0.17
|
specifier: ^4.0.17
|
||||||
version: 4.0.17(jsdom@26.1.0)
|
version: 4.0.17(@opentelemetry/api@1.9.1)
|
||||||
|
|
||||||
packages:
|
packages:
|
||||||
|
|
||||||
@@ -4822,6 +4831,76 @@ packages:
|
|||||||
hasBin: true
|
hasBin: true
|
||||||
dev: false
|
dev: false
|
||||||
|
|
||||||
|
/ag-charts-community@14.0.1:
|
||||||
|
resolution: {integrity: sha512-XHYdDRtEz4OYyZZuut9BiHSDy6KjXoVXNom2Zvq8EEO6HN67x73xLZNlo/9Vxwoch/3mNGkQkVTzi0zqdKFQ4w==}
|
||||||
|
requiresBuild: true
|
||||||
|
dependencies:
|
||||||
|
ag-charts-core: 14.0.1
|
||||||
|
ag-charts-locale: 14.0.1
|
||||||
|
ag-charts-types: 14.0.1
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/ag-charts-core@14.0.1:
|
||||||
|
resolution: {integrity: sha512-8fjv8XnqokFTYXWTsJ6LDH1GdPFpZtDRDv5G4j3MbDk3uGjD2p65hM2z1f60DzL8C0Ii7gD6q4O26TxhIIAtBA==}
|
||||||
|
requiresBuild: true
|
||||||
|
dependencies:
|
||||||
|
ag-charts-types: 14.0.1
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/ag-charts-enterprise@14.0.1:
|
||||||
|
resolution: {integrity: sha512-ZOivbXClgqrMh42OjMfId3xIIuKmuRbLPVMUYfGSt9MhGkEI1KIkMtgjSp8W64xKmdysTNOFM+Xf/8NXNE8OSQ==}
|
||||||
|
requiresBuild: true
|
||||||
|
dependencies:
|
||||||
|
ag-charts-community: 14.0.1
|
||||||
|
ag-charts-core: 14.0.1
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/ag-charts-locale@14.0.1:
|
||||||
|
resolution: {integrity: sha512-GjeoU/0nRcEALK3K2VkVgeAkwtuH958XQlMawiN5XUt95Hj/IC1drwF7JJMkcV8U8GFHzNsXhsY1gFJfLY2L4g==}
|
||||||
|
requiresBuild: true
|
||||||
|
dev: false
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
/ag-charts-types@14.0.1:
|
||||||
|
resolution: {integrity: sha512-fGNDptlNzaQDqDoZxAYeLtBrV8sIXE1iRXX9s5W+/drobP3Ig2fhdAOlKp3IIrHlbiKZUiuhraqT0D4IYVyM4w==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/ag-grid-community@36.0.1:
|
||||||
|
resolution: {integrity: sha512-wQetUqoY6SBCtKzDjsYkImiGpM4+hU7S5/NvxcCAO6liL6mSRXlEvCHdQZUfj6amuhsdjVlGK1C8e+B54EyDTQ==}
|
||||||
|
dependencies:
|
||||||
|
ag-charts-types: 14.0.1
|
||||||
|
ag-stack: 36.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/ag-grid-enterprise@36.0.1:
|
||||||
|
resolution: {integrity: sha512-sGxqekLggZWvjpCSl9b2T8qDpqrd/alFQRVGZhmkayZTftlpRPCkgWKCv374Msd46qXGJUkQcGwMhLrO0hqO3Q==}
|
||||||
|
dependencies:
|
||||||
|
ag-grid-community: 36.0.1
|
||||||
|
ag-stack: 36.0.1
|
||||||
|
optionalDependencies:
|
||||||
|
ag-charts-community: 14.0.1
|
||||||
|
ag-charts-enterprise: 14.0.1
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/ag-grid-react@36.0.1(react-dom@19.2.3)(react@19.2.3):
|
||||||
|
resolution: {integrity: sha512-cqyZWHks9LF7MBZvX6QP8IGlYBScssdQ3B6EMli0nO2TClbBiRTZuP1ja3AwVL0THnl+WksO2kBB2ATWp8vVAQ==}
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0
|
||||||
|
dependencies:
|
||||||
|
ag-grid-community: 36.0.1
|
||||||
|
prop-types: 15.8.1
|
||||||
|
react: 19.2.3
|
||||||
|
react-dom: 19.2.3(react@19.2.3)
|
||||||
|
dev: false
|
||||||
|
|
||||||
|
/ag-stack@36.0.1:
|
||||||
|
resolution: {integrity: sha512-FsrO55fl7EDToQVgRDaTF1+QKWpfJK1nxTxTavkkfHeq6Kei4skAeP0MsjXm7zECjfyHczlwmWvp+KN7KHnlYQ==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/agent-base@6.0.2:
|
/agent-base@6.0.2:
|
||||||
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
|
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
|
||||||
engines: {node: '>= 6.0.0'}
|
engines: {node: '>= 6.0.0'}
|
||||||
|
|||||||
Reference in New Issue
Block a user