New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details
Socket
Book a DemoSign in
Socket

react-matrix-canvas

Package Overview
Dependencies
Maintainers
1
Versions
1
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

react-matrix-canvas

A React component library for creating interactive matrix/grid canvases with draggable markers

latest
Source
npmnpm
Version
0.1.0
Version published
Weekly downloads
2
-88.89%
Maintainers
1
Weekly downloads
 
Created
Source

react-matrix-canvas

A React component library for creating interactive matrix/grid canvases with draggable markers. Perfect for building Eisenhower matrices, BCG matrices, risk matrices, and other quadrant-based UIs.

Features

  • 🎯 Flexible Grid System - Support for 2x2, 3x3, or custom grid configurations
  • 🖱️ Drag & Drop - Smooth dragging with area detection
  • 📱 Touch Support - Full touch device support for mobile
  • 💬 Tooltips - Built-in tooltip support with customizable content
  • ⌨️ Keyboard Navigation - Full keyboard accessibility
  • 🎨 Customizable - Minimal styling, easy to customize
  • 📦 Zero Dependencies - Only React as peer dependency
  • 🔷 TypeScript - Full type definitions included

Installation

npm install react-matrix-canvas

Quick Start

import { MatrixCanvas, Marker, type AreaConfig } from 'react-matrix-canvas';

const areas: AreaConfig[] = [
  { id: 'urgent-important', label: 'Do First', backgroundColor: '#fee2e2', position: { row: 0, col: 0 } },
  { id: 'not-urgent-important', label: 'Schedule', backgroundColor: '#dbeafe', position: { row: 0, col: 1 } },
  { id: 'urgent-not-important', label: 'Delegate', backgroundColor: '#fef3c7', position: { row: 1, col: 0 } },
  { id: 'not-urgent-not-important', label: 'Eliminate', backgroundColor: '#f3e8ff', position: { row: 1, col: 1 } },
];

function App() {
  const [items, setItems] = useState([
    { id: '1', title: 'Task 1', areaId: 'urgent-important', position: { x: 25, y: 25 } },
  ]);

  return (
    <MatrixCanvas
      areas={areas}
      grid={{ rows: 2, cols: 2 }}
      onCanvasClick={(position, areaId) => {
        // Add new item at clicked position
      }}
      style={{ height: '500px' }}
    >
      {items.map(item => (
        <Marker
          key={item.id}
          id={item.id}
          position={item.position}
          areaId={item.areaId}
          onPositionChange={(newPos) => {
            setItems(prev => prev.map(i =>
              i.id === item.id ? { ...i, position: newPos } : i
            ));
          }}
          onAreaChange={(newArea) => {
            setItems(prev => prev.map(i =>
              i.id === item.id ? { ...i, areaId: newArea } : i
            ));
          }}
          tooltip={<div>{item.title}</div>}
        />
      ))}
    </MatrixCanvas>
  );
}

API Reference

MatrixCanvas

Main container component.

PropTypeDescription
areasAreaConfig[]Area configurations (optional for free canvas)
grid{ rows: number; cols: number }Grid dimensions (auto-calculated from areas if omitted)
onCanvasClick(position, areaId) => voidCallback when clicking empty canvas area
dragEndClickDelaynumberDelay (ms) to ignore clicks after drag ends
renderArea(area) => ReactNodeCustom area renderer
classNamestringCustom class name
styleCSSPropertiesCustom styles

Marker

Draggable marker component.

PropTypeDescription
idstringUnique identifier
position{ x: number; y: number }Position in percentage (0-100)
areaIdstringCurrent area ID
dataTCustom data passed to renderTooltip
onPositionChange(position) => voidCallback when position changes
onAreaChange(newArea, oldArea) => voidCallback when area changes
onDragEnd() => voidCallback when drag ends
onClick() => voidCallback when clicked
tooltipReactNode | (data) => ReactNodeTooltip content
renderTooltip(props) => ReactNodeCustom tooltip renderer
sizenumberMarker size in pixels (default: 20)
colorstringMarker color (default: #3b82f6)
hoverScalenumberScale on hover (e.g., 1.25)
hoverClassNamestringClass name applied on hover
hoverStyleCSSPropertiesStyle applied on hover
disabledbooleanDisable dragging
classNamestringCustom class name
styleCSSPropertiesCustom styles

AreaConfig

interface AreaConfig {
  id: string;
  label?: string;
  backgroundColor?: string;
  labelColor?: string;
  position: { row: number; col: number };
}

Examples

Custom Tooltip with renderTooltip

renderTooltipを使うと、ライブラリが提供する位置情報とマウスイベントを使って、独自のツールチップUIを実装できます。

// ライブラリが提供するprops:
// - data: Markerに渡したカスタムデータ
// - position: ツールチップの表示位置 { top, left }
// - onMouseEnter/onMouseLeave: ホバー状態管理用

<Marker
  id="task-1"
  position={{ x: 50, y: 50 }}
  areaId="design"
  data={{ title: 'Task 1', status: 'active' }}
  renderTooltip={({ data, position, onMouseEnter, onMouseLeave }) => (
    <MyCustomTooltip
      title={data.title}
      status={data.status}
      style={{ top: position.top, left: position.left }}
      onMouseEnter={onMouseEnter}
      onMouseLeave={onMouseLeave}
    />
  )}
/>

Real-World Example: Hobbit Matrix

実際のアプリケーションでの使用例(アイゼンハワーマトリクス風のタスク管理):

import { MatrixCanvas, Marker, type AreaConfig } from 'react-matrix-canvas';
import { createPortal } from 'react-dom';

// エリア設定
const AREA_CONFIGS: AreaConfig[] = [
  { id: 'design', label: 'Design', backgroundColor: '#dbeafe', position: { row: 0, col: 0 } },
  { id: 'action', label: 'Action', backgroundColor: '#dcfce7', position: { row: 0, col: 1 } },
  { id: 'hold', label: 'Hold', backgroundColor: '#fef3c7', position: { row: 1, col: 0 } },
  { id: 'leave', label: 'Leave', backgroundColor: '#fee2e2', position: { row: 1, col: 1 } },
];

// カスタムツールチップ(Portalで表示)
function TaskTooltip({ task, position, onMouseEnter, onMouseLeave, onEdit, onDelete }) {
  return createPortal(
    <div
      className="fixed z-50 rounded-lg bg-white p-3 shadow-xl"
      style={{ top: position.top - 8, left: position.left, transform: 'translate(-50%, -100%)' }}
      onMouseEnter={onMouseEnter}
      onMouseLeave={onMouseLeave}
    >
      <h4>{task.title}</h4>
      <div className="mt-2 flex gap-2">
        <button onClick={onEdit}>編集</button>
        <button onClick={onDelete}>削除</button>
      </div>
    </div>,
    document.body
  );
}

function TaskMatrix({ tasks, onUpdateTask, onDeleteTask }) {
  // カスタムエリアレンダリング
  const renderArea = useCallback((area: AreaConfig) => (
    <div
      className="relative p-4"
      style={{ backgroundColor: area.backgroundColor }}
    >
      <span className="rounded-full bg-white px-3 py-1 shadow">
        {area.label}
      </span>
    </div>
  ), []);

  return (
    <MatrixCanvas
      areas={AREA_CONFIGS}
      grid={{ rows: 2, cols: 2 }}
      onCanvasClick={(position, areaId) => {
        // クリック位置とエリアIDを使って新規タスク作成
        console.log('Clicked at', position, 'in area', areaId);
      }}
      dragEndClickDelay={150}
      renderArea={renderArea}
      className="h-[600px] w-full"
    >
      {tasks.map(task => (
        <Marker
          key={task.id}
          id={task.id}
          position={task.position}
          areaId={task.areaId}
          data={task}
          onPositionChange={(pos) => onUpdateTask(task.id, { position: pos })}
          onAreaChange={(newAreaId) => onUpdateTask(task.id, { areaId: newAreaId })}
          color="#3b82f6"
          size={20}
          hoverScale={1.25}
          renderTooltip={({ data, position, onMouseEnter, onMouseLeave }) => (
            <TaskTooltip
              task={data}
              position={position}
              onMouseEnter={onMouseEnter}
              onMouseLeave={onMouseLeave}
              onEdit={() => console.log('Edit', data.id)}
              onDelete={() => onDeleteTask(data.id)}
            />
          )}
        />
      ))}
    </MatrixCanvas>
  );
}

Hover Effects

<Marker
  id="1"
  position={{ x: 50, y: 50 }}
  hoverScale={1.25}
  hoverClassName="shadow-lg"
  hoverStyle={{ boxShadow: '0 4px 12px rgba(0,0,0,0.3)' }}
/>

Prevent Click After Drag

<MatrixCanvas
  areas={areas}
  dragEndClickDelay={150}  // Ignore clicks for 150ms after drag ends
  onCanvasClick={(position, areaId) => {
    // This won't fire immediately after dragging
  }}
>
  {/* markers */}
</MatrixCanvas>

Free Canvas (No Areas)

<MatrixCanvas>
  <Marker id="1" position={{ x: 50, y: 50 }} />
</MatrixCanvas>

2-Area Layout (Left/Right)

<MatrixCanvas
  areas={[
    { id: 'low', label: 'Low', position: { row: 0, col: 0 } },
    { id: 'high', label: 'High', position: { row: 0, col: 1 } },
  ]}
  grid={{ rows: 1, cols: 2 }}
>
  {/* markers */}
</MatrixCanvas>

3x3 Grid

<MatrixCanvas
  areas={[
    { id: '0-0', position: { row: 0, col: 0 } },
    { id: '0-1', position: { row: 0, col: 1 } },
    { id: '0-2', position: { row: 0, col: 2 } },
    // ... 9 areas total
  ]}
  grid={{ rows: 3, cols: 3 }}
>
  {/* markers */}
</MatrixCanvas>

Architecture

このライブラリは「ライブラリが処理を担当し、アプリがUIを担当する」という設計思想に基づいています。

ライブラリが提供するもの

  • ドラッグ&ドロップの処理
  • エリア検出(どのエリアにいるか)
  • 位置計算(パーセンテージベース)
  • ツールチップの表示位置計算
  • マウスイベントのハンドリング

アプリが決めるもの

  • エリアの見た目(renderArea
  • ツールチップの見た目(renderTooltip
  • マーカーのスタイル(color, size, classNameなど)
  • データの管理と永続化

License

Copyright (c) 2025 yuitonn

Keywords

react

FAQs

Package last updated on 27 Dec 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts