Skip to content
This repository has been archived by the owner on Aug 29, 2023. It is now read-only.

Commit

Permalink
Merge pull request #61 from smartive-education/feat/navi-buttons-as-link
Browse files Browse the repository at this point in the history
feat: add possibility to render naviButtons as link
  • Loading branch information
nschaer92 authored Apr 4, 2023
2 parents 70c1c31 + a397abc commit 48a7af8
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 18 deletions.
34 changes: 29 additions & 5 deletions src/components/buttons/navi-buttons/logout-button.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,39 @@
import React, { FC, ButtonHTMLAttributes } from 'react';
import React, { FC, ButtonHTMLAttributes, AnchorHTMLAttributes } from 'react';
import { NaviButton } from './navi-button';

export type LogoutButtonProps = {
/**
* Specifies a custom link component, e.g. next/link.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
linkComponent?: FC<any>;
/**
* Specifies the arguments of the custom link component.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
linkComponentArgs?: Record<string, any>;
/**
* Specifies the action, which is called as the user clicks on the logout button.
*/
onClick: () => void;
} & ButtonHTMLAttributes<HTMLButtonElement>;
onClick?: () => void;
/**
* Specifies if the navi button should render as a link component.
*/
renderAsLink?: boolean;
} & ButtonHTMLAttributes<HTMLButtonElement> &
AnchorHTMLAttributes<HTMLAnchorElement>;

export const LogoutButton: FC<LogoutButtonProps> = ({ onClick, ...args }) => {
export const LogoutButton: FC<LogoutButtonProps> = ({
linkComponent,
linkComponentArgs,
onClick,
renderAsLink = false,
...args
}) => {
return (
<NaviButton
{...args}
{...linkComponentArgs}
/*
* Es wurde bewusst entschieden, dass IconLogout zu kopieren und nicht dieses wiederzuverwenden, da die Animation des Pfeils hier ein sehr spezifischer
* Anwendungsfall darstellt. Gemäss Definition im Figma würde der Pfeil initial 3px aus der viewBox des SVGs ragen. Auf die Vergrösserung der viewBox wurde
Expand All @@ -36,8 +59,9 @@ export const LogoutButton: FC<LogoutButtonProps> = ({ onClick, ...args }) => {
</defs>
</svg>
}
linkComponent={linkComponent}
onClick={onClick}
{...args}
renderAsLink={renderAsLink}
>
Logout
</NaviButton>
Expand Down
47 changes: 40 additions & 7 deletions src/components/buttons/navi-buttons/navi-button.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React, { ButtonHTMLAttributes, FC, ReactNode } from 'react';
import React, { AnchorHTMLAttributes, ButtonHTMLAttributes, FC, ReactNode } from 'react';
import { Label, LabelSize } from '../../typography/label';
import { mergeClassNames } from '../../../helpers/merge-class-names';

export type NaviButtonProps = {
export type NaviButtonProps<T> = {
/**
* Optional aria-label (Verb + Noun) has to be set, if no inner text is set or the text of the button does not describe the action.
*/
Expand All @@ -15,13 +15,29 @@ export type NaviButtonProps = {
* Specifies the icon to display in the navi button.
*/
icon?: ReactNode;
/**
* Specifies a custom link component, e.g. next/link.
*/
linkComponent?: FC<T>;
/**
* Specifies the action, which is called as the user clicks on the navi button.
*/
onClick: () => void;
} & ButtonHTMLAttributes<HTMLButtonElement>;
onClick?: () => void;
/**
* Specifies if the navi button should render as a link component.
*/
renderAsLink?: boolean;
} & ButtonHTMLAttributes<HTMLButtonElement> &
AnchorHTMLAttributes<HTMLAnchorElement> &
Omit<T, 'className'>;

export function NaviButton<
T extends {
className?: string;
} = AnchorHTMLAttributes<HTMLElement>
>({ ariaLabel, children, icon, linkComponent, onClick, renderAsLink = false, ...args }: NaviButtonProps<T>): JSX.Element {
const LinkComponent = linkComponent || 'a';

export const NaviButton: FC<NaviButtonProps> = ({ ariaLabel, children, icon, onClick, ...args }) => {
const naviButtonBaseStyle = [
'flex',
'items-center',
Expand All @@ -41,12 +57,29 @@ export const NaviButton: FC<NaviButtonProps> = ({ ariaLabel, children, icon, onC

const classes = mergeClassNames(naviButtonBaseStyle);

return (
const linkComponentToRender = (
<LinkComponent
// eslint-disable-next-line @typescript-eslint/no-explicit-any
{...(args as any)}
aria-label={ariaLabel}
// eslint-disable-next-line react/forbid-component-props
className={classes}
>
<>
{icon}
<Label size={LabelSize.s}>{children}</Label>
</>
</LinkComponent>
);

const buttonComponentToRender = (
<button aria-label={ariaLabel} className={classes} onClick={onClick} {...args}>
<>
{icon}
<Label size={LabelSize.s}>{children}</Label>
</>
</button>
);
};

return renderAsLink ? linkComponentToRender : buttonComponentToRender;
}
33 changes: 29 additions & 4 deletions src/components/buttons/navi-buttons/profile-picture-button.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { FC, ButtonHTMLAttributes } from 'react';
import React, { FC, ButtonHTMLAttributes, AnchorHTMLAttributes } from 'react';
import { NaviButton } from './navi-button';
import { ProfilePicture, ProfilePictureSize } from '../../profile-picture/profile-picture';

Expand All @@ -21,27 +21,52 @@ export type ProfilePictureButtonProps = {
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
imageComponentArgs?: Record<string, any>;
/**
* Specifies a custom link component, e.g. next/link.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
linkComponent?: FC<any>;
/**
* Specifies the arguments of the custom link component.
*/
// eslint-disable-next-line @typescript-eslint/no-explicit-any
linkComponentArgs?: Record<string, any>;
/**
* Specifies the action, which is called as the user clicks on the profile picture button.
*/
onClick: () => void;
onClick?: () => void;
/**
* Specifies if the profile picture button should render as a link component.
*/
renderAsLink?: boolean;
/**
* Specifies the URL of the profile picture.
*/
src: string;
} & ButtonHTMLAttributes<HTMLButtonElement>;
} & ButtonHTMLAttributes<HTMLButtonElement> &
AnchorHTMLAttributes<HTMLAnchorElement>;

export const ProfilePictureButton: FC<ProfilePictureButtonProps> = ({
alt,
ariaLabel,
imageComponent,
imageComponentArgs,
linkComponent,
linkComponentArgs,
onClick,
renderAsLink = false,
src,
...args
}) => {
return (
<NaviButton aria-label={ariaLabel} onClick={onClick} {...args}>
<NaviButton
{...args}
{...linkComponentArgs}
aria-label={ariaLabel}
onClick={onClick}
linkComponent={linkComponent}
renderAsLink={renderAsLink}
>
<ProfilePicture
imageComponent={imageComponent}
{...imageComponentArgs}
Expand Down
5 changes: 3 additions & 2 deletions src/components/buttons/navi-buttons/settings-button.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { FC, ButtonHTMLAttributes } from 'react';
import React, { FC, ButtonHTMLAttributes, AnchorHTMLAttributes } from 'react';
import { NaviButton } from './navi-button';
import { IconSettings } from '../../icons/icon-settings';

Expand All @@ -7,7 +7,8 @@ export type SettingsButtonProps = {
* Specifies the action, which is called as the user clicks on the settings button.
*/
onClick: () => void;
} & ButtonHTMLAttributes<HTMLButtonElement>;
} & ButtonHTMLAttributes<HTMLButtonElement> &
AnchorHTMLAttributes<HTMLAnchorElement>;

export const SettingsButton: FC<SettingsButtonProps> = ({ onClick, ...args }) => {
return (
Expand Down

0 comments on commit 48a7af8

Please sign in to comment.