Component: Button Migration 2: IconButton (#7598)

## Summary

Still a work in progress. Buttons with just icons are already in the
stories for button.

┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-7598-WIP-Component-Button-Migration-2-IconButton-2cc6d73d365081c09143c63464ac60b7)
by [Unito](https://www.unito.io)
This commit is contained in:
Alexander Brown
2025-12-17 18:11:43 -08:00
committed by GitHub
parent 1d014c0dbe
commit fba580dc7d
35 changed files with 334 additions and 632 deletions

View File

@@ -1,152 +0,0 @@
import type { Meta, StoryObj } from '@storybook/vue3-vite'
import IconButton from './IconButton.vue'
const meta: Meta<typeof IconButton> = {
title: 'Components/Button/IconButton',
component: IconButton,
tags: ['autodocs'],
argTypes: {
size: {
control: { type: 'select' },
options: ['sm', 'md']
},
type: {
control: { type: 'select' },
options: ['primary', 'secondary', 'transparent']
},
border: {
control: 'boolean',
description: 'Toggle border attribute'
},
disabled: {
control: 'boolean',
description: 'Toggle disable status'
},
onClick: { action: 'clicked' }
}
}
export default meta
type Story = StoryObj<typeof meta>
export const Primary: Story = {
render: (args) => ({
components: { IconButton },
setup() {
return { args }
},
template: `
<IconButton v-bind="args">
<i class="icon-[lucide--trophy] size-4" />
</IconButton>
`
}),
args: {
type: 'primary',
size: 'md'
}
}
export const Secondary: Story = {
render: (args) => ({
components: { IconButton },
setup() {
return { args }
},
template: `
<IconButton v-bind="args">
<i class="icon-[lucide--settings] size-4" />
</IconButton>
`
}),
args: {
type: 'secondary',
size: 'md'
}
}
export const Transparent: Story = {
render: (args) => ({
components: { IconButton },
setup() {
return { args }
},
template: `
<IconButton v-bind="args">
<i class="icon-[lucide--x] size-4" />
</IconButton>
`
}),
args: {
type: 'transparent',
size: 'md'
}
}
export const Small: Story = {
render: (args) => ({
components: { IconButton },
setup() {
return { args }
},
template: `
<IconButton v-bind="args">
<i class="icon-[lucide--bell] size-3" />
</IconButton>
`
}),
args: {
type: 'secondary',
size: 'sm'
}
}
export const AllVariants: Story = {
render: () => ({
components: { IconButton },
template: `
<div class="flex flex-col gap-4">
<div class="flex gap-2 items-center">
<IconButton type="primary" size="sm" @click="() => {}">
<i class="icon-[lucide--trophy] size-3" />
</IconButton>
<IconButton type="primary" size="md" @click="() => {}">
<i class="icon-[lucide--trophy] size-4" />
</IconButton>
</div>
<div class="flex gap-2 items-center">
<IconButton type="secondary" size="sm" @click="() => {}">
<i class="icon-[lucide--settings] size-3" />
</IconButton>
<IconButton type="secondary" size="md" @click="() => {}">
<i class="icon-[lucide--settings] size-4" />
</IconButton>
</div>
<div class="flex gap-2 items-center">
<IconButton type="transparent" size="sm" @click="() => {}">
<i class="icon-[lucide--x] size-3" />
</IconButton>
<IconButton type="transparent" size="md" @click="() => {}">
<i class="icon-[lucide--x] size-4" />
</IconButton>
</div>
<div class="flex gap-2 items-center">
<IconButton type="primary" size="md" @click="() => {}">
<i class="icon-[lucide--bell] size-4" />
</IconButton>
<IconButton type="secondary" size="md" @click="() => {}">
<i class="icon-[lucide--heart] size-4" />
</IconButton>
<IconButton type="transparent" size="md" @click="() => {}">
<i class="icon-[lucide--download] size-4" />
</IconButton>
</div>
</div>
`
}),
parameters: {
controls: { disable: true },
actions: { disable: true }
}
}

View File

@@ -1,52 +0,0 @@
<template>
<Button
v-bind="$attrs"
unstyled
:class="buttonStyle"
:disabled="disabled"
@click="onClick"
>
<slot></slot>
</Button>
</template>
<script setup lang="ts">
import Button from 'primevue/button'
import { computed } from 'vue'
import type { BaseButtonProps } from '@/types/buttonTypes'
import {
getBaseButtonClasses,
getBorderButtonTypeClasses,
getButtonTypeClasses,
getIconButtonSizeClasses
} from '@/types/buttonTypes'
import { cn } from '@/utils/tailwindUtil'
interface IconButtonProps extends BaseButtonProps {
onClick?: (event: MouseEvent) => void
}
defineOptions({
inheritAttrs: false
})
const {
size = 'md',
type = 'secondary',
border = false,
disabled = false,
class: className,
onClick
} = defineProps<IconButtonProps>()
const buttonStyle = computed(() => {
const baseClasses = `${getBaseButtonClasses()} p-0`
const sizeClasses = getIconButtonSizeClasses(size)
const typeClasses = border
? getBorderButtonTypeClasses(type)
: getButtonTypeClasses(type)
return cn(baseClasses, sizeClasses, typeClasses, className)
})
</script>

View File

@@ -1,6 +1,6 @@
import type { Meta, StoryObj } from '@storybook/vue3-vite'
import IconButton from './IconButton.vue'
import Button from '@/components/ui/button/Button.vue'
import IconGroup from './IconGroup.vue'
const meta: Meta<typeof IconGroup> = {
@@ -16,18 +16,18 @@ type Story = StoryObj<typeof IconGroup>
export const Basic: Story = {
render: () => ({
components: { IconGroup, IconButton },
components: { IconGroup, Button },
template: `
<IconGroup>
<IconButton @click="console.log('Hello World!!')">
<Button size="icon" @click="console.log('Hello World!!')">
<i class="icon-[lucide--heart] size-4" />
</IconButton>
<IconButton @click="console.log('Hello World!!')">
</Button>
<Button size="icon" @click="console.log('Hello World!!')">
<i class="icon-[lucide--download] size-4" />
</IconButton>
<IconButton @click="console.log('Hello World!!')">
</Button>
<Button size="icon" @click="console.log('Hello World!!')">
<i class="icon-[lucide--external-link] size-4" />
</IconButton>
</Button>
</IconGroup>
`
})

View File

@@ -1,9 +1,17 @@
<template>
<div class="relative inline-flex items-center">
<IconButton :size="size" :type="type" @click="popover?.toggle">
<i v-if="!isVertical" class="icon-[lucide--ellipsis] text-sm" />
<i v-else class="icon-[lucide--more-vertical] text-sm" />
</IconButton>
<Button size="icon" variant="secondary" @click="popover?.toggle">
<i
:class="
cn(
!isVertical
? 'icon-[lucide--ellipsis]'
: 'icon-[lucide--more-vertical]',
'text-sm'
)
"
/>
</Button>
<Popover
ref="popover"
@@ -49,20 +57,14 @@
import Popover from 'primevue/popover'
import { ref } from 'vue'
import type { BaseButtonProps } from '@/types/buttonTypes'
import Button from '@/components/ui/button/Button.vue'
import { cn } from '@/utils/tailwindUtil'
import IconButton from './IconButton.vue'
interface MoreButtonProps extends BaseButtonProps {
interface MoreButtonProps {
isVertical?: boolean
}
const {
size = 'md',
type = 'secondary',
isVertical = false
} = defineProps<MoreButtonProps>()
const { isVertical = false } = defineProps<MoreButtonProps>()
defineEmits<{
menuOpened: []