go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/milo/ui/src/generic_libs/components/drag_tracker.ts (about)

     1  // Copyright 2021 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  import { html, LitElement } from 'lit';
    16  import { customElement } from 'lit/decorators.js';
    17  
    18  export interface DragEventDetails {
    19    // relative to the start.
    20    dx: number;
    21    dy: number;
    22  }
    23  
    24  export type DragEvent = CustomEvent<DragEventDetails>;
    25  
    26  /**
    27   * A element that tracks the dragging event.
    28   * Comparing to the native HTML drag event, this has higher resolution, and
    29   * fires dragend event consistently when dragging stopped.
    30   */
    31  @customElement('milo-drag-tracker')
    32  export class DragTrackerElement extends LitElement {
    33    constructor() {
    34      super();
    35  
    36      this.addEventListener('mousedown', (startEvent: MouseEvent) => {
    37        const x = startEvent.pageX;
    38        const y = startEvent.pageY;
    39  
    40        const dispatchEvent = (e: MouseEvent, type: string) => {
    41          const dx = e.pageX - x;
    42          const dy = e.pageY - y;
    43          this.dispatchEvent(
    44            new CustomEvent<DragEventDetails>(type, { detail: { dx, dy } }),
    45          );
    46        };
    47  
    48        const onMouseMove = (dragEvent: MouseEvent) => {
    49          dragEvent.preventDefault();
    50          dispatchEvent(dragEvent, 'drag');
    51        };
    52        document.addEventListener('mousemove', onMouseMove);
    53  
    54        document.addEventListener(
    55          'mouseup',
    56          (endEvent: MouseEvent) => {
    57            dispatchEvent(endEvent, 'dragend');
    58            document.removeEventListener('mousemove', onMouseMove);
    59          },
    60          { once: true },
    61        );
    62  
    63        dispatchEvent(startEvent, 'dragstart');
    64      });
    65    }
    66  
    67    protected render() {
    68      return html``;
    69    }
    70  }