Skip to content

Commit

Permalink
fix(Offcanvas): fix backdrop class (#5821)
Browse files Browse the repository at this point in the history
  • Loading branch information
kyletsang committed May 17, 2021
1 parent 1f5d50b commit 309f881
Show file tree
Hide file tree
Showing 2 changed files with 144 additions and 132 deletions.
272 changes: 142 additions & 130 deletions src/Offcanvas.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import BaseModal, {
} from 'react-overlays/Modal';
import ModalManager from 'react-overlays/ModalManager';
import useRootClose from 'react-overlays/useRootClose';
import Fade from './Fade';
import OffcanvasBody from './OffcanvasBody';
import OffcanvasToggling from './OffcanvasToggling';
import ModalContext from './ModalContext';
Expand Down Expand Up @@ -48,7 +49,7 @@ const propTypes = {
backdrop: PropTypes.bool,

/**
* Add an optional extra class name to .offcanvas-backdrop.
* Add an optional extra class name to .modal-backdrop.
*/
backdropClassName: PropTypes.string,

Expand Down Expand Up @@ -171,136 +172,147 @@ function DialogTransition(props) {
return <OffcanvasToggling {...props} />;
}

const Offcanvas: BsPrefixRefForwardingComponent<
'div',
OffcanvasProps
> = React.forwardRef<ModalHandle, OffcanvasProps>(
(
{
bsPrefix,
className,
children,
'aria-labelledby': ariaLabelledby,
placement,

/* BaseModal props */

show,
backdrop,
keyboard,
scroll,
onEscapeKeyDown,
onShow,
onHide,
container,
autoFocus,
enforceFocus,
restoreFocus,
restoreFocusOptions,
onEntered,
onExit,
onExiting,
onEnter,
onEntering,
onExited,
backdropClassName,
manager: propsManager,
...props
},
ref,
) => {
const [dialogElement, setDialogElement] = useCallbackRef<HTMLElement>();
const modalManager = useRef<ModalManager>();
const handleHide = useEventCallback(onHide);

bsPrefix = useBootstrapPrefix(bsPrefix, 'offcanvas');

// If there's a backdrop, let BaseModal handle closing.
useRootClose(dialogElement, handleHide, {
disabled: backdrop,
});

const modalContext = useMemo(
() => ({
onHide: handleHide,
}),
[handleHide],
);

function getModalManager() {
if (propsManager) return propsManager;
if (!modalManager.current)
modalManager.current = new ModalManager({
handleContainerOverflow: !scroll,
});
return modalManager.current;
}

const handleEnter = (node, ...args) => {
if (node) node.style.visibility = 'visible';
onEnter?.(node, ...args);
setDialogElement(node);
};

const handleExited = (node, ...args) => {
if (node) node.style.visibility = '';
onExited?.(...args);
setDialogElement(null);
};

const renderBackdrop = useCallback(
(backdropProps) => (
function BackdropTransition(props) {
return <Fade {...props} />;
}

const Offcanvas: BsPrefixRefForwardingComponent<'div', OffcanvasProps> =
React.forwardRef<ModalHandle, OffcanvasProps>(
(
{
bsPrefix,
className,
children,
'aria-labelledby': ariaLabelledby,
placement,

/* BaseModal props */

show,
backdrop,
keyboard,
scroll,
onEscapeKeyDown,
onShow,
onHide,
container,
autoFocus,
enforceFocus,
restoreFocus,
restoreFocusOptions,
onEntered,
onExit,
onExiting,
onEnter,
onEntering,
onExited,
backdropClassName,
manager: propsManager,
...props
},
ref,
) => {
const [dialogElement, setDialogElement] = useCallbackRef<HTMLElement>();
const modalManager = useRef<ModalManager>();
const handleHide = useEventCallback(onHide);

bsPrefix = useBootstrapPrefix(bsPrefix, 'offcanvas');
const modalBsPrefix = useBootstrapPrefix(undefined, 'modal');

// If there's a backdrop, let BaseModal handle closing.
useRootClose(dialogElement, handleHide, {
disabled: backdrop,
});

const modalContext = useMemo(
() => ({
onHide: handleHide,
}),
[handleHide],
);

function getModalManager() {
if (propsManager) return propsManager;
if (!modalManager.current)
modalManager.current = new ModalManager({
handleContainerOverflow: !scroll,
});
return modalManager.current;
}

const handleEnter = (node, ...args) => {
if (node) node.style.visibility = 'visible';
onEnter?.(node, ...args);
setDialogElement(node);
};

const handleExited = (node, ...args) => {
if (node) node.style.visibility = '';
onExited?.(...args);
setDialogElement(null);
};

const renderBackdrop = useCallback(
(backdropProps) => (
<div
{...backdropProps}
className={classNames(
`${modalBsPrefix}-backdrop`,
backdropClassName,
)}
/>
),
[backdropClassName, modalBsPrefix],
);

const renderDialog = (dialogProps) => (
<div
{...backdropProps}
className={classNames(`${bsPrefix}-backdrop`, backdropClassName)}
/>
),
[backdropClassName, bsPrefix],
);

const renderDialog = (dialogProps) => (
<div
role="dialog"
{...dialogProps}
{...props}
className={classNames(className, bsPrefix, `${bsPrefix}-${placement}`)}
aria-labelledby={ariaLabelledby}
>
{children}
</div>
);

return (
<ModalContext.Provider value={modalContext}>
<BaseModal
show={show}
ref={ref}
backdrop={backdrop}
container={container}
keyboard={keyboard}
autoFocus={autoFocus}
enforceFocus={enforceFocus}
restoreFocus={restoreFocus}
restoreFocusOptions={restoreFocusOptions}
onEscapeKeyDown={onEscapeKeyDown}
onShow={onShow}
onHide={onHide}
onEnter={handleEnter}
onEntering={onEntering}
onEntered={onEntered}
onExit={onExit}
onExiting={onExiting}
onExited={handleExited}
manager={getModalManager()}
containerClassName={`${bsPrefix}-open`}
transition={DialogTransition}
renderBackdrop={renderBackdrop}
renderDialog={renderDialog}
/>
</ModalContext.Provider>
);
},
);
role="dialog"
{...dialogProps}
{...props}
className={classNames(
className,
bsPrefix,
`${bsPrefix}-${placement}`,
)}
aria-labelledby={ariaLabelledby}
>
{children}
</div>
);

return (
<ModalContext.Provider value={modalContext}>
<BaseModal
show={show}
ref={ref}
backdrop={backdrop}
container={container}
keyboard={keyboard}
autoFocus={autoFocus}
enforceFocus={enforceFocus}
restoreFocus={restoreFocus}
restoreFocusOptions={restoreFocusOptions}
onEscapeKeyDown={onEscapeKeyDown}
onShow={onShow}
onHide={onHide}
onEnter={handleEnter}
onEntering={onEntering}
onEntered={onEntered}
onExit={onExit}
onExiting={onExiting}
onExited={handleExited}
manager={getModalManager()}
containerClassName={`${bsPrefix}-open`}
transition={DialogTransition}
backdropTransition={BackdropTransition}
renderBackdrop={renderBackdrop}
renderDialog={renderDialog}
/>
</ModalContext.Provider>
);
},
);

Offcanvas.displayName = 'Offcanvas';
Offcanvas.propTypes = propTypes;
Expand Down
4 changes: 2 additions & 2 deletions test/OffcanvasSpec.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ describe('<Offcanvas>', () => {
<Offcanvas show backdropClassName="custom-backdrop" onHide={noOp}>
<strong>Message</strong>
</Offcanvas>,
).find('.offcanvas-backdrop.custom-backdrop');
).find('.modal-backdrop.custom-backdrop');
});

it('Should pass style to the offcanvas', () => {
Expand Down Expand Up @@ -114,7 +114,7 @@ describe('<Offcanvas>', () => {
<strong>Message</strong>
</Offcanvas>,
)
.find('div.offcanvas-backdrop')
.find('div.modal-backdrop')
.simulate('click');

expect(onHideSpy).to.have.been.called;
Expand Down

0 comments on commit 309f881

Please sign in to comment.