{"version":3,"file":"virtualRow.mjs","names":[],"sources":["../../../../package/common/virtualList/virtualRow.tsx"],"sourcesContent":["import React, { useRef, useLayoutEffect } from 'react';\nimport cx from 'classnames';\n\nimport styles from './virtualList.module.pcss';\nimport { ROW_FOCUSABLE_SELECTOR, ROW_PARKED_ATTRIBUTE } from './virtualList.utils';\nimport type { TreeDropPosition } from './virtualList.types';\n\nexport interface VirtualRowProps {\n  index: number;\n  /** Referenced by the list's `aria-activedescendant` while this row is active. */\n  id?: string;\n  top: number;\n  /** Padding applied to the row (already normalised to a CSS string). */\n  padding?: string;\n  columnTemplate: string | undefined;\n  isSelected: boolean;\n  /** The row the arrow keys are on. Distinct from selection. */\n  isActive?: boolean;\n  /**\n   * Hold this row's own controls out of the tab order unless it is the row being\n   * used. Off when the list leaves the keyboard to its rows.\n   */\n  manageTabStops?: boolean;\n  /** This is the row being used, so its controls are reachable with Tab. */\n  isEntered?: boolean;\n  activeClassName?: string;\n  activeStyle?: React.CSSProperties;\n  showDivider: boolean;\n  hover: boolean;\n  onClick: () => void;\n  observer: ResizeObserver | null;\n  ariaRowIndex?: number;\n  ariaPosInSet?: number;\n  ariaSetSize?: number;\n  rowRole: string;\n  reorderable?: boolean;\n  /**\n   * Native mouse DnD is active for the list. Distinct from `draggable`, which in\n   * `dragHandle` mode is only set on the row the pointer has armed.\n   */\n  mouseDragEnabled?: boolean;\n  draggable?: boolean;\n  isDragging?: boolean;\n  reserveToggleGutter?: boolean;\n  onMouseDown?: (e: React.MouseEvent<HTMLDivElement>) => void;\n  onMouseOver?: (e: React.MouseEvent<HTMLDivElement>) => void;\n  onMouseLeave?: (e: React.MouseEvent<HTMLDivElement>) => void;\n  onDragStart?: (e: React.DragEvent<HTMLDivElement>) => void;\n  onDragOver?: (e: React.DragEvent<HTMLDivElement>) => void;\n  onDragEnd?: () => void;\n  onDrop?: (e: React.DragEvent<HTMLDivElement>) => void;\n  onTouchStart?: (e: React.TouchEvent<HTMLDivElement>) => void;\n  dropPosition?: TreeDropPosition;\n  dropIndentPx?: number;\n  dropIndicatorClassName?: string;\n  dropIndicatorStyle?: React.CSSProperties;\n  rowClassName?: string;\n  rowStyle?: React.CSSProperties;\n  children: React.ReactNode;\n}\n\n/**\n * A single virtualized row: absolutely positioned at its `top`, optionally a\n * grid (table mode), registering itself with the shared ResizeObserver and\n * carrying all the drag / drop-indicator wiring the parent assigns it.\n */\nfunction VirtualRow({\n  index,\n  id,\n  top,\n  padding,\n  columnTemplate,\n  isSelected,\n  isActive,\n  manageTabStops,\n  isEntered,\n  activeClassName,\n  activeStyle,\n  showDivider,\n  hover,\n  onClick,\n  observer,\n  ariaRowIndex,\n  ariaPosInSet,\n  ariaSetSize,\n  rowRole,\n  reorderable,\n  mouseDragEnabled,\n  draggable,\n  isDragging,\n  reserveToggleGutter,\n  onMouseDown,\n  onMouseOver,\n  onMouseLeave,\n  onDragStart,\n  onDragOver,\n  onDragEnd,\n  onDrop,\n  onTouchStart,\n  dropPosition,\n  dropIndentPx,\n  dropIndicatorClassName,\n  dropIndicatorStyle,\n  rowClassName,\n  rowStyle,\n  children,\n}: VirtualRowProps) {\n  const ref = useRef<HTMLDivElement>(null);\n\n  // A single observer is shared across all rows (created by the parent); each\n  // row just registers/unregisters its element. The parent reads the row index\n  // back from the `data-index` attribute when the observer fires.\n  useLayoutEffect(() => {\n    const el = ref.current;\n    if (!el || !observer) return;\n    observer.observe(el);\n    return () => observer.unobserve(el);\n  }, [observer]);\n\n  // One row at a time carries tab stops. Without this every control in every\n  // rendered row is one, the set changes as the list scrolls, and tabbing\n  // through a windowed list leaves it at an arbitrary point: the next row does\n  // not exist in the DOM yet when the browser looks for the next stop.\n  //\n  // Runs on every commit of the row rather than on a dependency list, because\n  // the cells are the consumer's and can change without anything here changing.\n  // The selector only matches what is in the tab order to begin with, and an\n  // attribute write invalidates no layout, so a scroll frame pays a query per\n  // row and nothing else.\n  useLayoutEffect(() => {\n    const el = ref.current;\n    if (!el || !manageTabStops || isEntered) return;\n    const restore: [HTMLElement, string | null][] = [];\n    el.querySelectorAll<HTMLElement>(ROW_FOCUSABLE_SELECTOR).forEach((node) => {\n      restore.push([node, node.getAttribute('tabindex')]);\n      node.setAttribute('tabindex', '-1');\n      node.setAttribute(ROW_PARKED_ATTRIBUTE, '');\n    });\n    return () => {\n      for (const [node, previous] of restore) {\n        if (previous === null) node.removeAttribute('tabindex');\n        else node.setAttribute('tabindex', previous);\n        node.removeAttribute(ROW_PARKED_ATTRIBUTE);\n      }\n    };\n  });\n\n  return (\n    <div\n      ref={ref}\n      id={id}\n      data-index={index}\n      className={cx(\n        styles.virtualListRow,\n        isSelected && styles.virtualListRowSelected,\n        isActive && styles.virtualListRowActive,\n        isActive && activeClassName,\n        !showDivider && styles.virtualListRowNoDivider,\n        !hover && styles.virtualListRowNoHover,\n        reorderable && styles.virtualListRowDraggable,\n        isDragging && styles.virtualListRowDragging,\n        dropPosition === 'inside' && styles.virtualListRowDropInside,\n        rowClassName,\n      )}\n      style={{\n        position: 'absolute',\n        top: 0,\n        left: 0,\n        right: 0,\n        transform: `translateY(${top}px)`,\n        ...(padding != null ? { padding } : {}),\n        ...(columnTemplate ? { display: 'grid', gridTemplateColumns: columnTemplate } : {}),\n        // Match the header's reserved gutter for the column-toggle cog so row\n        // cells line up with their header cells instead of drifting under it.\n        // Applied after `padding` so the alignment gutter always wins on the right.\n        ...(reserveToggleGutter ? { paddingRight: 32 } : {}),\n        ...rowStyle,\n        ...(isActive ? activeStyle : undefined),\n      }}\n      onClick={onClick}\n      draggable={draggable}\n      onMouseDown={onMouseDown}\n      onMouseOver={onMouseOver}\n      onMouseLeave={onMouseLeave}\n      onDragStart={onDragStart}\n      onDragOver={onDragOver}\n      onDragEnd={onDragEnd}\n      onDrop={onDrop ?? (mouseDragEnabled ? (e) => e.preventDefault() : undefined)}\n      onTouchStart={onTouchStart}\n      onContextMenu={mouseDragEnabled ? (e) => e.preventDefault() : undefined}\n      aria-selected={isSelected}\n      aria-rowindex={ariaRowIndex}\n      aria-posinset={ariaPosInSet}\n      aria-setsize={ariaSetSize}\n      role={rowRole}\n    >\n      {(dropPosition === 'before' || dropPosition === 'after') && (\n        <div\n          data-drop-line={dropPosition}\n          aria-hidden\n          className={cx(\n            styles.virtualListDropLine,\n            dropPosition === 'before' ? styles.virtualListDropLineBefore : styles.virtualListDropLineAfter,\n            dropIndicatorClassName,\n          )}\n          style={{ left: dropIndentPx ?? 0, ...dropIndicatorStyle }}\n        />\n      )}\n      {children}\n    </div>\n  );\n}\n\nexport default VirtualRow;\n"],"mappings":"gRAkEA,SAAS,EAAW,CAClB,QACA,KACA,MACA,UACA,iBACA,aACA,WACA,iBACA,YACA,kBACA,cACA,cACA,QACA,UACA,WACA,eACA,eACA,cACA,UACA,cACA,mBACA,YACA,aACA,sBACA,cACA,cACA,eACA,cACA,aACA,YACA,SACA,eACA,eACA,eACA,yBACA,qBACA,eACA,WACA,YACkB,CAClB,IAAM,EAAM,EAAuB,IAAI,EAwCvC,OAnCA,MAAsB,CACpB,IAAM,EAAK,EAAI,QACX,GAAC,GAAO,EAEZ,OADA,EAAS,QAAQ,CAAE,MACN,EAAS,UAAU,CAAE,CACpC,EAAG,CAAC,CAAQ,CAAC,EAYb,MAAsB,CACpB,IAAM,EAAK,EAAI,QACf,GAAI,CAAC,GAAM,CAAC,GAAkB,EAAW,OACzC,IAAM,EAA0C,CAAC,EAMjD,OALA,EAAG,iBAA8B,CAAsB,CAAC,CAAC,QAAS,GAAS,CACzE,EAAQ,KAAK,CAAC,EAAM,EAAK,aAAa,UAAU,CAAC,CAAC,EAClD,EAAK,aAAa,WAAY,IAAI,EAClC,EAAK,aAAa,EAAsB,EAAE,CAC5C,CAAC,MACY,CACX,IAAK,GAAM,CAAC,EAAM,KAAa,EACzB,IAAa,KAAM,EAAK,gBAAgB,UAAU,EACjD,EAAK,aAAa,WAAY,CAAQ,EAC3C,EAAK,gBAAgB,CAAoB,CAE7C,CACF,CAAC,EAGC,EAAC,MAAD,CACO,MACD,KACJ,aAAY,EACZ,UAAW,EACT,EAAO,eACP,GAAc,EAAO,uBACrB,GAAY,EAAO,qBACnB,GAAY,EACZ,CAAC,GAAe,EAAO,wBACvB,CAAC,GAAS,EAAO,sBACjB,GAAe,EAAO,wBACtB,GAAc,EAAO,uBACrB,IAAiB,UAAY,EAAO,yBACpC,CACF,EACA,MAAO,CACL,SAAU,WACV,IAAK,EACL,KAAM,EACN,MAAO,EACP,UAAW,cAAc,EAAI,KAC7B,GAAI,GAAW,KAAqB,CAAC,EAAf,CAAE,SAAQ,EAChC,GAAI,EAAiB,CAAE,QAAS,OAAQ,oBAAqB,CAAe,EAAI,CAAC,EAIjF,GAAI,EAAsB,CAAE,aAAc,EAAG,EAAI,CAAC,EAClD,GAAG,EACH,GAAI,EAAW,EAAc,IAAA,EAC/B,EACS,UACE,YACE,cACA,cACC,eACD,cACD,aACD,YACX,OAAQ,IAAW,EAAoB,GAAM,EAAE,eAAe,EAAI,IAAA,IACpD,eACd,cAAe,EAAoB,GAAM,EAAE,eAAe,EAAI,IAAA,GAC9D,gBAAe,EACf,gBAAe,EACf,gBAAe,EACf,eAAc,EACd,KAAM,EA9CR,SAAA,EAgDI,IAAiB,UAAY,IAAiB,UAC9C,EAAC,MAAD,CACE,iBAAgB,EAChB,cAAA,GACA,UAAW,EACT,EAAO,oBACP,IAAiB,SAAW,EAAO,0BAA4B,EAAO,yBACtE,CACF,EACA,MAAO,CAAE,KAAM,GAAgB,EAAG,GAAG,CAAmB,CACzD,CAAA,EAEF,CACE,GAET"}