apex-grid 3.3.0 → 3.5.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 (132) hide show
  1. package/CHANGELOG.md +143 -0
  2. package/README.md +74 -6
  3. package/components/cell.d.ts +2 -2
  4. package/components/cell.js +30 -2
  5. package/components/cell.js.map +1 -1
  6. package/components/filter-row.js +65 -6
  7. package/components/filter-row.js.map +1 -1
  8. package/components/grid.d.ts +132 -0
  9. package/components/grid.js +59 -2
  10. package/components/grid.js.map +1 -1
  11. package/components/header-row.js +8 -0
  12. package/components/header-row.js.map +1 -1
  13. package/components/header.js +85 -12
  14. package/components/header.js.map +1 -1
  15. package/components/row.js +32 -4
  16. package/components/row.js.map +1 -1
  17. package/components/virtualizer.d.ts +5 -1
  18. package/components/virtualizer.js +72 -2
  19. package/components/virtualizer.js.map +1 -1
  20. package/controllers/expansion.js +4 -4
  21. package/controllers/expansion.js.map +1 -1
  22. package/controllers/filter.js +11 -0
  23. package/controllers/filter.js.map +1 -1
  24. package/controllers/history.js +11 -4
  25. package/controllers/history.js.map +1 -1
  26. package/controllers/navigation.d.ts +35 -2
  27. package/controllers/navigation.js +102 -8
  28. package/controllers/navigation.js.map +1 -1
  29. package/controllers/pagination.js +1 -1
  30. package/controllers/pagination.js.map +1 -1
  31. package/controllers/reorder.js +4 -2
  32. package/controllers/reorder.js.map +1 -1
  33. package/controllers/row-pin.js +2 -2
  34. package/controllers/row-pin.js.map +1 -1
  35. package/controllers/row-reorder.js +6 -6
  36. package/controllers/row-reorder.js.map +1 -1
  37. package/controllers/selection.js +3 -3
  38. package/controllers/selection.js.map +1 -1
  39. package/controllers/sort.js +4 -2
  40. package/controllers/sort.js.map +1 -1
  41. package/controllers/state.d.ts +9 -3
  42. package/controllers/state.js +11 -1
  43. package/controllers/state.js.map +1 -1
  44. package/custom-elements.json +664 -190
  45. package/docs/assets/hierarchy.js +1 -1
  46. package/docs/assets/navigation.js +1 -1
  47. package/docs/assets/search.js +1 -1
  48. package/docs/classes/ApexGrid.html +586 -0
  49. package/docs/classes/ApexGridPaginator.html +36 -0
  50. package/docs/classes/ApexGridToolbar.html +67 -0
  51. package/docs/functions/localize.html +2 -2
  52. package/docs/functions/setup.html +1 -2
  53. package/docs/hierarchy.html +1 -1
  54. package/docs/index.html +94 -6
  55. package/docs/interfaces/ApexCellValidationFailedEvent.html +1 -1
  56. package/docs/interfaces/ApexCellValueChangedEvent.html +1 -1
  57. package/docs/interfaces/ApexCellValueChangingEvent.html +2 -2
  58. package/docs/interfaces/ApexColumnMovedEvent.html +2 -2
  59. package/docs/interfaces/ApexColumnMovingEvent.html +1 -1
  60. package/docs/interfaces/ApexDetailContext.html +2 -2
  61. package/docs/interfaces/ApexGridEventMap.html +5 -5
  62. package/docs/interfaces/ApexRowMovingEvent.html +1 -1
  63. package/docs/interfaces/ApexRowPinningEvent.html +1 -1
  64. package/docs/interfaces/BaseApexCellContext.html +1 -1
  65. package/docs/interfaces/BaseApexEditorContext.html +1 -1
  66. package/docs/interfaces/BaseColumnConfiguration.html +3 -3
  67. package/docs/interfaces/CSVExportOptions.html +2 -2
  68. package/docs/interfaces/DataPipelineConfiguration.html +2 -2
  69. package/docs/interfaces/EditingHistoryConfiguration.html +1 -1
  70. package/docs/interfaces/ExportFormat.html +2 -2
  71. package/docs/interfaces/ExportOptions.html +1 -1
  72. package/docs/interfaces/GridRowPinningConfiguration.html +1 -1
  73. package/docs/interfaces/GridRowReorderingConfiguration.html +2 -2
  74. package/docs/interfaces/PaginationConfiguration.html +1 -1
  75. package/docs/interfaces/PaginationState.html +1 -1
  76. package/docs/media/_tokens.scss +29 -8
  77. package/docs/media/package.json +4 -5
  78. package/docs/media/state-persistence.html +0 -10
  79. package/docs/modules.html +1 -1
  80. package/docs/types/DataPipelineParams.html +2 -2
  81. package/docs/types/EditMode.html +2 -2
  82. package/docs/types/GridLocaleText.html +1 -1
  83. package/docs/types/PaginationMode.html +1 -1
  84. package/docs/variables/EN_LOCALE.html +3 -3
  85. package/docs/variables/esLocale.html +1 -1
  86. package/i18n/en.d.ts +109 -1
  87. package/i18n/en.js +109 -1
  88. package/i18n/en.js.map +1 -1
  89. package/i18n/es.js +109 -1
  90. package/i18n/es.js.map +1 -1
  91. package/index.d.ts +2 -0
  92. package/index.js +2 -0
  93. package/index.js.map +1 -1
  94. package/internal/column-types.js +1 -1
  95. package/internal/column-types.js.map +1 -1
  96. package/internal/feature-module.d.ts +22 -0
  97. package/internal/feature-module.js +5 -0
  98. package/internal/feature-module.js.map +1 -1
  99. package/internal/index.d.ts +2 -2
  100. package/internal/index.js +1 -1
  101. package/internal/index.js.map +1 -1
  102. package/internal/utils.d.ts +14 -0
  103. package/internal/utils.js +5 -0
  104. package/internal/utils.js.map +1 -1
  105. package/package.json +1 -2
  106. package/setup.d.ts +12 -11
  107. package/setup.js +12 -4
  108. package/setup.js.map +1 -1
  109. package/styles/_common.css.js +1 -1
  110. package/styles/_common.css.js.map +1 -1
  111. package/styles/_tokens.css.js +1 -1
  112. package/styles/_tokens.css.js.map +1 -1
  113. package/styles/body-cell/body-cell.css.js +1 -1
  114. package/styles/body-cell/body-cell.css.js.map +1 -1
  115. package/styles/body-row/body-row.css.js +1 -1
  116. package/styles/body-row/body-row.css.js.map +1 -1
  117. package/styles/filter-row/filter-row.css.js +1 -1
  118. package/styles/filter-row/filter-row.css.js.map +1 -1
  119. package/styles/grid/_grid.base.css.js +1 -1
  120. package/styles/grid/_grid.base.css.js.map +1 -1
  121. package/styles/grid/grid.css.js +1 -1
  122. package/styles/grid/grid.css.js.map +1 -1
  123. package/styles/group-header-row/group-header-row.css.js +1 -1
  124. package/styles/group-header-row/group-header-row.css.js.map +1 -1
  125. package/styles/header-cell/header-cell.css.js +1 -1
  126. package/styles/header-cell/header-cell.css.js.map +1 -1
  127. package/styles/header-row/header-row.base.css.js +1 -1
  128. package/styles/header-row/header-row.base.css.js.map +1 -1
  129. package/styles/paginator/paginator.css.js +1 -1
  130. package/styles/paginator/paginator.css.js.map +1 -1
  131. package/styles/toolbar/toolbar.css.js +1 -1
  132. package/styles/toolbar/toolbar.css.js.map +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"row.js","sourceRoot":"","sources":["../../src/components/row.ts"],"names":[],"mappings":"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","sourcesContent":["import { consume } from '@lit/context';\nimport { html, LitElement, nothing } from 'lit';\nimport { property, queryAll } from 'lit/decorators.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport type { RowGhostInit } from '../controllers/row-reorder.js';\nimport { gridStateContext, type StateController } from '../controllers/state.js';\nimport type { PresentedRow } from '../internal/feature-module.js';\nimport { registerComponent } from '../internal/register.js';\nimport { GRID_ROW_TAG } from '../internal/tags.js';\nimport type { ActiveNode, ColumnConfiguration, Keys } from '../internal/types.js';\nimport { getPinEdge } from '../internal/utils.js';\nimport { styles } from '../styles/body-row/body-row.css.js';\nimport ApexGridCell from './cell.js';\n\n/** The six-dot grip drawn inside the row-reorder drag handle. */\nconst GRIP_ICON = html`<svg\n part=\"reorder-grip\"\n viewBox=\"0 0 16 16\"\n width=\"16\"\n height=\"16\"\n aria-hidden=\"true\"\n>\n <circle cx=\"6\" cy=\"3.5\" r=\"1.25\" />\n <circle cx=\"10\" cy=\"3.5\" r=\"1.25\" />\n <circle cx=\"6\" cy=\"8\" r=\"1.25\" />\n <circle cx=\"10\" cy=\"8\" r=\"1.25\" />\n <circle cx=\"6\" cy=\"12.5\" r=\"1.25\" />\n <circle cx=\"10\" cy=\"12.5\" r=\"1.25\" />\n</svg>`;\n\n/**\n * Component representing the DOM row in the Apex grid.\n */\nexport default class ApexGridRow<T extends object> extends LitElement {\n public static get tagName() {\n return GRID_ROW_TAG;\n }\n public static override styles = styles;\n\n public static register(): void {\n registerComponent(ApexGridRow, ApexGridCell);\n }\n\n @queryAll(ApexGridCell.tagName)\n protected _cells!: NodeListOf<ApexGridCell<T>>;\n\n @property({ attribute: false })\n public data!: T;\n\n @property({ attribute: false })\n public columns: Array<ColumnConfiguration<T>> = [];\n\n /** Cumulative pin offsets (px) keyed by column key. */\n @property({ attribute: false })\n public pinOffsets: Map<unknown, number> = new Map();\n\n public get cells() {\n return Array.from(this._cells);\n }\n\n @consume({ context: gridStateContext, subscribe: true })\n @property({ attribute: false })\n public state!: StateController<T>;\n\n @property({ attribute: false })\n public activeNode!: ActiveNode<T>;\n\n @property({ attribute: false, type: Number })\n public index = -1;\n\n /** Reflects current selection state so SCSS can highlight the row. */\n @property({ type: Boolean, reflect: true })\n public selected = false;\n\n /** Reflects current expansion state so SCSS can rotate the chevron. */\n @property({ type: Boolean, reflect: true })\n public expanded = false;\n\n /** Reflects pointer-drag state (row reorder) so SCSS can dim the source. */\n @property({ type: Boolean, reflect: true })\n public dragging = false;\n\n /** Reflects keyboard-grab state (row reorder) so SCSS can outline the row. */\n @property({ type: Boolean, reflect: true })\n public grabbed = false;\n\n /** Reveal the spreadsheet row-number gutter cell (transient formula coordinate hint). */\n @property({ type: Boolean })\n public coordinateHints = false;\n\n /** The column key currently being edited in this row, or `null`. */\n @property({ attribute: false })\n public editingKey: Keys<T> | null = null;\n\n /**\n * Reactive token from {@link StateController.decorationVersion}, forwarded to\n * each cell so a decoration-only change re-renders the row's cells. Stays `0`\n * for the community grid.\n */\n @property({ attribute: false, type: Number })\n public decorationVersion = 0;\n\n /**\n * Reactive token from {@link EditingController.validationVersion}, forwarded to\n * each cell so a validation-only change re-renders the row's cells (toggling\n * `aria-invalid` and the inline error node). Stays `0` until the first\n * validation failure.\n */\n @property({ attribute: false, type: Number })\n public validationVersion = 0;\n\n /**\n * Result of the feature-module row presenter for the current update, or\n * `null` when no module renders this row full-width (the normal case).\n * Computed in {@link willUpdate} and consumed in {@link render}.\n */\n #presented: PresentedRow | null = null;\n\n #dragStartX = 0;\n #dragStartY = 0;\n\n /**\n * Arms a row drag. In handle mode only the grip starts one; in whole-row mode\n * a press anywhere except an interactive sub-part does. The move / up plumbing\n * lives on the grid host (see {@link RowReorderController.armPointerDrag}), so\n * a live-swap that recycles this row's DOM can't break the gesture.\n */\n #handleReorderPointerDown = (event: PointerEvent) => {\n const reorder = this.state?.rowReorder;\n if (!reorder?.enabled || event.button !== 0 || !this.data) return;\n // Pinned rows are not reorder sources (F4 scope).\n if (this.state.rowPin.isPinned(this.data)) return;\n\n const path = event.composedPath();\n const onHandle = path.some(\n (node) =>\n node instanceof Element && (node.getAttribute?.('part') ?? '').includes('reorder-handle')\n );\n\n if (reorder.handleMode) {\n // Handle mode: only the grip starts a drag. The rest of the row stays free\n // for selection / editing / text selection.\n if (!onHandle) return;\n // Own the gesture: keep the grid's body handler from treating the press as\n // a cell interaction, and suppress native text/element drag-selection.\n event.preventDefault();\n event.stopPropagation();\n } else {\n // Whole-row mode: a drag begins anywhere except an interactive sub-part\n // (editor, checkbox, button).\n const target = path[0];\n if (\n target instanceof Element &&\n target.closest?.('input, button, a, select, textarea, [data-apex-editor]')\n ) {\n return;\n }\n }\n\n this.#dragStartX = event.clientX;\n this.#dragStartY = event.clientY;\n // The controller snapshots the ghost the instant the drag engages (the row\n // is still in place then), seeded from the original press point.\n reorder.armPointerDrag(\n this.data,\n () => this.#captureGhost(this.#dragStartX, this.#dragStartY),\n event\n );\n };\n\n /**\n * Snapshots the row's visible cells (text, width, alignment) and bounding rect\n * so the controller can paint a faithful floating ghost. Invoked once, at the\n * moment the drag engages.\n */\n #captureGhost(clientX: number, clientY: number): RowGhostInit {\n const rect = this.getBoundingClientRect();\n const cells = this.cells.map((cell) => {\n const el = cell as unknown as HTMLElement;\n return {\n text: (el.textContent ?? '').replace(/\\s+/g, ' ').trim(),\n width: el.getBoundingClientRect().width,\n align: getComputedStyle(el).textAlign,\n };\n });\n return { rect, clientX, clientY, cells };\n }\n\n public override connectedCallback(): void {\n super.connectedCallback();\n this.setAttribute('exportparts', 'cell');\n this.setAttribute('role', 'row');\n this.addEventListener('pointerdown', this.#handleReorderPointerDown);\n }\n\n public override disconnectedCallback(): void {\n this.removeEventListener('pointerdown', this.#handleReorderPointerDown);\n super.disconnectedCallback();\n }\n\n /**\n * The number of \"chrome\" rows (header + filter) above the body. Used to\n * derive `aria-rowindex` from {@link index}. Set by the parent grid.\n */\n @property({ attribute: false, type: Number })\n public ariaRowOffset = 1;\n\n protected override willUpdate() {\n this.setAttribute('aria-rowindex', String(this.index + this.ariaRowOffset + 1));\n\n // Ask feature modules whether this row is rendered full-width (e.g. an\n // enterprise group header). When one owns it, the row is not a selectable\n // data row — it carries its own level/expanded semantics and skips the\n // selection/tree aria below.\n this.#presented = this.state\n ? this.state.presentRow(this.data, { columns: this.columns, rowIndex: this.index })\n : null;\n if (this.#presented) {\n this.selected = false;\n this.removeAttribute('aria-selected');\n if (typeof this.#presented.level === 'number') {\n this.setAttribute('aria-level', String(this.#presented.level));\n } else {\n this.removeAttribute('aria-level');\n }\n if (typeof this.#presented.expanded === 'boolean') {\n this.setAttribute('aria-expanded', this.#presented.expanded ? 'true' : 'false');\n } else {\n this.removeAttribute('aria-expanded');\n }\n return;\n }\n\n this.selected = Boolean(this.state?.selection.isSelected(this.data));\n this.expanded = Boolean(this.state?.expansion.isExpanded(this.data));\n if (this.state?.selection.enabled) {\n this.setAttribute('aria-selected', this.selected ? 'true' : 'false');\n } else {\n this.removeAttribute('aria-selected');\n }\n\n // Tree mode reports aria-level (1-based depth) and aria-expanded for\n // parent rows; expansion mode shares the same attribute on detail-panel\n // rows. Tree wins when both are enabled since it's the more structural\n // semantic (the row represents a tree node).\n const tree = this.state?.tree;\n const treeMeta = tree?.enabled ? tree.getMeta(this.data) : undefined;\n if (treeMeta) {\n this.setAttribute('aria-level', String(treeMeta.depth + 1));\n if (treeMeta.hasChildren) {\n this.setAttribute('aria-expanded', tree!.isExpanded(this.data) ? 'true' : 'false');\n } else {\n this.removeAttribute('aria-expanded');\n }\n } else {\n this.removeAttribute('aria-level');\n if (this.state?.expansion.enabled) {\n this.setAttribute('aria-expanded', this.expanded ? 'true' : 'false');\n } else {\n this.removeAttribute('aria-expanded');\n }\n }\n }\n\n /**\n * Leading row-number gutter cell (transient spreadsheet coordinate hint). Shown\n * only while `coordinateHints` is on; pinned rows render an empty spacer (their\n * band-local index is not a meaningful A1 row number) so the track stays\n * aligned. Presentational: the accessible row index is `aria-rowindex`.\n */\n protected renderRowNumber() {\n if (!this.coordinateHints) return nothing;\n const pinned = Boolean(this.state?.rowPin?.isPinned(this.data));\n return html`<div part=\"row-number-cell\" data-pinned=\"start\" aria-hidden=\"true\">\n ${pinned ? nothing : html`<span part=\"row-number\">${this.index + 1}</span>`}\n </div>`;\n }\n\n /**\n * Leading drag-handle (grip) cell. Rendered only in handle mode; pinned rows\n * get an empty spacer so the grid track stays aligned. The cell is\n * presentational (`aria-hidden`) — the accessible reorder path is the keyboard\n * grab flow, not this pointer affordance.\n */\n protected renderReorderHandle() {\n const reorder = this.state?.rowReorder;\n if (!reorder?.showHandleColumn) return nothing;\n const draggable = !this.state?.rowPin?.isPinned(this.data);\n return html`<div part=\"reorder-handle-cell\" data-pinned=\"start\" aria-hidden=\"true\">\n ${draggable ? html`<span part=\"reorder-handle\">${GRIP_ICON}</span>` : nothing}\n </div>`;\n }\n\n protected renderExpansionToggle(colindex: number) {\n const expansion = this.state?.expansion;\n if (!expansion?.showToggleColumn) return nothing;\n const canExpand = expansion.canExpand(this.data) || expansion.isExpanded(this.data);\n const expanded = this.expanded;\n const handleClick = (event: MouseEvent) => {\n event.stopPropagation();\n if (!canExpand) return;\n void expansion.toggleRow(this.data);\n };\n return html`<div\n part=\"expansion-cell\"\n role=\"gridcell\"\n aria-colindex=${colindex}\n data-pinned=\"start\"\n >\n <button\n type=\"button\"\n part=\"expansion-toggle\"\n aria-label=${\n expanded ? this.state.localize('row.collapse') : this.state.localize('row.expand')\n }\n aria-expanded=${expanded ? 'true' : 'false'}\n ?disabled=${!canExpand}\n @click=${handleClick}\n >\n <svg\n part=\"expansion-chevron\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n width=\"14\"\n height=\"14\"\n >\n <path\n d=\"M9 6l6 6-6 6\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n </div>`;\n }\n\n protected renderDetailPanel() {\n const expansion = this.state?.expansion;\n if (!expansion?.isExpanded(this.data)) return nothing;\n const template = this.state.host.expansion?.detailTemplate;\n if (typeof template !== 'function') return nothing;\n const content = template({\n data: this.data,\n rowIndex: this.index,\n parent: this.state.host,\n });\n return html`<div part=\"detail-panel\" role=\"region\" aria-label=${this.state.localize('row.detail')}>${content}</div>`;\n }\n\n protected renderSelectionCell(colindex: number) {\n if (!this.state?.selection.showCheckboxColumn) return nothing;\n const selected = this.selected;\n const handleChange = (event: Event) => {\n const mouseEvent = event as Event & {\n shiftKey?: boolean;\n ctrlKey?: boolean;\n metaKey?: boolean;\n };\n // The native `change` event on a checkbox doesn't expose modifier keys\n // — they're carried on the preceding `click`. We handle Shift/Ctrl in\n // the click listener below; the change handler covers keyboard toggles\n // (Space on a focused checkbox) which always behave as plain toggles.\n void mouseEvent;\n this.state.selection.toggleRow(this.data);\n };\n const handleClick = (event: MouseEvent) => {\n // Prevent the click from bubbling to the grid's body click handler\n // (which would otherwise re-target the active cell to a non-existent\n // selection column).\n event.stopPropagation();\n if (event.shiftKey && this.state.selection.mode === 'multiple') {\n event.preventDefault();\n void this.state.selection.rangeToggle(this.data);\n return;\n }\n if ((event.ctrlKey || event.metaKey) && this.state.selection.mode === 'multiple') {\n event.preventDefault();\n void this.state.selection.additiveToggle(this.data);\n return;\n }\n // Plain click: let the default checkbox toggle proceed; `change` will\n // commit the new state via `toggleRow`.\n };\n return html`<div\n part=\"selection-cell\"\n role=\"gridcell\"\n aria-colindex=${colindex}\n data-pinned=\"start\"\n >\n <input\n type=\"checkbox\"\n part=\"selection-checkbox\"\n aria-label=${this.state.localize('row.select')}\n .checked=${selected}\n @click=${handleClick}\n @change=${handleChange}\n />\n </div>`;\n }\n\n protected override render() {\n // Full-width module-rendered row (e.g. a group header): render the module's\n // content spanning all columns, like the master-detail panel, and skip the\n // normal selection/expansion/cell grid.\n if (this.#presented) {\n return html`<div part=${this.#presented.part ?? 'group-row'} style=\"grid-column: 1 / -1\">\n ${this.#presented.content}\n </div>`;\n }\n\n // A row index can transiently fall beyond the current data — e.g. while a\n // server-side / infinite row model resizes `data` on a filter or sort\n // change, the virtualizer may render a stale index for a frame. Render\n // nothing until the real item arrives, rather than dereferencing undefined.\n if (this.data == null) return nothing;\n\n const { column: key, row: index } = this.activeNode;\n\n // Track aria-colindex (1-based) across the auto chrome columns and the\n // data columns. Selection comes first, then expansion, then data.\n let colCursor = 0;\n const selectionCol = this.state?.selection.showCheckboxColumn ? ++colCursor : 0;\n const expansionCol = this.state?.expansion.showToggleColumn ? ++colCursor : 0;\n\n // Keyed by column.key so the same `<apex-grid-cell>` follows its\n // column through a reorder swap — required for the column-reorder FLIP\n // animation in ReorderController to track motion per cell.\n return html`\n ${this.renderRowNumber()}\n ${this.renderReorderHandle()}\n ${this.renderSelectionCell(selectionCol)}\n ${this.renderExpansionToggle(expansionCol)}\n ${repeat(\n this.columns,\n (column) => String(column.key),\n (column, colIndex) => {\n if (column.hidden) return nothing;\n const offset = this.pinOffsets.get(column.key);\n const pinStyle =\n column.pinned && typeof offset === 'number' ? `--apex-pin-offset:${offset}px` : '';\n const edge = getPinEdge(this.columns, colIndex);\n const editing = this.editingKey === column.key;\n const ariaColindex = ++colCursor;\n return html`<apex-grid-cell\n part=\"cell\"\n data-pinned=${column.pinned ?? 'none'}\n data-pin-edge=${edge ?? 'none'}\n data-cell-type=${column.type ?? 'string'}\n style=${pinStyle}\n .active=${key === column.key && index === this.index}\n .editing=${editing}\n .column=${column}\n .row=${this as ApexGridRow<T>}\n .value=${this.data[column.key]}\n .colindex=${ariaColindex}\n .decorationVersion=${this.decorationVersion}\n .validationVersion=${this.validationVersion}\n ></apex-grid-cell>`;\n }\n )}\n ${this.renderDetailPanel()}\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n [ApexGridRow.tagName]: ApexGridRow<object>;\n }\n}\n"]}
1
+ {"version":3,"file":"row.js","sourceRoot":"","sources":["../../src/components/row.ts"],"names":[],"mappings":"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","sourcesContent":["import { consume } from '@lit/context';\nimport { html, LitElement, nothing } from 'lit';\nimport { property, queryAll } from 'lit/decorators.js';\nimport { repeat } from 'lit/directives/repeat.js';\nimport type { RowGhostInit } from '../controllers/row-reorder.js';\nimport { gridStateContext, type StateController } from '../controllers/state.js';\nimport type { PresentedRow } from '../internal/feature-module.js';\nimport { registerComponent } from '../internal/register.js';\nimport { GRID_ROW_TAG } from '../internal/tags.js';\nimport type { ActiveNode, ColumnConfiguration, Keys } from '../internal/types.js';\nimport { getPinEdge } from '../internal/utils.js';\nimport { styles } from '../styles/body-row/body-row.css.js';\nimport ApexGridCell from './cell.js';\n\n/** The six-dot grip drawn inside the row-reorder drag handle. */\nconst GRIP_ICON = html`<svg\n part=\"reorder-grip\"\n viewBox=\"0 0 16 16\"\n width=\"16\"\n height=\"16\"\n aria-hidden=\"true\"\n>\n <circle cx=\"6\" cy=\"3.5\" r=\"1.25\" />\n <circle cx=\"10\" cy=\"3.5\" r=\"1.25\" />\n <circle cx=\"6\" cy=\"8\" r=\"1.25\" />\n <circle cx=\"10\" cy=\"8\" r=\"1.25\" />\n <circle cx=\"6\" cy=\"12.5\" r=\"1.25\" />\n <circle cx=\"10\" cy=\"12.5\" r=\"1.25\" />\n</svg>`;\n\n/**\n * Component representing the DOM row in the Apex grid.\n */\nexport default class ApexGridRow<T extends object> extends LitElement {\n public static get tagName() {\n return GRID_ROW_TAG;\n }\n public static override styles = styles;\n\n public static register(): void {\n registerComponent(ApexGridRow, ApexGridCell);\n }\n\n @queryAll(ApexGridCell.tagName)\n protected _cells!: NodeListOf<ApexGridCell<T>>;\n\n @property({ attribute: false })\n public data!: T;\n\n @property({ attribute: false })\n public columns: Array<ColumnConfiguration<T>> = [];\n\n /** Cumulative pin offsets (px) keyed by column key. */\n @property({ attribute: false })\n public pinOffsets: Map<unknown, number> = new Map();\n\n public get cells() {\n return Array.from(this._cells);\n }\n\n @consume({ context: gridStateContext, subscribe: true })\n @property({ attribute: false })\n public state!: StateController<T>;\n\n @property({ attribute: false })\n public activeNode!: ActiveNode<T>;\n\n @property({ attribute: false, type: Number })\n public index = -1;\n\n /** Reflects current selection state so SCSS can highlight the row. */\n @property({ type: Boolean, reflect: true })\n public selected = false;\n\n /** Reflects current expansion state so SCSS can rotate the chevron. */\n @property({ type: Boolean, reflect: true })\n public expanded = false;\n\n /** Reflects pointer-drag state (row reorder) so SCSS can dim the source. */\n @property({ type: Boolean, reflect: true })\n public dragging = false;\n\n /** Reflects keyboard-grab state (row reorder) so SCSS can outline the row. */\n @property({ type: Boolean, reflect: true })\n public grabbed = false;\n\n /** Reveal the spreadsheet row-number gutter cell (transient formula coordinate hint). */\n @property({ type: Boolean })\n public coordinateHints = false;\n\n /** The column key currently being edited in this row, or `null`. */\n @property({ attribute: false })\n public editingKey: Keys<T> | null = null;\n\n /**\n * Reactive token from {@link StateController.decorationVersion}, forwarded to\n * each cell so a decoration-only change re-renders the row's cells. Stays `0`\n * for the community grid.\n */\n @property({ attribute: false, type: Number })\n public decorationVersion = 0;\n\n /**\n * Reactive token from {@link EditingController.validationVersion}, forwarded to\n * each cell so a validation-only change re-renders the row's cells (toggling\n * `aria-invalid` and the inline error node). Stays `0` until the first\n * validation failure.\n */\n @property({ attribute: false, type: Number })\n public validationVersion = 0;\n\n /**\n * Result of the feature-module row presenter for the current update, or\n * `null` when no module renders this row full-width (the normal case).\n * Computed in {@link willUpdate} and consumed in {@link render}.\n */\n #presented: PresentedRow | null = null;\n\n #dragStartX = 0;\n #dragStartY = 0;\n\n /**\n * Arms a row drag. In handle mode only the grip starts one; in whole-row mode\n * a press anywhere except an interactive sub-part does. The move / up plumbing\n * lives on the grid host (see {@link RowReorderController.armPointerDrag}), so\n * a live-swap that recycles this row's DOM can't break the gesture.\n */\n #handleReorderPointerDown = (event: PointerEvent) => {\n const reorder = this.state?.rowReorder;\n if (!reorder?.enabled || event.button !== 0 || !this.data) return;\n // Pinned rows are not reorder sources (F4 scope).\n if (this.state.rowPin.isPinned(this.data)) return;\n\n const path = event.composedPath();\n const onHandle = path.some(\n (node) =>\n node instanceof Element && (node.getAttribute?.('part') ?? '').includes('reorder-handle')\n );\n\n if (reorder.handleMode) {\n // Handle mode: only the grip starts a drag. The rest of the row stays free\n // for selection / editing / text selection.\n if (!onHandle) return;\n // Own the gesture: keep the grid's body handler from treating the press as\n // a cell interaction, and suppress native text/element drag-selection.\n event.preventDefault();\n event.stopPropagation();\n } else {\n // Whole-row mode: a drag begins anywhere except an interactive sub-part\n // (editor, checkbox, button).\n const target = path[0];\n if (\n target instanceof Element &&\n target.closest?.('input, button, a, select, textarea, [data-apex-editor]')\n ) {\n return;\n }\n }\n\n this.#dragStartX = event.clientX;\n this.#dragStartY = event.clientY;\n // The controller snapshots the ghost the instant the drag engages (the row\n // is still in place then), seeded from the original press point.\n reorder.armPointerDrag(\n this.data,\n () => this.#captureGhost(this.#dragStartX, this.#dragStartY),\n event\n );\n };\n\n /**\n * Snapshots the row's visible cells (text, width, alignment) and bounding rect\n * so the controller can paint a faithful floating ghost. Invoked once, at the\n * moment the drag engages.\n */\n #captureGhost(clientX: number, clientY: number): RowGhostInit {\n const rect = this.getBoundingClientRect();\n const cells = this.cells.map((cell) => {\n const el = cell as unknown as HTMLElement;\n return {\n text: (el.textContent ?? '').replace(/\\s+/g, ' ').trim(),\n width: el.getBoundingClientRect().width,\n align: getComputedStyle(el).textAlign,\n };\n });\n return { rect, clientX, clientY, cells };\n }\n\n public override connectedCallback(): void {\n super.connectedCallback();\n this.setAttribute('exportparts', 'cell');\n this.setAttribute('role', 'row');\n this.addEventListener('pointerdown', this.#handleReorderPointerDown);\n }\n\n public override disconnectedCallback(): void {\n this.removeEventListener('pointerdown', this.#handleReorderPointerDown);\n super.disconnectedCallback();\n }\n\n /**\n * The number of \"chrome\" rows (header + filter) above the body. Used to\n * derive `aria-rowindex` from {@link index}. Set by the parent grid.\n */\n @property({ attribute: false, type: Number })\n public ariaRowOffset = 1;\n\n protected override willUpdate() {\n this.setAttribute('aria-rowindex', String(this.index + this.ariaRowOffset + 1));\n\n // Ask feature modules whether this row is rendered full-width (e.g. an\n // enterprise group header). When one owns it, the row is not a selectable\n // data row — it carries its own level/expanded semantics and skips the\n // selection/tree aria below.\n this.#presented = this.state\n ? this.state.presentRow(this.data, { columns: this.columns, rowIndex: this.index })\n : null;\n if (this.#presented) {\n this.selected = false;\n this.removeAttribute('aria-selected');\n if (typeof this.#presented.level === 'number') {\n this.setAttribute('aria-level', String(this.#presented.level));\n } else {\n this.removeAttribute('aria-level');\n }\n if (typeof this.#presented.expanded === 'boolean') {\n this.setAttribute('aria-expanded', this.#presented.expanded ? 'true' : 'false');\n } else {\n this.removeAttribute('aria-expanded');\n }\n return;\n }\n\n this.selected = Boolean(this.state?.selection.isSelected(this.data));\n this.expanded = Boolean(this.state?.expansion.isExpanded(this.data));\n if (this.state?.selection.enabled) {\n this.setAttribute('aria-selected', this.selected ? 'true' : 'false');\n } else {\n this.removeAttribute('aria-selected');\n }\n\n // Tree mode reports aria-level (1-based depth) and aria-expanded for\n // parent rows; expansion mode shares the same attribute on detail-panel\n // rows. Tree wins when both are enabled since it's the more structural\n // semantic (the row represents a tree node).\n const tree = this.state?.tree;\n const treeMeta = tree?.enabled ? tree.getMeta(this.data) : undefined;\n if (treeMeta) {\n this.setAttribute('aria-level', String(treeMeta.depth + 1));\n if (treeMeta.hasChildren) {\n this.setAttribute('aria-expanded', tree!.isExpanded(this.data) ? 'true' : 'false');\n } else {\n this.removeAttribute('aria-expanded');\n }\n } else {\n // A module may attach tree/expansion ARIA to a normal cell-rendered row\n // (e.g. pivoting's expandable parent rows, which keep their value cells).\n const aria = this.state?.describeRow(this.data, {\n columns: this.columns,\n rowIndex: this.index,\n });\n if (aria) {\n if (typeof aria.level === 'number') {\n this.setAttribute('aria-level', String(aria.level));\n } else {\n this.removeAttribute('aria-level');\n }\n if (typeof aria.expanded === 'boolean') {\n this.setAttribute('aria-expanded', aria.expanded ? 'true' : 'false');\n } else {\n this.removeAttribute('aria-expanded');\n }\n } else {\n this.removeAttribute('aria-level');\n if (this.state?.expansion.enabled) {\n this.setAttribute('aria-expanded', this.expanded ? 'true' : 'false');\n } else {\n this.removeAttribute('aria-expanded');\n }\n }\n }\n }\n\n /**\n * Leading row-number gutter cell (transient spreadsheet coordinate hint). Shown\n * only while `coordinateHints` is on; pinned rows render an empty spacer (their\n * band-local index is not a meaningful A1 row number) so the track stays\n * aligned. Presentational: the accessible row index is `aria-rowindex`.\n */\n protected renderRowNumber() {\n if (!this.coordinateHints) return nothing;\n const pinned = Boolean(this.state?.rowPin?.isPinned(this.data));\n return html`<div part=\"row-number-cell\" data-pinned=\"start\" aria-hidden=\"true\">\n ${pinned ? nothing : html`<span part=\"row-number\">${this.index + 1}</span>`}\n </div>`;\n }\n\n /**\n * Leading drag-handle (grip) cell. Rendered only in handle mode; pinned rows\n * get an empty spacer so the grid track stays aligned. The cell is\n * presentational (`aria-hidden`) — the accessible reorder path is the keyboard\n * grab flow, not this pointer affordance.\n */\n protected renderReorderHandle() {\n const reorder = this.state?.rowReorder;\n if (!reorder?.showHandleColumn) return nothing;\n const draggable = !this.state?.rowPin?.isPinned(this.data);\n return html`<div part=\"reorder-handle-cell\" data-pinned=\"start\" aria-hidden=\"true\">\n ${draggable ? html`<span part=\"reorder-handle\">${GRIP_ICON}</span>` : nothing}\n </div>`;\n }\n\n protected renderExpansionToggle(colindex: number) {\n const expansion = this.state?.expansion;\n if (!expansion?.showToggleColumn) return nothing;\n const canExpand = expansion.canExpand(this.data) || expansion.isExpanded(this.data);\n const expanded = this.expanded;\n const handleClick = (event: MouseEvent) => {\n event.stopPropagation();\n if (!canExpand) return;\n void expansion.toggleRow(this.data);\n };\n return html`<div\n part=\"expansion-cell\"\n role=\"gridcell\"\n aria-colindex=${colindex}\n data-pinned=\"start\"\n >\n <button\n type=\"button\"\n part=\"expansion-toggle\"\n aria-label=${\n expanded ? this.state.localize('row.collapse') : this.state.localize('row.expand')\n }\n aria-expanded=${expanded ? 'true' : 'false'}\n ?disabled=${!canExpand}\n @click=${handleClick}\n >\n <svg\n part=\"expansion-chevron\"\n viewBox=\"0 0 24 24\"\n aria-hidden=\"true\"\n width=\"14\"\n height=\"14\"\n >\n <path\n d=\"M9 6l6 6-6 6\"\n fill=\"none\"\n stroke=\"currentColor\"\n stroke-width=\"2\"\n stroke-linecap=\"round\"\n stroke-linejoin=\"round\"\n />\n </svg>\n </button>\n </div>`;\n }\n\n protected renderDetailPanel() {\n const expansion = this.state?.expansion;\n if (!expansion?.isExpanded(this.data)) return nothing;\n const template = this.state.host.expansion?.detailTemplate;\n if (typeof template !== 'function') return nothing;\n const content = template({\n data: this.data,\n rowIndex: this.index,\n parent: this.state.host,\n });\n return html`<div part=\"detail-panel\" role=\"region\" aria-label=${this.state.localize('row.detail')}>${content}</div>`;\n }\n\n protected renderSelectionCell(colindex: number) {\n if (!this.state?.selection.showCheckboxColumn) return nothing;\n const selected = this.selected;\n const handleChange = (event: Event) => {\n const mouseEvent = event as Event & {\n shiftKey?: boolean;\n ctrlKey?: boolean;\n metaKey?: boolean;\n };\n // The native `change` event on a checkbox doesn't expose modifier keys\n // — they're carried on the preceding `click`. We handle Shift/Ctrl in\n // the click listener below; the change handler covers keyboard toggles\n // (Space on a focused checkbox) which always behave as plain toggles.\n void mouseEvent;\n this.state.selection.toggleRow(this.data);\n };\n const handleClick = (event: MouseEvent) => {\n // Prevent the click from bubbling to the grid's body click handler\n // (which would otherwise re-target the active cell to a non-existent\n // selection column).\n event.stopPropagation();\n if (event.shiftKey && this.state.selection.mode === 'multiple') {\n event.preventDefault();\n void this.state.selection.rangeToggle(this.data);\n return;\n }\n if ((event.ctrlKey || event.metaKey) && this.state.selection.mode === 'multiple') {\n event.preventDefault();\n void this.state.selection.additiveToggle(this.data);\n return;\n }\n // Plain click: let the default checkbox toggle proceed; `change` will\n // commit the new state via `toggleRow`.\n };\n // The checkbox itself is 14x14, well under the 24x24 WCAG 2.2 AA minimum\n // (2.5.8), and growing it would make a chunky box out of a deliberately\n // small mark. Instead the whole cell is the target: a click anywhere in it\n // forwards to the checkbox, which is both compliant and what people expect\n // of a selection column. Clicks that land on the checkbox are left alone,\n // or the forward would toggle twice and cancel out.\n const forwardToCheckbox = (event: MouseEvent) => {\n const target = event.target as HTMLElement;\n if (target instanceof HTMLInputElement) return;\n event.currentTarget instanceof HTMLElement &&\n event.currentTarget.querySelector<HTMLInputElement>('input[type=\"checkbox\"]')?.click();\n };\n return html`<div\n part=\"selection-cell\"\n role=\"gridcell\"\n aria-colindex=${colindex}\n data-pinned=\"start\"\n @click=${forwardToCheckbox}\n >\n <input\n type=\"checkbox\"\n part=\"selection-checkbox\"\n aria-label=${this.state.localize('row.select')}\n .checked=${selected}\n @click=${handleClick}\n @change=${handleChange}\n />\n </div>`;\n }\n\n protected override render() {\n // Full-width module-rendered row (e.g. a group header): render the module's\n // content spanning all columns, like the master-detail panel, and skip the\n // normal selection/expansion/cell grid.\n if (this.#presented) {\n return html`<div part=${this.#presented.part ?? 'group-row'} style=\"grid-column: 1 / -1\">\n ${this.#presented.content}\n </div>`;\n }\n\n // A row index can transiently fall beyond the current data — e.g. while a\n // server-side / infinite row model resizes `data` on a filter or sort\n // change, the virtualizer may render a stale index for a frame. Render\n // nothing until the real item arrives, rather than dereferencing undefined.\n if (this.data == null) return nothing;\n\n const { column: key, row: index } = this.activeNode;\n\n // Track aria-colindex (1-based) across the auto chrome columns and the\n // data columns. Selection comes first, then expansion, then data.\n let colCursor = 0;\n const selectionCol = this.state?.selection.showCheckboxColumn ? ++colCursor : 0;\n const expansionCol = this.state?.expansion.showToggleColumn ? ++colCursor : 0;\n\n // Keyed by column.key so the same `<apex-grid-cell>` follows its\n // column through a reorder swap — required for the column-reorder FLIP\n // animation in ReorderController to track motion per cell.\n return html`\n ${this.renderRowNumber()}\n ${this.renderReorderHandle()}\n ${this.renderSelectionCell(selectionCol)}\n ${this.renderExpansionToggle(expansionCol)}\n ${repeat(\n this.columns,\n (column) => String(column.key),\n (column, colIndex) => {\n if (column.hidden) return nothing;\n const offset = this.pinOffsets.get(column.key);\n const pinStyle =\n column.pinned && typeof offset === 'number' ? `--apex-pin-offset:${offset}px` : '';\n const edge = getPinEdge(this.columns, colIndex);\n const editing = this.editingKey === column.key;\n const ariaColindex = ++colCursor;\n return html`<apex-grid-cell\n part=\"cell\"\n data-pinned=${column.pinned ?? 'none'}\n data-pin-edge=${edge ?? 'none'}\n data-cell-type=${column.type ?? 'string'}\n style=${pinStyle}\n .active=${key === column.key && index === this.index}\n .editing=${editing}\n .column=${column}\n .row=${this as ApexGridRow<T>}\n .value=${this.data[column.key]}\n .colindex=${ariaColindex}\n .decorationVersion=${this.decorationVersion}\n .validationVersion=${this.validationVersion}\n ></apex-grid-cell>`;\n }\n )}\n ${this.renderDetailPanel()}\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n [ApexGridRow.tagName]: ApexGridRow<object>;\n }\n}\n"]}
@@ -1,9 +1,13 @@
1
1
  import { LitVirtualizer } from '@lit-labs/virtualizer/LitVirtualizer.js';
2
+ import type { PropertyValues } from 'lit';
2
3
  export default class ApexVirtualizer extends LitVirtualizer {
4
+ #private;
3
5
  static get tagName(): "apex-virtualizer";
4
6
  static register(): void;
5
7
  scroller: boolean;
6
- connectedCallback(): Promise<void>;
8
+ connectedCallback(): void;
9
+ disconnectedCallback(): void;
10
+ protected updated(changed: PropertyValues): void;
7
11
  }
8
12
  declare global {
9
13
  interface HTMLElementTagNameMap {
@@ -1,21 +1,91 @@
1
1
  import { LitVirtualizer } from '@lit-labs/virtualizer/LitVirtualizer.js';
2
2
  import { registerComponent } from '../internal/register.js';
3
3
  import { GRID_BODY } from '../internal/tags.js';
4
+ const SIZER_ATTRIBUTE = 'virtualizer-sizer';
5
+ const MAX_RECOVERY_ATTEMPTS = 3;
4
6
  export default class ApexVirtualizer extends LitVirtualizer {
5
7
  constructor() {
6
8
  super(...arguments);
9
+ this.#viewportObserver = null;
10
+ this.#visibleHeight = 0;
11
+ this.#pendingCheck = 0;
12
+ this.#recoveryAttempts = 0;
7
13
  this.scroller = false;
8
14
  }
15
+ #viewportObserver;
16
+ #visibleHeight;
17
+ #pendingCheck;
18
+ #recoveryAttempts;
9
19
  static get tagName() {
10
20
  return GRID_BODY;
11
21
  }
12
22
  static register() {
13
23
  registerComponent(ApexVirtualizer);
14
24
  }
15
- async connectedCallback() {
16
- await super.layoutComplete;
25
+ connectedCallback() {
17
26
  super.connectedCallback();
18
27
  this.setAttribute('tabindex', '0');
28
+ this.#observeViewport();
29
+ }
30
+ disconnectedCallback() {
31
+ this.#viewportObserver?.disconnect();
32
+ this.#viewportObserver = null;
33
+ this.#visibleHeight = 0;
34
+ if (this.#pendingCheck) {
35
+ cancelAnimationFrame(this.#pendingCheck);
36
+ this.#pendingCheck = 0;
37
+ }
38
+ super.disconnectedCallback();
39
+ }
40
+ updated(changed) {
41
+ super.updated(changed);
42
+ this.#scheduleViewportCheck();
43
+ }
44
+ #observeViewport() {
45
+ if (this.#viewportObserver || typeof IntersectionObserver === 'undefined')
46
+ return;
47
+ this.#viewportObserver = new IntersectionObserver((entries) => {
48
+ this.#visibleHeight = entries.at(-1)?.intersectionRect.height ?? 0;
49
+ this.#recoveryAttempts = 0;
50
+ this.#scheduleViewportCheck();
51
+ });
52
+ this.#viewportObserver.observe(this);
53
+ }
54
+ #scheduleViewportCheck() {
55
+ if (this.#pendingCheck || !this.isConnected)
56
+ return;
57
+ if (!this.items?.length || this.#hasRenderedRows())
58
+ return;
59
+ this.#pendingCheck = requestAnimationFrame(() => {
60
+ this.#pendingCheck = requestAnimationFrame(() => {
61
+ this.#pendingCheck = 0;
62
+ this.#recoverIfStale();
63
+ });
64
+ });
65
+ }
66
+ #recoverIfStale() {
67
+ if (!this.isConnected)
68
+ return;
69
+ const items = this.items;
70
+ if (!Array.isArray(items) || items.length === 0)
71
+ return;
72
+ if (this.#hasRenderedRows()) {
73
+ this.#recoveryAttempts = 0;
74
+ return;
75
+ }
76
+ if (this.#visibleHeight <= 0)
77
+ return;
78
+ if (this.#recoveryAttempts >= MAX_RECOVERY_ATTEMPTS)
79
+ return;
80
+ this.#recoveryAttempts++;
81
+ this.items = items.slice();
82
+ }
83
+ #hasRenderedRows() {
84
+ for (let child = this.firstElementChild; child; child = child.nextElementSibling) {
85
+ if (!child.hasAttribute(SIZER_ATTRIBUTE))
86
+ return true;
87
+ }
88
+ return false;
19
89
  }
20
90
  }
21
91
  //# sourceMappingURL=virtualizer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"virtualizer.js","sourceRoot":"","sources":["../../src/components/virtualizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,yCAAyC,CAAC;AACzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAC5D,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAEhD,MAAM,CAAC,OAAO,OAAO,eAAgB,SAAQ,cAAc;IAA3D;;QAckB,aAAQ,GAAG,KAAK,CAAC;IAQnC,CAAC;IArBQ,MAAM,KAAK,OAAO;QACvB,OAAO,SAAS,CAAC;IACnB,CAAC;IAEM,MAAM,CAAC,QAAQ;QACpB,iBAAiB,CAAC,eAAe,CAAC,CAAC;IACrC,CAAC;IASe,KAAK,CAAC,iBAAiB;QACrC,MAAM,KAAK,CAAC,cAAc,CAAC;QAE3B,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,IAAI,CAAC,YAAY,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC;IACrC,CAAC;CACF","sourcesContent":["import { LitVirtualizer } from '@lit-labs/virtualizer/LitVirtualizer.js';\nimport { registerComponent } from '../internal/register.js';\nimport { GRID_BODY } from '../internal/tags.js';\n\nexport default class ApexVirtualizer extends LitVirtualizer {\n public static get tagName() {\n return GRID_BODY;\n }\n\n public static register(): void {\n registerComponent(ApexVirtualizer);\n }\n\n // The virtualizer used to own vertical scrolling, which made it a scroll container\n // and broke `position: sticky` for body cells in pinned columns (cells would anchor\n // to the virtualizer instead of the horizontally-scrolling grid host). With\n // `scroller = false` the grid host owns both axes, so headers and pinned body cells\n // share a single sticky containing block.\n public override scroller = false;\n\n public override async connectedCallback() {\n await super.layoutComplete;\n\n super.connectedCallback();\n this.setAttribute('tabindex', '0');\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n [ApexVirtualizer.tagName]: ApexVirtualizer;\n }\n}\n"]}
1
+ {"version":3,"file":"virtualizer.js","sourceRoot":"","sources":["../../src/components/virtualizer.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitVirtualizer } from '@lit-labs/virtualizer/LitVirtualizer.js';\nimport type { PropertyValues } from 'lit';\nimport { registerComponent } from '../internal/register.js';\nimport { GRID_BODY } from '../internal/tags.js';\n\n/**\n * Attribute the upstream virtualizer stamps on the spacer element it appends in\n * scroller mode. It is not a rendered row, so it is skipped when asking whether\n * the body rendered anything.\n */\nconst SIZER_ATTRIBUTE = 'virtualizer-sizer';\n\n/**\n * Re-measure attempts allowed per geometry change. A grid that still renders\n * nothing after this many tries has a cause we cannot fix by re-measuring, so\n * we stop rather than spin.\n */\nconst MAX_RECOVERY_ATTEMPTS = 3;\n\nexport default class ApexVirtualizer extends LitVirtualizer {\n /**\n * Watches the host's intersection with the window, which is the one input to\n * the upstream viewport measurement that has no invalidation signal of its\n * own. See the note on `#observeViewport`.\n */\n #viewportObserver: IntersectionObserver | null = null;\n\n /**\n * Height of the host's last observed intersection with the window: the\n * viewport height the layout should be working from. Zero means an empty\n * range is the *correct* render and there is nothing to recover.\n */\n #visibleHeight = 0;\n\n #pendingCheck = 0;\n\n #recoveryAttempts = 0;\n\n public static get tagName() {\n return GRID_BODY;\n }\n\n public static register(): void {\n registerComponent(ApexVirtualizer);\n }\n\n // The virtualizer used to own vertical scrolling, which made it a scroll container\n // and broke `position: sticky` for body cells in pinned columns (cells would anchor\n // to the virtualizer instead of the horizontally-scrolling grid host). With\n // `scroller = false` the grid host owns both axes, so headers and pinned body cells\n // share a single sticky containing block.\n public override scroller = false;\n\n public override connectedCallback() {\n // Nothing may be awaited before this call. The upstream virtualizer is only\n // created (and reconnected) from the element's own Lit update cycle, which\n // `super.connectedCallback()` is what starts. Deferring it past an await on\n // any virtualizer state deadlocks on a reconnect: the promise waits for a\n // layout that waits for the update that this call would have scheduled.\n super.connectedCallback();\n this.setAttribute('tabindex', '0');\n this.#observeViewport();\n }\n\n public override disconnectedCallback() {\n this.#viewportObserver?.disconnect();\n this.#viewportObserver = null;\n // Geometry is meaningless while detached; the observer re-reports on connect.\n this.#visibleHeight = 0;\n if (this.#pendingCheck) {\n cancelAnimationFrame(this.#pendingCheck);\n this.#pendingCheck = 0;\n }\n super.disconnectedCallback();\n }\n\n protected override updated(changed: PropertyValues) {\n super.updated(changed);\n this.#scheduleViewportCheck();\n }\n\n /**\n * The upstream virtualizer derives its viewport from the intersection of the\n * host, its clipping ancestors and the window, and clears the rendered range\n * outright when that intersection is zero-height, while still sizing the\n * scroll extent from the full item count. A grid that is laid out while it\n * sits outside the window (an iframe not yet sized by its host page, a panel\n * still settling, content above it that has not finished loading) therefore\n * ends up reporting a correct row count and scroll extent with no rows in it.\n *\n * That state is not self-correcting, because the only invalidation signals\n * upstream listens for are `ResizeObserver` size changes and scroll events:\n * an element that *moves* into view, or a window that resizes around a\n * fixed-size host, fires neither. The grid then stays empty until something\n * unrelated forces a re-render, which is why the failure reads as a race and\n * heals on the first interaction.\n *\n * `IntersectionObserver` fires on exactly the missing signal, so it is what\n * arms the recovery check.\n *\n * @see https://github.com/apexcharts/apex-grid/issues/31\n */\n #observeViewport(): void {\n if (this.#viewportObserver || typeof IntersectionObserver === 'undefined') return;\n this.#viewportObserver = new IntersectionObserver((entries) => {\n this.#visibleHeight = entries.at(-1)?.intersectionRect.height ?? 0;\n // Fresh geometry, so the attempt budget starts over.\n this.#recoveryAttempts = 0;\n this.#scheduleViewportCheck();\n });\n this.#viewportObserver.observe(this);\n }\n\n #scheduleViewportCheck(): void {\n // Healthy path: one element lookup and out, no frame scheduled.\n if (this.#pendingCheck || !this.isConnected) return;\n if (!this.items?.length || this.#hasRenderedRows()) return;\n // Two frames, matching what the virtualizer itself waits before calling a\n // layout settled. Checking sooner would flag a first paint still in flight.\n this.#pendingCheck = requestAnimationFrame(() => {\n this.#pendingCheck = requestAnimationFrame(() => {\n this.#pendingCheck = 0;\n this.#recoverIfStale();\n });\n });\n }\n\n #recoverIfStale(): void {\n if (!this.isConnected) return;\n\n const items = this.items;\n if (!Array.isArray(items) || items.length === 0) return;\n\n if (this.#hasRenderedRows()) {\n this.#recoveryAttempts = 0;\n return;\n }\n\n // No visible slice means rendering nothing is correct: the grid is scrolled\n // out of view, inside a collapsed panel, or hidden. Leave it alone.\n if (this.#visibleHeight <= 0) return;\n if (this.#recoveryAttempts >= MAX_RECOVERY_ATTEMPTS) return;\n\n this.#recoveryAttempts++;\n // Re-assigning `items` with a new array identity is the public lever that\n // makes the virtualizer re-run its layout, and so re-measure the viewport.\n // Unlike a synthetic scroll event it cannot disturb a pending\n // `scrollIntoView`, which the layout holds as a pin until a real scroll.\n this.items = items.slice();\n }\n\n #hasRenderedRows(): boolean {\n for (let child = this.firstElementChild; child; child = child.nextElementSibling) {\n if (!child.hasAttribute(SIZER_ATTRIBUTE)) return true;\n }\n return false;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n [ApexVirtualizer.tagName]: ApexVirtualizer;\n }\n}\n"]}
@@ -106,16 +106,16 @@ export class ExpansionController {
106
106
  this.expanded = next;
107
107
  this.host.requestUpdate();
108
108
  if (added.length === 1 && removed.length === 0) {
109
- this.host.announce('Row expanded');
109
+ this.host.announce(this.host.localize('announce.rowExpanded'));
110
110
  }
111
111
  else if (added.length === 0 && removed.length === 1) {
112
- this.host.announce('Row collapsed');
112
+ this.host.announce(this.host.localize('announce.rowCollapsed'));
113
113
  }
114
114
  else if (added.length > 0 && next.size === added.length + this.expanded.size - added.length) {
115
- this.host.announce(`${added.length} rows expanded`);
115
+ this.host.announce(this.host.localize('announce.rowsExpanded', { count: added.length }));
116
116
  }
117
117
  else if (removed.length > 0 && next.size === 0) {
118
- this.host.announce('All rows collapsed');
118
+ this.host.announce(this.host.localize('announce.allRowsCollapsed'));
119
119
  }
120
120
  this.host.emitEvent('rowExpanded', {
121
121
  detail: { added, removed, expanded: Array.from(this.expanded) },
@@ -1 +1 @@
1
- {"version":3,"file":"expansion.js","sourceRoot":"","sources":["../../src/controllers/expansion.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\nimport type { GridHost } from '../internal/types.js';\n\n/**\n * The default expansion configuration used when the grid has none set.\n *\n * @remarks\n * `detailTemplate` defaults to `null` here — the controller will refuse to\n * toggle rows when the configuration is missing or no template is provided.\n */\nexport const DEFAULT_EXPANSION_CONFIG = Object.freeze({\n enabled: false,\n showToggleColumn: true,\n});\n\n/**\n * Reactive controller backing row expansion (master-detail).\n *\n * @remarks\n * Expansion state is reference-based — the controller holds a `Set` of row\n * data references so the expansion set survives sort / filter / pagination as\n * long as those operations preserve row identity (the default in-place\n * pipeline does). Replacing {@link ApexGrid.data} wholesale invalidates any\n * expanded rows that are no longer present; consumers should call\n * {@link collapseAll} or re-apply expansion afterwards.\n *\n * Mutations go through the cancellable `rowExpanding` event and emit a\n * follow-up `rowExpanded` event, mirroring the pattern used by selection\n * and editing.\n */\nexport class ExpansionController<T extends object> implements ReactiveController {\n /** Set of currently expanded row data references. */\n public expanded: Set<T> = new Set();\n\n constructor(protected host: GridHost<T>) {\n this.host.addController(this);\n }\n\n public hostConnected() {}\n\n /** Whether expansion is enabled at the grid level. */\n public get enabled(): boolean {\n return Boolean(this.host.expansion?.enabled);\n }\n\n /** Whether the built-in chevron toggle column should be rendered. */\n public get showToggleColumn(): boolean {\n return (\n this.enabled &&\n (this.host.expansion?.showToggleColumn ?? DEFAULT_EXPANSION_CONFIG.showToggleColumn)\n );\n }\n\n /** Whether `row` is currently expanded. */\n public isExpanded(row: T): boolean {\n return this.expanded.has(row);\n }\n\n /**\n * Whether `row` is permitted to expand. Combines the grid-wide `enabled`\n * flag, the presence of a `detailTemplate`, and the optional per-row\n * `isExpandable` predicate.\n */\n public canExpand(row: T): boolean {\n if (!this.enabled) return false;\n if (typeof this.host.expansion?.detailTemplate !== 'function') return false;\n const predicate = this.host.expansion?.isExpandable;\n return predicate ? Boolean(predicate(row)) : true;\n }\n\n /** Snapshot of currently expanded rows in insertion order. */\n public expandedRows(): T[] {\n return Array.from(this.expanded);\n }\n\n /** Toggles the expansion of `row`. */\n public async toggleRow(row: T): Promise<boolean> {\n if (!this.canExpand(row) && !this.expanded.has(row)) return false;\n const next = new Set(this.expanded);\n if (next.has(row)) next.delete(row);\n else next.add(row);\n return this.#commit(next);\n }\n\n /** Expands `row`. No-op when the row is already expanded or not expandable. */\n public async expandRow(row: T): Promise<boolean> {\n if (this.expanded.has(row)) return true;\n if (!this.canExpand(row)) return false;\n const next = new Set(this.expanded);\n next.add(row);\n return this.#commit(next);\n }\n\n /** Collapses `row`. No-op when the row is not expanded. */\n public async collapseRow(row: T): Promise<boolean> {\n if (!this.expanded.has(row)) return true;\n const next = new Set(this.expanded);\n next.delete(row);\n return this.#commit(next);\n }\n\n /**\n * Expands every expandable row in {@link ApexGrid.dataView}. Skips rows\n * the optional `isExpandable` predicate rejects.\n */\n public async expandAll(): Promise<boolean> {\n if (!this.enabled || typeof this.host.expansion?.detailTemplate !== 'function') return false;\n const predicate = this.host.expansion?.isExpandable;\n const next = new Set(this.expanded);\n for (const row of this.host.dataView as ReadonlyArray<T>) {\n if (!predicate || predicate(row)) next.add(row);\n }\n return this.#commit(next);\n }\n\n /** Collapses every currently expanded row. */\n public async collapseAll(): Promise<boolean> {\n if (this.expanded.size === 0) return true;\n return this.#commit(new Set());\n }\n\n /**\n * Replaces the expansion set with `rows`. Used by the public\n * {@link ApexGrid.expandedRows} setter for programmatic control.\n */\n public async replaceExpansion(rows: ReadonlyArray<T>): Promise<boolean> {\n if (!this.enabled) return false;\n const predicate = this.host.expansion?.isExpandable;\n const next = new Set(predicate ? rows.filter((row) => predicate(row)) : rows);\n return this.#commit(next);\n }\n\n async #commit(next: Set<T>): Promise<boolean> {\n const added: T[] = [];\n const removed: T[] = [];\n for (const row of next) {\n if (!this.expanded.has(row)) added.push(row);\n }\n for (const row of this.expanded) {\n if (!next.has(row)) removed.push(row);\n }\n if (added.length === 0 && removed.length === 0) return true;\n\n const proceed = this.host.emitEvent('rowExpanding', {\n detail: {\n added,\n removed,\n current: Array.from(this.expanded),\n next: Array.from(next),\n },\n cancelable: true,\n });\n if (!proceed) return false;\n\n this.expanded = next;\n this.host.requestUpdate();\n\n if (added.length === 1 && removed.length === 0) {\n this.host.announce('Row expanded');\n } else if (added.length === 0 && removed.length === 1) {\n this.host.announce('Row collapsed');\n } else if (added.length > 0 && next.size === added.length + this.expanded.size - added.length) {\n this.host.announce(`${added.length} rows expanded`);\n } else if (removed.length > 0 && next.size === 0) {\n this.host.announce('All rows collapsed');\n }\n\n this.host.emitEvent('rowExpanded', {\n detail: { added, removed, expanded: Array.from(this.expanded) },\n });\n return true;\n }\n}\n"]}
1
+ {"version":3,"file":"expansion.js","sourceRoot":"","sources":["../../src/controllers/expansion.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\nimport type { GridHost } from '../internal/types.js';\n\n/**\n * The default expansion configuration used when the grid has none set.\n *\n * @remarks\n * `detailTemplate` defaults to `null` here — the controller will refuse to\n * toggle rows when the configuration is missing or no template is provided.\n */\nexport const DEFAULT_EXPANSION_CONFIG = Object.freeze({\n enabled: false,\n showToggleColumn: true,\n});\n\n/**\n * Reactive controller backing row expansion (master-detail).\n *\n * @remarks\n * Expansion state is reference-based — the controller holds a `Set` of row\n * data references so the expansion set survives sort / filter / pagination as\n * long as those operations preserve row identity (the default in-place\n * pipeline does). Replacing {@link ApexGrid.data} wholesale invalidates any\n * expanded rows that are no longer present; consumers should call\n * {@link collapseAll} or re-apply expansion afterwards.\n *\n * Mutations go through the cancellable `rowExpanding` event and emit a\n * follow-up `rowExpanded` event, mirroring the pattern used by selection\n * and editing.\n */\nexport class ExpansionController<T extends object> implements ReactiveController {\n /** Set of currently expanded row data references. */\n public expanded: Set<T> = new Set();\n\n constructor(protected host: GridHost<T>) {\n this.host.addController(this);\n }\n\n public hostConnected() {}\n\n /** Whether expansion is enabled at the grid level. */\n public get enabled(): boolean {\n return Boolean(this.host.expansion?.enabled);\n }\n\n /** Whether the built-in chevron toggle column should be rendered. */\n public get showToggleColumn(): boolean {\n return (\n this.enabled &&\n (this.host.expansion?.showToggleColumn ?? DEFAULT_EXPANSION_CONFIG.showToggleColumn)\n );\n }\n\n /** Whether `row` is currently expanded. */\n public isExpanded(row: T): boolean {\n return this.expanded.has(row);\n }\n\n /**\n * Whether `row` is permitted to expand. Combines the grid-wide `enabled`\n * flag, the presence of a `detailTemplate`, and the optional per-row\n * `isExpandable` predicate.\n */\n public canExpand(row: T): boolean {\n if (!this.enabled) return false;\n if (typeof this.host.expansion?.detailTemplate !== 'function') return false;\n const predicate = this.host.expansion?.isExpandable;\n return predicate ? Boolean(predicate(row)) : true;\n }\n\n /** Snapshot of currently expanded rows in insertion order. */\n public expandedRows(): T[] {\n return Array.from(this.expanded);\n }\n\n /** Toggles the expansion of `row`. */\n public async toggleRow(row: T): Promise<boolean> {\n if (!this.canExpand(row) && !this.expanded.has(row)) return false;\n const next = new Set(this.expanded);\n if (next.has(row)) next.delete(row);\n else next.add(row);\n return this.#commit(next);\n }\n\n /** Expands `row`. No-op when the row is already expanded or not expandable. */\n public async expandRow(row: T): Promise<boolean> {\n if (this.expanded.has(row)) return true;\n if (!this.canExpand(row)) return false;\n const next = new Set(this.expanded);\n next.add(row);\n return this.#commit(next);\n }\n\n /** Collapses `row`. No-op when the row is not expanded. */\n public async collapseRow(row: T): Promise<boolean> {\n if (!this.expanded.has(row)) return true;\n const next = new Set(this.expanded);\n next.delete(row);\n return this.#commit(next);\n }\n\n /**\n * Expands every expandable row in {@link ApexGrid.dataView}. Skips rows\n * the optional `isExpandable` predicate rejects.\n */\n public async expandAll(): Promise<boolean> {\n if (!this.enabled || typeof this.host.expansion?.detailTemplate !== 'function') return false;\n const predicate = this.host.expansion?.isExpandable;\n const next = new Set(this.expanded);\n for (const row of this.host.dataView as ReadonlyArray<T>) {\n if (!predicate || predicate(row)) next.add(row);\n }\n return this.#commit(next);\n }\n\n /** Collapses every currently expanded row. */\n public async collapseAll(): Promise<boolean> {\n if (this.expanded.size === 0) return true;\n return this.#commit(new Set());\n }\n\n /**\n * Replaces the expansion set with `rows`. Used by the public\n * {@link ApexGrid.expandedRows} setter for programmatic control.\n */\n public async replaceExpansion(rows: ReadonlyArray<T>): Promise<boolean> {\n if (!this.enabled) return false;\n const predicate = this.host.expansion?.isExpandable;\n const next = new Set(predicate ? rows.filter((row) => predicate(row)) : rows);\n return this.#commit(next);\n }\n\n async #commit(next: Set<T>): Promise<boolean> {\n const added: T[] = [];\n const removed: T[] = [];\n for (const row of next) {\n if (!this.expanded.has(row)) added.push(row);\n }\n for (const row of this.expanded) {\n if (!next.has(row)) removed.push(row);\n }\n if (added.length === 0 && removed.length === 0) return true;\n\n const proceed = this.host.emitEvent('rowExpanding', {\n detail: {\n added,\n removed,\n current: Array.from(this.expanded),\n next: Array.from(next),\n },\n cancelable: true,\n });\n if (!proceed) return false;\n\n this.expanded = next;\n this.host.requestUpdate();\n\n if (added.length === 1 && removed.length === 0) {\n this.host.announce(this.host.localize('announce.rowExpanded'));\n } else if (added.length === 0 && removed.length === 1) {\n this.host.announce(this.host.localize('announce.rowCollapsed'));\n } else if (added.length > 0 && next.size === added.length + this.expanded.size - added.length) {\n this.host.announce(this.host.localize('announce.rowsExpanded', { count: added.length }));\n } else if (removed.length > 0 && next.size === 0) {\n this.host.announce(this.host.localize('announce.allRowsCollapsed'));\n }\n\n this.host.emitEvent('rowExpanded', {\n detail: { added, removed, expanded: Array.from(this.expanded) },\n });\n return true;\n }\n}\n"]}
@@ -86,6 +86,7 @@ export class FilterController {
86
86
  this.reset(key);
87
87
  this.#filter([]);
88
88
  await this.host.updateComplete;
89
+ this.#announce(key, 'cleared');
89
90
  this.#emitFilteredEvent({ key, state: this.get(key)?.all ?? [] });
90
91
  }
91
92
  async removeExpression(expression) {
@@ -99,6 +100,7 @@ export class FilterController {
99
100
  }
100
101
  this.#filter([]);
101
102
  await this.host.updateComplete;
103
+ this.#announce(expression.key, 'cleared');
102
104
  this.#emitFilteredEvent({ key: expression.key, state: state?.all ?? [] });
103
105
  }
104
106
  async filterWithEvent(expression, type) {
@@ -107,8 +109,17 @@ export class FilterController {
107
109
  }
108
110
  this.#filter(expression);
109
111
  await this.host.updateComplete;
112
+ if (type === 'add')
113
+ this.#announce(expression.key, 'applied');
110
114
  this.#emitFilteredEvent({ key: expression.key, state: this.get(expression.key)?.all ?? [] });
111
115
  }
116
+ #announce(key, kind) {
117
+ const column = this.host.getColumn(key);
118
+ const label = column?.headerText ?? String(key);
119
+ this.host.announce(this.host.localize(kind === 'applied' ? 'announce.filtered' : 'announce.filterCleared', {
120
+ label,
121
+ }));
122
+ }
112
123
  filter(expression) {
113
124
  this.#filter(asArray(expression).map((expr) => Object.assign(this.getDefaultExpression(this.host.getColumn(expr.key)), expr)));
114
125
  }
@@ -1 +1 @@
1
- {"version":3,"file":"filter.js","sourceRoot":"","sources":["../../src/controllers/filter.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\nimport type { ApexFilteredEvent } from '../components/grid.js';\nimport { PIPELINE } from '../internal/constants.js';\nimport type { ColumnConfiguration, GridHost, Keys } from '../internal/types.js';\nimport { asArray, getFilterOperandsFor } from '../internal/utils.js';\nimport { FilterState } from '../operations/filter/state.js';\nimport type { FilterExpression } from '../operations/filter/types.js';\n\nexport class FilterController<T extends object> implements ReactiveController {\n constructor(protected host: GridHost<T>) {\n this.host.addController(this);\n }\n\n public state: FilterState<T> = new FilterState();\n\n public get filterRow() {\n // @ts-expect-error - protected access\n return this.host.filterRow;\n }\n\n get #virtualizer() {\n // @ts-expect-error - protected access\n return this.host.scrollContainer;\n }\n\n #emitFilteringEvent(expression: FilterExpression<T>, type: 'add' | 'modify' | 'remove') {\n return this.host.emitEvent('filtering', {\n detail: {\n key: expression.key,\n expressions: [expression],\n type,\n },\n cancelable: true,\n });\n }\n\n #emitFilteredEvent(detail?: ApexFilteredEvent<T>) {\n return this.host.emitEvent('filtered', { detail });\n }\n\n #filter(expression: FilterExpression<T> | FilterExpression<T>[]) {\n for (const expr of asArray(expression)) {\n this.state.set(expr);\n }\n\n // HACK: In the case where the scrollTop is a large and amount and a big chunk of data is filtered out\n // HACK: the virtualizer can't recalculate its scroll position correctly. Thus, we reset the scrollTop state.\n this.#virtualizer?.scrollTo({ top: 0 });\n this.host.requestUpdate(PIPELINE);\n }\n\n public hostConnected() {}\n\n public hostUpdate(): void {\n this.filterRow?.requestUpdate();\n }\n\n public get(key: Keys<T>) {\n return this.state.get(key);\n }\n\n public reset(key?: Keys<T>) {\n key ? this.state.delete(key) : this.state.clear();\n }\n\n public setActiveColumn(column?: ColumnConfiguration<T>, triggerRect?: DOMRect) {\n const filterRow = this.filterRow;\n if (!filterRow) return;\n\n if (!column?.filter) {\n filterRow.active = false;\n return;\n }\n\n // Toggle: clicking the same column's filter while the panel is open closes it.\n if (filterRow.active && filterRow.column?.key === column.key) {\n filterRow.active = false;\n return;\n }\n\n filterRow.triggerRect = triggerRect ?? null;\n filterRow.column = column;\n filterRow.expression = this.getDefaultExpression(column);\n filterRow.active = true;\n this.host.requestUpdate();\n }\n\n public getDefaultExpression(column: ColumnConfiguration<T>) {\n const caseSensitive =\n typeof column.filter === 'boolean' ? false : Boolean(column.filter?.caseSensitive);\n const operands = getFilterOperandsFor(column);\n const keys = Object.keys(operands) as Keys<typeof operands>[];\n\n // XXX: Types\n return {\n key: column.key,\n condition: operands[keys[0]],\n caseSensitive,\n } as unknown as FilterExpression<T>;\n }\n\n public async removeAllExpressions(key: Keys<T>) {\n const state = this.get(key)?.all ?? [];\n\n if (\n !this.host.emitEvent('filtering', {\n detail: {\n key,\n expressions: state,\n type: 'remove',\n },\n cancelable: true,\n })\n ) {\n return;\n }\n\n this.reset(key);\n this.#filter([]);\n\n await this.host.updateComplete;\n this.#emitFilteredEvent({ key, state: this.get(key)?.all ?? [] });\n }\n\n public async removeExpression(expression: FilterExpression<T>) {\n const state = this.get(expression.key);\n\n if (!this.#emitFilteringEvent(expression, 'remove')) {\n return;\n }\n\n state?.remove(expression);\n\n if (state?.empty) {\n this.reset(state.key);\n }\n\n this.#filter([]);\n\n await this.host.updateComplete;\n this.#emitFilteredEvent({ key: expression.key, state: state?.all ?? [] });\n }\n\n public async filterWithEvent(expression: FilterExpression<T>, type: 'add' | 'modify' | 'remove') {\n if (!this.#emitFilteringEvent(expression, type)) {\n return;\n }\n\n this.#filter(expression);\n\n await this.host.updateComplete;\n this.#emitFilteredEvent({ key: expression.key, state: this.get(expression.key)?.all ?? [] });\n }\n\n public filter(expression: FilterExpression<T> | FilterExpression<T>[]) {\n this.#filter(\n asArray(expression).map((expr) =>\n Object.assign(this.getDefaultExpression(this.host.getColumn(expr.key)!), expr)\n )\n );\n }\n}\n"]}
1
+ {"version":3,"file":"filter.js","sourceRoot":"","sources":["../../src/controllers/filter.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,0BAA0B,CAAC;AAEpD,OAAO,EAAE,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAG5D,MAAM,OAAO,gBAAgB;IAC3B,YAAsB,IAAiB;QAAjB,SAAI,GAAJ,IAAI,CAAa;QAIhC,UAAK,GAAmB,IAAI,WAAW,EAAE,CAAC;QAH/C,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAID,IAAW,SAAS;QAElB,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC;IAC7B,CAAC;IAED,IAAI,YAAY;QAEd,OAAO,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC;IACnC,CAAC;IAED,mBAAmB,CAAC,UAA+B,EAAE,IAAiC;QACpF,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE;YACtC,MAAM,EAAE;gBACN,GAAG,EAAE,UAAU,CAAC,GAAG;gBACnB,WAAW,EAAE,CAAC,UAAU,CAAC;gBACzB,IAAI;aACL;YACD,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;IACL,CAAC;IAED,kBAAkB,CAAC,MAA6B;QAC9C,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC;IACrD,CAAC;IAED,OAAO,CAAC,UAAuD;QAC7D,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC;YACvC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACvB,CAAC;QAID,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;IAEM,aAAa,KAAI,CAAC;IAElB,UAAU;QACf,IAAI,CAAC,SAAS,EAAE,aAAa,EAAE,CAAC;IAClC,CAAC;IAEM,GAAG,CAAC,GAAY;QACrB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;IAEM,KAAK,CAAC,GAAa;QACxB,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACpD,CAAC;IAEM,eAAe,CAAC,MAA+B,EAAE,WAAqB;QAC3E,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC;QACjC,IAAI,CAAC,SAAS;YAAE,OAAO;QAEvB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;YACpB,SAAS,CAAC,MAAM,GAAG,KAAK,CAAC;YACzB,OAAO;QACT,CAAC;QAGD,IAAI,SAAS,CAAC,MAAM,IAAI,SAAS,CAAC,MAAM,EAAE,GAAG,KAAK,MAAM,CAAC,GAAG,EAAE,CAAC;YAC7D,SAAS,CAAC,MAAM,GAAG,KAAK,CAAC;YACzB,OAAO;QACT,CAAC;QAED,SAAS,CAAC,WAAW,GAAG,WAAW,IAAI,IAAI,CAAC;QAC5C,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC;QAC1B,SAAS,CAAC,UAAU,GAAG,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,CAAC;QACzD,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC;QACxB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;IAC5B,CAAC;IAEM,oBAAoB,CAAC,MAA8B;QACxD,MAAM,aAAa,GACjB,OAAO,MAAM,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;QACrF,MAAM,QAAQ,GAAG,oBAAoB,CAAC,MAAM,CAAC,CAAC;QAC9C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAA4B,CAAC;QAG9D,OAAO;YACL,GAAG,EAAE,MAAM,CAAC,GAAG;YACf,SAAS,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAC5B,aAAa;SACoB,CAAC;IACtC,CAAC;IAEM,KAAK,CAAC,oBAAoB,CAAC,GAAY;QAC5C,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC;QAEvC,IACE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE;YAChC,MAAM,EAAE;gBACN,GAAG;gBACH,WAAW,EAAE,KAAK;gBAClB,IAAI,EAAE,QAAQ;aACf;YACD,UAAU,EAAE,IAAI;SACjB,CAAC,EACF,CAAC;YACD,OAAO;QACT,CAAC;QAED,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAChB,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAEjB,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC;QAC/B,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC/B,IAAI,CAAC,kBAAkB,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,EAAE,EAAE,CAAC,CAAC;IACpE,CAAC;IAEM,KAAK,CAAC,gBAAgB,CAAC,UAA+B;QAC3D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QAEvC,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC;YACpD,OAAO;QACT,CAAC;QAED,KAAK,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;QAE1B,IAAI,KAAK,EAAE,KAAK,EAAE,CAAC;YACjB,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACxB,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAEjB,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC;QAC/B,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC1C,IAAI,CAAC,kBAAkB,CAAC,EAAE,GAAG,EAAE,UAAU,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE,CAAC,CAAC;IAC5E,CAAC;IAEM,KAAK,CAAC,eAAe,CAAC,UAA+B,EAAE,IAAiC;QAC7F,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,UAAU,EAAE,IAAI,CAAC,EAAE,CAAC;YAChD,OAAO;QACT,CAAC;QAED,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;QAEzB,MAAM,IAAI,CAAC,IAAI,CAAC,cAAc,CAAC;QAG/B,IAAI,IAAI,KAAK,KAAK;YAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;QAC9D,IAAI,CAAC,kBAAkB,CAAC,EAAE,GAAG,EAAE,UAAU,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI,EAAE,EAAE,CAAC,CAAC;IAC/F,CAAC;IAED,SAAS,CAAC,GAAY,EAAE,IAA2B;QACjD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QACxC,MAAM,KAAK,GAAG,MAAM,EAAE,UAAU,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;QAChD,IAAI,CAAC,IAAI,CAAC,QAAQ,CAChB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,mBAAmB,CAAC,CAAC,CAAC,wBAAwB,EAAE;YACtF,KAAK;SACN,CAAC,CACH,CAAC;IACJ,CAAC;IAEM,MAAM,CAAC,UAAuD;QACnE,IAAI,CAAC,OAAO,CACV,OAAO,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAC/B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAE,CAAC,EAAE,IAAI,CAAC,CAC/E,CACF,CAAC;IACJ,CAAC;CACF","sourcesContent":["import type { ReactiveController } from 'lit';\nimport type { ApexFilteredEvent } from '../components/grid.js';\nimport { PIPELINE } from '../internal/constants.js';\nimport type { ColumnConfiguration, GridHost, Keys } from '../internal/types.js';\nimport { asArray, getFilterOperandsFor } from '../internal/utils.js';\nimport { FilterState } from '../operations/filter/state.js';\nimport type { FilterExpression } from '../operations/filter/types.js';\n\nexport class FilterController<T extends object> implements ReactiveController {\n constructor(protected host: GridHost<T>) {\n this.host.addController(this);\n }\n\n public state: FilterState<T> = new FilterState();\n\n public get filterRow() {\n // @ts-expect-error - protected access\n return this.host.filterRow;\n }\n\n get #virtualizer() {\n // @ts-expect-error - protected access\n return this.host.scrollContainer;\n }\n\n #emitFilteringEvent(expression: FilterExpression<T>, type: 'add' | 'modify' | 'remove') {\n return this.host.emitEvent('filtering', {\n detail: {\n key: expression.key,\n expressions: [expression],\n type,\n },\n cancelable: true,\n });\n }\n\n #emitFilteredEvent(detail?: ApexFilteredEvent<T>) {\n return this.host.emitEvent('filtered', { detail });\n }\n\n #filter(expression: FilterExpression<T> | FilterExpression<T>[]) {\n for (const expr of asArray(expression)) {\n this.state.set(expr);\n }\n\n // HACK: In the case where the scrollTop is a large and amount and a big chunk of data is filtered out\n // HACK: the virtualizer can't recalculate its scroll position correctly. Thus, we reset the scrollTop state.\n this.#virtualizer?.scrollTo({ top: 0 });\n this.host.requestUpdate(PIPELINE);\n }\n\n public hostConnected() {}\n\n public hostUpdate(): void {\n this.filterRow?.requestUpdate();\n }\n\n public get(key: Keys<T>) {\n return this.state.get(key);\n }\n\n public reset(key?: Keys<T>) {\n key ? this.state.delete(key) : this.state.clear();\n }\n\n public setActiveColumn(column?: ColumnConfiguration<T>, triggerRect?: DOMRect) {\n const filterRow = this.filterRow;\n if (!filterRow) return;\n\n if (!column?.filter) {\n filterRow.active = false;\n return;\n }\n\n // Toggle: clicking the same column's filter while the panel is open closes it.\n if (filterRow.active && filterRow.column?.key === column.key) {\n filterRow.active = false;\n return;\n }\n\n filterRow.triggerRect = triggerRect ?? null;\n filterRow.column = column;\n filterRow.expression = this.getDefaultExpression(column);\n filterRow.active = true;\n this.host.requestUpdate();\n }\n\n public getDefaultExpression(column: ColumnConfiguration<T>) {\n const caseSensitive =\n typeof column.filter === 'boolean' ? false : Boolean(column.filter?.caseSensitive);\n const operands = getFilterOperandsFor(column);\n const keys = Object.keys(operands) as Keys<typeof operands>[];\n\n // XXX: Types\n return {\n key: column.key,\n condition: operands[keys[0]],\n caseSensitive,\n } as unknown as FilterExpression<T>;\n }\n\n public async removeAllExpressions(key: Keys<T>) {\n const state = this.get(key)?.all ?? [];\n\n if (\n !this.host.emitEvent('filtering', {\n detail: {\n key,\n expressions: state,\n type: 'remove',\n },\n cancelable: true,\n })\n ) {\n return;\n }\n\n this.reset(key);\n this.#filter([]);\n\n await this.host.updateComplete;\n this.#announce(key, 'cleared');\n this.#emitFilteredEvent({ key, state: this.get(key)?.all ?? [] });\n }\n\n public async removeExpression(expression: FilterExpression<T>) {\n const state = this.get(expression.key);\n\n if (!this.#emitFilteringEvent(expression, 'remove')) {\n return;\n }\n\n state?.remove(expression);\n\n if (state?.empty) {\n this.reset(state.key);\n }\n\n this.#filter([]);\n\n await this.host.updateComplete;\n this.#announce(expression.key, 'cleared');\n this.#emitFilteredEvent({ key: expression.key, state: state?.all ?? [] });\n }\n\n public async filterWithEvent(expression: FilterExpression<T>, type: 'add' | 'modify' | 'remove') {\n if (!this.#emitFilteringEvent(expression, type)) {\n return;\n }\n\n this.#filter(expression);\n\n await this.host.updateComplete;\n // Announce only on `add`: `modify` fires per keystroke while typing a\n // filter value and would flood the live region.\n if (type === 'add') this.#announce(expression.key, 'applied');\n this.#emitFilteredEvent({ key: expression.key, state: this.get(expression.key)?.all ?? [] });\n }\n\n #announce(key: Keys<T>, kind: 'applied' | 'cleared') {\n const column = this.host.getColumn(key);\n const label = column?.headerText ?? String(key);\n this.host.announce(\n this.host.localize(kind === 'applied' ? 'announce.filtered' : 'announce.filterCleared', {\n label,\n })\n );\n }\n\n public filter(expression: FilterExpression<T> | FilterExpression<T>[]) {\n this.#filter(\n asArray(expression).map((expr) =>\n Object.assign(this.getDefaultExpression(this.host.getColumn(expr.key)!), expr)\n )\n );\n }\n}\n"]}
@@ -77,7 +77,7 @@ export class HistoryController {
77
77
  return;
78
78
  command.revert();
79
79
  this.#redo.push(command);
80
- this.#afterReplay(command, 'Undo');
80
+ this.#afterReplay(command, 'undo');
81
81
  }
82
82
  redo() {
83
83
  const command = this.#redo.pop();
@@ -85,7 +85,7 @@ export class HistoryController {
85
85
  return;
86
86
  command.apply();
87
87
  this.#undo.push(command);
88
- this.#afterReplay(command, 'Redo');
88
+ this.#afterReplay(command, 'redo');
89
89
  }
90
90
  clear() {
91
91
  if (this.#undo.length === 0 && this.#redo.length === 0)
@@ -103,10 +103,17 @@ export class HistoryController {
103
103
  }
104
104
  this.#emitChanged();
105
105
  }
106
- #afterReplay(command, label) {
106
+ #afterReplay(command, kind) {
107
107
  this.host.requestUpdate(PIPELINE);
108
108
  const count = command instanceof CellEditCommand ? command.changes.length : 1;
109
- this.host.announce(`${label} ${count} cell ${count === 1 ? 'change' : 'changes'}`);
109
+ const key = kind === 'undo'
110
+ ? count === 1
111
+ ? 'announce.undoOne'
112
+ : 'announce.undoMany'
113
+ : count === 1
114
+ ? 'announce.redoOne'
115
+ : 'announce.redoMany';
116
+ this.host.announce(this.host.localize(key, { count }));
110
117
  this.#emitChanged();
111
118
  }
112
119
  #emitChanged() {
@@ -1 +1 @@
1
- {"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/controllers/history.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\nimport { PIPELINE } from '../internal/constants.js';\nimport type { GridHost, Keys } from '../internal/types.js';\n\n/** Default number of commands retained on the undo stack. */\nconst DEFAULT_STACK_SIZE = 100;\n\n/**\n * A single recorded cell mutation: the record reference, its column, and the\n * before / after values. `rowIndex` is the view-relative index at record time\n * and is used only for the replayed `cellValueChanged` event (the live record\n * reference is authoritative).\n */\nexport interface CellChange<T extends object> {\n record: T;\n key: Keys<T>;\n rowIndex: number;\n oldValue: unknown;\n newValue: unknown;\n}\n\n/**\n * A reversible unit of work on the history stacks.\n *\n * @remarks\n * `apply` re-performs the change (redo); `revert` undoes it. Cell-data edits use\n * {@link CellEditCommand}; the interface is deliberately open so later command\n * kinds (e.g. view-state) can join the same stacks.\n */\nexport interface EditCommand {\n apply(): void;\n revert(): void;\n}\n\n/**\n * One or more cell mutations that undo / redo as a single step. A single-cell\n * edit holds one change; a row-mode commit or a bulk paste / fill holds many so\n * one Ctrl+Z reverts the whole batch.\n */\nexport class CellEditCommand<T extends object> implements EditCommand {\n constructor(\n private host: GridHost<T>,\n public readonly changes: ReadonlyArray<CellChange<T>>\n ) {}\n\n public apply(): void {\n for (const change of this.changes) {\n this.#write(change, change.newValue);\n }\n }\n\n public revert(): void {\n // Revert in reverse so overlapping writes to the same cell unwind cleanly.\n for (let i = this.changes.length - 1; i >= 0; i -= 1) {\n this.#write(this.changes[i], this.changes[i].oldValue);\n }\n }\n\n #write(change: CellChange<T>, value: unknown): void {\n (change.record as Record<string, unknown>)[change.key as string] = value;\n // Re-emit `cellValueChanged` (never the cancellable `cellValueChanging`) so\n // data-bound consumers stay in sync. Validation and history recording are\n // intentionally skipped on replay. Prefer the record's current view index\n // when it is on the page; fall back to the recorded one.\n const liveIndex = this.host.pageItems.indexOf(change.record);\n this.host.emitEvent('cellValueChanged', {\n detail: {\n key: change.key,\n rowIndex: liveIndex >= 0 ? liveIndex : change.rowIndex,\n data: change.record,\n value,\n },\n });\n }\n}\n\n/**\n * Reactive controller owning the undo / redo stacks for cell-data edits.\n *\n * @remarks\n * Recording is driven from the {@link EditingController.applyCellEdit} choke\n * point: every successful write calls {@link record}. Single edits push one\n * command; {@link beginBatch} / {@link endBatch} coalesce a row-mode commit or a\n * bulk paste / fill into one command. Disabled unless\n * `editing.history.enabled` is set, so the community grid pays nothing.\n */\nexport class HistoryController<T extends object> implements ReactiveController {\n #undo: EditCommand[] = [];\n #redo: EditCommand[] = [];\n #batch: CellChange<T>[] | null = null;\n\n constructor(protected host: GridHost<T>) {\n this.host.addController(this);\n }\n\n public hostConnected(): void {}\n\n /** Whether undo / redo tracking is enabled. */\n public get enabled(): boolean {\n return Boolean(this.host.editing?.history?.enabled);\n }\n\n /** Maximum number of commands retained on the undo stack. */\n public get stackSize(): number {\n const size = this.host.editing?.history?.stackSize;\n return typeof size === 'number' && size > 0 ? size : DEFAULT_STACK_SIZE;\n }\n\n /** Whether there is at least one command to undo. */\n public get canUndo(): boolean {\n return this.#undo.length > 0;\n }\n\n /** Whether there is at least one command to redo. */\n public get canRedo(): boolean {\n return this.#redo.length > 0;\n }\n\n /**\n * Records a single cell mutation. Routed to the open batch when one is active,\n * otherwise pushed immediately as a standalone command. No-op when history is\n * disabled.\n */\n public record(change: CellChange<T>): void {\n if (!this.enabled) return;\n if (this.#batch) {\n this.#batch.push(change);\n return;\n }\n this.#push(new CellEditCommand(this.host, [change]));\n }\n\n /**\n * Opens a batch so subsequent {@link record} calls coalesce into one command.\n * Nestable calls are flattened (the outermost {@link endBatch} commits).\n */\n public beginBatch(): void {\n if (!this.enabled) return;\n this.#batch ??= [];\n }\n\n /**\n * Closes the open batch, pushing it as a single command when it captured any\n * changes.\n */\n public endBatch(): void {\n const batch = this.#batch;\n this.#batch = null;\n if (batch && batch.length > 0) {\n this.#push(new CellEditCommand(this.host, batch));\n }\n }\n\n /** Reverts the most recent command. No-op when the undo stack is empty. */\n public undo(): void {\n const command = this.#undo.pop();\n if (!command) return;\n command.revert();\n this.#redo.push(command);\n this.#afterReplay(command, 'Undo');\n }\n\n /** Re-applies the most recently undone command. No-op when nothing to redo. */\n public redo(): void {\n const command = this.#redo.pop();\n if (!command) return;\n command.apply();\n this.#undo.push(command);\n this.#afterReplay(command, 'Redo');\n }\n\n /** Clears both stacks (e.g. after a data reset). */\n public clear(): void {\n if (this.#undo.length === 0 && this.#redo.length === 0) return;\n this.#undo = [];\n this.#redo = [];\n this.#batch = null;\n this.#emitChanged();\n }\n\n #push(command: EditCommand): void {\n this.#undo.push(command);\n // A fresh edit invalidates the redo branch.\n this.#redo = [];\n // Evict the oldest commands once the stack exceeds its cap.\n while (this.#undo.length > this.stackSize) {\n this.#undo.shift();\n }\n this.#emitChanged();\n }\n\n #afterReplay(command: EditCommand, label: string): void {\n this.host.requestUpdate(PIPELINE);\n const count = command instanceof CellEditCommand ? command.changes.length : 1;\n this.host.announce(`${label} ${count} cell ${count === 1 ? 'change' : 'changes'}`);\n this.#emitChanged();\n }\n\n #emitChanged(): void {\n this.host.emitEvent('historyChanged', {\n detail: { canUndo: this.canUndo, canRedo: this.canRedo },\n });\n }\n}\n"]}
1
+ {"version":3,"file":"history.js","sourceRoot":"","sources":["../../src/controllers/history.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\nimport { PIPELINE } from '../internal/constants.js';\nimport type { GridHost, Keys } from '../internal/types.js';\n\n/** Default number of commands retained on the undo stack. */\nconst DEFAULT_STACK_SIZE = 100;\n\n/**\n * A single recorded cell mutation: the record reference, its column, and the\n * before / after values. `rowIndex` is the view-relative index at record time\n * and is used only for the replayed `cellValueChanged` event (the live record\n * reference is authoritative).\n */\nexport interface CellChange<T extends object> {\n record: T;\n key: Keys<T>;\n rowIndex: number;\n oldValue: unknown;\n newValue: unknown;\n}\n\n/**\n * A reversible unit of work on the history stacks.\n *\n * @remarks\n * `apply` re-performs the change (redo); `revert` undoes it. Cell-data edits use\n * {@link CellEditCommand}; the interface is deliberately open so later command\n * kinds (e.g. view-state) can join the same stacks.\n */\nexport interface EditCommand {\n apply(): void;\n revert(): void;\n}\n\n/**\n * One or more cell mutations that undo / redo as a single step. A single-cell\n * edit holds one change; a row-mode commit or a bulk paste / fill holds many so\n * one Ctrl+Z reverts the whole batch.\n */\nexport class CellEditCommand<T extends object> implements EditCommand {\n constructor(\n private host: GridHost<T>,\n public readonly changes: ReadonlyArray<CellChange<T>>\n ) {}\n\n public apply(): void {\n for (const change of this.changes) {\n this.#write(change, change.newValue);\n }\n }\n\n public revert(): void {\n // Revert in reverse so overlapping writes to the same cell unwind cleanly.\n for (let i = this.changes.length - 1; i >= 0; i -= 1) {\n this.#write(this.changes[i], this.changes[i].oldValue);\n }\n }\n\n #write(change: CellChange<T>, value: unknown): void {\n (change.record as Record<string, unknown>)[change.key as string] = value;\n // Re-emit `cellValueChanged` (never the cancellable `cellValueChanging`) so\n // data-bound consumers stay in sync. Validation and history recording are\n // intentionally skipped on replay. Prefer the record's current view index\n // when it is on the page; fall back to the recorded one.\n const liveIndex = this.host.pageItems.indexOf(change.record);\n this.host.emitEvent('cellValueChanged', {\n detail: {\n key: change.key,\n rowIndex: liveIndex >= 0 ? liveIndex : change.rowIndex,\n data: change.record,\n value,\n },\n });\n }\n}\n\n/**\n * Reactive controller owning the undo / redo stacks for cell-data edits.\n *\n * @remarks\n * Recording is driven from the {@link EditingController.applyCellEdit} choke\n * point: every successful write calls {@link record}. Single edits push one\n * command; {@link beginBatch} / {@link endBatch} coalesce a row-mode commit or a\n * bulk paste / fill into one command. Disabled unless\n * `editing.history.enabled` is set, so the community grid pays nothing.\n */\nexport class HistoryController<T extends object> implements ReactiveController {\n #undo: EditCommand[] = [];\n #redo: EditCommand[] = [];\n #batch: CellChange<T>[] | null = null;\n\n constructor(protected host: GridHost<T>) {\n this.host.addController(this);\n }\n\n public hostConnected(): void {}\n\n /** Whether undo / redo tracking is enabled. */\n public get enabled(): boolean {\n return Boolean(this.host.editing?.history?.enabled);\n }\n\n /** Maximum number of commands retained on the undo stack. */\n public get stackSize(): number {\n const size = this.host.editing?.history?.stackSize;\n return typeof size === 'number' && size > 0 ? size : DEFAULT_STACK_SIZE;\n }\n\n /** Whether there is at least one command to undo. */\n public get canUndo(): boolean {\n return this.#undo.length > 0;\n }\n\n /** Whether there is at least one command to redo. */\n public get canRedo(): boolean {\n return this.#redo.length > 0;\n }\n\n /**\n * Records a single cell mutation. Routed to the open batch when one is active,\n * otherwise pushed immediately as a standalone command. No-op when history is\n * disabled.\n */\n public record(change: CellChange<T>): void {\n if (!this.enabled) return;\n if (this.#batch) {\n this.#batch.push(change);\n return;\n }\n this.#push(new CellEditCommand(this.host, [change]));\n }\n\n /**\n * Opens a batch so subsequent {@link record} calls coalesce into one command.\n * Nestable calls are flattened (the outermost {@link endBatch} commits).\n */\n public beginBatch(): void {\n if (!this.enabled) return;\n this.#batch ??= [];\n }\n\n /**\n * Closes the open batch, pushing it as a single command when it captured any\n * changes.\n */\n public endBatch(): void {\n const batch = this.#batch;\n this.#batch = null;\n if (batch && batch.length > 0) {\n this.#push(new CellEditCommand(this.host, batch));\n }\n }\n\n /** Reverts the most recent command. No-op when the undo stack is empty. */\n public undo(): void {\n const command = this.#undo.pop();\n if (!command) return;\n command.revert();\n this.#redo.push(command);\n this.#afterReplay(command, 'undo');\n }\n\n /** Re-applies the most recently undone command. No-op when nothing to redo. */\n public redo(): void {\n const command = this.#redo.pop();\n if (!command) return;\n command.apply();\n this.#undo.push(command);\n this.#afterReplay(command, 'redo');\n }\n\n /** Clears both stacks (e.g. after a data reset). */\n public clear(): void {\n if (this.#undo.length === 0 && this.#redo.length === 0) return;\n this.#undo = [];\n this.#redo = [];\n this.#batch = null;\n this.#emitChanged();\n }\n\n #push(command: EditCommand): void {\n this.#undo.push(command);\n // A fresh edit invalidates the redo branch.\n this.#redo = [];\n // Evict the oldest commands once the stack exceeds its cap.\n while (this.#undo.length > this.stackSize) {\n this.#undo.shift();\n }\n this.#emitChanged();\n }\n\n #afterReplay(command: EditCommand, kind: 'undo' | 'redo'): void {\n this.host.requestUpdate(PIPELINE);\n const count = command instanceof CellEditCommand ? command.changes.length : 1;\n const key =\n kind === 'undo'\n ? count === 1\n ? 'announce.undoOne'\n : 'announce.undoMany'\n : count === 1\n ? 'announce.redoOne'\n : 'announce.redoMany';\n this.host.announce(this.host.localize(key, { count }));\n this.#emitChanged();\n }\n\n #emitChanged(): void {\n this.host.emitEvent('historyChanged', {\n detail: { canUndo: this.canUndo, canRedo: this.canRedo },\n });\n }\n}\n"]}
@@ -1,8 +1,9 @@
1
1
  import type { ReactiveController } from 'lit';
2
- import type { ActiveNode, GridHost, Keys } from '../internal/types.js';
2
+ import type { ActiveNode, ColumnConfiguration, GridHost, Keys } from '../internal/types.js';
3
3
  export declare class NavigationController<T extends object> implements ReactiveController {
4
+ #private;
4
5
  protected host: GridHost<T>;
5
- protected handlers: Map<string, (() => void) | (() => void) | (() => void) | (() => void) | (() => void) | (() => void) | (() => void)>;
6
+ protected handlers: Map<string, (() => void) | (() => void) | (() => void) | (() => void) | (() => void) | (() => void) | (() => void) | (() => void) | (() => void)>;
6
7
  protected get virtualizer(): import("../components/virtualizer.js").default;
7
8
  protected state: Map<import("../internal/types.js").NavigationState, ActiveNode<any>>;
8
9
  protected _active: Readonly<ActiveNode<any>>;
@@ -22,11 +23,33 @@ export declare class NavigationController<T extends object> implements ReactiveC
22
23
  protected getPreviousColumn(key: Keys<T>): Keys<T>;
23
24
  protected getNextColumn(key: Keys<T>): Keys<T>;
24
25
  protected scrollToCell(node: ActiveNode<T>): void;
26
+ protected findActiveCell(): import("../components/cell.js").default<T> | undefined;
27
+ /**
28
+ * Moves real DOM focus to the active cell (the grid body's roving tab stop),
29
+ * so screen readers track keyboard navigation. Waits for the host render to
30
+ * commit the cell's `active` state, then retries once on the next frame to
31
+ * cover virtualizer re-materialization after a long jump. No-op while no
32
+ * cell is active (the scroll container keeps focus as the entry point).
33
+ */
34
+ focusActiveCell(): void;
25
35
  get active(): ActiveNode<T>;
26
36
  set active(node: ActiveNode<T>);
27
37
  constructor(host: GridHost<T>);
38
+ /** Home moves to the first cell in the row (ARIA grid pattern). */
28
39
  protected home(): void;
40
+ /** End moves to the last cell in the row (ARIA grid pattern). */
29
41
  protected end(): void;
42
+ /** Ctrl/Cmd+Home moves to the first cell of the grid. */
43
+ protected ctrlHome(): void;
44
+ /** Ctrl/Cmd+End moves to the last cell of the grid. */
45
+ protected ctrlEnd(): void;
46
+ /**
47
+ * Rows per Page Up/Down step, derived from the host viewport and the height
48
+ * of a rendered row (fallback: 10 rows when nothing is measurable yet).
49
+ */
50
+ protected pageStep(): number;
51
+ protected pageUp(): void;
52
+ protected pageDown(): void;
30
53
  protected arrowDown(): void;
31
54
  protected arrowUp(): void;
32
55
  protected arrowLeft(): void;
@@ -34,6 +57,16 @@ export declare class NavigationController<T extends object> implements ReactiveC
34
57
  protected toggleSelection(): void;
35
58
  hostConnected(): void;
36
59
  hostDisconnected(): void;
60
+ protected get editing(): {
61
+ enabled: boolean;
62
+ isEditable(column: ColumnConfiguration<T>): boolean;
63
+ editCell(rowIndex: number, columnKey: Keys<T>): Promise<boolean>;
64
+ } | undefined;
65
+ /**
66
+ * Enter / F2 on the active cell opens its editor (the keyboard path into
67
+ * edit mode). Returns `true` when the event was consumed.
68
+ */
69
+ protected handleEditKey(event: KeyboardEvent): boolean;
37
70
  protected get rowReorder(): {
38
71
  enabled: boolean;
39
72
  isGrabbing: boolean;