Skip to content

Commit

Permalink
feat(@clayui/button): improves component typing to create API Table
Browse files Browse the repository at this point in the history
  • Loading branch information
matuzalemsteles committed Jan 29, 2025
1 parent da6267a commit e4eff1c
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 81 deletions.
3 changes: 2 additions & 1 deletion packages/clay-button/docs/button.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ description: 'Buttons communicate an action to happen on user interaction.'
lexiconDefinition: 'https://liferay.design/lexicon/core-components/buttons/'
packageNpm: '@clayui/button'
packageUse: "import Button from '@clayui/button';"
packageTypes: ['clay-button/src']
---

## Display Types
Expand Down Expand Up @@ -88,7 +89,7 @@ export default function App() {
/>
<Button>
<span className="inline-item inline-item-before">
<Icon spritemap={spritemap} symbol="times" />
<Icon symbol="times" />
</span>
Close w/ text
</Button>
Expand Down
148 changes: 75 additions & 73 deletions packages/clay-button/src/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,84 +83,86 @@ export interface IProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
translucent?: boolean;
}

function ButtonInner(
{
alert,
block,
borderless,
children,
className,
dark,
displayType = 'primary',
monospaced,
outline,
rounded,
size = 'regular',
small,
translucent,
type = 'button',
...otherProps
}: IProps,
ref: React.Ref<HTMLButtonElement>
) {
const childArray = React.Children.toArray(children);

warning(
!(
childArray.length === 1 &&
// @ts-ignore
childArray[0].type?.displayName === 'ClayIcon' &&
typeof otherProps['aria-label'] !== 'string' &&
typeof otherProps['aria-labelledby'] !== 'string'
),
'Button Accessibility: Component has only the Icon declared. Define an `aria-label` or `aria-labelledby` attribute that labels the interactive button that screen readers can read. The `title` attribute is optional but consult your design team.'
);

if (displayType === 'beta') {
displayType = 'info';
translucent = true;
} else if (displayType === 'beta-dark') {
dark = true;
displayType = 'info';
translucent = true;
}

return (
<button
className={classNames(className, 'btn', {
'alert-btn': alert,
'btn-block': block,
'btn-monospaced': monospaced,
'btn-outline-borderless': borderless,
'btn-sm': small && (!size || size === 'regular'),
'btn-translucent': translucent,
'clay-dark': dark,
[`btn-${displayType}`]: displayType && !outline && !borderless,
[`btn-outline-${displayType}`]:
displayType && (outline || borderless),
'rounded-pill': rounded,
[`btn-${size}`]: size && size !== 'regular',
})}
ref={ref}
type={type}
{...otherProps}
>
{children}
</button>
);
export interface IForwardRef<T, P = {}>
extends React.ForwardRefExoticComponent<P & React.RefAttributes<T>> {
Group: typeof Group;
}

type ForwardRef = {
displayName: string;
Group: typeof Group;
(props: IProps & {ref?: React.Ref<HTMLButtonElement>}): JSX.Element;
};
function forwardRef<T, P = {}>(component: React.RefForwardingComponent<T, P>) {
return React.forwardRef<T, P>(component) as IForwardRef<T, P>;
}

const Button = React.forwardRef(ButtonInner) as unknown as ForwardRef;
const Button = forwardRef(
(
{
alert,
block,
borderless,
children,
className,
dark,
displayType = 'primary',
monospaced,
outline,
rounded,
size = 'regular',
small,
translucent,
type = 'button',
...otherProps
}: IProps,
ref: React.Ref<HTMLButtonElement>
) => {
const childArray = React.Children.toArray(children);

warning(
!(
childArray.length === 1 &&
// @ts-ignore
childArray[0].type?.displayName === 'ClayIcon' &&
typeof otherProps['aria-label'] !== 'string' &&
typeof otherProps['aria-labelledby'] !== 'string'
),
'Button Accessibility: Component has only the Icon declared. Define an `aria-label` or `aria-labelledby` attribute that labels the interactive button that screen readers can read. The `title` attribute is optional but consult your design team.'
);

if (displayType === 'beta') {
displayType = 'info';
translucent = true;
} else if (displayType === 'beta-dark') {
dark = true;
displayType = 'info';
translucent = true;
}

return (
<button
className={classNames(className, 'btn', {
'alert-btn': alert,
'btn-block': block,
'btn-monospaced': monospaced,
'btn-outline-borderless': borderless,
'btn-sm': small && (!size || size === 'regular'),
'btn-translucent': translucent,
'clay-dark': dark,
[`btn-${displayType}`]:
displayType && !outline && !borderless,
[`btn-outline-${displayType}`]:
displayType && (outline || borderless),
'rounded-pill': rounded,
[`btn-${size}`]: size && size !== 'regular',
})}
ref={ref}
type={type}
{...otherProps}
>
{children}
</button>
);
}
);

Button.Group = Group;

Button.displayName = 'ClayButton';

export {Button};
export default Button;
13 changes: 7 additions & 6 deletions packages/clay-button/src/Group.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
import classNames from 'classnames';
import React from 'react';

export interface IButtonGroupProps
extends React.HTMLAttributes<HTMLDivElement> {
export type Props = {
/**
* Flag to indicate the spacing between the buttons.
*/
Expand All @@ -17,16 +16,16 @@ export interface IButtonGroupProps
* Flag to indicate if buttons are stacked vertically.
*/
vertical?: boolean;
}
} & React.HTMLAttributes<HTMLDivElement>;

const ClayButtonGroup = ({
const Group = ({
children,
className,
role = 'group',
spaced,
vertical,
...otherProps
}: IButtonGroupProps) => (
}: Props) => (
<div
{...otherProps}
className={classNames(className, {
Expand All @@ -40,4 +39,6 @@ const ClayButtonGroup = ({
</div>
);

export default ClayButtonGroup;
Group.displayName = 'ClayButtonGroup';

export default Group;
3 changes: 2 additions & 1 deletion packages/clay-button/src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

import Button from './Button';
import ClayButtonWithIcon from './ButtonWithIcon';
import Group from './Group';

export type {Props as ButtonWithIconProps} from './ButtonWithIcon';
export {ClayButtonWithIcon};
export {ClayButtonWithIcon, Group, Button};
export default Button;
1 change: 1 addition & 0 deletions tsconfig.declarations.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"emitDeclarationOnly": true,
"noEmit": false,
"removeComments": false,
"skipLibCheck": true,
"paths": {}
},
"exclude": [
Expand Down

0 comments on commit e4eff1c

Please sign in to comment.