apex-grid 3.2.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +120 -0
- package/README.md +229 -52
- package/components/cell.d.ts +16 -3
- package/components/cell.js +78 -8
- package/components/cell.js.map +1 -1
- package/components/filter-row.d.ts +3 -6
- package/components/filter-row.js +144 -115
- package/components/filter-row.js.map +1 -1
- package/components/grid.d.ts +421 -77
- package/components/grid.js +432 -13
- package/components/grid.js.map +1 -1
- package/components/group-header-row.d.ts +34 -0
- package/components/group-header-row.js +125 -0
- package/components/group-header-row.js.map +1 -0
- package/components/header-row.d.ts +13 -2
- package/components/header-row.js +33 -18
- package/components/header-row.js.map +1 -1
- package/components/header.d.ts +11 -0
- package/components/header.js +209 -8
- package/components/header.js.map +1 -1
- package/components/paginator.d.ts +6 -1
- package/components/paginator.js +17 -11
- package/components/paginator.js.map +1 -1
- package/components/row.d.ts +28 -0
- package/components/row.js +100 -3
- package/components/row.js.map +1 -1
- package/components/toolbar.d.ts +8 -1
- package/components/toolbar.js +25 -7
- package/components/toolbar.js.map +1 -1
- package/controllers/data-operation.js +1 -0
- package/controllers/data-operation.js.map +1 -1
- package/controllers/dom.d.ts +24 -6
- package/controllers/dom.js +62 -5
- package/controllers/dom.js.map +1 -1
- package/controllers/editing.d.ts +68 -1
- package/controllers/editing.js +129 -44
- package/controllers/editing.js.map +1 -1
- package/controllers/expansion.js +4 -4
- package/controllers/expansion.js.map +1 -1
- package/controllers/filter.d.ts +1 -1
- package/controllers/filter.js +27 -5
- package/controllers/filter.js.map +1 -1
- package/controllers/history.d.ts +86 -0
- package/controllers/history.js +125 -0
- package/controllers/history.js.map +1 -0
- package/controllers/navigation.d.ts +49 -2
- package/controllers/navigation.js +145 -3
- package/controllers/navigation.js.map +1 -1
- package/controllers/pagination.js +1 -1
- package/controllers/pagination.js.map +1 -1
- package/controllers/reorder.js +3 -1
- package/controllers/reorder.js.map +1 -1
- package/controllers/row-pin.d.ts +59 -0
- package/controllers/row-pin.js +75 -0
- package/controllers/row-pin.js.map +1 -0
- package/controllers/row-reorder.d.ts +161 -0
- package/controllers/row-reorder.js +332 -0
- package/controllers/row-reorder.js.map +1 -0
- package/controllers/selection.js +3 -3
- package/controllers/selection.js.map +1 -1
- package/controllers/sort.js +13 -3
- package/controllers/sort.js.map +1 -1
- package/controllers/state.d.ts +33 -0
- package/controllers/state.js +37 -2
- package/controllers/state.js.map +1 -1
- package/controllers/tree.d.ts +8 -0
- package/controllers/tree.js +0 -0
- package/controllers/tree.js.map +1 -1
- package/custom-elements.json +4667 -926
- package/docs/assets/hierarchy.js +1 -1
- package/docs/assets/highlight.css +28 -0
- package/docs/assets/navigation.js +1 -1
- package/docs/assets/search.js +1 -1
- package/docs/functions/custom.html +3 -0
- package/docs/functions/interpolate.html +4 -0
- package/docs/functions/localize.html +8 -0
- package/docs/functions/max.html +3 -0
- package/docs/functions/min.html +3 -0
- package/docs/functions/pattern.html +3 -0
- package/docs/functions/required.html +3 -0
- package/docs/hierarchy.html +1 -1
- package/docs/index.html +245 -54
- package/docs/interfaces/ApexCellValidationFailedEvent.html +13 -0
- package/docs/interfaces/ApexCellValueChangedEvent.html +1 -1
- package/docs/interfaces/ApexCellValueChangingEvent.html +2 -2
- package/docs/interfaces/ApexColumnGroupContext.html +6 -0
- package/docs/interfaces/ApexColumnMovedEvent.html +2 -2
- package/docs/interfaces/ApexColumnMovingEvent.html +1 -1
- package/docs/interfaces/ApexDetailContext.html +2 -2
- package/docs/interfaces/ApexGridEventMap.html +37 -9
- package/docs/interfaces/ApexHistoryChangedEvent.html +6 -0
- package/docs/interfaces/ApexPageChangedEvent.html +1 -1
- package/docs/interfaces/ApexRowMovingEvent.html +9 -0
- package/docs/interfaces/ApexRowPinningEvent.html +8 -0
- package/docs/interfaces/ApexStateChangedEvent.html +4 -0
- package/docs/interfaces/BaseApexCellContext.html +1 -1
- package/docs/interfaces/BaseApexEditorContext.html +1 -1
- package/docs/interfaces/BaseColumnConfiguration.html +42 -17
- package/docs/interfaces/CSVExportOptions.html +2 -2
- package/docs/interfaces/ColumnGroupConfiguration.html +12 -0
- package/docs/interfaces/ColumnLayoutState.html +2 -0
- package/docs/interfaces/ColumnSchema.html +22 -0
- package/docs/interfaces/DataPipelineConfiguration.html +2 -2
- package/docs/interfaces/EditingHistoryConfiguration.html +10 -0
- package/docs/interfaces/ExportFormat.html +2 -2
- package/docs/interfaces/ExportOptions.html +1 -1
- package/docs/interfaces/FilterStateSnapshot.html +4 -0
- package/docs/interfaces/GetStateOptions.html +4 -0
- package/docs/interfaces/GridCapabilities.html +8 -0
- package/docs/interfaces/GridEditingConfiguration.html +4 -2
- package/docs/interfaces/GridRowPinningConfiguration.html +5 -0
- package/docs/interfaces/GridRowReorderingConfiguration.html +22 -0
- package/docs/interfaces/GridSchema.html +19 -0
- package/docs/interfaces/GridState.html +41 -0
- package/docs/interfaces/GridTreeConfiguration.html +2 -2
- package/docs/interfaces/PaginationConfiguration.html +1 -1
- package/docs/interfaces/PaginationState.html +1 -1
- package/docs/interfaces/SetStateOptions.html +9 -0
- package/docs/interfaces/SetStateResult.html +11 -0
- package/docs/interfaces/SortStateSnapshot.html +2 -0
- package/docs/interfaces/ValidatorContext.html +8 -0
- package/docs/media/_tokens.scss +70 -81
- package/docs/media/package.json +2 -2
- package/docs/media/state-persistence.html +189 -0
- package/docs/modules.html +1 -1
- package/docs/types/DataPipelineParams.html +2 -2
- package/docs/types/EditMode.html +2 -2
- package/docs/types/GridLocaleKey.html +3 -0
- package/docs/types/GridLocaleText.html +5 -0
- package/docs/types/LocaleParams.html +2 -0
- package/docs/types/PaginationMode.html +1 -1
- package/docs/types/RowDropPosition.html +2 -0
- package/docs/types/RowPinPosition.html +2 -0
- package/docs/types/RowRef.html +3 -0
- package/docs/types/Validator.html +4 -0
- package/docs/variables/EN_LOCALE.html +9 -0
- package/docs/variables/esLocale.html +8 -0
- package/i18n/en.d.ts +245 -0
- package/i18n/en.js +219 -0
- package/i18n/en.js.map +1 -0
- package/i18n/es.d.ts +18 -0
- package/i18n/es.js +219 -0
- package/i18n/es.js.map +1 -0
- package/i18n/index.d.ts +3 -0
- package/i18n/index.js +4 -0
- package/i18n/index.js.map +1 -0
- package/i18n/localize.d.ts +23 -0
- package/i18n/localize.js +15 -0
- package/i18n/localize.js.map +1 -0
- package/index.d.ts +8 -2
- package/index.js +2 -0
- package/index.js.map +1 -1
- package/internal/column-types.js +1 -1
- package/internal/column-types.js.map +1 -1
- package/internal/feature-module.d.ts +46 -0
- package/internal/feature-module.js +11 -0
- package/internal/feature-module.js.map +1 -1
- package/internal/flip.js +1 -1
- package/internal/flip.js.map +1 -1
- package/internal/icons.d.ts +9 -7
- package/internal/icons.js +75 -35
- package/internal/icons.js.map +1 -1
- package/internal/index.d.ts +5 -3
- package/internal/index.js +2 -1
- package/internal/index.js.map +1 -1
- package/internal/state-schema.d.ts +85 -0
- package/internal/state-schema.js +27 -0
- package/internal/state-schema.js.map +1 -0
- package/internal/state-snapshot.d.ts +152 -0
- package/internal/state-snapshot.js +115 -0
- package/internal/state-snapshot.js.map +1 -0
- package/internal/tags.d.ts +1 -0
- package/internal/tags.js +1 -0
- package/internal/tags.js.map +1 -1
- package/internal/types.d.ts +162 -2
- package/internal/types.js.map +1 -1
- package/internal/utils.d.ts +12 -0
- package/internal/utils.js +17 -0
- package/internal/utils.js.map +1 -1
- package/internal/validators.d.ts +31 -0
- package/internal/validators.js +44 -0
- package/internal/validators.js.map +1 -0
- package/package.json +1 -1
- package/styles/_tokens.css.js +1 -1
- package/styles/_tokens.css.js.map +1 -1
- package/styles/body-cell/body-cell.css.js +1 -1
- package/styles/body-cell/body-cell.css.js.map +1 -1
- package/styles/body-row/body-row.css.js +1 -1
- package/styles/body-row/body-row.css.js.map +1 -1
- package/styles/filter-row/filter-row.css.js +1 -1
- package/styles/filter-row/filter-row.css.js.map +1 -1
- package/styles/grid/_grid.base.css.js +1 -1
- package/styles/grid/_grid.base.css.js.map +1 -1
- package/styles/grid/grid.css.js +1 -1
- package/styles/grid/grid.css.js.map +1 -1
- package/styles/group-header-row/group-header-row.css.d.ts +1 -0
- package/styles/group-header-row/group-header-row.css.js +3 -0
- package/styles/group-header-row/group-header-row.css.js.map +1 -0
- package/styles/header-cell/header-cell.css.js +1 -1
- package/styles/header-cell/header-cell.css.js.map +1 -1
- package/styles/header-row/header-row.base.css.js +1 -1
- package/styles/header-row/header-row.base.css.js.map +1 -1
- package/styles/toolbar/toolbar.css.js +1 -1
- package/styles/toolbar/toolbar.css.js.map +1 -1
- package/docs/classes/ApexGrid.html +0 -399
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"editing.js","sourceRoot":"","sources":["../../src/controllers/editing.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\nimport { PIPELINE } from '../internal/constants.js';\nimport type {\n ColumnConfiguration,\n EditMode,\n EditTrigger,\n GridHost,\n Keys,\n} from '../internal/types.js';\n\n/**\n * The default editing configuration used when the grid has none set.\n */\nexport const DEFAULT_EDITING_CONFIG = Object.freeze({\n enabled: false,\n mode: 'cell' as EditMode,\n trigger: 'doubleClick' as EditTrigger,\n});\n\ninterface ActiveCell<T> {\n rowIndex: number;\n columnKey: Keys<T>;\n /**\n * Live reference to the underlying record (preserved through the pipeline so\n * the source array can be mutated on commit).\n */\n data: T;\n}\n\n/**\n * Reactive controller backing inline cell + row editing.\n *\n * @remarks\n * Holds the currently active cell / row, pending values for row-mode edits,\n * and is responsible for emitting the cancellable `cellValueChanging` event\n * and follow-up `cellValueChanged` event. The actual data mutation writes\n * through to {@link ApexGrid.data} so changes survive pipeline runs and\n * propagate to consumers that own the source array.\n */\nexport class EditingController<T extends object> implements ReactiveController {\n /** The cell currently in edit mode, or `null`. */\n public activeCell: ActiveCell<T> | null = null;\n\n /** The row currently in edit mode (row mode only), or `null`. */\n public activeRow: { rowIndex: number; data: T } | null = null;\n\n /**\n * Pending values keyed by column for the currently editing row. Populated in\n * row mode as the user edits individual cells; flushed on\n * {@link commitRow}.\n */\n public pending: Map<Keys<T>, unknown> = new Map();\n\n constructor(protected host: GridHost<T>) {\n this.host.addController(this);\n }\n\n public hostConnected() {}\n\n /**\n * Whether editing is enabled at the grid level.\n */\n public get enabled(): boolean {\n return Boolean(this.host.editing?.enabled);\n }\n\n /**\n * The resolved edit mode (`'cell'` if unset).\n */\n public get mode(): EditMode {\n return this.host.editing?.mode ?? DEFAULT_EDITING_CONFIG.mode;\n }\n\n /**\n * The resolved edit trigger (`'doubleClick'` if unset).\n */\n public get trigger(): EditTrigger {\n return this.host.editing?.trigger ?? DEFAULT_EDITING_CONFIG.trigger;\n }\n\n /**\n * Whether the given column can be edited.\n */\n public isEditable(column: ColumnConfiguration<T>): boolean {\n return Boolean(this.enabled && column.editable && !column.hidden);\n }\n\n /**\n * Whether the cell `(rowIndex, columnKey)` is currently in edit mode.\n */\n public isCellEditing(rowIndex: number, columnKey: Keys<T>): boolean {\n return this.activeCell?.rowIndex === rowIndex && this.activeCell?.columnKey === columnKey;\n }\n\n /**\n * Whether the given row is currently in edit mode (row mode).\n */\n public isRowEditing(rowIndex: number): boolean {\n return this.activeRow?.rowIndex === rowIndex;\n }\n\n /**\n * Begins editing the cell at `(rowIndex, columnKey)`. Auto-commits any cell\n * already in edit mode (in cell mode); in row mode it switches the active\n * cell within the same row and rejects cross-row moves.\n *\n * @returns `true` if edit started, `false` if rejected (column not editable\n * or row-mode constraint violated).\n */\n public async editCell(rowIndex: number, columnKey: Keys<T>): Promise<boolean> {\n if (!this.enabled) return false;\n const column = this.host.getColumn(columnKey);\n if (!column || !this.isEditable(column)) return false;\n const data = this.host.pageItems[rowIndex] as T | undefined;\n if (!data) return false;\n\n if (this.mode === 'row') {\n if (!this.activeRow) {\n await this.editRow(rowIndex);\n } else if (this.activeRow.rowIndex !== rowIndex) {\n // Switching rows in row mode — commit pending edits in the previous row\n // before starting elsewhere.\n const committed = await this.commitRow();\n if (!committed) return false;\n await this.editRow(rowIndex);\n }\n } else if (this.activeCell && !this.isCellEditing(rowIndex, columnKey)) {\n // Cell mode — commit any in-flight cell before switching.\n await this.commitCell();\n }\n\n this.activeCell = { rowIndex, columnKey, data };\n this.host.requestUpdate();\n return true;\n }\n\n /**\n * Begins editing the given row in row mode. Emits `rowEditStarted` on\n * success. No-op in cell mode.\n */\n public async editRow(rowIndex: number): Promise<boolean> {\n if (!this.enabled || this.mode !== 'row') return false;\n const data = this.host.pageItems[rowIndex] as T | undefined;\n if (!data) return false;\n if (this.activeRow && this.activeRow.rowIndex !== rowIndex) {\n const committed = await this.commitRow();\n if (!committed) return false;\n }\n if (this.activeRow?.rowIndex === rowIndex) return true;\n this.activeRow = { rowIndex, data };\n this.pending.clear();\n this.host.requestUpdate();\n this.host.emitEvent('rowEditStarted', { detail: { rowIndex } });\n return true;\n }\n\n /**\n * Commits a candidate value for the currently editing cell. In cell mode the\n * value is written through to {@link ApexGrid.data}; in row mode it is staged\n * in {@link pending} until {@link commitRow} is called.\n *\n * @param value - The candidate value.\n * @returns `true` if accepted (or staged), `false` if rejected by\n * `cellValueChanging.preventDefault()`.\n */\n public async commitCell(value?: unknown): Promise<boolean> {\n const active = this.activeCell;\n if (!active) return false;\n const { rowIndex, columnKey, data } = active;\n const oldValue = (data as Record<string, unknown>)[columnKey as string];\n const candidate = value === undefined ? oldValue : value;\n\n if (this.mode === 'cell') {\n if (Object.is(candidate, oldValue)) {\n this.activeCell = null;\n this.host.requestUpdate();\n return true;\n }\n const proceed = this.host.emitEvent('cellValueChanging', {\n detail: { key: columnKey, rowIndex, data, oldValue, newValue: candidate },\n cancelable: true,\n });\n if (!proceed) return false;\n (data as Record<string, unknown>)[columnKey as string] = candidate;\n this.activeCell = null;\n this.host.requestUpdate(PIPELINE);\n await this.host.updateComplete;\n this.host.emitEvent('cellValueChanged', {\n detail: { key: columnKey, rowIndex, data, value: candidate },\n });\n return true;\n }\n\n // Row mode — stage and exit cell edit (row stays open).\n if (!Object.is(candidate, oldValue)) {\n this.pending.set(columnKey, candidate);\n }\n this.activeCell = null;\n this.host.requestUpdate();\n return true;\n }\n\n /**\n * Writes `value` directly to the cell at `(rowIndex, columnKey)` without\n * entering edit mode. Used by interactive display widgets (e.g. the boolean\n * checkbox) that handle their own input. Goes through the same\n * `cellValueChanging` / `cellValueChanged` event path as a normal commit.\n *\n * @returns `true` if the value was applied, `false` if rejected by\n * `cellValueChanging.preventDefault()` or the column is not editable.\n */\n public async commitImmediate(\n rowIndex: number,\n columnKey: Keys<T>,\n value: unknown\n ): Promise<boolean> {\n if (!this.enabled) return false;\n const column = this.host.getColumn(columnKey);\n if (!column || !this.isEditable(column)) return false;\n const data = this.host.pageItems[rowIndex] as T | undefined;\n if (!data) return false;\n const oldValue = (data as Record<string, unknown>)[columnKey as string];\n if (Object.is(value, oldValue)) return true;\n const proceed = this.host.emitEvent('cellValueChanging', {\n detail: { key: columnKey, rowIndex, data, oldValue, newValue: value },\n cancelable: true,\n });\n if (!proceed) return false;\n (data as Record<string, unknown>)[columnKey as string] = value;\n this.host.requestUpdate(PIPELINE);\n await this.host.updateComplete;\n this.host.emitEvent('cellValueChanged', {\n detail: { key: columnKey, rowIndex, data, value },\n });\n return true;\n }\n\n /**\n * Discards the current cell edit without writing. In row mode the row edit\n * stays open.\n */\n public cancelCell(): void {\n if (!this.activeCell) return;\n this.activeCell = null;\n this.host.requestUpdate();\n }\n\n /**\n * Commits all pending edits for the currently editing row. Emits\n * `cellValueChanging` for every changed cell and `rowEditEnded` at the end.\n *\n * @returns `true` if the row was applied, `false` if any cell change was\n * cancelled (the row remains in edit mode in that case).\n */\n public async commitRow(): Promise<boolean> {\n const active = this.activeRow;\n if (!active) return false;\n const { rowIndex, data } = active;\n\n // Make sure any open cell editor flushes its pending value first.\n if (this.activeCell?.rowIndex === rowIndex) {\n await this.commitCell();\n }\n\n for (const [columnKey, candidate] of this.pending) {\n const oldValue = (data as Record<string, unknown>)[columnKey as string];\n if (Object.is(candidate, oldValue)) continue;\n const proceed = this.host.emitEvent('cellValueChanging', {\n detail: { key: columnKey, rowIndex, data, oldValue, newValue: candidate },\n cancelable: true,\n });\n if (!proceed) return false;\n (data as Record<string, unknown>)[columnKey as string] = candidate;\n this.host.emitEvent('cellValueChanged', {\n detail: { key: columnKey, rowIndex, data, value: candidate },\n });\n }\n\n this.pending.clear();\n this.activeRow = null;\n this.host.requestUpdate(PIPELINE);\n await this.host.updateComplete;\n this.host.emitEvent('rowEditEnded', { detail: { rowIndex, committed: true } });\n return true;\n }\n\n /**\n * Discards every pending edit for the active row and exits row edit mode.\n * Emits `rowEditEnded` with `committed: false`.\n */\n public cancelRow(): void {\n if (!this.activeRow) return;\n const { rowIndex } = this.activeRow;\n this.activeCell = null;\n this.activeRow = null;\n this.pending.clear();\n this.host.requestUpdate();\n this.host.emitEvent('rowEditEnded', { detail: { rowIndex, committed: false } });\n }\n\n /**\n * Returns the current pending or committed value for `(rowIndex, columnKey)`.\n * Cells in row mode read this so unstaged-but-pending values are reflected\n * during the edit.\n */\n public getValue(rowIndex: number, columnKey: Keys<T>): unknown {\n if (\n this.mode === 'row' &&\n this.activeRow?.rowIndex === rowIndex &&\n this.pending.has(columnKey)\n ) {\n return this.pending.get(columnKey);\n }\n const data = this.host.pageItems[rowIndex] as T | undefined;\n return data ? (data as Record<string, unknown>)[columnKey as string] : undefined;\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"editing.js","sourceRoot":"","sources":["../../src/controllers/editing.ts"],"names":[],"mappings":"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","sourcesContent":["import type { ReactiveController } from 'lit';\nimport { PIPELINE } from '../internal/constants.js';\nimport type {\n ColumnConfiguration,\n EditMode,\n EditTrigger,\n GridHost,\n Keys,\n Validator,\n ValidatorContext,\n} from '../internal/types.js';\nimport { runValidators } from '../internal/validators.js';\nimport type { HistoryController } from './history.js';\n\n/**\n * The default editing configuration used when the grid has none set.\n */\nexport const DEFAULT_EDITING_CONFIG = Object.freeze({\n enabled: false,\n mode: 'cell' as EditMode,\n trigger: 'doubleClick' as EditTrigger,\n});\n\ninterface ActiveCell<T> {\n rowIndex: number;\n columnKey: Keys<T>;\n /**\n * Live reference to the underlying record (preserved through the pipeline so\n * the source array can be mutated on commit).\n */\n data: T;\n}\n\n/**\n * Outcome of a single committed cell edit routed through\n * {@link EditingController.applyCellEdit}.\n *\n * - `'unchanged'` - the candidate equalled the current value; nothing happened.\n * - `'invalid'` - a column validator rejected the candidate; the value was not\n * written and `cellValidationFailed` fired.\n * - `'cancelled'` - a `cellValueChanging` listener called `preventDefault()`.\n * - `'applied'` - the value was written and `cellValueChanged` fired.\n */\nexport type CellEditResult = 'unchanged' | 'invalid' | 'cancelled' | 'applied';\n\n/**\n * Options for {@link EditingController.applyCellEdit}.\n */\nexport interface ApplyCellEditOptions {\n /**\n * Run the column's declarative validators before writing. Defaults to `true`.\n * Set to `false` for writes that must not be re-validated (e.g. reverting a\n * previously valid value during undo/redo).\n */\n validate?: boolean;\n}\n\n/**\n * Reactive controller backing inline cell + row editing.\n *\n * @remarks\n * Holds the currently active cell / row, pending values for row-mode edits,\n * and is responsible for emitting the cancellable `cellValueChanging` event\n * and follow-up `cellValueChanged` event. The actual data mutation writes\n * through to {@link ApexGrid.data} so changes survive pipeline runs and\n * propagate to consumers that own the source array.\n */\nexport class EditingController<T extends object> implements ReactiveController {\n /** The cell currently in edit mode, or `null`. */\n public activeCell: ActiveCell<T> | null = null;\n\n /** The row currently in edit mode (row mode only), or `null`. */\n public activeRow: { rowIndex: number; data: T } | null = null;\n\n /**\n * Pending values keyed by column for the currently editing row. Populated in\n * row mode as the user edits individual cells; flushed on\n * {@link commitRow}.\n */\n public pending: Map<Keys<T>, unknown> = new Map();\n\n /**\n * Per-record validation errors, keyed by the live data reference and then by\n * column. Keyed by reference (not row index) so an invalid marker tracks its\n * row across pipeline runs (sort / filter / paginate).\n */\n #invalid: Map<T, Map<Keys<T>, string[]>> = new Map();\n\n #validationVersion = 0;\n\n /**\n * Monotonic token bumped whenever the validation-error set changes. Forwarded\n * down to each cell as a reactive property so a validation-only change\n * re-renders the affected cells (toggling `aria-invalid` and the error node)\n * without re-running the data pipeline. Stays `0` until the first failure.\n */\n public get validationVersion(): number {\n return this.#validationVersion;\n }\n\n constructor(\n protected host: GridHost<T>,\n protected history?: HistoryController<T>\n ) {\n this.host.addController(this);\n }\n\n public hostConnected() {}\n\n /**\n * Whether editing is enabled at the grid level.\n */\n public get enabled(): boolean {\n return Boolean(this.host.editing?.enabled);\n }\n\n /**\n * The resolved edit mode (`'cell'` if unset).\n */\n public get mode(): EditMode {\n return this.host.editing?.mode ?? DEFAULT_EDITING_CONFIG.mode;\n }\n\n /**\n * The resolved edit trigger (`'doubleClick'` if unset).\n */\n public get trigger(): EditTrigger {\n return this.host.editing?.trigger ?? DEFAULT_EDITING_CONFIG.trigger;\n }\n\n /**\n * Whether the given column can be edited.\n */\n public isEditable(column: ColumnConfiguration<T>): boolean {\n return Boolean(this.enabled && column.editable && !column.hidden);\n }\n\n /**\n * Whether the cell `(rowIndex, columnKey)` is currently in edit mode.\n */\n public isCellEditing(rowIndex: number, columnKey: Keys<T>): boolean {\n return this.activeCell?.rowIndex === rowIndex && this.activeCell?.columnKey === columnKey;\n }\n\n /**\n * Whether the given row is currently in edit mode (row mode).\n */\n public isRowEditing(rowIndex: number): boolean {\n return this.activeRow?.rowIndex === rowIndex;\n }\n\n /**\n * Begins editing the cell at `(rowIndex, columnKey)`. Auto-commits any cell\n * already in edit mode (in cell mode); in row mode it switches the active\n * cell within the same row and rejects cross-row moves.\n *\n * @returns `true` if edit started, `false` if rejected (column not editable\n * or row-mode constraint violated).\n */\n public async editCell(rowIndex: number, columnKey: Keys<T>): Promise<boolean> {\n if (!this.enabled) return false;\n const column = this.host.getColumn(columnKey);\n if (!column || !this.isEditable(column)) return false;\n const data = this.host.pageItems[rowIndex] as T | undefined;\n if (!data) return false;\n\n if (this.mode === 'row') {\n if (!this.activeRow) {\n await this.editRow(rowIndex);\n } else if (this.activeRow.rowIndex !== rowIndex) {\n // Switching rows in row mode — commit pending edits in the previous row\n // before starting elsewhere.\n const committed = await this.commitRow();\n if (!committed) return false;\n await this.editRow(rowIndex);\n }\n } else if (this.activeCell && !this.isCellEditing(rowIndex, columnKey)) {\n // Cell mode — commit any in-flight cell before switching.\n await this.commitCell();\n }\n\n this.activeCell = { rowIndex, columnKey, data };\n this.host.requestUpdate();\n return true;\n }\n\n /**\n * Begins editing the given row in row mode. Emits `rowEditStarted` on\n * success. No-op in cell mode.\n */\n public async editRow(rowIndex: number): Promise<boolean> {\n if (!this.enabled || this.mode !== 'row') return false;\n const data = this.host.pageItems[rowIndex] as T | undefined;\n if (!data) return false;\n if (this.activeRow && this.activeRow.rowIndex !== rowIndex) {\n const committed = await this.commitRow();\n if (!committed) return false;\n }\n if (this.activeRow?.rowIndex === rowIndex) return true;\n this.activeRow = { rowIndex, data };\n this.pending.clear();\n this.host.requestUpdate();\n this.host.emitEvent('rowEditStarted', { detail: { rowIndex } });\n return true;\n }\n\n /**\n * The single choke point for committing a cell value to the backing record.\n * Short-circuits no-op writes, runs the cancellable `cellValueChanging` gate,\n * writes the value through to {@link ApexGrid.data}, and emits\n * `cellValueChanged`. Returns the {@link CellEditResult} so callers can manage\n * their own UI state (active cell) and batch the render.\n *\n * @remarks\n * Does **not** request a render — callers refresh (once per edit, or once per\n * batch) so row-mode and bulk edits coalesce into a single pipeline pass.\n * Every committed edit (single-cell, row-mode, and enterprise paste/fill)\n * funnels through here so cross-cutting concerns (validation, undo/redo) have\n * one place to hook the old/new values and the write.\n */\n public applyCellEdit(\n rowIndex: number,\n columnKey: Keys<T>,\n data: T,\n value: unknown,\n options?: ApplyCellEditOptions\n ): CellEditResult {\n const record = data as Record<string, unknown>;\n const oldValue = record[columnKey as string];\n if (Object.is(value, oldValue)) {\n // Re-entering the original value clears any stale invalid marker.\n this.clearCellErrors(data, columnKey);\n return 'unchanged';\n }\n\n if (options?.validate !== false) {\n const errors = this.validateCell(rowIndex, columnKey, data, value);\n if (errors.length > 0) {\n this.#setCellErrors(data, columnKey, errors);\n this.host.emitEvent('cellValidationFailed', {\n detail: { key: columnKey, rowIndex, data, value, errors },\n });\n return 'invalid';\n }\n }\n\n const proceed = this.host.emitEvent('cellValueChanging', {\n detail: { key: columnKey, rowIndex, data, oldValue, newValue: value },\n cancelable: true,\n });\n if (!proceed) return 'cancelled';\n\n record[columnKey as string] = value;\n this.clearCellErrors(data, columnKey);\n this.history?.record({ record: data, key: columnKey, rowIndex, oldValue, newValue: value });\n this.host.emitEvent('cellValueChanged', {\n detail: { key: columnKey, rowIndex, data, value },\n });\n return 'applied';\n }\n\n /**\n * Runs the column's declarative validators against a candidate value and\n * returns the collected error messages (empty when the value passes or the\n * column has no validators).\n */\n public validateCell(rowIndex: number, columnKey: Keys<T>, data: T, value: unknown): string[] {\n const column = this.host.getColumn(columnKey);\n if (!column?.validators?.length) return [];\n // `ColumnConfiguration<T>` is a distributive conditional, so `validators`\n // and `column` widen to a per-key union here; collapse to the base form for\n // the runner (the runtime shapes are identical).\n return runValidators(column.validators as Validator<T>[], value, {\n column,\n data,\n rowIndex,\n } as ValidatorContext<T>);\n }\n\n /**\n * The current validation errors for `(data, columnKey)`, or `null` when the\n * cell is valid. Read by {@link ApexGridCell} to drive `aria-invalid` and the\n * inline error node.\n */\n public getCellErrors(data: T, columnKey: Keys<T>): readonly string[] | null {\n return this.#invalid.get(data)?.get(columnKey) ?? null;\n }\n\n /**\n * Clears any validation error recorded for `(data, columnKey)`.\n */\n public clearCellErrors(data: T, columnKey: Keys<T>): void {\n const perColumn = this.#invalid.get(data);\n if (!perColumn) return;\n if (perColumn.delete(columnKey)) {\n if (perColumn.size === 0) this.#invalid.delete(data);\n this.#validationVersion += 1;\n }\n }\n\n /**\n * Clears every validation error recorded for a record (all columns).\n */\n public clearRecordErrors(data: T): void {\n if (this.#invalid.delete(data)) {\n this.#validationVersion += 1;\n }\n }\n\n #setCellErrors(data: T, columnKey: Keys<T>, errors: string[]): void {\n let perColumn = this.#invalid.get(data);\n if (!perColumn) {\n perColumn = new Map();\n this.#invalid.set(data, perColumn);\n }\n perColumn.set(columnKey, errors);\n this.#validationVersion += 1;\n }\n\n /**\n * Commits a candidate value for the currently editing cell. In cell mode the\n * value is written through to {@link ApexGrid.data}; in row mode it is staged\n * in {@link pending} until {@link commitRow} is called.\n *\n * @param value - The candidate value.\n * @returns `true` if accepted (or staged), `false` if rejected by\n * `cellValueChanging.preventDefault()`.\n */\n public async commitCell(value?: unknown): Promise<boolean> {\n const active = this.activeCell;\n if (!active) return false;\n const { rowIndex, columnKey, data } = active;\n const oldValue = (data as Record<string, unknown>)[columnKey as string];\n const candidate = value === undefined ? oldValue : value;\n\n if (this.mode === 'cell') {\n const result = this.applyCellEdit(rowIndex, columnKey, data, candidate);\n if (result === 'cancelled') return false;\n // A failed validation keeps the editor open so the user can correct the\n // value; re-render to surface `aria-invalid` + the error node.\n if (result === 'invalid') {\n this.host.requestUpdate();\n return false;\n }\n // Both 'applied' and 'unchanged' close the editor; only an applied write\n // needs the data pipeline to re-run.\n this.activeCell = null;\n if (result === 'applied') {\n this.host.requestUpdate(PIPELINE);\n await this.host.updateComplete;\n } else {\n this.host.requestUpdate();\n }\n return true;\n }\n\n // Row mode — stage and exit cell edit (row stays open).\n if (!Object.is(candidate, oldValue)) {\n this.pending.set(columnKey, candidate);\n }\n this.activeCell = null;\n this.host.requestUpdate();\n return true;\n }\n\n /**\n * Writes `value` directly to the cell at `(rowIndex, columnKey)` without\n * entering edit mode. Used by interactive display widgets (e.g. the boolean\n * checkbox) that handle their own input. Goes through the same\n * `cellValueChanging` / `cellValueChanged` event path as a normal commit.\n *\n * @returns `true` if the value was applied, `false` if rejected by\n * `cellValueChanging.preventDefault()` or the column is not editable.\n */\n public async commitImmediate(\n rowIndex: number,\n columnKey: Keys<T>,\n value: unknown\n ): Promise<boolean> {\n if (!this.enabled) return false;\n const column = this.host.getColumn(columnKey);\n if (!column || !this.isEditable(column)) return false;\n const data = this.host.pageItems[rowIndex] as T | undefined;\n if (!data) return false;\n\n const result = this.applyCellEdit(rowIndex, columnKey, data, value);\n if (result === 'cancelled') return false;\n if (result === 'invalid') {\n this.host.requestUpdate();\n return false;\n }\n if (result === 'applied') {\n this.host.requestUpdate(PIPELINE);\n await this.host.updateComplete;\n }\n return true;\n }\n\n /**\n * Discards the current cell edit without writing. In row mode the row edit\n * stays open.\n */\n public cancelCell(): void {\n if (!this.activeCell) return;\n const { data, columnKey } = this.activeCell;\n this.activeCell = null;\n // Abandoning the edit discards any validation error raised for the cell.\n this.clearCellErrors(data, columnKey);\n this.host.requestUpdate();\n }\n\n /**\n * Commits all pending edits for the currently editing row. Emits\n * `cellValueChanging` for every changed cell and `rowEditEnded` at the end.\n *\n * @returns `true` if the row was applied, `false` if any cell change was\n * cancelled (the row remains in edit mode in that case).\n */\n public async commitRow(): Promise<boolean> {\n const active = this.activeRow;\n if (!active) return false;\n const { rowIndex, data } = active;\n\n // Make sure any open cell editor flushes its pending value first.\n if (this.activeCell?.rowIndex === rowIndex) {\n await this.commitCell();\n }\n\n // Pre-validate every pending cell so a single failure aborts the whole row\n // commit without a partial write. Each failing cell is marked invalid and\n // the row stays in edit mode.\n let hasInvalid = false;\n for (const [columnKey, candidate] of this.pending) {\n const errors = this.validateCell(rowIndex, columnKey, data, candidate);\n if (errors.length > 0) {\n this.#setCellErrors(data, columnKey, errors);\n this.host.emitEvent('cellValidationFailed', {\n detail: { key: columnKey, rowIndex, data, value: candidate, errors },\n });\n hasInvalid = true;\n }\n }\n if (hasInvalid) {\n this.host.requestUpdate();\n return false;\n }\n\n // Coalesce the row's writes into one undo step.\n this.history?.beginBatch();\n try {\n for (const [columnKey, candidate] of this.pending) {\n // Validation already ran above; a cancelled cell aborts the whole row\n // commit, leaving it in edit mode.\n if (\n this.applyCellEdit(rowIndex, columnKey, data, candidate, { validate: false }) ===\n 'cancelled'\n ) {\n return false;\n }\n }\n } finally {\n this.history?.endBatch();\n }\n\n this.pending.clear();\n this.activeRow = null;\n this.host.requestUpdate(PIPELINE);\n await this.host.updateComplete;\n this.host.emitEvent('rowEditEnded', { detail: { rowIndex, committed: true } });\n return true;\n }\n\n /**\n * Discards every pending edit for the active row and exits row edit mode.\n * Emits `rowEditEnded` with `committed: false`.\n */\n public cancelRow(): void {\n if (!this.activeRow) return;\n const { rowIndex, data } = this.activeRow;\n this.activeCell = null;\n this.activeRow = null;\n this.pending.clear();\n // Abandoning the row discards every validation error raised for it.\n this.clearRecordErrors(data);\n this.host.requestUpdate();\n this.host.emitEvent('rowEditEnded', { detail: { rowIndex, committed: false } });\n }\n\n /**\n * Returns the current pending or committed value for `(rowIndex, columnKey)`.\n * Cells in row mode read this so unstaged-but-pending values are reflected\n * during the edit.\n */\n public getValue(rowIndex: number, columnKey: Keys<T>): unknown {\n if (\n this.mode === 'row' &&\n this.activeRow?.rowIndex === rowIndex &&\n this.pending.has(columnKey)\n ) {\n return this.pending.get(columnKey);\n }\n const data = this.host.pageItems[rowIndex] as T | undefined;\n return data ? (data as Record<string, unknown>)[columnKey as string] : undefined;\n }\n}\n"]}
|
package/controllers/expansion.js
CHANGED
|
@@ -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('
|
|
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('
|
|
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(
|
|
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('
|
|
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":"AAUA,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC,MAAM,CAAC;IACpD,OAAO,EAAE,KAAK;IACd,gBAAgB,EAAE,IAAI;CACvB,CAAC,CAAC;AAiBH,MAAM,OAAO,mBAAmB;IAI9B,YAAsB,IAAiB;QAAjB,SAAI,GAAJ,IAAI,CAAa;QAFhC,aAAQ,GAAW,IAAI,GAAG,EAAE,CAAC;QAGlC,IAAI,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;IAChC,CAAC;IAEM,aAAa,KAAI,CAAC;IAGzB,IAAW,OAAO;QAChB,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IAGD,IAAW,gBAAgB;QACzB,OAAO,CACL,IAAI,CAAC,OAAO;YACZ,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,gBAAgB,IAAI,wBAAwB,CAAC,gBAAgB,CAAC,CACrF,CAAC;IACJ,CAAC;IAGM,UAAU,CAAC,GAAM;QACtB,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC;IAOM,SAAS,CAAC,GAAM;QACrB,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAChC,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,KAAK,UAAU;YAAE,OAAO,KAAK,CAAC;QAC5E,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC;QACpD,OAAO,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACpD,CAAC;IAGM,YAAY;QACjB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACnC,CAAC;IAGM,KAAK,CAAC,SAAS,CAAC,GAAM;QAC3B,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QAClE,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;;YAC/B,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACnB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAGM,KAAK,CAAC,SAAS,CAAC,GAAM;QAC3B,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACxC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;YAAE,OAAO,KAAK,CAAC;QACvC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACd,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAGM,KAAK,CAAC,WAAW,CAAC,GAAM;QAC7B,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACzC,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjB,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAMM,KAAK,CAAC,SAAS;QACpB,IAAI,CAAC,IAAI,CAAC,OAAO,IAAI,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,KAAK,UAAU;YAAE,OAAO,KAAK,CAAC;QAC7F,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC;QACpD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACpC,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,QAA4B,EAAE,CAAC;YACzD,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,GAAG,CAAC;gBAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAClD,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAGM,KAAK,CAAC,WAAW;QACtB,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAC1C,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC;IACjC,CAAC;IAMM,KAAK,CAAC,gBAAgB,CAAC,IAAsB;QAClD,IAAI,CAAC,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAChC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,YAAY,CAAC;QACpD,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC9E,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,IAAY;QACxB,MAAM,KAAK,GAAQ,EAAE,CAAC;QACtB,MAAM,OAAO,GAAQ,EAAE,CAAC;QACxB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC/C,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACxC,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAE5D,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,cAAc,EAAE;YAClD,MAAM,EAAE;gBACN,KAAK;gBACL,OAAO;gBACP,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC;gBAClC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;aACvB;YACD,UAAU,EAAE,IAAI;SACjB,CAAC,CAAC;QACH,IAAI,CAAC,OAAO;YAAE,OAAO,KAAK,CAAC;QAE3B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC;QAE1B,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/C,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC;QACjE,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACtD,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,uBAAuB,CAAC,CAAC,CAAC;QAClE,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK,CAAC,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;YAC9F,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,uBAAuB,EAAE,EAAE,KAAK,EAAE,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;QAC3F,CAAC;aAAM,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC,EAAE,CAAC;YACjD,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CAAC,CAAC;QACtE,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,EAAE;YACjC,MAAM,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE;SAChE,CAAC,CAAC;QACH,OAAO,IAAI,CAAC;IACd,CAAC;CACF","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"]}
|
package/controllers/filter.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export declare class FilterController<T extends object> implements ReactiveContr
|
|
|
12
12
|
hostUpdate(): void;
|
|
13
13
|
get(key: Keys<T>): import("../operations/filter/tree.js").FilterExpressionTree<T> | undefined;
|
|
14
14
|
reset(key?: Keys<T>): void;
|
|
15
|
-
setActiveColumn(column?: ColumnConfiguration<T
|
|
15
|
+
setActiveColumn(column?: ColumnConfiguration<T>, triggerRect?: DOMRect): void;
|
|
16
16
|
getDefaultExpression(column: ColumnConfiguration<T>): FilterExpression<T>;
|
|
17
17
|
removeAllExpressions(key: Keys<T>): Promise<void>;
|
|
18
18
|
removeExpression(expression: FilterExpression<T>): Promise<void>;
|
package/controllers/filter.js
CHANGED
|
@@ -43,12 +43,23 @@ export class FilterController {
|
|
|
43
43
|
reset(key) {
|
|
44
44
|
key ? this.state.delete(key) : this.state.clear();
|
|
45
45
|
}
|
|
46
|
-
setActiveColumn(column) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
46
|
+
setActiveColumn(column, triggerRect) {
|
|
47
|
+
const filterRow = this.filterRow;
|
|
48
|
+
if (!filterRow)
|
|
49
|
+
return;
|
|
50
|
+
if (!column?.filter) {
|
|
51
|
+
filterRow.active = false;
|
|
52
|
+
return;
|
|
51
53
|
}
|
|
54
|
+
if (filterRow.active && filterRow.column?.key === column.key) {
|
|
55
|
+
filterRow.active = false;
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
filterRow.triggerRect = triggerRect ?? null;
|
|
59
|
+
filterRow.column = column;
|
|
60
|
+
filterRow.expression = this.getDefaultExpression(column);
|
|
61
|
+
filterRow.active = true;
|
|
62
|
+
this.host.requestUpdate();
|
|
52
63
|
}
|
|
53
64
|
getDefaultExpression(column) {
|
|
54
65
|
const caseSensitive = typeof column.filter === 'boolean' ? false : Boolean(column.filter?.caseSensitive);
|
|
@@ -75,6 +86,7 @@ export class FilterController {
|
|
|
75
86
|
this.reset(key);
|
|
76
87
|
this.#filter([]);
|
|
77
88
|
await this.host.updateComplete;
|
|
89
|
+
this.#announce(key, 'cleared');
|
|
78
90
|
this.#emitFilteredEvent({ key, state: this.get(key)?.all ?? [] });
|
|
79
91
|
}
|
|
80
92
|
async removeExpression(expression) {
|
|
@@ -88,6 +100,7 @@ export class FilterController {
|
|
|
88
100
|
}
|
|
89
101
|
this.#filter([]);
|
|
90
102
|
await this.host.updateComplete;
|
|
103
|
+
this.#announce(expression.key, 'cleared');
|
|
91
104
|
this.#emitFilteredEvent({ key: expression.key, state: state?.all ?? [] });
|
|
92
105
|
}
|
|
93
106
|
async filterWithEvent(expression, type) {
|
|
@@ -96,8 +109,17 @@ export class FilterController {
|
|
|
96
109
|
}
|
|
97
110
|
this.#filter(expression);
|
|
98
111
|
await this.host.updateComplete;
|
|
112
|
+
if (type === 'add')
|
|
113
|
+
this.#announce(expression.key, 'applied');
|
|
99
114
|
this.#emitFilteredEvent({ key: expression.key, state: this.get(expression.key)?.all ?? [] });
|
|
100
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
|
+
}
|
|
101
123
|
filter(expression) {
|
|
102
124
|
this.#filter(asArray(expression).map((expr) => Object.assign(this.getDefaultExpression(this.host.getColumn(expr.key)), expr)));
|
|
103
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>) {\n if (column?.filter && this.filterRow?.active) {\n this.filterRow.column = column;\n this.filterRow.expression = this.getDefaultExpression(column);\n this.host.requestUpdate();\n }\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":"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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.#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"]}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { ReactiveController } from 'lit';
|
|
2
|
+
import type { GridHost, Keys } from '../internal/types.js';
|
|
3
|
+
/**
|
|
4
|
+
* A single recorded cell mutation: the record reference, its column, and the
|
|
5
|
+
* before / after values. `rowIndex` is the view-relative index at record time
|
|
6
|
+
* and is used only for the replayed `cellValueChanged` event (the live record
|
|
7
|
+
* reference is authoritative).
|
|
8
|
+
*/
|
|
9
|
+
export interface CellChange<T extends object> {
|
|
10
|
+
record: T;
|
|
11
|
+
key: Keys<T>;
|
|
12
|
+
rowIndex: number;
|
|
13
|
+
oldValue: unknown;
|
|
14
|
+
newValue: unknown;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* A reversible unit of work on the history stacks.
|
|
18
|
+
*
|
|
19
|
+
* @remarks
|
|
20
|
+
* `apply` re-performs the change (redo); `revert` undoes it. Cell-data edits use
|
|
21
|
+
* {@link CellEditCommand}; the interface is deliberately open so later command
|
|
22
|
+
* kinds (e.g. view-state) can join the same stacks.
|
|
23
|
+
*/
|
|
24
|
+
export interface EditCommand {
|
|
25
|
+
apply(): void;
|
|
26
|
+
revert(): void;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* One or more cell mutations that undo / redo as a single step. A single-cell
|
|
30
|
+
* edit holds one change; a row-mode commit or a bulk paste / fill holds many so
|
|
31
|
+
* one Ctrl+Z reverts the whole batch.
|
|
32
|
+
*/
|
|
33
|
+
export declare class CellEditCommand<T extends object> implements EditCommand {
|
|
34
|
+
#private;
|
|
35
|
+
private host;
|
|
36
|
+
readonly changes: ReadonlyArray<CellChange<T>>;
|
|
37
|
+
constructor(host: GridHost<T>, changes: ReadonlyArray<CellChange<T>>);
|
|
38
|
+
apply(): void;
|
|
39
|
+
revert(): void;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Reactive controller owning the undo / redo stacks for cell-data edits.
|
|
43
|
+
*
|
|
44
|
+
* @remarks
|
|
45
|
+
* Recording is driven from the {@link EditingController.applyCellEdit} choke
|
|
46
|
+
* point: every successful write calls {@link record}. Single edits push one
|
|
47
|
+
* command; {@link beginBatch} / {@link endBatch} coalesce a row-mode commit or a
|
|
48
|
+
* bulk paste / fill into one command. Disabled unless
|
|
49
|
+
* `editing.history.enabled` is set, so the community grid pays nothing.
|
|
50
|
+
*/
|
|
51
|
+
export declare class HistoryController<T extends object> implements ReactiveController {
|
|
52
|
+
#private;
|
|
53
|
+
protected host: GridHost<T>;
|
|
54
|
+
constructor(host: GridHost<T>);
|
|
55
|
+
hostConnected(): void;
|
|
56
|
+
/** Whether undo / redo tracking is enabled. */
|
|
57
|
+
get enabled(): boolean;
|
|
58
|
+
/** Maximum number of commands retained on the undo stack. */
|
|
59
|
+
get stackSize(): number;
|
|
60
|
+
/** Whether there is at least one command to undo. */
|
|
61
|
+
get canUndo(): boolean;
|
|
62
|
+
/** Whether there is at least one command to redo. */
|
|
63
|
+
get canRedo(): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Records a single cell mutation. Routed to the open batch when one is active,
|
|
66
|
+
* otherwise pushed immediately as a standalone command. No-op when history is
|
|
67
|
+
* disabled.
|
|
68
|
+
*/
|
|
69
|
+
record(change: CellChange<T>): void;
|
|
70
|
+
/**
|
|
71
|
+
* Opens a batch so subsequent {@link record} calls coalesce into one command.
|
|
72
|
+
* Nestable calls are flattened (the outermost {@link endBatch} commits).
|
|
73
|
+
*/
|
|
74
|
+
beginBatch(): void;
|
|
75
|
+
/**
|
|
76
|
+
* Closes the open batch, pushing it as a single command when it captured any
|
|
77
|
+
* changes.
|
|
78
|
+
*/
|
|
79
|
+
endBatch(): void;
|
|
80
|
+
/** Reverts the most recent command. No-op when the undo stack is empty. */
|
|
81
|
+
undo(): void;
|
|
82
|
+
/** Re-applies the most recently undone command. No-op when nothing to redo. */
|
|
83
|
+
redo(): void;
|
|
84
|
+
/** Clears both stacks (e.g. after a data reset). */
|
|
85
|
+
clear(): void;
|
|
86
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { PIPELINE } from '../internal/constants.js';
|
|
2
|
+
const DEFAULT_STACK_SIZE = 100;
|
|
3
|
+
export class CellEditCommand {
|
|
4
|
+
constructor(host, changes) {
|
|
5
|
+
this.host = host;
|
|
6
|
+
this.changes = changes;
|
|
7
|
+
}
|
|
8
|
+
apply() {
|
|
9
|
+
for (const change of this.changes) {
|
|
10
|
+
this.#write(change, change.newValue);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
revert() {
|
|
14
|
+
for (let i = this.changes.length - 1; i >= 0; i -= 1) {
|
|
15
|
+
this.#write(this.changes[i], this.changes[i].oldValue);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
#write(change, value) {
|
|
19
|
+
change.record[change.key] = value;
|
|
20
|
+
const liveIndex = this.host.pageItems.indexOf(change.record);
|
|
21
|
+
this.host.emitEvent('cellValueChanged', {
|
|
22
|
+
detail: {
|
|
23
|
+
key: change.key,
|
|
24
|
+
rowIndex: liveIndex >= 0 ? liveIndex : change.rowIndex,
|
|
25
|
+
data: change.record,
|
|
26
|
+
value,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
export class HistoryController {
|
|
32
|
+
#undo = [];
|
|
33
|
+
#redo = [];
|
|
34
|
+
#batch = null;
|
|
35
|
+
constructor(host) {
|
|
36
|
+
this.host = host;
|
|
37
|
+
this.host.addController(this);
|
|
38
|
+
}
|
|
39
|
+
hostConnected() { }
|
|
40
|
+
get enabled() {
|
|
41
|
+
return Boolean(this.host.editing?.history?.enabled);
|
|
42
|
+
}
|
|
43
|
+
get stackSize() {
|
|
44
|
+
const size = this.host.editing?.history?.stackSize;
|
|
45
|
+
return typeof size === 'number' && size > 0 ? size : DEFAULT_STACK_SIZE;
|
|
46
|
+
}
|
|
47
|
+
get canUndo() {
|
|
48
|
+
return this.#undo.length > 0;
|
|
49
|
+
}
|
|
50
|
+
get canRedo() {
|
|
51
|
+
return this.#redo.length > 0;
|
|
52
|
+
}
|
|
53
|
+
record(change) {
|
|
54
|
+
if (!this.enabled)
|
|
55
|
+
return;
|
|
56
|
+
if (this.#batch) {
|
|
57
|
+
this.#batch.push(change);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
this.#push(new CellEditCommand(this.host, [change]));
|
|
61
|
+
}
|
|
62
|
+
beginBatch() {
|
|
63
|
+
if (!this.enabled)
|
|
64
|
+
return;
|
|
65
|
+
this.#batch ??= [];
|
|
66
|
+
}
|
|
67
|
+
endBatch() {
|
|
68
|
+
const batch = this.#batch;
|
|
69
|
+
this.#batch = null;
|
|
70
|
+
if (batch && batch.length > 0) {
|
|
71
|
+
this.#push(new CellEditCommand(this.host, batch));
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
undo() {
|
|
75
|
+
const command = this.#undo.pop();
|
|
76
|
+
if (!command)
|
|
77
|
+
return;
|
|
78
|
+
command.revert();
|
|
79
|
+
this.#redo.push(command);
|
|
80
|
+
this.#afterReplay(command, 'undo');
|
|
81
|
+
}
|
|
82
|
+
redo() {
|
|
83
|
+
const command = this.#redo.pop();
|
|
84
|
+
if (!command)
|
|
85
|
+
return;
|
|
86
|
+
command.apply();
|
|
87
|
+
this.#undo.push(command);
|
|
88
|
+
this.#afterReplay(command, 'redo');
|
|
89
|
+
}
|
|
90
|
+
clear() {
|
|
91
|
+
if (this.#undo.length === 0 && this.#redo.length === 0)
|
|
92
|
+
return;
|
|
93
|
+
this.#undo = [];
|
|
94
|
+
this.#redo = [];
|
|
95
|
+
this.#batch = null;
|
|
96
|
+
this.#emitChanged();
|
|
97
|
+
}
|
|
98
|
+
#push(command) {
|
|
99
|
+
this.#undo.push(command);
|
|
100
|
+
this.#redo = [];
|
|
101
|
+
while (this.#undo.length > this.stackSize) {
|
|
102
|
+
this.#undo.shift();
|
|
103
|
+
}
|
|
104
|
+
this.#emitChanged();
|
|
105
|
+
}
|
|
106
|
+
#afterReplay(command, kind) {
|
|
107
|
+
this.host.requestUpdate(PIPELINE);
|
|
108
|
+
const count = command instanceof CellEditCommand ? command.changes.length : 1;
|
|
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 }));
|
|
117
|
+
this.#emitChanged();
|
|
118
|
+
}
|
|
119
|
+
#emitChanged() {
|
|
120
|
+
this.host.emitEvent('historyChanged', {
|
|
121
|
+
detail: { canUndo: this.canUndo, canRedo: this.canRedo },
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=history.js.map
|
|
@@ -0,0 +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, 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,8 @@
|
|
|
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
4
|
protected host: GridHost<T>;
|
|
5
|
-
protected handlers: Map<string, (() => void) | (() => void) | (() => void) | (() => void) | (() => void) | (() => void) | (() => void)>;
|
|
5
|
+
protected handlers: Map<string, (() => void) | (() => void) | (() => void) | (() => void) | (() => void) | (() => void) | (() => void) | (() => void) | (() => void)>;
|
|
6
6
|
protected get virtualizer(): import("../components/virtualizer.js").default;
|
|
7
7
|
protected state: Map<import("../internal/types.js").NavigationState, ActiveNode<any>>;
|
|
8
8
|
protected _active: Readonly<ActiveNode<any>>;
|
|
@@ -22,11 +22,33 @@ export declare class NavigationController<T extends object> implements ReactiveC
|
|
|
22
22
|
protected getPreviousColumn(key: Keys<T>): Keys<T>;
|
|
23
23
|
protected getNextColumn(key: Keys<T>): Keys<T>;
|
|
24
24
|
protected scrollToCell(node: ActiveNode<T>): void;
|
|
25
|
+
protected findActiveCell(): import("../components/cell.js").default<T> | undefined;
|
|
26
|
+
/**
|
|
27
|
+
* Moves real DOM focus to the active cell (the grid body's roving tab stop),
|
|
28
|
+
* so screen readers track keyboard navigation. Waits for the host render to
|
|
29
|
+
* commit the cell's `active` state, then retries once on the next frame to
|
|
30
|
+
* cover virtualizer re-materialization after a long jump. No-op while no
|
|
31
|
+
* cell is active (the scroll container keeps focus as the entry point).
|
|
32
|
+
*/
|
|
33
|
+
focusActiveCell(): void;
|
|
25
34
|
get active(): ActiveNode<T>;
|
|
26
35
|
set active(node: ActiveNode<T>);
|
|
27
36
|
constructor(host: GridHost<T>);
|
|
37
|
+
/** Home moves to the first cell in the row (ARIA grid pattern). */
|
|
28
38
|
protected home(): void;
|
|
39
|
+
/** End moves to the last cell in the row (ARIA grid pattern). */
|
|
29
40
|
protected end(): void;
|
|
41
|
+
/** Ctrl/Cmd+Home moves to the first cell of the grid. */
|
|
42
|
+
protected ctrlHome(): void;
|
|
43
|
+
/** Ctrl/Cmd+End moves to the last cell of the grid. */
|
|
44
|
+
protected ctrlEnd(): void;
|
|
45
|
+
/**
|
|
46
|
+
* Rows per Page Up/Down step, derived from the host viewport and the height
|
|
47
|
+
* of a rendered row (fallback: 10 rows when nothing is measurable yet).
|
|
48
|
+
*/
|
|
49
|
+
protected pageStep(): number;
|
|
50
|
+
protected pageUp(): void;
|
|
51
|
+
protected pageDown(): void;
|
|
30
52
|
protected arrowDown(): void;
|
|
31
53
|
protected arrowUp(): void;
|
|
32
54
|
protected arrowLeft(): void;
|
|
@@ -34,5 +56,30 @@ export declare class NavigationController<T extends object> implements ReactiveC
|
|
|
34
56
|
protected toggleSelection(): void;
|
|
35
57
|
hostConnected(): void;
|
|
36
58
|
hostDisconnected(): void;
|
|
59
|
+
protected get editing(): {
|
|
60
|
+
enabled: boolean;
|
|
61
|
+
isEditable(column: ColumnConfiguration<T>): boolean;
|
|
62
|
+
editCell(rowIndex: number, columnKey: Keys<T>): Promise<boolean>;
|
|
63
|
+
} | undefined;
|
|
64
|
+
/**
|
|
65
|
+
* Enter / F2 on the active cell opens its editor (the keyboard path into
|
|
66
|
+
* edit mode). Returns `true` when the event was consumed.
|
|
67
|
+
*/
|
|
68
|
+
protected handleEditKey(event: KeyboardEvent): boolean;
|
|
69
|
+
protected get rowReorder(): {
|
|
70
|
+
enabled: boolean;
|
|
71
|
+
isGrabbing: boolean;
|
|
72
|
+
grab(rowIndex: number): boolean;
|
|
73
|
+
moveGrabbed(direction: -1 | 1): number;
|
|
74
|
+
drop(): void;
|
|
75
|
+
cancelGrab(): void;
|
|
76
|
+
} | undefined;
|
|
77
|
+
/**
|
|
78
|
+
* Keyboard row reorder: Space grabs the active row, arrows move it, Space /
|
|
79
|
+
* Enter drops, Escape cancels. Returns `true` when the event was consumed.
|
|
80
|
+
* Only active when `rowReordering.enabled` (so it never shadows Space-to-select
|
|
81
|
+
* on grids without reordering).
|
|
82
|
+
*/
|
|
83
|
+
protected handleReorderKey(event: KeyboardEvent): boolean;
|
|
37
84
|
navigate(event: KeyboardEvent): void;
|
|
38
85
|
}
|