Skip to content

Commit 4dbc0e2

Browse files
committed
refactor: add theming hooks for button and select
1 parent 5a3d725 commit 4dbc0e2

4 files changed

Lines changed: 186 additions & 64 deletions

File tree

src/v2/components/actions/button/Button.test.ts

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ describe('SolidUIButton', () => {
1818
document.body.appendChild(button)
1919
await button.updateComplete
2020

21-
const nativeButton = button.shadowRoot?.querySelector('button') as HTMLButtonElement
21+
const nativeButton = button.shadowRoot?.querySelector(
22+
'button'
23+
) as HTMLButtonElement
2224

2325
expect(button.variant).toBe('secondary')
2426
expect(nativeButton.type).toBe('button')
@@ -32,7 +34,9 @@ describe('SolidUIButton', () => {
3234
document.body.appendChild(button)
3335
await button.updateComplete
3436

35-
const nativeButton = button.shadowRoot?.querySelector('button') as HTMLButtonElement
37+
const nativeButton = button.shadowRoot?.querySelector(
38+
'button'
39+
) as HTMLButtonElement
3640

3741
expect(button.hasAttribute('selected')).toBe(true)
3842
expect(nativeButton.hasAttribute('aria-pressed')).toBe(false)
@@ -49,7 +53,9 @@ describe('SolidUIButton', () => {
4953
document.body.appendChild(button)
5054
await button.updateComplete
5155

52-
const nativeButton = button.shadowRoot?.querySelector('button') as HTMLButtonElement
56+
const nativeButton = button.shadowRoot?.querySelector(
57+
'button'
58+
) as HTMLButtonElement
5359
nativeButton.click()
5460

5561
expect(handleClick).toHaveBeenCalledTimes(1)
@@ -63,7 +69,9 @@ describe('SolidUIButton', () => {
6369
document.body.appendChild(button)
6470
await button.updateComplete
6571

66-
const icon = button.shadowRoot?.querySelector('.button__icon-image') as HTMLImageElement
72+
const icon = button.shadowRoot?.querySelector(
73+
'.button__icon-image'
74+
) as HTMLImageElement
6775
expect(icon.getAttribute('src')).toBe(button.icon)
6876
})
6977

@@ -76,8 +84,12 @@ describe('SolidUIButton', () => {
7684
document.body.appendChild(button)
7785
await button.updateComplete
7886

79-
const label = button.shadowRoot?.querySelector('.button__label') as HTMLSpanElement
80-
const icon = button.shadowRoot?.querySelector('.button__icon-image') as HTMLImageElement
87+
const label = button.shadowRoot?.querySelector(
88+
'.button__label'
89+
) as HTMLSpanElement
90+
const icon = button.shadowRoot?.querySelector(
91+
'.button__icon-image'
92+
) as HTMLImageElement
8193

8294
expect(button.variant).toBe('icon')
8395
expect(label).not.toBeNull()
@@ -119,4 +131,34 @@ describe('SolidUIButton', () => {
119131
expect(button.shadowRoot?.querySelector('.button__icon')).not.toBeNull()
120132
expect(button.shadowRoot?.querySelector('.button__icon-image')).toBeNull()
121133
})
134+
135+
it('applies layout styling hooks exposed through CSS custom properties', async () => {
136+
const stylesheetText = Array.isArray(Button.styles)
137+
? Button.styles.map((styleSheet) => styleSheet.toString()).join('\n')
138+
: Button.styles.toString()
139+
140+
expect(stylesheetText).toContain(
141+
'--button-padding-sm: 0 var(--button-padding-x-sm);'
142+
)
143+
expect(stylesheetText).toContain('--button-border-width: 1px;')
144+
expect(stylesheetText).toContain('padding: var(--button-padding-md);')
145+
expect(stylesheetText).toContain(
146+
'border: var(--button-border-width) solid var(--button-border);'
147+
)
148+
expect(stylesheetText).toContain(
149+
'border-radius: var(--button-border-radius);'
150+
)
151+
expect(stylesheetText).toContain('font-weight: var(--button-font-weight);')
152+
expect(stylesheetText).toContain('line-height: var(--button-line-height);')
153+
expect(stylesheetText).toContain(
154+
'justify-content: var(--button-justify-content);'
155+
)
156+
expect(stylesheetText).toContain(
157+
'box-shadow: var(--button-hover-box-shadow, var(--button-box-shadow));'
158+
)
159+
expect(stylesheetText).toContain('outline: var(--button-focus-outline);')
160+
expect(stylesheetText).toContain(
161+
'transform: var(--button-active-transform);'
162+
)
163+
})
122164
})

src/v2/components/actions/button/Button.ts

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,22 @@ export class Button extends LitElement {
4747
--button-icon-size-sm: var(--icon-xxxs, 0.75rem);
4848
--button-icon-size-md: var(--icon-xxs, 1rem);
4949
--button-icon-size-lg: var(--icon-xxs, 1rem);
50+
--button-padding-sm: 0 var(--button-padding-x-sm);
51+
--button-padding-md: 0 var(--button-padding-x-md);
52+
--button-padding-lg: 0 var(--button-padding-x-lg);
53+
--button-border-width: 1px;
54+
--button-border-radius: var(--border-radius-base, 0.3125rem);
55+
--button-font-weight: var(--font-weight-bold, 600);
56+
--button-line-height: 1;
57+
--button-justify-content: center;
58+
--button-box-shadow: none;
59+
--button-hover-box-shadow: var(--button-box-shadow);
60+
--button-active-box-shadow: var(--button-hover-box-shadow);
61+
--button-active-transform: translateY(1px);
62+
--button-focus-outline: 2px solid var(--button-focus-ring);
63+
--button-focus-outline-offset: 2px;
64+
--button-focus-box-shadow: none;
65+
--button-transition: transform 0.2s ease, background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
5066
}
5167
5268
:host([theme='dark']) {
@@ -90,46 +106,49 @@ export class Button extends LitElement {
90106
display: inline-flex;
91107
width: 100%;
92108
min-height: var(--button-height-md);
93-
padding: 0 var(--button-padding-x-md);
109+
padding: var(--button-padding-md);
94110
align-items: center;
95-
justify-content: center;
111+
justify-content: var(--button-justify-content);
96112
gap: var(--spacing-xxs, 0.375rem);
97-
border-radius: var(--border-radius-base, 0.3125rem);
113+
border-radius: var(--button-border-radius);
98114
background: var(--button-background);
99-
border: 1px solid var(--button-border);
115+
border: var(--button-border-width) solid var(--button-border);
116+
box-shadow: var(--button-box-shadow);
100117
color: var(--button-text);
101118
cursor: pointer;
102119
font: inherit;
103120
font-size: var(--button-font-size-md);
104-
font-weight: var(--font-weight-bold, 600);
105-
line-height: 1;
121+
font-weight: var(--button-font-weight);
122+
line-height: var(--button-line-height);
106123
white-space: nowrap;
107124
text-decoration: none;
108125
box-sizing: border-box;
109-
transition: transform 0.2s ease, background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
126+
transition: var(--button-transition);
110127
}
111128
112129
:host([size='sm']) .button {
113130
min-height: var(--button-height-sm);
114-
padding: 0 var(--button-padding-x-sm);
131+
padding: var(--button-padding-sm);
115132
font-size: var(--button-font-size-sm);
116133
}
117134
118135
:host([size='lg']) .button {
119136
min-height: var(--button-height-lg);
120-
padding: 0 var(--button-padding-x-lg);
137+
padding: var(--button-padding-lg);
121138
font-size: var(--button-font-size-lg);
122139
}
123140
124141
.button:hover:not(:disabled) {
125142
background: var(--button-hover-background);
126143
border-color: var(--button-hover-border, var(--button-border));
144+
box-shadow: var(--button-hover-box-shadow, var(--button-box-shadow));
127145
color: var(--button-hover-text);
128146
}
129147
130148
.button:focus-visible {
131-
outline: 2px solid var(--button-focus-ring);
132-
outline-offset: 2px;
149+
outline: var(--button-focus-outline);
150+
outline-offset: var(--button-focus-outline-offset);
151+
box-shadow: var(--button-focus-box-shadow);
133152
}
134153
135154
.button:disabled {
@@ -193,7 +212,8 @@ export class Button extends LitElement {
193212
}
194213
195214
.button:active {
196-
transform: translateY(1px);
215+
transform: var(--button-active-transform);
216+
box-shadow: var(--button-active-box-shadow, var(--button-hover-box-shadow, var(--button-box-shadow)));
197217
}
198218
`
199219

0 commit comments

Comments
 (0)