@props([ 'icon' => null, 'iconPosition' => 'left', // left | right | top | bottom 'variant' => 'primary', 'size' => 'md', 'href' => null, 'loading' => false, 'disableOnLoading' => false, // 🔥 optional ]) @php /* ====================================================== | Element tag * ====================================================== */ $tag = $href ? 'a' : 'button'; /* ====================================================== | Custom class dari user * ====================================================== */ $customClasses = $attributes->get('class', ''); /* ====================================================== | Deteksi custom padding * ====================================================== */ $hasCustomPadding = preg_match( '/\b(p|px|py|pt|pb|pl|pr)-(?:\d+|\[.*?\])\b/', $customClasses ); /* ====================================================== | Deteksi custom background * ====================================================== */ $hasCustomBg = preg_match('/\bbg-\S+/', $customClasses); /* ====================================================== | Variant class * ====================================================== */ $variantClass = ''; if (!$hasCustomBg) { $variantClass = match ($variant) { 'secondary' => 'bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-800 text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800', 'success' => 'bg-emerald-600 text-white hover:bg-emerald-700 dark:bg-emerald-500 dark:hover:bg-emerald-600', 'danger' => 'bg-rose-500 text-white hover:bg-rose-600', 'ghost' => 'bg-transparent hover:bg-gray-100 dark:hover:bg-gray-800 text-gray-600 dark:text-gray-400', default => 'bg-indigo-600 text-white hover:bg-indigo-700', }; } /* ====================================================== | Text size * ====================================================== */ $textSizeClass = match ($size) { 'sm' => 'text-xs', 'lg' => 'text-base', default => 'text-sm', }; /* ====================================================== | Padding size * ====================================================== */ $sizeClass = ''; if (!$hasCustomPadding) { $sizeClass = match ($size) { 'sm' => 'px-3 py-1.5', 'lg' => 'px-6 py-3.5', default => 'px-5 py-2.5', }; } /* ====================================================== | Icon position * ====================================================== */ $iconPositionClass = match ($iconPosition) { 'right' => 'flex-row-reverse', 'top' => 'flex-col', 'bottom' => 'flex-col-reverse', default => 'flex-row', }; /* ====================================================== | Interaction class * ====================================================== */ $interactionClass = $loading && !$disableOnLoading ? 'pointer-events-none' : ''; /* ====================================================== | Base class * ====================================================== */ $baseClass = ' inline-flex items-center justify-center gap-2 font-semibold rounded-2xl transition-all duration-200 active:scale-95 cursor-pointer disabled:opacity-50 disabled:pointer-events-none '; /* ====================================================== | Final class * ====================================================== */ $finalClass = trim(preg_replace('/\s+/', ' ', implode(' ', [ $baseClass, $iconPositionClass, $variantClass, $textSizeClass, $sizeClass, $interactionClass, $customClasses, ]))); /* ====================================================== | Icon & spinner size * ====================================================== */ $iconSizeClass = $size === 'sm' ? 'text-base' : 'text-lg'; $spinnerSizeClass = match ($size) { 'sm' => 'w-3.5 h-3.5', 'lg' => 'w-5 h-5', default => 'w-4 h-4', }; @endphp <{{ $tag }} @if($href) href="{{ $href }}" @if($loading && $disableOnLoading) aria-disabled="true" @endif @else type="{{ $attributes->get('type', 'button') }}" @if($loading && $disableOnLoading) disabled @endif @endif {{ $attributes->except('class')->merge(['class' => $finalClass]) }} > {{-- Spinner --}} @if($loading) @else @if($icon) @endif @endif {{-- Label --}} @if($slot->isNotEmpty()) {{ $slot }} @endif