Files
windmill/frontend/src/lib/components/common/button/Button.svelte
2022-10-07 19:54:44 +02:00

99 lines
3.4 KiB
Svelte

<script lang="ts">
import { createEventDispatcher } from 'svelte'
import { goto } from '$app/navigation'
import { classNames } from '$lib/utils'
import Icon from 'svelte-awesome'
import { ButtonType } from './model'
export let size: ButtonType.Size = 'md'
export let spacingSize: ButtonType.Size = size
export let color: ButtonType.Color = 'blue'
export let variant: ButtonType.Variant = 'contained'
export let btnClasses: string = ''
export let disabled: boolean = false
export let href: string | undefined = undefined
export let target: ButtonType.Target = '_self'
export let iconOnly: boolean = false
export let startIcon: ButtonType.Icon | undefined = undefined
export let endIcon: ButtonType.Icon | undefined = undefined
export let element: ButtonType.Element | undefined = undefined
export let id: string = ''
const dispatch = createEventDispatcher()
// Order of classes: border, border modifier, bg, bg modifier, text, text modifier, everything else
const colorVariants: Record<ButtonType.Color, Record<ButtonType.Variant, string>> = {
blue: {
border:
'border-blue-500 hover:border-blue-700 focus:border-blue-700 bg-white hover:bg-blue-100 focus:bg-blue-100 text-blue-500 hover:text-blue-700 focus:text-blue-700 focus:ring-blue-300',
contained: 'bg-blue-500 hover:bg-blue-700 focus:bg-blue-700 text-white focus:ring-blue-300'
},
red: {
border:
'border-red-600 hover:border-red-700 bg-white hover:bg-red-100 text-red-600 hover:text-red-700 focus:ring-red-300',
contained: 'bg-red-600 hover:bg-red-700 text-white focus:ring-red-300'
},
dark: {
border:
'border-gray-800 hover:border-gray-900 focus:border-gray-900 bg-white hover:bg-gray-200 focus:bg-gray-200 text-gray-800 hover:text-gray-900 focus:text-gray-900 focus:ring-gray-300',
contained: 'bg-gray-700 hover:bg-gray-900 focus:bg-gray-900 text-white focus:ring-gray-300'
},
light: {
border:
'border bg-white hover:bg-gray-100 focus:bg-gray-100 text-gray-700 hover:text-gray-800 focus:text-gray-800 focus:ring-gray-300',
contained: 'bg-white hover:bg-gray-100 focus:bg-gray-100 text-gray-700 focus:ring-gray-300'
}
}
$: buttonProps = {
class: classNames(
colorVariants[color][variant],
variant === 'border' ? 'border' : '',
ButtonType.FontSizeClasses[size],
ButtonType.SpacingClasses[spacingSize],
'focus:ring-4 font-medium',
'rounded-md',
'flex justify-center items-center text-center whitespace-nowrap',
btnClasses,
disabled ? 'pointer-events-none cursor-default filter grayscale' : ''
),
disabled,
href,
target,
tabindex: disabled ? -1 : 0
}
function onClick(event: MouseEvent) {
dispatch('click', event)
if (href) {
event.preventDefault()
goto(href)
}
}
$: isSmall = size === 'xs' || size === 'sm'
$: startIconClass = classNames(
iconOnly ? undefined : isSmall ? 'mr-1' : 'mr-2',
startIcon?.classes
)
$: endIconClass = classNames(iconOnly ? undefined : isSmall ? 'ml-1' : 'ml-2', endIcon?.classes)
</script>
<svelte:element
this={href ? 'a' : 'button'}
bind:this={element}
on:click|stopPropagation={onClick}
on:focus
on:blur
{...buttonProps}
>
{#if startIcon}
<Icon data={startIcon.icon} class={startIconClass} scale={ButtonType.IconScale[size]} />
{/if}
{#if !iconOnly}
<slot />
{/if}
{#if endIcon}
<Icon data={endIcon.icon} class={endIconClass} scale={ButtonType.IconScale[size]} />
{/if}
</svelte:element>