apex-grid 1.1.0 → 3.0.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.
Files changed (231) hide show
  1. package/LICENSE +76 -5
  2. package/README.md +523 -10
  3. package/components/cell.d.ts +39 -0
  4. package/components/cell.js +334 -5
  5. package/components/cell.js.map +1 -1
  6. package/components/filter-row.d.ts +7 -5
  7. package/components/filter-row.js +151 -68
  8. package/components/filter-row.js.map +1 -1
  9. package/components/grid.d.ts +955 -4
  10. package/components/grid.js +412 -40
  11. package/components/grid.js.map +1 -1
  12. package/components/header-row.d.ts +21 -1
  13. package/components/header-row.js +140 -7
  14. package/components/header-row.js.map +1 -1
  15. package/components/header.d.ts +7 -0
  16. package/components/header.js +151 -31
  17. package/components/header.js.map +1 -1
  18. package/components/paginator.d.ts +56 -0
  19. package/components/paginator.js +148 -0
  20. package/components/paginator.js.map +1 -0
  21. package/components/row.d.ts +21 -2
  22. package/components/row.js +185 -10
  23. package/components/row.js.map +1 -1
  24. package/components/toolbar.d.ts +60 -0
  25. package/components/toolbar.js +259 -0
  26. package/components/toolbar.js.map +1 -0
  27. package/components/virtualizer.js +1 -1
  28. package/components/virtualizer.js.map +1 -1
  29. package/controllers/data-operation.d.ts +14 -0
  30. package/controllers/data-operation.js +19 -2
  31. package/controllers/data-operation.js.map +1 -1
  32. package/controllers/dom.d.ts +37 -1
  33. package/controllers/dom.js +176 -9
  34. package/controllers/dom.js.map +1 -1
  35. package/controllers/editing.d.ts +130 -0
  36. package/controllers/editing.js +197 -0
  37. package/controllers/editing.js.map +1 -0
  38. package/controllers/expansion.d.ts +68 -0
  39. package/controllers/expansion.js +126 -0
  40. package/controllers/expansion.js.map +1 -0
  41. package/controllers/navigation.d.ts +17 -6
  42. package/controllers/navigation.js +24 -8
  43. package/controllers/navigation.js.map +1 -1
  44. package/controllers/pagination.d.ts +102 -0
  45. package/controllers/pagination.js +106 -0
  46. package/controllers/pagination.js.map +1 -0
  47. package/controllers/reorder.d.ts +78 -0
  48. package/controllers/reorder.js +124 -0
  49. package/controllers/reorder.js.map +1 -0
  50. package/controllers/selection.d.ts +109 -0
  51. package/controllers/selection.js +168 -0
  52. package/controllers/selection.js.map +1 -0
  53. package/controllers/sort.js +28 -0
  54. package/controllers/sort.js.map +1 -1
  55. package/controllers/state.d.ts +47 -1
  56. package/controllers/state.js +48 -1
  57. package/controllers/state.js.map +1 -1
  58. package/controllers/tree.d.ts +87 -0
  59. package/controllers/tree.js +0 -0
  60. package/controllers/tree.js.map +1 -0
  61. package/custom-elements.json +6491 -1355
  62. package/define.js.map +1 -1
  63. package/docs/assets/hierarchy.js +1 -1
  64. package/docs/assets/highlight.css +77 -14
  65. package/docs/assets/icons.js +1 -1
  66. package/docs/assets/icons.svg +1 -1
  67. package/docs/assets/main.js +4 -4
  68. package/docs/assets/navigation.js +1 -1
  69. package/docs/assets/search.js +1 -1
  70. package/docs/assets/style.css +3 -3
  71. package/docs/classes/ApexGrid.html +320 -24
  72. package/docs/functions/setup.html +16 -0
  73. package/docs/hierarchy.html +1 -1
  74. package/docs/index.html +543 -9
  75. package/docs/interfaces/ApexCellValueChangedEvent.html +11 -0
  76. package/docs/interfaces/ApexCellValueChangingEvent.html +13 -0
  77. package/docs/interfaces/ApexColumnMovedEvent.html +8 -0
  78. package/docs/interfaces/ApexColumnMovingEvent.html +11 -0
  79. package/docs/interfaces/ApexColumnPinnedEvent.html +6 -0
  80. package/docs/interfaces/ApexColumnPinningEvent.html +8 -0
  81. package/docs/interfaces/ApexDetailContext.html +8 -0
  82. package/docs/interfaces/ApexFilteredEvent.html +4 -4
  83. package/docs/interfaces/ApexFilteringEvent.html +4 -4
  84. package/docs/interfaces/ApexGridEventMap.html +60 -9
  85. package/docs/interfaces/ApexHeaderContext.html +4 -4
  86. package/docs/interfaces/ApexPageChangedEvent.html +10 -0
  87. package/docs/interfaces/ApexPageChangingEvent.html +10 -0
  88. package/docs/interfaces/ApexQuickFilterChangedEvent.html +4 -0
  89. package/docs/interfaces/ApexQuickFilterChangingEvent.html +6 -0
  90. package/docs/interfaces/ApexRowEditEndedEvent.html +6 -0
  91. package/docs/interfaces/ApexRowEditStartedEvent.html +4 -0
  92. package/docs/interfaces/ApexRowExpandedEvent.html +8 -0
  93. package/docs/interfaces/ApexRowExpandingEvent.html +11 -0
  94. package/docs/interfaces/ApexRowSelectedEvent.html +8 -0
  95. package/docs/interfaces/ApexRowSelectingEvent.html +11 -0
  96. package/docs/interfaces/ApexTreeRowExpandedEvent.html +8 -0
  97. package/docs/interfaces/ApexTreeRowExpandingEvent.html +10 -0
  98. package/docs/interfaces/BaseApexCellContext.html +12 -6
  99. package/docs/interfaces/BaseApexEditorContext.html +19 -0
  100. package/docs/interfaces/BaseColumnConfiguration.html +88 -14
  101. package/docs/interfaces/BaseColumnSortConfiguration.html +4 -4
  102. package/docs/interfaces/BaseFilterExpression.html +5 -5
  103. package/docs/interfaces/BaseSortExpression.html +4 -4
  104. package/docs/interfaces/CSVExportOptions.html +22 -0
  105. package/docs/interfaces/ColumnFilterConfiguration.html +3 -3
  106. package/docs/interfaces/DataPipelineConfiguration.html +13 -4
  107. package/docs/interfaces/ExportFormat.html +10 -0
  108. package/docs/interfaces/ExportOptions.html +15 -0
  109. package/docs/interfaces/GridEditingConfiguration.html +10 -0
  110. package/docs/interfaces/GridExpansionConfiguration.html +15 -0
  111. package/docs/interfaces/GridSelectionConfiguration.html +11 -0
  112. package/docs/interfaces/GridSortConfiguration.html +4 -4
  113. package/docs/interfaces/GridTreeConfiguration.html +33 -0
  114. package/docs/interfaces/PaginationConfiguration.html +18 -0
  115. package/docs/interfaces/PaginationState.html +10 -0
  116. package/docs/media/LICENSE +80 -0
  117. package/docs/media/_tokens.scss +106 -0
  118. package/docs/media/package.json +85 -0
  119. package/docs/modules.html +1 -1
  120. package/docs/types/ApexCellContext.html +2 -2
  121. package/docs/types/ApexEditorContext.html +2 -0
  122. package/docs/types/BasePropertyType.html +2 -2
  123. package/docs/types/BaseSortComparer.html +2 -2
  124. package/docs/types/ColumnConfiguration.html +2 -2
  125. package/docs/types/ColumnDropPosition.html +2 -0
  126. package/docs/types/ColumnSortConfiguration.html +2 -2
  127. package/docs/types/DataPipelineHook.html +2 -2
  128. package/docs/types/DataPipelineParams.html +5 -5
  129. package/docs/types/DataType.html +47 -2
  130. package/docs/types/EditMode.html +6 -0
  131. package/docs/types/EditTrigger.html +4 -0
  132. package/docs/types/ExportCellValue.html +5 -0
  133. package/docs/types/ExportSource.html +8 -0
  134. package/docs/types/FilterCriteria.html +2 -2
  135. package/docs/types/FilterExpression.html +2 -2
  136. package/docs/types/Keys.html +2 -2
  137. package/docs/types/PaginationMode.html +6 -0
  138. package/docs/types/PinPosition.html +5 -0
  139. package/docs/types/PropertyType.html +2 -2
  140. package/docs/types/SelectionMode.html +7 -0
  141. package/docs/types/SortComparer.html +2 -2
  142. package/docs/types/SortExpression.html +2 -2
  143. package/docs/types/SortState.html +2 -2
  144. package/docs/types/SortingDirection.html +1 -1
  145. package/index.d.ts +5 -2
  146. package/index.js +1 -0
  147. package/index.js.map +1 -1
  148. package/internal/column-types.d.ts +94 -0
  149. package/internal/column-types.js +428 -0
  150. package/internal/column-types.js.map +1 -0
  151. package/internal/export.d.ts +114 -0
  152. package/internal/export.js +122 -0
  153. package/internal/export.js.map +1 -0
  154. package/internal/feature-module.d.ts +27 -0
  155. package/internal/feature-module.js +2 -0
  156. package/internal/feature-module.js.map +1 -0
  157. package/internal/flip.d.ts +80 -0
  158. package/internal/flip.js +52 -0
  159. package/internal/flip.js.map +1 -0
  160. package/internal/icons.d.ts +31 -0
  161. package/internal/icons.js +145 -0
  162. package/internal/icons.js.map +1 -0
  163. package/internal/index.d.ts +20 -0
  164. package/internal/index.js +6 -0
  165. package/internal/index.js.map +1 -0
  166. package/internal/tags.d.ts +2 -0
  167. package/internal/tags.js +2 -0
  168. package/internal/tags.js.map +1 -1
  169. package/internal/types.d.ts +473 -3
  170. package/internal/types.js.map +1 -1
  171. package/internal/utils.d.ts +24 -1
  172. package/internal/utils.js +48 -7
  173. package/internal/utils.js.map +1 -1
  174. package/operations/filter/tree.d.ts +1 -1
  175. package/operations/filter/types.js.map +1 -1
  176. package/operations/pagination.d.ts +19 -0
  177. package/operations/pagination.js +12 -0
  178. package/operations/pagination.js.map +1 -0
  179. package/operations/quick-filter.d.ts +21 -0
  180. package/operations/quick-filter.js +26 -0
  181. package/operations/quick-filter.js.map +1 -0
  182. package/operations/sort/types.js.map +1 -1
  183. package/package.json +10 -5
  184. package/setup.d.ts +51 -0
  185. package/setup.js +31 -0
  186. package/setup.js.map +1 -0
  187. package/styles/_checkbox.css.js +3 -0
  188. package/styles/_checkbox.css.js.map +1 -0
  189. package/styles/_tokens.css.js +3 -0
  190. package/styles/_tokens.css.js.map +1 -0
  191. package/styles/body-cell/body-cell.css.js +1 -1
  192. package/styles/body-cell/body-cell.css.js.map +1 -1
  193. package/styles/body-cell/cell-renderers.css.js +3 -0
  194. package/styles/body-cell/cell-renderers.css.js.map +1 -0
  195. package/styles/body-row/body-row.css.js +1 -1
  196. package/styles/body-row/body-row.css.js.map +1 -1
  197. package/styles/filter-row/filter-row.css.js +1 -1
  198. package/styles/filter-row/filter-row.css.js.map +1 -1
  199. package/styles/grid/_grid.base.css.js +1 -1
  200. package/styles/grid/_grid.base.css.js.map +1 -1
  201. package/styles/grid/grid.css.js +3 -0
  202. package/styles/grid/grid.css.js.map +1 -0
  203. package/styles/header-cell/header-cell.css.js +1 -1
  204. package/styles/header-cell/header-cell.css.js.map +1 -1
  205. package/styles/header-row/header-row.base.css.js +1 -1
  206. package/styles/header-row/header-row.base.css.js.map +1 -1
  207. package/styles/paginator/paginator.css.d.ts +1 -0
  208. package/styles/paginator/paginator.css.js +3 -0
  209. package/styles/paginator/paginator.css.js.map +1 -0
  210. package/styles/toolbar/toolbar.css.d.ts +1 -0
  211. package/styles/toolbar/toolbar.css.js +3 -0
  212. package/styles/toolbar/toolbar.css.js.map +1 -0
  213. package/styles.css +17 -0
  214. package/internal/icon-registry.d.ts +0 -1
  215. package/internal/icon-registry.js +0 -29
  216. package/internal/icon-registry.js.map +0 -1
  217. package/internal/theming.d.ts +0 -34
  218. package/internal/theming.js +0 -123
  219. package/internal/theming.js.map +0 -1
  220. package/styles/grid/themes/light/grid.bootstrap.css.js +0 -3
  221. package/styles/grid/themes/light/grid.bootstrap.css.js.map +0 -1
  222. package/styles/grid/themes/light/grid.fluent.css.js +0 -3
  223. package/styles/grid/themes/light/grid.fluent.css.js.map +0 -1
  224. package/styles/grid/themes/light/grid.indigo.css.js +0 -3
  225. package/styles/grid/themes/light/grid.indigo.css.js.map +0 -1
  226. package/styles/grid/themes/light/grid.material.css.js +0 -3
  227. package/styles/grid/themes/light/grid.material.css.js.map +0 -1
  228. /package/styles/{grid/themes/light/grid.bootstrap.css.d.ts → _checkbox.css.d.ts} +0 -0
  229. /package/styles/{grid/themes/light/grid.fluent.css.d.ts → _tokens.css.d.ts} +0 -0
  230. /package/styles/{grid/themes/light/grid.indigo.css.d.ts → body-cell/cell-renderers.css.d.ts} +0 -0
  231. /package/styles/grid/{themes/light/grid.material.css.d.ts → grid.css.d.ts} +0 -0
package/LICENSE CHANGED
@@ -1,9 +1,80 @@
1
- The MIT License (MIT)
1
+ ## 📄 License Options for ApexCharts
2
2
 
3
- Copyright (c) 2023 ApexCharts
3
+ ApexCharts is offered under a **dual-license model** to support individuals, startups, and commercial products of all sizes.
4
4
 
5
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
5
+ ---
6
6
 
7
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
7
+ ### 🔓 Community License (Free)
8
8
 
9
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
9
+ For individuals, non-profits, educators, and small businesses with **less than $2 million USD in annual revenue**.
10
+
11
+ ✅ What’s allowed:
12
+
13
+ - Personal, educational, or non-profit use
14
+ - Commercial use by small orgs (< $2M annual revenue)
15
+ - Modifications and redistribution (with attribution)
16
+
17
+ 🚫 Not allowed:
18
+
19
+ - Use by companies or entities over $2M/year revenue
20
+ - Use in competing charting products
21
+ - Sublicensing under different terms
22
+
23
+ ➡ By using ApexCharts under this license, you confirm that **you qualify as a Small Organization**.
24
+
25
+ ---
26
+
27
+ ### 💼 Commercial License (Paid)
28
+
29
+ Required if **you or your affiliated organization earns $2 million USD or more per year**.
30
+
31
+ ✅ What's included:
32
+
33
+ - Use in internal tools and commercial applications
34
+ - Modifications and app-level distribution
35
+ - 12-month subscription with updates & support
36
+
37
+ 🚫 Not allowed:
38
+
39
+ - Redistribution in toolkits, SDKs, or platforms
40
+ - Use by unlicensed developers
41
+ - Competing charting products
42
+
43
+ ---
44
+
45
+ ### 🔄 OEM / Redistribution License (Paid)
46
+
47
+ Required if you are **embedding ApexCharts into a product or platform used by other people**, such as:
48
+
49
+ - No-code dashboards
50
+ - Developer platforms
51
+ - Embedded BI tools
52
+ - White-labeled apps or SDKs
53
+
54
+ ✅ What's included:
55
+
56
+ - Redistribution rights for 1 application or product
57
+ - 12-month subscription with updates & support
58
+
59
+ ✅ OEM **not required** if your app simply renders static charts and users **cannot** configure or interact with them.
60
+
61
+ ---
62
+
63
+ ### ⚠️ License Acceptance
64
+
65
+ By installing ApexCharts (e.g., via `npm install apexcharts`), you are agreeing to the applicable license based on your usage:
66
+
67
+ - Community License (if under $2M revenue)
68
+ - Commercial License (if over $2M revenue)
69
+ - OEM License (if redistributing to third-party users)
70
+
71
+ ---
72
+
73
+ ### 🛠 Need a License or Have Questions?
74
+
75
+ 📧 Contact us at [sales@apexcharts.com](mailto:sales@apexcharts.com)
76
+ 📚 Read full license agreements here: [https://apexcharts.com/license](https://apexcharts.com/license)
77
+
78
+ ---
79
+
80
+ Thank you for supporting ApexCharts! Your licensing helps keep it free and open for individuals and small teams.
package/README.md CHANGED
@@ -1,16 +1,529 @@
1
- # Apex data component grid
2
- [![Node.js CI](https://github.com/apexcharts/apexgrid/actions/workflows/node.js.yml/badge.svg)](https://github.com/apexcharts/apexgrid/actions/workflows/node.js.yml)
3
- [![Coverage Status](https://coveralls.io/repos/github/apexcharts/apexgrid/badge.svg?branch=master)](https://coveralls.io/github/apexcharts/apexgrid?branch=master)
1
+ # Apex Grid
4
2
 
3
+ [![Node.js CI](https://github.com/apexcharts/apex-grid/actions/workflows/node.js.yml/badge.svg?branch=main)](https://github.com/apexcharts/apex-grid/actions/workflows/node.js.yml)
4
+ [![Coverage Status](https://coveralls.io/repos/github/apexcharts/apex-grid/badge.svg?branch=main)](https://coveralls.io/github/apexcharts/apex-grid?branch=main)
5
+ [![npm](https://img.shields.io/npm/v/apex-grid.svg)](https://www.npmjs.com/package/apex-grid)
5
6
 
6
- This is still a **very** early proof of concept for a web component based data grid.
7
+ A Lit-based, framework-agnostic web component data grid. Ships as a single custom element `<apex-grid>` with a rich, opt-in feature set and full TypeScript types.
7
8
 
8
- ## Local Development
9
+ ## Features
9
10
 
10
- 1. Clone the repository.
11
- 2. Run `npm install`
12
- 3. Play and explore the codebase.
11
+ - **Row virtualization** via `@lit-labs/virtualizer` — only ~20 rows in the DOM at any time, regardless of dataset size.
12
+ - **Sorting** — single or multi-column, tri-state (asc / desc / none), per-column comparers.
13
+ - **Filtering** — per-column filter chips with string / number / boolean / date operands, plus a quick-filter (global search) input.
14
+ - **Pagination** — local slicing or remote mode with a `pageChanging` / `pageChanged` event pair; built-in `<apex-grid-paginator>`.
15
+ - **Column pinning** — pin to start or end; visual reordering only, source `columns` array is preserved.
16
+ - **Column reordering** — drag-and-drop with per-column opt-out, constrained to the column's pinning group.
17
+ - **Column resizing** — pointer-driven, with a min-width safeguard.
18
+ - **Inline editing** — cell or row mode, click or double-click trigger, per-column opt-in.
19
+ - **Row selection** — single or multiple, optional checkbox column, full programmatic API.
20
+ - **Row expansion (master-detail)** — opt-in chevron column with a `detailTemplate`.
21
+ - **Tree data (nested rows)** — AG Grid–style `getDataPath` pattern over a flat array.
22
+ - **CSV export** — programmatic method plus an optional toolbar dropdown. (Excel/XLSX export is in `apex-grid-enterprise`.)
23
+ - **Toolbar** — opt-in `<apex-grid-toolbar>` with debounced quick filter and export menu.
24
+ - **Templating** — slot-based templates for cells, headers, editors, and detail panels.
25
+ - **Theming** — styled out-of-the-box; fully customizable through `--ag-*` CSS custom properties (no theme import or build step). Auto-matches an `igniteui-webcomponents` host app when one is present.
26
+ - **Accessibility** — WCAG 2.2 AA semantics (`role="grid"` / `role="treegrid"`, `aria-rowcount`, `aria-colcount`, focus + keyboard navigation).
27
+ - **Provenance-signed npm releases** with OIDC trusted publishing.
13
28
 
14
- ## Local demo with Vite
29
+ ---
15
30
 
16
- Run `npm start` to open the demo page in `demo/index.html`
31
+ ## Quick Start
32
+
33
+ ### One-call setup
34
+
35
+ ```ts
36
+ import { setup } from 'apex-grid';
37
+
38
+ setup();
39
+ ```
40
+
41
+ That single call registers `<apex-grid>` and adopts a default host stylesheet (`height: 100%; min-height: 240px`). The grid is styled out-of-the-box — no theme CSS import is required.
42
+
43
+ ### Render the grid
44
+
45
+ ```ts
46
+ import { html, render } from 'lit';
47
+ import 'apex-grid/define';
48
+ import type { ColumnConfiguration } from 'apex-grid';
49
+
50
+ type User = { id: number; name: string; age: number; subscribed: boolean };
51
+
52
+ const data: User[] = [
53
+ { id: 1, name: 'Ada Lovelace', age: 36, subscribed: true },
54
+ { id: 2, name: 'Carl Sagan', age: 62, subscribed: false },
55
+ { id: 3, name: 'Grace Hopper', age: 85, subscribed: true },
56
+ ];
57
+
58
+ const columns: ColumnConfiguration<User>[] = [
59
+ { key: 'id', type: 'number', headerText: 'ID', width: '80px', sort: true, filter: true },
60
+ { key: 'name', type: 'string', headerText: 'Name', width: '240px', sort: true, filter: true },
61
+ { key: 'age', type: 'number', headerText: 'Age', width: '100px', sort: true, filter: true },
62
+ { key: 'subscribed', type: 'boolean', headerText: 'Subscribed', width: '140px', sort: true, filter: true },
63
+ ];
64
+
65
+ render(
66
+ html`<apex-grid .data=${data} .columns=${columns}></apex-grid>`,
67
+ document.getElementById('app')!,
68
+ );
69
+ ```
70
+
71
+ ```html
72
+ <style>
73
+ apex-grid { height: 480px; }
74
+ </style>
75
+ <div id="app"></div>
76
+ ```
77
+
78
+ ---
79
+
80
+ ## Manual setup (four steps)
81
+
82
+ If you'd rather not use `setup()`, this is what it does under the hood. Skipping any step produces a grid that "runs" but renders broken (no borders, no filter UI, or only a few collapsed rows).
83
+
84
+ ### 1. Install
85
+
86
+ ```bash
87
+ npm install apex-grid lit
88
+ ```
89
+
90
+ `igniteui-webcomponents` ships as a transitive dependency — no separate install.
91
+
92
+ ### 2. Register the custom element
93
+
94
+ ```ts
95
+ import 'apex-grid/define';
96
+ ```
97
+
98
+ Equivalent long form:
99
+
100
+ ```ts
101
+ import { ApexGrid } from 'apex-grid';
102
+ ApexGrid.register();
103
+ ```
104
+
105
+ Without this, `<apex-grid>` is an inert unknown element.
106
+
107
+ ### 3. (Optional) Customize the look
108
+
109
+ The grid is styled out-of-the-box — there is no theme to import. Customize it by overriding the `--ag-*` CSS custom properties on `apex-grid` (or any ancestor); a one-line brand override cascades to every tint:
110
+
111
+ ```css
112
+ apex-grid {
113
+ --ag-brand: #7c3aed; /* selection, focus, accents */
114
+ --ag-brand-strong: #6d28d9; /* hover / pressed */
115
+ --ag-radius: 12px; /* outer card radius */
116
+ --ag-row-h: 40px; /* row height */
117
+ }
118
+ ```
119
+
120
+ See [`src/styles/_tokens.scss`](src/styles/_tokens.scss) for the full token list (brand, surfaces, text, semantic state colors, typography, spacing, motion).
121
+
122
+ If you embed the grid alongside `igniteui-webcomponents`, the brand tokens automatically re-tint from the igniteui palette (`--ig-primary-500`) — no configuration needed.
123
+
124
+ ### 4. Size the host
125
+
126
+ `@lit-labs/virtualizer` requires a **bounded height**. Without one, the virtualizer collapses to its natural content height (~150px) and only a few rows ever render.
127
+
128
+ ```css
129
+ apex-grid {
130
+ height: 480px; /* any explicit pixel height; % works if the parent has a height */
131
+ }
132
+ ```
133
+
134
+ > [!TIP]
135
+ > `import 'apex-grid/styles.css'` ships a default rule that sets `height: 100%` with a `min-height: 240px` fallback.
136
+
137
+ > [!IMPORTANT]
138
+ > **Do not set `display` on `<apex-grid>`.** The component declares `:host { display: grid }` internally for its track layout (header / filter / body). Any consumer rule that sets `display` (including `block`, `flex`, `inline-block`) collapses the grid. If you accidentally do this, the grid emits a one-shot `console.warn` at startup pointing here.
139
+
140
+ ### What success looks like
141
+
142
+ With the element registered and the host sized, you should see:
143
+
144
+ - **Visible borders** between rows and columns.
145
+ - **Sort arrows** (↕) next to each header when `sort: true`.
146
+ - A **filter row** below the headers with a "Filter" chip per column when `filter: true`.
147
+ - **Hover state** on rows.
148
+ - **Smooth scrolling** — DevTools shows only ~20 `<apex-grid-row>` elements at any time.
149
+
150
+ ### Troubleshooting
151
+
152
+ | What you see | Likely cause |
153
+ |---|---|
154
+ | Want a different look / brand color | Step 3 — override the `--ag-*` CSS variables |
155
+ | Only ~3 rows visible regardless of data size | Step 4 — no bounded height, **or** consumer CSS sets `display` on `<apex-grid>` (check console for the warning) |
156
+ | `<apex-grid>` blank tag in DOM | Step 2 — element not registered |
157
+ | Columns shown as literal `[object Object]` | `columns=` used as an attribute — must be a **property** (`.columns=${...}` in Lit, `[columns]=` in Angular, `:columns.prop=` in Vue, `el.columns = ...` in vanilla JS) |
158
+
159
+ ---
160
+
161
+ ## Features in depth
162
+
163
+ Each feature below is fully opt-in — you only pay for what you turn on. Snippets assume `const grid = document.querySelector('apex-grid')!`.
164
+
165
+ ### Sorting
166
+
167
+ ```ts
168
+ const columns = [
169
+ { key: 'name', sort: true }, // UI sort + tri-state
170
+ { key: 'age', sort: { direction: 'desc' } }, // initial state
171
+ ];
172
+
173
+ grid.sortConfiguration = { multiple: true, triState: true };
174
+ grid.sort({ key: 'age', direction: 'asc' });
175
+ grid.clearSort(); // or grid.clearSort('age')
176
+ ```
177
+
178
+ Events: `sorting` (cancellable), `sorted`.
179
+
180
+ ### Filtering
181
+
182
+ ```ts
183
+ const columns = [
184
+ { key: 'name', filter: true }, // UI filter chip
185
+ { key: 'age', filter: true, type: 'number' }, // operands by type
186
+ ];
187
+
188
+ import { StringOperands } from 'apex-grid';
189
+ grid.filter({ key: 'name', condition: StringOperands.contains, searchTerm: 'Ada' });
190
+ grid.clearFilter();
191
+ ```
192
+
193
+ Operand classes: `StringOperands`, `NumberOperands`, `BooleanOperands`. Events: `filtering` (cancellable), `filtered`.
194
+
195
+ ### Quick filter (global search)
196
+
197
+ ```ts
198
+ grid.showQuickFilter = true; // renders the toolbar input
199
+ grid.quickFilter = 'ada'; // or: await grid.setQuickFilter('ada')
200
+ ```
201
+
202
+ Custom matcher via `dataPipelineConfiguration.quickFilter`. Events: `quickFilterChanging` (cancellable), `quickFilterChanged`. Attribute: `show-quick-filter`, `quick-filter`.
203
+
204
+ ### Pagination
205
+
206
+ ```ts
207
+ grid.pagination = {
208
+ enabled: true,
209
+ pageSize: 25,
210
+ pageSizeOptions: [10, 25, 50, 100],
211
+ };
212
+
213
+ await grid.gotoPage(2);
214
+ await grid.setPageSize(50);
215
+ grid.nextPage(); grid.previousPage(); grid.firstPage(); grid.lastPage();
216
+ ```
217
+
218
+ Remote mode:
219
+
220
+ ```ts
221
+ grid.pagination = { enabled: true, mode: 'remote', pageSize: 25, totalItems: 1280 };
222
+ grid.addEventListener('pageChanged', async (e) => {
223
+ grid.data = await fetchPage(e.detail.page, e.detail.pageSize);
224
+ });
225
+ ```
226
+
227
+ Properties: `page`, `pageSize`, `pageCount`, `totalItems`, `pageItems`. Events: `pageChanging` (cancellable), `pageChanged`.
228
+
229
+ ### Column pinning
230
+
231
+ ```ts
232
+ const columns = [
233
+ { key: 'id', pinned: 'start' },
234
+ { key: 'name' },
235
+ { key: 'actions', pinned: 'end' },
236
+ ];
237
+
238
+ await grid.pinColumn('name', 'start');
239
+ await grid.unpinColumn('name'); // or pinColumn('name', null)
240
+ ```
241
+
242
+ The source `columns` array is **not** reordered — only the visual render order changes. Read `grid.displayColumns` for the render order. Events: `columnPinning` (cancellable), `columnPinned`.
243
+
244
+ ### Column reordering
245
+
246
+ ```html
247
+ <apex-grid column-reordering></apex-grid>
248
+ ```
249
+
250
+ Or programmatic:
251
+
252
+ ```ts
253
+ await grid.moveColumn('email', 'name', 'after');
254
+ ```
255
+
256
+ Per-column opt-out: `{ key: 'id', reorderable: false }`. Reordering is constrained to the column's own pinning group (start / unpinned / end). Events: `columnMoving` (cancellable), `columnMoved`. Attribute: `column-reordering`.
257
+
258
+ ### Inline editing
259
+
260
+ ```ts
261
+ const columns = [
262
+ { key: 'name', editable: true },
263
+ { key: 'age', editable: true, type: 'number' },
264
+ ];
265
+
266
+ grid.editing = { enabled: true, mode: 'cell', trigger: 'doubleClick' };
267
+
268
+ await grid.editCell(0, 'name');
269
+ await grid.commitEdit();
270
+ grid.cancelEdit();
271
+ ```
272
+
273
+ `mode: 'row'` puts all editable cells in the row into edit together. Properties: `editingCell`, `editingRow`. Events: `cellValueChanging` (cancellable), `cellValueChanged`, plus `rowEditStarted` / `rowEditEnded` in row mode.
274
+
275
+ ### Row selection
276
+
277
+ ```ts
278
+ grid.selection = { enabled: true, mode: 'multiple', showCheckboxColumn: true };
279
+
280
+ await grid.selectRow(data[0]);
281
+ await grid.toggleRowSelection(data[1]);
282
+ await grid.selectAllRows();
283
+ await grid.clearSelection();
284
+ grid.selectedRows; // snapshot
285
+ grid.selectedRows = [data[2]]; // replace selection (goes through `rowSelecting`)
286
+ ```
287
+
288
+ Events: `rowSelecting` (cancellable), `rowSelected`.
289
+
290
+ ### Row expansion (master-detail)
291
+
292
+ ```ts
293
+ grid.expansion = {
294
+ enabled: true,
295
+ detailTemplate: ({ data }) => html`<order-summary .order=${data}></order-summary>`,
296
+ isExpandable: (row) => row.hasDetails,
297
+ };
298
+
299
+ await grid.expandRow(data[0]);
300
+ await grid.toggleRowExpansion(data[0]);
301
+ await grid.expandAllRows();
302
+ await grid.collapseAllRows();
303
+ grid.expandedRows; // snapshot
304
+ ```
305
+
306
+ Events: `rowExpanding` (cancellable), `rowExpanded`.
307
+
308
+ ### Tree data (nested rows)
309
+
310
+ The data array stays **flat**. The grid derives the hierarchy from a `getDataPath(row)` callback that returns the path from root to that row — AG Grid's "tree data" pattern.
311
+
312
+ ```ts
313
+ type Person = { id: number; name: string; title: string; path: string[] };
314
+
315
+ const data: Person[] = [
316
+ { id: 1, name: 'Adrian', title: 'CEO', path: ['Adrian'] },
317
+ { id: 2, name: 'Bryan', title: 'VP Eng', path: ['Adrian', 'Bryan'] },
318
+ { id: 3, name: 'Cara', title: 'Manager', path: ['Adrian', 'Bryan', 'Cara'] },
319
+ ];
320
+
321
+ grid.tree = {
322
+ enabled: true,
323
+ getDataPath: (row) => row.path,
324
+ defaultExpanded: 1, // boolean | number — depth to expand
325
+ groupColumnKey: 'name', // which column shows the chevron + indent
326
+ childIndent: 20, // px per depth level
327
+ };
328
+
329
+ await grid.toggleTreeRow(data[0]);
330
+ await grid.expandAllTreeRows();
331
+ ```
332
+
333
+ Methods: `toggleTreeRow`, `expandTreeRow`, `collapseTreeRow`, `expandAllTreeRows`, `collapseAllTreeRows`, `isTreeRowExpanded`. Events: `treeRowExpanding` (cancellable), `treeRowExpanded`. When tree mode is active, the host element advertises `role="treegrid"`.
334
+
335
+ ### CSV export
336
+
337
+ Programmatic:
338
+
339
+ ```ts
340
+ grid.exportToCSV(); // downloads data.csv
341
+ grid.exportToCSV({ filename: 'users', source: 'selected' });
342
+ const text = grid.exportToCSV({ filename: '' }); // no download, returns the string
343
+ ```
344
+
345
+ `source` can be `'view'` (default — post-filter/post-sort), `'page'`, `'selected'`, or `'all'`. Per-column opt-out: `{ key: 'secret', exportable: false }`.
346
+
347
+ > **XLSX (Excel) export** moved to [`apex-grid-enterprise`](https://www.npmjs.com/package/apex-grid-enterprise) in v3. `<apex-grid-enterprise>` adds `grid.exportToXLSX(...)` and an "Export XLSX" entry to this same toolbar menu. CSV stays free.
348
+
349
+ Toolbar dropdown:
350
+
351
+ ```html
352
+ <apex-grid show-export></apex-grid>
353
+ ```
354
+
355
+ Renders a download icon in the toolbar's trailing actions area; the menu has an "Export CSV" entry (the enterprise grid adds "Export XLSX"). Toolbar `exportFilename` overrides the default `data` filename. Attribute: `show-export`.
356
+
357
+ ### Toolbar
358
+
359
+ Rendered automatically above the header row when at least one of `show-quick-filter` or `show-export` is on. CSS parts:
360
+
361
+ | Part | What |
362
+ |---|---|
363
+ | `toolbar` | Root container |
364
+ | `toolbar-search` | Quick-filter input wrapper |
365
+ | `search-field` | The bordered input field |
366
+ | `search-icon`, `search-input` | Leading icon, input element |
367
+ | `toolbar-actions` | Trailing actions area |
368
+ | `export-trigger` | Export menu button |
369
+ | `export-menu` | Dropdown panel |
370
+ | `export-menu-item` | Menu item |
371
+
372
+ Search input has a `debounce` attribute (default `200`ms).
373
+
374
+ ### Theming
375
+
376
+ The grid styles itself through `--ag-*` CSS custom properties — override them on `apex-grid` (or any ancestor) to rebrand; see [`src/styles/_tokens.scss`](src/styles/_tokens.scss) for the full list. When `igniteui-webcomponents` is present, the brand tokens auto-tint from its palette.
377
+
378
+ Style with CSS parts on the grid, paginator, and toolbar:
379
+
380
+ ```css
381
+ apex-grid::part(paginator) { background: var(--surface-2); }
382
+ apex-grid-toolbar::part(search-input) { font-family: var(--font-mono); }
383
+ ```
384
+
385
+ ---
386
+
387
+ ## API Reference
388
+
389
+ ### Properties
390
+
391
+ | Property | Type | Default | Notes |
392
+ |---|---|---|---|
393
+ | `data` | `T[]` | `[]` | Source records (property only) |
394
+ | `columns` | `ColumnConfiguration<T>[]` | `[]` | Column configuration (property only) |
395
+ | `autoGenerate` | `boolean` | `false` | Infer columns from `data[0]` keys. Attr `auto-generate` |
396
+ | `sortConfiguration` | `GridSortConfiguration` | `{ multiple, triState }` | |
397
+ | `dataPipelineConfiguration` | `DataPipelineConfiguration<T>` | — | Custom sort/filter/pagination hooks |
398
+ | `pagination` | `PaginationConfiguration` | — | |
399
+ | `quickFilter` | `string` | `''` | Attr `quick-filter` |
400
+ | `showQuickFilter` | `boolean` | `false` | Attr `show-quick-filter` |
401
+ | `showExport` | `boolean` | `false` | Attr `show-export` |
402
+ | `columnReordering` | `boolean` | `false` | Attr `column-reordering` |
403
+ | `editing` | `GridEditingConfiguration` | — | |
404
+ | `selection` | `GridSelectionConfiguration` | — | |
405
+ | `expansion` | `GridExpansionConfiguration<T>` | — | |
406
+ | `tree` | `GridTreeConfiguration<T>` | — | |
407
+ | `sortExpressions` | `SortExpression<T>[]` | — | Get/set |
408
+ | `filterExpressions` | `FilterExpression<T>[]` | — | Get/set |
409
+ | `selectedRows` | `T[]` | — | Get/set |
410
+ | `expandedRows` | `T[]` | — | Get/set |
411
+ | `page`, `pageSize`, `pageCount`, `totalItems` | `number` | — | |
412
+ | `pageItems` | `readonly T[]` | — | Currently rendered slice |
413
+ | `dataView` | `readonly T[]` | — | Post-filter, post-sort |
414
+ | `displayColumns` | `readonly ColumnConfiguration<T>[]` | — | Render order (pinned start → unpinned → pinned end) |
415
+ | `editingCell` | `{ rowIndex, columnKey } \| null` | — | |
416
+ | `editingRow` | `number \| null` | — | Row-mode only |
417
+
418
+ ### Methods
419
+
420
+ ```ts
421
+ sort(expr): void
422
+ filter(expr): void
423
+ clearSort(key?): void
424
+ clearFilter(key?): void
425
+ setQuickFilter(value): Promise<boolean>
426
+
427
+ getColumn(keyOrIndex): ColumnConfiguration<T> | undefined
428
+ updateColumns(columns): void
429
+ pinColumn(key, 'start' | 'end' | null): Promise<boolean>
430
+ unpinColumn(key): Promise<boolean>
431
+ moveColumn(fromKey, toKey, 'before' | 'after'): Promise<boolean>
432
+
433
+ gotoPage(page): Promise<boolean>
434
+ setPageSize(size): Promise<boolean>
435
+ nextPage(); previousPage(); firstPage(); lastPage()
436
+
437
+ editCell(rowIndex, columnKey): Promise<boolean>
438
+ editRow(rowIndex): Promise<boolean>
439
+ commitEdit(): Promise<boolean>
440
+ cancelEdit(): void
441
+
442
+ selectRow(row); deselectRow(row); toggleRowSelection(row)
443
+ selectAllRows(); clearSelection(); isRowSelected(row)
444
+
445
+ expandRow(row); collapseRow(row); toggleRowExpansion(row)
446
+ expandAllRows(); collapseAllRows(); isRowExpanded(row)
447
+
448
+ toggleTreeRow(row); expandTreeRow(row); collapseTreeRow(row)
449
+ expandAllTreeRows(); collapseAllTreeRows(); isTreeRowExpanded(row)
450
+
451
+ exportToCSV(options?): string
452
+ exportAs(formatId, options?): void // toolbar dispatch; 'csv' (community), 'xlsx' (enterprise)
453
+ ```
454
+
455
+ ### Events
456
+
457
+ All events bubble and are composed across shadow boundaries. Names ending in `-ing` are cancellable.
458
+
459
+ | Event | Cancellable | Detail |
460
+ |---|---|---|
461
+ | `sorting` / `sorted` | yes / no | `SortExpression<T>[]` |
462
+ | `filtering` / `filtered` | yes / no | `FilterExpression<T>[]` |
463
+ | `quickFilterChanging` / `quickFilterChanged` | yes / no | `{ value, nextValue? }` |
464
+ | `pageChanging` / `pageChanged` | yes / no | `{ page, pageSize, pageCount, totalItems }` |
465
+ | `columnPinning` / `columnPinned` | yes / no | `{ key, previous, next }` / `{ key, pinned }` |
466
+ | `columnMoving` / `columnMoved` | yes / no | `{ key, fromIndex, toKey, position }` / `{ key, fromIndex, toIndex }` |
467
+ | `cellValueChanging` / `cellValueChanged` | yes / no | `{ row, column, value, newValue }` |
468
+ | `rowEditStarted` / `rowEditEnded` | no / no | row context |
469
+ | `rowSelecting` / `rowSelected` | yes / no | `{ added, removed }` |
470
+ | `rowExpanding` / `rowExpanded` | yes / no | row context |
471
+ | `treeRowExpanding` / `treeRowExpanded` | yes / no | row context |
472
+
473
+ Programmatic `sort()` / `filter()` calls are silent — only UI-initiated changes emit `sorting` / `filtering`.
474
+
475
+ ### Attributes
476
+
477
+ `auto-generate`, `quick-filter`, `show-quick-filter`, `show-export`, `column-reordering`.
478
+
479
+ ### CSS parts
480
+
481
+ | Component | Parts |
482
+ |---|---|
483
+ | `<apex-grid-toolbar>` | `toolbar`, `toolbar-search`, `search-field`, `search-icon`, `search-input`, `toolbar-actions`, `export-trigger`, `export-menu`, `export-menu-item` |
484
+ | `<apex-grid-paginator>` | `paginator`, `paginator-size`, `paginator-info`, `paginator-controls`, `paginator-page` |
485
+ | `<apex-grid-cell>` | `cell`, `editor` |
486
+
487
+ ---
488
+
489
+ ## Framework integration
490
+
491
+ `<apex-grid>` is a standard custom element. Bind properties (not attributes) for `data` / `columns`:
492
+
493
+ | Framework | Syntax |
494
+ |---|---|
495
+ | Lit | `<apex-grid .data=${data} .columns=${columns}>` |
496
+ | Angular | `<apex-grid [data]="data" [columns]="columns">` (use `CUSTOM_ELEMENTS_SCHEMA`) |
497
+ | Vue | `<apex-grid :data.prop="data" :columns.prop="columns">` |
498
+ | React (19+) | `<apex-grid data={data} columns={columns}>` |
499
+ | Vanilla | `el.data = data; el.columns = columns;` |
500
+
501
+ ---
502
+
503
+ ## Local development
504
+
505
+ ```bash
506
+ git clone https://github.com/apexcharts/apex-grid.git
507
+ cd apex-grid
508
+ npm install
509
+ npm start # demo at http://localhost:5173
510
+ npm test # web-test-runner
511
+ npm run lint
512
+ npm run build # builds dist/ + custom-elements.json + typedoc
513
+ ```
514
+
515
+ ## Releasing
516
+
517
+ Releases are automated by [.github/workflows/publish.yml](.github/workflows/publish.yml):
518
+
519
+ 1. Bump `"version"` in [package.json](package.json) — the single source of truth. The build injects it into `dist/package.json`.
520
+ 2. Commit with a message starting with `release:` and the same version, e.g. `release: 2.0.0` or `release: 2.0.0-rc.1`.
521
+ 3. Push to `main`.
522
+
523
+ The workflow then verifies the version triple-match, runs lint + tests + build, publishes `dist/` to npm with `--provenance` (OIDC trusted publishing — no token in secrets), and creates a `vX.Y.Z` git tag and GitHub Release with auto-generated notes. Pre-release versions (containing `-`) publish under the `next` dist-tag; stable versions under `latest`.
524
+
525
+ Any push whose head commit does not start with `release:` is a no-op for the workflow.
526
+
527
+ ## License
528
+
529
+ See [LICENSE](LICENSE).
@@ -1,10 +1,15 @@
1
1
  import { LitElement } from 'lit';
2
+ import { type StateController } from '../controllers/state.js';
2
3
  import type { ApexCellContext, ColumnConfiguration, PropertyType } from '../internal/types.js';
3
4
  import type ApexGridRow from './row.js';
4
5
  /**
5
6
  * Component representing a DOM cell of the Apex grid.
7
+ *
8
+ * @csspart cell - The cell host element.
9
+ * @csspart editor - The editor wrapper rendered while the cell is in edit mode.
6
10
  */
7
11
  export default class ApexGridCell<T extends object> extends LitElement {
12
+ #private;
8
13
  static get tagName(): "apex-grid-cell";
9
14
  static styles: import("lit").CSSResult;
10
15
  static register(): void;
@@ -21,11 +26,45 @@ export default class ApexGridCell<T extends object> extends LitElement {
21
26
  *
22
27
  */
23
28
  active: boolean;
29
+ /**
30
+ * Whether the cell is currently in edit mode. Set by the parent row from the
31
+ * editing controller's state so cells re-render on edit state changes.
32
+ */
33
+ editing: boolean;
34
+ state: StateController<T>;
24
35
  /**
25
36
  * The parent row component holding this cell.
26
37
  */
27
38
  row: ApexGridRow<T>;
39
+ protected editorElement: HTMLElement | null;
28
40
  protected get context(): ApexCellContext<T>;
41
+ protected get editingController(): import("../controllers/editing.js").EditingController<T>;
42
+ protected get isEditing(): boolean;
43
+ protected get isEditable(): boolean;
44
+ /**
45
+ * 1-based column index used to populate `aria-colindex`. Accounts for the
46
+ * auto-rendered selection + expansion columns ahead of the data columns.
47
+ */
48
+ colindex: number;
49
+ connectedCallback(): void;
50
+ disconnectedCallback(): void;
51
+ protected willUpdate(): void;
52
+ protected updated(): void;
53
+ protected renderDefaultEditor(): import("lit-html").TemplateResult<1>;
54
+ protected renderEditor(): unknown;
55
+ /**
56
+ * Renders the tree affordance — depth-based indent + a chevron toggle (or
57
+ * leaf spacer) — that prefixes the group cell when {@link ApexGrid.tree}
58
+ * is enabled. Returns `nothing` for every other cell.
59
+ */
60
+ protected renderTreeAffordance(): import("lit-html").TemplateResult<1> | null;
61
+ /**
62
+ * Resolves the value to display for the cell. Synthesized tree parents
63
+ * (those that appear only as a path segment with no backing data) render
64
+ * their last path segment in the group column and nothing elsewhere.
65
+ */
66
+ protected resolveDisplayValue(): unknown;
67
+ protected renderCellBody(): unknown;
29
68
  protected render(): unknown;
30
69
  }
31
70
  declare global {