Skip to content

mouse()

Track mouse position and button states.

Import

tsx
import { mouse } from 'flexium/interactive'

Signature

ts
function mouse(options?: { target?: HTMLElement }): MouseState

interface MouseState {
  position: Accessor<{ x: number, y: number }>
  delta: Accessor<{ x: number, y: number }>
  wheelDelta: Accessor<number>
  isPressed: (button: number) => boolean
  isLeftPressed: () => boolean
  isRightPressed: () => boolean
  isMiddlePressed: () => boolean
  clearFrameState: () => void
  dispose: () => void
}

Returns

PropertyTypeDescription
positionAccessor<{ x, y }>Current mouse position
deltaAccessor<{ x, y }>Movement since last frame
wheelDeltaAccessor<number>Scroll wheel delta
isPressed(button) => booleanCheck if button is held
isLeftPressed() => booleanCheck if left button is held
isRightPressed() => booleanCheck if right button is held
isMiddlePressed() => booleanCheck if middle button is held
clearFrameState() => voidReset per-frame state
dispose() => voidClean up event listeners

Mouse Buttons

ValueButton
0Left button
1Middle button
2Right button

Usage

Basic Usage

tsx
function Game() {
  const m = mouse()

  return (
    <div>
      Position: {m.position.x}, {m.position.y}
    </div>
  )
}

Canvas Drawing

tsx
function DrawingApp() {
  const canvasRef = ref(null)
  const m = mouse()
  const [isDrawing, setIsDrawing] = state(false)

  effect(() => {
    if (m.isLeftPressed()) {
      const ctx = canvasRef.current.getContext('2d')
      ctx.lineTo(m.position.x, m.position.y)
      ctx.stroke()
    }
  })

  return <canvas ref={canvasRef} />
}

Click Detection

tsx
const m = mouse()

const loop = createLoop({
  onUpdate: () => {
    if (m.isLeftPressed()) {
      handleClick(m.position.x, m.position.y)
    }
  }
})

Cursor Following

tsx
function Cursor() {
  const m = mouse()

  return (
    <div
      class="custom-cursor"
      style={{
        transform: `translate(${m.position.x}px, ${m.position.y}px)`
      }}
    />
  )
}

Canvas-Relative Position

tsx
function CanvasGame() {
  let canvasRef

  const m = mouse()

  const getCanvasPosition = () => {
    if (!canvasRef) return { x: 0, y: 0 }
    const rect = canvasRef.getBoundingClientRect()
    return {
      x: m.position.x - rect.left,
      y: m.position.y - rect.top
    }
  }

  return (
    <canvas
      ref={canvasRef}
      onmousemove={() => {
        const pos = getCanvasPosition()
        updateCursor(pos.x, pos.y)
      }}
    />
  )
}

Drag and Drop

tsx
function Draggable(props) {
  const m = mouse()
  const [isDragging, setIsDragging] = state(false)
  const [offset, setOffset] = state({ x: 0, y: 0 })

  effect(() => {
    if (!m.isLeftPressed()) {
      setIsDragging(false)
    }
  })

  const handleMouseDown = (e) => {
    setIsDragging(true)
    setOffset({
      x: e.clientX - props.x,
      y: e.clientY - props.y
    })
  }

  return (
    <div
      style={{
        position: 'absolute',
        left: isDragging ? m.position.x - offset.x : props.x,
        top: isDragging ? m.position.y - offset.y : props.y
      }}
      onmousedown={handleMouseDown}
    >
      {props.children}
    </div>
  )
}

Right-Click Context Menu

tsx
function ContextMenuArea() {
  const m = mouse()
  const [menuPos, setMenuPos] = state(null)

  effect(() => {
    if (m.isRightPressed()) {
      setMenuPos({ x: m.position.x, y: m.position.y })
    }
    if (m.isLeftPressed() && menuPos()) {
      setMenuPos(null)
    }
  })

  return (
    <div oncontextmenu={(e) => e.preventDefault()}>
      {menuPos && <ContextMenu x={menuPos.x} y={menuPos.y} />}
    </div>
  )
}

Behavior

  • Tracks global mouse position by default
  • Can track relative to element with target
  • Updates on every mouse move
  • Button states reset each frame

Notes

  • Use with createLoop for interactive input
  • Position is relative to viewport by default
  • Prevent default context menu for right-click handling

Demo

See Also

Released under the MIT License.