# Cell Flash
URL: https://pro.rv-grid.com/api/cell-flash/
Source: src/content/docs/api/cell-flash.md
## Module Extensions

### `CellTemplateProp` (Extended from `@revolist/revogrid`)

```ts
interface CellTemplateProp {
  /**
       * Previous value captured when the flash was requested.
       */
      previousValue?: any;
  /**
       * Direction resolved by the flash plugin.
       */
      flashDirection?: CellFlashDirection;
  /**
       * Active flash state for the rendered cell.
       */
      flashState?: any
}
```

---

### `ColumnRegular` (Extended from `@revolist/revogrid`)

```ts
interface ColumnRegular {
  /**
       * Enables flash feedback for this column.
       *
       * Legacy `(value) => boolean` predicates are supported. Context-aware
       * predicates can inspect the previous value, row model, row type, and edit
       * event metadata, and can return a decision object to customize a flash.
       *
       * @example
       * ```ts
       * const columns = [
       *   { prop: 'name', name: 'Name', flash: value => Boolean(value) },
       *   {
       *     prop: 'price',
       *     name: 'Price',
       *     flash: (value, context) => ({
       *       flash: value !== context.previousValue,
       *       rowFlash: true,
       *       direction: Number(value) > Number(context.previousValue) ? 'up' : 'down',
       *     }),
       *   },
       * ];
       * ```
       */
      flash?: CellFlashPredicate
}
```

---

### `HTMLRevoGridElement` (Extended from `@revolist/revogrid`)

```ts
interface HTMLRevoGridElement {
  /**
       * Cell flash plugin configuration.
       *
       * @example
       * ```ts
       * const grid = document.querySelector('revo-grid');
       * grid.plugins = [CellFlashPlugin, EventManagerPlugin];
       * grid.cellFlash = {
       *   duration: 1200,
       *   mode: 'cell-and-row',
       *   queue: 'merge',
       * };
       * ```
       */
      cellFlash?: CellFlashConfig
}
```

---

### `AdditionalData` (Extended from `@revolist/revogrid`)

```ts
interface AdditionalData {
  /**
       * Additional data property for cell flash configuration.
       *
       * Useful for framework wrappers where all plugin options are passed through
       * one memoized or computed `additionalData` object.
       *
       * @example
       * ```tsx
       * const additionalData = useMemo(() => ({
       *   cellFlash: {
       *     duration: 900,
       *     mode: 'cell-and-row',
       *   },
       * }), []);
       * ```
       */
      cellFlash?: CellFlashConfig
}
```

## Plugin API

### `CellFlashPlugin`

Highlights recently changed cells and rows.

Existing usage with `flash: (value) => true`, `FLASH_CELL_EVENT`, and
`cellFlashArrowTemplate()` remains supported. Configure richer behavior
through `grid.cellFlash` or call the instance methods for manual dashboard
updates.

**Example:**
```typescript
* import { CellFlashPlugin, EventManagerPlugin } from '@revolist/revogrid-pro';
 *
 * const grid = document.querySelector('revo-grid');
 * grid.plugins = [CellFlashPlugin, EventManagerPlugin];
 * grid.columns = [
 *   { prop: 'name', name: 'Name' },
 *   { prop: 'price', name: 'Price', flash: value => value !== undefined },
 * ];
 *
 *
```
**Example:**
```typescript
* grid.cellFlash = {
 *   mode: 'cell-and-row',
 *   queue: 'merge',
 *   duration: 900,
 *   rowDuration: 1400,
 *   aria: { enabled: true },
 * };
 *
 *
```
**Example:**
```typescript
* grid.columns = [
 *   {
 *     prop: 'inventory',
 *     name: 'Inventory',
 *     flash: (value, context) => ({
 *       flash: value !== context.previousValue,
 *       rowFlash: Number(value) === 0,
 *       direction: Number(value) > Number(context.previousValue) ? 'up' : 'down',
 *       ariaLabel: `Inventory changed to ${value}`,
 *     }),
 *   },
 * ];
```

#### Dependencies

- **Event integration** `EventManagerPlugin`: Integrates with EventManagerPlugin edit events for automatic edit flashes.
- **Event integration** `HistoryPlugin`: Integrates with HistoryPlugin undo and redo replay edit events when present.
- **Config integration** `additionalData.cellFlash`: Reads cell flash configuration from additionalData.cellFlash.

```ts
class CellFlashPlugin {
  /**
     * Flashes one cell manually.
     *
     * Use this for live-feed updates or external actions that do not come through
     * RevoGrid edit events. The method keeps the old event-driven behavior intact
     * and only applies an additional manual flash state.
     *
     * @param target Cell coordinates and optional flash metadata.
     *
     * @example
     * ```ts
     * const plugin = grid.getPlugins?.().find(p => p instanceof CellFlashPlugin);
     * plugin?.flashCell({
     *   rowIndex: 3,
     *   prop: 'price',
     *   previousValue: 42,
     *   value: 45,
     *   direction: 'up',
     *   duration: 800,
     * });
     * ```
     */
  flashCell(target: CellFlashCellTarget);

  /**
     * Flashes a batch of changed cells using the same detail shape as the
     * `flashcell` event.
     *
     * Column `flash` predicates are evaluated for each changed prop. Queue and
     * mode options override the configured defaults for this call only.
     *
     * @param detail Batch detail containing changed values, row type, and optional previous values.
     * @param options Optional queue, mode, and duration overrides for this batch.
     *
     * @example
     * ```ts
     * plugin.flashCells(
     *   {
     *     type: 'rgRow',
     *     data: { 0: { price: 45, status: 'Updated' } },
     *     previousData: { 0: { price: 42, status: 'Draft' } },
     *     eventTypes: ['live-feed'],
     *   },
     *   { queue: 'merge', mode: 'cell-and-row' },
     * );
     * ```
     *
     * @example
     * ```ts
     * grid.dispatchEvent(new CustomEvent('flashcell', {
     *   detail: {
     *     type: 'rgRow',
     *     data: { 1: { price: 50 } },
     *     previousData: { 1: { price: 48 } },
     *   },
     * }));
     * ```
     */
  flashCells(detail: FlashBatchDetail, options?: CellFlashApplyOptions);

  /**
     * Flashes one or more rows manually.
     *
     * Row flashes are rendered through `beforerowrender`, so virtualized rows keep
     * the correct visual state when they re-enter the viewport before expiry.
     *
     * @param targets One row target or an array of row targets.
     * @param options Optional queue, mode, and row duration overrides.
     *
     * @example
     * ```ts
     * plugin.flashRows(
     *   [
     *     { rowIndex: 0, direction: 'changed' },
     *     { rowIndex: 4, direction: 'down', rowClassName: 'risk-row-flash' },
     *   ],
     *   { queue: 'merge', rowDuration: 1200 },
     * );
     * ```
     */
  flashRows(targets: CellFlashRowTarget | CellFlashRowTarget[], options?: CellFlashApplyOptions);

  /**
     * Clears active flash state.
     *
     * Without a target, all active cell and row flashes are cleared. Passing a
     * row target clears the row plus all active cell flashes in that row. Passing
     * both `rowIndex` and `prop` clears one cell.
     *
     * @param target Optional cell or row target to clear.
     *
     * @example
     * ```ts
     * plugin.clearFlash(); // clear all flashes
     * plugin.clearFlash({ rowIndex: 2 }); // clear row 2 and its cell flashes
     * plugin.clearFlash({ rowIndex: 2, prop: 'price' }); // clear one cell
     * ```
     */
  clearFlash(target?: Partial<CellFlashCellTarget & CellFlashRowTarget>);

  destroy();
}
```

---

### `cellFlashArrowTemplate`

```ts
cellFlashArrowTemplate: (templateOrOptions?: CellTemplate<DataType<any, ColumnProp>> | CellFlashArrowTemplateOptions | undefined, templateOptions?: CellFlashArrowTemplateOptions | undefined) => CellTemplate<DataType<any, ColumnProp>> | undefined;
```

---

### `resolveCellFlashConfig`

Resolves partial public configuration into the plugin's internal defaults.

**Example:**
```typescript
* ```ts
 * const config = resolveCellFlashConfig({ duration: 1500, queue: 'merge' });
 * console.log(config.mode); // "cell"
 * ```
```

```ts
export function resolveCellFlashConfig(
  config?: CellFlashConfig,
): ResolvedCellFlashConfig;
```

---

### `CellFlashDirection`

Direction metadata attached to an active cell or row flash.

The default resolver returns `up` or `down` for numeric changes,
`changed` for non-numeric value changes, and `none` when no previous value
is available.

**Example:**
```typescript
* ```ts
 * const columns = [
 *   {
 *     prop: 'price',
 *     name: 'Price',
 *     flash: (value, context) => ({
 *       flash: true,
 *       direction: Number(value) > Number(context.previousValue) ? 'up' : 'down',
 *     }),
 *   },
 * ];
 * ```
```

```ts
/**
 * Direction metadata attached to an active cell or row flash.
 *
 * The default resolver returns `up` or `down` for numeric changes,
 * `changed` for non-numeric value changes, and `none` when no previous value
 * is available.
 *
 * @example
 * ```ts
 * const columns = [
 *   {
 *     prop: 'price',
 *     name: 'Price',
 *     flash: (value, context) => ({
 *       flash: true,
 *       direction: Number(value) > Number(context.previousValue) ? 'up' : 'down',
 *     }),
 *   },
 * ];
 * ```
 */
export type CellFlashDirection = 'up' | 'down' | 'changed' | 'none';
```

---

### `CellFlashMode`

Defines whether flash requests affect cells, rows, or both.

**Example:**
```typescript
* ```ts
 * grid.cellFlash = {
 *   mode: 'cell-and-row',
 *   rowDuration: 1400,
 * };
 * ```
```

```ts
/**
 * Defines whether flash requests affect cells, rows, or both.
 *
 * @example
 * ```ts
 * grid.cellFlash = {
 *   mode: 'cell-and-row',
 *   rowDuration: 1400,
 * };
 * ```
 */
export type CellFlashMode = 'cell' | 'row' | 'cell-and-row';
```

---

### `CellFlashQueueMode`

Controls how new flash requests interact with active flashes.

`replace` preserves the legacy behavior by clearing existing flashes before
applying a new batch. `merge` keeps existing flashes active until their own
timers expire.

**Example:**
```typescript
* ```ts
 * grid.cellFlash = {
 *   queue: 'merge',
 *   maxActive: 300,
 * };
 * ```
```

```ts
/**
 * Controls how new flash requests interact with active flashes.
 *
 * `replace` preserves the legacy behavior by clearing existing flashes before
 * applying a new batch. `merge` keeps existing flashes active until their own
 * timers expire.
 *
 * @example
 * ```ts
 * grid.cellFlash = {
 *   queue: 'merge',
 *   maxActive: 300,
 * };
 * ```
 */
export type CellFlashQueueMode = 'replace' | 'merge';
```

---

### `CellFlashContext`

Runtime information passed to context-aware column flash predicates and
direction resolvers.

**Example:**
```typescript
* ```ts
 * const columns = [
 *   {
 *     prop: 'status',
 *     name: 'Status',
 *     flash: (value, context) => {
 *       return context.previousValue !== value && context.eventTypes?.includes('edit');
 *     },
 *   },
 * ];
 * ```
```

```ts
interface CellFlashContext {
  /** New value from the edit/manual flash batch. */
    value: unknown;
  /** Previous value captured from the event detail or current row model. */
    previousValue: unknown;
  /** Row index in the target row type. */
    rowIndex: number;
  /** Column property for the changed cell. */
    prop: ColumnProp;
  /** Column definition for the changed cell. */
    column: ColumnRegular;
  /** Current row model, when available from the data provider. */
    model?: DataType;
  /** RevoGrid row bucket, for example `rgRow`, `rowPinStart`, or `rowPinEnd`. */
    type: DimensionRows;
  /** Edit/history event type metadata when emitted by EventManagerPlugin. */
    eventTypes?: string[];
  /** Original flash/edit event detail for advanced consumers. */
    detail?: Partial<BeforeRangeSaveDataDetails>
}
```

---

### `CellFlashDecision`

Per-change decision returned from a context-aware column `flash` predicate.

Returning `true` is equivalent to `{ flash: true }`. Return a decision object
to customize duration, direction, classes, row flashing, or accessibility
text for a specific value change.

**Example:**
```typescript
* ```ts
 * const columns = [
 *   {
 *     prop: 'inventory',
 *     name: 'Inventory',
 *     flash: (value, context) => ({
 *       flash: true,
 *       rowFlash: Number(value) === 0,
 *       direction: Number(value) > Number(context.previousValue) ? 'up' : 'down',
 *       className: Number(value) === 0 ? 'cell-flash-danger' : undefined,
 *       ariaLabel: `Inventory changed to ${value}`,
 *     }),
 *   },
 * ];
 * ```
```

```ts
interface CellFlashDecision {
  /** Whether the changed cell should flash. Defaults to true for decision objects. */
    flash?: boolean;
  /** Whether the containing row should flash for this change. */
    rowFlash?: boolean;
  /** Cell flash duration in milliseconds for this change. */
    duration?: number;
  /** Row flash duration in milliseconds for this change. */
    rowDuration?: number;
  /** Direction metadata for templates, attributes, and CSS selectors. */
    direction?: CellFlashDirection;
  /** Additional class applied to the flashing cell. */
    className?: string;
  /** Additional class applied to the flashing row. */
    rowClassName?: string;
  /** Message announced through the plugin aria-live region when enabled. */
    ariaLabel?: string
}
```

---

### `CellFlashPredicate`

Column flash configuration.

Legacy predicates that only accept `(value) => boolean` still work. New
predicates may accept the second `CellFlashContext` argument and return a
`CellFlashDecision`.

**Example:**
```typescript
* ```ts
 * const columns = [
 *   { prop: 'name', name: 'Name', flash: true },
 *   {
 *     prop: 'price',
 *     name: 'Price',
 *     flash: (value, context) => ({
 *       flash: value !== context.previousValue,
 *       direction: Number(value) > Number(context.previousValue) ? 'up' : 'down',
 *     }),
 *   },
 * ];
 * ```
```

```ts
/**
 * Column flash configuration.
 *
 * Legacy predicates that only accept `(value) = > boolean` still work. New
 * predicates may accept the second `CellFlashContext` argument and return a
 * `CellFlashDecision`.
 *
 * @example
 * ```ts
 * const columns = [
 *   { prop: 'name', name: 'Name', flash: true },
 *   {
 *     prop: 'price',
 *     name: 'Price',
 *     flash: (value, context) => ({
 *       flash: value !== context.previousValue,
 *       direction: Number(value) > Number(context.previousValue) ? 'up' : 'down',
 *     }),
 *   },
 * ];
 * ```
 */
export type CellFlashPredicate =
  | boolean
  | ((value: unknown, context: CellFlashContext) => boolean | CellFlashDecision);
```

---

### `CellFlashAriaConfig`

Accessibility announcement configuration for cell and row flashes.

**Example:**
```typescript
* ```ts
 * grid.cellFlash = {
 *   aria: {
 *     enabled: true,
 *     label: state => `Row ${state.rowIndex + 1} changed`,
 *   },
 * };
 * ```
```

```ts
interface CellFlashAriaConfig {
  /** Enables aria-live announcements for flash requests. */
    enabled?: boolean;
  /** Live-region politeness. Defaults to `polite`. */
    live?: 'off' | 'polite' | 'assertive';
  /** Controls the `aria-atomic` attribute on the live region. Defaults to true. */
    atomic?: boolean;
  /** CSS class applied to the generated live region. */
    liveRegionClassName?: string;
  /** Static label or callback that returns the announcement text. */
    label?: string | ((state: CellFlashState) => string)
}
```

---

### `CellFlashLabels`

User-facing labels used by the plugin.

These labels are used for default accessibility announcements. A decision or
manual target `ariaLabel` still has highest priority, followed by
`aria.label`, then these per-kind labels.

**Example:**
```typescript
* ```ts
 * grid.cellFlash = {
 *   aria: true,
 *   labels: {
 *     cellUpdated: state => `Updated ${String(state.prop)} on row ${state.rowIndex + 1}`,
 *     rowUpdated: state => `Updated row ${state.rowIndex + 1}`,
 *   },
 * };
 * ```
```

```ts
interface CellFlashLabels {
  /** Default announcement for cell flashes. */
    cellUpdated?: string | ((state: CellFlashState) => string);
  /** Default announcement for row flashes. */
    rowUpdated?: string | ((state: CellFlashState) => string)
}
```

---

### `CellFlashConfig`

Public plugin configuration accepted by `grid.cellFlash` and
`additionalData.cellFlash`.

Defaults preserve the original plugin behavior: flashing is enabled,
cell-only, lasts 1000ms, replaces active flashes on each event, and clears on
source reset.

**Example:**
```typescript
* ```ts
 * grid.plugins = [CellFlashPlugin, EventManagerPlugin];
 * grid.cellFlash = {
 *   duration: 1200,
 *   mode: 'cell-and-row',
 *   queue: 'merge',
 *   rowClassName: 'price-row-flash',
 *   aria: { enabled: true },
 *   labels: {
 *     cellUpdated: state => `Price cell changed on row ${state.rowIndex + 1}`,
 *     rowUpdated: state => `Market row ${state.rowIndex + 1} changed`,
 *   },
 *   directionResolver: ({ value, previousValue }) => {
 *     if (Number(value) > Number(previousValue)) return 'up';
 *     if (Number(value) < Number(previousValue)) return 'down';
 *     return 'changed';
 *   },
 * };
 * ```
```

```ts
interface CellFlashConfig {
  /** Enables or disables new flash requests. */
    enabled?: boolean;
  /** Default cell flash duration in milliseconds. */
    duration?: number;
  /** Default row flash duration in milliseconds. */
    rowDuration?: number;
  /** Default flash target mode. */
    mode?: CellFlashMode;
  /** Default active flash queue behavior. */
    queue?: CellFlashQueueMode;
  /** Maximum number of active cell and row flashes retained at once. */
    maxActive?: number;
  /** Clears active flash state when the grid source changes. */
    clearOnSourceChange?: boolean;
  /** Disables animation when the user prefers reduced motion. */
    respectReducedMotion?: boolean;
  /** Enables or configures aria-live announcements. */
    aria?: boolean | CellFlashAriaConfig;
  /** User-facing labels used by default plugin announcements. */
    labels?: CellFlashLabels;
  /** Base class applied to flashing cells. */
    className?: string;
  /** Base class applied to flashing rows. */
    rowClassName?: string;
  /** Optional custom direction resolver used before the default resolver. */
    directionResolver?: (context: CellFlashContext) => CellFlashDirection
}
```

---

### `ResolvedCellFlashConfig`

```ts
interface ResolvedCellFlashConfig {
  enabled: boolean;
  duration: number;
  rowDuration: number;
  mode: CellFlashMode;
  queue: CellFlashQueueMode;
  maxActive: number;
  clearOnSourceChange: boolean;
  respectReducedMotion: boolean;
  aria: Required<Pick<CellFlashAriaConfig, 'enabled' | 'live' | 'atomic' | 'liveRegionClassName'>>
      & Pick<CellFlashAriaConfig, 'label'>;
  labels: Required<CellFlashLabels>;
  className: string;
  rowClassName: string;
  directionResolver?: (context: CellFlashContext) => CellFlashDirection
}
```

---

### `CellFlashState`

```ts
interface CellFlashState {
  rowIndex: number;
  prop?: ColumnProp;
  type: DimensionRows;
  value?: unknown;
  previousValue?: unknown;
  direction: CellFlashDirection;
  className?: string;
  rowClassName?: string;
  ariaLabel?: string;
  startedAt: number;
  duration: number
}
```

---

### `CellFlashCellTarget`

Target accepted by `CellFlashPlugin.flashCell()`.

**Example:**
```typescript
* ```ts
 * const plugin = grid.getPlugins?.().find(p => p instanceof CellFlashPlugin);
 * plugin?.flashCell({
 *   rowIndex: 0,
 *   prop: 'price',
 *   previousValue: 42,
 *   value: 47,
 *   direction: 'up',
 * });
 * ```
```

```ts
interface CellFlashCellTarget {
  rowIndex: number;
  prop: ColumnProp;
  type?: DimensionRows;
  value?: unknown;
  previousValue?: unknown;
  duration?: number;
  direction?: CellFlashDirection;
  className?: string;
  ariaLabel?: string
}
```

---

### `CellFlashRowTarget`

Target accepted by `CellFlashPlugin.flashRows()`.

**Example:**
```typescript
* ```ts
 * const plugin = grid.getPlugins?.().find(p => p instanceof CellFlashPlugin);
 * plugin?.flashRows([
 *   { rowIndex: 2, direction: 'changed', rowClassName: 'row-flash-warning' },
 *   { rowIndex: 5, direction: 'down' },
 * ]);
 * ```
```

```ts
interface CellFlashRowTarget {
  rowIndex: number;
  type?: DimensionRows;
  duration?: number;
  direction?: CellFlashDirection;
  rowClassName?: string;
  ariaLabel?: string
}
```

---

### `CellFlashApplyOptions`

Per-call options for manual and event-driven flash batches.

**Example:**
```typescript
* ```ts
 * plugin.flashCells(
 *   { type: 'rgRow', data: { 0: { price: 12 } }, previousData: { 0: { price: 10 } } },
 *   { queue: 'merge', mode: 'cell-and-row', duration: 800 },
 * );
 * ```
```

```ts
interface CellFlashApplyOptions {
  queue?: CellFlashQueueMode;
  mode?: CellFlashMode;
  duration?: number;
  rowDuration?: number
}
```

---

### `CellFlashTemplatePropExtension`

```ts
interface CellFlashTemplatePropExtension {
  previousValue?: any;
  flashDirection?: CellFlashDirection;
  flashState?: any
}
```

---

### `CellFlashArrowTemplateOptions`

Options for `cellFlashArrowTemplate()`.

Defaults preserve the original helper output: wrapper class `cell-flash`,
arrow class `cell-flash-arrow`, `up`/`down`/`changed` direction classes,
and `↑` / `↓` symbols.

**Example:**
```typescript
* ```ts
 * cellTemplate: cellFlashArrowTemplate({
 *   symbols: { up: '+', down: '-', changed: '~' },
 *   className: 'market-flash',
 *   arrowClassName: 'market-flash-icon',
 *   directionClassNames: { up: 'positive', down: 'negative' },
 * })
 * ```
```

```ts
interface CellFlashArrowTemplateOptions {
  /** Direction symbols rendered before the cell content. */
    symbols?: Partial<Record<CellFlashDirection, string>>;
  /** Wrapper class applied around the arrow and cell content. */
    className?: string;
  /** Class applied to the symbol element. */
    arrowClassName?: string;
  /** Direction-specific wrapper classes. */
    directionClassNames?: Partial<Record<CellFlashDirection, string>>
}
```

---

### `CellFlashTemplateParams` (Extended from `index.ts`)

```ts
export type CellFlashTemplateParams = CellTemplateProp & CellFlashTemplatePropExtension;
```
