Skip to content

Commit 53c12a0

Browse files
committed
Remove 'icon' variant from Button component
1 parent 8bbe83a commit 53c12a0

6 files changed

Lines changed: 167 additions & 42 deletions

File tree

src/components/Button/__tests__/index.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ describe('Button (Astro)', () => {
3939
await expect(
4040
container.renderToString(Button, {
4141
props: {
42-
variant: 'icon',
42+
variant: 'primary',
4343
icon: 'close',
4444
iconPosition: 'only',
4545
},
@@ -52,7 +52,7 @@ describe('Button (Astro)', () => {
5252

5353
const renderedHtml = await container.renderToString(Button, {
5454
props: {
55-
variant: 'icon',
55+
variant: 'primary',
5656
icon: 'close',
5757
iconPosition: 'only',
5858
ariaLabel: 'Close dialog',

src/components/Button/index.astro

Lines changed: 37 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
---
22
import type { ButtonLabelOptions, ButtonProps } from '@components/Button/server'
33
import { buildButtonClassList, resolveAriaLabel } from '@components/Button/server'
4-
import Icon from '@components/Icon/index.astro'
4+
import AnchorLayout from '@components/Button/layouts/anchor.astro'
5+
import DefaultLayout from '@components/Button/layouts/default.astro'
56
67
type Props = ButtonProps
78
@@ -27,6 +28,9 @@ const buttonClassList = buildButtonClassList({
2728
variant,
2829
size,
2930
additionalClasses,
31+
icon,
32+
iconPosition,
33+
text,
3034
})
3135
3236
// Determine icon size based on button size if not specified
@@ -49,51 +53,50 @@ if (typeof icon !== 'undefined') {
4953
const computedAriaLabel = resolveAriaLabel(labelOptions)
5054
const ariaAttributes = computedAriaLabel ? { 'aria-label': computedAriaLabel } : {}
5155
52-
const linkHref = disabled ? undefined : href
53-
const linkOnClick = disabled ? undefined : onClick
56+
const hasAriaAttributes = Object.keys(ariaAttributes).length > 0
57+
const anchorOptionalProps = {
58+
...(id !== undefined ? { id } : {}),
59+
...(onClick !== undefined ? { onClick } : {}),
60+
...(icon !== undefined ? { icon } : {}),
61+
...(text !== undefined ? { text } : {}),
62+
...(hasAriaAttributes ? { ariaAttributes } : {}),
63+
}
64+
65+
const defaultOptionalProps = {
66+
...(id !== undefined ? { id } : {}),
67+
...(onClick !== undefined ? { onClick } : {}),
68+
...(icon !== undefined ? { icon } : {}),
69+
...(text !== undefined ? { text } : {}),
70+
...(hasAriaAttributes ? { ariaAttributes } : {}),
71+
}
5472
---
5573

5674
<div style="display: contents">
5775
{
5876
href ? (
59-
<a
60-
href={linkHref}
61-
class:list={buttonClassList}
62-
id={id}
63-
onclick={linkOnClick}
64-
aria-disabled={disabled ? 'true' : undefined}
65-
tabindex={disabled ? -1 : undefined}
66-
{...ariaAttributes}
67-
{...rest}
77+
<AnchorLayout
78+
href={href}
79+
disabled={disabled}
80+
classList={buttonClassList}
81+
iconPosition={iconPosition}
82+
iconSize={defaultIconSize}
83+
attributes={rest}
84+
{...anchorOptionalProps}
6885
>
69-
{icon && (iconPosition === 'left' || iconPosition === 'only') && (
70-
<Icon icon={icon} size={defaultIconSize} classes={text ? 'mr-2' : ''} />
71-
)}
72-
{text && <span>{text}</span>}
73-
{icon && iconPosition === 'right' && (
74-
<Icon icon={icon} size={defaultIconSize} classes="ml-2" />
75-
)}
7686
<slot />
77-
</a>
87+
</AnchorLayout>
7888
) : (
79-
<button
89+
<DefaultLayout
8090
type={type}
81-
class:list={buttonClassList}
8291
disabled={disabled}
83-
id={id}
84-
onclick={onClick}
85-
{...ariaAttributes}
86-
{...rest}
92+
classList={buttonClassList}
93+
iconPosition={iconPosition}
94+
iconSize={defaultIconSize}
95+
attributes={rest}
96+
{...defaultOptionalProps}
8797
>
88-
{icon && (iconPosition === 'left' || iconPosition === 'only') && (
89-
<Icon icon={icon} size={defaultIconSize} classes={text ? 'mr-2' : ''} />
90-
)}
91-
{text && <span>{text}</span>}
92-
{icon && iconPosition === 'right' && (
93-
<Icon icon={icon} size={defaultIconSize} classes="ml-2" />
94-
)}
9598
<slot />
96-
</button>
99+
</DefaultLayout>
97100
)
98101
}
99102
</div>
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
---
2+
import Icon from '@components/Icon/index.astro'
3+
import type { IconPosition } from '@components/Button/server'
4+
5+
type Props = {
6+
id?: string | undefined
7+
href?: string | undefined
8+
onClick?: string | undefined
9+
disabled?: boolean | undefined
10+
classList: Record<string, boolean>
11+
ariaAttributes?: Record<string, string> | undefined
12+
icon?: string | undefined
13+
iconPosition?: IconPosition | undefined
14+
iconSize: number
15+
text?: string | undefined
16+
attributes?: Record<string, unknown> | undefined
17+
}
18+
19+
const {
20+
id,
21+
href,
22+
onClick,
23+
disabled = false,
24+
classList,
25+
ariaAttributes = {},
26+
icon,
27+
iconPosition = 'left',
28+
iconSize,
29+
text,
30+
attributes = {},
31+
} = Astro.props
32+
33+
const linkHref = disabled ? undefined : href
34+
const linkOnClick = disabled ? undefined : onClick
35+
---
36+
37+
<a
38+
href={linkHref}
39+
class:list={classList}
40+
id={id}
41+
onclick={linkOnClick}
42+
aria-disabled={disabled ? 'true' : undefined}
43+
tabindex={disabled ? -1 : undefined}
44+
{...ariaAttributes}
45+
{...attributes}
46+
>
47+
{icon && (iconPosition === 'left' || iconPosition === 'only') && (
48+
<Icon icon={icon} size={iconSize} classes={text ? 'mr-2' : ''} />
49+
)}
50+
{text && <span>{text}</span>}
51+
{icon && iconPosition === 'right' && (
52+
<Icon icon={icon} size={iconSize} classes="ml-2" />
53+
)}
54+
<slot />
55+
</a>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
---
2+
import Icon from '@components/Icon/index.astro'
3+
import type { ButtonType, IconPosition } from '@components/Button/server'
4+
5+
type Props = {
6+
id?: string | undefined
7+
type?: ButtonType | undefined
8+
onClick?: string | undefined
9+
disabled?: boolean | undefined
10+
classList: Record<string, boolean>
11+
ariaAttributes?: Record<string, string> | undefined
12+
icon?: string | undefined
13+
iconPosition?: IconPosition | undefined
14+
iconSize: number
15+
text?: string | undefined
16+
attributes?: Record<string, unknown> | undefined
17+
}
18+
19+
const {
20+
id,
21+
type = 'button',
22+
onClick,
23+
disabled = false,
24+
classList,
25+
ariaAttributes = {},
26+
icon,
27+
iconPosition = 'left',
28+
iconSize,
29+
text,
30+
attributes = {},
31+
} = Astro.props
32+
---
33+
34+
<button
35+
type={type}
36+
class:list={classList}
37+
disabled={disabled}
38+
id={id}
39+
onclick={onClick}
40+
{...ariaAttributes}
41+
{...attributes}
42+
>
43+
{icon && (iconPosition === 'left' || iconPosition === 'only') && (
44+
<Icon icon={icon} size={iconSize} classes={text ? 'mr-2' : ''} />
45+
)}
46+
{text && <span>{text}</span>}
47+
{icon && iconPosition === 'right' && (
48+
<Icon icon={icon} size={iconSize} classes="ml-2" />
49+
)}
50+
<slot />
51+
</button>

src/components/Button/server/__tests__/index.spec.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,17 @@ describe('Button server helpers', () => {
3939
expect(classList['custom']).toBe(true)
4040
expect(classList['extra-class']).toBe(true)
4141
})
42+
43+
it('adds icon-only structural classes when icon-only props are provided', () => {
44+
const classList = buildButtonClassList({
45+
variant: 'primary',
46+
icon: 'close',
47+
iconPosition: 'only',
48+
})
49+
50+
expect(classList['aspect-square']).toBe(true)
51+
expect(classList['p-2']).toBe(true)
52+
})
4253
})
4354

4455
describe('resolveAriaLabel', () => {

src/components/Button/server/index.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ export type ButtonVariant =
77
| 'success'
88
| 'info'
99
| 'warning'
10-
| 'icon'
1110
export type ButtonSize = 'small' | 'medium' | 'large'
1211
export type ButtonType = 'button' | 'submit' | 'reset'
1312
export type IconPosition = 'left' | 'right' | 'only'
@@ -30,6 +29,7 @@ export interface ButtonProps {
3029
}
3130

3231
const ICON_ONLY_POSITION: IconPosition = 'only'
32+
const iconOnlyClasses = 'aspect-square p-2'
3333

3434
type ClassList = Record<string, boolean>
3535

@@ -70,11 +70,6 @@ const variantClasses: Record<ButtonVariant, string> = {
7070
'hover:bg-danger-offset ' +
7171
'focus-visible:bg-danger-offset ' +
7272
'active:bg-danger-offset',
73-
icon:
74-
'aspect-square bg-transparent text-white p-2 ' +
75-
'hover:bg-page-offset hover:text-primary ' +
76-
'focus-visible:bg-page-offset focus-visible:text-primary ' +
77-
'active:bg-page-offset',
7873
info:
7974
'bg-info text-white ' +
8075
'hover:bg-info-offset ' +
@@ -116,12 +111,18 @@ export interface ButtonClassOptions {
116111
variant?: ButtonVariant
117112
size?: ButtonSize
118113
additionalClasses?: string
114+
icon?: string
115+
iconPosition?: IconPosition
116+
text?: string
119117
}
120118

121119
export function buildButtonClassList({
122120
variant = 'primary',
123121
size = 'medium',
124122
additionalClasses,
123+
icon,
124+
iconPosition,
125+
text,
125126
}: ButtonClassOptions) {
126127
const classList: ClassList = {}
127128
const selectedVariant = variant as string
@@ -138,6 +139,10 @@ export function buildButtonClassList({
138139
addClassNames(classList, additionalClasses)
139140
}
140141

142+
if (icon && iconPosition === ICON_ONLY_POSITION && !text) {
143+
addClassNames(classList, iconOnlyClasses)
144+
}
145+
141146
return classList
142147
}
143148

0 commit comments

Comments
 (0)