-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(atomic): add button function for lit components (#4857)
Add Lit equivalent to `<Button>` functional element. Also replaced `button.tsx` to `stencil-button.tsx` which is responsible for all the file changes ## Usage ### With Stencil ```tsx return ( <Button style="primary" text={i18n.t('load-more-results')} part="load-more-results-button" class="my-2 p-3 font-bold" onClick={() => onClick()} ></Button> ); ``` ### With Lit ```ts return button({ props: { style: 'primary', text: i18n.t('load-more-results'), part: 'load-more-results-button', class: 'my-2 p-3 font-bold', onClick: () => onClick(), }, }); ``` ## Question Lit does not natively support spreading attributes as we do in .tsx files, which can lead to code repetition. To address this, we could use [lit-helpers](https://open-wc.org/docs/development/lit-helpers/#spread-directives) to avoid duplicating attributes, properties, and events while maintaining consistency in our patterns. WDYT
- Loading branch information
Showing
64 changed files
with
373 additions
and
75 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
.../src/components/commerce/facets/facet-number-input/atomic-commerce-facet-number-input.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
packages/atomic/src/components/common/breadbox/breadcrumb-button.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
packages/atomic/src/components/common/breadbox/breadcrumb-clear-all.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
packages/atomic/src/components/common/breadbox/breadcrumb-show-less.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
packages/atomic/src/components/common/breadbox/breadcrumb-show-more.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
import {createRipple} from '@/src/utils/ripple'; | ||
import {fireEvent, within} from '@storybook/test'; | ||
import {html, render} from 'lit'; | ||
import {vi} from 'vitest'; | ||
import {button, ButtonProps} from './button'; | ||
|
||
vi.mock('@/src/utils/ripple', () => ({ | ||
createRipple: vi.fn(), | ||
})); | ||
|
||
describe('button', () => { | ||
let container: HTMLElement; | ||
|
||
beforeEach(() => { | ||
container = document.createElement('div'); | ||
document.body.appendChild(container); | ||
}); | ||
|
||
afterEach(() => { | ||
document.body.removeChild(container); | ||
}); | ||
|
||
const renderButton = (props: Partial<ButtonProps>): HTMLButtonElement => { | ||
render( | ||
html`${button({ | ||
props: { | ||
...props, | ||
style: props.style ?? 'primary', | ||
}, | ||
children: html``, | ||
})}`, | ||
container | ||
); | ||
return within(container).getByRole('button') as HTMLButtonElement; | ||
}; | ||
|
||
it('should render a button in the document', () => { | ||
const props = {}; | ||
const button = renderButton(props); | ||
expect(button).toBeInTheDocument(); | ||
}); | ||
|
||
it('should render a button with the correct style', () => { | ||
const props: Partial<ButtonProps> = { | ||
style: 'outline-error', | ||
}; | ||
|
||
const button = renderButton(props); | ||
|
||
expect(button).toHaveClass('btn-outline-error'); | ||
}); | ||
|
||
it('should render a button with the correct text', () => { | ||
const props = { | ||
text: 'Click me', | ||
}; | ||
|
||
const button = renderButton(props); | ||
|
||
expect(button.querySelector('span')?.textContent).toBe('Click me'); | ||
}); | ||
|
||
it('should wrap the button text with a truncate class', () => { | ||
const props = { | ||
text: 'Click me', | ||
}; | ||
|
||
const button = renderButton(props); | ||
|
||
expect(button.querySelector('span')).toHaveClass('truncate'); | ||
}); | ||
|
||
it('should handle click event', async () => { | ||
const handleClick = vi.fn(); | ||
const props = { | ||
onClick: handleClick, | ||
}; | ||
|
||
const button = renderButton(props); | ||
|
||
await fireEvent.click(button); | ||
|
||
expect(handleClick).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should apply disabled attribute', () => { | ||
const props = { | ||
disabled: true, | ||
}; | ||
|
||
const button = renderButton(props); | ||
|
||
expect(button.hasAttribute('disabled')).toBe(true); | ||
}); | ||
|
||
it('should apply aria attributes', () => { | ||
const props: Partial<ButtonProps> = { | ||
ariaLabel: 'button', | ||
ariaPressed: 'true', | ||
}; | ||
|
||
const button = renderButton(props); | ||
|
||
expect(button.getAttribute('aria-label')).toBe('button'); | ||
expect(button.getAttribute('aria-pressed')).toBe('true'); | ||
}); | ||
|
||
it('should apply custom class', () => { | ||
const props = { | ||
class: 'custom-class', | ||
}; | ||
|
||
const button = renderButton(props); | ||
|
||
expect(button).toHaveClass('custom-class'); | ||
expect(button).toHaveClass('btn-primary'); | ||
}); | ||
|
||
it('should apply part attribute', () => { | ||
const props = { | ||
part: 'button-part', | ||
}; | ||
|
||
const button = renderButton(props); | ||
|
||
expect(button.getAttribute('part')).toBe('button-part'); | ||
}); | ||
|
||
it('should apply title attribute', () => { | ||
const props = { | ||
title: 'Button Title', | ||
}; | ||
|
||
const button = renderButton(props); | ||
|
||
expect(button.getAttribute('title')).toBe('Button Title'); | ||
}); | ||
|
||
it('should apply tabindex attribute', () => { | ||
const props = { | ||
tabIndex: 1, | ||
}; | ||
|
||
const button = renderButton(props); | ||
|
||
expect(button.getAttribute('tabindex')).toBe('1'); | ||
}); | ||
|
||
it('should apply role attribute', () => { | ||
const props: Partial<ButtonProps> = { | ||
role: 'button', | ||
}; | ||
|
||
const button = renderButton(props); | ||
|
||
expect(button.getAttribute('role')).toBe('button'); | ||
}); | ||
|
||
it('should call onMouseDown when the mousedown event is fired on the button', async () => { | ||
const props: Partial<ButtonProps> = {}; | ||
const button = renderButton(props); | ||
await fireEvent.mouseDown(button); | ||
expect(createRipple).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should apply form attribute', () => { | ||
const props = { | ||
form: 'form-id', | ||
}; | ||
|
||
const button = renderButton(props); | ||
|
||
expect(button.getAttribute('form')).toBe('form-id'); | ||
}); | ||
|
||
it('should apply type attribute', () => { | ||
const props: Partial<ButtonProps> = { | ||
type: 'submit', | ||
}; | ||
|
||
const button = renderButton(props); | ||
|
||
expect(button.getAttribute('type')).toBe('submit'); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
import {html} from 'lit-html'; | ||
import {ifDefined} from 'lit-html/directives/if-defined.js'; | ||
import {createRipple} from '../../utils/ripple'; | ||
import { | ||
getRippleColorForButtonStyle, | ||
getClassNameForButtonStyle, | ||
ButtonStyle, | ||
} from './button-style'; | ||
|
||
export interface ButtonProps { | ||
style: ButtonStyle; | ||
onClick?(event?: MouseEvent): void; | ||
class?: string; | ||
text?: string; | ||
part?: string; | ||
type?: 'button' | 'submit' | 'reset' | 'menu'; | ||
form?: string; | ||
role?: | ||
| 'status' | ||
| 'application' | ||
| 'checkbox' | ||
| 'button' | ||
| 'dialog' | ||
| 'img' | ||
| 'radiogroup' | ||
| 'toolbar' | ||
| 'listitem' | ||
| 'list' | ||
| 'separator'; | ||
disabled?: boolean; | ||
ariaLabel?: string; | ||
ariaExpanded?: 'true' | 'false'; | ||
ariaPressed?: 'true' | 'false' | 'mixed'; | ||
ariaChecked?: 'true' | 'false' | 'mixed'; | ||
ariaCurrent?: 'page' | 'false'; | ||
ariaControls?: string; | ||
ariaHidden?: 'true' | 'false'; | ||
tabIndex?: number; | ||
title?: string; | ||
} | ||
|
||
export const button = <T>({ | ||
props, | ||
children, | ||
}: { | ||
props: ButtonProps; | ||
children: T; | ||
}) => { | ||
const rippleColor = getRippleColorForButtonStyle(props.style); | ||
const className = getClassNameForButtonStyle(props.style); | ||
|
||
return html` <button | ||
type=${ifDefined(props.type)} | ||
title=${ifDefined(props.title)} | ||
tabindex=${ifDefined(props.tabIndex)} | ||
role=${ifDefined(props.role)} | ||
part=${ifDefined(props.part)} | ||
form=${ifDefined(props.form)} | ||
class=${props.class ? `${className} ${props.class}` : className} | ||
aria-pressed=${ifDefined(props.ariaPressed)} | ||
aria-label=${ifDefined(props.ariaLabel)} | ||
aria-hidden=${ifDefined(props.ariaHidden)} | ||
aria-expanded=${ifDefined(props.ariaExpanded)} | ||
aria-current=${ifDefined(props.ariaCurrent)} | ||
aria-controls=${ifDefined(props.ariaControls)} | ||
aria-checked=${ifDefined(props.ariaChecked)} | ||
@mousedown=${(e: MouseEvent) => createRipple(e, {color: rippleColor})} | ||
@click=${props.onClick} | ||
?disabled=${props.disabled} | ||
> | ||
{props.text ? <span class="truncate">${props.text}</span> : null} | ||
${children} | ||
</button>`; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
packages/atomic/src/components/common/expandable-text/expandable-text.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
packages/atomic/src/components/common/facets/category-facet/all-categories-button.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
packages/atomic/src/components/common/facets/category-facet/search-value.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
packages/atomic/src/components/common/facets/facet-number-input/facet-number-input.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.