Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Update button component #14

Merged
merged 3 commits into from
Oct 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
"build": "run-p type-check \"build-only {@}\" --",
"preview": "vite preview",
"test:unit": "vitest",
"test:ui": "vitest --ui",
"test:update": "vitest -u",
"coverage": "vitest run --coverage",
"test:e2e": "playwright test",
"build-only": "vite build",
Expand Down Expand Up @@ -63,6 +65,7 @@
"@types/node": "^18.18.5",
"@vitejs/plugin-vue": "^4.4.0",
"@vitest/coverage-istanbul": "^0.34.6",
"@vitest/ui": "^0.34.6",
"@vue/eslint-config-prettier": "^8.0.0",
"@vue/eslint-config-typescript": "^12.0.0",
"@vue/test-utils": "^2.4.1",
Expand Down
47 changes: 32 additions & 15 deletions src/components/BuiButton/BuiButton.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import { ButtonColor } from './types'
import type { TestWrapper } from '../../types/globalTypes'

describe('BuiButton', () => {
// @ts-ignore
// @ts-ignore-next-line
let wrapper: TestWrapper

const createComponent = (props: {
props: {
disabled?: boolean
color: ButtonColor
}
}) => {
Expand All @@ -18,25 +19,41 @@ describe('BuiButton', () => {
...props
})
}
test('default button classes is correct', () => {
test('default button snapshot', async () => {
createComponent({ props: { color: 'primary' } })

expect(wrapper.classes().join(' ')).toEqual(
'focus:ring-4 focus:ring-primary-200 font-medium rounded text-sm px-5 py-2.5 mr-2 mb-2 focus:outline-none bg-primary-500 hover:bg-primary-550 dark:bg-primary-500 dark:hover:bg-primary-600 dark:focus:ring-primary-400 text-white'
)
const result = wrapper.html()
await expect(result).toMatchFileSnapshot('./test/default.output.html')
})
test('default disabled button snapshot', async () => {
createComponent({ props: { color: 'primary', disabled: true } })
const result = wrapper.html()
await expect(result).toMatchFileSnapshot('./test/default-disabled.output.html')
})
test('secondary button classes is correct', () => {

test('secondary button classes is correct', async () => {
createComponent({ props: { color: 'secondary' } })

expect(wrapper.classes().join(' ')).toEqual(
'focus:ring-4 focus:ring-primary-200 font-medium rounded text-sm px-5 py-2.5 mr-2 mb-2 focus:outline-none bg-primary-150 hover:bg-primary-200 dark:bg-primary-650 dark:hover:bg-primary-700 dark:focus:ring-primary-300 text-primary-500'
)
const result = wrapper.html()
await expect(result).toMatchFileSnapshot('./test/secondary.output.html')
})

test('secondary disabled button snapshot', async () => {
createComponent({ props: { color: 'secondary', disabled: true } })
const result = wrapper.html()
await expect(result).toMatchFileSnapshot('./test/secondary-disabled.output.html')
})
test('text button classes is correct', () => {
createComponent({ props: { color: 'link' } })

expect(wrapper.classes().join(' ')).toEqual(
'focus:ring-4 focus:ring-primary-200 font-medium rounded text-sm px-5 py-2.5 mr-2 mb-2 focus:outline-none text-primary-500 bg-transparent hover:bg-primary-100 dark:hover:bg-primary-650 dark:hover:text-primary-400'
)
test('text button classes is correct', async () => {
createComponent({ props: { color: 'text' } })

const result = wrapper.html()
await expect(result).toMatchFileSnapshot('./test/text.output.html')
})

test('text button disabled snapshot', async () => {
createComponent({ props: { color: 'text' } })

const result = wrapper.html()
await expect(result).toMatchFileSnapshot('./test/text-disabled.output.html')
})
})
51 changes: 47 additions & 4 deletions src/components/BuiButton/BuiButton.story.vue
Original file line number Diff line number Diff line change
@@ -1,16 +1,59 @@
<script setup lang="ts">
import BuiButton from './BuiButton.vue'
import { ButtonColor } from './types'
import { ButtonColor, ButtonSize } from './types'

const colorOptions: ButtonColor[] = ['primary', 'secondary', 'link']
const colorOptions: ButtonColor[] = ['primary', 'secondary', 'outline', 'text']
const sizes: {
name: string
value: ButtonSize
}[] = [
{
name: 'Large',
value: 'lg'
},
{
name: 'Medium',
value: 'md'
},
{
name: 'Small',
value: 'sm'
}
]
</script>

<template>
<Story title="BuiButton" autoPropsDisabled :layout="{ type: 'grid', width: '200px' }">
<Story title="BuiButton" autoPropsDisabled :layout="{ type: 'grid', width: '25%' }">
<Variant v-for="color in colorOptions" :title="color" :key="color">
<div class="p-4">
<div class="p-4 flex justify-center">
<BuiButton :color="color">{{ color }}</BuiButton>
</div>
</Variant>
<h2>Disabled</h2>
<Variant v-for="color in colorOptions" :title="color" :key="color">
<div class="p-4 flex justify-center">
<BuiButton :color="color" disabled>{{ color }}</BuiButton>
</div>
</Variant>
<h2>Sizes</h2>
<Variant v-for="size in sizes" :title="size.name" :key="size">
<div class="p-4 flex justify-center">
<BuiButton :size="size.value">{{ size.name }}</BuiButton>
</div>
</Variant>
</Story>
</template>

<docs lang="md">
# BuiButton

## Props:

### color

Values: `primary` | `secondary` | `text`

### size

Values: `lg` | `md` | `sm`
</docs>
95 changes: 77 additions & 18 deletions src/components/BuiButton/BuiButton.vue
Original file line number Diff line number Diff line change
@@ -1,32 +1,91 @@
<script setup lang="ts">
import { twMerge } from 'tailwind-merge'
import { twJoin, twMerge } from 'tailwind-merge'
import { computed } from 'vue-demi'
import { ButtonColor } from './types.ts'

const baseClasses =
'focus:ring-4 focus:ring-primary-200 font-medium rounded text-sm px-5 py-2.5 mr-2 mb-2 focus:outline-none'

const colorClasses: Record<ButtonColor, string> = {
primary:
'bg-primary-500 hover:bg-primary-550 dark:bg-primary-500 dark:hover:bg-primary-600 dark:focus:ring-primary-400 text-white',
secondary:
'bg-primary-150 hover:bg-primary-200 dark:bg-primary-650 dark:hover:bg-primary-700 dark:focus:ring-primary-300 text-primary-500',
link: 'text-primary-500 bg-transparent hover:bg-primary-100 dark:hover:bg-primary-650 dark:hover:text-primary-400'
}
import type { ButtonColor, ButtonSize } from './types.ts'

interface IBuiButtonProps {
color: ButtonColor
disabled?: boolean
color?: ButtonColor
size?: ButtonSize
}
const props = withDefaults(defineProps<IBuiButtonProps>(), {
color: 'primary'
disabled: false,
color: 'primary',
size: 'md'
})

const baseClasses = 'font-medium rounded text-sm focus:outline-none'

// Style Classes

const primaryButtonClasses = {
base: 'bg-primary-500 dark:bg-primary-500 text-white',
hover: 'hover:bg-primary-550 dark:hover:bg-primary-600',
focus: 'dark:focus:ring-primary-400 focus:bg-primary-575',
disabled:
'border-slate-300 hover:border-slate-300 bg-gray-150 dark:bg-primary-600 hover:bg-gray-150 text-gray-400 hover:text-gray-400 cursor-not-allowed'
}
const secondaryButtonClasses = {
base: 'bg-transparent text-primary-550',
hover: 'hover:bg-primary-150 dark:hover:bg-primary-650',
focus: 'dark:focus:ring-primary-300 focus:bg-primary-175',
disabled: 'text-primary-250 hover:bg-white cursor-not-allowed'
}
const textButtonClasses = {
base: 'text-primary-500 dark:text-primary-225 bg-transparent',
hover: 'dark:hover:text-primary-400',
focus: '',
disabled:
'text-primary-250 dark:text-primary-175 dark:hover:text-primary-175 bg-white hover:bg-white dark:bg-transparent cursor-not-allowed'
}
const outlineButtonClasses = {
base: 'text-primary-500 bg-transparent border border-primary-500 dark:border:primary-400 dark:text-primary-400',
hover: 'hover:bg-primary-150 dark:hover:text-primary-500 dark:hover:bg-primary-650',
focus: 'focus:bg-primary-175 dark:focus:bg-primary-625',
disabled:
'text-primary-250 border-primary-250 bg-primary-100 dark:bg-transparent hover:bg-primary-100 cursor-not-allowed dark:border-primary-590 dark:text-primary-590 dark:hover:text-primary-590'
}
const colorClasses: Record<ButtonColor, string> = {
primary: twJoin(
primaryButtonClasses.base,
primaryButtonClasses.hover,
primaryButtonClasses.focus,
props.disabled && primaryButtonClasses.disabled
),
secondary: twJoin(
secondaryButtonClasses.base,
secondaryButtonClasses.hover,
secondaryButtonClasses.focus,
props.disabled && secondaryButtonClasses.disabled
),
text: twJoin(
textButtonClasses.base,
textButtonClasses.hover,
textButtonClasses.focus,
props.disabled && textButtonClasses.disabled
),
outline: twJoin(
outlineButtonClasses.base,
outlineButtonClasses.hover,
outlineButtonClasses.focus,
props.disabled && outlineButtonClasses.disabled
)
}
const sizeClasses: Record<ButtonSize, string> = {
lg: 'py-2 px-5',
md: 'py-1 px-4',
sm: 'py-0.5 px-4'
}

const buttonClasses = computed(() => {
return twMerge(baseClasses, colorClasses[props.color])
return twMerge(baseClasses, colorClasses[props.color], sizeClasses[props.size])
})
</script>

<template>
<button :class="buttonClasses">
<slot>Primary</slot>
<button :class="buttonClasses" :disabled="disabled">
<slot name="prefix"></slot>
<slot name="default">Primary</slot>
<slot name="suffix"></slot>
</button>
</template>
1 change: 1 addition & 0 deletions src/components/BuiButton/test/default-disabled.output.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<button class="font-medium rounded text-sm focus:outline-none dark:hover:bg-primary-600 dark:focus:ring-primary-400 focus:bg-primary-575 border-slate-300 hover:border-slate-300 bg-gray-150 dark:bg-primary-600 hover:bg-gray-150 text-gray-400 hover:text-gray-400 cursor-not-allowed py-1 px-4" disabled="">Primary</button>
1 change: 1 addition & 0 deletions src/components/BuiButton/test/default.output.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<button class="font-medium rounded text-sm focus:outline-none bg-primary-500 dark:bg-primary-500 text-white hover:bg-primary-550 dark:hover:bg-primary-600 dark:focus:ring-primary-400 focus:bg-primary-575 py-1 px-4">Primary</button>
1 change: 1 addition & 0 deletions src/components/BuiButton/test/secondaey.output.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<button class="focus:ring-4 focus:ring-primary-200 font-medium rounded text-sm focus:outline-none bg-primary-150 dark:bg-primary-650 text-primary-500 hover:bg-primary-200 dark:hover:bg-primary-700 dark:focus:ring-primary-300 py-1 px-4">Primary</button>
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<button class="font-medium rounded text-sm focus:outline-none bg-transparent dark:hover:bg-primary-650 dark:focus:ring-primary-300 focus:bg-primary-175 text-primary-250 hover:bg-white cursor-not-allowed py-1 px-4" disabled="">Primary</button>
1 change: 1 addition & 0 deletions src/components/BuiButton/test/secondary.output.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<button class="font-medium rounded text-sm focus:outline-none bg-transparent text-primary-550 hover:bg-primary-150 dark:hover:bg-primary-650 dark:focus:ring-primary-300 focus:bg-primary-175 py-1 px-4">Primary</button>
1 change: 1 addition & 0 deletions src/components/BuiButton/test/text-disabled.output.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<button class="font-medium rounded text-sm focus:outline-none text-primary-500 dark:text-primary-225 bg-transparent dark:hover:text-primary-400 py-1 px-4">Primary</button>
1 change: 1 addition & 0 deletions src/components/BuiButton/test/text.output.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<button class="font-medium rounded text-sm focus:outline-none text-primary-500 dark:text-primary-225 bg-transparent dark:hover:text-primary-400 py-1 px-4">Primary</button>
3 changes: 2 additions & 1 deletion src/components/BuiButton/types.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export type ButtonColor = 'primary' | 'secondary' | 'link'
export type ButtonColor = 'primary' | 'secondary' | 'text' | 'outline'
export type ButtonSize = 'lg' | 'md' | 'sm'
Loading