refactor(ui): migrate button and pagination components to radix-vue

- Replace reka-ui imports with radix-vue in Button component
- Update pagination components to use direct radix-vue icons
- Simplify button variants styling and adjust size variants
- Remove unused data-slot attribute from Button component
This commit is contained in:
Khafid Prayoga
2025-08-26 16:57:11 +07:00
parent e21e5f1e7a
commit 153c171a3b
7 changed files with 44 additions and 38 deletions
+2 -3
View File
@@ -1,9 +1,9 @@
<script setup lang="ts">
import type { PrimitiveProps } from 'reka-ui'
import type { PrimitiveProps } from 'radix-vue'
import type { HTMLAttributes } from 'vue'
import type { ButtonVariants } from '.'
import { Primitive } from 'reka-ui'
import { cn } from '~/lib/utils'
import { Primitive } from 'radix-vue'
import { buttonVariants } from '.'
interface Props extends PrimitiveProps {
@@ -19,7 +19,6 @@ const props = withDefaults(defineProps<Props>(), {
<template>
<Primitive
data-slot="button"
:as="as"
:as-child="asChild"
:class="cn(buttonVariants({ variant, size }), props.class)"
+11 -12
View File
@@ -4,27 +4,26 @@ import { cva } from 'class-variance-authority'
export { default as Button } from './Button.vue'
export const buttonVariants = cva(
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*=\'size-\'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive',
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
{
variants: {
variant: {
default:
'bg-primary text-primary-foreground shadow-xs hover:bg-primary/90',
default: 'bg-primary text-primary-foreground shadow hover:bg-primary/90',
destructive:
'bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60',
'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
outline:
'border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50',
'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
secondary:
'bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80',
ghost:
'hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50',
'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
ghost: 'hover:bg-accent hover:text-accent-foreground',
link: 'text-primary underline-offset-4 hover:underline',
},
size: {
default: 'h-9 px-4 py-2 has-[>svg]:px-3',
sm: 'h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5',
lg: 'h-10 rounded-md px-6 has-[>svg]:px-4',
icon: 'size-9',
default: 'h-9 px-4 py-2',
xs: 'h-7 rounded px-2',
sm: 'h-8 rounded-md px-3 text-xs',
lg: 'h-10 rounded-md px-8',
icon: 'h-9 w-9',
},
},
defaultVariants: {
@@ -1,10 +1,10 @@
<script setup lang="ts">
import type { PaginationEllipsisProps } from 'radix-vue'
import type { HTMLAttributes } from 'vue'
import { cn } from '~/lib/utils'
import { DotsHorizontalIcon } from '@radix-icons/vue'
import { PaginationEllipsis } from 'radix-vue'
import { computed } from 'vue'
import { cn } from '~/lib/utils'
const props = defineProps<PaginationEllipsisProps & { class?: HTMLAttributes['class'] }>()
@@ -18,7 +18,7 @@ const delegatedProps = computed(() => {
<template>
<PaginationEllipsis v-bind="delegatedProps" :class="cn('w-9 h-9 flex items-center justify-center', props.class)">
<slot>
<Icon name="i-radix-icons-dots-horizontal" />
<DotsHorizontalIcon />
</slot>
</PaginationEllipsis>
</template>
@@ -1,11 +1,13 @@
<script setup lang="ts">
import type { PaginationFirstProps } from 'radix-vue'
import type { HTMLAttributes } from 'vue'
import {
Button,
} from '~/components/pub/ui/button'
import { cn } from '~/lib/utils'
import { DoubleArrowLeftIcon } from '@radix-icons/vue'
import { PaginationFirst } from 'radix-vue'
import { computed } from 'vue'
import { Button } from '~/components/pub/ui/button'
import { cn } from '~/lib/utils'
const props = withDefaults(defineProps<PaginationFirstProps & { class?: HTMLAttributes['class'] }>(), {
asChild: true,
@@ -20,9 +22,9 @@ const delegatedProps = computed(() => {
<template>
<PaginationFirst v-bind="delegatedProps">
<Button :class="cn('h-9 w-9 p-0', props.class)" variant="outline">
<Button :class="cn('w-9 h-9 p-0', props.class)" variant="outline">
<slot>
<Icon name="i-radix-icons-double-arrow-left" />
<DoubleArrowLeftIcon />
</slot>
</Button>
</PaginationFirst>
@@ -1,11 +1,13 @@
<script setup lang="ts">
import type { PaginationLastProps } from 'radix-vue'
import type { HTMLAttributes } from 'vue'
import {
Button,
} from '~/components/pub/ui/button'
import { cn } from '~/lib/utils'
import { DoubleArrowRightIcon } from '@radix-icons/vue'
import { PaginationLast } from 'radix-vue'
import { computed } from 'vue'
import { Button } from '~/components/pub/ui/button'
import { cn } from '~/lib/utils'
const props = withDefaults(defineProps<PaginationLastProps & { class?: HTMLAttributes['class'] }>(), {
asChild: true,
@@ -20,9 +22,9 @@ const delegatedProps = computed(() => {
<template>
<PaginationLast v-bind="delegatedProps">
<Button :class="cn('h-9 w-9 p-0', props.class)" variant="outline">
<Button :class="cn('w-9 h-9 p-0', props.class)" variant="outline">
<slot>
<Icon name="i-radix-icons-double-arrow-right" />
<DoubleArrowRightIcon />
</slot>
</Button>
</PaginationLast>
@@ -1,11 +1,13 @@
<script setup lang="ts">
import type { PaginationNextProps } from 'radix-vue'
import type { HTMLAttributes } from 'vue'
import {
Button,
} from '~/components/pub/ui/button'
import { cn } from '~/lib/utils'
import { ChevronRightIcon } from '@radix-icons/vue'
import { PaginationNext } from 'radix-vue'
import { computed } from 'vue'
import { Button } from '~/components/pub/ui/button'
import { cn } from '~/lib/utils'
const props = withDefaults(defineProps<PaginationNextProps & { class?: HTMLAttributes['class'] }>(), {
asChild: true,
@@ -20,9 +22,9 @@ const delegatedProps = computed(() => {
<template>
<PaginationNext v-bind="delegatedProps">
<Button :class="cn('h-9 w-9 p-0', props.class)" variant="outline">
<Button :class="cn('w-9 h-9 p-0', props.class)" variant="outline">
<slot>
<Icon name="i-radix-icons-chevron-right" />
<ChevronRightIcon />
</slot>
</Button>
</PaginationNext>
@@ -1,11 +1,13 @@
<script setup lang="ts">
import type { PaginationPrevProps } from 'radix-vue'
import type { HTMLAttributes } from 'vue'
import {
Button,
} from '~/components/pub/ui/button'
import { cn } from '~/lib/utils'
import { ChevronLeftIcon } from '@radix-icons/vue'
import { PaginationPrev } from 'radix-vue'
import { computed } from 'vue'
import { Button } from '~/components/pub/ui/button'
import { cn } from '~/lib/utils'
const props = withDefaults(defineProps<PaginationPrevProps & { class?: HTMLAttributes['class'] }>(), {
asChild: true,
@@ -20,9 +22,9 @@ const delegatedProps = computed(() => {
<template>
<PaginationPrev v-bind="delegatedProps">
<Button :class="cn('h-9 w-9 p-0', props.class)" variant="outline">
<Button :class="cn('w-9 h-9 p-0', props.class)" variant="outline">
<slot>
<Icon name="i-radix-icons-chevron-left" />
<ChevronLeftIcon />
</slot>
</Button>
</PaginationPrev>