@amstfn/td-design-system 0.3.0

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/CHANGELOG.md ADDED
@@ -0,0 +1,45 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ## [0.3.0] - 2026-10-05
11
+
12
+ ### Added
13
+
14
+ - Added `TdAlert`, `TdCollapse`, `TdFloatButton`, `TdRadio`, `TdSkeleton`, and `TdTag`.
15
+ - Added `TdText`, `TdTitle`, `TdParagraph`, and `TdLink` as Ant Design Typography wrappers.
16
+ - Added Figma token maps for palette, alias, component, and responsive values.
17
+
18
+ ### Changed
19
+
20
+ - Packaging: AG Grid is a peer only, CommonJS publishes as `index.cjs`, and library types exclude Vitest and Vite client types.
21
+ - Replaced all MUI primitives, theme APIs, and peer dependencies with Ant Design 6.
22
+ - Changed component props to Ant Design-native contracts.
23
+ - Rebuilt `TdThemeProvider` with Ant Design `ConfigProvider`, including dark mode and RTL.
24
+ - Preserved Gregorian and Jalali date pickers using Day.js and `antd-jalali-v5`.
25
+ - Kept the `TdDataGrid` engine on AG Grid while migrating its toolbar and error state to Ant Design.
26
+
27
+ ### Breaking
28
+
29
+ - `TdDataGrid` and its types moved off the root export to `@td/design-system/data-grid`.
30
+ - Date picker values now use Day.js instead of ISO strings.
31
+ - Modal callbacks and footer configuration now follow Ant Design's `ModalProps`.
32
+ - Theme overrides now use Ant Design `ThemeConfig`.
33
+ - MUI-specific variants, props, and event signatures have been removed.
34
+
35
+ ## [0.1.0] - 2026-06-11
36
+
37
+ ### Added
38
+
39
+ - Initial release of `@td/design-system`
40
+ - Design token system (colors, spacing, radius, shadows, typography, z-index)
41
+ - `TdThemeProvider` with light/dark themes, RTL and localization preparation
42
+ - Core components: `TdButton`, `TdInput`, `TdSelect`, `TdModal`, `TdDataGrid`
43
+ - Storybook documentation
44
+ - Vitest test suite with 80% coverage target
45
+ - GitHub Actions CI/CD pipeline
package/README.md ADDED
@@ -0,0 +1,219 @@
1
+ # @amstfn/td-design-system
2
+
3
+ Enterprise-grade React Design System built with TypeScript, Ant Design, and AG Grid.
4
+
5
+ ## Installation
6
+
7
+ Install from the public npm registry, along with the peer dependencies:
8
+
9
+ ```bash
10
+ npm install @amstfn/td-design-system antd antd-jalali-v5 dayjs react react-dom
11
+ ```
12
+
13
+ Mohaymen applications can install the same version from Nexus. Copy `.npmrc.example` into the app instead of publishing registry credentials in source files.
14
+
15
+ `ag-grid-community` and `ag-grid-react` are optional. Install them only when the app imports `@amstfn/td-design-system/data-grid`.
16
+
17
+ ## Quick Start
18
+
19
+ Wrap your application with `TdThemeProvider`:
20
+
21
+ ```tsx
22
+ import { TdButton, TdThemeProvider } from "@amstfn/td-design-system";
23
+ import "@amstfn/td-design-system/styles.css";
24
+
25
+ export function App() {
26
+ return (
27
+ <TdThemeProvider mode="light">
28
+ <TdButton type="primary">Get Started</TdButton>
29
+ </TdThemeProvider>
30
+ );
31
+ }
32
+ ```
33
+
34
+ That file is the Ant Design reset extracted by the library build. AG Grid CSS is not inside `styles.css`. Importing `TdDataGrid` from `@amstfn/td-design-system/data-grid` loads `ag-grid.css` and `ag-theme-alpine.css` as a side effect of that module. The host app must load the `IRANSansX` font itself.
35
+
36
+ ## Important Rules
37
+
38
+ ### Public API only
39
+
40
+ Import from the package root. `TdDataGrid` is the exception and comes from `@amstfn/td-design-system/data-grid`:
41
+
42
+ ```tsx
43
+ import { TdButton, TdInput } from "@amstfn/td-design-system";
44
+ import { TdDataGrid } from "@amstfn/td-design-system/data-grid";
45
+ ```
46
+
47
+ Never import internal paths such as `@amstfn/td-design-system/src/components/TdButton`.
48
+
49
+ ### Ant Design-native component APIs
50
+
51
+ ```tsx
52
+ <TdButton type="primary" htmlType="submit" loading={false}>
53
+ Save
54
+ </TdButton>
55
+ ```
56
+
57
+ ## Components
58
+
59
+ | Component | Description |
60
+ | ----------------- | ------------------------------------------------------------------------------------------------------- |
61
+ | `TdThemeProvider` | Theme, RTL, and localization foundation |
62
+ | `TdButton` | Primary action button with loading and variants |
63
+ | `TdInput` | Text input with validation and accessibility |
64
+ | `TdSelect` | Dropdown select with controlled/uncontrolled modes |
65
+ | `TdAutocomplete` | Searchable free-text suggestions |
66
+ | `TdCheckbox` | Checkbox with validation help |
67
+ | `TdRadio` | Radio and radio group |
68
+ | `TdDatePicker` | Ant DatePicker with Gregorian/Jalali support |
69
+ | `TdModal` | Ant Design modal |
70
+ | `TdAlert` | Inline status message |
71
+ | `TdCollapse` | Expandable content panels |
72
+ | `TdFloatButton` | Floating action button |
73
+ | `TdSkeleton` | Loading placeholder |
74
+ | `TdTag` | Status and category label |
75
+ | `TdText` | Ant Design Typography text |
76
+ | `TdTitle` | Ant Design Typography title |
77
+ | `TdParagraph` | Ant Design Typography paragraph |
78
+ | `TdLink` | Ant Design Typography link |
79
+ | `TdForm` | Closed form wrapper; consumers do not install or call `react-hook-form` to use `TdForm` / `TdFormField` |
80
+ | `TdDataGrid` | AG Grid abstraction with Ant Design toolbar. Import from `@amstfn/td-design-system/data-grid` |
81
+
82
+ ## Theme
83
+
84
+ ```tsx
85
+ <TdThemeProvider mode="dark" direction="rtl" locale={{ locale: "fa-IR" }}>
86
+ <App />
87
+ </TdThemeProvider>
88
+ ```
89
+
90
+ Extend the theme:
91
+
92
+ ```tsx
93
+ <TdThemeProvider
94
+ themeOptions={{
95
+ token: {
96
+ colorPrimary: "#004D40",
97
+ },
98
+ }}
99
+ >
100
+ <App />
101
+ </TdThemeProvider>
102
+ ```
103
+
104
+ ## Design Tokens
105
+
106
+ All components consume centralized tokens:
107
+
108
+ ```tsx
109
+ import { TdSpacing, TdColors, TdRadius } from "@amstfn/td-design-system";
110
+ ```
111
+
112
+ Available token groups: `TdColors`, `TdSpacing`, `TdRadius`, `TdShadows`, `TdTypography`, `TdZIndex`.
113
+
114
+ ## Development
115
+
116
+ ```bash
117
+ npm install
118
+ npm run lint
119
+ npm run typecheck
120
+ npm run test
121
+ npm run build
122
+ npm run storybook
123
+ ```
124
+
125
+ ## Testing
126
+
127
+ Tests use Vitest and React Testing Library. Minimum coverage target: 80%.
128
+
129
+ ```bash
130
+ npm run test:coverage
131
+ ```
132
+
133
+ ## Storybook
134
+
135
+ Component documentation and visual testing:
136
+
137
+ ```bash
138
+ npm run storybook
139
+ npm run build-storybook
140
+ ```
141
+
142
+ ## Contribution Guide
143
+
144
+ 1. Fork and clone the repository
145
+ 2. Create a feature branch from `develop`
146
+ 3. Follow existing patterns: compose Ant Design components, export props types, and use tokens
147
+ 4. Add tests and Storybook stories for every public component
148
+ 5. Ensure `npm run lint`, `npm run typecheck`, and `npm run test` pass
149
+ 6. Open a pull request with a clear description
150
+
151
+ ### Code standards
152
+
153
+ - TypeScript strict mode, no `any`
154
+ - Accessibility first (ARIA, keyboard navigation)
155
+ - No business logic in UI components
156
+ - No hardcoded design values
157
+
158
+ ## Migration from the MUI-based API
159
+
160
+ This release changes component props to their Ant Design equivalents:
161
+
162
+ - `TdButton`: use `type="primary"` and `htmlType="submit"` instead of MUI variants/native `type`.
163
+ - `TdInput`, `TdSelect`, `TdAutocomplete`, and `TdDatePicker`: use `status="error"` and `help`.
164
+ - `TdDatePicker`: values and callbacks use Day.js objects.
165
+ - `TdModal`: use `onCancel`, `footer`, `closable`, `keyboard`, and `maskClosable`.
166
+ - `TdThemeProvider.themeOptions`: accepts Ant Design `ThemeConfig`.
167
+
168
+ `TdDataGrid` continues to use AG Grid; only its surrounding controls use Ant Design.
169
+
170
+ ## CI/CD (GitLab)
171
+
172
+ This repository uses `.gitlab-ci.yml` for a **Node.js library pipeline** (lint, test, build).
173
+
174
+ **Important:** Disable GitLab Auto DevOps in your project:
175
+
176
+ `Settings → General → Auto DevOps → Disable Auto DevOps`
177
+
178
+ Auto DevOps uses Heroku buildpacks and tries to build a Docker web app. That is incorrect for this npm package and causes errors like:
179
+
180
+ - `invalid tag "/main:..."` (empty container registry path)
181
+ - Node.js download timeouts on Heroku buildpack
182
+ - Very slow builds (~5 minutes)
183
+
184
+ The included pipeline uses `node:22` directly and typically finishes in 2–3 minutes with npm cache.
185
+
186
+ Publish to Nexus (`npm-hosted-tax`) automatically when CI pushes a version tag (see **Release Process** below). Consumers install from the `moaadian-npm` group.
187
+
188
+ ## Release Process
189
+
190
+ This project follows [Semantic Versioning](https://semver.org/).
191
+
192
+ On every successful merge to `main`, GitLab CI automatically:
193
+
194
+ 1. Finds the latest `v*` tag (e.g. `v0.2.0`)
195
+ 2. Bumps the **patch** version (`v0.2.1`)
196
+ 3. Updates `package.json` and `package-lock.json`
197
+ 4. Creates and pushes the new tag
198
+ 5. Publishes to `https://repo.mohaymen.ir/repository/npm-hosted-tax/`
199
+
200
+ ### One-time CI setup
201
+
202
+ Add a **Project Access Token** (Settings → Access tokens) with `write_repository` scope, then add it as a masked CI/CD variable:
203
+
204
+ | Variable | Value |
205
+ | --------------- | ------------------------ |
206
+ | `CI_PUSH_TOKEN` | `<project access token>` |
207
+
208
+ Without `CI_PUSH_TOKEN`, the `release` job cannot push tags.
209
+
210
+ Manual release (optional):
211
+
212
+ ```bash
213
+ git tag v0.2.0
214
+ git push origin v0.2.0
215
+ ```
216
+
217
+ ## License
218
+
219
+ MIT
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const c=require("react/jsx-runtime"),x=require("antd"),O=require("ag-grid-community"),fe=require("ag-grid-react"),n=require("react"),w=require("./spacing-BkZfHpT0.cjs"),ce=require("react-dom/client");require("ag-grid-community/styles/ag-grid.css");require("ag-grid-community/styles/ag-theme-alpine.css");function V(e,t){return e?.some(a=>a.rowId===t.row.id&&a.field===t.field)??!1}function ge(e,t){return!(e.editableRowIds!==void 0&&!e.editableRowIds.includes(t.id)||e.isRowEditable&&!e.isRowEditable(t))}function be(e,t){return e.editable===!1?!1:typeof e.editable=="function"?e.editable(t):e.editable===!0}function Ce(e,t,a){return a.isCellEditable?a.isCellEditable(t):a.editableCells!==void 0&&!V(a.editableCells,t)||!ge(a,t.row)?!1:e.editable!==void 0?be(e,t):V(a.editableCells,t)?!0:a.defaultEditable}function K(e,t){return t.defaultEditable||t.editableRowIds!==void 0||t.isRowEditable!==void 0||t.editableCells!==void 0||t.isCellEditable!==void 0?!0:e.some(a=>a.editable===!0||typeof a.editable=="function")}function he(e,t){return K([e],t)?a=>{if(!a.data)return!1;const o={row:a.data,field:e.field,value:a.data[e.field]};return Ce(e,o,t)}:!1}function pe(e){return e==null?"":typeof e=="string"||typeof e=="number"||typeof e=="boolean"?String(e).replace(/<[^>]*>/g,""):""}const me="__td_row_actions";function ye(e){return e?"agTextColumnFilter":!1}function y(e){return pe(e)}class Ee{root=null;eGui;init(t){this.eGui=document.createElement("div"),this.eGui.className="td-datagrid-cell";const a=t.renderCell;if(!a||!t.data){this.eGui.textContent=y(t.value);return}const o=a({row:t.data,value:t.value,field:t.colDef?.field});if(typeof o=="string"||typeof o=="number"){this.eGui.textContent=y(o);return}if(n.isValidElement(o)){this.root=ce.createRoot(this.eGui),this.root.render(o);return}this.eGui.textContent=y(o)}getGui(){return this.eGui}refresh(t){return this.destroy(),this.init(t),!0}destroy(){this.root&&(this.root.unmount(),this.root=null)}}class Se{root=null;eGui;init(t){this.eGui=document.createElement("div"),this.eGui.className="td-datagrid-actions";const a=t.data,o=t.rowActions??[];if(!a)return;const l=o.filter(s=>!s.hidden?.(a));l.length!==0&&(this.eGui.style.display="flex",this.eGui.style.gap="8px",l.forEach(s=>{const d=document.createElement("button");d.type="button",d.textContent=s.label,d.disabled=s.disabled?.(a)??!1,d.className="td-datagrid-action-button",d.addEventListener("click",h=>{h.stopPropagation(),t.onActionClick?.(s.id,a),s.onClick(a)}),this.eGui.appendChild(d)}))}getGui(){return this.eGui}refresh(){return!1}destroy(){this.root&&(this.root.unmount(),this.root=null)}}function ve(e,t,a={defaultEditable:!1}){const o=e.filter(l=>!l.hidden).map(l=>{const s={field:l.field,headerName:l.headerName,width:l.width,minWidth:l.minWidth,flex:l.flex,sortable:l.sortable??!0,filter:ye(l.filterable),editable:he(l,a),valueFormatter:l.valueFormatter?d=>l.valueFormatter(d.value,d.data):d=>y(d.value)};return l.renderCell&&(s.cellRenderer=Ee,s.cellRendererParams={renderCell:l.renderCell}),s});return t&&t.length>0&&o.push({field:me,headerName:"",sortable:!1,filter:!1,width:Math.max(120,t.length*80),pinned:"right",cellRenderer:Se,cellRendererParams:{rowActions:t}}),o}O.ModuleRegistry.registerModules([O.AllCommunityModule]);const U=20,Ge=[10,20,25,50,100],Re="ag-theme-alpine";function xe(e,t){return e===!0?{enabled:!0,model:{page:0,pageSize:t??U}}:e&&typeof e=="object"?{enabled:!0,model:e}:{enabled:!1}}function we({columns:e,rows:t,loading:a=!1,height:o=400,selectable:l,checkboxSelection:s=!1,selectedRowIds:d,onSelectionChange:h,onRowSelect:N,onRowClick:T,pagination:B,pageSize:k,onPaginationChange:E,rowCount:Te,serverSidePagination:ke=!1,sortModel:S,onSortChange:p,filterModel:Pe,onFilterChange:_e,search:De,export:C,persistence:u,permissions:v,rowActions:P,editable:_=!1,editableRowIds:D,isRowEditable:A,editableCells:F,isCellEditable:I,editTrigger:W="doubleClick",onCellValueChanged:M,themeClassName:J=Re,className:Z,style:H,emptyMessage:$="No rows to display",error:Q=!1,errorMessage:X,"aria-label":j="Data grid"}){const f=n.useRef(null),L=l??s,m=n.useMemo(()=>({defaultEditable:_||(v?.canEdit??!1),editableRowIds:D,isRowEditable:A,editableCells:F,isCellEditable:I}),[_,v?.canEdit,D,A,F,I]),Y=n.useMemo(()=>K(e,m),[e,m]),g=xe(B,k),ee=C?.enabled&&(v?.canExport??!0),te=n.useMemo(()=>ve(e,P,m),[e,P,m]),ie=n.useMemo(()=>({resizable:!0,sortable:!0,filter:!1,editable:!1}),[]),q=n.useCallback(i=>{if(!(!u?.enabled||!u.storageKey))try{const r=localStorage.getItem(u.storageKey);r&&i.applyColumnState({state:JSON.parse(r),applyOrder:!0})}catch{}},[u]),z=n.useCallback(i=>{if(!u?.enabled||!u.storageKey)return;const r=i.getColumnState();localStorage.setItem(u.storageKey,JSON.stringify(r))},[u]),ae=n.useCallback(i=>{f.current=i.api,q(i.api),g.model&&i.api.paginationGoToPage(g.model.page)},[g.model,q]),le=n.useCallback(()=>{const i=f.current;if(!i)return;const r=i.getSelectedRows(),R=r.map(b=>b.id);h?.(R),N?.(r)},[h,N]),re=n.useCallback(()=>{const i=f.current;!i||!E||E({page:i.paginationGetCurrentPage(),pageSize:i.paginationGetPageSize()})},[E]),ne=n.useCallback(()=>{const i=f.current;if(!i||!p)return;const R=i.getColumnState().filter(b=>b.sort).map(b=>({field:b.colId,sort:b.sort==="desc"?"desc":"asc"}));p(R)},[p]),G=n.useCallback(()=>{const i=f.current;i&&z(i)},[z]),oe=n.useCallback(i=>{!i.data||!i.colDef.field||M?.({row:i.data,field:i.colDef.field,oldValue:i.oldValue,newValue:i.newValue})},[M]),de=n.useCallback(i=>{const r=f.current;if(r){if(i==="csv"){r.exportDataAsCsv({fileName:C?.fileName??"export"});return}r.exportDataAsCsv({fileName:C?.fileName??"export"})}},[C?.fileName]);if(n.useEffect(()=>{const i=f.current;!i||!d||i.forEachNode(r=>{r.data&&r.setSelected(d.includes(r.data.id))})},[d,t]),n.useEffect(()=>{const i=f.current;!i||!S||i.applyColumnState({state:S.map(r=>({colId:r.field,sort:r.sort})),defaultState:{sort:null}})},[S]),Q)return c.jsx("div",{"aria-label":j,style:{height:o,padding:w.TdSpacing.md},children:c.jsx(x.Alert,{type:"error",title:X??"Failed to load data"})});const se=C?.formats??["csv"],ue=[J,"td-datagrid",Z].filter(Boolean).join(" ");return c.jsxs("div",{"aria-label":j,style:{width:"100%"},children:[ee?c.jsx(x.Flex,{gap:w.TdSpacing.sm,style:{marginBottom:w.TdSpacing.sm},children:se.map(i=>c.jsxs(x.Button,{size:"small",variant:"outlined",onClick:()=>{de(i)},children:["Export ",i.toUpperCase()]},i))}):null,c.jsx("div",{className:ue,style:{height:o,width:"100%",...H},children:c.jsx(fe.AgGridReact,{rowData:t,columnDefs:te,defaultColDef:ie,loading:a,domLayout:"normal",getRowId:i=>String(i.data.id),rowSelection:L?{mode:"multiRow",checkboxes:!0,headerCheckbox:!0,enableClickSelection:!1}:void 0,onSelectionChanged:L?le:void 0,onRowClicked:T?i=>{i.data&&T(i.data)}:void 0,pagination:g.enabled,paginationPageSize:g.model?.pageSize??k??U,paginationPageSizeSelector:Ge,onPaginationChanged:g.enabled?re:void 0,suppressPaginationPanel:!1,onGridReady:ae,onSortChanged:p?ne:void 0,onColumnMoved:G,onColumnResized:G,onColumnVisible:G,singleClickEdit:W==="singleClick",stopEditingWhenCellsLoseFocus:!0,onCellValueChanged:Y?oe:void 0,overlayNoRowsTemplate:`<span>${$}</span>`,overlayLoadingTemplate:"<span>Loading...</span>"})})]})}const Ne=n.memo(we);exports.TdDataGrid=Ne;
2
+ //# sourceMappingURL=data-grid.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-grid.cjs","sources":["../src/components/TdDataGrid/TdDataGrid.edit.ts","../src/utils/sanitize.ts","../src/components/TdDataGrid/TdDataGrid.mapper.ts","../src/components/TdDataGrid/TdDataGrid.tsx"],"sourcesContent":["import type { EditableCallbackParams } from \"ag-grid-community\";\n\nimport type {\n TdDataGridCellContext,\n TdDataGridColumn,\n TdDataGridEditRules,\n TdDataGridRow,\n} from \"./TdDataGrid.types\";\n\nfunction isCellListed<T extends TdDataGridRow>(\n editableCells: TdDataGridEditRules<T>[\"editableCells\"],\n context: TdDataGridCellContext<T>,\n): boolean {\n return (\n editableCells?.some((cell) => cell.rowId === context.row.id && cell.field === context.field) ??\n false\n );\n}\n\nfunction passesRowRules<T extends TdDataGridRow>(rules: TdDataGridEditRules<T>, row: T): boolean {\n if (rules.editableRowIds !== undefined && !rules.editableRowIds.includes(row.id)) {\n return false;\n }\n\n if (rules.isRowEditable && !rules.isRowEditable(row)) {\n return false;\n }\n\n return true;\n}\n\nfunction passesColumnRules<T extends TdDataGridRow>(\n column: TdDataGridColumn<T>,\n context: TdDataGridCellContext<T>,\n): boolean {\n if (column.editable === false) {\n return false;\n }\n\n if (typeof column.editable === \"function\") {\n return column.editable(context);\n }\n\n if (column.editable === true) {\n return true;\n }\n\n return false;\n}\n\nexport function isCellEditableResolved<T extends TdDataGridRow>(\n column: TdDataGridColumn<T>,\n context: TdDataGridCellContext<T>,\n rules: TdDataGridEditRules<T>,\n): boolean {\n if (rules.isCellEditable) {\n return rules.isCellEditable(context);\n }\n\n if (rules.editableCells !== undefined && !isCellListed(rules.editableCells, context)) {\n return false;\n }\n\n if (!passesRowRules(rules, context.row)) {\n return false;\n }\n\n if (column.editable !== undefined) {\n return passesColumnRules(column, context);\n }\n\n if (isCellListed(rules.editableCells, context)) {\n return true;\n }\n\n return rules.defaultEditable;\n}\n\nexport function hasAnyEditingEnabled<T extends TdDataGridRow>(\n columns: TdDataGridColumn<T>[],\n rules: TdDataGridEditRules<T>,\n): boolean {\n if (\n rules.defaultEditable ||\n rules.editableRowIds !== undefined ||\n rules.isRowEditable !== undefined ||\n rules.editableCells !== undefined ||\n rules.isCellEditable !== undefined\n ) {\n return true;\n }\n\n return columns.some(\n (column) => column.editable === true || typeof column.editable === \"function\",\n );\n}\n\nexport function createCellEditableCallback<T extends TdDataGridRow>(\n column: TdDataGridColumn<T>,\n rules: TdDataGridEditRules<T>,\n): boolean | ((params: EditableCallbackParams<T>) => boolean) {\n if (!hasAnyEditingEnabled([column], rules)) {\n return false;\n }\n\n return (params: EditableCallbackParams<T>) => {\n if (!params.data) {\n return false;\n }\n\n const context: TdDataGridCellContext<T> = {\n row: params.data,\n field: column.field,\n value: params.data[column.field],\n };\n\n return isCellEditableResolved(column, context, rules);\n };\n}\n","/**\n * Strip HTML tags from a string value for safe grid cell display.\n */\nexport function sanitizeText(value: unknown): string {\n if (value === null || value === undefined) {\n return \"\";\n }\n\n if (typeof value === \"string\" || typeof value === \"number\" || typeof value === \"boolean\") {\n return String(value).replace(/<[^>]*>/g, \"\");\n }\n\n return \"\";\n}\n\n/**\n * Escape HTML entities so text can be rendered safely.\n */\nexport function escapeHtml(value: unknown): string {\n if (value === null || value === undefined) {\n return \"\";\n }\n\n if (typeof value !== \"string\" && typeof value !== \"number\" && typeof value !== \"boolean\") {\n return \"\";\n }\n\n const text = String(value);\n\n return text\n .replace(/&/g, \"&amp;\")\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\")\n .replace(/\"/g, \"&quot;\")\n .replace(/'/g, \"&#39;\");\n}\n","import type { ColDef, ICellRendererParams, ValueFormatterParams } from \"ag-grid-community\";\nimport { isValidElement } from \"react\";\nimport { createRoot, type Root } from \"react-dom/client\";\n\nimport { sanitizeText } from \"../../utils/sanitize\";\nimport { createCellEditableCallback } from \"./TdDataGrid.edit\";\nimport type {\n TdDataGridColumn,\n TdDataGridEditRules,\n TdDataGridRow,\n TdDataGridRowAction,\n} from \"./TdDataGrid.types\";\n\nconst ACTION_COLUMN_FIELD = \"__td_row_actions\";\n\n/** Maps filter operator to AG Grid text filter type */\nfunction mapFilterType(filterable?: boolean): boolean | string {\n return filterable ? \"agTextColumnFilter\" : false;\n}\n\n/** Safely stringify cell values for default rendering */\nfunction formatCellValue(value: unknown): string {\n return sanitizeText(value);\n}\n\nclass TdReactCellRenderer<T extends TdDataGridRow> {\n private root: Root | null = null;\n private eGui!: HTMLDivElement;\n\n init(params: ICellRendererParams<T> & { renderCell?: TdDataGridColumn<T>[\"renderCell\"] }) {\n this.eGui = document.createElement(\"div\");\n this.eGui.className = \"td-datagrid-cell\";\n\n const renderCell = params.renderCell;\n if (!renderCell || !params.data) {\n this.eGui.textContent = formatCellValue(params.value);\n return;\n }\n\n const content = renderCell({\n row: params.data,\n value: params.value,\n field: params.colDef?.field as keyof T & string,\n });\n\n if (typeof content === \"string\" || typeof content === \"number\") {\n this.eGui.textContent = formatCellValue(content);\n return;\n }\n\n if (isValidElement(content)) {\n this.root = createRoot(this.eGui);\n this.root.render(content);\n return;\n }\n\n this.eGui.textContent = formatCellValue(content);\n }\n\n getGui() {\n return this.eGui;\n }\n\n refresh(params: ICellRendererParams<T> & { renderCell?: TdDataGridColumn<T>[\"renderCell\"] }) {\n this.destroy();\n this.init(params);\n return true;\n }\n\n destroy() {\n if (this.root) {\n this.root.unmount();\n this.root = null;\n }\n }\n}\n\nclass TdRowActionsCellRenderer<T extends TdDataGridRow> {\n private root: Root | null = null;\n private eGui!: HTMLDivElement;\n\n init(\n params: ICellRendererParams<T> & {\n rowActions?: TdDataGridRowAction<T>[];\n onActionClick?: (actionId: string, row: T) => void;\n },\n ) {\n this.eGui = document.createElement(\"div\");\n this.eGui.className = \"td-datagrid-actions\";\n\n const row = params.data;\n const rowActions = params.rowActions ?? [];\n\n if (!row) {\n return;\n }\n\n const visibleActions = rowActions.filter((action) => !action.hidden?.(row));\n\n if (visibleActions.length === 0) {\n return;\n }\n\n this.eGui.style.display = \"flex\";\n this.eGui.style.gap = \"8px\";\n\n visibleActions.forEach((action) => {\n const button = document.createElement(\"button\");\n button.type = \"button\";\n button.textContent = action.label;\n button.disabled = action.disabled?.(row) ?? false;\n button.className = \"td-datagrid-action-button\";\n button.addEventListener(\"click\", (event) => {\n event.stopPropagation();\n params.onActionClick?.(action.id, row);\n action.onClick(row);\n });\n this.eGui.appendChild(button);\n });\n }\n\n getGui() {\n return this.eGui;\n }\n\n refresh() {\n return false;\n }\n\n destroy() {\n if (this.root) {\n this.root.unmount();\n this.root = null;\n }\n }\n}\n\nexport function mapColumnsToAgGrid<T extends TdDataGridRow>(\n columns: TdDataGridColumn<T>[],\n rowActions?: TdDataGridRowAction<T>[],\n editRules: TdDataGridEditRules<T> = { defaultEditable: false },\n): ColDef<T>[] {\n const mappedColumns: ColDef<T>[] = columns\n .filter((column) => !column.hidden)\n .map((column) => {\n const colDef: ColDef<T> = {\n field: column.field as ColDef<T>[\"field\"],\n headerName: column.headerName,\n width: column.width,\n minWidth: column.minWidth,\n flex: column.flex,\n sortable: column.sortable ?? true,\n filter: mapFilterType(column.filterable),\n editable: createCellEditableCallback(column, editRules),\n valueFormatter: column.valueFormatter\n ? (params: ValueFormatterParams<T>) => column.valueFormatter!(params.value, params.data!)\n : (params: ValueFormatterParams<T>) => formatCellValue(params.value),\n };\n\n if (column.renderCell) {\n colDef.cellRenderer = TdReactCellRenderer;\n colDef.cellRendererParams = { renderCell: column.renderCell };\n }\n\n return colDef;\n });\n\n if (rowActions && rowActions.length > 0) {\n mappedColumns.push({\n field: ACTION_COLUMN_FIELD as ColDef<T>[\"field\"],\n headerName: \"\",\n sortable: false,\n filter: false,\n width: Math.max(120, rowActions.length * 80),\n pinned: \"right\",\n cellRenderer: TdRowActionsCellRenderer,\n cellRendererParams: { rowActions },\n });\n }\n\n return mappedColumns;\n}\n\nexport function getActionColumnField(): string {\n return ACTION_COLUMN_FIELD;\n}\n","import { Alert, Button, Flex } from \"antd\";\nimport {\n AllCommunityModule,\n ModuleRegistry,\n type CellValueChangedEvent,\n type ColumnState,\n type GridApi,\n} from \"ag-grid-community\";\nimport { AgGridReact } from \"ag-grid-react\";\nimport { memo, useCallback, useEffect, useMemo, useRef } from \"react\";\n\nimport { TdSpacing } from \"../../tokens/spacing\";\nimport { hasAnyEditingEnabled } from \"./TdDataGrid.edit\";\nimport { mapColumnsToAgGrid } from \"./TdDataGrid.mapper\";\nimport type {\n TdDataGridEditRules,\n TdDataGridExportFormat,\n TdDataGridPaginationModel,\n TdDataGridProps,\n TdDataGridRow,\n TdDataGridSortModel,\n TdDataGridThemeClassName,\n} from \"./TdDataGrid.types\";\n\nimport \"ag-grid-community/styles/ag-grid.css\";\nimport \"ag-grid-community/styles/ag-theme-alpine.css\";\n\nModuleRegistry.registerModules([AllCommunityModule]);\n\nconst DEFAULT_PAGE_SIZE = 20;\nconst PAGE_SIZE_OPTIONS = [10, 20, 25, 50, 100];\nconst DEFAULT_THEME_CLASS: TdDataGridThemeClassName = \"ag-theme-alpine\";\n\nfunction resolvePaginationConfig(\n pagination: TdDataGridProps[\"pagination\"],\n pageSize?: number,\n): { enabled: boolean; model?: TdDataGridPaginationModel } {\n if (pagination === true) {\n return {\n enabled: true,\n model: { page: 0, pageSize: pageSize ?? DEFAULT_PAGE_SIZE },\n };\n }\n\n if (pagination && typeof pagination === \"object\") {\n return { enabled: true, model: pagination };\n }\n\n return { enabled: false };\n}\n\nfunction TdDataGridInner<T extends TdDataGridRow>({\n columns,\n rows,\n loading = false,\n height = 400,\n selectable,\n checkboxSelection = false,\n selectedRowIds,\n onSelectionChange,\n onRowSelect,\n onRowClick,\n pagination,\n pageSize,\n onPaginationChange,\n rowCount: _rowCount,\n serverSidePagination: _serverSidePagination = false,\n sortModel,\n onSortChange,\n filterModel: _filterModel,\n onFilterChange: _onFilterChange,\n search: _search,\n export: exportConfig,\n persistence,\n permissions,\n rowActions,\n editable = false,\n editableRowIds,\n isRowEditable,\n editableCells,\n isCellEditable,\n editTrigger = \"doubleClick\",\n onCellValueChanged,\n themeClassName = DEFAULT_THEME_CLASS,\n className,\n style,\n emptyMessage = \"No rows to display\",\n error = false,\n errorMessage,\n \"aria-label\": ariaLabel = \"Data grid\",\n}: TdDataGridProps<T>) {\n const gridApiRef = useRef<GridApi<T> | null>(null);\n const isSelectionEnabled = selectable ?? checkboxSelection;\n const editRules = useMemo<TdDataGridEditRules<T>>(\n () => ({\n defaultEditable: editable || (permissions?.canEdit ?? false),\n editableRowIds,\n isRowEditable,\n editableCells,\n isCellEditable,\n }),\n [editable, permissions?.canEdit, editableRowIds, isRowEditable, editableCells, isCellEditable],\n );\n const isEditingEnabled = useMemo(\n () => hasAnyEditingEnabled(columns, editRules),\n [columns, editRules],\n );\n const paginationConfig = resolvePaginationConfig(pagination, pageSize);\n const canExport = exportConfig?.enabled && (permissions?.canExport ?? true);\n\n const gridColumns = useMemo(\n () => mapColumnsToAgGrid(columns, rowActions, editRules),\n [columns, rowActions, editRules],\n );\n\n const defaultColDef = useMemo(\n () => ({\n resizable: true,\n sortable: true,\n filter: false,\n editable: false,\n }),\n [],\n );\n\n const restoreColumnState = useCallback(\n (api: GridApi<T>) => {\n if (!persistence?.enabled || !persistence.storageKey) {\n return;\n }\n\n try {\n const stored = localStorage.getItem(persistence.storageKey);\n if (stored) {\n api.applyColumnState({ state: JSON.parse(stored) as ColumnState[], applyOrder: true });\n }\n } catch {\n // Ignore invalid persisted state\n }\n },\n [persistence],\n );\n\n const persistColumnState = useCallback(\n (api: GridApi<T>) => {\n if (!persistence?.enabled || !persistence.storageKey) {\n return;\n }\n\n const state = api.getColumnState();\n localStorage.setItem(persistence.storageKey, JSON.stringify(state));\n },\n [persistence],\n );\n\n const handleGridReady = useCallback(\n (params: { api: GridApi<T> }) => {\n gridApiRef.current = params.api;\n restoreColumnState(params.api);\n\n if (paginationConfig.model) {\n params.api.paginationGoToPage(paginationConfig.model.page);\n }\n },\n [paginationConfig.model, restoreColumnState],\n );\n\n const handleSelectionChanged = useCallback(() => {\n const api = gridApiRef.current;\n if (!api) {\n return;\n }\n\n const selectedRows = api.getSelectedRows();\n const selectedIds = selectedRows.map((row) => row.id);\n\n onSelectionChange?.(selectedIds);\n onRowSelect?.(selectedRows);\n }, [onSelectionChange, onRowSelect]);\n\n const handlePaginationChanged = useCallback(() => {\n const api = gridApiRef.current;\n if (!api || !onPaginationChange) {\n return;\n }\n\n onPaginationChange({\n page: api.paginationGetCurrentPage(),\n pageSize: api.paginationGetPageSize(),\n });\n }, [onPaginationChange]);\n\n const handleSortChanged = useCallback(() => {\n const api = gridApiRef.current;\n if (!api || !onSortChange) {\n return;\n }\n\n const columnState = api.getColumnState();\n const nextSortModel: TdDataGridSortModel[] = columnState\n .filter((column) => column.sort)\n .map((column) => ({\n field: column.colId,\n sort: column.sort === \"desc\" ? \"desc\" : \"asc\",\n }));\n\n onSortChange(nextSortModel);\n }, [onSortChange]);\n\n const handleColumnChanged = useCallback(() => {\n const api = gridApiRef.current;\n if (api) {\n persistColumnState(api);\n }\n }, [persistColumnState]);\n\n const handleCellValueChanged = useCallback(\n (event: CellValueChangedEvent<T>) => {\n if (!event.data || !event.colDef.field) {\n return;\n }\n\n onCellValueChanged?.({\n row: event.data,\n field: event.colDef.field as keyof T & string,\n oldValue: event.oldValue,\n newValue: event.newValue,\n });\n },\n [onCellValueChanged],\n );\n\n const handleExport = useCallback(\n (format: TdDataGridExportFormat) => {\n const api = gridApiRef.current;\n if (!api) {\n return;\n }\n\n if (format === \"csv\") {\n api.exportDataAsCsv({\n fileName: exportConfig?.fileName ?? \"export\",\n });\n return;\n }\n\n // Excel export requires Enterprise; abstracted for future migration\n api.exportDataAsCsv({\n fileName: exportConfig?.fileName ?? \"export\",\n });\n },\n [exportConfig?.fileName],\n );\n\n useEffect(() => {\n const api = gridApiRef.current;\n if (!api || !selectedRowIds) {\n return;\n }\n\n api.forEachNode((node) => {\n if (node.data) {\n node.setSelected(selectedRowIds.includes(node.data.id));\n }\n });\n }, [selectedRowIds, rows]);\n\n useEffect(() => {\n const api = gridApiRef.current;\n if (!api || !sortModel) {\n return;\n }\n\n api.applyColumnState({\n state: sortModel.map((item) => ({\n colId: item.field,\n sort: item.sort,\n })),\n defaultState: { sort: null },\n });\n }, [sortModel]);\n\n if (error) {\n return (\n <div aria-label={ariaLabel} style={{ height, padding: TdSpacing.md }}>\n <Alert type=\"error\" title={errorMessage ?? \"Failed to load data\"} />\n </div>\n );\n }\n\n const exportFormats = exportConfig?.formats ?? [\"csv\"];\n const gridClassName = [themeClassName, \"td-datagrid\", className].filter(Boolean).join(\" \");\n\n return (\n <div aria-label={ariaLabel} style={{ width: \"100%\" }}>\n {canExport ? (\n <Flex gap={TdSpacing.sm} style={{ marginBottom: TdSpacing.sm }}>\n {exportFormats.map((format) => (\n <Button\n key={format}\n size=\"small\"\n variant=\"outlined\"\n onClick={() => {\n handleExport(format);\n }}\n >\n Export {format.toUpperCase()}\n </Button>\n ))}\n </Flex>\n ) : null}\n\n <div className={gridClassName} style={{ height, width: \"100%\", ...style }}>\n <AgGridReact<T>\n rowData={rows}\n columnDefs={gridColumns}\n defaultColDef={defaultColDef}\n loading={loading}\n domLayout=\"normal\"\n getRowId={(params) => String(params.data.id)}\n rowSelection={\n isSelectionEnabled\n ? {\n mode: \"multiRow\",\n checkboxes: true,\n headerCheckbox: true,\n enableClickSelection: false,\n }\n : undefined\n }\n onSelectionChanged={isSelectionEnabled ? handleSelectionChanged : undefined}\n onRowClicked={\n onRowClick\n ? (event) => {\n if (event.data) {\n onRowClick(event.data);\n }\n }\n : undefined\n }\n pagination={paginationConfig.enabled}\n paginationPageSize={paginationConfig.model?.pageSize ?? pageSize ?? DEFAULT_PAGE_SIZE}\n paginationPageSizeSelector={PAGE_SIZE_OPTIONS}\n onPaginationChanged={paginationConfig.enabled ? handlePaginationChanged : undefined}\n suppressPaginationPanel={false}\n onGridReady={handleGridReady}\n onSortChanged={onSortChange ? handleSortChanged : undefined}\n onColumnMoved={handleColumnChanged}\n onColumnResized={handleColumnChanged}\n onColumnVisible={handleColumnChanged}\n singleClickEdit={editTrigger === \"singleClick\"}\n stopEditingWhenCellsLoseFocus\n onCellValueChanged={isEditingEnabled ? handleCellValueChanged : undefined}\n overlayNoRowsTemplate={`<span>${emptyMessage}</span>`}\n overlayLoadingTemplate=\"<span>Loading...</span>\"\n />\n </div>\n </div>\n );\n}\n\nexport const TdDataGrid = memo(TdDataGridInner) as typeof TdDataGridInner;\n\nexport { DEFAULT_THEME_CLASS as TD_DATAGRID_DEFAULT_THEME_CLASS };\n"],"names":["isCellListed","editableCells","context","cell","passesRowRules","rules","row","passesColumnRules","column","isCellEditableResolved","hasAnyEditingEnabled","columns","createCellEditableCallback","params","sanitizeText","value","ACTION_COLUMN_FIELD","mapFilterType","filterable","formatCellValue","TdReactCellRenderer","renderCell","content","isValidElement","createRoot","TdRowActionsCellRenderer","rowActions","visibleActions","action","button","event","mapColumnsToAgGrid","editRules","mappedColumns","colDef","ModuleRegistry","AllCommunityModule","DEFAULT_PAGE_SIZE","PAGE_SIZE_OPTIONS","DEFAULT_THEME_CLASS","resolvePaginationConfig","pagination","pageSize","TdDataGridInner","rows","loading","height","selectable","checkboxSelection","selectedRowIds","onSelectionChange","onRowSelect","onRowClick","onPaginationChange","_rowCount","_serverSidePagination","sortModel","onSortChange","_filterModel","_onFilterChange","_search","exportConfig","persistence","permissions","editable","editableRowIds","isRowEditable","isCellEditable","editTrigger","onCellValueChanged","themeClassName","className","style","emptyMessage","error","errorMessage","ariaLabel","gridApiRef","useRef","isSelectionEnabled","useMemo","isEditingEnabled","paginationConfig","canExport","gridColumns","defaultColDef","restoreColumnState","useCallback","api","stored","persistColumnState","state","handleGridReady","handleSelectionChanged","selectedRows","selectedIds","handlePaginationChanged","handleSortChanged","nextSortModel","handleColumnChanged","handleCellValueChanged","handleExport","format","useEffect","node","item","TdSpacing","Alert","exportFormats","gridClassName","jsxs","jsx","Flex","Button","AgGridReact","TdDataGrid","memo"],"mappings":"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"}
@@ -0,0 +1,218 @@
1
+ import { JSX } from 'react';
2
+ import { ReactNode } from 'react';
3
+
4
+ export declare const TdDataGrid: typeof TdDataGridInner;
5
+
6
+ /** Context passed to cell/row editability callbacks */
7
+ export declare interface TdDataGridCellContext<T extends TdDataGridRow = TdDataGridRow> {
8
+ row: T;
9
+ field: keyof T & string;
10
+ value: unknown;
11
+ }
12
+
13
+ export declare interface TdDataGridCellEditEvent<T extends TdDataGridRow = TdDataGridRow> {
14
+ row: T;
15
+ field: keyof T & string;
16
+ oldValue: unknown;
17
+ newValue: unknown;
18
+ }
19
+
20
+ export declare interface TdDataGridColumn<T extends TdDataGridRow = TdDataGridRow> {
21
+ /** Unique column identifier */
22
+ field: keyof T & string;
23
+ /** Column header label */
24
+ headerName: string;
25
+ /** Column width in pixels */
26
+ width?: number;
27
+ /** Minimum column width */
28
+ minWidth?: number;
29
+ /** Flex grow factor */
30
+ flex?: number;
31
+ /** Enable sorting for this column */
32
+ sortable?: boolean;
33
+ /** Enable filtering for this column */
34
+ filterable?: boolean;
35
+ /** Enable inline cell editing for this column */
36
+ editable?: boolean | ((params: TdDataGridCellContext<T>) => boolean);
37
+ /** Hide column */
38
+ hidden?: boolean;
39
+ /** Custom cell renderer */
40
+ renderCell?: (params: TdDataGridRenderCellParams<T>) => ReactNode;
41
+ /** Value formatter */
42
+ valueFormatter?: (value: unknown, row: T) => string;
43
+ }
44
+
45
+ /** Explicit editable cell (row + field pair) */
46
+ export declare interface TdDataGridEditableCell<T extends TdDataGridRow = TdDataGridRow> {
47
+ rowId: string | number;
48
+ field: keyof T & string;
49
+ }
50
+
51
+ export declare type TdDataGridEditTrigger = "singleClick" | "doubleClick";
52
+
53
+ export declare interface TdDataGridExportConfig {
54
+ /** Enable export capability */
55
+ enabled?: boolean;
56
+ /** Export formats */
57
+ formats?: TdDataGridExportFormat[];
58
+ /** Default export file name (without extension) */
59
+ fileName?: string;
60
+ }
61
+
62
+ export declare type TdDataGridExportFormat = "csv" | "xlsx";
63
+
64
+ export declare interface TdDataGridFilterModel {
65
+ field: string;
66
+ operator: TdDataGridFilterOperator;
67
+ value: unknown;
68
+ }
69
+
70
+ export declare type TdDataGridFilterOperator = "equals" | "contains" | "startsWith" | "endsWith" | "greaterThan" | "lessThan";
71
+
72
+ declare function TdDataGridInner<T extends TdDataGridRow>({ columns, rows, loading, height, selectable, checkboxSelection, selectedRowIds, onSelectionChange, onRowSelect, onRowClick, pagination, pageSize, onPaginationChange, rowCount: _rowCount, serverSidePagination: _serverSidePagination, sortModel, onSortChange, filterModel: _filterModel, onFilterChange: _onFilterChange, search: _search, export: exportConfig, persistence, permissions, rowActions, editable, editableRowIds, isRowEditable, editableCells, isCellEditable, editTrigger, onCellValueChanged, themeClassName, className, style, emptyMessage, error, errorMessage, "aria-label": ariaLabel, }: TdDataGridProps<T>): JSX.Element;
73
+
74
+ export declare interface TdDataGridPaginationModel {
75
+ page: number;
76
+ pageSize: number;
77
+ }
78
+
79
+ export declare interface TdDataGridPermissionsConfig {
80
+ /** Can user edit rows */
81
+ canEdit?: boolean;
82
+ /** Can user delete rows */
83
+ canDelete?: boolean;
84
+ /** Can user export data */
85
+ canExport?: boolean;
86
+ }
87
+
88
+ export declare interface TdDataGridPersistenceConfig {
89
+ /** Storage key for column state persistence */
90
+ storageKey?: string;
91
+ /** Enable state persistence */
92
+ enabled?: boolean;
93
+ }
94
+
95
+ export declare interface TdDataGridProps<T extends TdDataGridRow = TdDataGridRow> {
96
+ /** Column definitions */
97
+ columns: TdDataGridColumn<T>[];
98
+ /** Row data */
99
+ rows: T[];
100
+ /** Loading state */
101
+ loading?: boolean;
102
+ /** Grid height */
103
+ height?: number | string;
104
+ /** Enable row selection (alias: checkboxSelection) */
105
+ selectable?: boolean;
106
+ /** @deprecated Use selectable */
107
+ checkboxSelection?: boolean;
108
+ /** Selected row IDs */
109
+ selectedRowIds?: (string | number)[];
110
+ /** Selection change handler (returns selected IDs) */
111
+ onSelectionChange?: (selectedIds: (string | number)[]) => void;
112
+ /** Row selection handler (returns selected row objects) */
113
+ onRowSelect?: (selectedRows: T[]) => void;
114
+ /** Row click handler */
115
+ onRowClick?: (row: T) => void;
116
+ /** Enable pagination or provide controlled pagination model */
117
+ pagination?: boolean | TdDataGridPaginationModel;
118
+ /** Default or controlled page size when pagination is enabled */
119
+ pageSize?: number;
120
+ /** Pagination change handler */
121
+ onPaginationChange?: (model: TdDataGridPaginationModel) => void;
122
+ /** Total row count for server-side pagination */
123
+ rowCount?: number;
124
+ /** Server-side pagination mode */
125
+ serverSidePagination?: boolean;
126
+ /** Server-side mode flags (future-ready) */
127
+ serverSideMode?: TdDataGridServerSideMode[];
128
+ /** Sort model */
129
+ sortModel?: TdDataGridSortModel[];
130
+ /** Sort change handler */
131
+ onSortChange?: (model: TdDataGridSortModel[]) => void;
132
+ /** Filter model */
133
+ filterModel?: TdDataGridFilterModel[];
134
+ /** Filter change handler */
135
+ onFilterChange?: (model: TdDataGridFilterModel[]) => void;
136
+ /** Global search configuration */
137
+ search?: TdDataGridSearchConfig;
138
+ /** Export configuration */
139
+ export?: TdDataGridExportConfig;
140
+ /** State persistence configuration */
141
+ persistence?: TdDataGridPersistenceConfig;
142
+ /** Permission configuration */
143
+ permissions?: TdDataGridPermissionsConfig;
144
+ /** Row-level actions */
145
+ rowActions?: TdDataGridRowAction<T>[];
146
+ /** Enable inline cell editing (can be overridden per column, row, or cell) */
147
+ editable?: boolean;
148
+ /** Only these row IDs are editable */
149
+ editableRowIds?: (string | number)[];
150
+ /** Dynamic row editability check */
151
+ isRowEditable?: (row: T) => boolean;
152
+ /** Whitelist of editable cells (row + field pairs) */
153
+ editableCells?: TdDataGridEditableCell<T>[];
154
+ /** Dynamic per-cell editability check (highest priority) */
155
+ isCellEditable?: (params: TdDataGridCellContext<T>) => boolean;
156
+ /** How editing is triggered */
157
+ editTrigger?: TdDataGridEditTrigger;
158
+ /** Cell value change handler */
159
+ onCellValueChanged?: (event: TdDataGridCellEditEvent<T>) => void;
160
+ /** AG Grid theme class (default: ag-theme-alpine) */
161
+ themeClassName?: TdDataGridThemeClassName | (string & {});
162
+ /** Additional CSS class for the grid container */
163
+ className?: string;
164
+ /** Inline styles for the grid container */
165
+ style?: React.CSSProperties;
166
+ /** Empty state message */
167
+ emptyMessage?: string;
168
+ /** Error state */
169
+ error?: boolean;
170
+ /** Error message */
171
+ errorMessage?: string;
172
+ /** Accessible label */
173
+ "aria-label"?: string;
174
+ }
175
+
176
+ export declare interface TdDataGridRenderCellParams<T extends TdDataGridRow> {
177
+ row: T;
178
+ value: unknown;
179
+ field: keyof T & string;
180
+ }
181
+
182
+ export declare interface TdDataGridRow {
183
+ id: string | number;
184
+ [key: string]: unknown;
185
+ }
186
+
187
+ export declare interface TdDataGridRowAction<T extends TdDataGridRow> {
188
+ id: string;
189
+ label: string;
190
+ icon?: ReactNode;
191
+ onClick: (row: T) => void;
192
+ disabled?: (row: T) => boolean;
193
+ hidden?: (row: T) => boolean;
194
+ }
195
+
196
+ export declare interface TdDataGridSearchConfig {
197
+ /** Enable global search */
198
+ enabled?: boolean;
199
+ /** Search placeholder */
200
+ placeholder?: string;
201
+ /** Controlled search value */
202
+ value?: string;
203
+ /** Search change handler */
204
+ onChange?: (value: string) => void;
205
+ }
206
+
207
+ /** Server-side data fetching mode (future-ready abstraction) */
208
+ export declare type TdDataGridServerSideMode = "pagination" | "sort" | "filter" | "full";
209
+
210
+ export declare interface TdDataGridSortModel {
211
+ field: string;
212
+ sort: "asc" | "desc";
213
+ }
214
+
215
+ /** Built-in AG Grid theme class names */
216
+ export declare type TdDataGridThemeClassName = "ag-theme-alpine" | "ag-theme-balham" | "ag-theme-quartz" | "ag-theme-material";
217
+
218
+ export { }