Tagixo Docs

Developer Documentation for Laravel, SDK integrations, and extensibility

Extending Tagixo

Custom PropTypes

Build a reusable group of design fields that emits its own CSS, registered alongside the built-in PropTypes.

Custom PropTypes

A custom PropType is the right tool when you need a reusable group of design fields plus consolidated CSS output that no built-in PropType covers. Typical triggers:

  • A multi-shadow stack PropType emitting compound box-shadow values
  • A "Box decoration" PropType bundling background + border + shadow as one ergonomic unit
  • A glassmorphism / neumorphism design preset wired into the design tab
  • A 3D-transform PropType with origin + perspective controls

If you only need a single field, build a Custom Prop instead.

Scaffold

php artisan make:tagixo-prop-type GlassmorphismPropType

Default destination: app/Tagixo/PropTypes/GlassmorphismPropType.php. Relocate globally via config('tagixo.scaffolding') or per-command with --path=/--namespace=/--package=.

Skeleton

The class extends Ccast\Tagixo\Core\PropTypes\AbstractPropType, which provides defaults and shared helpers like resolveColor().

<?php

namespace App\Tagixo\PropTypes;

use Ccast\Tagixo\Core\PropTypes\AbstractPropType;

class GlassmorphismPropType extends AbstractPropType
{
    public function key(): string
    {
        return 'glassmorphism';
    }

    public function label(): string
    {
        return __('Glassmorphism');
    }

    public function tab(): string
    {
        return 'design';
    }

    public function hasCss(): bool
    {
        return true;
    }

    public function schema(): array
    {
        return [];
    }

    public function toCss(array $values): string
    {
        return '';
    }
}

Concrete example

A GlassmorphismPropType that combines a translucent background, backdrop blur/brightness, and border radius into one design unit:

<?php

namespace App\Tagixo\PropTypes;

use Ccast\Tagixo\Core\PropTypes\AbstractPropType;
use Ccast\Tagixo\Core\Props\ColorProp;
use Ccast\Tagixo\Core\Props\SliderProp;

class GlassmorphismPropType extends AbstractPropType
{
    public function key(): string    { return 'glassmorphism'; }
    public function label(): string  { return __('Glassmorphism'); }
    public function tab(): string    { return 'design'; }
    public function hasCss(): bool   { return true; }

    public function schema(): array
    {
        return [
            ColorProp::make('background_color')
                ->setLabel(__('Background Color'))
                ->default('rgba(255, 255, 255, 0.1)')
                ->variablePicker('color'),
            SliderProp::make('backdrop_blur')
                ->setLabel(__('Backdrop Blur'))
                ->default(10)->min(0)->max(20)->step(0.5)->unit('px'),
            SliderProp::make('backdrop_brightness')
                ->setLabel(__('Backdrop Brightness'))
                ->default(100)->min(0)->max(200)->unit('%'),
            SliderProp::make('border_radius')
                ->setLabel(__('Border Radius'))
                ->default(8)->min(0)->max(50)->step(1)->unit('px'),
        ];
    }

    public function features(): array
    {
        return ['resetAll', 'resetField', 'preview'];
    }

    public function toCss(array $values): string
    {
        $rules = [];

        $bg = $values['background_color'] ?? null;
        if (! empty($bg)) {
            $rules[] = "background: {$bg};";
        }

        $filterParts = [];
        $blur = (float) ($values['backdrop_blur'] ?? 0);
        if ($blur > 0) $filterParts[] = "blur({$blur}px)";

        $brightness = (float) ($values['backdrop_brightness'] ?? 100);
        if ($brightness !== 100.0) $filterParts[] = "brightness({$brightness}%)";

        if (! empty($filterParts)) {
            $rules[] = "backdrop-filter: " . implode(' ', $filterParts) . ';';
        }

        $radius = (float) ($values['border_radius'] ?? 0);
        if ($radius > 0) {
            $rules[] = "border-radius: {$radius}px;";
        }

        return implode(' ', $rules);
    }
}

Required methods

Method Purpose
key(): string Registry key. Used in ModuleDefinition::design(...) to enable the PropType on a module.
label(): string Human-readable name shown in the drawer.
tab(): string One of 'content', 'design', 'advanced'. Controls which drawer tab the PropType appears in.
hasCss(): bool Return true for CSS-generating PropTypes โ€” the renderer collects only PropTypes that opt in.
schema(): array List of AbstractProp instances. The drawer renders one input per Prop.
toCss(array $values): string Return CSS declarations (no selector, no braces). The default toCssWithSelectors($values, $selector) wraps this output with the right selector.

Optional methods

Method Purpose
features(): array Toggle UI affordances: ['resetAll', 'resetField', 'preview'].
defaults(): array Auto-computed from schema(). Override if you need custom merging.
placeholders(): array Per-prop placeholder values for the drawer inputs.
vueComponent(): ?string Return a string to use a CUSTOM Vue component instead of the schema-driven renderer. This is the escape hatch when a PropType needs UI you can't express via Props (gradient builders, color-stop pickers, drag-to-position controls).

CSS generation idioms

  • Skip emission when value equals default to avoid CSS bloat โ€” see FilterPropType for the canonical pattern.
  • Compose multiple values into a single CSS property when the underlying spec is one (e.g. filter: brightness() blur()).
  • Use StyleGenerator helpers (StyleGenerator::backgroundToCss(), boxShadowToCss(), etc.) for shapes that the core already handles.
  • No selectors in toCss(): the wrapping is done by toCssWithSelectors(). Return just declarations.

Registration

Two ways:

// In config/tagixo.php
'prop_types' => [
    \App\Tagixo\PropTypes\GlassmorphismPropType::class,
],
// In any service provider's boot()
\Ccast\Tagixo\Facades\Tagixo::registerPropTypes([
    \App\Tagixo\PropTypes\GlassmorphismPropType::class,
]);

The scaffold command prints the right snippet for you when the file is created.

Frontend rendering

Schema-driven PropTypes render through DynamicPropType.vue automatically โ€” no Vue code needed when vueComponent() returns null. You only build a custom Vue component when the UX cannot be expressed via the built-in Prop widgets (slider, select, toggle, text, number, color, ...).

Testing checklist

  • PropType appears in the bootstrap payload (availableComponents.propTypeRegistry)
  • toCss() produces expected output for sensible value sets
  • Default values do NOT emit CSS (verify by inspecting render output)
  • Reset behaviour works in the drawer
  • Adding the PropType to a module via ->design(...) makes the tab section render without console errors