aureuserp/progress-stepper

A Filament v5 progress-stepper form & infolist component for visualising workflow state as a horizontal arrow-stepper.

Maintainers

Package info

github.com/aureuserp/progress-stepper

pkg:composer/aureuserp/progress-stepper

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-master 2026-04-21 11:39 UTC

This package is auto-updated.

Last update: 2026-04-21 11:39:59 UTC


README

Latest Version on Packagist License

A feature-rich Filament v5 plugin that renders workflow state as an interactive arrow-stepper (form) or a read-only status bar (infolist). Built for business apps where orders, applications, or projects move through named states and you want every screen to show that progress visually.

Progress Stepper — Filament v5 plugin

Table of contents

Features

  • Form component (extends ToggleButtons) — interactive radio/checkbox stepper
  • Infolist entry — read-only status visualisation
  • 4 state colors — completed, current, upcoming, error — each overridable
  • Auto-mark completedmarkCompletedUpToCurrent() paints every step before the active one
  • Error states — flag any states as danger via errorStates([…])
  • Hide states conditionallyhideStatesFor(fn) based on the current record
  • BackedEnum integrationoptionsFromEnum(MyStatus::class) auto-derives labels / icons / colors
  • Type-safe enumsSize::Large, Direction::Vertical, Theme::Outlined, ConnectorShape::Chevron, StepStatus::Completed — strings still work for backwards compatibility
  • 3 sizes — sm / md / lg
  • 2 directions — horizontal / vertical
  • 4 connector shapes — arrow / chevron / dot / line
  • 3 themes — filled / outlined / minimal
  • Step numberingshowIndex() prepends 1., 2., 3.
  • Icon-only (compact) mode for tight navigation bars
  • Per-step content — descriptions, tooltips, badges, icons
  • Overridable icons via FilamentIcon::register()
  • Translations shipped for en and ar
  • Full Pest test coverage — 74 tests across architecture, API, status resolver, enum input, and component instantiation

Requirements

  • PHP 8.2+
  • Laravel 11+
  • Filament v5+
  • Tailwind CSS (via a custom Filament theme if you use Panels)

Installation

composer require aureuserp/progress-stepper

The service provider is auto-discovered. The component CSS is registered via FilamentAsset and published automatically during artisan filament:assets.

Quick start

Form component

use Webkul\ProgressStepper\Forms\Components\ProgressStepper;

ProgressStepper::make('state')
    ->options([
        'draft'     => 'Draft',
        'sent'      => 'Sent',
        'confirmed' => 'Confirmed',
        'done'      => 'Done',
    ])
    ->default('draft');

Infolist entry

use Webkul\ProgressStepper\Infolists\Components\ProgressStepper;

ProgressStepper::make('state')
    ->options([
        'draft' => 'Draft',
        'sent'  => 'Sent',
        'done'  => 'Done',
    ]);

Both components extend normal Filament base classes (ToggleButtons and Entry), so all standard Filament methods — ->label(), ->helperText(), ->visible(), ->columnSpanFull(), ->state() — still work.

API reference

All methods return static so they chain. Each accepts either a scalar value or a Closure where applicable (per Filament's standard pattern).

Options

->options(array | Closure $options)               // ['value' => 'Label', …]
->optionsFromEnum(string $enumClass)              // derive from a BackedEnum

BackedEnum integration

Implement HasLabel, HasColor, HasIcon on your enum and every case's label / icon / color is picked up automatically:

enum OrderStatus: string implements HasLabel, HasColor, HasIcon
{
    case Draft = 'draft';
    case Sent = 'sent';
    case Confirmed = 'confirmed';
    case Done = 'done';

    public function getLabel(): ?string
    {
        return match ($this) {
            self::Draft => __('orders.state.draft'),
            self::Sent => __('orders.state.sent'),
            self::Confirmed => __('orders.state.confirmed'),
            self::Done => __('orders.state.done'),
        };
    }

    public function getColor(): string | array | null
    {
        return match ($this) {
            self::Draft => 'gray',
            self::Sent => 'info',
            self::Confirmed => 'primary',
            self::Done => 'success',
        };
    }

    public function getIcon(): ?string
    {
        return match ($this) {
            self::Draft => 'heroicon-m-document',
            self::Sent => 'heroicon-m-paper-airplane',
            self::Confirmed => 'heroicon-m-check-badge',
            self::Done => 'heroicon-m-check-circle',
        };
    }
}

ProgressStepper::make('state')->optionsFromEnum(OrderStatus::class);

State behaviour

->markCompletedUpToCurrent(bool | Closure $condition = true)
    // Steps ordered before the current one take the completedColor. Default: false.

->errorStates(array | Closure $states)
    // Values that should render with errorColor. e.g. ['cancelled', 'rejected'].

->hideStatesFor(Closure $callback)
    // Callback returns an array of values to hide. Receives ['record' => …] if
    // used inside a resource form/infolist — see the real-world example below.

State colors

Each slot accepts any Filament color token (primary, success, warning, danger, info, gray, custom) or a Closure.

->completedColor(string | Closure $color)   // default: 'success'
->currentColor(string | Closure $color)     // default: 'primary'
->upcomingColor(string | Closure $color)    // default: 'gray'
->errorColor(string | Closure $color)       // default: 'danger'

Layout

Each layout setter accepts either the dedicated enum (recommended — IDE autocomplete, compile-time checked) or the raw string (quick one-offs, backward compatible):

use Webkul\ProgressStepper\Enums\{ConnectorShape, Direction, Size, Theme};

->size(Size::Large)                              // or ->size('lg')         — default: Size::Medium
->direction(Direction::Vertical)                  // or ->direction('vertical') — default: Direction::Horizontal
->theme(Theme::Outlined)                          // or ->theme('outlined')  — default: Theme::Filled
->connectorShape(ConnectorShape::Chevron)         // or ->connectorShape('chevron') — default: ConnectorShape::Arrow
->showIndex(bool | Closure $condition = true)     // prepend 1., 2., …
->iconOnly(bool | Closure $condition = true)      // hide labels, keep icons
->inline(bool | Closure $condition = true)        // align to the right of the field label

Unknown values silently fall back to the enum's default() case, so misspellings never crash a page.

Per-step enrichment

Each accepts an array<value, string|int> OR a Closure($value, $label, $state):

->stepDescription(array | Closure $descriptions)   // subtitle under the label
->stepTooltip(array | Closure $tooltips)           // hover help (title attribute)
->stepBadge(array | Closure $badges)               // small pill with count/text

Example:

->stepDescription([
    'draft' => 'Not yet sent',
    'sent'  => 'Awaiting response',
])
->stepBadge(fn (string $value) => $value === 'review' ? auth()->user()->unreadReviewCount() : null)
->stepTooltip(fn (string $value) => __("orders.stepper.{$value}.tooltip"))

Icons

->icons([                                   // available on both components
    'draft'     => 'heroicon-m-document',
    'sent'      => 'heroicon-m-paper-airplane',
    'confirmed' => 'heroicon-m-check-badge',
    'done'      => 'heroicon-m-check-circle',
])

The form component inherits icons() from ToggleButtons; the infolist component declares its own.

Enums

The plugin ships five BackedEnums under Webkul\ProgressStepper\Enums so you can use symbolic constants instead of magic strings. Every string value matches what the CSS data-ps-* attributes expect, so passing an enum produces the same rendered output as the equivalent string.

Enum Cases → values Default
Size Small'sm', Medium'md', Large'lg' Size::Medium
Direction Horizontal, Vertical Direction::Horizontal
Theme Filled, Outlined, Minimal Theme::Filled
ConnectorShape Arrow, Chevron, Dot, Line ConnectorShape::Arrow
StepStatus Completed, Current, Upcoming, Error (internal; returned by getStepStatus())

Each of the first four exposes a default() static method that returns the case used when no explicit value is set or when an unknown value falls through — useful for building resilient defaults in custom code.

Enum usage

use Webkul\ProgressStepper\Enums\ConnectorShape;
use Webkul\ProgressStepper\Enums\Direction;
use Webkul\ProgressStepper\Enums\Size;
use Webkul\ProgressStepper\Enums\Theme;
use Webkul\ProgressStepper\Forms\Components\ProgressStepper;

ProgressStepper::make('state')
    ->options([...])
    ->size(Size::Large)
    ->direction(Direction::Horizontal)
    ->theme(Theme::Outlined)
    ->connectorShape(ConnectorShape::Chevron);

Interop with getStepStatus()

Need to inspect the classification of a step programmatically? Round-trip through StepStatus::from(...):

use Webkul\ProgressStepper\Enums\StepStatus;

$status = StepStatus::from($component->getStepStatus('confirmed'));

match ($status) {
    StepStatus::Completed => /* … */,
    StepStatus::Current   => /* … */,
    StepStatus::Upcoming  => /* … */,
    StepStatus::Error     => /* … */,
};

Real-world example

Adapted from a Sales Order Resource — mirrors the aureuserp pattern, mixing the Size / ConnectorShape enums with a domain OrderStatus enum:

use App\Enums\OrderStatus;
use Filament\Schemas\Schema;
use Webkul\ProgressStepper\Enums\ConnectorShape;
use Webkul\ProgressStepper\Enums\Size;
use Webkul\ProgressStepper\Forms\Components\ProgressStepper;

public static function form(Schema $schema): Schema
{
    return $schema->components([
        ProgressStepper::make('state')
            ->optionsFromEnum(OrderStatus::class)
            ->markCompletedUpToCurrent()
            ->errorStates([OrderStatus::Cancelled->value])
            ->hideStatesFor(fn ($record) => $record?->is_refunded
                ? []
                : [OrderStatus::Refunded->value])
            ->size(Size::Large)
            ->connectorShape(ConnectorShape::Chevron)
            ->showIndex()
            ->stepDescription([
                OrderStatus::Draft->value     => 'Not yet sent to the customer',
                OrderStatus::Confirmed->value => 'Customer has confirmed the quote',
            ])
            ->stepBadge(fn (string $value, $record) => match ($value) {
                OrderStatus::Sent->value => $record?->unread_comment_count ?: null,
                default                  => null,
            })
            ->columnSpanFull()
            ->disabled(),
    ]);
}

Theming & customisation

Custom colors

Any color registered on your panel flows through automatically. Just reference its key:

// AdminPanelProvider
->colors(['magenta' => '#b72d81'])

// Usage
->currentColor('magenta')

Extending the CSS

The plugin styles ship at vendor/aureuserp/progress-stepper/resources/dist/progress-stepper.css. Publish it if you want to fork it:

php artisan vendor:publish --tag="progress-stepper-config"

Or override selectors in your own theme CSS — the stable hooks are:

  • .ps-container — outer wrapper
  • .ps-step — each step wrapper
  • .ps-button — the rendered stepper segment
  • .ps-label, .ps-label-text, .ps-index, .ps-description, .ps-badge — inner label parts
  • data-ps-direction | data-ps-size | data-ps-theme | data-ps-separator | data-ps-compact | data-ps-inline on .ps-container — values match the Direction, Size, Theme, ConnectorShape enum values
  • data-ps-status="completed | current | upcoming | error" — values match StepStatus enum values
  • data-ps-color="primary | success | warning | danger | info | gray | <custom>" — drives the --ps-color-500 / --ps-color-600 CSS variables that the filled / outlined / minimal themes consume

Overridable icons

The plugin registers three aliases you can override globally:

use Filament\Support\Facades\FilamentIcon;

FilamentIcon::register([
    'progress-stepper::step-completed' => 'phosphor-check-bold',
    'progress-stepper::step-current'   => 'phosphor-caret-right-bold',
    'progress-stepper::step-error'     => 'phosphor-x-bold',
]);
Alias Default
progress-stepper::step-completed heroicon-m-check
progress-stepper::step-current heroicon-m-arrow-right
progress-stepper::step-error heroicon-m-x-mark

Translations

The plugin ships en and ar translations under the progress-stepper:: namespace for status / separator / theme labels used internally.

Publish them to customise:

php artisan vendor:publish --tag="progress-stepper-translations"

Files appear in lang/vendor/progress-stepper/{locale}/progress-stepper.php.

Publishing resources

# Config file (currently empty — reserved for future tuning knobs)
php artisan vendor:publish --tag="progress-stepper-config"

# Blade views
php artisan vendor:publish --tag="progress-stepper-views"

# Translations
php artisan vendor:publish --tag="progress-stepper-translations"

Testing

The plugin ships with a full Pest test suite covering every public API surface.

vendor/bin/pest plugins/aureuserp/progress-stepper/tests/Feature

74 tests (148 assertions) across:

Area Coverage
Architecture Components extend ToggleButtons / Entry, shared trait used on both, Plugin implements Filament\Contracts\Plugin, ServiceProvider extends Spatie PackageServiceProvider, no debug calls (dd, dump, var_dump, ray, die, exit) in shipped code
State colors Defaults, scalar setters, closure setters, chaining
State behaviour markCompletedUpToCurrent, errorStates, hideStatesFor
Layout API size, direction, theme, connectorShape, showIndex, iconOnly — value acceptance and default-fallback
Content enrichment stepDescription, stepTooltip, stepBadge — arrays, closures, empty-value coercion
Status resolver getStepStatus / getStepColor across completed / current / upcoming / error; errorStates overrides; custom color overrides
Enum input Size::Large, Direction::Vertical etc. produce the same strings as raw equivalents; string inputs still work; closures returning enums work
optionsFromEnum Derives labels from HasLabel, icons from HasIcon, colors from HasColor; safely ignores non-enum classes
Component instantiation Base class assertions, view paths, chainable API, inline(), getColor() delegation

Fixtures live at tests/Feature/Fixtures/ (only a SampleStatus BackedEnum).

Troubleshooting

Symptom Likely cause Fix
Target class [Webkul\ProgressStepper\Forms\…] not found Autoload cache is stale composer dump-autoload && php artisan optimize:clear
View progress-stepper::forms.progress-stepper not found Service provider not registered Check the provider is in bootstrap/providers.php or that package discovery ran (php artisan package:discover)
Steps render without arrows / colors Filament asset cache stale php artisan filament:assets
Form component throws Declaration of … must be compatible with Filament\Schemas\Components\Component::… You called one of the legacy methods (separator(), compact(), description(), tooltip(), badge()) which collide with Filament base traits Use the prefixed names: connectorShape(), iconOnly(), stepDescription(), stepTooltip(), stepBadge()

Naming notes

Five method names on this plugin intentionally differ from the natural English word to avoid collisions with Filament's base traits:

Natural name Use this instead Why
separator() connectorShape() Component::separator() takes string|null = ','
compact() iconOnly() CanBeCompact::compact() exists
description() stepDescription() HasDescription::description() exists
tooltip() stepTooltip() HasTooltip::tooltip() exists
badge() stepBadge() HasBadge::badge() exists

Security

If you discover a security vulnerability, email support@webkul.com rather than opening a public issue.

Contributing

PRs welcome. Please run the test suite before submitting:

vendor/bin/pest plugins/aureuserp/progress-stepper/tests/Feature
vendor/bin/pint plugins/aureuserp/progress-stepper       # code style

When adding a new configuration option, please:

  1. Define (or extend) a BackedEnum under src/Enums/ if the option is one of a fixed set of values.
  2. Accept both the enum and the raw string in the setter signature for backward compatibility.
  3. Add coverage to the relevant test file under tests/Feature/Unit/.
  4. Document the option in the API reference and Enums sections as appropriate.

Credits

License

MIT. See LICENSE.md.