orzubek-rakhimov/laravel-sdui

There is no license information available for the latest version (dev-main) of this package.

Server-Driven UI framework for Laravel - Build dynamic, native-like mobile and web interfaces declaratively in PHP

Maintainers

Package info

github.com/Orzubek-Rakhimov/laravel-sdui

pkg:composer/orzubek-rakhimov/laravel-sdui

Statistics

Installs: 0

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

dev-main 2026-03-29 14:06 UTC

This package is auto-updated.

Last update: 2026-04-29 14:19:30 UTC


README

Build dynamic, native-like mobile and web interfaces using Laravel. Define your UI declaratively in PHP and render it anywhere.

PHP Laravel Tests License

Features

โœจ Declarative UI Definition - Define screens in pure PHP using a fluent, chainable API ๐ŸŽฏ Type-Safe - Full PHP 8.3+ type hints and strict typing throughout ๐Ÿงฉ Component-Based - Rich set of built-in components (Text, Button, Image, Stack, Card, Badge, etc.) โšก Action System - Handle navigation, URL opening, events, and custom actions ๐Ÿ”„ Dynamic Rendering - Conditionally render components, map collections, nest layouts ๐ŸŽจ Highly Extensible - Create custom components by extending the base Component class ๐Ÿงช Thoroughly Tested - 76+ comprehensive unit and integration tests ๐Ÿ“ฆ Single Dependency - Only requires illuminate/support

Installation

composer require sdui/laravel-sdui

The package is auto-discovered by Laravel. If you're not using Laravel auto-discovery, add the service provider:

// config/app.php
'providers' => [
    // ...
    SDUI\SDUIServiceProvider::class,
],

'aliases' => [
    // ...
    'SDUI' => SDUI\Facades\SDUI::class,
],

Quick Start

Basic Screen

use SDUI\Screen;
use SDUI\Components\Text;
use SDUI\Components\Button;

$screen = Screen::make('home')
    ->title('Welcome')
    ->add(
        Text::make('Hello, World!')
            ->bold()
            ->variant('heading')
    )
    ->add(
        Button::make('Get Started')
            ->variant('primary')
            ->navigateTo('features')
    );

return $screen->render();

Using the Facade

use SDUI\Facades\SDUI;

$screen = SDUI::screen('dashboard')
    ->title('Dashboard')
    ->add(Text::make('Welcome to your dashboard'));

return $screen->render();

Conditional Rendering

$screen = Screen::make('profile')
    ->title('User Profile')
    ->add(Text::make($user->name))
    ->add(Text::make($user->email)->muted())
    ->addIf($user->isAdmin(), Button::make('Admin Panel')->destructive())
    ->addIf($user->isPremium(), Text::make('Premium User')->color('gold'));

Rendering Collections

$products = Product::all();

$screen = Screen::make('products')
    ->title('Our Products')
    ->addMany($products, fn($product) =>
        Stack::vertical(12)
            ->add(Image::make($product->image)->width(200)->height(200))
            ->add(Text::make($product->name)->bold())
            ->add(Text::make("$" . $product->price)->color('green'))
            ->add(
                Button::make('View')
                    ->navigateTo('product.show', ['id' => $product->id])
            )
    );

Components

Text

Text::make('Hello')
    ->bold()
    ->variant('heading') // display | heading | subheading | body | caption | label
    ->align('center')
    ->color('blue')
    ->muted()

Button

Button::make('Click Me')
    ->variant('primary') // primary | secondary | ghost | danger
    ->disabled()
    ->loading()
    ->fullWidth()
    ->icon('icon-name', 'left')
    ->navigateTo('route.name', ['id' => 1])

Image

Image::make('https://example.com/image.jpg')
    ->width(300)
    ->height(300)
    ->rounded(12)
    ->circle()
    ->alt('Description')

Stack (Layouts)

Stack::vertical(16)  // spacing in pixels
    ->add(Text::make('Item 1'))
    ->add(Text::make('Item 2'))
    ->align('center')
    ->justify('space-between')

Stack::horizontal(8)
    ->add(Button::make('Cancel'))
    ->add(Button::make('Confirm'))

Card

Card::make()
    ->add(Text::make('Card content'))
    ->padding(16)
    ->elevated()

Badge

Badge::make('NEW')
    ->color('green')
    ->variant('filled')

ListItem

ListItem::make('Item Label')
    ->subtitle('Subtitle text')
    ->icon('icon-name')
    ->trailing('โ†’')
    ->disclosure()

Actions

Navigate

Button::make('Go to Profile')
    ->navigateTo('profile.show', ['id' => $user->id])

Open URL

Button::make('Visit Website')
    ->openUrl('https://example.com', $inApp = true)

Emit Events

Button::make('Submit')
    ->emit('form_submitted', ['status' => 'success'])

Custom Actions

Button::make('Custom')
    ->action('my_custom_action', ['key' => 'value'])

Metadata

$screen = Screen::make('app')
    ->title('My App')
    ->meta('version', '1.0')
    ->meta('user_id', auth()->id())
    ->meta('timestamp', now())
    ->add(/* components */);

Building a REST API Response

use Illuminate\Routing\Controller;

class ScreenController extends Controller
{
    public function home()
    {
        return Screen::make('home')
            ->title('Welcome')
            ->add(Text::make('This is your home screen'))
            ->render();
    }

    public function statusCode()
    {
        return Screen::make('error')
            ->add(Text::make('Something went wrong'))
            ->render(500);
    }

    public function withHeaders()
    {
        return Screen::make('app')
            ->add(Text::make('Content'))
            ->render(200, [
                'X-Custom-Header' => 'value',
            ]);
    }
}

Artisan Commands

Make a Custom Component

php artisan sdui:make-component CustomComponent

This creates a new component template in app/SDUI/Components/CustomComponent.php

Preview a Screen

php artisan sdui:preview HomeScreen

JSON Output Format

{
  "sdui": 1,
  "screen": {
    "id": "home",
    "title": "Welcome",
    "meta": {
      "version": "1.0"
    },
    "root": {
      "type": "stack",
      "props": {
        "direction": "vertical",
        "gap": 16
      },
      "children": [
        {
          "type": "text",
          "props": {
            "text": "Hello World",
            "bold": true,
            "variant": "heading"
          }
        },
        {
          "type": "button",
          "props": {
            "label": "Click Me",
            "variant": "primary"
          },
          "action": {
            "type": "navigate",
            "payload": {
              "route": "features"
            }
          }
        }
      ]
    }
  }
}

Testing

# Run all tests
composer test

# Run with coverage
XDEBUG_MODE=coverage composer test:coverage

# Run specific test
./vendor/bin/phpunit tests/Unit/ScreenTest.php

# Watch mode
composer test:watch

Test Coverage: 76+ tests covering all components, actions, and edge cases.

Available Components

  • Text - Display text with styling
  • Button - Interactive button with actions
  • Image - Display images with sizing
  • Stack - Vertical/horizontal layouts
  • Card - Contained content with styling
  • Badge - Labels and tags
  • Avatar - User profile pictures
  • Spacer - Add spacing between elements
  • Divider - Visual separators
  • ListItem - List entry components
  • StatGrid - Display statistics in a grid

Creating Custom Components

<?php

namespace App\SDUI\Components;

use SDUI\Components\Component;

final class CustomComponent extends Component
{
    private function __construct(string $title)
    {
        $this->props['title'] = $title;
    }

    public static function make(string $title): self
    {
        return new self($title);
    }

    protected function type(): string
    {
        return 'custom_component';
    }

    public function subtitle(string $text): self
    {
        return $this->prop('subtitle', $text);
    }
}

API Reference

Screen Methods

Method Description
make(string $id) Create a new screen
title(string $title) Set screen title
meta(string $key, mixed $value) Add metadata
add(Componentable|array $component) Add component(s)
addIf(bool $condition, Componentable $component) Conditionally add component
addMany(iterable $items, callable $mapper) Map collection to components
toArray(): array Convert to array
render(int $status = 200, array $headers = []): JsonResponse Render as JSON response

Component Methods

Method Description
make() Create component instance
prop(string $key, mixed $value) Set property
navigateTo(string $route, array $params = []) Navigate to route
openUrl(string $url, bool $inApp = false) Open URL
emit(string $event, mixed $data = null) Emit event
action(string $type, mixed $payload = null) Custom action
add(Componentable|array $component) Add child components
toArray(): array Convert to array

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

This library is open-sourced software licensed under the MIT license.

Changelog

See CHANGELOG.md for a detailed history of changes.

Support

For issues, questions, or suggestions, please open an issue on GitHub.