Global Component Configuration 之後是接續 Macros 跟 review base component 由於之前已經有針對 Macro 深入理解過,這邊就直接進入構建自定義欄位。

要把 https://iro.js.org/ 整合到自訂欄位內: 創建自訂欄位

$ php artisan make:form-field ColorPicker
//創建 demo form
$ php artisan make:livewire-form DemoForm

開啟 color-picker.blade.php 將 iro.js CDN 掛入並且 new instance:

<script src="https://cdn.jsdelivr.net/npm/@jaames/iro@5"></script>
<x-dynamic-component
    :component="$getFieldWrapperView()"
    :field="$field"
>
// alpine.js x-*
    <div x-data="{ state: $wire.$entangle('{{ $getStatePath() }}') }"
    x-init="
    const colorPicker = new iro.ColorPicker($refs.picker);
    ">
        <div x-ref="picker"></div> // 配置 ref
    </div>
</x-dynamic-component>

添加忽略 wire:ignore 防止 livewire refresh 頁面

<div wire:ignore x-ref="picker"></div>

DemoForm 嘗試添加組件:

ColorPicker::make('color1')

添加 default

ColorPicker::make('color1')->default('#ff0000')

color-picker.blade.php 進行 state 綁定:

const colorPicker = new iro.ColorPicker($refs.picker, {
        color: state
    });
// 監聽 picker 顏色如果改變則更新 state

colorPicker.on('color:change', (color) => {
        state = color.hexString;
    });

添加額外方法 width

class ColorPicker extends Field
{
    protected int | \Closure | null $width = null;

    public function width(int | \Closure | null $width): static
    {
        $this->width = $width;

        return $this;
    }

    public function getWidth(): ?int
    {
        return $this->evaluate($this->width);
    }

color-picker.blade.php 進行混合綁定:

<div x-data="{ state: $wire.$entangle('{{ $getStatePath() }}') }"
    x-init="
    const colorPicker = new iro.ColorPicker($refs.picker, {
        @if($getWidth())
            width: @js($getWidth()),
        @endif
        color: state
    });
    colorPicker.on('color:change', (color) => {
        state = color.hexString;
    });
    ">
ColorPicker::make('color1')
    ->default('#ff0000')
    ->width(200),

ColorPicker::make('color2')
    ->default('#000000')
    ->width(50),