Repository: sst/opentui
File: packages/core/src/renderer.ts (TypeScript)

Code before:

        if (maybeRenderable) {
          const event = new MouseEvent(maybeRenderable, mouseEvent)
          maybeRenderable.processMouseEvent(event)
        }
        return true
      }

      const maybeRenderableId = this.hitTest(mouseEvent.x, mouseEvent.y)
      const sameElement = maybeRenderableId === this.lastOverRenderableNum
      this.lastOverRenderableNum = maybeRenderableId
      const maybeRenderable = Renderable.renderablesByNumber.get(maybeRenderableId)

      // Auto-focus on click (browser-like behavior)
      // Bubble up to find closest focusable ancestor
      if (mouseEvent.type === "down" && mouseEvent.button === MouseButton.LEFT) {
        let current: Renderable | null = maybeRenderable ?? null
        while (current) {
          if (current.focusable) {
            current.focus()
            break
          }
          current = current.parent
        }
      }

      if (
        mouseEvent.type === "down" &&
        mouseEvent.button === MouseButton.LEFT &&
        !this.currentSelection?.isSelecting &&
        !mouseEvent.modifiers.ctrl
      ) {
        if (
          maybeRenderable &&
          maybeRenderable.selectable &&
          !maybeRenderable.isDestroyed &&
          maybeRenderable.shouldStartSelection(mouseEvent.x, mouseEvent.y)
        ) {
          this.startSelection(maybeRenderable, mouseEvent.x, mouseEvent.y)
          const event = new MouseEvent(maybeRenderable, mouseEvent)
          maybeRenderable.processMouseEvent(event)
          return true
        }
      }

      if (mouseEvent.type === "drag" && this.currentSelection?.isSelecting) {
        this.updateSelection(maybeRenderable, mouseEvent.x, mouseEvent.y)

        if (maybeRenderable) {
          const event = new MouseEvent(maybeRenderable, { ...mouseEvent, isSelecting: true })
          maybeRenderable.processMouseEvent(event)

Review comment (suggestion):
This is a default behaviour that should be cancelable with `preventDefault` so I think this logic should happen after the event is triggered and potentially handled, then a renderable event handler or even a global event handler could use `event.preventDefault` and this logic can check `event.defaultPrevented`.

Code after:
      this._latestPointer.y = mouseEvent.y
      this._hasPointer = true
      this._lastPointerModifiers = mouseEvent.modifiers

      if (this._console.visible) {
        const consoleBounds = this._console.bounds
        if (
          mouseEvent.x >= consoleBounds.x &&
          mouseEvent.x < consoleBounds.x + consoleBounds.width &&
          mouseEvent.y >= consoleBounds.y &&
          mouseEvent.y < consoleBounds.y + consoleBounds.height
        ) {
          const event = new MouseEvent(null, mouseEvent)
          const handled = this._console.handleMouse(event)
          if (handled) return true
        }
      }

      if (mouseEvent.type === "scroll") {
        const maybeRenderableId = this.hitTest(mouseEvent.x, mouseEvent.y)
        const maybeRenderable = Renderable.renderablesByNumber.get(maybeRenderableId)

        if (maybeRenderable) {
          const event = new MouseEvent(maybeRenderable, mouseEvent)
          maybeRenderable.processMouseEvent(event)
        }
        return true
      }

      const maybeRenderableId = this.hitTest(mouseEvent.x, mouseEvent.y)
      const sameElement = maybeRenderableId === this.lastOverRenderableNum
      this.lastOverRenderableNum = maybeRenderableId
      const maybeRenderable = Renderable.renderablesByNumber.get(maybeRenderableId)

      if (
        mouseEvent.type === "down" &&
        mouseEvent.button === MouseButton.LEFT &&
        !this.currentSelection?.isDragging &&
        !mouseEvent.modifiers.ctrl
      ) {
        if (
          maybeRenderable &&
          maybeRenderable.selectable &&
          !maybeRenderable.isDestroyed &&
          maybeRenderable.shouldStartSelection(mouseEvent.x, mouseEvent.y)
        ) {
          this.startSelection(maybeRenderable, mouseEvent.x, mouseEvent.y)
          this.dispatchMouseEvent(maybeRenderable, mouseEvent)
          return true
        }
      }