All files / client/src/hmr indicator.js

100% Statements 22/22
100% Branches 10/10
100% Functions 4/4
100% Lines 21/21

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105                        3x                   3x                   3x                 28x               22x   21x 21x 21x                       21x   21x 21x                   13x 12x     13x 13x   13x 13x             28x 20x   28x             3x  
/**
 * HMR Connection Status Indicator
 *
 * Displays a small colored dot in the bottom-right corner indicating
 * WebSocket connection status. Unobtrusive design per CONTEXT.md decision.
 *
 * @module @coherent.js/client/hmr/indicator
 */
 
/**
 * Status color mapping for connection states.
 */
const STATUS_COLORS = {
  connected: '#10b981',    // Green
  disconnected: '#ef4444', // Red
  reconnecting: '#f59e0b', // Yellow/amber
  error: '#ef4444'         // Red
};
 
/**
 * Status title mapping for accessibility.
 */
const STATUS_TITLES = {
  connected: 'HMR: Connected',
  disconnected: 'HMR: Disconnected',
  reconnecting: 'HMR: Reconnecting...',
  error: 'HMR: Error'
};
 
/**
 * Default/initial color before status is set.
 */
const DEFAULT_COLOR = '#666';
 
/**
 * Connection status indicator class.
 * Shows an 8px colored dot in the bottom-right corner of the viewport.
 */
export class ConnectionIndicator {
  constructor() {
    /** @type {HTMLElement | null} */
    this.indicator = null;
  }
 
  /**
   * Create the indicator element if it doesn't exist.
   * Uses inline styles to avoid external CSS dependencies.
   */
  create() {
    if (this.indicator) return;
 
    const el = document.createElement('div');
    el.id = 'coherent-hmr-indicator';
    el.style.cssText = `
      position: fixed;
      bottom: 8px;
      right: 8px;
      width: 8px;
      height: 8px;
      border-radius: 50%;
      background: ${DEFAULT_COLOR};
      z-index: 99998;
      pointer-events: none;
      transition: background 0.3s ease;
    `;
    el.title = 'HMR: Initializing';
 
    document.body.appendChild(el);
    this.indicator = el;
  }
 
  /**
   * Update the indicator status.
   * Creates the element if it doesn't exist (lazy initialization).
   *
   * @param {string} status - Status string: 'connected', 'disconnected', 'reconnecting', or 'error'
   */
  update(status) {
    if (!this.indicator) {
      this.create();
    }
 
    const color = STATUS_COLORS[status] || STATUS_COLORS.disconnected;
    const title = STATUS_TITLES[status] || 'HMR: Unknown';
 
    this.indicator.style.background = color;
    this.indicator.title = title;
  }
 
  /**
   * Remove the indicator from the DOM.
   */
  destroy() {
    if (this.indicator?.parentNode) {
      this.indicator.parentNode.removeChild(this.indicator);
    }
    this.indicator = null;
  }
}
 
/**
 * Singleton instance of ConnectionIndicator.
 */
export const connectionIndicator = new ConnectionIndicator();