-
-
Notifications
You must be signed in to change notification settings - Fork 425
Expand file tree
/
Copy pathBase.vue
More file actions
81 lines (74 loc) · 2.46 KB
/
Base.vue
File metadata and controls
81 lines (74 loc) · 2.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
<script setup lang="ts">
import type { IconClass } from '~/types'
/**
* A base button component that supports multiple variants, sizes, and states as well as icons and keyboard shortcuts.
*/
defineOptions({
name: 'ButtonBase',
})
const props = withDefaults(
defineProps<{
disabled?: boolean
/** @default "button" */
type?: 'button' | 'submit'
/** @default "secondary" */
variant?: 'primary' | 'secondary'
/** @default "md" */
size?: 'sm' | 'md'
/** Keyboard shortcut hint */
ariaKeyshortcuts?: string
/** Forces the button to occupy the entire width of its container. */
block?: boolean
classicon?: IconClass
}>(),
{
type: 'button',
variant: 'secondary',
size: 'md',
},
)
const el = useTemplateRef('el')
const keyboardShortcutsEnabled = useKeyboardShortcutsPreference()
defineExpose({
focus: () => el.value?.focus(),
getBoundingClientRect: () => el.value?.getBoundingClientRect(),
})
</script>
<template>
<button
ref="el"
class="group gap-x-1 items-center justify-center font-mono border border-border rounded-md transition-all duration-200 disabled:(opacity-40 cursor-not-allowed border-transparent)"
:class="{
'inline-flex': !block,
'flex': block,
'text-sm px-4 py-2': size === 'md',
'text-xs px-2 py-0.5': size === 'sm',
'bg-transparent text-fg hover:enabled:(bg-fg/10) focus-visible:enabled:(bg-fg/10) aria-pressed:(bg-fg/10 border-fg/20 hover:enabled:(bg-fg/20 text-fg/50))':
variant === 'secondary',
'text-bg bg-fg hover:enabled:(bg-fg/50) focus-visible:enabled:(bg-fg/50) aria-pressed:(bg-fg text-bg border-fg hover:enabled:(text-bg/50))':
variant === 'primary',
}"
:type="props.type"
:disabled="
/**
* Unfortunately Vue _sometimes_ doesn't handle `disabled` correct,
* resulting in an invalid `disabled=false` attribute in the final HTML.
*
* This fixes this.
*/
disabled ? true : undefined
"
:aria-keyshortcuts="keyboardShortcutsEnabled ? ariaKeyshortcuts : undefined"
>
<span v-if="classicon" class="size-[1em]" :class="classicon" aria-hidden="true" />
<slot />
<kbd
v-if="keyboardShortcutsEnabled && ariaKeyshortcuts"
data-kbd-hint
class="ms-2 inline-flex items-center justify-center w-4 h-4 text-xs text-fg bg-bg-muted border border-border rounded no-underline"
aria-hidden="true"
>
{{ ariaKeyshortcuts }}
</kbd>
</button>
</template>