Skip to content

Commit

Permalink
feat: Migrate Toast and ToastHeader to be ref forwarders
Browse files Browse the repository at this point in the history
  • Loading branch information
bpas247 committed Jul 28, 2019
1 parent df29001 commit 7fa9489
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 97 deletions.
139 changes: 71 additions & 68 deletions src/Toast.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import classNames from 'classnames';
import Fade from './Fade';
import Header from './ToastHeader';
import Body from './ToastBody';
import { createBootstrapComponent } from './ThemeProvider';
import { useBootstrapPrefix } from './ThemeProvider';
import ToastContext from './ToastContext';

const propTypes = {
Expand Down Expand Up @@ -56,76 +56,79 @@ const defaultProps = {
transition: Fade,
};

const Toast = ({
bsPrefix,
className,
children,
transition: Transition,
show,
animation,
delay,
autohide,
onClose,
innerRef,
...props
}) => {
const delayRef = useRef(delay);
const onCloseRef = useRef(onClose);

// We use refs for these, because we don't want to restart the autohide
// timer in case these values change.
delayRef.current = delay;
onCloseRef.current = onClose;

useEffect(() => {
if (!(autohide && show)) {
return undefined;
}

const autohideHandle = setTimeout(() => {
onCloseRef.current();
}, delayRef.current);

return () => {
clearTimeout(autohideHandle);
const Toast = React.forwardRef(
(
{
bsPrefix,
className,
children,
transition: Transition,
show,
animation,
delay,
autohide,
onClose,
...props
},
ref,
) => {
bsPrefix = useBootstrapPrefix('toast');
const delayRef = useRef(delay);
const onCloseRef = useRef(onClose);

// We use refs for these, because we don't want to restart the autohide
// timer in case these values change.
delayRef.current = delay;
onCloseRef.current = onClose;

useEffect(() => {
if (!(autohide && show)) {
return undefined;
}

const autohideHandle = setTimeout(() => {
onCloseRef.current();
}, delayRef.current);

return () => {
clearTimeout(autohideHandle);
};
}, [autohide, show]);

const useAnimation = Transition && animation;
const toast = (
<div
{...props}
ref={ref}
className={classNames(
bsPrefix,
className,
!useAnimation && show && 'show',
)}
role="alert"
aria-live="assertive"
aria-atomic="true"
>
{children}
</div>
);

const toastContext = {
onClose,
};
}, [autohide, show]);

const useAnimation = Transition && animation;
const toast = (
<div
{...props}
ref={innerRef}
className={classNames(
bsPrefix,
className,
!useAnimation && show && 'show',
)}
role="alert"
aria-live="assertive"
aria-atomic="true"
>
{children}
</div>
);

const toastContext = {
onClose,
};

return (
<ToastContext.Provider value={toastContext}>
{useAnimation ? <Transition in={show}>{toast}</Transition> : toast}
</ToastContext.Provider>
);
};

return (
<ToastContext.Provider value={toastContext}>
{useAnimation ? <Transition in={show}>{toast}</Transition> : toast}
</ToastContext.Provider>
);
},
);

Toast.propTypes = propTypes;
Toast.defaultProps = defaultProps;

const DecoratedToast = createBootstrapComponent(Toast, 'toast');

DecoratedToast.Body = Body;
DecoratedToast.Header = Header;
Toast.Body = Body;
Toast.Header = Header;

export default DecoratedToast;
export default Toast;
56 changes: 27 additions & 29 deletions src/ToastHeader.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,39 +28,37 @@ const defaultProps = {
closeButton: true,
};

const ToastHeader = ({
bsPrefix,
closeLabel,
closeButton,
className,
children,
...props
}) => {
bsPrefix = useBootstrapPrefix(bsPrefix, 'toast-header');
const ToastHeader = React.forwardRef(
(
{ bsPrefix, closeLabel, closeButton, className, children, ...props },
ref,
) => {
bsPrefix = useBootstrapPrefix(bsPrefix, 'toast-header');

const context = useContext(ToastContext);
const context = useContext(ToastContext);

const handleClick = useEventCallback(() => {
if (context) {
context.onClose();
}
});
const handleClick = useEventCallback(() => {
if (context) {
context.onClose();
}
});

return (
<div {...props} className={classNames(bsPrefix, className)}>
{children}
return (
<div ref={ref} {...props} className={classNames(bsPrefix, className)}>
{children}

{closeButton && (
<CloseButton
label={closeLabel}
onClick={handleClick}
className="ml-2 mb-1"
data-dismiss="toast"
/>
)}
</div>
);
};
{closeButton && (
<CloseButton
label={closeLabel}
onClick={handleClick}
className="ml-2 mb-1"
data-dismiss="toast"
/>
)}
</div>
);
},
);

ToastHeader.displayName = 'ToastHeader';
ToastHeader.propTypes = propTypes;
Expand Down

0 comments on commit 7fa9489

Please sign in to comment.