Skip to content

Commit

Permalink
chore(atomic): add interfaces for functional lit components (#5000)
Browse files Browse the repository at this point in the history
https://coveord.atlassian.net/browse/KIT-3990

This will be helpful as it will be easier to create new functions with
this and simpler to use since all components will have :

```
props :{},
children: ...
```
  • Loading branch information
alexprudhomme authored Feb 24, 2025
1 parent 6ddc34b commit 66c7f30
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 37 deletions.
6 changes: 2 additions & 4 deletions packages/atomic/src/components/common/button.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {FunctionalComponentWithChildren} from '@/src/utils/functional-component-utils';
import {html} from 'lit';
import {ifDefined} from 'lit/directives/if-defined.js';
import {when} from 'lit/directives/when.js';
Expand Down Expand Up @@ -40,12 +41,9 @@ export interface ButtonProps {
title?: string;
}

export const button = <T>({
export const button: FunctionalComponentWithChildren<ButtonProps> = ({
props,
children,
}: {
props: ButtonProps;
children: T;
}) => {
const rippleColor = getRippleColorForButtonStyle(props.style);
const className = getClassNameForButtonStyle(props.style);
Expand Down
9 changes: 5 additions & 4 deletions packages/atomic/src/components/common/checkbox.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,11 @@ describe('checkbox', () => {
const renderCheckbox = (props: Partial<CheckboxProps>): HTMLButtonElement => {
render(
html`${checkbox({
...props,
checked: props.checked ?? false,
onToggle: props.onToggle ?? vi.fn(),
props: {
...props,
checked: props.checked ?? false,
onToggle: props.onToggle ?? vi.fn(),
},
})}`,
container
);
Expand Down Expand Up @@ -111,7 +113,6 @@ describe('checkbox', () => {
expect(button).toHaveClass(
'w-4',
// TODO: KIT-3907
// @ts-expect-error the typing is incorrect. matchers should be a string[]
'h-4',
'grid',
'place-items-center',
Expand Down
5 changes: 3 additions & 2 deletions packages/atomic/src/components/common/checkbox.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {html, TemplateResult} from 'lit';
import {FunctionalComponent} from '@/src/utils/functional-component-utils';
import {html} from 'lit';
import {classMap} from 'lit/directives/class-map.js';
import {ifDefined} from 'lit/directives/if-defined.js';
import {ref, RefOrCallback} from 'lit/directives/ref.js';
Expand Down Expand Up @@ -26,7 +27,7 @@ export interface CheckboxProps {
onMouseDown?(evt: MouseEvent): void;
}

export const checkbox = (props: CheckboxProps): TemplateResult => {
export const checkbox: FunctionalComponent<CheckboxProps> = ({props}) => {
const partName = props.part ?? 'checkbox';
const baseClassNames =
'w-4 h-4 grid place-items-center rounded no-outline hover:border-primary-light focus-visible:border-primary-light';
Expand Down
11 changes: 4 additions & 7 deletions packages/atomic/src/components/common/heading.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,10 @@ describe('heading', () => {
children?: string
): HTMLElement => {
render(
html`${heading(
{
...props,
level: props.level ?? 1,
},
html`${children}`
)}`,
html` ${heading({
props: {...props, level: props.level ?? 1},
children: html`${children}`,
})}`,
container
);
return within(container).getByRole(
Expand Down
11 changes: 7 additions & 4 deletions packages/atomic/src/components/common/heading.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import {FunctionalComponentWithChildren} from '@/src/utils/functional-component-utils';
import {ifDefined} from 'lit/directives/if-defined.js';
import {html, literal, unsafeStatic} from 'lit/static-html.js';

Expand All @@ -18,10 +19,12 @@ export interface HeadingProps {
part?: string;
}

export const heading = <T>(
{level, class: classname, part}: HeadingProps,
children?: T
) => {
export const heading: FunctionalComponentWithChildren<HeadingProps> = ({
props,
children,
}) => {
const {level, class: classname, part} = props;

const headingTag =
level > 0 && level <= 6 ? unsafeStatic(`h${level}`) : literal`div`;

Expand Down
21 changes: 12 additions & 9 deletions packages/atomic/src/components/common/load-more/button.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import {FunctionalComponent} from '@/src/utils/functional-component-utils';
import {i18n} from 'i18next';
import {html} from 'lit';
import {button, ButtonProps} from '../button';

interface LoadMoreButtonProps {
Expand All @@ -8,20 +10,21 @@ interface LoadMoreButtonProps {
label?: 'load-more-results' | 'load-more-products';
}

export function loadMoreButton({
i18n,
onClick,
moreAvailable,
label,
}: LoadMoreButtonProps) {
export const loadMoreButton: FunctionalComponent<LoadMoreButtonProps> = ({
props,
}) => {
const {i18n, onClick, moreAvailable, label} = props;
if (!moreAvailable) {
return;
}
const props: ButtonProps = {
const buttonProps: ButtonProps = {
style: 'primary',
part: 'load-more-results-button',
class: 'my-2 p-3 font-bold',
onClick: () => onClick(),
};
return button({props, children: i18n.t(label || 'load-more-results')});
}
return button({
props: buttonProps,
children: html`${i18n.t(label || 'load-more-results')}`,
});
};
11 changes: 6 additions & 5 deletions packages/atomic/src/components/common/radio-button.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ describe('radioButton', () => {
props: Partial<RadioButtonProps>
): HTMLInputElement => {
render(
html`${radioButton({...props, groupName: 'test-group'})}`,
html`${radioButton({props: {...props, groupName: 'test-group'}})}`,
container
);

return within(container).getByRole('radio');
};

Expand Down Expand Up @@ -69,9 +70,9 @@ describe('radioButton', () => {
};

render(
html`${radioButton({...props, text: 'radio-1'})}
${radioButton({...props, text: 'radio-2'})}
${radioButton({...props, text: 'radio-3'})}`,
html`${radioButton({props: {...props, text: 'radio-1'}})}
${radioButton({props: {...props, text: 'radio-2'}})}
${radioButton({props: {...props, text: 'radio-3'}})}`,
container
);

Expand Down Expand Up @@ -131,7 +132,7 @@ describe('radioButton', () => {
ref,
};

render(html`${radioButton(props)}`, container);
render(html`${radioButton({props})}`, container);

expect(ref).toHaveBeenCalled();
});
Expand Down
5 changes: 3 additions & 2 deletions packages/atomic/src/components/common/radio-button.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {html, TemplateResult} from 'lit';
import {FunctionalComponent} from '@/src/utils/functional-component-utils';
import {html} from 'lit';
import {classMap} from 'lit/directives/class-map.js';
import {ifDefined} from 'lit/directives/if-defined.js';
import {ref, RefOrCallback} from 'lit/directives/ref.js';
Expand Down Expand Up @@ -31,7 +32,7 @@ export interface RadioButtonProps {
ref?: RefOrCallback;
}

export const radioButton = (props: RadioButtonProps): TemplateResult => {
export const radioButton: FunctionalComponent<RadioButtonProps> = ({props}) => {
const classNames = {
'btn-radio': true,
selected: Boolean(props.checked),
Expand Down
18 changes: 18 additions & 0 deletions packages/atomic/src/utils/functional-component-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import {TemplateResult} from 'lit';

export interface FunctionalComponent<T> {
({props}: {props: T}): TemplateResult | undefined;
}

export interface FunctionalComponentWithChildren<T> {
({
props,
children,
}: {
props: T;
children:
| TemplateResult
| TemplateResult[]
| (TemplateResult | undefined)[];
}): TemplateResult;
}

0 comments on commit 66c7f30

Please sign in to comment.