268 lines
13 KiB
PHP
268 lines
13 KiB
PHP
@props([
|
|
// name to uniquely identity a select
|
|
'name' => 'bw-select-'.uniqid(),
|
|
|
|
// the default text to display when the select shows
|
|
'placeholder' => config('bladewind.select.placeholder', 'Select One'),
|
|
'search_placeholder' => config('bladewind.select.search_placeholder', 'Type here...'),
|
|
'empty_placeholder' => config('bladewind.select.empty_placeholder', 'No options available'),
|
|
'label' => config('bladewind.select.label', null),
|
|
|
|
/**
|
|
* Optional function to execute when a select item is selected.
|
|
* By default, the value of a select item is written to an input field with the name dd_name.
|
|
* Where name is the name you provided for the select. If you named your select <countries> for example,
|
|
* whatever country is selected can be found in the <input type="hidden" clas="input-countries" name="dd_countries" />
|
|
*/
|
|
'onselect' => '',
|
|
|
|
/**
|
|
* Data to pass to the select.
|
|
* Your data must be a json string (not object) with the keys <value> and <label>
|
|
* <value> is whatever value will be passed to your code when an item is selected
|
|
* <label> is what will be displayed to the user
|
|
* If you want to display icons for each item your json can contain the optional 'icon' key.
|
|
* Where icons are required, they must be in the semantic UI icon format
|
|
* [{"label":"Burkina Faso","icon":"bf flag","value":"+226"},{"label":"Ghana","icon":"gh flag","value":"+233"},{"label":"Ivory Coast","icon":"ivc flag","value":"+228"}]
|
|
* */
|
|
'data' => [],
|
|
|
|
/**
|
|
* What key in your data array should be used to populate 'value' of the select when an item is selected
|
|
* By default, a key of 'value' is used. If your data is something like
|
|
* [ {"id": 1,"name": "Burkina Faso"} ], your value_key will be 'id'
|
|
*/
|
|
'value_key' => 'value',
|
|
'valueKey' => 'value',
|
|
|
|
/**
|
|
* What key in your data array should be used to display the labels the user will see as select items
|
|
* The default key used for labels is 'label'. If your data is something like
|
|
* [ {"id": 1,"name": "Burkina Faso"} ] your label_key will be 'name'
|
|
*/
|
|
'label_key' => 'label',
|
|
'labelKey' => 'label',
|
|
|
|
/**
|
|
* What key in your data array should be used to display flag icons next to the labels
|
|
* [ {"id": 1, "name": "Burkina Faso", "flag": "/assets/images/bf-flag.png"} ] your flag_key will be 'flag'
|
|
*/
|
|
'flag_key' => null,
|
|
'flagKey' => null,
|
|
|
|
/**
|
|
* What key in your data array should be used to display images next to the labels
|
|
* The default key used for images is '', meaning images will be ignored. If your data is something like
|
|
* [ {"id":"1","name":"Burkina Faso", "image":"/assets/images/bf-flag.png"}] your image_key will be 'image'
|
|
*/
|
|
'image_key' => null,
|
|
'imageKey' => null,
|
|
|
|
/**
|
|
* There are instances when you want the name passed during form submission to be
|
|
* different from the name you gave the component. Example. you may name the select as country but
|
|
* want the data to be submitted as country_id.
|
|
*/
|
|
'data_serialize_as' => '',
|
|
'dataSerializeAs' => '',
|
|
|
|
// enforces validation if set to true
|
|
'required' => 'false',
|
|
|
|
'disabled' => 'false',
|
|
|
|
'readonly' => 'false',
|
|
|
|
'multiple' => 'false',
|
|
|
|
// adds margin after the input box
|
|
'add_clearing' => config('bladewind.select.add_clearing', true),
|
|
'addClearing' => config('bladewind.select.add_clearing', true),
|
|
|
|
/**
|
|
* Determines if a value passed in the data array should automatically be selected
|
|
* Helpful when using the component in edit mode or as part of filter options
|
|
* The value you specify should exist in your value_key. If your value_key is 'id', you
|
|
* cannot set a selected_value of 'Burkina Faso'
|
|
*/
|
|
'selected_value' => '',
|
|
'selectedValue' => '',
|
|
|
|
// setting this to true adds a search box above the select items
|
|
// this can be used to filter the contents of the select items
|
|
'searchable' => false,
|
|
|
|
// specify the maximum number of items that can be selected
|
|
'max_selectable' => -1,
|
|
'maxSelectable' => -1,
|
|
|
|
// error message to display when max_selectable is exceeded
|
|
'max_error_message' => config('bladewind.select.max_error_message', 'Please select only %s items'),
|
|
'maxErrorMessage' => config('bladewind.select.max_error_message', 'Please select only %s items'),
|
|
|
|
'filter' => '',
|
|
|
|
'filter_by' => '',
|
|
|
|
// append type="module" to script tags
|
|
'modular' => config('bladewind.select.modular', false),
|
|
|
|
'size' => config('bladewind.select.size', 'medium'),
|
|
|
|
'empty_state' => 'false',
|
|
'empty_state_message' => config('bladewind.select.empty_placeholder', 'No options available'),
|
|
'empty_state_button_label' => 'Add',
|
|
'empty_state_onclick' => '',
|
|
'empty_state_show_image' => 'true',
|
|
'empty_state_image' => config('bladewind.empty_state.image', '/vendor/bladewind/images/empty-state.svg'),
|
|
'meta' => null,
|
|
|
|
])
|
|
@php
|
|
$add_clearing = parseBladewindVariable($add_clearing);
|
|
$addClearing = parseBladewindVariable($addClearing);
|
|
$searchable = parseBladewindVariable($searchable);
|
|
$required = parseBladewindVariable($required);
|
|
$readonly = parseBladewindVariable($readonly);
|
|
$disabled = parseBladewindVariable($disabled);
|
|
$empty_state = parseBladewindVariable($empty_state);
|
|
$max_selectable = (int) $max_selectable;
|
|
$maxSelectable = (int) $maxSelectable;
|
|
|
|
if ($dataSerializeAs !== $data_serialize_as) $data_serialize_as = $dataSerializeAs;
|
|
if ($selectedValue !== $selected_value) $selected_value = $selectedValue;
|
|
if ($valueKey !== $value_key) $value_key = $valueKey;
|
|
if ($labelKey !== $label_key) $label_key = $labelKey;
|
|
if ($flagKey !== $flag_key) $flag_key = $flagKey;
|
|
if ($imageKey !== $image_key) $image_key = $imageKey;
|
|
if (!$add_clearing) $add_clearing = $addClearing;
|
|
if ($maxSelectable !== $max_selectable) $max_selectable = $maxSelectable;
|
|
$max_error_message = ($maxErrorMessage != $max_error_message) ? addslashes($maxErrorMessage) : addslashes($max_error_message);
|
|
if($max_error_message == '') $max_error_message = 'Please select only %s items';
|
|
|
|
$input_name = preg_replace('/[\s-]/', '_', $name);
|
|
$filter = preg_replace('/[\s-]/', '_', $filter);
|
|
$selected_value = ($selected_value != '') ? explode(',', str_replace(', ', ',', $selected_value)) : [];
|
|
|
|
if ($data !== 'manual') {
|
|
$data = (!is_array($data)) ? json_decode(str_replace('"', '"', $data), true) : $data;
|
|
// if $data is empty there is no point to show the search bar even if user asked for it
|
|
if($searchable && empty($data)) {
|
|
$searchable = false;
|
|
}
|
|
}
|
|
|
|
$size = (!in_array($size, ['small','medium', 'regular', 'big'])) ? 'medium' : $size;
|
|
$sizes = [ 'small' => 'py-[6px]', 'medium' => 'py-[10px]', 'regular' => 'py-[6.5px]', 'big' => 'py-[18.5px]' ];
|
|
@endphp
|
|
<style xmlns:x-bladewind="http://www.w3.org/1999/html">
|
|
.display-area::-webkit-scrollbar {
|
|
display: none;
|
|
width: 0 !important;
|
|
}
|
|
|
|
.display-area {
|
|
scrollbar-width: none;
|
|
-ms-overflow-style: none;
|
|
scroll-behavior: smooth;
|
|
}
|
|
</style>
|
|
<div class="relative bw-select bw-select-{{$input_name}} @if($add_clearing) mb-3 @endif"
|
|
role="combobox"
|
|
data-multiple="{{$multiple}}" data-required="{{$required?'true':'false'}}"
|
|
data-type="{{ $data !== 'manual' ? 'dynamic' : 'manual'}}"
|
|
@if(!empty($filter)) data-filter="{{ $filter}}" @endif
|
|
@if(!empty($meta)) data-meta-data="{{ $meta}}" @endif
|
|
@if($data == 'manual' && $selected_value != '') data-selected-value="{{implode(',',$selected_value)}}" @endif>
|
|
<div tabindex="0"
|
|
class="flex justify-between text-sm items-center rounded-md bg-white text-slate-600 border-2 border-slate-300/50 hover:border-slate-300
|
|
dark:text-dark-300 dark:border-dark-600 dark:hover:border-dark-500/50 dark:bg-transparent {{$sizes[$size]}} pl-4 pr-2 clickable
|
|
@if($disabled) disabled @elseif($readonly) readonly @else enabled @endif">
|
|
<x-bladewind::icon name="chevron-left" class="!-ml-3 hidden scroll-left"/>
|
|
<div class="text-left placeholder grow-0 text-blue-900/40 dark:text-slate-500">
|
|
@if(!empty($label))
|
|
<span class="form-label !top-4">{{$label}}
|
|
@if($required)
|
|
<x-bladewind::icon name="star" class="!text-red-400 !w-2 !h-2 mt-[-2px]" type="solid"/>
|
|
@endif</span>
|
|
@else
|
|
{{ $placeholder }}
|
|
@if($required)
|
|
<x-bladewind::icon name="star" class="!text-red-400 !w-2 !h-2 mt-[-2px]" type="solid"/>
|
|
@endif
|
|
@endif
|
|
</div>
|
|
<div class="text-left grow display-area hidden whitespace-nowrap overflow-x-scroll p-0 m-0"></div>
|
|
<div class="whitespace-nowrap inline-flex">
|
|
<x-bladewind::icon name="chevron-right" class="scroll-right !-mr-2 !mt-0.5 !w-5 !h-5 hidden"/>
|
|
<x-bladewind::icon
|
|
name="x-circle" type="solid"
|
|
class="hidden reset size-6 text-white fill-gray-400/70 hover:fill-gray-400 dark:fill-white/40 dark:hover:fill-white/60"/>
|
|
<x-bladewind::icon name="chevron-up-down" class="opacity-40 opener !ml-2"/>
|
|
</div>
|
|
</div>
|
|
<div class="w-full absolute z-30 rounded-br-lg rounded-bl-lg bg-white shadow-sm shadow-slate-400 dark:shadow-none border-2
|
|
border-blue-400 dark:text-slate-300 dark:border-dark-600 dark:bg-dark-700 border-t-0 -mt-1.5
|
|
hidden bw-select-items-container overflow-scroll max-h-64 animate__animated animate__fadeIn animate__faster">
|
|
<div class="sticky top-0 min-w-full bg-slate-100 dark:bg-transparent py-1 pr-0 -pl-1 @if(!$searchable) hidden @endif">
|
|
<x-bladewind::input
|
|
class="!border-0 !border-b !rounded-none focus:!border-slate-300 dark:focus:!border-slate-600 !w-full !text-sm bw_search"
|
|
add_clearing="false"
|
|
:placeholder="$search_placeholder"
|
|
suffix="magnifying-glass"
|
|
suffixIsIcon="true"/>
|
|
</div>
|
|
<div class="divide-y divide-slate-100 dark:divide-slate-600/70 bw-select-items mt-0">
|
|
@if($data !== 'manual')
|
|
@forelse ($data as $item)
|
|
<x-bladewind::select-item
|
|
label="{{ $item[$label_key] }}"
|
|
value="{{ $item[$value_key] }}"
|
|
filter_by="{{ ($filter_by != '') ? $item[$filter_by] : '' }}"
|
|
onselect="{{ $onselect }}"
|
|
flag="{{ $item[$flag_key] ?? '' }}"
|
|
image="{{ $item[$image_key] ?? '' }}"
|
|
selected="{{ (in_array($item[$value_key], $selected_value)) ? 'true' : 'false' }}"/>
|
|
@empty
|
|
@if($empty_state)
|
|
<x-bladewind::select-item
|
|
:selectable="false"
|
|
:empty_state="true"
|
|
:empty_state_message="$empty_state_message"
|
|
:empty_state_show_image="$empty_state_show_image"
|
|
:empty_state_button_label="$empty_state_button_label"
|
|
empty_state_onclick="{!! $empty_state_onclick !!}"
|
|
:empty_state_image="$empty_state_image"/>
|
|
@else
|
|
<x-bladewind::select-item
|
|
:selectable="false"
|
|
:label="$empty_placeholder"
|
|
/>
|
|
@endif
|
|
@endforelse
|
|
@else
|
|
{!! $slot !!}
|
|
@endif
|
|
</div>
|
|
</div>
|
|
<input type="hidden" name="{{ ($data_serialize_as !== '') ? $data_serialize_as : $input_name }}"
|
|
class="bw-{{$input_name}} @if($required) required @endif"
|
|
@if($required) data-parent="bw-select-{{$input_name}}" @endif
|
|
@if($multiple) autocomplete="off" @endif />
|
|
</div>
|
|
|
|
<script>
|
|
@php include_once(public_path('vendor/bladewind/js/select.js')); @endphp
|
|
</script>
|
|
<script @if($modular) type="module" @endif>
|
|
const bw_{{ $input_name }} = new BladewindSelect('{{ $input_name }}', '{{ $placeholder }}');
|
|
bw_{{ $input_name }}.activate({disabled: '{{$disabled}}', readonly: '{{$readonly}}'});
|
|
@if(!$disabled && !$readonly)
|
|
bw_{{ $input_name }}.maxSelectable({{$max_selectable}}, '{{ sprintf($max_error_message, $max_selectable) }}');
|
|
@endif
|
|
@if(!empty($filter))
|
|
bw_{{ $input_name }}.filter('{{ $filter }}');
|
|
@endif
|
|
@if(!$required && $multiple == 'false') bw_{{ $input_name }}.clearable();
|
|
@endif
|
|
</script> |