npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@prahladkuma11/canvas-editor

v1.0.8

Published

Powerful React/Konva canvas editor with floating toolbars, multi-page support, and text effects

Downloads

723

Readme

@prahladkuma11/canvas-editor

A production-ready React component library for building powerful canvas-based design applications. Complete with text effects, multi-page support, floating toolbars, Unsplash image integration, and role-based permissions.

Version: 1.0.7 · License: MIT

🚀 Features

Complete Design Tools

  • Text editing with 40+ Google Fonts
  • Shape tools (rectangles, circles)
  • Image editing with filters (hue, saturation, brightness, sharpness)
  • Icon support via Iconify (10,000+ icons)

🎨 Advanced Effects

  • Text effects (shadow, highlight, glitch, echo)
  • Directional angle controls
  • Image filters and adjustments
  • Smart alignment guides during drag

📄 Multi-Page Support

  • Sides mode (front/back pages)
  • Pages mode (unlimited pages)
  • Page management with admin controls
  • Multiple printable areas per page

🔐 Role-Based Permissions

  • Admin vs Custom user roles
  • Feature access control
  • Permission-based UI rendering

High Performance

  • High-performance Konva rendering
  • Lazy font loading
  • Optimized asset management

📱 Responsive Design

  • Mobile-friendly floating toolbars
  • Adaptive UI based on screen size
  • Touch-ready controls

🖼️ Unsplash Integration

  • Browse and search millions of photos
  • Built-in request caching (memory + localStorage)
  • Pass your API key via unsplashApiKey prop

📦 Installation

npm install @prahladkuma11/canvas-editor

Requirements

  • React 18+ or 19+
  • React DOM 18+ or 19+

The library ships its own CSS. Do not add Tailwind CSS — it is not required.

🎯 Quick Start

Option 1: Use Complete App Component

The simplest way — import the complete, ready-to-use canvas editor:

import React from 'react';
import { CanvasEditorApp } from '@prahladkuma11/canvas-editor';
import '@prahladkuma11/canvas-editor/styles';

export default function MyApp() {
  return (
    <CanvasEditorApp
      designStateId="tshirt-design-001"
      userRole="admin"
      unsplashApiKey={import.meta.env.VITE_UNSPLASH_ACCESS_KEY}
      initialState={{
        settings: { showGrids: false },
      }}
      onChange={(state) => {
        // Live state updates
        console.log('Editor changed', state);
      }}
      onSave={(state) => {
        // Save snapshot from Export button
        localStorage.setItem('canvas-template', JSON.stringify(state));
      }}
    />
  );
}

This gives you a full-featured editor with all tools, panels, and controls.

Option 2: Build Custom Layout

For more control, use individual components:

import React from 'react';
import {
  CanvasEditorProvider,
  CanvasSurface,
  LeftPanel,
  RightPanel,
} from '@prahladkuma11/canvas-editor';
import '@prahladkuma11/canvas-editor/styles';

export default function CustomEditor() {
  return (
    <CanvasEditorProvider>
      <div style={{ display: 'flex', height: '100vh', width: '100vw' }}>
        <LeftPanel />
        <CanvasSurface />
        <RightPanel />
      </div>
    </CanvasEditorProvider>
  );
}

🔌 Core API

Props

| Prop | Type | Description | |---|---|---| | userRole | 'admin' \| 'custom' | Actual user role. Custom users are restricted to custom view only. | | role | 'admin' \| 'custom' | Optional preview/view role. Admin users can switch between admin and custom views. | | unsplashApiKey | string | Your Unsplash API access key. Pass this to enable the image browser in the Graphics and Background panels. | | designStateId | string | Optional design identifier for automatic localStorage persistence. If local data exists for this ID and initialState is also provided, the editor prompts users to choose between local data and incoming design data. | | initialState | Partial<CanvasState> \| CanvasState | Optional initial state to pre-populate the canvas. Missing fields are filled from library defaults (including nested settings/pan and partial objects/pages). | | onChange | (state: CanvasState) => void | Optional callback fired whenever canvas state changes. | | onSave | (state: CanvasState) => void | Optional callback fired when save is triggered (for example from Export button). |

Design ID Persistence Example

Use designStateId when you want autosave/restore by design key:

import { CanvasEditorApp } from '@prahladkuma11/canvas-editor';

export default function HostApp() {
  const designId = 'order-7843-front';
  const incomingDesign = {
    settings: { showGrids: false },
  };

  return (
    <CanvasEditorApp
      userRole="admin"
      designStateId={designId}
      initialState={incomingDesign}
      onSave={(state) => {
        // Optional: persist exported JSON to your backend
        console.log('Saved state', state);
      }}
    />
  );
}

Behavior:

  • If localStorage has no data for this ID, initialState is used.
  • If localStorage has data for this ID and initialState is passed, users are prompted to choose which one to load.
  • State changes are auto-saved to localStorage under this ID.

Admin Template + Custom Load Example

Save a template JSON as admin, then load it for custom users via initialState:

import { useState } from 'react';
import { CanvasEditorApp } from '@prahladkuma11/canvas-editor';
import '@prahladkuma11/canvas-editor/styles';

export default function App() {
  const [savedTemplate, setSavedTemplate] = useState(() => {
    const raw = localStorage.getItem('canvas-template');
    return raw ? JSON.parse(raw) : undefined;
  });

  return (
    <>
      <CanvasEditorApp
        userRole="admin"
        initialState={savedTemplate}
        onSave={(state) => {
          const json = JSON.stringify(state);
          localStorage.setItem('canvas-template', json);
          setSavedTemplate(state);
        }}
      />

      <CanvasEditorApp
        userRole="custom"
        initialState={savedTemplate}
      />
    </>
  );
}

useCanvasEditor

Access canvas state and dispatch actions:

import { useCanvasEditor } from '@prahladkuma11/canvas-editor';

function MyComponent() {
  const { state, dispatch, triggerSave } = useCanvasEditor();

  // Add text object
  const addText = () => {
    dispatch({
      type: 'ADD_OBJECT',
      payload: {
        type: 'text',
        text: 'Hello Canvas',
        x: 100,
        y: 100,
        fontSize: 24,
        fontFamily: 'Poppins',
      },
    });
  };

  // Update object
  const updateText = () => {
    dispatch({
      type: 'UPDATE_OBJECT',
      payload: {
        id: 'object-id',
        updates: {
          text: 'Updated Text',
          fontSize: 32,
        },
      },
    });
  };

  // Delete object
  const deleteObject = (id) => {
    dispatch({
      type: 'DELETE_OBJECTS',
      payload: [id],
    });
  };

  const exportJson = () => {
    console.log(JSON.stringify(state, null, 2));
    triggerSave();
  };

  return (
    <div>
      <button onClick={addText}>Add Text</button>
      <button onClick={updateText}>Update Text</button>
      <button onClick={() => deleteObject('object-1')}>Delete</button>
      <button onClick={exportJson}>Export</button>
    </div>
  );
}

Available Actions

// Object management
dispatch({ type: 'ADD_OBJECT', payload: { type, x, y, ... } });
dispatch({ type: 'UPDATE_OBJECT', payload: { id, updates: { ...props } } });
dispatch({ type: 'DELETE_OBJECTS', payload: [objectId] });
dispatch({ type: 'SET_SELECTION', payload: [objectId] });
dispatch({ type: 'SET_EDITING_ID', payload: objectId });

// Canvas controls
dispatch({ type: 'SET_ZOOM', payload: zoomLevel });
dispatch({ type: 'SET_PAN', payload: { x, y } });
dispatch({ type: 'SET_TOOL', payload: 'select' | 'pan' | 'text' | 'rect' | 'circle' | 'image' });

// Page management
dispatch({ type: 'SET_PAGE_MODE', payload: 'sides' | 'pages' });
dispatch({ type: 'ADD_PAGE', payload: { name: 'Page Name', ... } });
dispatch({ type: 'DELETE_PAGE', payload: pageId });
dispatch({ type: 'SET_CURRENT_PAGE', payload: pageId });
dispatch({ type: 'SET_SIDE_ENABLED', payload: { side: 'front' | 'back', enabled: true } });

// Background/printable area
dispatch({ type: 'SET_BACKGROUND_IMAGE', payload: { image: imageDataUrl } });
dispatch({ type: 'SET_BACKGROUND_COLOR', payload: { color: '#ffffff' } });
dispatch({ type: 'TOGGLE_EDIT_PRINTABLE_AREA' });
dispatch({ type: 'ADD_PRINTABLE_AREA' });
dispatch({ type: 'DELETE_PRINTABLE_AREA', payload: printableAreaId });
dispatch({ type: 'SET_ACTIVE_PRINTABLE_AREA', payload: printableAreaId });
dispatch({ type: 'UPDATE_PRINTABLE_AREA', payload: { id: printableAreaId, x: 120, y: 80 } });

// Role & permissions
dispatch({ type: 'SET_ROLE', payload: 'admin' | 'custom' });
dispatch({ type: 'SET_USER_ROLE', payload: 'admin' | 'custom' });

// Settings
dispatch({ type: 'UPDATE_SETTINGS', payload: { showRulers: true, ... } });

📦 Components

Main Components

CanvasSurface

Main canvas rendering area with interactive object selection and manipulation.

import { CanvasSurface } from '@prahladkuma11/canvas-editor';

<CanvasSurface />

LeftPanel

Sidebar with page/side selection and tools.

import { LeftPanel } from '@prahladkuma11/canvas-editor';

<LeftPanel />

RightPanel

Properties panel for editing selected object properties.

import { RightPanel } from '@prahladkuma11/canvas-editor';

<RightPanel />

ProductSidePanel

Floating side panel with secondary tools.

import { ProductSidePanel } from '@prahladkuma11/canvas-editor';

<ProductSidePanel />

Floating Toolbars

FloatingObjectToolbar

Appears when hovering over objects for quick manipulation.

import { FloatingObjectToolbar } from '@prahladkuma11/canvas-editor';

<FloatingObjectToolbar />

TextToolbar

Floating toolbar for text formatting (font, size, effects, alignment).

import { TextToolbar } from '@prahladkuma11/canvas-editor';

<TextToolbar />

ShapeToolbar

Toolbar for shape properties (fill, stroke, rotation).

import { ShapeToolbar } from '@prahladkuma11/canvas-editor';

<ShapeToolbar />

Secondary Panels

SecondaryPanel

Tab-based panel container for advanced controls.

import { SecondaryPanel } from '@prahladkuma11/canvas-editor';

<SecondaryPanel />

Available sub-panels:

  • TextPanel - Text-specific controls
  • GraphicsPanel - Shape and image tools
  • BackgroundPanel - Page background settings
  • LayersPanel - Object layer management
  • MaterialPanel - Color and material presets
  • ObjectsPanel - Object listing and selection
  • UploadsPanel - Asset management

💾 Usage Examples

Example 1: Add Text with Effects

import { useCanvasEditor } from '@prahladkuma11/canvas-editor';

function AddEffectText() {
  const { dispatch } = useCanvasEditor();

  const addGlitchText = () => {
    dispatch({
      type: 'ADD_OBJECT',
      payload: {
        type: 'text',
        text: 'Glitch Effect',
        x: 100,
        y: 100,
        fontSize: 48,
        fontFamily: 'Bebas Neue',
        textEffect: 'glitch',
        effectColor: '#ff0000',
        effectDistance: 3,
        effectAngle: 45,
      },
    });
  };

  return <button onClick={addGlitchText}>Add Glitch Text</button>;
}

Example 2: Work with Images

function ImageEditor() {
  const { dispatch } = useCanvasEditor();

  const addImage = (imageUrl) => {
    dispatch({
      type: 'ADD_OBJECT',
      payload: {
        type: 'image',
        src: imageUrl,
        x: 50,
        y: 50,
        width: 300,
        height: 300,
      },
    });
  };

  const applyFilters = (imageId) => {
    dispatch({
      type: 'UPDATE_OBJECT',
      payload: {
        id: imageId,
        updates: {
          imageAdjustHue: 25,
          imageAdjustSaturation: 1.3,
          imageAdjustBrightness: 1.1,
          imageSharpness: 1.5,
        },
      },
    });
  };

  return (
    <>
      <button onClick={() => addImage('https://example.com/image.jpg')}>
        Add Image
      </button>
      <button onClick={() => applyFilters('image-id')}>Apply Filters</button>
    </>
  );
}

Example 3: Multi-Page Management

function PageManager() {
  const { state, dispatch } = useCanvasEditor();

  const switchToPages = () => {
    dispatch({ type: 'SET_PAGE_MODE', payload: 'pages' });
  };

  const addNewPage = () => {
    dispatch({
      type: 'ADD_PAGE',
      payload: { name: 'Page ' + (state.pages.length + 1) },
    });
  };

  const selectPage = (pageId) => {
    dispatch({ type: 'SET_CURRENT_PAGE', payload: pageId });
  };

  return (
    <div>
      <button onClick={switchToPages}>Switch to Pages Mode</button>
      <button onClick={addNewPage}>Add Page</button>
      <div>
        {state.pages.map((page) => (
          <button
            key={page.id}
            onClick={() => selectPage(page.id)}
            style={{
              fontWeight: page.id === state.currentPageId ? 'bold' : 'normal',
            }}
          >
            {page.name}
          </button>
        ))}
      </div>
    </div>
  );
}

Example 4: Role-Based Features

function RoleToggle() {
  const { state, dispatch } = useCanvasEditor();

  const toggleRole = () => {
    const newRole = state.role === 'admin' ? 'custom' : 'admin';
    dispatch({ type: 'SET_ROLE', payload: newRole });
  };

  return (
    <div>
      <p>Current Role: {state.role}</p>
      <button onClick={toggleRole}>Switch Role</button>
      {state.role === 'admin' && (
        <p>✅ Admin can add/remove pages and customize layouts</p>
      )}
      {state.role === 'custom' && (
        <p>⚠️ Custom users have limited permissions</p>
      )}
    </div>
  );
}

🎨 Fonts

The editor includes 40+ Google Fonts organized by category:

Sans-serif: Inter, Roboto, Poppins, Montserrat, Open Sans, Lato, Ubuntu, Source Sans Pro, Raleway, Nunito

Serif: Playfair Display, Merriweather, PT Serif, Crimson Text, Lora, Cormorant

Monospace: JetBrains Mono, Roboto Mono, IBM Plex Mono

Display: Bebas Neue, Oswald, Barlow Condensed, Fredoka

Handwriting: Caveat, Pacifico, Permanent Marker

Fonts are loaded dynamically on-demand via WebFont Loader.

import { TEXT_FONT_OPTIONS, ensureFontLoaded } from '@prahladkuma11/canvas-editor';

// List all available fonts
console.log(TEXT_FONT_OPTIONS);

// Ensure a font is loaded before using it
await ensureFontLoaded('Poppins');

🖼️ Unsplash Integration

The Graphics and Background panels can browse and search Unsplash photos. To enable them, pass your Unsplash API access key via the unsplashApiKey prop:

import { CanvasEditorProvider } from '@prahladkuma11/canvas-editor';

<CanvasEditorProvider unsplashApiKey={process.env.REACT_APP_UNSPLASH_KEY}>
  ...
</CanvasEditorProvider>

Or set the key programmatically (e.g. after fetching from your backend):

import { setUnsplashApiKey } from '@prahladkuma11/canvas-editor';

setUnsplashApiKey('your_access_key');

To check if a key is currently set:

import { hasUnsplashApiKey } from '@prahladkuma11/canvas-editor';

if (hasUnsplashApiKey()) {
  // images are available
}

If no key is provided, the image panels display an informational banner instead of broken UI.

Results are cached in memory and localStorage to minimize API calls.

🎯 Type Definitions

Full TypeScript support with exported types:

import {
  CanvasState,
  CanvasObject,
  Page,
  Role,
  ToolType,
  PageMode,
  CanvasEditorContextType,
  CanvasAction,
} from '@prahladkuma11/canvas-editor';

interface CanvasState {
  objects: CanvasObject[];
  selectedObjectId: string | null;
  activeTool: ToolType;
  zoom: number;
  pan: { x: number; y: number };
  pages: Page[];
  selectedPageId: string;
  role: Role;
  settings: {
    showRulers: boolean;
    showGrids: boolean;
  };
}

interface CanvasObject {
  id: string;
  type: 'text' | 'rect' | 'circle' | 'image';
  x: number;
  y: number;
  width?: number;
  height?: number;
  // ... many more properties
}

type Role = 'admin' | 'custom';
type ToolType = 'select' | 'pan' | 'text' | 'rect' | 'circle' | 'image';
type PageMode = 'sides' | 'pages';

🎨 Styling

The library ships its own standalone CSS — no Tailwind CSS required. Simply import the stylesheet once at the top level of your app:

import '@prahladkuma11/canvas-editor/styles';

This maps to dist/canvas-editor.css in the package. The stylesheet is self-contained and will not conflict with your existing CSS framework or reset.

🎮 Keyboard Shortcuts

  • Delete - Delete selected object
  • Escape - Deselect
  • Arrow Keys - Move selected object
  • Shift + Arrow Keys - Fine-tune position
  • V - Select tool
  • H - Pan tool

⚡ Performance Tips

  1. Lazy Font Loading - Fonts load on-demand when used
  2. Asset Optimization - Compress images before uploading
  3. Layer Management - Use the Layers panel to organize objects
  4. Page Structure - Keep pages focused on specific content
  5. Zoom Levels - Use preset zoom levels (25%, 50%, 100%, 200%, etc.)

🌍 Browser Support

  • Chrome/Edge 90+
  • Firefox 88+
  • Safari 14+
  • Mobile browsers (iOS Safari, Chrome Mobile)

📱 Responsive Behavior

The library automatically adapts to different screen sizes:

  • Desktop (1920px+): Full UI with all panels
  • Tablet (768px-1920px): Optimized layout with hidden panels
  • Mobile (<768px): Icon-only toolbars and collapsible panels

🔒 Permissions & Roles

Admin Role

  • Add/remove pages
  • Customize layouts
  • Set canvas background
  • Adjust printable areas
  • Export canvas

Custom Role

  • Edit objects
  • Add text/shapes/images
  • Apply effects
  • Limited feature access

📊 State Management

The editor uses React Context + useReducer for state management:

const { state, dispatch } = useCanvasEditor();

// state: Current canvas state
// dispatch: Send actions to update state

No external state management required!

📦 Exports Reference

// Complete app
import { CanvasEditorApp } from '@prahladkuma11/canvas-editor';

// Core
import { CanvasEditorProvider, useCanvasEditor } from '@prahladkuma11/canvas-editor';

// Components
import {
  CanvasSurface, LeftPanel, RightPanel, SecondaryPanel,
  FloatingObjectToolbar, TextToolbar, ShapeToolbar,
} from '@prahladkuma11/canvas-editor';

// Unsplash utilities
import { setUnsplashApiKey, hasUnsplashApiKey } from '@prahladkuma11/canvas-editor';

// Font utilities
import { ensureFontLoaded, TEXT_FONT_OPTIONS } from '@prahladkuma11/canvas-editor';

// Types
import type { CanvasEditorAppProps, CanvasState, CanvasObject, Page, Role, ToolType } from '@prahladkuma11/canvas-editor';

🚀 Distribution

The package exports both ES Module and CommonJS bundles plus a stylesheet:

{
  "exports": {
    ".": {
      "import": "./dist/canvas-editor.mjs",
      "require": "./dist/canvas-editor.cjs"
    },
    "./styles": "./dist/canvas-editor.css"
  }
}

Usage in different environments

// ES Module / TypeScript
import { CanvasEditorApp, useCanvasEditor } from '@prahladkuma11/canvas-editor';

// CommonJS
const { CanvasEditorApp } = require('@prahladkuma11/canvas-editor');

🤝 Contributing

Contributions are welcome! Please fork the repository and submit a pull request.

📄 License

MIT License — See LICENSE file for details


Built with ❤️ using React, Konva, and TypeScript