Skip to content
This repository was archived by the owner on Mar 18, 2025. It is now read-only.
Merged
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
15 changes: 15 additions & 0 deletions config/form-components.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,16 @@
'clear_icon' => 'heroicon-o-x-circle',
],

'file-upload' => [
'class' => Components\Files\FileUpload::class,
'view' => 'form-components::components.files.file-upload',
],

'file-pond' => [
'class' => Components\Files\FilePond::class,
'view' => 'form-components::components.files.file-pond',
],

],

/*
Expand Down Expand Up @@ -171,6 +181,11 @@
'https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css',
'https://cdnjs.cloudflare.com/ajax/libs/flatpickr/4.6.3/flatpickr.min.js',
],

'filepond' => [
'https://unpkg.com/filepond/dist/filepond.css',
'https://unpkg.com/filepond/dist/filepond.js',
],
],

];
1 change: 1 addition & 0 deletions resources/sass/form-components.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
@import 'utils/choice';
@import 'utils/addon';
@import 'utils/flatpickr';
@import 'utils/files';
83 changes: 83 additions & 0 deletions resources/sass/utils/_files.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
.file-upload {
@apply flex;
@apply items-center;
}

.file-upload__input {
@apply rounded-md;
}

.file-upload__label {
@apply cursor-pointer;
@apply py-2;
@apply px-3;
@apply border;
@apply border-gray-300;
@apply rounded-md;
@apply text-sm;
@apply leading-4;
@apply font-medium;
@apply text-cool-gray-700;
@apply transition;
@apply duration-150;
@apply ease-in-out;
@apply shadow-sm;

&:hover {
@apply text-cool-gray-500;
}

&:active {
@apply bg-gray-50;
@apply text-cool-gray-800;
}

[role="button"] {
@apply outline-none;
}
}

.file-upload__label--focused {
@apply outline-none;
@apply border-blue-300;
@apply shadow-outline-blue;
}

// FilePond style overrides
/* purgecss start ignore */
.filepond--panel-root {
@apply border-dashed;
@apply border-2;
@apply border-cool-gray-200;
@apply rounded-md;
}

.filepond--panel-root {
@apply bg-transparent;
@apply max-w-lg;
@apply transition;
@apply duration-150;
@apply ease-in-out;
}

.filepond--label-action {
@apply text-blue-600;
text-decoration-color: theme('colors.blue.600');
@apply transition;
@apply duration-100;
@apply ease-in-out;

&:hover,
&:focus {
@apply opacity-75;
}
}

.fc-filepond--desc {
@apply text-cool-gray-500;
}

.fc-filepond--sub-desc {
@apply text-xs #{!important};
}
/* purgecss end ignore */
30 changes: 30 additions & 0 deletions resources/views/components/files/file-pond.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<div wire:ignore
x-data
x-cloak
x-init="
{{ $plugins ?? '' }}
FilePond.setOptions({
{{ $jsonOptions() }}
{{-- Enhance for livewire support --}}
@if ($attributes->whereStartsWith('wire:model')->first())
server: {
process: (fieldName, file, metadata, load, error, progress, abort, transfer, options) => {
@this.upload('{{ $attributes['wire:model'] }}', file, load, error, progress);
},
revert: (filename, load) => {
@this.removeUpload('{{ $attributes['wire:model'] }}', filename, load);
},
},
@endif
{{ $optionsSlot ?? '' }}
});
FilePond.create($refs.input);
"
>
<input x-ref="input"
type="file"
style="display:none;"
@if ($accepts()) accept="{{ $accepts() }}" @endif
{{ $attributes->except('wire:model') }}
/>
</div>
74 changes: 74 additions & 0 deletions resources/views/components/files/file-upload.blade.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
<div class="file-upload space-x-5 {{ $attributes['class'] ?? '' }}">
{{ $slot }}

<div x-data="{ focused: false, isUploading: false, progress: 0 }"
@if ($canShowUploadProgress($attributes))
x-on:livewire-upload-start="isUploading = true"
x-on:livewire-upload-finish="isUploading = false"
x-on:livewire-upload-error="isUploading = false"
x-on:livewire-upload-progress="progress = $event.detail.progress"
@endif
class="space-y-4 w-full"
>
<span class="file-upload__input">
<input x-on:focus="focused = true"
x-on:blur="focused = false"
class="sr-only"
type="file"
@if ($multiple) multiple @endif
name="{{ $name }}"
@if ($id) id="{{ $id }}" @endif
@if ($accepts()) accept="{{ $accepts() }}" @endif

@if ($hasErrorsAndShow($name))
aria-invalid="true"

@if (! $attributes->offsetExists('aria-describedby'))
aria-describedby="{{ $id }}-error"
@endif
@endif

{{ $attributes->except('class') }}
/>

<label for="{{ $id }}"
x-bind:class="{ 'file-upload__label--focused': focused }"
class="file-upload__label"
>
<span role="button"
aria-controls="{{ $id }}"
tabindex="0"
>
{{ $label }}
</span>
</label>
</span>

{{-- Upload progress --}}
@if ($canShowUploadProgress($attributes))
<div class="relative" x-show.transition.opacity.duration.150ms="isUploading" x-cloak>
<div class="flex mb-2 items-center justify-between">
<div class="file-upload__badge inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium leading-4 bg-green-100 text-green-800">
{{ __('Processing...') }}
</div>

<div class="text-right">
<span class="text-xs font-semibold inline-block text-green-600"
x-text="progress + '%'"
>
</span>
</div>
</div>

<div class="file-upload__progress overflow-hidden h-2 mb-4 text-xs flex rounded bg-green-200">
<div class="shadow-none flex flex-col text-center whitespace-nowrap text-white justify-center bg-green-500"
x-bind:style="'width: ' + progress + '%;'"
>
</div>
</div>
</div>
@endif
</div>

{{ $after ?? '' }}
</div>
84 changes: 84 additions & 0 deletions src/Components/Files/FilePond.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

declare(strict_types=1);

namespace Rawilk\FormComponents\Components\Files;

use Rawilk\FormComponents\Components\BladeComponent;
use Rawilk\FormComponents\Concerns\AcceptsFiles;
use Rawilk\FormComponents\Concerns\HandlesValidationErrors;

class FilePond extends BladeComponent
{
use HandlesValidationErrors;
use AcceptsFiles;

protected static array $assets = ['alpine', 'filepond'];

public bool $multiple;
public bool $allowDrop;
public bool $disabled;
public array $options;

/** @var string|null */
public $name;

/** @var int|null */
public $maxFiles;

/** @var string|null */
public $description;

public function __construct(
bool $multiple = false,
bool $allowDrop = true,
string $name = null,
array $options = [],
bool $disabled = false,
int $maxFiles = null,
string $type = null,
string $description = null
) {
$this->multiple = $multiple;
$this->allowDrop = $allowDrop;
$this->name = $name;
$this->disabled = $disabled;
$this->maxFiles = $maxFiles;
$this->type = $type;
$this->options = $options;
$this->description = $description;
}

public function options(): array
{
$label = array_filter([
'<span class="filepond--label-action">Upload a file</span> or drag and drop',
$this->description,
]);

if (isset($label[1])) {
$label[1] = '<span class="fc-filepond--sub-desc">' . $label[1] . '</span>';
}

$defaultOptions = [
'allowMultiple' => $this->multiple,
'allowDrop' => $this->allowDrop,
'disabled' => $this->disabled,
] + array_filter([
'maxFiles' => $this->multiple && $this->maxFiles ? $this->maxFiles : null,
'name' => $this->name,
'labelIdle' => '<span class="fc-filepond--desc">' . implode('<br>', $label) . '</span>',
]);

return array_merge($defaultOptions, $this->options);
}

public function jsonOptions(): string
{
if (empty($this->options())) {
return '';
}

return '...' . json_encode((object) $this->options()) . ',';
}
}
71 changes: 71 additions & 0 deletions src/Components/Files/FileUpload.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
<?php

declare(strict_types=1);

namespace Rawilk\FormComponents\Components\Files;

use Rawilk\FormComponents\Components\BladeComponent;
use Rawilk\FormComponents\Concerns\AcceptsFiles;
use Rawilk\FormComponents\Concerns\HandlesValidationErrors;

class FileUpload extends BladeComponent
{
use HandlesValidationErrors;
use AcceptsFiles;

protected static array $assets = ['alpine'];

/** @var string */
public $name;

/** @var string */
public $id;

/** @var string */
public $label;

public bool $multiple;

/*
* Display the file upload progress if using livewire.
* Only applies if a "wire:model" attribute is set.
*/
public bool $displayUploadProgress;

protected ?bool $canShowUploadProgress = null;

public function __construct(
string $name = null,
string $id = null,
string $label = 'Select File',
bool $multiple = false,
string $type = null,
bool $displayUploadProgress = true,
bool $showErrors = true
) {
$this->name = $name;
$this->id = $id ?? $name;
$this->multiple = $multiple;
$this->label = $label;
$this->displayUploadProgress = $displayUploadProgress;
$this->showErrors = $showErrors;
$this->type = $type;
}

public function canShowUploadProgress($attributes)
{
if (! is_null($this->canShowUploadProgress)) {
return $this->canShowUploadProgress;
}

if (! $this->displayUploadProgress) {
return $this->canShowUploadProgress = false;
}

if (! $attributes->whereStartsWith('wire:model')->first()) {
return $this->canShowUploadProgress = false;
}

return $this->canShowUploadProgress = true;
}
}
Loading