Skip to content

Commit

Permalink
feat: abstract out common component props as oc base props, add abili…
Browse files Browse the repository at this point in the history
…ty to forward ref (#106)

* feat: extract out common component props as oc base props

* feat: extend HTMLAttributes

* feat: use OcBaseProps in button

* feat: use base prop in all components

* chore: update snapshots
  • Loading branch information
ychhabra-eightfold authored May 5, 2022
1 parent d68d746 commit 48b7919
Show file tree
Hide file tree
Showing 37 changed files with 556 additions and 483 deletions.
3 changes: 2 additions & 1 deletion src/components/Badge/Badge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export const Badge: FC<BadgeProps> = ({
style,
children,
disruptive,
...rest
}) => {
const badgeClasses: string = mergeClasses([
styles.badge,
Expand All @@ -19,7 +20,7 @@ export const Badge: FC<BadgeProps> = ({
{ [styles.active]: active },
]);
return (
<span className={badgeClasses} style={style}>
<span className={badgeClasses} style={style} {...rest}>
{children}
</span>
);
Expand Down
11 changes: 2 additions & 9 deletions src/components/Badge/Badge.types.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from 'react';
import { OcBaseProps } from '../OcBase';

export interface BadgeProps {
export interface BadgeProps extends OcBaseProps<HTMLSpanElement> {
/**
* Badge is in an active state or not
*/
Expand All @@ -9,12 +10,4 @@ export interface BadgeProps {
* If badge is disruptive or not
*/
disruptive?: boolean;
/**
* Custom badge classNames
*/
classNames?: string;
/**
* Custom badge style
*/
style?: React.CSSProperties;
}
3 changes: 2 additions & 1 deletion src/components/Button/Button.types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React, { Ref } from 'react';
import { IconProps } from '../Icon';
import { OcBaseProps } from '../OcBase';

export enum ButtonIconAlign {
Left = 'left',
Expand Down Expand Up @@ -52,7 +53,7 @@ export interface InternalButtonProps extends ButtonProps {
ref?: Ref<HTMLButtonElement>;
}

export type NativeButtonProps = Omit<React.ButtonHTMLAttributes<any>, 'type'>;
export type NativeButtonProps = Omit<OcBaseProps<HTMLButtonElement>, 'type'>;

export interface SplitButtonProps
extends Omit<
Expand Down
2 changes: 2 additions & 0 deletions src/components/Button/PrimaryButton/PrimaryButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const PrimaryButton: FC<ButtonProps> = React.forwardRef(
theme,
toggle,
buttonWidth,
...rest
},
ref: Ref<HTMLButtonElement>
) => {
Expand All @@ -50,6 +51,7 @@ export const PrimaryButton: FC<ButtonProps> = React.forwardRef(

return (
<BaseButton
{...rest}
ref={ref}
alignIcon={alignIcon}
alignText={alignText}
Expand Down
2 changes: 2 additions & 0 deletions src/components/Button/SecondaryButton/SecondaryButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export const SecondaryButton: FC<ButtonProps> = React.forwardRef(
style,
toggle,
buttonWidth,
...rest
},
ref: Ref<HTMLButtonElement>
) => {
Expand All @@ -49,6 +50,7 @@ export const SecondaryButton: FC<ButtonProps> = React.forwardRef(

return (
<BaseButton
{...rest}
ref={ref}
alignIcon={alignIcon}
alignText={alignText}
Expand Down
154 changes: 82 additions & 72 deletions src/components/Dialog/BaseDialog/BaseDialog.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { FC, useEffect } from 'react';
import React, { FC, Ref, useEffect } from 'react';
import { BaseDialogProps } from './BaseDialog.types';
import { Portal } from '../../Portal';
import {
Expand All @@ -12,85 +12,95 @@ import { useScrollLock } from '../../../hooks/useScrollLock';

import styles from './base-dialog.module.scss';

export const BaseDialog: FC<BaseDialogProps> = ({
parent = document.body,
visible,
onClose,
maskClosable = true,
onVisibleChange,
height,
width,
zIndex,
header,
headerClassNames,
body,
bodyClassNames,
actions,
actionsClassNames,
dialogWrapperClassNames,
dialogClassNames,
}) => {
const labelId = uniqueId('dialog-label-');
export const BaseDialog: FC<BaseDialogProps> = React.forwardRef(
(
{
parent = document.body,
visible,
onClose,
maskClosable = true,
onVisibleChange,
height,
width,
zIndex,
header,
headerClassNames,
body,
bodyClassNames,
actions,
actionsClassNames,
dialogWrapperClassNames,
dialogClassNames,
...rest
},
ref: Ref<HTMLDivElement>
) => {
const labelId = uniqueId('dialog-label-');

const { lockScroll, unlockScroll } = useScrollLock(parent);
const { lockScroll, unlockScroll } = useScrollLock(parent);

const dialogBackdropClasses: string = mergeClasses([
styles.dialogBackdrop,
dialogWrapperClassNames,
{ [styles.visible]: visible },
]);
const dialogBackdropClasses: string = mergeClasses([
styles.dialogBackdrop,
dialogWrapperClassNames,
{ [styles.visible]: visible },
]);

const dialogClasses: string = mergeClasses([
styles.dialog,
dialogClassNames,
]);
const dialogClasses: string = mergeClasses([
styles.dialog,
dialogClassNames,
]);

const headerClasses: string = mergeClasses([
styles.header,
headerClassNames,
]);
const headerClasses: string = mergeClasses([
styles.header,
headerClassNames,
]);

const dialogStyle: React.CSSProperties = {
zIndex,
height,
width,
};
const dialogStyle: React.CSSProperties = {
zIndex,
height,
width,
};

useEffect(() => {
onVisibleChange?.(visible);
if (visible) {
lockScroll();
} else {
unlockScroll();
}
}, [visible]);
useEffect(() => {
onVisibleChange?.(visible);
if (visible) {
lockScroll();
} else {
unlockScroll();
}
}, [visible]);

const getDialog = (): JSX.Element => (
<div
role="dialog"
aria-modal={true}
aria-labelledby={labelId}
className={dialogBackdropClasses}
onClick={(e: React.MouseEvent<HTMLDivElement>) => {
maskClosable && onClose?.(e);
}}
>
const getDialog = (): JSX.Element => (
<div
className={dialogClasses}
style={dialogStyle}
onClick={stopPropagation}
{...rest}
ref={ref}
role="dialog"
aria-modal={true}
aria-labelledby={labelId}
className={dialogBackdropClasses}
onClick={(e: React.MouseEvent<HTMLDivElement>) => {
maskClosable && onClose?.(e);
}}
>
<div className={headerClasses}>
<span id={labelId}>{header}</span>
<NeutralButton
iconProps={{ path: IconName.mdiClose }}
onClick={onClose}
/>
<div
className={dialogClasses}
style={dialogStyle}
onClick={stopPropagation}
>
<div className={headerClasses}>
<span id={labelId}>{header}</span>
<NeutralButton
iconProps={{ path: IconName.mdiClose }}
onClick={onClose}
/>
</div>
<div className={bodyClassNames}>{body}</div>
{actions && (
<div className={actionsClassNames}>{actions}</div>
)}
</div>
<div className={bodyClassNames}>{body}</div>
{actions && <div className={actionsClassNames}>{actions}</div>}
</div>
</div>
);
return <Portal getContainer={() => parent}>{getDialog()}</Portal>;
};
);
return <Portal getContainer={() => parent}>{getDialog()}</Portal>;
}
);
10 changes: 8 additions & 2 deletions src/components/Dialog/BaseDialog/BaseDialog.types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React from 'react';
import React, { Ref } from 'react';
import { OcBaseProps } from '../../OcBase';

type EventType =
| React.KeyboardEvent<HTMLDivElement>
| React.MouseEvent<HTMLDivElement | HTMLButtonElement>;

export interface BaseDialogProps {
export interface BaseDialogProps
extends Omit<OcBaseProps<HTMLDivElement>, 'classNames'> {
/**
* Dialog is visible or not
*/
Expand Down Expand Up @@ -73,4 +75,8 @@ export interface BaseDialogProps {
* @default HTMLBodyElement
*/
parent?: HTMLDivElement | HTMLBodyElement;
/**
* Ref for the dialog element
*/
ref?: Ref<HTMLDivElement>;
}
Loading

0 comments on commit 48b7919

Please sign in to comment.