LCOV - code coverage report
Current view: top level - dashql-app/src/views/query_result - data_table_focus.ts Coverage Total Hit
Test: DashQL 915828b Lines: 100.0 % 52 52
Test Date: 2026-11-06 19:30:32

            Line data    Source code
       1              : import * as React from 'react';
       2              : 
       3              : /// The focus of a single cell
       4            1 : export enum CellFocus {
       5            1 :     None = 0,
       6              :     /// Another cell in the same row is hovered
       7            1 :     Secondary = 1,
       8              :     /// The cell itself is hovered
       9            1 :     Primary = 2,
      10            1 : }
      11              : 
      12              : /// The hovered cell of a data table, kept outside of React state.
      13              : /// Cells subscribe by their data row so that moving the pointer only re-renders the previous and the next row.
      14            1 : export class DataTableFocusStore {
      15            1 :     protected focusedRow: number | null = null;
      16            1 :     protected focusedField: number | null = null;
      17            1 :     protected listenersByRow = new Map<number, Set<() => void>>();
      18              : 
      19            1 :     public setFocus(row: number | null, field: number | null) {
      20            1 :         if (row === this.focusedRow && field === this.focusedField) {
      21            1 :             return;
      22              :         }
      23            1 :         const prevRow = this.focusedRow;
      24            1 :         this.focusedRow = row;
      25            1 :         this.focusedField = field;
      26            1 :         if (prevRow != null) {
      27            1 :             this.notify(prevRow);
      28              :         }
      29            1 :         if (row != null && row !== prevRow) {
      30            1 :             this.notify(row);
      31              :         }
      32            1 :     }
      33              : 
      34            1 :     public getFocus(row: number, field: number): CellFocus {
      35            1 :         if (row !== this.focusedRow) {
      36            1 :             return CellFocus.None;
      37              :         }
      38            1 :         return field === this.focusedField ? CellFocus.Primary : CellFocus.Secondary;
      39            1 :     }
      40              : 
      41            1 :     public subscribe(row: number, listener: () => void): () => void {
      42            1 :         let listeners = this.listenersByRow.get(row);
      43            1 :         if (listeners == null) {
      44            1 :             listeners = new Set();
      45            1 :             this.listenersByRow.set(row, listeners);
      46            1 :         }
      47            1 :         listeners.add(listener);
      48            1 :         return () => {
      49            1 :             const current = this.listenersByRow.get(row);
      50            1 :             if (current == null) return;
      51            1 :             current.delete(listener);
      52            1 :             if (current.size == 0) {
      53            1 :                 this.listenersByRow.delete(row);
      54              :             }
      55            1 :         };
      56            1 :     }
      57              : 
      58            1 :     protected notify(row: number) {
      59            1 :         const listeners = this.listenersByRow.get(row);
      60            1 :         if (listeners == null) return;
      61            1 :         for (const listener of [...listeners]) {
      62            1 :             listener();
      63              :         }
      64            1 :     }
      65            1 : }
      66              : 
      67              : /// Subscribe to the focus of a single cell
      68            1 : export function useCellFocus(store: DataTableFocusStore, row: number, field: number): CellFocus {
      69            1 :     const subscribe = React.useCallback((listener: () => void) => store.subscribe(row, listener), [store, row]);
      70            1 :     const getSnapshot = React.useCallback(() => store.getFocus(row, field), [store, row, field]);
      71            1 :     return React.useSyncExternalStore(subscribe, getSnapshot);
      72            1 : }
        

Generated by: LCOV version 2.0-1