# Griddy Examples ## Table of Contents 1. [Basic Grid](#basic-grid) 2. [Editable Grid](#editable-grid) 3. [Searchable Grid](#searchable-grid) 4. [Filtered Grid](#filtered-grid) 5. [Paginated Grid](#paginated-grid) 6. [Server-Side Grid](#server-side-grid) 7. [Custom Renderers](#custom-renderers) 8. [Selection](#selection) 9. [TypeScript Integration](#typescript-integration) ## Basic Grid ```typescript import { Griddy, type GriddyColumn } from '@warkypublic/oranguru' interface Product { id: number name: string price: number inStock: boolean } const columns: GriddyColumn[] = [ { id: 'id', accessor: 'id', header: 'ID', width: 60 }, { id: 'name', accessor: 'name', header: 'Product Name', width: 200, sortable: true }, { id: 'price', accessor: 'price', header: 'Price', width: 100, sortable: true }, { id: 'inStock', accessor: row => row.inStock ? 'Yes' : 'No', header: 'In Stock', width: 100 }, ] const data: Product[] = [ { id: 1, name: 'Laptop', price: 999, inStock: true }, { id: 2, name: 'Mouse', price: 29, inStock: false }, ] export function ProductGrid() { return ( String(row.id)} /> ) } ``` ## Editable Grid ```typescript import { useState } from 'react' import { Griddy, type GriddyColumn } from '@warkypublic/oranguru' interface User { id: number firstName: string lastName: string age: number role: string } export function EditableUserGrid() { const [users, setUsers] = useState([ { id: 1, firstName: 'John', lastName: 'Doe', age: 30, role: 'Admin' }, { id: 2, firstName: 'Jane', lastName: 'Smith', age: 25, role: 'User' }, ]) const columns: GriddyColumn[] = [ { id: 'id', accessor: 'id', header: 'ID', width: 60 }, { id: 'firstName', accessor: 'firstName', header: 'First Name', width: 150, editable: true, editorConfig: { type: 'text' }, }, { id: 'lastName', accessor: 'lastName', header: 'Last Name', width: 150, editable: true, editorConfig: { type: 'text' }, }, { id: 'age', accessor: 'age', header: 'Age', width: 80, editable: true, editorConfig: { type: 'number', min: 18, max: 120 }, }, { id: 'role', accessor: 'role', header: 'Role', width: 120, editable: true, editorConfig: { type: 'select', options: [ { label: 'Admin', value: 'Admin' }, { label: 'User', value: 'User' }, { label: 'Guest', value: 'Guest' }, ], }, }, ] const handleEditCommit = async (rowId: string, columnId: string, value: unknown) => { setUsers(prev => prev.map(user => String(user.id) === rowId ? { ...user, [columnId]: value } : user )) } return ( String(row.id)} onEditCommit={handleEditCommit} /> ) } ``` ## Searchable Grid ```typescript import { Griddy, type GriddyColumn } from '@warkypublic/oranguru' export function SearchableGrid() { const columns: GriddyColumn[] = [ { id: 'name', accessor: 'name', header: 'Name', width: 150, searchable: true }, { id: 'email', accessor: 'email', header: 'Email', width: 250, searchable: true }, { id: 'department', accessor: 'department', header: 'Department', width: 150 }, ] return ( ) } ``` ## Filtered Grid ```typescript import { useState } from 'react' import { Griddy, type GriddyColumn } from '@warkypublic/oranguru' import type { ColumnFiltersState } from '@tanstack/react-table' export function FilteredGrid() { const [filters, setFilters] = useState([]) const columns: GriddyColumn[] = [ { id: 'name', accessor: 'name', header: 'Name', filterable: true, filterConfig: { type: 'text' }, width: 150, }, { id: 'age', accessor: 'age', header: 'Age', filterable: true, filterConfig: { type: 'number' }, width: 80, }, { id: 'department', accessor: 'department', header: 'Department', filterable: true, filterConfig: { type: 'enum', enumOptions: [ { label: 'Engineering', value: 'Engineering' }, { label: 'Marketing', value: 'Marketing' }, { label: 'Sales', value: 'Sales' }, ], }, width: 150, }, ] return ( ) } ``` ## Paginated Grid ```typescript import { Griddy, type GriddyColumn } from '@warkypublic/oranguru' export function PaginatedGrid() { const columns: GriddyColumn[] = [ { id: 'id', accessor: 'id', header: 'ID', width: 60 }, { id: 'name', accessor: 'name', header: 'Name', width: 150 }, { id: 'email', accessor: 'email', header: 'Email', width: 250 }, ] return ( ) } ``` ## Server-Side Grid ```typescript import { useState, useEffect } from 'react' import { Griddy, type GriddyColumn } from '@warkypublic/oranguru' import type { ColumnFiltersState, SortingState } from '@tanstack/react-table' export function ServerSideGrid() { const [data, setData] = useState([]) const [totalCount, setTotalCount] = useState(0) const [filters, setFilters] = useState([]) const [sorting, setSorting] = useState([]) const [pageIndex, setPageIndex] = useState(0) const [pageSize, setPageSize] = useState(25) const [isLoading, setIsLoading] = useState(false) // Fetch data when filters, sorting, or pagination changes useEffect(() => { const fetchData = async () => { setIsLoading(true) try { const response = await fetch('/api/users', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ filters, sorting, pagination: { pageIndex, pageSize }, }), }) const result = await response.json() setData(result.data) setTotalCount(result.total) } finally { setIsLoading(false) } } fetchData() }, [filters, sorting, pageIndex, pageSize]) const columns: GriddyColumn[] = [ { id: 'name', accessor: 'name', header: 'Name', sortable: true, filterable: true, filterConfig: { type: 'text' }, width: 150, }, // ... more columns ] return ( { setPageSize(size) setPageIndex(0) }, }} /> ) } ``` ## Custom Renderers ```typescript import { Griddy, type GriddyColumn, type CellRenderer } from '@warkypublic/oranguru' import { Badge } from '@mantine/core' interface Order { id: number customer: string amount: number status: 'pending' | 'shipped' | 'delivered' } const StatusRenderer: CellRenderer = ({ value }) => { const color = value === 'delivered' ? 'green' : value === 'shipped' ? 'blue' : 'yellow' return {String(value)} } const AmountRenderer: CellRenderer = ({ value }) => { const amount = Number(value) const color = amount > 1000 ? 'green' : 'gray' return ${amount.toFixed(2)} } export function OrderGrid() { const columns: GriddyColumn[] = [ { id: 'id', accessor: 'id', header: 'Order ID', width: 100 }, { id: 'customer', accessor: 'customer', header: 'Customer', width: 200 }, { id: 'amount', accessor: 'amount', header: 'Amount', width: 120, renderer: AmountRenderer, }, { id: 'status', accessor: 'status', header: 'Status', width: 120, renderer: StatusRenderer, }, ] return } ``` ## Selection ```typescript import { useState } from 'react' import { Griddy, type GriddyColumn } from '@warkypublic/oranguru' import type { RowSelectionState } from '@tanstack/react-table' export function SelectableGrid() { const [selection, setSelection] = useState({}) const columns: GriddyColumn[] = [ { id: 'name', accessor: 'name', header: 'Name', width: 150 }, { id: 'email', accessor: 'email', header: 'Email', width: 250 }, ] const selectedRows = Object.keys(selection).filter(key => selection[key]) return ( <>
Selected: {selectedRows.length} rows
) } ``` ## TypeScript Integration ```typescript // Define your data type interface Employee { id: number firstName: string lastName: string email: string department: string salary: number hireDate: string isActive: boolean } // Type-safe column definition const columns: GriddyColumn[] = [ { id: 'id', accessor: 'id', // Type-checked against Employee keys header: 'ID', width: 60, }, { id: 'fullName', accessor: (row) => `${row.firstName} ${row.lastName}`, // Type-safe accessor function header: 'Full Name', width: 200, }, { id: 'salary', accessor: 'salary', header: 'Salary', width: 120, renderer: ({ value }) => `$${Number(value).toLocaleString()}`, }, ] // Type-safe component export function EmployeeGrid() { const [employees, setEmployees] = useState([]) const handleEdit = async (rowId: string, columnId: string, value: unknown) => { // TypeScript knows employees is Employee[] setEmployees(prev => prev.map(emp => String(emp.id) === rowId ? { ...emp, [columnId]: value } : emp )) } return ( columns={columns} data={employees} height={600} getRowId={(row) => String(row.id)} onEditCommit={handleEdit} /> ) } ```