apex-grid 3.2.0 → 3.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.
Files changed (197) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +200 -52
  3. package/components/cell.d.ts +14 -1
  4. package/components/cell.js +48 -6
  5. package/components/cell.js.map +1 -1
  6. package/components/filter-row.d.ts +3 -6
  7. package/components/filter-row.js +79 -109
  8. package/components/filter-row.js.map +1 -1
  9. package/components/grid.d.ts +416 -77
  10. package/components/grid.js +398 -11
  11. package/components/grid.js.map +1 -1
  12. package/components/group-header-row.d.ts +34 -0
  13. package/components/group-header-row.js +125 -0
  14. package/components/group-header-row.js.map +1 -0
  15. package/components/header-row.d.ts +13 -2
  16. package/components/header-row.js +33 -18
  17. package/components/header-row.js.map +1 -1
  18. package/components/header.d.ts +11 -0
  19. package/components/header.js +135 -5
  20. package/components/header.js.map +1 -1
  21. package/components/paginator.d.ts +6 -1
  22. package/components/paginator.js +17 -11
  23. package/components/paginator.js.map +1 -1
  24. package/components/row.d.ts +28 -0
  25. package/components/row.js +100 -3
  26. package/components/row.js.map +1 -1
  27. package/components/toolbar.d.ts +8 -1
  28. package/components/toolbar.js +25 -7
  29. package/components/toolbar.js.map +1 -1
  30. package/controllers/data-operation.js +1 -0
  31. package/controllers/data-operation.js.map +1 -1
  32. package/controllers/dom.d.ts +24 -6
  33. package/controllers/dom.js +62 -5
  34. package/controllers/dom.js.map +1 -1
  35. package/controllers/editing.d.ts +68 -1
  36. package/controllers/editing.js +129 -44
  37. package/controllers/editing.js.map +1 -1
  38. package/controllers/filter.d.ts +1 -1
  39. package/controllers/filter.js +16 -5
  40. package/controllers/filter.js.map +1 -1
  41. package/controllers/history.d.ts +86 -0
  42. package/controllers/history.js +118 -0
  43. package/controllers/history.js.map +1 -0
  44. package/controllers/navigation.d.ts +15 -0
  45. package/controllers/navigation.js +53 -0
  46. package/controllers/navigation.js.map +1 -1
  47. package/controllers/reorder.js +3 -1
  48. package/controllers/reorder.js.map +1 -1
  49. package/controllers/row-pin.d.ts +59 -0
  50. package/controllers/row-pin.js +75 -0
  51. package/controllers/row-pin.js.map +1 -0
  52. package/controllers/row-reorder.d.ts +161 -0
  53. package/controllers/row-reorder.js +332 -0
  54. package/controllers/row-reorder.js.map +1 -0
  55. package/controllers/sort.js +9 -1
  56. package/controllers/sort.js.map +1 -1
  57. package/controllers/state.d.ts +33 -0
  58. package/controllers/state.js +37 -2
  59. package/controllers/state.js.map +1 -1
  60. package/controllers/tree.d.ts +8 -0
  61. package/controllers/tree.js +0 -0
  62. package/controllers/tree.js.map +1 -1
  63. package/custom-elements.json +4411 -886
  64. package/docs/assets/hierarchy.js +1 -1
  65. package/docs/assets/highlight.css +28 -0
  66. package/docs/assets/navigation.js +1 -1
  67. package/docs/assets/search.js +1 -1
  68. package/docs/functions/custom.html +3 -0
  69. package/docs/functions/interpolate.html +4 -0
  70. package/docs/functions/localize.html +8 -0
  71. package/docs/functions/max.html +3 -0
  72. package/docs/functions/min.html +3 -0
  73. package/docs/functions/pattern.html +3 -0
  74. package/docs/functions/required.html +3 -0
  75. package/docs/hierarchy.html +1 -1
  76. package/docs/index.html +184 -54
  77. package/docs/interfaces/ApexCellValidationFailedEvent.html +13 -0
  78. package/docs/interfaces/ApexCellValueChangedEvent.html +1 -1
  79. package/docs/interfaces/ApexCellValueChangingEvent.html +2 -2
  80. package/docs/interfaces/ApexColumnGroupContext.html +6 -0
  81. package/docs/interfaces/ApexColumnMovedEvent.html +2 -2
  82. package/docs/interfaces/ApexColumnMovingEvent.html +1 -1
  83. package/docs/interfaces/ApexDetailContext.html +2 -2
  84. package/docs/interfaces/ApexGridEventMap.html +37 -9
  85. package/docs/interfaces/ApexHistoryChangedEvent.html +6 -0
  86. package/docs/interfaces/ApexPageChangedEvent.html +1 -1
  87. package/docs/interfaces/ApexRowMovingEvent.html +9 -0
  88. package/docs/interfaces/ApexRowPinningEvent.html +8 -0
  89. package/docs/interfaces/ApexStateChangedEvent.html +4 -0
  90. package/docs/interfaces/BaseApexCellContext.html +1 -1
  91. package/docs/interfaces/BaseApexEditorContext.html +1 -1
  92. package/docs/interfaces/BaseColumnConfiguration.html +42 -17
  93. package/docs/interfaces/CSVExportOptions.html +2 -2
  94. package/docs/interfaces/ColumnGroupConfiguration.html +12 -0
  95. package/docs/interfaces/ColumnLayoutState.html +2 -0
  96. package/docs/interfaces/ColumnSchema.html +22 -0
  97. package/docs/interfaces/DataPipelineConfiguration.html +2 -2
  98. package/docs/interfaces/EditingHistoryConfiguration.html +10 -0
  99. package/docs/interfaces/ExportFormat.html +2 -2
  100. package/docs/interfaces/ExportOptions.html +1 -1
  101. package/docs/interfaces/FilterStateSnapshot.html +4 -0
  102. package/docs/interfaces/GetStateOptions.html +4 -0
  103. package/docs/interfaces/GridCapabilities.html +8 -0
  104. package/docs/interfaces/GridEditingConfiguration.html +4 -2
  105. package/docs/interfaces/GridRowPinningConfiguration.html +5 -0
  106. package/docs/interfaces/GridRowReorderingConfiguration.html +22 -0
  107. package/docs/interfaces/GridSchema.html +19 -0
  108. package/docs/interfaces/GridState.html +41 -0
  109. package/docs/interfaces/GridTreeConfiguration.html +2 -2
  110. package/docs/interfaces/PaginationConfiguration.html +1 -1
  111. package/docs/interfaces/PaginationState.html +1 -1
  112. package/docs/interfaces/SetStateOptions.html +9 -0
  113. package/docs/interfaces/SetStateResult.html +11 -0
  114. package/docs/interfaces/SortStateSnapshot.html +2 -0
  115. package/docs/interfaces/ValidatorContext.html +8 -0
  116. package/docs/media/_tokens.scss +70 -81
  117. package/docs/media/package.json +1 -1
  118. package/docs/media/state-persistence.html +189 -0
  119. package/docs/modules.html +1 -1
  120. package/docs/types/DataPipelineParams.html +2 -2
  121. package/docs/types/EditMode.html +2 -2
  122. package/docs/types/GridLocaleKey.html +3 -0
  123. package/docs/types/GridLocaleText.html +5 -0
  124. package/docs/types/LocaleParams.html +2 -0
  125. package/docs/types/PaginationMode.html +1 -1
  126. package/docs/types/RowDropPosition.html +2 -0
  127. package/docs/types/RowPinPosition.html +2 -0
  128. package/docs/types/RowRef.html +3 -0
  129. package/docs/types/Validator.html +4 -0
  130. package/docs/variables/EN_LOCALE.html +9 -0
  131. package/docs/variables/esLocale.html +8 -0
  132. package/i18n/en.d.ts +151 -0
  133. package/i18n/en.js +125 -0
  134. package/i18n/en.js.map +1 -0
  135. package/i18n/es.d.ts +18 -0
  136. package/i18n/es.js +125 -0
  137. package/i18n/es.js.map +1 -0
  138. package/i18n/index.d.ts +3 -0
  139. package/i18n/index.js +4 -0
  140. package/i18n/index.js.map +1 -0
  141. package/i18n/localize.d.ts +23 -0
  142. package/i18n/localize.js +15 -0
  143. package/i18n/localize.js.map +1 -0
  144. package/index.d.ts +8 -2
  145. package/index.js +2 -0
  146. package/index.js.map +1 -1
  147. package/internal/feature-module.d.ts +46 -0
  148. package/internal/feature-module.js +11 -0
  149. package/internal/feature-module.js.map +1 -1
  150. package/internal/flip.js +1 -1
  151. package/internal/flip.js.map +1 -1
  152. package/internal/icons.d.ts +9 -7
  153. package/internal/icons.js +75 -35
  154. package/internal/icons.js.map +1 -1
  155. package/internal/index.d.ts +5 -3
  156. package/internal/index.js +2 -1
  157. package/internal/index.js.map +1 -1
  158. package/internal/state-schema.d.ts +85 -0
  159. package/internal/state-schema.js +27 -0
  160. package/internal/state-schema.js.map +1 -0
  161. package/internal/state-snapshot.d.ts +152 -0
  162. package/internal/state-snapshot.js +115 -0
  163. package/internal/state-snapshot.js.map +1 -0
  164. package/internal/tags.d.ts +1 -0
  165. package/internal/tags.js +1 -0
  166. package/internal/tags.js.map +1 -1
  167. package/internal/types.d.ts +162 -2
  168. package/internal/types.js.map +1 -1
  169. package/internal/utils.d.ts +12 -0
  170. package/internal/utils.js +17 -0
  171. package/internal/utils.js.map +1 -1
  172. package/internal/validators.d.ts +31 -0
  173. package/internal/validators.js +44 -0
  174. package/internal/validators.js.map +1 -0
  175. package/package.json +1 -1
  176. package/styles/_tokens.css.js +1 -1
  177. package/styles/_tokens.css.js.map +1 -1
  178. package/styles/body-cell/body-cell.css.js +1 -1
  179. package/styles/body-cell/body-cell.css.js.map +1 -1
  180. package/styles/body-row/body-row.css.js +1 -1
  181. package/styles/body-row/body-row.css.js.map +1 -1
  182. package/styles/filter-row/filter-row.css.js +1 -1
  183. package/styles/filter-row/filter-row.css.js.map +1 -1
  184. package/styles/grid/_grid.base.css.js +1 -1
  185. package/styles/grid/_grid.base.css.js.map +1 -1
  186. package/styles/grid/grid.css.js +1 -1
  187. package/styles/grid/grid.css.js.map +1 -1
  188. package/styles/group-header-row/group-header-row.css.d.ts +1 -0
  189. package/styles/group-header-row/group-header-row.css.js +3 -0
  190. package/styles/group-header-row/group-header-row.css.js.map +1 -0
  191. package/styles/header-cell/header-cell.css.js +1 -1
  192. package/styles/header-cell/header-cell.css.js.map +1 -1
  193. package/styles/header-row/header-row.base.css.js +1 -1
  194. package/styles/header-row/header-row.base.css.js.map +1 -1
  195. package/styles/toolbar/toolbar.css.js +1 -1
  196. package/styles/toolbar/toolbar.css.js.map +1 -1
  197. package/docs/classes/ApexGrid.html +0 -399
@@ -1 +1 @@
1
- {"version":3,"file":"dom.js","sourceRoot":"","sources":["../../src/controllers/dom.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RenderItemFunction } from '@lit-labs/virtualizer/virtualize.js';\nimport { html, type ReactiveController } from 'lit';\nimport { type StyleInfo, styleMap } from 'lit/directives/style-map.js';\nimport type { ColumnConfiguration, GridHost, Keys } from '../internal/types.js';\nimport { applyColumnWidths, getDisplayColumns } from '../internal/utils.js';\nimport type { StateController } from './state.js';\n\nexport class GridDOMController<T extends object> implements ReactiveController {\n constructor(\n protected host: GridHost<T>,\n protected state: StateController<T>\n ) {\n this.host.addController(this);\n }\n\n #initialSize = () => {\n setTimeout(() => {\n this.setScrollOffset();\n this.recomputePinOffsets();\n this.recomputeStickyRowOffsets();\n });\n };\n\n #resizeObserver: ResizeObserver | null = null;\n #observedHeaders = new Set<Element>();\n #stickyRowObserver: ResizeObserver | null = null;\n #observedStickyRows = new Set<Element>();\n\n public get container() {\n // @ts-expect-error: protected member access\n return this.host.scrollContainer;\n }\n\n /**\n * Visual render order: `'start'`-pinned columns first, then unpinned, then\n * `'end'`-pinned. The user-supplied `columns` array is never mutated.\n */\n public get displayColumns(): Array<ColumnConfiguration<T>> {\n return getDisplayColumns(this.host.columns);\n }\n\n public columnSizes: StyleInfo = {};\n\n /**\n * The resolved inline-start (for `'start'` pin) or inline-end (for `'end'` pin)\n * pixel offset per pinned column key. Populated after layout by\n * {@link recomputePinOffsets}.\n */\n public pinOffsets = new Map<Keys<T>, number>();\n\n public rowRenderer: RenderItemFunction<T> = (data: T, index: number) => {\n const editingCell = this.state.editing.activeCell;\n const editingKey = editingCell?.rowIndex === index ? editingCell.columnKey : null;\n // aria-rowindex offset: header row is always row 1; filter row (when\n // any column has a filter configured) sits at row 2; body rows start\n // immediately after.\n const hasFilter = this.host.columns.some((column) => column.filter);\n const ariaRowOffset = hasFilter ? 2 : 1;\n return html`\n <apex-grid-row\n part=\"row\"\n style=${styleMap({ ...this.columnSizes, ...this.getActiveRowStyles(index) })}\n .index=${index}\n .activeNode=${this.state.active}\n .data=${data}\n .columns=${this.displayColumns}\n .pinOffsets=${this.pinOffsets}\n .editingKey=${editingKey}\n .ariaRowOffset=${ariaRowOffset}\n .decorationVersion=${this.state.decorationVersion}\n >\n </apex-grid-row>\n `;\n };\n\n public async hostConnected() {\n this.setGridColumnSizes();\n // Wait for the initial paint of the virtualizer and recalculate the scrollbar offset\n // for the next one\n await this.host.updateComplete;\n this.#initialSize();\n if (typeof ResizeObserver !== 'undefined' && !this.#hostWidthObserver) {\n this.#hostWidthObserver = new ResizeObserver(() => {\n requestAnimationFrame(() => this.recomputeHostWidth());\n });\n this.#hostWidthObserver.observe(this.host as HTMLElement);\n }\n this.recomputeHostWidth();\n }\n\n public hostUpdate(): void {\n this.setScrollOffset();\n this.setGridColumnSizes();\n }\n\n public hostUpdated(): void {\n this.recomputePinOffsets();\n this.observeHeaderCells();\n this.recomputeStickyRowOffsets();\n this.observeStickyRows();\n }\n\n public hostDisconnected(): void {\n this.#resizeObserver?.disconnect();\n this.#resizeObserver = null;\n this.#observedHeaders.clear();\n this.#stickyRowObserver?.disconnect();\n this.#stickyRowObserver = null;\n this.#observedStickyRows.clear();\n this.#hostWidthObserver?.disconnect();\n this.#hostWidthObserver = null;\n }\n\n /**\n * Writes the grid host's `clientWidth` into `--apex-host-width`. Used by the\n * toolbar and paginator to clamp their width to the visible viewport so\n * horizontal scrolling doesn't drag them off-screen.\n */\n public recomputeHostWidth(): void {\n const host = this.host as HTMLElement;\n const width = host.clientWidth;\n if (width === this.#lastHostWidth) return;\n host.style.setProperty('--apex-host-width', `${width}px`);\n this.#lastHostWidth = width;\n }\n\n public setScrollOffset() {\n // The grid host now owns vertical scrolling, so the historic per-row\n // padding-inline-end compensation is no longer needed. Keep the CSS var\n // set to `0` for forward compatibility with consumer themes that read it.\n this.host.style.setProperty('--scrollbar-offset', '0px');\n }\n\n protected setGridColumnSizes() {\n this.columnSizes = applyColumnWidths(this.displayColumns, {\n showSelectionColumn: this.state.selection.showCheckboxColumn,\n showExpansionColumn: this.state.expansion.showToggleColumn,\n });\n }\n\n public getActiveRowStyles(index: number): StyleInfo {\n const { row } = this.state.active;\n return row === index ? { 'z-index': '3' } : {};\n }\n\n /**\n * Measures the rendered widths of pinned header cells and writes cumulative\n * inline-start / inline-end pixel offsets into {@link pinOffsets}. Called after\n * each grid update and whenever a header cell is resized.\n */\n public recomputePinOffsets(): void {\n // @ts-expect-error - protected member access\n const headerRow = this.host.headerRow as\n | {\n headers?: Array<{\n column: ColumnConfiguration<T>;\n getBoundingClientRect: () => DOMRect;\n }>;\n }\n | undefined;\n if (!headerRow?.headers) return;\n\n const next = new Map<Keys<T>, number>();\n const headersByKey = new Map<Keys<T>, DOMRect>();\n for (const header of headerRow.headers) {\n headersByKey.set(header.column.key as Keys<T>, header.getBoundingClientRect());\n }\n\n let leftAccum = 0;\n for (const column of this.displayColumns) {\n if (column.hidden) continue;\n if (column.pinned !== 'start') break;\n next.set(column.key as Keys<T>, leftAccum);\n const rect = headersByKey.get(column.key as Keys<T>);\n leftAccum += rect?.width ?? 0;\n }\n\n let rightAccum = 0;\n for (let i = this.displayColumns.length - 1; i >= 0; i--) {\n const column = this.displayColumns[i];\n if (column.hidden) continue;\n if (column.pinned !== 'end') break;\n next.set(column.key as Keys<T>, rightAccum);\n const rect = headersByKey.get(column.key as Keys<T>);\n rightAccum += rect?.width ?? 0;\n }\n\n if (!offsetsEqual(this.pinOffsets, next)) {\n this.pinOffsets = next;\n this.host.requestUpdate();\n }\n }\n\n protected observeHeaderCells(): void {\n // @ts-expect-error - protected member access\n const headerRow = this.host.headerRow as { headers?: Array<Element> } | undefined;\n if (!headerRow?.headers) return;\n\n if (!this.#resizeObserver) {\n this.#resizeObserver = new ResizeObserver(() => {\n // Defer to a new frame so any layout writes can't synchronously feed back\n // into this observer (which makes the browser raise the benign\n // \"ResizeObserver loop completed\" warning).\n requestAnimationFrame(() => this.recomputePinOffsets());\n });\n }\n\n const next = new Set<Element>(headerRow.headers);\n for (const element of this.#observedHeaders) {\n if (!next.has(element)) this.#resizeObserver.unobserve(element);\n }\n for (const element of next) {\n if (!this.#observedHeaders.has(element)) this.#resizeObserver.observe(element);\n }\n this.#observedHeaders = next;\n }\n\n #lastHeaderTop = -1;\n #lastFilterTop = -1;\n #lastHostWidth = -1;\n #hostWidthObserver: ResizeObserver | null = null;\n\n /**\n * Writes the cumulative height of the sticky top rows into CSS custom\n * properties used by the header/filter rows for their `inset-block-start`\n * offsets. The toolbar is always at `top: 0`; the header sits below it\n * (`--apex-row-top-header`) and the filter sits below the header\n * (`--apex-row-top-filter`). Writes are skipped when the values haven't\n * changed so the ResizeObserver feedback loop terminates.\n */\n public recomputeStickyRowOffsets(): void {\n const root = (this.host as HTMLElement).shadowRoot;\n if (!root) return;\n const toolbar = root.querySelector('apex-grid-toolbar') as HTMLElement | null;\n const header = root.querySelector('apex-grid-header-row') as HTMLElement | null;\n\n const toolbarH = toolbar?.offsetHeight ?? 0;\n const headerH = header?.offsetHeight ?? 0;\n const headerTop = toolbarH;\n const filterTop = toolbarH + headerH;\n\n if (headerTop !== this.#lastHeaderTop) {\n this.host.style.setProperty('--apex-row-top-header', `${headerTop}px`);\n this.#lastHeaderTop = headerTop;\n }\n if (filterTop !== this.#lastFilterTop) {\n this.host.style.setProperty('--apex-row-top-filter', `${filterTop}px`);\n this.#lastFilterTop = filterTop;\n }\n }\n\n protected observeStickyRows(): void {\n const root = (this.host as HTMLElement).shadowRoot;\n if (!root) return;\n const toolbar = root.querySelector('apex-grid-toolbar') as HTMLElement | null;\n const header = root.querySelector('apex-grid-header-row') as HTMLElement | null;\n\n if (!this.#stickyRowObserver) {\n this.#stickyRowObserver = new ResizeObserver(() => {\n requestAnimationFrame(() => this.recomputeStickyRowOffsets());\n });\n }\n\n const next = new Set<Element>([toolbar, header].filter((el): el is HTMLElement => !!el));\n for (const element of this.#observedStickyRows) {\n if (!next.has(element)) this.#stickyRowObserver.unobserve(element);\n }\n for (const element of next) {\n if (!this.#observedStickyRows.has(element)) this.#stickyRowObserver.observe(element);\n }\n this.#observedStickyRows = next;\n }\n}\n\nfunction offsetsEqual<K>(a: Map<K, number>, b: Map<K, number>): boolean {\n if (a.size !== b.size) return false;\n for (const [key, value] of a) {\n if (b.get(key) !== value) return false;\n }\n return true;\n}\n"]}
1
+ {"version":3,"file":"dom.js","sourceRoot":"","sources":["../../src/controllers/dom.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RenderItemFunction } from '@lit-labs/virtualizer/virtualize.js';\nimport { html, type ReactiveController } from 'lit';\nimport { type StyleInfo, styleMap } from 'lit/directives/style-map.js';\nimport { SENTINEL_NODE } from '../internal/constants.js';\nimport type { ActiveNode, ColumnConfiguration, GridHost, Keys } from '../internal/types.js';\nimport { applyColumnWidths, getDisplayColumns } from '../internal/utils.js';\nimport type { StateController } from './state.js';\n\nexport class GridDOMController<T extends object> implements ReactiveController {\n constructor(\n protected host: GridHost<T>,\n protected state: StateController<T>\n ) {\n this.host.addController(this);\n }\n\n #initialSize = () => {\n setTimeout(() => {\n this.setScrollOffset();\n this.recomputePinOffsets();\n this.recomputeStickyRowOffsets();\n });\n };\n\n #resizeObserver: ResizeObserver | null = null;\n #observedHeaders = new Set<Element>();\n #stickyRowObserver: ResizeObserver | null = null;\n #observedStickyRows = new Set<Element>();\n\n public get container() {\n // @ts-expect-error: protected member access\n return this.host.scrollContainer;\n }\n\n /**\n * Visual render order: `'start'`-pinned columns first, then unpinned, then\n * `'end'`-pinned. The user-supplied `columns` array is never mutated.\n */\n public get displayColumns(): Array<ColumnConfiguration<T>> {\n return getDisplayColumns(this.host.columns);\n }\n\n public columnSizes: StyleInfo = {};\n\n /**\n * The resolved inline-start (for `'start'` pin) or inline-end (for `'end'` pin)\n * pixel offset per pinned column key. Populated after layout by\n * {@link recomputePinOffsets}.\n */\n public pinOffsets = new Map<Keys<T>, number>();\n\n /**\n * Number of chrome rows above the body for `aria-rowindex`: an optional group\n * header row and the column header (always present). The filter panel is a\n * floating overlay rather than a table row, so it is not counted here.\n */\n protected get headerRowCount(): number {\n return this.host.columnGroupDepth + 1;\n }\n\n public rowRenderer: RenderItemFunction<T> = (data: T, index: number) => {\n const editingCell = this.state.editing.activeCell;\n const editingKey = editingCell?.rowIndex === index ? editingCell.columnKey : null;\n // Body rows follow the chrome rows and any pinned-top rows in the\n // aria-rowindex sequence.\n const ariaRowOffset = this.headerRowCount + this.state.rowPin.pinnedRows.top.length;\n return html`\n <apex-grid-row\n part=\"row\"\n style=${styleMap({ ...this.columnSizes, ...this.getActiveRowStyles(index) })}\n .index=${index}\n .activeNode=${this.state.active}\n .data=${data}\n .columns=${this.displayColumns}\n .pinOffsets=${this.pinOffsets}\n .editingKey=${editingKey}\n .ariaRowOffset=${ariaRowOffset}\n .decorationVersion=${this.state.decorationVersion}\n .validationVersion=${this.state.editing.validationVersion}\n .dragging=${this.state.rowReorder.dragging === data}\n .grabbed=${this.state.rowReorder.grabbed === data}\n .coordinateHints=${Boolean(this.host.coordinateHints)}\n >\n </apex-grid-row>\n `;\n };\n\n /**\n * Renders a single pinned row for a sticky band. Reuses {@link ApexGridRow}\n * so selection / expansion / decoration all work by data reference, but pins a\n * sentinel {@link ActiveNode} (pinned rows are presentation + selection\n * surfaces in v1, never the active/edited cell) and renders no editor.\n *\n * @param localIndex - position within the band (drives the active sentinel id).\n * @param ariaRowOffset - so `aria-rowindex` continues the unified sequence.\n */\n public pinnedRowRenderer(data: T, localIndex: number, ariaRowOffset: number) {\n return html`\n <apex-grid-row\n part=\"row pinned-row\"\n style=${styleMap(this.columnSizes)}\n .index=${localIndex}\n .activeNode=${SENTINEL_NODE as ActiveNode<T>}\n .data=${data}\n .columns=${this.displayColumns}\n .pinOffsets=${this.pinOffsets}\n .editingKey=${null}\n .ariaRowOffset=${ariaRowOffset}\n .decorationVersion=${this.state.decorationVersion}\n .validationVersion=${this.state.editing.validationVersion}\n .coordinateHints=${Boolean(this.host.coordinateHints)}\n >\n </apex-grid-row>\n `;\n }\n\n public async hostConnected() {\n this.setGridColumnSizes();\n // Wait for the initial paint of the virtualizer and recalculate the scrollbar offset\n // for the next one\n await this.host.updateComplete;\n this.#initialSize();\n if (typeof ResizeObserver !== 'undefined' && !this.#hostWidthObserver) {\n this.#hostWidthObserver = new ResizeObserver(() => {\n requestAnimationFrame(() => this.recomputeHostWidth());\n });\n this.#hostWidthObserver.observe(this.host as HTMLElement);\n }\n this.recomputeHostWidth();\n }\n\n public hostUpdate(): void {\n this.setScrollOffset();\n this.setGridColumnSizes();\n }\n\n public hostUpdated(): void {\n this.recomputePinOffsets();\n this.observeHeaderCells();\n this.recomputeStickyRowOffsets();\n this.observeStickyRows();\n }\n\n public hostDisconnected(): void {\n this.#resizeObserver?.disconnect();\n this.#resizeObserver = null;\n this.#observedHeaders.clear();\n this.#stickyRowObserver?.disconnect();\n this.#stickyRowObserver = null;\n this.#observedStickyRows.clear();\n this.#hostWidthObserver?.disconnect();\n this.#hostWidthObserver = null;\n }\n\n /**\n * Writes the grid host's `clientWidth` into `--apex-host-width`. Used by the\n * toolbar and paginator to clamp their width to the visible viewport so\n * horizontal scrolling doesn't drag them off-screen.\n */\n public recomputeHostWidth(): void {\n const host = this.host as HTMLElement;\n const width = host.clientWidth;\n if (width === this.#lastHostWidth) return;\n host.style.setProperty('--apex-host-width', `${width}px`);\n this.#lastHostWidth = width;\n }\n\n public setScrollOffset() {\n // The grid host now owns vertical scrolling, so the historic per-row\n // padding-inline-end compensation is no longer needed. Keep the CSS var\n // set to `0` for forward compatibility with consumer themes that read it.\n this.host.style.setProperty('--scrollbar-offset', '0px');\n }\n\n protected setGridColumnSizes() {\n this.columnSizes = applyColumnWidths(this.displayColumns, {\n showSelectionColumn: this.state.selection.showCheckboxColumn,\n showExpansionColumn: this.state.expansion.showToggleColumn,\n showReorderHandle: this.state.rowReorder.showHandleColumn,\n showRowNumbers: Boolean(this.host.coordinateHints),\n });\n }\n\n public getActiveRowStyles(index: number): StyleInfo {\n const { row } = this.state.active;\n return row === index ? { 'z-index': '3' } : {};\n }\n\n /**\n * Measures the rendered widths of pinned header cells and writes cumulative\n * inline-start / inline-end pixel offsets into {@link pinOffsets}. Called after\n * each grid update and whenever a header cell is resized.\n */\n public recomputePinOffsets(): void {\n // @ts-expect-error - protected member access\n const headerRow = this.host.headerRow as\n | {\n headers?: Array<{\n column: ColumnConfiguration<T>;\n getBoundingClientRect: () => DOMRect;\n }>;\n }\n | undefined;\n if (!headerRow?.headers) return;\n\n const next = new Map<Keys<T>, number>();\n const headersByKey = new Map<Keys<T>, DOMRect>();\n for (const header of headerRow.headers) {\n headersByKey.set(header.column.key as Keys<T>, header.getBoundingClientRect());\n }\n\n let leftAccum = 0;\n for (const column of this.displayColumns) {\n if (column.hidden) continue;\n if (column.pinned !== 'start') break;\n next.set(column.key as Keys<T>, leftAccum);\n const rect = headersByKey.get(column.key as Keys<T>);\n leftAccum += rect?.width ?? 0;\n }\n\n let rightAccum = 0;\n for (let i = this.displayColumns.length - 1; i >= 0; i--) {\n const column = this.displayColumns[i];\n if (column.hidden) continue;\n if (column.pinned !== 'end') break;\n next.set(column.key as Keys<T>, rightAccum);\n const rect = headersByKey.get(column.key as Keys<T>);\n rightAccum += rect?.width ?? 0;\n }\n\n if (!offsetsEqual(this.pinOffsets, next)) {\n this.pinOffsets = next;\n this.host.requestUpdate();\n }\n }\n\n protected observeHeaderCells(): void {\n // @ts-expect-error - protected member access\n const headerRow = this.host.headerRow as { headers?: Array<Element> } | undefined;\n if (!headerRow?.headers) return;\n\n if (!this.#resizeObserver) {\n this.#resizeObserver = new ResizeObserver(() => {\n // Defer to a new frame so any layout writes can't synchronously feed back\n // into this observer (which makes the browser raise the benign\n // \"ResizeObserver loop completed\" warning).\n requestAnimationFrame(() => this.recomputePinOffsets());\n });\n }\n\n const next = new Set<Element>(headerRow.headers);\n for (const element of this.#observedHeaders) {\n if (!next.has(element)) this.#resizeObserver.unobserve(element);\n }\n for (const element of next) {\n if (!this.#observedHeaders.has(element)) this.#resizeObserver.observe(element);\n }\n this.#observedHeaders = next;\n }\n\n #lastGroupTop = -1;\n #lastHeaderTop = -1;\n #lastFilterTop = -1;\n #lastPinnedTop = -1;\n #lastPinnedBottom = -1;\n #lastHostWidth = -1;\n #hostWidthObserver: ResizeObserver | null = null;\n\n /**\n * Writes the cumulative heights of the sticky chrome rows into CSS custom\n * properties used for their `inset-block-start` / `inset-block-end` offsets.\n * The toolbar is at `top: 0`; the header sits below it\n * (`--apex-row-top-header`), the filter below the header\n * (`--apex-row-top-filter`), and the pinned-top band below the filter\n * (`--apex-row-top-pinned`). The pinned-bottom band sticks above the\n * paginator (`--apex-row-bottom-pinned`). Writes are skipped when values are\n * unchanged so the ResizeObserver feedback loop terminates.\n */\n public recomputeStickyRowOffsets(): void {\n const root = (this.host as HTMLElement).shadowRoot;\n if (!root) return;\n const toolbar = root.querySelector('apex-grid-toolbar') as HTMLElement | null;\n const groupHeader = root.querySelector('apex-grid-group-header-row') as HTMLElement | null;\n const header = root.querySelector('apex-grid-header-row') as HTMLElement | null;\n const filter = root.querySelector('apex-filter-row') as HTMLElement | null;\n const paginator = root.querySelector('apex-grid-paginator') as HTMLElement | null;\n\n const toolbarH = toolbar?.offsetHeight ?? 0;\n const groupH = groupHeader?.offsetHeight ?? 0;\n const headerH = header?.offsetHeight ?? 0;\n const filterH = filter?.offsetHeight ?? 0;\n const paginatorH = paginator?.offsetHeight ?? 0;\n // The group header (when present) sits below the toolbar; the column header\n // sits below the group header; filter below header; pinned-top below filter.\n const groupTop = toolbarH;\n const headerTop = toolbarH + groupH;\n const filterTop = toolbarH + groupH + headerH;\n const pinnedTop = toolbarH + groupH + headerH + filterH;\n\n if (groupTop !== this.#lastGroupTop) {\n this.host.style.setProperty('--apex-row-top-group', `${groupTop}px`);\n this.#lastGroupTop = groupTop;\n }\n if (headerTop !== this.#lastHeaderTop) {\n this.host.style.setProperty('--apex-row-top-header', `${headerTop}px`);\n this.#lastHeaderTop = headerTop;\n }\n if (filterTop !== this.#lastFilterTop) {\n this.host.style.setProperty('--apex-row-top-filter', `${filterTop}px`);\n this.#lastFilterTop = filterTop;\n }\n if (pinnedTop !== this.#lastPinnedTop) {\n this.host.style.setProperty('--apex-row-top-pinned', `${pinnedTop}px`);\n this.#lastPinnedTop = pinnedTop;\n }\n if (paginatorH !== this.#lastPinnedBottom) {\n this.host.style.setProperty('--apex-row-bottom-pinned', `${paginatorH}px`);\n this.#lastPinnedBottom = paginatorH;\n }\n }\n\n protected observeStickyRows(): void {\n const root = (this.host as HTMLElement).shadowRoot;\n if (!root) return;\n const toolbar = root.querySelector('apex-grid-toolbar') as HTMLElement | null;\n const groupHeader = root.querySelector('apex-grid-group-header-row') as HTMLElement | null;\n const header = root.querySelector('apex-grid-header-row') as HTMLElement | null;\n const filter = root.querySelector('apex-filter-row') as HTMLElement | null;\n const paginator = root.querySelector('apex-grid-paginator') as HTMLElement | null;\n\n if (!this.#stickyRowObserver) {\n this.#stickyRowObserver = new ResizeObserver(() => {\n requestAnimationFrame(() => this.recomputeStickyRowOffsets());\n });\n }\n\n const next = new Set<Element>(\n [toolbar, groupHeader, header, filter, paginator].filter((el): el is HTMLElement => !!el)\n );\n for (const element of this.#observedStickyRows) {\n if (!next.has(element)) this.#stickyRowObserver.unobserve(element);\n }\n for (const element of next) {\n if (!this.#observedStickyRows.has(element)) this.#stickyRowObserver.observe(element);\n }\n this.#observedStickyRows = next;\n }\n}\n\nfunction offsetsEqual<K>(a: Map<K, number>, b: Map<K, number>): boolean {\n if (a.size !== b.size) return false;\n for (const [key, value] of a) {\n if (b.get(key) !== value) return false;\n }\n return true;\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import type { ReactiveController } from 'lit';
2
2
  import type { ColumnConfiguration, EditMode, EditTrigger, GridHost, Keys } from '../internal/types.js';
3
+ import type { HistoryController } from './history.js';
3
4
  /**
4
5
  * The default editing configuration used when the grid has none set.
5
6
  */
@@ -17,6 +18,28 @@ interface ActiveCell<T> {
17
18
  */
18
19
  data: T;
19
20
  }
21
+ /**
22
+ * Outcome of a single committed cell edit routed through
23
+ * {@link EditingController.applyCellEdit}.
24
+ *
25
+ * - `'unchanged'` - the candidate equalled the current value; nothing happened.
26
+ * - `'invalid'` - a column validator rejected the candidate; the value was not
27
+ * written and `cellValidationFailed` fired.
28
+ * - `'cancelled'` - a `cellValueChanging` listener called `preventDefault()`.
29
+ * - `'applied'` - the value was written and `cellValueChanged` fired.
30
+ */
31
+ export type CellEditResult = 'unchanged' | 'invalid' | 'cancelled' | 'applied';
32
+ /**
33
+ * Options for {@link EditingController.applyCellEdit}.
34
+ */
35
+ export interface ApplyCellEditOptions {
36
+ /**
37
+ * Run the column's declarative validators before writing. Defaults to `true`.
38
+ * Set to `false` for writes that must not be re-validated (e.g. reverting a
39
+ * previously valid value during undo/redo).
40
+ */
41
+ validate?: boolean;
42
+ }
20
43
  /**
21
44
  * Reactive controller backing inline cell + row editing.
22
45
  *
@@ -28,7 +51,9 @@ interface ActiveCell<T> {
28
51
  * propagate to consumers that own the source array.
29
52
  */
30
53
  export declare class EditingController<T extends object> implements ReactiveController {
54
+ #private;
31
55
  protected host: GridHost<T>;
56
+ protected history?: HistoryController<T> | undefined;
32
57
  /** The cell currently in edit mode, or `null`. */
33
58
  activeCell: ActiveCell<T> | null;
34
59
  /** The row currently in edit mode (row mode only), or `null`. */
@@ -42,7 +67,14 @@ export declare class EditingController<T extends object> implements ReactiveCont
42
67
  * {@link commitRow}.
43
68
  */
44
69
  pending: Map<Keys<T>, unknown>;
45
- constructor(host: GridHost<T>);
70
+ /**
71
+ * Monotonic token bumped whenever the validation-error set changes. Forwarded
72
+ * down to each cell as a reactive property so a validation-only change
73
+ * re-renders the affected cells (toggling `aria-invalid` and the error node)
74
+ * without re-running the data pipeline. Stays `0` until the first failure.
75
+ */
76
+ get validationVersion(): number;
77
+ constructor(host: GridHost<T>, history?: HistoryController<T> | undefined);
46
78
  hostConnected(): void;
47
79
  /**
48
80
  * Whether editing is enabled at the grid level.
@@ -82,6 +114,41 @@ export declare class EditingController<T extends object> implements ReactiveCont
82
114
  * success. No-op in cell mode.
83
115
  */
84
116
  editRow(rowIndex: number): Promise<boolean>;
117
+ /**
118
+ * The single choke point for committing a cell value to the backing record.
119
+ * Short-circuits no-op writes, runs the cancellable `cellValueChanging` gate,
120
+ * writes the value through to {@link ApexGrid.data}, and emits
121
+ * `cellValueChanged`. Returns the {@link CellEditResult} so callers can manage
122
+ * their own UI state (active cell) and batch the render.
123
+ *
124
+ * @remarks
125
+ * Does **not** request a render — callers refresh (once per edit, or once per
126
+ * batch) so row-mode and bulk edits coalesce into a single pipeline pass.
127
+ * Every committed edit (single-cell, row-mode, and enterprise paste/fill)
128
+ * funnels through here so cross-cutting concerns (validation, undo/redo) have
129
+ * one place to hook the old/new values and the write.
130
+ */
131
+ applyCellEdit(rowIndex: number, columnKey: Keys<T>, data: T, value: unknown, options?: ApplyCellEditOptions): CellEditResult;
132
+ /**
133
+ * Runs the column's declarative validators against a candidate value and
134
+ * returns the collected error messages (empty when the value passes or the
135
+ * column has no validators).
136
+ */
137
+ validateCell(rowIndex: number, columnKey: Keys<T>, data: T, value: unknown): string[];
138
+ /**
139
+ * The current validation errors for `(data, columnKey)`, or `null` when the
140
+ * cell is valid. Read by {@link ApexGridCell} to drive `aria-invalid` and the
141
+ * inline error node.
142
+ */
143
+ getCellErrors(data: T, columnKey: Keys<T>): readonly string[] | null;
144
+ /**
145
+ * Clears any validation error recorded for `(data, columnKey)`.
146
+ */
147
+ clearCellErrors(data: T, columnKey: Keys<T>): void;
148
+ /**
149
+ * Clears every validation error recorded for a record (all columns).
150
+ */
151
+ clearRecordErrors(data: T): void;
85
152
  /**
86
153
  * Commits a candidate value for the currently editing cell. In cell mode the
87
154
  * value is written through to {@link ApexGrid.data}; in row mode it is staged
@@ -1,15 +1,24 @@
1
1
  import { PIPELINE } from '../internal/constants.js';
2
+ import { runValidators } from '../internal/validators.js';
2
3
  export const DEFAULT_EDITING_CONFIG = Object.freeze({
3
4
  enabled: false,
4
5
  mode: 'cell',
5
6
  trigger: 'doubleClick',
6
7
  });
7
8
  export class EditingController {
8
- constructor(host) {
9
+ #invalid;
10
+ #validationVersion;
11
+ get validationVersion() {
12
+ return this.#validationVersion;
13
+ }
14
+ constructor(host, history) {
9
15
  this.host = host;
16
+ this.history = history;
10
17
  this.activeCell = null;
11
18
  this.activeRow = null;
12
19
  this.pending = new Map();
20
+ this.#invalid = new Map();
21
+ this.#validationVersion = 0;
13
22
  this.host.addController(this);
14
23
  }
15
24
  hostConnected() { }
@@ -77,6 +86,74 @@ export class EditingController {
77
86
  this.host.emitEvent('rowEditStarted', { detail: { rowIndex } });
78
87
  return true;
79
88
  }
89
+ applyCellEdit(rowIndex, columnKey, data, value, options) {
90
+ const record = data;
91
+ const oldValue = record[columnKey];
92
+ if (Object.is(value, oldValue)) {
93
+ this.clearCellErrors(data, columnKey);
94
+ return 'unchanged';
95
+ }
96
+ if (options?.validate !== false) {
97
+ const errors = this.validateCell(rowIndex, columnKey, data, value);
98
+ if (errors.length > 0) {
99
+ this.#setCellErrors(data, columnKey, errors);
100
+ this.host.emitEvent('cellValidationFailed', {
101
+ detail: { key: columnKey, rowIndex, data, value, errors },
102
+ });
103
+ return 'invalid';
104
+ }
105
+ }
106
+ const proceed = this.host.emitEvent('cellValueChanging', {
107
+ detail: { key: columnKey, rowIndex, data, oldValue, newValue: value },
108
+ cancelable: true,
109
+ });
110
+ if (!proceed)
111
+ return 'cancelled';
112
+ record[columnKey] = value;
113
+ this.clearCellErrors(data, columnKey);
114
+ this.history?.record({ record: data, key: columnKey, rowIndex, oldValue, newValue: value });
115
+ this.host.emitEvent('cellValueChanged', {
116
+ detail: { key: columnKey, rowIndex, data, value },
117
+ });
118
+ return 'applied';
119
+ }
120
+ validateCell(rowIndex, columnKey, data, value) {
121
+ const column = this.host.getColumn(columnKey);
122
+ if (!column?.validators?.length)
123
+ return [];
124
+ return runValidators(column.validators, value, {
125
+ column,
126
+ data,
127
+ rowIndex,
128
+ });
129
+ }
130
+ getCellErrors(data, columnKey) {
131
+ return this.#invalid.get(data)?.get(columnKey) ?? null;
132
+ }
133
+ clearCellErrors(data, columnKey) {
134
+ const perColumn = this.#invalid.get(data);
135
+ if (!perColumn)
136
+ return;
137
+ if (perColumn.delete(columnKey)) {
138
+ if (perColumn.size === 0)
139
+ this.#invalid.delete(data);
140
+ this.#validationVersion += 1;
141
+ }
142
+ }
143
+ clearRecordErrors(data) {
144
+ if (this.#invalid.delete(data)) {
145
+ this.#validationVersion += 1;
146
+ }
147
+ }
148
+ #setCellErrors(data, columnKey, errors) {
149
+ let perColumn = this.#invalid.get(data);
150
+ if (!perColumn) {
151
+ perColumn = new Map();
152
+ this.#invalid.set(data, perColumn);
153
+ }
154
+ perColumn.set(columnKey, errors);
155
+ this.#validationVersion += 1;
156
+ }
80
157
  async commitCell(value) {
81
158
  const active = this.activeCell;
82
159
  if (!active)
@@ -85,24 +162,21 @@ export class EditingController {
85
162
  const oldValue = data[columnKey];
86
163
  const candidate = value === undefined ? oldValue : value;
87
164
  if (this.mode === 'cell') {
88
- if (Object.is(candidate, oldValue)) {
89
- this.activeCell = null;
165
+ const result = this.applyCellEdit(rowIndex, columnKey, data, candidate);
166
+ if (result === 'cancelled')
167
+ return false;
168
+ if (result === 'invalid') {
90
169
  this.host.requestUpdate();
91
- return true;
92
- }
93
- const proceed = this.host.emitEvent('cellValueChanging', {
94
- detail: { key: columnKey, rowIndex, data, oldValue, newValue: candidate },
95
- cancelable: true,
96
- });
97
- if (!proceed)
98
170
  return false;
99
- data[columnKey] = candidate;
171
+ }
100
172
  this.activeCell = null;
101
- this.host.requestUpdate(PIPELINE);
102
- await this.host.updateComplete;
103
- this.host.emitEvent('cellValueChanged', {
104
- detail: { key: columnKey, rowIndex, data, value: candidate },
105
- });
173
+ if (result === 'applied') {
174
+ this.host.requestUpdate(PIPELINE);
175
+ await this.host.updateComplete;
176
+ }
177
+ else {
178
+ this.host.requestUpdate();
179
+ }
106
180
  return true;
107
181
  }
108
182
  if (!Object.is(candidate, oldValue)) {
@@ -121,27 +195,25 @@ export class EditingController {
121
195
  const data = this.host.pageItems[rowIndex];
122
196
  if (!data)
123
197
  return false;
124
- const oldValue = data[columnKey];
125
- if (Object.is(value, oldValue))
126
- return true;
127
- const proceed = this.host.emitEvent('cellValueChanging', {
128
- detail: { key: columnKey, rowIndex, data, oldValue, newValue: value },
129
- cancelable: true,
130
- });
131
- if (!proceed)
198
+ const result = this.applyCellEdit(rowIndex, columnKey, data, value);
199
+ if (result === 'cancelled')
132
200
  return false;
133
- data[columnKey] = value;
134
- this.host.requestUpdate(PIPELINE);
135
- await this.host.updateComplete;
136
- this.host.emitEvent('cellValueChanged', {
137
- detail: { key: columnKey, rowIndex, data, value },
138
- });
201
+ if (result === 'invalid') {
202
+ this.host.requestUpdate();
203
+ return false;
204
+ }
205
+ if (result === 'applied') {
206
+ this.host.requestUpdate(PIPELINE);
207
+ await this.host.updateComplete;
208
+ }
139
209
  return true;
140
210
  }
141
211
  cancelCell() {
142
212
  if (!this.activeCell)
143
213
  return;
214
+ const { data, columnKey } = this.activeCell;
144
215
  this.activeCell = null;
216
+ this.clearCellErrors(data, columnKey);
145
217
  this.host.requestUpdate();
146
218
  }
147
219
  async commitRow() {
@@ -152,20 +224,32 @@ export class EditingController {
152
224
  if (this.activeCell?.rowIndex === rowIndex) {
153
225
  await this.commitCell();
154
226
  }
227
+ let hasInvalid = false;
155
228
  for (const [columnKey, candidate] of this.pending) {
156
- const oldValue = data[columnKey];
157
- if (Object.is(candidate, oldValue))
158
- continue;
159
- const proceed = this.host.emitEvent('cellValueChanging', {
160
- detail: { key: columnKey, rowIndex, data, oldValue, newValue: candidate },
161
- cancelable: true,
162
- });
163
- if (!proceed)
164
- return false;
165
- data[columnKey] = candidate;
166
- this.host.emitEvent('cellValueChanged', {
167
- detail: { key: columnKey, rowIndex, data, value: candidate },
168
- });
229
+ const errors = this.validateCell(rowIndex, columnKey, data, candidate);
230
+ if (errors.length > 0) {
231
+ this.#setCellErrors(data, columnKey, errors);
232
+ this.host.emitEvent('cellValidationFailed', {
233
+ detail: { key: columnKey, rowIndex, data, value: candidate, errors },
234
+ });
235
+ hasInvalid = true;
236
+ }
237
+ }
238
+ if (hasInvalid) {
239
+ this.host.requestUpdate();
240
+ return false;
241
+ }
242
+ this.history?.beginBatch();
243
+ try {
244
+ for (const [columnKey, candidate] of this.pending) {
245
+ if (this.applyCellEdit(rowIndex, columnKey, data, candidate, { validate: false }) ===
246
+ 'cancelled') {
247
+ return false;
248
+ }
249
+ }
250
+ }
251
+ finally {
252
+ this.history?.endBatch();
169
253
  }
170
254
  this.pending.clear();
171
255
  this.activeRow = null;
@@ -177,10 +261,11 @@ export class EditingController {
177
261
  cancelRow() {
178
262
  if (!this.activeRow)
179
263
  return;
180
- const { rowIndex } = this.activeRow;
264
+ const { rowIndex, data } = this.activeRow;
181
265
  this.activeCell = null;
182
266
  this.activeRow = null;
183
267
  this.pending.clear();
268
+ this.clearRecordErrors(data);
184
269
  this.host.requestUpdate();
185
270
  this.host.emitEvent('rowEditEnded', { detail: { rowIndex, committed: false } });
186
271
  }
@@ -1 +1 @@
1
- {"version":3,"file":"editing.js","sourceRoot":"","sources":["../../src/controllers/editing.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\nimport { PIPELINE } from '../internal/constants.js';\nimport type {\n ColumnConfiguration,\n EditMode,\n EditTrigger,\n GridHost,\n Keys,\n} from '../internal/types.js';\n\n/**\n * The default editing configuration used when the grid has none set.\n */\nexport const DEFAULT_EDITING_CONFIG = Object.freeze({\n enabled: false,\n mode: 'cell' as EditMode,\n trigger: 'doubleClick' as EditTrigger,\n});\n\ninterface ActiveCell<T> {\n rowIndex: number;\n columnKey: Keys<T>;\n /**\n * Live reference to the underlying record (preserved through the pipeline so\n * the source array can be mutated on commit).\n */\n data: T;\n}\n\n/**\n * Reactive controller backing inline cell + row editing.\n *\n * @remarks\n * Holds the currently active cell / row, pending values for row-mode edits,\n * and is responsible for emitting the cancellable `cellValueChanging` event\n * and follow-up `cellValueChanged` event. The actual data mutation writes\n * through to {@link ApexGrid.data} so changes survive pipeline runs and\n * propagate to consumers that own the source array.\n */\nexport class EditingController<T extends object> implements ReactiveController {\n /** The cell currently in edit mode, or `null`. */\n public activeCell: ActiveCell<T> | null = null;\n\n /** The row currently in edit mode (row mode only), or `null`. */\n public activeRow: { rowIndex: number; data: T } | null = null;\n\n /**\n * Pending values keyed by column for the currently editing row. Populated in\n * row mode as the user edits individual cells; flushed on\n * {@link commitRow}.\n */\n public pending: Map<Keys<T>, unknown> = new Map();\n\n constructor(protected host: GridHost<T>) {\n this.host.addController(this);\n }\n\n public hostConnected() {}\n\n /**\n * Whether editing is enabled at the grid level.\n */\n public get enabled(): boolean {\n return Boolean(this.host.editing?.enabled);\n }\n\n /**\n * The resolved edit mode (`'cell'` if unset).\n */\n public get mode(): EditMode {\n return this.host.editing?.mode ?? DEFAULT_EDITING_CONFIG.mode;\n }\n\n /**\n * The resolved edit trigger (`'doubleClick'` if unset).\n */\n public get trigger(): EditTrigger {\n return this.host.editing?.trigger ?? DEFAULT_EDITING_CONFIG.trigger;\n }\n\n /**\n * Whether the given column can be edited.\n */\n public isEditable(column: ColumnConfiguration<T>): boolean {\n return Boolean(this.enabled && column.editable && !column.hidden);\n }\n\n /**\n * Whether the cell `(rowIndex, columnKey)` is currently in edit mode.\n */\n public isCellEditing(rowIndex: number, columnKey: Keys<T>): boolean {\n return this.activeCell?.rowIndex === rowIndex && this.activeCell?.columnKey === columnKey;\n }\n\n /**\n * Whether the given row is currently in edit mode (row mode).\n */\n public isRowEditing(rowIndex: number): boolean {\n return this.activeRow?.rowIndex === rowIndex;\n }\n\n /**\n * Begins editing the cell at `(rowIndex, columnKey)`. Auto-commits any cell\n * already in edit mode (in cell mode); in row mode it switches the active\n * cell within the same row and rejects cross-row moves.\n *\n * @returns `true` if edit started, `false` if rejected (column not editable\n * or row-mode constraint violated).\n */\n public async editCell(rowIndex: number, columnKey: Keys<T>): Promise<boolean> {\n if (!this.enabled) return false;\n const column = this.host.getColumn(columnKey);\n if (!column || !this.isEditable(column)) return false;\n const data = this.host.pageItems[rowIndex] as T | undefined;\n if (!data) return false;\n\n if (this.mode === 'row') {\n if (!this.activeRow) {\n await this.editRow(rowIndex);\n } else if (this.activeRow.rowIndex !== rowIndex) {\n // Switching rows in row mode — commit pending edits in the previous row\n // before starting elsewhere.\n const committed = await this.commitRow();\n if (!committed) return false;\n await this.editRow(rowIndex);\n }\n } else if (this.activeCell && !this.isCellEditing(rowIndex, columnKey)) {\n // Cell mode — commit any in-flight cell before switching.\n await this.commitCell();\n }\n\n this.activeCell = { rowIndex, columnKey, data };\n this.host.requestUpdate();\n return true;\n }\n\n /**\n * Begins editing the given row in row mode. Emits `rowEditStarted` on\n * success. No-op in cell mode.\n */\n public async editRow(rowIndex: number): Promise<boolean> {\n if (!this.enabled || this.mode !== 'row') return false;\n const data = this.host.pageItems[rowIndex] as T | undefined;\n if (!data) return false;\n if (this.activeRow && this.activeRow.rowIndex !== rowIndex) {\n const committed = await this.commitRow();\n if (!committed) return false;\n }\n if (this.activeRow?.rowIndex === rowIndex) return true;\n this.activeRow = { rowIndex, data };\n this.pending.clear();\n this.host.requestUpdate();\n this.host.emitEvent('rowEditStarted', { detail: { rowIndex } });\n return true;\n }\n\n /**\n * Commits a candidate value for the currently editing cell. In cell mode the\n * value is written through to {@link ApexGrid.data}; in row mode it is staged\n * in {@link pending} until {@link commitRow} is called.\n *\n * @param value - The candidate value.\n * @returns `true` if accepted (or staged), `false` if rejected by\n * `cellValueChanging.preventDefault()`.\n */\n public async commitCell(value?: unknown): Promise<boolean> {\n const active = this.activeCell;\n if (!active) return false;\n const { rowIndex, columnKey, data } = active;\n const oldValue = (data as Record<string, unknown>)[columnKey as string];\n const candidate = value === undefined ? oldValue : value;\n\n if (this.mode === 'cell') {\n if (Object.is(candidate, oldValue)) {\n this.activeCell = null;\n this.host.requestUpdate();\n return true;\n }\n const proceed = this.host.emitEvent('cellValueChanging', {\n detail: { key: columnKey, rowIndex, data, oldValue, newValue: candidate },\n cancelable: true,\n });\n if (!proceed) return false;\n (data as Record<string, unknown>)[columnKey as string] = candidate;\n this.activeCell = null;\n this.host.requestUpdate(PIPELINE);\n await this.host.updateComplete;\n this.host.emitEvent('cellValueChanged', {\n detail: { key: columnKey, rowIndex, data, value: candidate },\n });\n return true;\n }\n\n // Row mode — stage and exit cell edit (row stays open).\n if (!Object.is(candidate, oldValue)) {\n this.pending.set(columnKey, candidate);\n }\n this.activeCell = null;\n this.host.requestUpdate();\n return true;\n }\n\n /**\n * Writes `value` directly to the cell at `(rowIndex, columnKey)` without\n * entering edit mode. Used by interactive display widgets (e.g. the boolean\n * checkbox) that handle their own input. Goes through the same\n * `cellValueChanging` / `cellValueChanged` event path as a normal commit.\n *\n * @returns `true` if the value was applied, `false` if rejected by\n * `cellValueChanging.preventDefault()` or the column is not editable.\n */\n public async commitImmediate(\n rowIndex: number,\n columnKey: Keys<T>,\n value: unknown\n ): Promise<boolean> {\n if (!this.enabled) return false;\n const column = this.host.getColumn(columnKey);\n if (!column || !this.isEditable(column)) return false;\n const data = this.host.pageItems[rowIndex] as T | undefined;\n if (!data) return false;\n const oldValue = (data as Record<string, unknown>)[columnKey as string];\n if (Object.is(value, oldValue)) return true;\n const proceed = this.host.emitEvent('cellValueChanging', {\n detail: { key: columnKey, rowIndex, data, oldValue, newValue: value },\n cancelable: true,\n });\n if (!proceed) return false;\n (data as Record<string, unknown>)[columnKey as string] = value;\n this.host.requestUpdate(PIPELINE);\n await this.host.updateComplete;\n this.host.emitEvent('cellValueChanged', {\n detail: { key: columnKey, rowIndex, data, value },\n });\n return true;\n }\n\n /**\n * Discards the current cell edit without writing. In row mode the row edit\n * stays open.\n */\n public cancelCell(): void {\n if (!this.activeCell) return;\n this.activeCell = null;\n this.host.requestUpdate();\n }\n\n /**\n * Commits all pending edits for the currently editing row. Emits\n * `cellValueChanging` for every changed cell and `rowEditEnded` at the end.\n *\n * @returns `true` if the row was applied, `false` if any cell change was\n * cancelled (the row remains in edit mode in that case).\n */\n public async commitRow(): Promise<boolean> {\n const active = this.activeRow;\n if (!active) return false;\n const { rowIndex, data } = active;\n\n // Make sure any open cell editor flushes its pending value first.\n if (this.activeCell?.rowIndex === rowIndex) {\n await this.commitCell();\n }\n\n for (const [columnKey, candidate] of this.pending) {\n const oldValue = (data as Record<string, unknown>)[columnKey as string];\n if (Object.is(candidate, oldValue)) continue;\n const proceed = this.host.emitEvent('cellValueChanging', {\n detail: { key: columnKey, rowIndex, data, oldValue, newValue: candidate },\n cancelable: true,\n });\n if (!proceed) return false;\n (data as Record<string, unknown>)[columnKey as string] = candidate;\n this.host.emitEvent('cellValueChanged', {\n detail: { key: columnKey, rowIndex, data, value: candidate },\n });\n }\n\n this.pending.clear();\n this.activeRow = null;\n this.host.requestUpdate(PIPELINE);\n await this.host.updateComplete;\n this.host.emitEvent('rowEditEnded', { detail: { rowIndex, committed: true } });\n return true;\n }\n\n /**\n * Discards every pending edit for the active row and exits row edit mode.\n * Emits `rowEditEnded` with `committed: false`.\n */\n public cancelRow(): void {\n if (!this.activeRow) return;\n const { rowIndex } = this.activeRow;\n this.activeCell = null;\n this.activeRow = null;\n this.pending.clear();\n this.host.requestUpdate();\n this.host.emitEvent('rowEditEnded', { detail: { rowIndex, committed: false } });\n }\n\n /**\n * Returns the current pending or committed value for `(rowIndex, columnKey)`.\n * Cells in row mode read this so unstaged-but-pending values are reflected\n * during the edit.\n */\n public getValue(rowIndex: number, columnKey: Keys<T>): unknown {\n if (\n this.mode === 'row' &&\n this.activeRow?.rowIndex === rowIndex &&\n this.pending.has(columnKey)\n ) {\n return this.pending.get(columnKey);\n }\n const data = this.host.pageItems[rowIndex] as T | undefined;\n return data ? (data as Record<string, unknown>)[columnKey as string] : undefined;\n }\n}\n"]}
1
+ {"version":3,"file":"editing.js","sourceRoot":"","sources":["../../src/controllers/editing.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\nimport { PIPELINE } from '../internal/constants.js';\nimport type {\n ColumnConfiguration,\n EditMode,\n EditTrigger,\n GridHost,\n Keys,\n Validator,\n ValidatorContext,\n} from '../internal/types.js';\nimport { runValidators } from '../internal/validators.js';\nimport type { HistoryController } from './history.js';\n\n/**\n * The default editing configuration used when the grid has none set.\n */\nexport const DEFAULT_EDITING_CONFIG = Object.freeze({\n enabled: false,\n mode: 'cell' as EditMode,\n trigger: 'doubleClick' as EditTrigger,\n});\n\ninterface ActiveCell<T> {\n rowIndex: number;\n columnKey: Keys<T>;\n /**\n * Live reference to the underlying record (preserved through the pipeline so\n * the source array can be mutated on commit).\n */\n data: T;\n}\n\n/**\n * Outcome of a single committed cell edit routed through\n * {@link EditingController.applyCellEdit}.\n *\n * - `'unchanged'` - the candidate equalled the current value; nothing happened.\n * - `'invalid'` - a column validator rejected the candidate; the value was not\n * written and `cellValidationFailed` fired.\n * - `'cancelled'` - a `cellValueChanging` listener called `preventDefault()`.\n * - `'applied'` - the value was written and `cellValueChanged` fired.\n */\nexport type CellEditResult = 'unchanged' | 'invalid' | 'cancelled' | 'applied';\n\n/**\n * Options for {@link EditingController.applyCellEdit}.\n */\nexport interface ApplyCellEditOptions {\n /**\n * Run the column's declarative validators before writing. Defaults to `true`.\n * Set to `false` for writes that must not be re-validated (e.g. reverting a\n * previously valid value during undo/redo).\n */\n validate?: boolean;\n}\n\n/**\n * Reactive controller backing inline cell + row editing.\n *\n * @remarks\n * Holds the currently active cell / row, pending values for row-mode edits,\n * and is responsible for emitting the cancellable `cellValueChanging` event\n * and follow-up `cellValueChanged` event. The actual data mutation writes\n * through to {@link ApexGrid.data} so changes survive pipeline runs and\n * propagate to consumers that own the source array.\n */\nexport class EditingController<T extends object> implements ReactiveController {\n /** The cell currently in edit mode, or `null`. */\n public activeCell: ActiveCell<T> | null = null;\n\n /** The row currently in edit mode (row mode only), or `null`. */\n public activeRow: { rowIndex: number; data: T } | null = null;\n\n /**\n * Pending values keyed by column for the currently editing row. Populated in\n * row mode as the user edits individual cells; flushed on\n * {@link commitRow}.\n */\n public pending: Map<Keys<T>, unknown> = new Map();\n\n /**\n * Per-record validation errors, keyed by the live data reference and then by\n * column. Keyed by reference (not row index) so an invalid marker tracks its\n * row across pipeline runs (sort / filter / paginate).\n */\n #invalid: Map<T, Map<Keys<T>, string[]>> = new Map();\n\n #validationVersion = 0;\n\n /**\n * Monotonic token bumped whenever the validation-error set changes. Forwarded\n * down to each cell as a reactive property so a validation-only change\n * re-renders the affected cells (toggling `aria-invalid` and the error node)\n * without re-running the data pipeline. Stays `0` until the first failure.\n */\n public get validationVersion(): number {\n return this.#validationVersion;\n }\n\n constructor(\n protected host: GridHost<T>,\n protected history?: HistoryController<T>\n ) {\n this.host.addController(this);\n }\n\n public hostConnected() {}\n\n /**\n * Whether editing is enabled at the grid level.\n */\n public get enabled(): boolean {\n return Boolean(this.host.editing?.enabled);\n }\n\n /**\n * The resolved edit mode (`'cell'` if unset).\n */\n public get mode(): EditMode {\n return this.host.editing?.mode ?? DEFAULT_EDITING_CONFIG.mode;\n }\n\n /**\n * The resolved edit trigger (`'doubleClick'` if unset).\n */\n public get trigger(): EditTrigger {\n return this.host.editing?.trigger ?? DEFAULT_EDITING_CONFIG.trigger;\n }\n\n /**\n * Whether the given column can be edited.\n */\n public isEditable(column: ColumnConfiguration<T>): boolean {\n return Boolean(this.enabled && column.editable && !column.hidden);\n }\n\n /**\n * Whether the cell `(rowIndex, columnKey)` is currently in edit mode.\n */\n public isCellEditing(rowIndex: number, columnKey: Keys<T>): boolean {\n return this.activeCell?.rowIndex === rowIndex && this.activeCell?.columnKey === columnKey;\n }\n\n /**\n * Whether the given row is currently in edit mode (row mode).\n */\n public isRowEditing(rowIndex: number): boolean {\n return this.activeRow?.rowIndex === rowIndex;\n }\n\n /**\n * Begins editing the cell at `(rowIndex, columnKey)`. Auto-commits any cell\n * already in edit mode (in cell mode); in row mode it switches the active\n * cell within the same row and rejects cross-row moves.\n *\n * @returns `true` if edit started, `false` if rejected (column not editable\n * or row-mode constraint violated).\n */\n public async editCell(rowIndex: number, columnKey: Keys<T>): Promise<boolean> {\n if (!this.enabled) return false;\n const column = this.host.getColumn(columnKey);\n if (!column || !this.isEditable(column)) return false;\n const data = this.host.pageItems[rowIndex] as T | undefined;\n if (!data) return false;\n\n if (this.mode === 'row') {\n if (!this.activeRow) {\n await this.editRow(rowIndex);\n } else if (this.activeRow.rowIndex !== rowIndex) {\n // Switching rows in row mode — commit pending edits in the previous row\n // before starting elsewhere.\n const committed = await this.commitRow();\n if (!committed) return false;\n await this.editRow(rowIndex);\n }\n } else if (this.activeCell && !this.isCellEditing(rowIndex, columnKey)) {\n // Cell mode — commit any in-flight cell before switching.\n await this.commitCell();\n }\n\n this.activeCell = { rowIndex, columnKey, data };\n this.host.requestUpdate();\n return true;\n }\n\n /**\n * Begins editing the given row in row mode. Emits `rowEditStarted` on\n * success. No-op in cell mode.\n */\n public async editRow(rowIndex: number): Promise<boolean> {\n if (!this.enabled || this.mode !== 'row') return false;\n const data = this.host.pageItems[rowIndex] as T | undefined;\n if (!data) return false;\n if (this.activeRow && this.activeRow.rowIndex !== rowIndex) {\n const committed = await this.commitRow();\n if (!committed) return false;\n }\n if (this.activeRow?.rowIndex === rowIndex) return true;\n this.activeRow = { rowIndex, data };\n this.pending.clear();\n this.host.requestUpdate();\n this.host.emitEvent('rowEditStarted', { detail: { rowIndex } });\n return true;\n }\n\n /**\n * The single choke point for committing a cell value to the backing record.\n * Short-circuits no-op writes, runs the cancellable `cellValueChanging` gate,\n * writes the value through to {@link ApexGrid.data}, and emits\n * `cellValueChanged`. Returns the {@link CellEditResult} so callers can manage\n * their own UI state (active cell) and batch the render.\n *\n * @remarks\n * Does **not** request a render — callers refresh (once per edit, or once per\n * batch) so row-mode and bulk edits coalesce into a single pipeline pass.\n * Every committed edit (single-cell, row-mode, and enterprise paste/fill)\n * funnels through here so cross-cutting concerns (validation, undo/redo) have\n * one place to hook the old/new values and the write.\n */\n public applyCellEdit(\n rowIndex: number,\n columnKey: Keys<T>,\n data: T,\n value: unknown,\n options?: ApplyCellEditOptions\n ): CellEditResult {\n const record = data as Record<string, unknown>;\n const oldValue = record[columnKey as string];\n if (Object.is(value, oldValue)) {\n // Re-entering the original value clears any stale invalid marker.\n this.clearCellErrors(data, columnKey);\n return 'unchanged';\n }\n\n if (options?.validate !== false) {\n const errors = this.validateCell(rowIndex, columnKey, data, value);\n if (errors.length > 0) {\n this.#setCellErrors(data, columnKey, errors);\n this.host.emitEvent('cellValidationFailed', {\n detail: { key: columnKey, rowIndex, data, value, errors },\n });\n return 'invalid';\n }\n }\n\n const proceed = this.host.emitEvent('cellValueChanging', {\n detail: { key: columnKey, rowIndex, data, oldValue, newValue: value },\n cancelable: true,\n });\n if (!proceed) return 'cancelled';\n\n record[columnKey as string] = value;\n this.clearCellErrors(data, columnKey);\n this.history?.record({ record: data, key: columnKey, rowIndex, oldValue, newValue: value });\n this.host.emitEvent('cellValueChanged', {\n detail: { key: columnKey, rowIndex, data, value },\n });\n return 'applied';\n }\n\n /**\n * Runs the column's declarative validators against a candidate value and\n * returns the collected error messages (empty when the value passes or the\n * column has no validators).\n */\n public validateCell(rowIndex: number, columnKey: Keys<T>, data: T, value: unknown): string[] {\n const column = this.host.getColumn(columnKey);\n if (!column?.validators?.length) return [];\n // `ColumnConfiguration<T>` is a distributive conditional, so `validators`\n // and `column` widen to a per-key union here; collapse to the base form for\n // the runner (the runtime shapes are identical).\n return runValidators(column.validators as Validator<T>[], value, {\n column,\n data,\n rowIndex,\n } as ValidatorContext<T>);\n }\n\n /**\n * The current validation errors for `(data, columnKey)`, or `null` when the\n * cell is valid. Read by {@link ApexGridCell} to drive `aria-invalid` and the\n * inline error node.\n */\n public getCellErrors(data: T, columnKey: Keys<T>): readonly string[] | null {\n return this.#invalid.get(data)?.get(columnKey) ?? null;\n }\n\n /**\n * Clears any validation error recorded for `(data, columnKey)`.\n */\n public clearCellErrors(data: T, columnKey: Keys<T>): void {\n const perColumn = this.#invalid.get(data);\n if (!perColumn) return;\n if (perColumn.delete(columnKey)) {\n if (perColumn.size === 0) this.#invalid.delete(data);\n this.#validationVersion += 1;\n }\n }\n\n /**\n * Clears every validation error recorded for a record (all columns).\n */\n public clearRecordErrors(data: T): void {\n if (this.#invalid.delete(data)) {\n this.#validationVersion += 1;\n }\n }\n\n #setCellErrors(data: T, columnKey: Keys<T>, errors: string[]): void {\n let perColumn = this.#invalid.get(data);\n if (!perColumn) {\n perColumn = new Map();\n this.#invalid.set(data, perColumn);\n }\n perColumn.set(columnKey, errors);\n this.#validationVersion += 1;\n }\n\n /**\n * Commits a candidate value for the currently editing cell. In cell mode the\n * value is written through to {@link ApexGrid.data}; in row mode it is staged\n * in {@link pending} until {@link commitRow} is called.\n *\n * @param value - The candidate value.\n * @returns `true` if accepted (or staged), `false` if rejected by\n * `cellValueChanging.preventDefault()`.\n */\n public async commitCell(value?: unknown): Promise<boolean> {\n const active = this.activeCell;\n if (!active) return false;\n const { rowIndex, columnKey, data } = active;\n const oldValue = (data as Record<string, unknown>)[columnKey as string];\n const candidate = value === undefined ? oldValue : value;\n\n if (this.mode === 'cell') {\n const result = this.applyCellEdit(rowIndex, columnKey, data, candidate);\n if (result === 'cancelled') return false;\n // A failed validation keeps the editor open so the user can correct the\n // value; re-render to surface `aria-invalid` + the error node.\n if (result === 'invalid') {\n this.host.requestUpdate();\n return false;\n }\n // Both 'applied' and 'unchanged' close the editor; only an applied write\n // needs the data pipeline to re-run.\n this.activeCell = null;\n if (result === 'applied') {\n this.host.requestUpdate(PIPELINE);\n await this.host.updateComplete;\n } else {\n this.host.requestUpdate();\n }\n return true;\n }\n\n // Row mode — stage and exit cell edit (row stays open).\n if (!Object.is(candidate, oldValue)) {\n this.pending.set(columnKey, candidate);\n }\n this.activeCell = null;\n this.host.requestUpdate();\n return true;\n }\n\n /**\n * Writes `value` directly to the cell at `(rowIndex, columnKey)` without\n * entering edit mode. Used by interactive display widgets (e.g. the boolean\n * checkbox) that handle their own input. Goes through the same\n * `cellValueChanging` / `cellValueChanged` event path as a normal commit.\n *\n * @returns `true` if the value was applied, `false` if rejected by\n * `cellValueChanging.preventDefault()` or the column is not editable.\n */\n public async commitImmediate(\n rowIndex: number,\n columnKey: Keys<T>,\n value: unknown\n ): Promise<boolean> {\n if (!this.enabled) return false;\n const column = this.host.getColumn(columnKey);\n if (!column || !this.isEditable(column)) return false;\n const data = this.host.pageItems[rowIndex] as T | undefined;\n if (!data) return false;\n\n const result = this.applyCellEdit(rowIndex, columnKey, data, value);\n if (result === 'cancelled') return false;\n if (result === 'invalid') {\n this.host.requestUpdate();\n return false;\n }\n if (result === 'applied') {\n this.host.requestUpdate(PIPELINE);\n await this.host.updateComplete;\n }\n return true;\n }\n\n /**\n * Discards the current cell edit without writing. In row mode the row edit\n * stays open.\n */\n public cancelCell(): void {\n if (!this.activeCell) return;\n const { data, columnKey } = this.activeCell;\n this.activeCell = null;\n // Abandoning the edit discards any validation error raised for the cell.\n this.clearCellErrors(data, columnKey);\n this.host.requestUpdate();\n }\n\n /**\n * Commits all pending edits for the currently editing row. Emits\n * `cellValueChanging` for every changed cell and `rowEditEnded` at the end.\n *\n * @returns `true` if the row was applied, `false` if any cell change was\n * cancelled (the row remains in edit mode in that case).\n */\n public async commitRow(): Promise<boolean> {\n const active = this.activeRow;\n if (!active) return false;\n const { rowIndex, data } = active;\n\n // Make sure any open cell editor flushes its pending value first.\n if (this.activeCell?.rowIndex === rowIndex) {\n await this.commitCell();\n }\n\n // Pre-validate every pending cell so a single failure aborts the whole row\n // commit without a partial write. Each failing cell is marked invalid and\n // the row stays in edit mode.\n let hasInvalid = false;\n for (const [columnKey, candidate] of this.pending) {\n const errors = this.validateCell(rowIndex, columnKey, data, candidate);\n if (errors.length > 0) {\n this.#setCellErrors(data, columnKey, errors);\n this.host.emitEvent('cellValidationFailed', {\n detail: { key: columnKey, rowIndex, data, value: candidate, errors },\n });\n hasInvalid = true;\n }\n }\n if (hasInvalid) {\n this.host.requestUpdate();\n return false;\n }\n\n // Coalesce the row's writes into one undo step.\n this.history?.beginBatch();\n try {\n for (const [columnKey, candidate] of this.pending) {\n // Validation already ran above; a cancelled cell aborts the whole row\n // commit, leaving it in edit mode.\n if (\n this.applyCellEdit(rowIndex, columnKey, data, candidate, { validate: false }) ===\n 'cancelled'\n ) {\n return false;\n }\n }\n } finally {\n this.history?.endBatch();\n }\n\n this.pending.clear();\n this.activeRow = null;\n this.host.requestUpdate(PIPELINE);\n await this.host.updateComplete;\n this.host.emitEvent('rowEditEnded', { detail: { rowIndex, committed: true } });\n return true;\n }\n\n /**\n * Discards every pending edit for the active row and exits row edit mode.\n * Emits `rowEditEnded` with `committed: false`.\n */\n public cancelRow(): void {\n if (!this.activeRow) return;\n const { rowIndex, data } = this.activeRow;\n this.activeCell = null;\n this.activeRow = null;\n this.pending.clear();\n // Abandoning the row discards every validation error raised for it.\n this.clearRecordErrors(data);\n this.host.requestUpdate();\n this.host.emitEvent('rowEditEnded', { detail: { rowIndex, committed: false } });\n }\n\n /**\n * Returns the current pending or committed value for `(rowIndex, columnKey)`.\n * Cells in row mode read this so unstaged-but-pending values are reflected\n * during the edit.\n */\n public getValue(rowIndex: number, columnKey: Keys<T>): unknown {\n if (\n this.mode === 'row' &&\n this.activeRow?.rowIndex === rowIndex &&\n this.pending.has(columnKey)\n ) {\n return this.pending.get(columnKey);\n }\n const data = this.host.pageItems[rowIndex] as T | undefined;\n return data ? (data as Record<string, unknown>)[columnKey as string] : undefined;\n }\n}\n"]}
@@ -12,7 +12,7 @@ export declare class FilterController<T extends object> implements ReactiveContr
12
12
  hostUpdate(): void;
13
13
  get(key: Keys<T>): import("../operations/filter/tree.js").FilterExpressionTree<T> | undefined;
14
14
  reset(key?: Keys<T>): void;
15
- setActiveColumn(column?: ColumnConfiguration<T>): void;
15
+ setActiveColumn(column?: ColumnConfiguration<T>, triggerRect?: DOMRect): void;
16
16
  getDefaultExpression(column: ColumnConfiguration<T>): FilterExpression<T>;
17
17
  removeAllExpressions(key: Keys<T>): Promise<void>;
18
18
  removeExpression(expression: FilterExpression<T>): Promise<void>;
@@ -43,12 +43,23 @@ export class FilterController {
43
43
  reset(key) {
44
44
  key ? this.state.delete(key) : this.state.clear();
45
45
  }
46
- setActiveColumn(column) {
47
- if (column?.filter && this.filterRow?.active) {
48
- this.filterRow.column = column;
49
- this.filterRow.expression = this.getDefaultExpression(column);
50
- this.host.requestUpdate();
46
+ setActiveColumn(column, triggerRect) {
47
+ const filterRow = this.filterRow;
48
+ if (!filterRow)
49
+ return;
50
+ if (!column?.filter) {
51
+ filterRow.active = false;
52
+ return;
53
+ }
54
+ if (filterRow.active && filterRow.column?.key === column.key) {
55
+ filterRow.active = false;
56
+ return;
51
57
  }
58
+ filterRow.triggerRect = triggerRect ?? null;
59
+ filterRow.column = column;
60
+ filterRow.expression = this.getDefaultExpression(column);
61
+ filterRow.active = true;
62
+ this.host.requestUpdate();
52
63
  }
53
64
  getDefaultExpression(column) {
54
65
  const caseSensitive = typeof column.filter === 'boolean' ? false : Boolean(column.filter?.caseSensitive);