apex-grid 3.4.0 → 3.6.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 (217) hide show
  1. package/CHANGELOG.md +439 -0
  2. package/LICENSE.md +125 -0
  3. package/README.md +107 -14
  4. package/components/cell.d.ts +30 -4
  5. package/components/cell.js +199 -53
  6. package/components/cell.js.map +1 -1
  7. package/components/filter-row.d.ts +2 -0
  8. package/components/filter-row.js +82 -28
  9. package/components/filter-row.js.map +1 -1
  10. package/components/grid.d.ts +257 -20
  11. package/components/grid.js +463 -99
  12. package/components/grid.js.map +1 -1
  13. package/components/group-header-row.js +28 -25
  14. package/components/group-header-row.js.map +1 -1
  15. package/components/header-row.d.ts +7 -5
  16. package/components/header-row.js +19 -9
  17. package/components/header-row.js.map +1 -1
  18. package/components/header.js +36 -22
  19. package/components/header.js.map +1 -1
  20. package/components/row.d.ts +19 -3
  21. package/components/row.js +96 -22
  22. package/components/row.js.map +1 -1
  23. package/components/toolbar.js +2 -1
  24. package/components/toolbar.js.map +1 -1
  25. package/components/virtualizer.d.ts +45 -1
  26. package/components/virtualizer.js +184 -3
  27. package/components/virtualizer.js.map +1 -1
  28. package/controllers/dom.d.ts +4 -4
  29. package/controllers/dom.js +40 -22
  30. package/controllers/dom.js.map +1 -1
  31. package/controllers/editing.d.ts +104 -37
  32. package/controllers/editing.js +230 -78
  33. package/controllers/editing.js.map +1 -1
  34. package/controllers/expansion.d.ts +14 -5
  35. package/controllers/expansion.js +24 -1
  36. package/controllers/expansion.js.map +1 -1
  37. package/controllers/filter.d.ts +10 -2
  38. package/controllers/filter.js +62 -17
  39. package/controllers/filter.js.map +1 -1
  40. package/controllers/history.d.ts +45 -8
  41. package/controllers/history.js +58 -20
  42. package/controllers/history.js.map +1 -1
  43. package/controllers/navigation.d.ts +68 -13
  44. package/controllers/navigation.js +196 -51
  45. package/controllers/navigation.js.map +1 -1
  46. package/controllers/pagination.d.ts +6 -0
  47. package/controllers/pagination.js +10 -2
  48. package/controllers/pagination.js.map +1 -1
  49. package/controllers/reorder.js +42 -24
  50. package/controllers/reorder.js.map +1 -1
  51. package/controllers/resize.d.ts +17 -2
  52. package/controllers/resize.js +16 -6
  53. package/controllers/resize.js.map +1 -1
  54. package/controllers/row-pin.d.ts +20 -2
  55. package/controllers/row-pin.js +16 -9
  56. package/controllers/row-pin.js.map +1 -1
  57. package/controllers/row-reorder.d.ts +31 -11
  58. package/controllers/row-reorder.js +117 -37
  59. package/controllers/row-reorder.js.map +1 -1
  60. package/controllers/selection.d.ts +11 -4
  61. package/controllers/selection.js +26 -11
  62. package/controllers/selection.js.map +1 -1
  63. package/controllers/sort.d.ts +22 -2
  64. package/controllers/sort.js +29 -23
  65. package/controllers/sort.js.map +1 -1
  66. package/controllers/state.d.ts +65 -10
  67. package/controllers/state.js +86 -6
  68. package/controllers/state.js.map +1 -1
  69. package/controllers/tree.d.ts +15 -10
  70. package/controllers/tree.js +0 -0
  71. package/controllers/tree.js.map +1 -1
  72. package/custom-elements.json +3589 -452
  73. package/docs/assets/hierarchy.js +1 -1
  74. package/docs/assets/highlight.css +15 -8
  75. package/docs/assets/navigation.js +1 -1
  76. package/docs/assets/search.js +1 -1
  77. package/docs/classes/ApexGrid.html +660 -0
  78. package/docs/classes/ApexGridPaginator.html +36 -0
  79. package/docs/classes/ApexGridToolbar.html +67 -0
  80. package/docs/functions/localize.html +2 -2
  81. package/docs/functions/setup.html +1 -2
  82. package/docs/hierarchy.html +1 -1
  83. package/docs/index.html +105 -15
  84. package/docs/interfaces/ApexCellValidationFailedEvent.html +3 -2
  85. package/docs/interfaces/ApexCellValueChangedEvent.html +4 -2
  86. package/docs/interfaces/ApexCellValueChangingEvent.html +3 -2
  87. package/docs/interfaces/ApexColumnMovedEvent.html +2 -2
  88. package/docs/interfaces/ApexColumnMovingEvent.html +1 -1
  89. package/docs/interfaces/ApexDetailContext.html +2 -2
  90. package/docs/interfaces/ApexGridEventMap.html +9 -6
  91. package/docs/interfaces/ApexRowEditEndedEvent.html +2 -1
  92. package/docs/interfaces/ApexRowEditStartedEvent.html +2 -1
  93. package/docs/interfaces/ApexRowMovingEvent.html +9 -3
  94. package/docs/interfaces/ApexRowPinningEvent.html +1 -1
  95. package/docs/interfaces/ApexTreeRowExpandedEvent.html +4 -1
  96. package/docs/interfaces/ApexTreeRowExpandingEvent.html +4 -1
  97. package/docs/interfaces/BaseApexCellContext.html +1 -1
  98. package/docs/interfaces/BaseApexEditorContext.html +1 -1
  99. package/docs/interfaces/BaseColumnConfiguration.html +3 -3
  100. package/docs/interfaces/BaseFilterExpression.html +2 -2
  101. package/docs/interfaces/CSVExportOptions.html +13 -5
  102. package/docs/interfaces/DataPipelineConfiguration.html +2 -2
  103. package/docs/interfaces/EditingHistoryConfiguration.html +1 -1
  104. package/docs/interfaces/ExportFormat.html +2 -2
  105. package/docs/interfaces/ExportOptions.html +5 -3
  106. package/docs/interfaces/GridExpansionConfiguration.html +6 -2
  107. package/docs/interfaces/GridRowPinningConfiguration.html +1 -1
  108. package/docs/interfaces/GridRowReorderingConfiguration.html +2 -2
  109. package/docs/interfaces/PaginationConfiguration.html +1 -1
  110. package/docs/interfaces/PaginationState.html +1 -1
  111. package/docs/interfaces/SetStateResult.html +3 -2
  112. package/docs/interfaces/ValidatorContext.html +7 -2
  113. package/docs/media/_token-values.scss +118 -0
  114. package/docs/media/package.json +5 -5
  115. package/docs/media/state-persistence.html +0 -10
  116. package/docs/modules.html +1 -1
  117. package/docs/types/DataPipelineParams.html +2 -2
  118. package/docs/types/EditMode.html +2 -2
  119. package/docs/types/ExportSource.html +6 -4
  120. package/docs/types/GridLocaleText.html +1 -1
  121. package/docs/types/OperandKeys.html +9 -0
  122. package/docs/types/PaginationMode.html +1 -1
  123. package/docs/variables/EN_LOCALE.html +3 -3
  124. package/docs/variables/esLocale.html +1 -1
  125. package/i18n/en.d.ts +19 -0
  126. package/i18n/en.js +19 -0
  127. package/i18n/en.js.map +1 -1
  128. package/i18n/es.js +19 -0
  129. package/i18n/es.js.map +1 -1
  130. package/index.d.ts +2 -0
  131. package/index.js +2 -0
  132. package/index.js.map +1 -1
  133. package/internal/column-types.d.ts +27 -1
  134. package/internal/column-types.js +75 -49
  135. package/internal/column-types.js.map +1 -1
  136. package/internal/constants.d.ts +1 -2
  137. package/internal/constants.js +0 -4
  138. package/internal/constants.js.map +1 -1
  139. package/internal/document-styles.d.ts +30 -0
  140. package/internal/document-styles.js +48 -0
  141. package/internal/document-styles.js.map +1 -0
  142. package/internal/export.d.ts +39 -7
  143. package/internal/export.js +35 -34
  144. package/internal/export.js.map +1 -1
  145. package/internal/feature-module.d.ts +82 -3
  146. package/internal/feature-module.js +11 -0
  147. package/internal/feature-module.js.map +1 -1
  148. package/internal/index.d.ts +6 -4
  149. package/internal/index.js +5 -3
  150. package/internal/index.js.map +1 -1
  151. package/internal/normalize-case.d.ts +8 -1
  152. package/internal/normalize-case.js +3 -2
  153. package/internal/normalize-case.js.map +1 -1
  154. package/internal/state-snapshot.d.ts +60 -8
  155. package/internal/state-snapshot.js +87 -19
  156. package/internal/state-snapshot.js.map +1 -1
  157. package/internal/types.d.ts +17 -2
  158. package/internal/types.js.map +1 -1
  159. package/internal/utils.d.ts +48 -6
  160. package/internal/utils.js +35 -21
  161. package/internal/utils.js.map +1 -1
  162. package/internal/validators.js +1 -0
  163. package/internal/validators.js.map +1 -1
  164. package/operations/filter/operands/number.js +9 -6
  165. package/operations/filter/operands/number.js.map +1 -1
  166. package/operations/filter/operands/string.js +2 -3
  167. package/operations/filter/operands/string.js.map +1 -1
  168. package/operations/filter/types.d.ts +13 -1
  169. package/operations/filter/types.js.map +1 -1
  170. package/operations/filter.d.ts +6 -0
  171. package/operations/filter.js +23 -7
  172. package/operations/filter.js.map +1 -1
  173. package/operations/quick-filter.js +2 -5
  174. package/operations/quick-filter.js.map +1 -1
  175. package/operations/sort.d.ts +21 -2
  176. package/operations/sort.js +41 -14
  177. package/operations/sort.js.map +1 -1
  178. package/package.json +8 -4
  179. package/setup.d.ts +23 -11
  180. package/setup.js +19 -21
  181. package/setup.js.map +1 -1
  182. package/styles/_common.css.js +1 -1
  183. package/styles/_common.css.js.map +1 -1
  184. package/styles/_token-values.css.d.ts +1 -0
  185. package/styles/_token-values.css.js +3 -0
  186. package/styles/_token-values.css.js.map +1 -0
  187. package/styles/_tokens.css.js +1 -1
  188. package/styles/_tokens.css.js.map +1 -1
  189. package/styles/body-cell/body-cell.css.js +1 -1
  190. package/styles/body-cell/body-cell.css.js.map +1 -1
  191. package/styles/body-cell/cell-renderers.css.js +1 -1
  192. package/styles/body-cell/cell-renderers.css.js.map +1 -1
  193. package/styles/body-row/body-row.css.js +1 -1
  194. package/styles/body-row/body-row.css.js.map +1 -1
  195. package/styles/document-tokens.css.d.ts +1 -0
  196. package/styles/document-tokens.css.js +3 -0
  197. package/styles/document-tokens.css.js.map +1 -0
  198. package/styles/filter-row/filter-row.css.js +1 -1
  199. package/styles/filter-row/filter-row.css.js.map +1 -1
  200. package/styles/grid/_grid.base.css.js +1 -1
  201. package/styles/grid/_grid.base.css.js.map +1 -1
  202. package/styles/grid/grid.css.js +1 -1
  203. package/styles/grid/grid.css.js.map +1 -1
  204. package/styles/group-header-row/group-header-row.css.js +1 -1
  205. package/styles/group-header-row/group-header-row.css.js.map +1 -1
  206. package/styles/header-cell/header-cell.css.js +1 -1
  207. package/styles/header-cell/header-cell.css.js.map +1 -1
  208. package/styles/header-row/header-row.base.css.js +1 -1
  209. package/styles/header-row/header-row.base.css.js.map +1 -1
  210. package/styles/paginator/paginator.css.js +1 -1
  211. package/styles/paginator/paginator.css.js.map +1 -1
  212. package/styles/toolbar/toolbar.css.js +1 -1
  213. package/styles/toolbar/toolbar.css.js.map +1 -1
  214. package/tokens.css +78 -0
  215. package/LICENSE +0 -80
  216. package/docs/media/LICENSE +0 -80
  217. package/docs/media/_tokens.scss +0 -193
package/README.md CHANGED
@@ -29,7 +29,7 @@ A Lit-based, framework-agnostic web component data grid. Ships as a single custo
29
29
  - **CSV export**: programmatic method plus an optional toolbar dropdown. (Excel/XLSX export is in `apex-grid-enterprise`.)
30
30
  - **Toolbar**: opt-in `<apex-grid-toolbar>` with debounced quick filter and export menu.
31
31
  - **Templating**: slot-based templates for cells, headers, editors, and detail panels.
32
- - **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.
32
+ - **Theming**: styled out-of-the-box; fully customizable through `--ag-*` CSS custom properties (no theme import or build step). Auto-tints to an Ignite UI host app's palette when one is present, with no dependency on it.
33
33
  - **Accessibility**: WCAG 2.2 AA semantics (`role="grid"` / `role="treegrid"`, `aria-rowcount`, `aria-colcount`, focus + keyboard navigation).
34
34
  - **Provenance-signed npm releases** with OIDC trusted publishing.
35
35
 
@@ -45,7 +45,7 @@ import { setup } from 'apex-grid';
45
45
  setup();
46
46
  ```
47
47
 
48
- 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.
48
+ That single call registers `<apex-grid>` and adopts a default host stylesheet (`height: 100%; min-height: 240px`), also inside any shadow root a grid connects in. The grid is styled out-of-the-box; no theme CSS import is required.
49
49
 
50
50
  ### Render the grid
51
51
 
@@ -94,8 +94,6 @@ If you'd rather not use `setup()`, this is what it does under the hood. Skipping
94
94
  npm install apex-grid lit
95
95
  ```
96
96
 
97
- `igniteui-webcomponents` ships as a transitive dependency; no separate install.
98
-
99
97
  ### 2. Register the custom element
100
98
 
101
99
  ```ts
@@ -113,7 +111,7 @@ Without this, `<apex-grid>` is an inert unknown element.
113
111
 
114
112
  ### 3. (Optional) Customize the look
115
113
 
116
- 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:
114
+ 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 on any ancestor: `:root`, a dashboard panel, or the shadow host of a web component the grid renders in (custom properties inherit through shadow boundaries, however deep). A one-line brand override cascades to every tint:
117
115
 
118
116
  ```css
119
117
  apex-grid {
@@ -124,16 +122,40 @@ apex-grid {
124
122
  }
125
123
  ```
126
124
 
127
- See [`src/styles/_tokens.scss`](src/styles/_tokens.scss) for the full token list (brand, surfaces, text, semantic state colors, typography, spacing, motion).
125
+ See [`src/styles/_token-values.scss`](src/styles/_token-values.scss) for the full token list and defaults (surfaces, text, semantic state colors, typography, spacing, motion).
126
+
127
+ **Where the defaults live.** The first grid to connect adopts the token defaults into its document, on `:where(:root)`, through `adoptedStyleSheets` (no `<style>` element, so no CSP nonce). Zero specificity means any value you set wins, and `var(--ag-*)` reads in your own CSS resolve to the defaults. If you manage your own CSS, opt out with `setup({ tokenStyles: false })` and import the same defaults as a file (also the way to get them into server-rendered HTML):
128
+
129
+ ```ts
130
+ import 'apex-grid/tokens.css';
131
+ ```
132
+
133
+ The grid renders the same without the sheet; it carries the defaults as fallbacks. Three groups have no root default, so page CSS reading them needs its own fallback:
134
+
135
+ - `--ag-brand` and `--ag-brand-strong`, so an Ignite UI palette set on any ancestor keeps tinting the grid (see below).
136
+ - The derived washes `--ag-brand-soft`, `--ag-brand-softer`, `--ag-brand-line`, `--ag-row-hover` and `--ag-surface-alt`. The grid mixes them from the brand and surface in effect, so they follow a brand set on an ancestor. Set them only to override the mix.
137
+
138
+ **Dark mode.** `theme="dark"` reads its own colour inputs, `--ag-dark-*` (`--ag-dark-surface`, `--ag-dark-text`, `--ag-dark-hairline`, `--ag-dark-shadow-card`, and so on), so a light palette set on a shared ancestor never puts a white surface under the dark theme's light text. Sizing, typography, motion, the brand and the base state colours are shared by both modes. To theme both from one place, set both palettes:
139
+
140
+ ```css
141
+ .dashboard {
142
+ --ag-brand: #7c3aed;
143
+ --ag-surface: #fdfcff;
144
+ --ag-dark-surface: #140f24;
145
+ }
146
+ ```
147
+
148
+ `theme="tinted"` mixes a little brand into the surface, gridline and muted-text values in effect, including any you set. Its row separators are the brand alone, so a tinted grid ignores `--ag-border` and `--ag-dark-border`.
128
149
 
129
150
  **Grid edge / shadow.** By default the grid shows a flat 1px hairline edge (no drop shadow). Control it with the `--ag-grid-shadow` hook, an opt-in override that is not one of the `_tokens.scss` defaults:
130
151
 
131
152
  ```css
132
- apex-grid { --ag-grid-shadow: var(--ag-shadow-card); } /* elevated floating-card look */
133
- apex-grid { --ag-grid-shadow: none; } /* remove the edge entirely */
153
+ apex-grid { --ag-grid-shadow: var(--ag-shadow-card); } /* elevated floating-card look */
154
+ apex-grid[theme~='dark'] { --ag-grid-shadow: var(--ag-dark-shadow-card); } /* the same, for dark grids */
155
+ apex-grid { --ag-grid-shadow: none; } /* remove the edge entirely */
134
156
  ```
135
157
 
136
- If you embed the grid alongside `igniteui-webcomponents`, the brand tokens automatically re-tint from the igniteui palette (`--ig-primary-500`); no configuration needed.
158
+ If you embed the grid in an Ignite UI app, the brand tokens automatically re-tint from its palette, wherever it is declared: they read `--ig-primary-500` with the grid's own default as the fallback. That is a plain CSS variable lookup, so the grid neither depends on nor bundles Ignite UI.
137
159
 
138
160
  ### 4. Size the host
139
161
 
@@ -281,7 +303,7 @@ A persistent vertical divider on each column header's trailing edge, on by defau
281
303
  grid.columnSeparator = false; // hide the dividers
282
304
  ```
283
305
 
284
- Theme the line with `--ag-header-separator` (or the `--header-separator-color` / `--igx-header-separator-color` override hooks) and set its vertical inset with `--apex-header-separator-inset`. Because the default is `true`, disable it through the property rather than markup (a default-on boolean attribute cannot be turned off by attribute alone). Attribute: `column-separator`.
306
+ Theme the line with `--ag-header-separator` (or the `--header-separator-color` override hook) and set its vertical inset with `--apex-header-separator-inset`. Because the default is `true`, disable it through the property rather than markup (a default-on boolean attribute cannot be turned off by attribute alone). Attribute: `column-separator`.
285
307
 
286
308
  ### Column groups (spanning headers)
287
309
 
@@ -317,6 +339,33 @@ grid.cancelEdit();
317
339
 
318
340
  `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.
319
341
 
342
+ For programmatic writes, `applyEdits()` takes many cells at once:
343
+
344
+ ```ts
345
+ const { applied, invalid, skipped } = grid.applyEdits([
346
+ { rowIndex: 0, column: 'name', value: 'Ada' },
347
+ { rowIndex: 1, column: 'age', value: 36 },
348
+ ]);
349
+ ```
350
+
351
+ Each write goes through the same choke point interactive editing uses, so it
352
+ emits `cellValueChanging` / `cellValueChanged` and runs the column's validators.
353
+ What differs from looping over `editCell` + `commitEdit` is that the whole batch
354
+ lands as **one** undo step and triggers **one** pipeline run — a thousand
355
+ round-trips would otherwise mean a thousand undo entries and a thousand
356
+ re-renders. The returned tally splits `applied` from `unchanged`, `invalid`,
357
+ `cancelled`, and `skipped`, so a rejected batch is distinguishable from a no-op
358
+ one. Edits naming a row out of range or a column the user could not edit either
359
+ are skipped rather than throwing.
360
+
361
+ `rowIndex` is view-relative, so it reaches the current page only. To edit rows
362
+ anywhere (other pages, pinned rows, rows under a collapsed tree parent), name
363
+ the record itself with `row`:
364
+
365
+ ```ts
366
+ grid.applyEdits(grid.selectedRows.map((row) => ({ row, column: 'discount', value: 0 })));
367
+ ```
368
+
320
369
  ### Keyboard navigation and accessibility
321
370
 
322
371
  The grid body is a single tab stop: Tab enters the grid, and the active cell
@@ -399,7 +448,7 @@ grid.unpinRow(data[0]);
399
448
  grid.pinnedRows; // { top: T[], bottom: T[] }
400
449
  ```
401
450
 
402
- Pinned rows render in sticky top / bottom bands outside the virtualizer and are lifted out of the scrollable set (no duplication). Selection and styling work by row reference. Events: `rowPinning` (cancellable), `rowPinned`.
451
+ Pinned rows render in sticky top / bottom bands outside the virtualizer and are lifted out of the scrollable set (no duplication). Selection and styling work by row reference. Replacing `grid.data` carries the pins onto the new rows (by `rowId` when set, else a pin whose row left the data is dropped). While `rowPinning.enabled` is false the pinned rows return to the body and `pinnedRows` reports none, but the pins are kept (`getState` still saves them) and re-enabling brings them back. Events: `rowPinning` (cancellable), `rowPinned`.
403
452
 
404
453
  ### Row drag-reorder
405
454
 
@@ -409,7 +458,7 @@ grid.rowReordering = { enabled: true }; // add applyToData: true to splice gri
409
458
  grid.moveRow(0, 4, 'after');
410
459
  ```
411
460
 
412
- By default (`rowReordering.handle`, boolean, default `true`) a six-dot grip handle shows at the start of every reorderable row, and dragging lifts a full-row floating ghost that follows the cursor. Both interaction modes are supported: **handle mode** (only the grip starts a drag, so the rest of the row stays free for selection and editing) and **whole-row mode** (set `handle: false` to drag from anywhere on the row, excluding interactive sub-parts like inputs and buttons). Or use the keyboard: focus a row, **Space** to grab, **Arrow** keys to move, **Space / Enter** to drop, **Esc** to cancel. The grid holds a manual order that is mutually exclusive with sorting (applying a sort clears it). By default the app persists the order via the `rowMoved` event; set `applyToData: true` to splice `grid.data` directly. Events: `rowMoving` (cancellable), `rowMoved { from, to, data }`.
461
+ By default (`rowReordering.handle`, boolean, default `true`) a six-dot grip handle shows at the start of every reorderable row, and dragging lifts a full-row floating ghost that follows the cursor. Both interaction modes are supported: **handle mode** (only the grip starts a drag, so the rest of the row stays free for selection and editing) and **whole-row mode** (set `handle: false` to drag from anywhere on the row, excluding interactive sub-parts like inputs and buttons). Or use the keyboard: focus a row, **Space** to grab, **Arrow** keys to move, **Space / Enter** to drop, **Esc** to cancel. The grid holds a manual order that is mutually exclusive with sorting (applying a sort clears it, and a move clears the sort). Rows hidden by a filter keep their place when a visible row moves, and the order follows `grid.data` when it is replaced (by `rowId` when set). By default the app persists the order via the `rowMoved` event; set `applyToData: true` to splice `grid.data` directly. Events: `rowMoving` (cancellable), `rowMoved { from, to, position, toIndex, data }`, where `toIndex` is the view index the row lands at.
413
462
 
414
463
  ### Row expansion (master-detail)
415
464
 
@@ -497,7 +546,7 @@ Search input has a `debounce` attribute (default `200`ms).
497
546
 
498
547
  ### Theming
499
548
 
500
- 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.
549
+ The grid styles itself through `--ag-*` CSS custom properties; override them on `apex-grid` or any ancestor (shadow hosts included) to rebrand, and use `--ag-dark-*` for dark grids. See [Customize the look](#3-optional-customize-the-look) and [`src/styles/_token-values.scss`](src/styles/_token-values.scss) for the full list. Where an Ignite UI palette is present, the brand tokens auto-tint from `--ig-primary-500`.
501
550
 
502
551
  Style with CSS parts on the grid, paginator, and toolbar:
503
552
 
@@ -506,6 +555,50 @@ apex-grid::part(paginator) { background: var(--surface-2); }
506
555
  apex-grid-toolbar::part(search-input) { font-family: var(--font-mono); }
507
556
  ```
508
557
 
558
+ Body rows re-export these parts, so `apex-grid::part(name)` reaches them:
559
+
560
+ | Part | What |
561
+ |---|---|
562
+ | `cell` | A data cell |
563
+ | `selection-cell`, `selection-checkbox` | Selection column cell and its checkbox |
564
+ | `expansion-cell`, `expansion-toggle`, `expansion-chevron` | Expansion column cell, its button and the chevron icon |
565
+ | `detail-panel` | Expanded detail panel container |
566
+ | `row-number-cell`, `row-number` | Row-number gutter cell and its label (`coordinateHints`) |
567
+ | `reorder-handle-cell`, `reorder-handle`, `reorder-grip` | Row-reorder grip cell, handle and icon (handle mode) |
568
+ | `group-row` | Default container of a row a feature module renders full width |
569
+
570
+ Parts used inside your own `detailTemplate` content are re-exported when you list them in `expansion.exportParts`:
571
+
572
+ ```js
573
+ grid.expansion = {
574
+ enabled: true,
575
+ exportParts: ['order-summary'],
576
+ detailTemplate: ({ data }) => html`<div part="order-summary">${data.total}</div>`,
577
+ };
578
+ ```
579
+
580
+ ### Right-to-left
581
+
582
+ Set `dir="rtl"` on the grid or any ancestor and the whole grid mirrors — no
583
+ separate stylesheet, build flag, or option:
584
+
585
+ ```html
586
+ <html dir="rtl">
587
+ <apex-grid id="grid"></apex-grid>
588
+ </html>
589
+ ```
590
+
591
+ The stylesheets are written entirely in logical properties (`inline-size`,
592
+ `inset-inline-start`, `border-inline-end`, …), so layout, pinning, and the fill
593
+ handle follow the text direction on their own. The direction is read from the
594
+ *computed* style, so inheriting it from `<html>` or a wrapper works as well as
595
+ setting it on the grid.
596
+
597
+ Behaviour that reasons in physical directions mirrors too: ArrowLeft moves to the
598
+ next column rather than the previous one, column resize grows the column as the
599
+ pointer moves toward the (now left-hand) inline-end edge, and a column drag drops
600
+ on the side the cursor actually crossed.
601
+
509
602
  ### Spreadsheet coordinates
510
603
 
511
604
  ```ts
@@ -649,7 +742,7 @@ All events bubble and are composed across shadow boundaries. Names ending in `-i
649
742
  | `historyChanged` | no | `{ canUndo, canRedo }` |
650
743
  | `rowSelecting` / `rowSelected` | yes / no | `{ added, removed }` |
651
744
  | `rowPinning` / `rowPinned` | yes / no | `{ row, position }` |
652
- | `rowMoving` / `rowMoved` | yes / no | `{ from, to, data }` |
745
+ | `rowMoving` / `rowMoved` | yes / no | `{ from, to, position, toIndex, data }` |
653
746
  | `rowExpanding` / `rowExpanded` | yes / no | row context |
654
747
  | `treeRowExpanding` / `treeRowExpanded` | yes / no | row context |
655
748
  | `stateChanged` | no | `{ state }` (debounced; only while listened) |
@@ -46,13 +46,30 @@ export default class ApexGridCell<T extends object> extends LitElement {
46
46
  * auto-rendered selection + expansion columns ahead of the data columns.
47
47
  */
48
48
  colindex: number;
49
+ /**
50
+ * The parent row's view index, set by the row. Changing it re-decorates the
51
+ * cell (decoration such as a range selection is positional), so a row that
52
+ * moves with the same data (sort, filter, an expand above it) never keeps a
53
+ * stale highlight.
54
+ *
55
+ * @internal
56
+ */
57
+ rowIndex: number;
49
58
  /**
50
59
  * Reactive token forwarded from {@link StateController.decorationVersion}.
51
- * Changing it re-runs {@link willUpdate} so module-driven cell decoration is
52
- * re-evaluated when it changes (e.g. while dragging a selection range). Stays
53
- * `0` for the community grid, so cells are never re-decorated there.
60
+ * Changing it re-applies module-driven cell decoration (e.g. while dragging a
61
+ * selection range) without re-rendering the cell content. Stays `0` for the
62
+ * community grid, so cells are never re-decorated there.
54
63
  */
55
64
  decorationVersion: number;
65
+ /**
66
+ * Reactive token forwarded from {@link StateController.dataVersion}, bumped
67
+ * once per pipeline run. Re-renders only a cell that reads its row beyond
68
+ * its own value (see {@link shouldUpdate}).
69
+ *
70
+ * @internal
71
+ */
72
+ dataVersion: number;
56
73
  /**
57
74
  * Reactive token forwarded from {@link EditingController.validationVersion}.
58
75
  * Changing it re-runs {@link willUpdate} so the cell re-reads its validation
@@ -62,7 +79,16 @@ export default class ApexGridCell<T extends object> extends LitElement {
62
79
  validationVersion: number;
63
80
  connectedCallback(): void;
64
81
  disconnectedCallback(): void;
65
- protected willUpdate(): void;
82
+ /**
83
+ * Skips the render when only positional or decoration tokens changed: the
84
+ * decoration is host attributes, so it is reconciled here and the cell
85
+ * template (type renderers, user templates) is not re-run. A cell that reads
86
+ * its row beyond {@link value} (a `cellTemplate`, which may read other fields
87
+ * or the row index, or the tree group cell, whose chevron shows the row's
88
+ * expansion) still renders when the row index or the data token moves.
89
+ */
90
+ protected shouldUpdate(changed: PropertyValues<this>): boolean;
91
+ protected willUpdate(changed: PropertyValues<this>): void;
66
92
  /**
67
93
  * The inline error node surfaced when the cell is invalid. `role="alert"`
68
94
  * announces the message when it appears, covering the cross-shadow gap where