Skip to content

Fields

Un Field describe una columna del modelo: tipo, label, validación, visibilidad, dependencias. Arqel incluye 21 tipos de Field canónicos con un mapeo 1:1 entre PHP (packages/fields) y React (@arqel-dev/fields).

Lo mínimo

php
use Arqel\Fields\FieldFactory as Field;

public function fields(): array
{
    return [
        Field::text('name')->required(),
        Field::email('email')->required()->unique(User::class, 'email'),
        Field::password('password')->required()->minLength(8),
    ];
}
FactoryClaseComponente (React)Caso de uso
Field::text(name)TextFieldTextInputStrings cortos
Field::textarea(name)TextareaFieldTextareaInputTexto multi-línea
Field::email(name)EmailFieldEmailInputEmail con regla email
Field::url(name)UrlFieldUrlInputURL con regla url
Field::password(name)PasswordFieldPasswordInputContraseña con toggle de revelar
Field::slug(name)SlugFieldSlugInputSlug normalizado
Field::number(name)NumberFieldNumberInputEnteros/decimales con stepper
Field::currency(name)CurrencyFieldCurrencyInputDinero con formato Intl
Field::boolean(name)BooleanFieldCheckboxTrue/false como checkbox
Field::toggle(name)ToggleFieldToggleTrue/false como switch
Field::select(name)SelectFieldSelectInputPicker de un solo valor
Field::multiSelect(name)MultiSelectFieldMultiSelectInputPicker multi-valor (chips)
Field::radio(name)RadioFieldRadioGroupPicker de un solo valor como radio
Field::belongsTo(name, Resource)BelongsToFieldBelongsToInputForeign key (combobox async)
Field::hasMany(name, Resource)HasManyFieldHasManyReadonlyLista readonly (Fase 1)
Field::date(name)DateFieldDateInputFecha nativa
Field::dateTime(name)DateTimeFieldDateTimeInputDatetime nativo
Field::file(name)FileFieldFileInputUpload con drag-drop
Field::image(name)ImageFieldImageInputUpload con preview
Field::color(name)ColorFieldColorInputColor picker + presets
Field::hidden(name)HiddenFieldHiddenInput<input type=hidden>

API fluida común

Setters disponibles en todos los Fields (vía los traits HasValidation, HasVisibility, HasDependencies, HasAuthorization):

php
Field::text('title')
    ->label('Article title')
    ->placeholder('e.g. "Why Arqel beats Filament"')
    ->helperText('Appears as `<title>` on the public page')
    ->required()
    ->maxLength(200)
    ->minLength(3)
    ->columnSpan(2)            // grid span
    ->columnSpanFull()         // span = form columns
    ->disabled()               // o disabled(fn($record) => $record?->locked)
    ->readonly()
    ->dehydrated(false)        // no serializa al guardar
    ->live()                   // re-renderiza el form en cada tecla
    ->liveDebounced(300)       // debounce en ms
    ->afterStateUpdated(fn ($state, $set) => $set('slug', Str::slug($state)));

Validación

Reglas nativas de Laravel:

php
Field::text('email')
    ->required()
    ->rule('email')
    ->unique(User::class, 'email')
    ->validationAttribute('email address')
    ->validationMessage('That email is already registered.');

Cada Field expone getValidationRules(), usado por el FormRequestGenerator (php artisan arqel:form-request) para generar Store{Model}Request/Update{Model}Request. En el cliente, ValidationBridge traduce las reglas a un schema Zod (z.string().email().min(1).max(255).nullable()) — útil para validación en tiempo real si la quieres.

Visibilidad

php
Field::text('internal_note')
    ->hiddenOnTable()                   // oculto en el index
    ->hiddenOnDetail()                  // oculto en el show
    ->visibleOn(['edit'])               // solo edit
    ->visibleIf(fn ($record) => $record?->is_admin);

4 contextos: create, edit, detail, table. visibleIf y hiddenIf son mutuamente excluyentes.

Dependencias

php
Field::select('country')
    ->options(Country::pluck('name', 'id')->toArray()),

Field::select('state')
    ->dependsOn(['country'])
    ->resolveOptionsUsing(fn ($state) =>
        State::where('country_id', $state['country'] ?? null)->pluck('name', 'id')->toArray()
    ),

Arqel ejecuta un partial reload de Inertia (only: ['fields.state.options']) con un debounce de 300ms cuando country cambia — sin TanStack Query.

Autorización

php
Field::text('salary')
    ->canSee(fn ($user, $record) => $user?->hasRole('hr'))
    ->canEdit(fn ($user, $record) => $user?->id === $record?->user_id);

La auth a nivel de Field es solo de UX — el servidor siempre re-valida vía Policies. Ver Auth.

Currency PT-BR

php
Field::currency('price')
    ->prefix('R$ ')
    ->thousandsSeparator('.')
    ->decimalSeparator(',')
    ->decimals(2);

Muestra R$ 1.234,56 en el cliente; serializa como 1234.56 al backend.

Macros

Acorta configuraciones repetidas vía FieldFactory::macro:

php
// AppServiceProvider::boot
Field::macro('priceBRL', fn (string $name) =>
    Field::currency($name)
        ->prefix('R$ ')
        ->thousandsSeparator('.')
        ->decimalSeparator(',')
);

// uso
Field::priceBRL('price')->required(),

Field personalizado

Ver Custom Fields para crear un nuevo tipo (clase PHP + componente React + registro).

Anti-patrones

  • Field::text('email') — usa Field::email('email') para heredar la regla email automáticamente
  • Validación solo del servidor ignorada en el cliente — reglas como confirmed, password, current_password son saltadas por ValidationBridge (server-only por diseño)
  • Hardcodear colores en un Field — usa las CSS vars de @arqel-dev/ui

Próximos pasos

Licencia MIT — construido con Inertia + React + Laravel.