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

@hadyfayed/filament-workflow-canvas

v1.1.0

Published

Visual workflow builder and canvas component for Filament applications

Downloads

16

Readme

Laravel Workflow Canvas

A visual workflow builder and canvas component for Laravel applications. Built on top of the React Wrapper package, providing a drag-and-drop interface for creating complex workflows.

Features

  • 🎨 Visual Workflow Builder - Drag-and-drop interface for building workflows
  • 🔗 Node-based System - Trigger, Condition, Transform, and Analytics nodes
  • 📊 Real-time Preview - Live workflow execution preview
  • 💾 Auto-save - Automatic saving of workflow changes
  • 🔄 State Management - Advanced state management with persistence
  • 🎯 Type Safe - Full TypeScript support
  • 🖥️ Fullscreen Mode - Expandable canvas for complex workflows
  • 🔍 Validation - Built-in workflow validation and error detection
  • 📱 Responsive - Works on desktop and tablet devices

Installation

Option 1: Using as Distributed Packages (Recommended)

composer require hadyfayed/filament-workflow-canvas
npm install @hadyfayed/filament-workflow-canvas

Dependencies:

This package requires the React Wrapper as a base:

composer require hadyfayed/filament-react-wrapper
npm install @hadyfayed/filament-react-wrapper

Option 2: Using as Local Development Packages

# Copy package files to your resources directory
cp -r packages/react-wrapper/resources/js/* resources/js/react-wrapper/
cp -r packages/workflow-canvas/resources/js/* resources/js/workflow-canvas/

Setup

Publish the configuration files:

php artisan vendor:publish --tag=workflow-canvas-config

Publish the assets:

php artisan vendor:publish --tag=workflow-canvas-assets

Run the migrations:

php artisan migrate

✨ No Plugin Registration Required!

React Wrapper v3.0 provides direct Filament integration:

  • No plugin registration needed in your Filament panel
  • Components work directly with Filament forms and resources
  • Automatic asset loading and dependency management
  • Just install the packages and start using the components!

Vite Configuration (Standard Laravel Approach)

// vite.config.js
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import react from '@vitejs/plugin-react';

export default defineConfig({
    plugins: [
        laravel({
            input: [
                'resources/css/app.css',
                'resources/js/app.js',
                'resources/js/bootstrap-react.tsx'
            ],
            refresh: true,
        }),
        react(),
    ],
    resolve: {
        alias: {
            '@': '/resources/js',
        },
    },
});

Bootstrap Configuration

For distributed packages:

// resources/js/bootstrap-react.tsx
import React from 'react';

// Initialize the React wrapper core system
import '@hadyfayed/filament-react-wrapper/bootstrap';

// Initialize workflow canvas components
import '@hadyfayed/filament-workflow-canvas/bootstrap';

console.log('React Wrapper and Workflow Canvas bootstrapped for Filament integration');

export default function bootstrap() {
    return true;
}

For local development:

// resources/js/bootstrap-react.tsx
import React from 'react';

// Initialize the React wrapper core system
import './react-wrapper/core';

// Initialize workflow canvas components
import './workflow-canvas/index';

console.log('React Wrapper and Workflow Canvas bootstrapped for Filament integration');

export default function bootstrap() {
    return true;
}

Basic Usage

Blade Component

<x-workflow-canvas::workflow-canvas 
    :workflow="$workflow"
    :readonly="false"
    height="600px"
    state-path="workflow.canvas_data"
/>

Livewire Integration

use HadyFayed\WorkflowCanvas\Models\Workflow;

class WorkflowBuilder extends Component
{
    public Workflow $workflow;
    public array $canvasData = [];
    
    public function mount(Workflow $workflow)
    {
        $this->workflow = $workflow;
        $this->canvasData = $workflow->canvas_data ?? [];
    }
    
    public function updatedCanvasData()
    {
        $this->workflow->update(['canvas_data' => $this->canvasData]);
    }
    
    public function render()
    {
        return view('livewire.workflow-builder');
    }
}
<!-- livewire.workflow-builder.blade.php -->
<div>
    <x-workflow-canvas::workflow-canvas 
        :workflow="$workflow"
        state-path="canvasData"
    />
</div>

Filament Integration (React Wrapper v3.0 Direct Integration)

Form Field Integration

use HadyFayed\WorkflowCanvas\Forms\Components\WorkflowCanvasField;

// In your Filament Resource
WorkflowCanvasField::make('canvas_data')
    ->reactive()           // Enable real-time React-PHP state sync
    ->lazy()              // Load component when visible (performance optimization)
    ->enableAutoSave()    // Auto-save workflow changes
    ->showMinimap()       // Show workflow minimap
    ->enableFullscreen()  // Allow fullscreen editing
    ->nodeTypes(config('workflow-canvas.node_types'))
    ->onWorkflowChange(fn($state) => $this->processWorkflow($state));

Widget Integration

use HadyFayed\WorkflowCanvas\Widgets\WorkflowStatsWidget;

// In your Filament Panel
class WorkflowStatsWidget extends ReactWidget
{
    protected string $componentName = 'WorkflowStatsWidget';
    
    public function getData(): array
    {
        return $this->getWorkflowStats(); // Data automatically shared with React
    }
}

No Plugin Required!

React Wrapper v3.0 provides direct Filament integration without requiring plugin registration:

  • Components work directly with Filament forms and resources
  • Lazy loading and asset management handled automatically
  • 90%+ React-PHP function mapping for seamless integration

Node Types

The package comes with four built-in node types:

Trigger Nodes

  • Entry points for workflows
  • Support event, webhook, schedule, and manual triggers
  • Configuration options for event types and filters

Condition Nodes

  • Filter data based on configurable conditions
  • Support multiple operators (equals, contains, exists, etc.)
  • AND/OR logic for multiple conditions

Transform Nodes

  • Modify and map data between workflow steps
  • Support field mapping, JavaScript code, and templates
  • Built-in transformations (uppercase, lowercase, hash, base64)

Analytics Driver Nodes

  • Send data to analytics platforms
  • Support for GA4, Meta Pixel, Mixpanel, and more
  • Configurable async processing and error handling

Configuration

Customize the workflow canvas in config/workflow-canvas.php:

return [
    'canvas' => [
        'default_height' => '600px',
        'fullscreen_enabled' => true,
        'auto_save' => true,
        'auto_save_delay' => 500,
    ],
    
    'node_types' => [
        'trigger' => [
            'label' => 'Trigger',
            'icon' => '⚡',
            'color' => 'blue',
            'processor' => TriggerProcessor::class,
        ],
        // ... more node types
    ],
    
    'validation' => [
        'max_nodes' => 100,
        'max_connections' => 200,
        'required_trigger' => true,
        'prevent_cycles' => true,
    ],
];

Custom Node Types

Create custom node types by extending the base processor:

use HadyFayed\WorkflowCanvas\Processors\BaseNodeProcessor;

class CustomProcessor extends BaseNodeProcessor
{
    public function process(mixed $node, array $inputData, WorkflowExecution $execution): array
    {
        // Your custom processing logic
        return $outputData;
    }
    
    public function getConfigSchema(): array
    {
        return [
            'custom_field' => [
                'type' => 'text',
                'label' => 'Custom Field',
                'required' => true,
            ],
        ];
    }
}

Register the custom node type:

// config/workflow-canvas.php
'node_types' => [
    'custom' => [
        'label' => 'Custom Node',
        'icon' => '⭐',
        'color' => 'purple',
        'processor' => CustomProcessor::class,
    ],
],

Workflow Execution

Execute workflows programmatically:

use HadyFayed\WorkflowCanvas\Services\WorkflowExecutionService;

$executionService = app(WorkflowExecutionService::class);
$result = $executionService->execute($workflow, $inputData);

if ($result->isSuccessful()) {
    $outputData = $result->getOutputData();
} else {
    $errors = $result->getErrors();
}

Events

The package dispatches several events during workflow execution:

use HadyFayed\WorkflowCanvas\Events\WorkflowStarted;
use HadyFayed\WorkflowCanvas\Events\WorkflowCompleted;
use HadyFayed\WorkflowCanvas\Events\WorkflowFailed;

// Listen for workflow events
Event::listen(WorkflowStarted::class, function ($event) {
    Log::info('Workflow started', ['workflow_id' => $event->workflow->id]);
});

API Reference

Workflow Model

$workflow = Workflow::create([
    'name' => 'My Workflow',
    'description' => 'A sample workflow',
    'canvas_data' => $canvasData,
    'is_active' => true,
]);

// Validate workflow structure
$errors = $workflow->validate();

// Duplicate workflow
$copy = $workflow->duplicate('New Name');

// Check for cycles
$hasCycles = $workflow->hasCycles();

Canvas Component Props

WorkflowCanvasComponent::make(
    workflow: $workflow,
    readonly: false,
    height: '800px',
    statePath: 'canvas_data'
)

Development

Package Development

When developing the packages locally:

# In the package directory
cd packages/workflow-canvas
npm install
npm run build  # Build distributable package

# Copy to main app for testing
cd ../../
cp -r packages/workflow-canvas/resources/js/* resources/js/workflow-canvas/

TypeScript Compilation

# Check types in package
cd packages/workflow-canvas
npm run typecheck

# Build with type declarations
npm run build

Main App Development

# Start development server
npm run dev

# Build for production
npm run build

Testing

# Package tests
cd packages/workflow-canvas
composer test
npm test

# Main app tests
cd ../../
php artisan test

Custom Node Development

Create custom nodes by extending the base components:

// resources/js/components/CustomNode.tsx
import React from 'react';
import { NodeProps } from 'reactflow';

export default function CustomNode({ data }: NodeProps) {
    return (
        <div className="custom-node">
            <h3>{data.label}</h3>
            {/* Your custom UI */}
        </div>
    );
}

Register the custom node:

// resources/js/bootstrap-react.tsx
import { componentRegistry } from './react-wrapper/core';
import CustomNode from './components/CustomNode';

componentRegistry.register({
    name: 'CustomNode',
    component: CustomNode,
    metadata: {
        category: 'custom',
        description: 'Custom workflow node'
    }
});

License

MIT License. See LICENSE for details.