From 2e5926bbf800d641b2baab3cb1a8b57eeae88945 Mon Sep 17 00:00:00 2001 From: ghiscoding Date: Tue, 19 Dec 2023 19:01:20 -0500 Subject: [PATCH] feat(core): add `rowHighlightCssClass` & `highlightRow()` to SlickGrid - remove previous `highlightRowByMetadata()` method in GridService, we can avoid using ItemMetaData altogether by adding a simple `highlightRow()` method directly in the SlickGrid core lib and also add `rowHighlightCssClass` grid option which will be animated by default but user could also disable the animation and/or even disable the fade out (remain highlighted) - also fix potential mem leak found on some `setTimeout` not having any `clearTimeout` assigned which could cause potential mem leaks --- .../src/core/__tests__/slickGrid.spec.ts | 37 +++++ packages/common/src/core/slickGrid.ts | 53 +++++-- .../src/interfaces/gridOption.interface.ts | 7 + .../services/__tests__/grid.service.spec.ts | 130 +----------------- packages/common/src/services/grid.service.ts | 84 ++--------- packages/common/src/styles/_variables.scss | 3 +- .../common/src/styles/slick-bootstrap.scss | 56 ++------ .../src/slick-composite-editor.component.ts | 1 - 8 files changed, 122 insertions(+), 249 deletions(-) diff --git a/packages/common/src/core/__tests__/slickGrid.spec.ts b/packages/common/src/core/__tests__/slickGrid.spec.ts index 52f4ea042..971ca7833 100644 --- a/packages/common/src/core/__tests__/slickGrid.spec.ts +++ b/packages/common/src/core/__tests__/slickGrid.spec.ts @@ -2,6 +2,8 @@ import { Column, FormatterResultWithHtml, FormatterResultWithText, GridOption } import { SlickDataView } from '../slickDataview'; import { SlickGrid } from '../slickGrid'; +jest.useFakeTimers(); + describe('SlickGrid core file', () => { let container: HTMLElement; let grid: SlickGrid; @@ -190,4 +192,39 @@ describe('SlickGrid core file', () => { expect(cellNodeElm.outerHTML).toBe('
some content
'); }); }); + + describe('highlightRow() method', () => { + const columns = [ + { id: 'firstName', field: 'firstName', name: 'First Name' }, + { id: 'lastName', field: 'lastName', name: 'Last Name' }, + { id: 'age', field: 'age', name: 'Age' }, + ] as Column[]; + const options = { enableCellNavigation: true, devMode: { ownerNodeIndex: 0 } } as GridOption; + const dv = new SlickDataView({}); + + it('should call the method and expect the highlight to happen for a certain duration', () => { + const mockItems = [{ id: 0, firstName: 'John', lastName: 'Doe', age: 30 }, { id: 0, firstName: 'Jane', lastName: 'Doe', age: 28 }]; + + grid = new SlickGrid(container, dv, columns, options); + dv.addItems(mockItems); + grid.init(); + grid.render(); + + grid.highlightRow(0, 10); + expect(grid).toBeTruthy(); + expect(grid.getDataLength()).toBe(2); + + let slickRowElms = container.querySelectorAll('.slick-row'); + expect(slickRowElms.length).toBe(2); + expect(slickRowElms[0].classList.contains('highlight-animate')).toBeTruthy(); // only 1st row is highlighted + expect(slickRowElms[1].classList.contains('highlight-animate')).toBeFalsy(); + + jest.runAllTimers(); // fast-forward timer + + slickRowElms = container.querySelectorAll('.slick-row'); + expect(slickRowElms.length).toBe(2); + expect(slickRowElms[0].classList.contains('highlight-animate')).toBeFalsy(); + expect(slickRowElms[1].classList.contains('highlight-animate')).toBeFalsy(); + }); + }); }); \ No newline at end of file diff --git a/packages/common/src/core/slickGrid.ts b/packages/common/src/core/slickGrid.ts index c2c78d367..e20f71754 100644 --- a/packages/common/src/core/slickGrid.ts +++ b/packages/common/src/core/slickGrid.ts @@ -218,6 +218,7 @@ export class SlickGrid = Column, O e formatterFactory: null, editorFactory: null, cellFlashingCssClass: 'flashing', + rowHighlightCssClass: 'highlight-animate', selectedCellCssClass: 'selected', multiSelect: true, enableTextSelectionOnCells: false, @@ -266,6 +267,11 @@ export class SlickGrid = Column, O e hidden: false } as Partial; + protected _columnResizeTimer?: NodeJS.Timeout; + protected _executionBlockTimer?: NodeJS.Timeout; + protected _flashCellTimer?: NodeJS.Timeout; + protected _highlightRowTimer?: NodeJS.Timeout; + // scroller protected th!: number; // virtual height protected h!: number; // real scrollable height @@ -374,7 +380,7 @@ export class SlickGrid = Column, O e // async call handles protected h_editorLoader: any = null; protected h_render = null; - protected h_postrender: any = null; + protected h_postrender?: NodeJS.Timeout; protected h_postrenderCleanup: any = null; protected postProcessedRows: any = {}; protected postProcessToRow: number = null as any; @@ -2214,7 +2220,8 @@ export class SlickGrid = Column, O e this.updateCanvasWidth(true); this.render(); this.trigger(this.onColumnsResized, { triggeredByColumn }); - setTimeout(() => { this.columnResizeDragging = false; }, 300); + clearTimeout(this._columnResizeTimer); + this._columnResizeTimer = setTimeout(() => { this.columnResizeDragging = false; }, 300); } }) ); @@ -2462,6 +2469,15 @@ export class SlickGrid = Column, O e this.stylesheet = null; } + /** Clear all highlight timers that might have been left opened */ + protected clearAllTimers() { + clearTimeout(this._columnResizeTimer); + clearTimeout(this._executionBlockTimer); + clearTimeout(this._flashCellTimer); + clearTimeout(this._highlightRowTimer); + clearTimeout(this.h_editorLoader); + } + /** * Destroy (dispose) of SlickGrid * @param {boolean} shouldDestroyAllElements - do we want to destroy (nullify) all DOM elements as well? This help in avoiding mem leaks @@ -2546,6 +2562,7 @@ export class SlickGrid = Column, O e emptyElement(this._container); this._container.classList.remove(this.uid); + this.clearAllTimers(); if (shouldDestroyAllElements) { this.destroyAllElements(); @@ -4524,7 +4541,8 @@ export class SlickGrid = Column, O e const blockAndExecute = () => { blocked = true; - setTimeout(unblock, minPeriod_ms); + clearTimeout(this._executionBlockTimer); + this._executionBlockTimer = setTimeout(unblock, minPeriod_ms); action.call(this); }; @@ -4703,17 +4721,16 @@ export class SlickGrid = Column, O e * Flashes the cell twice by toggling the CSS class 4 times. * @param {Number} row A row index. * @param {Number} cell A column index. - * @param {Number} [speed] (optional) - The milliseconds delay between the toggling calls. Defaults to 100 ms. + * @param {Number} [speed] (optional) - The milliseconds delay between the toggling calls. Defaults to 250 ms. */ - flashCell(row: number, cell: number, speed?: number) { - speed = speed || 250; - + flashCell(row: number, cell: number, speed = 250) { const toggleCellClass = (cellNode: HTMLElement, times: number) => { if (times < 1) { return; } - setTimeout(() => { + clearTimeout(this._flashCellTimer); + this._flashCellTimer = setTimeout(() => { if (times % 2 === 0) { cellNode.classList.add(this._options.cellFlashingCssClass || ''); } else { @@ -4731,6 +4748,26 @@ export class SlickGrid = Column, O e } } + /** + * Highlight a row for a certain duration (ms) of time. + * If the duration is set to null/undefined, then the row will remain highlighted indifinitely. + * @param {Number} row - grid row number + * @param {Number} duration - duration (ms) + */ + highlightRow(row: number, duration?: number) { + const rowCache = this.rowsCache[row]; + + if (Array.isArray(rowCache?.rowNode) && this._options.rowHighlightCssClass) { + rowCache.rowNode.forEach(node => node.classList.add(this._options.rowHighlightCssClass || '')); + if (typeof duration === 'number') { + clearTimeout(this._highlightRowTimer); + this._highlightRowTimer = setTimeout(() => { + rowCache.rowNode?.forEach(node => node.classList.remove(this._options.rowHighlightCssClass || '')); + }, duration); + } + } + } + // Interactivity protected handleMouseWheel(e: MouseEvent, _delta: number, deltaX: number, deltaY: number) { diff --git a/packages/common/src/interfaces/gridOption.interface.ts b/packages/common/src/interfaces/gridOption.interface.ts index 15a3317df..da073d383 100644 --- a/packages/common/src/interfaces/gridOption.interface.ts +++ b/packages/common/src/interfaces/gridOption.interface.ts @@ -628,6 +628,13 @@ export interface GridOption { /** Grid row height in pixels (only type the number). Row of cell values. */ rowHeight?: number; + /** + * Defaults to "highlight-animate", a CSS class name used to simulate row highlight with an optional duration (e.g. after insert). + * The default class is "highlight-animate" but you could also use "highlight" if you don't plan on using duration neither animation. + * Note: when having a duration, make sure that it's always lower than the duration defined in the CSS/SASS variable `$slick-row-highlight-fade-animation` + */ + rowHighlightCssClass?: string; + /** Row Move Manager Plugin options & events */ rowMoveManager?: RowMoveManager; diff --git a/packages/common/src/services/__tests__/grid.service.spec.ts b/packages/common/src/services/__tests__/grid.service.spec.ts index d8ec3c779..1750e5e43 100644 --- a/packages/common/src/services/__tests__/grid.service.spec.ts +++ b/packages/common/src/services/__tests__/grid.service.spec.ts @@ -6,7 +6,6 @@ import { GridOption, CellArgs, Column, OnEventArgs } from '../../interfaces/inde import { SlickRowSelectionModel } from '../../extensions/slickRowSelectionModel'; import { type SlickDataView, SlickEvent, type SlickGrid } from '../../core/index'; -jest.useFakeTimers(); jest.mock('flatpickr', () => { }); const mockRowSelectionModel = { @@ -79,6 +78,7 @@ const gridStub = { getSelectionModel: jest.fn(), setSelectionModel: jest.fn(), getSelectedRows: jest.fn(), + highlightRow: jest.fn(), navigateBottom: jest.fn(), navigateTop: jest.fn(), render: jest.fn(), @@ -126,12 +126,17 @@ describe('Grid Service', () => { it('should dispose of the service', () => { const disposeSpy = jest.spyOn(mockRowSelectionModel, 'dispose'); - service.highlightRow(0, 10, 15); + service.highlightRow(0, 10); service.dispose(); expect(disposeSpy).toHaveBeenCalled(); }); + it('should be able to highlight first row at zero index', () => { + service.highlightRow(0, 10); + expect(gridStub.highlightRow).toHaveBeenCalled(); + }); + describe('getAllColumnDefinitions method', () => { it('should call "allColumns" GETTER ', () => { const mockColumns = [{ id: 'field1', field: 'field1', width: 100 }, { id: 'field2', field: 'field2', width: 100 }]; @@ -1406,105 +1411,6 @@ describe('Grid Service', () => { }); }); - describe('getItemRowMetadataToHighlight method', () => { - const options = { groupItemMetadataProvider: { getGroupRowMetadata: jest.fn(), getTotalsRowMetadata: jest.fn() } }; - const columnDefinitions = [ - { id: 'field1', width: 100, __group: {}, __groupTotals: {} }, - { id: 'field2', width: 150, rowClass: 'red' }, - { id: 'field3', field: 'field3', cssClasses: 'highlight', _dirty: true } - ]; - - // this mock is a typical callback function returned by SlickGrid internally, without anything changed to it's logic - const mockItemMetadataFn = (i: number) => { - const columnDef = columnDefinitions[i]; - if (columnDef === undefined) { - return null; - } - if (columnDef.__group) { // overrides for grouping rows - return options.groupItemMetadataProvider.getGroupRowMetadata(columnDef); - } - if (columnDef.__groupTotals) { // overrides for totals rows - return options.groupItemMetadataProvider.getTotalsRowMetadata(columnDef); - } - return null; - }; - - it('should return a callback function when method is called', () => { - const callback = service.getItemRowMetadataToHighlight(mockItemMetadataFn); - expect(typeof callback === 'function').toBe(true); - }); - - it('should return an Item Metadata object with empty "cssClasses" property after executing the callback function', () => { - const rowNumber = 0; - const dataviewSpy = jest.spyOn(dataviewStub, 'getItem').mockReturnValue(columnDefinitions[rowNumber]); - - const callback = service.getItemRowMetadataToHighlight(mockItemMetadataFn); - const output = callback(rowNumber); // execute callback with a row number - - expect(dataviewSpy).toHaveBeenCalled(); - expect(typeof callback === 'function').toBe(true); - expect(output).toEqual({ cssClasses: '' }); - }); - - it('should return an Item Metadata object with a "dirty" string in the "cssClasses" property after executing the callback function', () => { - const rowNumber = 2; - const dataviewSpy = jest.spyOn(dataviewStub, 'getItem').mockReturnValue(columnDefinitions[rowNumber]); - - const callback = service.getItemRowMetadataToHighlight(mockItemMetadataFn); - const output = callback(rowNumber); // execute callback with a row number - - expect(dataviewSpy).toHaveBeenCalled(); - expect(typeof callback === 'function').toBe(true); - expect(output).toEqual({ cssClasses: ' dirty' }); - }); - - it('should return an Item Metadata object with filled "cssClasses" property when callback provided already returns a "cssClasses" property', () => { - const rowNumber = 2; - const dataviewSpy = jest.spyOn(dataviewStub, 'getItem').mockReturnValue(columnDefinitions[rowNumber]); - - const callback = service.getItemRowMetadataToHighlight(() => { - return { cssClasses: 'highlight' }; - }); - const output = callback(rowNumber); // execute callback with a row number - - expect(dataviewSpy).toHaveBeenCalled(); - expect(typeof callback === 'function').toBe(true); - expect(output).toEqual({ cssClasses: 'highlight dirty' }); - }); - - it(`should return an Item Metadata object with filled "cssClasses" property including a row number in the string - when the column definition has a "rowClass" property and when callback provided already returns a "cssClasses" property`, () => { - const rowNumber = 1; - const dataviewSpy = jest.spyOn(dataviewStub, 'getItem').mockReturnValue(columnDefinitions[rowNumber]); - - const callback = service.getItemRowMetadataToHighlight(mockItemMetadataFn); - const output = callback(rowNumber); // execute callback with a row number - - expect(dataviewSpy).toHaveBeenCalled(); - expect(typeof callback === 'function').toBe(true); - expect(output).toEqual({ cssClasses: ' red row1' }); - }); - }); - - describe('highlightRowByMetadata method', () => { - it('should hightlight a row with a fading start & end delay', () => { - const mockColumn = { id: 'field2', field: 'field2', width: 150, rowClass: 'red' } as Column; - const getItemSpy = jest.spyOn(dataviewStub, 'getItem').mockReturnValue(mockColumn); - const getIndexSpy = jest.spyOn(dataviewStub, 'getIdxById').mockReturnValue(0); - const updateSpy = jest.spyOn(dataviewStub, 'updateItem'); - const renderSpy = jest.spyOn(service, 'renderGrid'); - - service.highlightRowByMetadata(2, 1, 1); - jest.runAllTimers(); // fast-forward timer - - expect(getItemSpy).toHaveBeenCalledWith(2); - expect(updateSpy).toHaveBeenCalledTimes(3); - expect(updateSpy).toHaveBeenCalledWith(mockColumn.id, mockColumn); - expect(renderSpy).toHaveBeenCalled(); - expect(getIndexSpy).toHaveBeenCalled(); - }); - }); - describe('getDataItemByRowIndex method', () => { afterEach(() => { gridStub.getDataItem = jest.fn(); // put it back as a valid mock for later tests @@ -1820,26 +1726,4 @@ describe('Grid Service', () => { expect(sortSpy).toHaveBeenCalled(); }); }); - - describe('highlightRow method', () => { - afterEach(() => { - jest.clearAllMocks(); - }); - - it('should be able to highlight first row at zero index', () => { - const mockRowMetadata = (rowNumber) => ({ cssClasses: `row-${rowNumber}` }); - const mockItem = { id: 0, firstName: 'John', lastName: 'Doe' }; - jest.spyOn(service, 'getItemRowMetadataToHighlight').mockReturnValue(mockRowMetadata); - jest.spyOn(dataviewStub, 'getItem').mockReturnValue(mockItem); - jest.spyOn(dataviewStub, 'getIdxById').mockReturnValue(0); - const updateSpy = jest.spyOn(dataviewStub, 'updateItem'); - const renderSpy = jest.spyOn(service, 'renderGrid'); - - service.highlightRow(0, 10, 15); - jest.runAllTimers(); // fast-forward timer - - expect(updateSpy).toHaveBeenCalledWith(0, mockItem); - expect(renderSpy).toHaveBeenCalledTimes(3); - }); - }); }); diff --git a/packages/common/src/services/grid.service.ts b/packages/common/src/services/grid.service.ts index e18dbbd6e..ec6e6a66c 100644 --- a/packages/common/src/services/grid.service.ts +++ b/packages/common/src/services/grid.service.ts @@ -29,8 +29,6 @@ const HideColumnOptionDefaults: HideColumnOption = { autoResizeColumns: true, tr export class GridService { protected _grid!: SlickGrid; protected _rowSelectionPlugin?: SlickRowSelectionModel; - protected _highlightTimer?: NodeJS.Timeout; - protected _highlightTimerEnd?: NodeJS.Timeout; constructor( protected readonly gridStateService: GridStateService, @@ -53,7 +51,6 @@ export class GridService { } dispose() { - this.clearHighlightTimer(); this._rowSelectionPlugin?.dispose(); } @@ -72,12 +69,6 @@ export class GridService { } } - /** Clear any highlight timer that might have been left opened */ - clearHighlightTimer() { - clearTimeout(this._highlightTimer); - clearTimeout(this._highlightTimerEnd); - } - /** Clear all the pinning (frozen) options */ clearPinning(resetColumns = true) { const visibleColumns = [...this.sharedService.visibleColumns]; @@ -154,32 +145,6 @@ export class GridService { return this._grid.getDataItem(rowNumber); } - /** Chain the item Metadata with our implementation of Metadata at given row index */ - getItemRowMetadataToHighlight(previousItemMetadata: any) { - return (rowNumber: number) => { - const item = this._dataView.getItem(rowNumber); - let meta = { cssClasses: '' }; - if (typeof previousItemMetadata === 'function') { - meta = previousItemMetadata.call(this._dataView, rowNumber); - } - - if (!meta) { - meta = { cssClasses: '' }; - } - - if (item && item._dirty) { - meta.cssClasses = (meta && meta.cssClasses || '') + ' dirty'; - } - - if (item && item.rowClass && meta) { - meta.cssClasses += ` ${item.rowClass}`; - meta.cssClasses += ` row${rowNumber}`; - } - - return meta; - }; - } - /** Get the Data Item from a grid row index */ getDataItemByRowIndex(index: number): T { if (!this._grid || typeof this._grid.getDataItem !== 'function') { @@ -290,12 +255,11 @@ export class GridService { } /** - * Highlight then fade a row for x seconds. - * The implementation follows this SO answer: https://stackoverflow.com/a/19985148/1212166 - * @param rowNumber - * @param fadeDelay + * Highlight then fade a row for certain duration (ms). + * @param {Number} rowNumber - grid row number + * @param {Number} duration - duration in ms */ - highlightRow(rowNumber: number | number[], fadeDelay = 1500, fadeOutDelay = 300) { + highlightRow(rowNumber: number | number[], duration = 750) { // create a SelectionModel if there's not one yet if (!this._grid.getSelectionModel()) { this._rowSelectionPlugin = new SlickRowSelectionModel(this._gridOptions.rowSelectionOptions); @@ -303,43 +267,25 @@ export class GridService { } if (Array.isArray(rowNumber)) { - rowNumber.forEach(row => this.highlightRowByMetadata(row, fadeDelay, fadeOutDelay)); + rowNumber.forEach(row => this._grid.highlightRow(row)); } else { - this.highlightRowByMetadata(rowNumber, fadeDelay, fadeOutDelay); + this._grid.highlightRow(rowNumber, duration); } } - highlightRowByMetadata(rowNumber: number, fadeDelay = 1500, fadeOutDelay = 300) { - this._dataView.getItemMetadata = this.getItemRowMetadataToHighlight(this._dataView.getItemMetadata); - - const item = this._dataView.getItem(rowNumber); - const idPropName = this._gridOptions.datasetIdPropertyName || 'id'; + protected fadeHighlight(item: any, idPropName: string) { + item.__slickRowCssClasses = 'highlight-end'; + this._dataView.updateItem(item[idPropName], item); + this.renderGrid(); + } + protected removeHighlight(item: any, idPropName: string) { if (item?.[idPropName] !== undefined) { - item.rowClass = 'highlight'; - this._dataView.updateItem(item[idPropName], item); - this.renderGrid(); - - // clear both timers - this.clearHighlightTimer(); - - // fade out - this._highlightTimerEnd = setTimeout(() => { - item.rowClass = 'highlight-end'; + delete item.__slickRowCssClasses; + if (this._dataView.getIdxById(item[idPropName]) !== undefined) { this._dataView.updateItem(item[idPropName], item); this.renderGrid(); - }, fadeOutDelay); - - // delete the row's CSS highlight classes once the delay is passed - this._highlightTimer = setTimeout(() => { - if (item?.[idPropName] !== undefined) { - delete item.rowClass; - if (this._dataView.getIdxById(item[idPropName]) !== undefined) { - this._dataView.updateItem(item[idPropName], item); - this.renderGrid(); - } - } - }, fadeDelay + fadeOutDelay); + } } } diff --git a/packages/common/src/styles/_variables.scss b/packages/common/src/styles/_variables.scss index 40d8f6e11..763e06188 100644 --- a/packages/common/src/styles/_variables.scss +++ b/packages/common/src/styles/_variables.scss @@ -71,8 +71,7 @@ $slick-row-mouse-hover-box-shadow: none !default; $slick-row-mouse-hover-z-index: 5 !default; $slick-row-selected-color: #dae8f1 !default; $slick-row-highlight-background-color: darken($slick-row-selected-color, 5%) !default; -$slick-row-highlight-fade-animation: 1.5s ease 1 !default; -$slick-row-highlight-fade-out-animation: 0.3s ease 1 !default; +$slick-row-highlight-fade-animation: 1s linear !default; $slick-row-checkbox-selector-background: inherit !default; $slick-row-checkbox-selector-border: none !default; diff --git a/packages/common/src/styles/slick-bootstrap.scss b/packages/common/src/styles/slick-bootstrap.scss index 31c32a632..aa6a89b7d 100644 --- a/packages/common/src/styles/slick-bootstrap.scss +++ b/packages/common/src/styles/slick-bootstrap.scss @@ -1,24 +1,9 @@ /* Mixins for SlickGrid */ @import './variables'; -@-webkit-keyframes highlight-start { - to { background: var(--slick-row-highlight-background-color, $slick-row-highlight-background-color); } - from { background: none; } -} - -@keyframes highlight-start { - to { background: var(--slick-row-highlight-background-color, $slick-row-highlight-background-color); } - from { background: none; } -} - -@-webkit-keyframes highlight-end { - from { background: var(--slick-row-highlight-fade-out-animation, $slick-row-highlight-fade-out-animation); } - to { background: none; } -} - -@keyframes highlight-end { - from { background: var(--slick-row-highlight-fade-out-animation, $slick-row-highlight-fade-out-animation); } - to { background: none; } +@keyframes fade { + 0%, 100% { background: none } + 50% { background: var(--slick-row-highlight-background-color, $slick-row-highlight-background-color) } } .slickgrid-container { @@ -72,34 +57,6 @@ &.active { padding: var(--slick-cell-padding, $slick-cell-padding); } - &.highlight { - background-color: var(--slick-row-highlight-background-color, $slick-row-highlight-background-color); - animation: highlight-start $slick-row-highlight-fade-animation; - .slick-cell { - &.copied { - background: var(--slick-copied-cell-bg-color-transition, $slick-copied-cell-bg-color-transition); - transition: var(--slick-copied-cell-transition, $slick-copied-cell-transition); - } - } - &.odd { - background-color: var(--slick-row-highlight-background-color, $slick-row-highlight-background-color); - animation: highlight-start #{var(--slick-row-highlight-fade-animation, $slick-row-highlight-fade-animation)}; - } - &.odd .slick-cell { - &.copied { - background: var(--slick-copied-cell-bg-color-transition, $slick-copied-cell-bg-color-transition); - transition: var(--slick-copied-cell-transition, $slick-copied-cell-transition); - } - } - } - &.highlight-end { - background-color: var(--slick-row-highlight-background-color, $slick-row-highlight-background-color); - animation: highlight-end #{var(--slick-row-highlight-fade-animation, $slick-row-highlight-fade-animation)}; - &.odd { - background-color: var(--slick-row-highlight-background-color, $slick-row-highlight-background-color); - animation: highlight-end #{var(--slick-row-highlight-fade-animation, $slick-row-highlight-fade-animation)}; - } - } &.highlighter { background: orange !important; transition-property: background; @@ -136,6 +93,13 @@ } background: inherit; } + &.highlight { + background: var(--slick-row-highlight-background-color, $slick-row-highlight-background-color); + } + &.highlight-animate { + background: var(--slick-row-highlight-background-color, $slick-row-highlight-background-color); + animation: fade var(--slick-row-highlight-fade-animation, $slick-row-highlight-fade-animation); + } &.slick-group-totals { color: var(--slick-group-totals-formatter-color, $slick-group-totals-formatter-color); background: var(--slick-group-totals-formatter-bgcolor, $slick-group-totals-formatter-bgcolor); diff --git a/packages/composite-editor-component/src/slick-composite-editor.component.ts b/packages/composite-editor-component/src/slick-composite-editor.component.ts index bf1dadde7..2d58d2331 100644 --- a/packages/composite-editor-component/src/slick-composite-editor.component.ts +++ b/packages/composite-editor-component/src/slick-composite-editor.component.ts @@ -501,7 +501,6 @@ export class SlickCompositeEditorComponent implements ExternalResource { // when adding a new row to the grid, we need to invalidate that row and re-render the grid this._eventHandler.subscribe(this.grid.onAddNewRow, (_e, args) => { this._originalDataContext = this.insertNewItemInDataView(args.item); // this becomes the new data context - // this.disposeComponent(); }); } return this;