Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ Each Statamic fieldtype is mapped to a Livewire Forms field model. Models are re

For instance, all the fields of type `\Statamic\Fieldtypes\Select::class` are bound to the `\Aerni\LivewireForms\Fields\Select::class` model. A field property is created for each model method ending with `Property`, e.g. `optionsProperty()` will generate an `options` property.

If a fieldtype has no binding of its own, the binding of its closest parent fieldtype is used instead, e.g. Statamic's `YesNo` fieldtype (the underlying fieldtype of the `yes_no` form fieldtype) resolves to the model of the `Radio` fieldtype it extends.

To change a field's default model, simply change the binding in the `models` property in your component:

```php
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@
],
"require": {
"php": "^8.3",
"marcorieser/statamic-livewire": "^5.0",
"laravel/framework": "^12.0 || ^13.0",
"laravel/prompts": "^0.3.0",
"livewire/livewire": "^4.1",
"marcorieser/statamic-livewire": "^5.0",
"spatie/invade": "^2.0",
"statamic/cms": "^6.10"
"statamic/cms": "dev-forms-2 as 6.31.0"
},
"require-dev": {
"laravel/pint": "^1.27",
Expand Down
11 changes: 11 additions & 0 deletions config/livewire-forms.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,26 @@
Aerni\LivewireForms\Fieldtypes\Captcha::class => Aerni\LivewireForms\Fields\Captcha::class,
Statamic\Fieldtypes\Assets\Assets::class => Aerni\LivewireForms\Fields\Assets::class,
Statamic\Fieldtypes\Checkboxes::class => Aerni\LivewireForms\Fields\Checkboxes::class,
Statamic\Fieldtypes\Date::class => Aerni\LivewireForms\Fields\Date::class,
Statamic\Fieldtypes\Dictionary::class => Aerni\LivewireForms\Fields\Dictionary::class,
Statamic\Fieldtypes\Files::class => Aerni\LivewireForms\Fields\Files::class,
Statamic\Fieldtypes\FormHeading::class => Aerni\LivewireForms\Fields\FormHeading::class,
Statamic\Fieldtypes\FormUpload::class => Aerni\LivewireForms\Fields\FormUpload::class,
Statamic\Fieldtypes\Group::class => Aerni\LivewireForms\Fields\Group::class,
Statamic\Fieldtypes\Hidden::class => Aerni\LivewireForms\Fields\Hidden::class,
Statamic\Fieldtypes\Html::class => Aerni\LivewireForms\Fields\Html::class,
Statamic\Fieldtypes\ImageChoice::class => Aerni\LivewireForms\Fields\ImageChoice::class,
Statamic\Fieldtypes\Info::class => Aerni\LivewireForms\Fields\Info::class,
Statamic\Fieldtypes\Integer::class => Aerni\LivewireForms\Fields\Integer::class,
Statamic\Fieldtypes\OpinionScale::class => Aerni\LivewireForms\Fields\OpinionScale::class,
Statamic\Fieldtypes\Radio::class => Aerni\LivewireForms\Fields\Radio::class,
Statamic\Fieldtypes\Ranking::class => Aerni\LivewireForms\Fields\Ranking::class,
Statamic\Fieldtypes\Select::class => Aerni\LivewireForms\Fields\Select::class,
Statamic\Fieldtypes\Spacer::class => Aerni\LivewireForms\Fields\Spacer::class,
Statamic\Fieldtypes\StarRating::class => Aerni\LivewireForms\Fields\StarRating::class,
Statamic\Fieldtypes\Text::class => Aerni\LivewireForms\Fields\Text::class,
Statamic\Fieldtypes\Textarea::class => Aerni\LivewireForms\Fields\Textarea::class,
Statamic\Fieldtypes\Time::class => Aerni\LivewireForms\Fields\Time::class,
Statamic\Fieldtypes\Toggle::class => Aerni\LivewireForms\Fields\Toggle::class,
],

Expand Down
19 changes: 19 additions & 0 deletions resources/views/default/fields/banner.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<div id="{{ $field->id }}" class="flex items-start gap-x-3 p-4 bg-gray-50 border border-gray-200 rounded-md">
@if($field->icon)
<div class="w-6 h-6 shrink-0 text-gray-500 [&_svg]:w-full [&_svg]:h-full">
{!! $field->icon !!}
</div>
@endif

<div class="flex flex-col gap-y-1">
<h3 class="text-sm font-medium text-gray-900">
{{ $field->display }}
</h3>

@if($field->content)
<p class="text-sm text-gray-500">
{{ $field->content }}
</p>
@endif
</div>
</div>
33 changes: 33 additions & 0 deletions resources/views/default/fields/group.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<fieldset>
<div class="flex flex-col gap-y-3">
@formView('messages.legend')

@if($field->instructions && $field->instructions_position === 'above')
@formView('messages.instructions')
@endif

<div class="grid grid-cols-1 gap-4 md:grid-cols-12">
@foreach($field->fields() as $groupField)
<div
wire:key="{{ $groupField->id }}"
class="flex flex-col gap-y-2 col-span-1
{{ $groupField->width === 25 ? 'md:col-span-3' : '' }}
{{ $groupField->width === 33 ? 'md:col-span-4' : '' }}
{{ $groupField->width === 50 ? 'md:col-span-6' : '' }}
{{ $groupField->width === 66 ? 'md:col-span-8' : '' }}
{{ $groupField->width === 75 ? 'md:col-span-9' : '' }}
{{ $groupField->width === 100 ? 'md:col-span-12' : '' }}
"
>
@formView($groupField->view, ['field' => $groupField])
</div>
@endforeach
</div>

@if($errors->has($field->key))
@formView('messages.error')
@elseif($field->instructions && $field->instructions_position === 'below')
@formView('messages.instructions')
@endif
</div>
</fieldset>
11 changes: 11 additions & 0 deletions resources/views/default/fields/heading.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<div class="flex flex-col gap-y-1">
<h2 id="{{ $field->id }}" class="text-lg font-semibold text-gray-900">
{{ $field->display }}
</h2>

@if($field->subheading)
<p class="text-sm text-gray-500">
{{ $field->subheading }}
</p>
@endif
</div>
60 changes: 60 additions & 0 deletions resources/views/default/fields/image_choice.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
@php($columns = ['sm:grid-cols-1', 'sm:grid-cols-2', 'sm:grid-cols-3', 'sm:grid-cols-4'][$field->columns - 1] ?? 'sm:grid-cols-3')

<fieldset>
<div class="flex flex-col gap-y-3">
@formView('messages.legend')

@if($field->instructions && $field->instructions_position === 'above')
@formView('messages.instructions')
@endif

<div class="grid grid-cols-2 gap-3 {{ $columns }}">
@foreach($field->options as $option)
<div wire:key="{{ $field->id }}-{{ $option['key'] }}">
<input
id="{{ $field->id }}-{{ $option['key'] }}"
name="{{ $field->id }}"
value="{{ $option['key'] }}"
type="{{ $field->multiple ? 'checkbox' : 'radio' }}"
class="sr-only peer"

@if($field->wire_model)
wire:model.{{ $field->wire_model }}="{{ $field->key }}"
@else
wire:model="{{ $field->key }}"
@endif

@if($errors->has($field->key))
aria-invalid="true"
aria-describedby="{{ $field->id }}-error"
@elseif($field->instructions)
aria-describedby="{{ $field->id }}-instructions"
@endif
/>

<label
for="{{ $field->id }}-{{ $option['key'] }}"
class="flex flex-col gap-y-2 p-2 cursor-pointer border-2 rounded-md peer-checked:border-indigo-600 peer-focus:ring-2 peer-focus:ring-indigo-500 {{ $errors->has($field->key) ? 'border-red-300' : 'border-gray-200' }}"
>
@if($option['image'])
<img src="{{ $option['image'] }}" alt="" class="object-cover w-full rounded" style="aspect-ratio: {{ $field->aspect_ratio ?? '1 / 1' }}" />
@endif

<span class="flex items-center gap-x-2 text-sm font-medium text-gray-900">
<span class="flex items-center justify-center w-5 h-5 text-xs border border-gray-300 rounded">
{{ $option['letter'] }}
</span>
{{ $option['label'] }}
</span>
</label>
</div>
@endforeach
</div>

@if($errors->has($field->key))
@formView('messages.error')
@elseif($field->instructions && $field->instructions_position === 'below')
@formView('messages.instructions')
@endif
</div>
</fieldset>
59 changes: 59 additions & 0 deletions resources/views/default/fields/opinion_scale.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
<fieldset>
<div class="flex flex-col gap-y-3">
@formView('messages.legend')

@if($field->instructions && $field->instructions_position === 'above')
@formView('messages.instructions')
@endif

<div class="flex flex-col gap-y-2">
<div class="flex items-start flex-wrap gap-2">
@foreach($field->scale_values as $value)
<div wire:key="{{ $field->id }}-{{ $value }}">
<input
id="{{ $field->id }}-{{ $value }}"
name="{{ $field->id }}"
value="{{ $value }}"
type="radio"
class="sr-only peer"

@if($field->wire_model)
wire:model.{{ $field->wire_model }}="{{ $field->key }}"
@else
wire:model="{{ $field->key }}"
@endif

@if($errors->has($field->key))
aria-invalid="true"
aria-describedby="{{ $field->id }}-error"
@elseif($field->instructions)
aria-describedby="{{ $field->id }}-instructions"
@endif
/>

<label
for="{{ $field->id }}-{{ $value }}"
class="flex items-center justify-center w-10 h-10 text-sm font-medium cursor-pointer border rounded-md peer-checked:bg-indigo-600 peer-checked:border-indigo-600 peer-checked:text-white peer-focus:ring-2 peer-focus:ring-indigo-500 {{ $errors->has($field->key) ? 'text-red-800 border-red-300' : 'text-gray-900 border-gray-300' }}"
>
{{ $value }}
</label>
</div>
@endforeach
</div>

@if($field->low_label || $field->middle_label || $field->high_label)
<div class="flex justify-between text-[13px] text-gray-500">
<span>{{ $field->low_label }}</span>
<span>{{ $field->middle_label }}</span>
<span>{{ $field->high_label }}</span>
</div>
@endif
</div>

@if($errors->has($field->key))
@formView('messages.error')
@elseif($field->instructions && $field->instructions_position === 'below')
@formView('messages.instructions')
@endif
</div>
</fieldset>
9 changes: 9 additions & 0 deletions resources/views/default/fields/paragraph.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@if($field->html)
<div id="{{ $field->id }}" class="text-sm text-gray-700">
{!! $field->html !!}
</div>
@else
<p id="{{ $field->id }}" class="text-sm text-gray-700">
{{ $field->text }}
</p>
@endif
71 changes: 71 additions & 0 deletions resources/views/default/fields/ranking.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<fieldset>
<div class="flex flex-col gap-y-3">
@formView('messages.legend')

@if($field->instructions && $field->instructions_position === 'above')
@formView('messages.instructions')
@endif

<ol
id="{{ $field->id }}"
x-data="{
move(from, to) {
const order = [...$wire.fields['{{ $field->handle }}'].value];
order.splice(to, 0, order.splice(from, 1)[0]);
$wire.set('{{ $field->key }}', order);
}
}"
class="flex flex-col gap-y-2"
@if($errors->has($field->key))
aria-invalid="true"
aria-describedby="{{ $field->id }}-error"
@elseif($field->instructions)
aria-describedby="{{ $field->id }}-instructions"
@endif
>
@foreach($field->value ?? [] as $index => $key)
<li
wire:key="{{ $field->id }}-{{ $key }}"
class="flex items-center justify-between gap-x-3 px-3 py-2 bg-white border border-gray-300 rounded-md"
>
<span class="text-sm font-medium text-gray-900">
<span class="text-gray-400">{{ $index + 1 }}.</span>
{{ $field->options[$key] ?? $key }}
</span>

<span class="flex items-center gap-x-1">
<button
type="button"
class="p-1 text-gray-500 rounded hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 disabled:opacity-30"
aria-label="{{ __('Move up') }}"
x-on:click="move({{ $index }}, {{ $index - 1 }})"
@disabled($loop->first)
>
<svg class="w-4 h-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M10 17a.75.75 0 01-.75-.75V5.612L5.29 9.77a.75.75 0 01-1.08-1.04l5.25-5.5a.75.75 0 011.08 0l5.25 5.5a.75.75 0 11-1.08 1.04l-3.96-4.158V16.25A.75.75 0 0110 17z" clip-rule="evenodd" />
</svg>
</button>

<button
type="button"
class="p-1 text-gray-500 rounded hover:text-gray-900 focus:outline-none focus:ring-2 focus:ring-indigo-500 disabled:opacity-30"
aria-label="{{ __('Move down') }}"
x-on:click="move({{ $index }}, {{ $index + 1 }})"
@disabled($loop->last)
>
<svg class="w-4 h-4" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M10 3a.75.75 0 01.75.75v10.638l3.96-4.158a.75.75 0 111.08 1.04l-5.25 5.5a.75.75 0 01-1.08 0l-5.25-5.5a.75.75 0 111.08-1.04l3.96 4.158V3.75A.75.75 0 0110 3z" clip-rule="evenodd" />
</svg>
</button>
</span>
</li>
@endforeach
</ol>

@if($errors->has($field->key))
@formView('messages.error')
@elseif($field->instructions && $field->instructions_position === 'below')
@formView('messages.instructions')
@endif
</div>
</fieldset>
68 changes: 68 additions & 0 deletions resources/views/default/fields/star_rating.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
@formView('messages.display')

@if($field->instructions && $field->instructions_position === 'above')
@formView('messages.instructions')
@endif

<div
id="{{ $field->id }}"
x-data="{ value: @js((float) ($field->value ?? 0)), hover: null }"
x-on:mouseleave="hover = null"
x-on:form-success.window="value = 0"
class="flex items-center gap-x-1"
role="radiogroup"
@if($errors->has($field->key))
aria-invalid="true"
aria-describedby="{{ $field->id }}-error"
@elseif($field->instructions)
aria-describedby="{{ $field->id }}-instructions"
@endif
>
@foreach(range(1, $field->max_stars) as $star)
<div wire:key="{{ $field->id }}-{{ $star }}" class="relative w-6 h-6">
<svg class="w-6 h-6 text-gray-300" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M10 2l2.47 5.007 5.53.803-4 3.9.944 5.505L10 14.615l-4.944 2.6L6 11.71l-4-3.9 5.53-.803L10 2z" clip-rule="evenodd" />
</svg>

<div
class="absolute inset-0 overflow-hidden text-yellow-400"
x-bind:style="{ width: ((hover ?? value) >= {{ $star }} ? 100 : (hover ?? value) >= {{ $star - 0.5 }} ? 50 : 0) + '%' }"
>
<svg class="w-6 h-6" viewBox="0 0 20 20" fill="currentColor" aria-hidden="true">
<path fill-rule="evenodd" d="M10 2l2.47 5.007 5.53.803-4 3.9.944 5.505L10 14.615l-4.944 2.6L6 11.71l-4-3.9 5.53-.803L10 2z" clip-rule="evenodd" />
</svg>
</div>

@foreach($field->step == 0.5 ? [$star - 0.5, $star] : [$star] as $rating)
<label
for="{{ $field->id }}-{{ $rating }}"
class="absolute inset-y-0 cursor-pointer {{ $field->step == 0.5 ? 'w-1/2 '.($loop->first ? 'left-0' : 'right-0') : 'inset-x-0' }}"
x-on:mouseenter="hover = {{ $rating }}"
>
<span class="sr-only">{{ $rating }}</span>

<input
id="{{ $field->id }}-{{ $rating }}"
name="{{ $field->id }}"
value="{{ $rating }}"
type="radio"
class="sr-only"
x-on:change="value = {{ $rating }}"

@if($field->wire_model)
wire:model.{{ $field->wire_model }}="{{ $field->key }}"
@else
wire:model="{{ $field->key }}"
@endif
/>
</label>
@endforeach
</div>
@endforeach
</div>

@if($errors->has($field->key))
@formView('messages.error')
@elseif($field->instructions && $field->instructions_position === 'below')
@formView('messages.instructions')
@endif
Loading
Loading