Skip to content

Commit

Permalink
feat(Portal): take in consideration parent theme (#1506)
Browse files Browse the repository at this point in the history
  • Loading branch information
ValeraS authored Apr 24, 2024
1 parent 5703184 commit 8c7ca2d
Show file tree
Hide file tree
Showing 14 changed files with 189 additions and 140 deletions.
58 changes: 28 additions & 30 deletions src/components/Modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -102,34 +102,32 @@ export function Modal({
});

return (
<Portal container={container}>
<CSSTransition
nodeRef={containerRef}
in={open}
addEndListener={(done) =>
containerRef.current?.addEventListener('animationend', done)
}
classNames={getCSSTransitionClassNames(b)}
mountOnEnter={!keepMounted}
unmountOnExit={!keepMounted}
appear={true}
onEnter={() => {
setInTransition(true);
onTransitionEnter?.();
}}
onExit={() => {
setInTransition(true);
onTransitionExit?.();
}}
onEntered={() => {
setInTransition(false);
onTransitionEntered?.();
}}
onExited={() => {
setInTransition(false);
onTransitionExited?.();
}}
>
<CSSTransition
nodeRef={containerRef}
in={open}
addEndListener={(done) => containerRef.current?.addEventListener('animationend', done)}
classNames={getCSSTransitionClassNames(b)}
mountOnEnter={!keepMounted}
unmountOnExit={!keepMounted}
appear={true}
onEnter={() => {
setInTransition(true);
onTransitionEnter?.();
}}
onExit={() => {
setInTransition(true);
onTransitionExit?.();
}}
onEntered={() => {
setInTransition(false);
onTransitionEntered?.();
}}
onExited={() => {
setInTransition(false);
onTransitionExited?.();
}}
>
<Portal container={container}>
<div ref={containerRef} style={style} className={b({open}, className)} data-qa={qa}>
<div className={b('content-aligner')}>
<div className={b('content-wrapper')}>
Expand Down Expand Up @@ -157,7 +155,7 @@ export function Modal({
</div>
</div>
</div>
</CSSTransition>
</Portal>
</Portal>
</CSSTransition>
);
}
50 changes: 24 additions & 26 deletions src/components/Popup/Popup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,30 +151,28 @@ export function Popup({
});

return (
<Portal container={container} disablePortal={disablePortal}>
<CSSTransition
nodeRef={containerRef}
in={open}
addEndListener={(done) =>
containerRef.current?.addEventListener('animationend', done)
}
classNames={getCSSTransitionClassNames(b)}
mountOnEnter={!keepMounted}
unmountOnExit={!keepMounted}
appear={true}
onEnter={() => {
onTransitionEnter?.();
}}
onEntered={() => {
onTransitionEntered?.();
}}
onExit={() => {
onTransitionExit?.();
}}
onExited={() => {
onTransitionExited?.();
}}
>
<CSSTransition
nodeRef={containerRef}
in={open}
addEndListener={(done) => containerRef.current?.addEventListener('animationend', done)}
classNames={getCSSTransitionClassNames(b)}
mountOnEnter={!keepMounted}
unmountOnExit={!keepMounted}
appear={true}
onEnter={() => {
onTransitionEnter?.();
}}
onEntered={() => {
onTransitionEntered?.();
}}
onExit={() => {
onTransitionExit?.();
}}
onExited={() => {
onTransitionExited?.();
}}
>
<Portal container={container} disablePortal={disablePortal}>
<div
ref={handleRef}
style={styles.popper}
Expand Down Expand Up @@ -211,7 +209,7 @@ export function Popup({
</div>
</FocusTrap>
</div>
</CSSTransition>
</Portal>
</Portal>
</CSSTransition>
);
}
9 changes: 9 additions & 0 deletions src/components/Portal/Portal.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
@use '../variables';

$block: '.#{variables.$ns}portal';

#{$block} {
&__theme-wrapper {
display: contents;
}
}
21 changes: 20 additions & 1 deletion src/components/Portal/Portal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@ import React from 'react';
import ReactDOM from 'react-dom';

import {usePortalContainer} from '../../hooks';
import {ThemeProvider} from '../theme';
import {useThemeContext} from '../theme/useThemeContext';
import {block} from '../utils/cn';

import './Portal.scss';

const b = block('portal');

export interface PortalProps {
container?: HTMLElement;
Expand All @@ -12,12 +19,24 @@ export interface PortalProps {

export function Portal({container, children, disablePortal}: PortalProps) {
const defaultContainer = usePortalContainer();
const {scoped} = useThemeContext();

const containerNode = container ?? defaultContainer;

if (disablePortal) {
return <React.Fragment>{children}</React.Fragment>;
}

return containerNode ? ReactDOM.createPortal(children, containerNode) : null;
return containerNode
? ReactDOM.createPortal(
scoped ? (
<ThemeProvider rootClassName={b('theme-wrapper')} scoped>
{children}
</ThemeProvider>
) : (
children
),
containerNode,
)
: null;
}
20 changes: 8 additions & 12 deletions src/components/layout/LayoutProvider/LayoutProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React from 'react';
import {LayoutContext} from '../contexts/LayoutContext';
import {useCurrentActiveMediaQuery} from '../hooks/useCurrentActiveMediaQuery';
import type {LayoutTheme, MediaType, RecursivePartial} from '../types';
import {makeLayoutDefaultTheme} from '../utils/makeLayoutDefaultTheme';
import {overrideLayoutTheme} from '../utils/overrideLayoutTheme';

export interface PrivateLayoutProviderProps {
config?: RecursivePartial<LayoutTheme>;
Expand All @@ -20,19 +20,15 @@ export function PrivateLayoutProvider({
config: override,
initialMediaQuery,
}: PrivateLayoutProviderProps) {
const theme = React.useMemo(() => makeLayoutDefaultTheme({override}), [override]);
const parentContext = React.useContext(LayoutContext);
const theme = React.useMemo(
() => overrideLayoutTheme({theme: parentContext.theme, override}),
[override, parentContext.theme],
);
const activeMediaQuery = useCurrentActiveMediaQuery(theme.breakpoints, initialMediaQuery);

return (
<LayoutContext.Provider
value={{
activeMediaQuery,
theme,
}}
>
{children}
</LayoutContext.Provider>
);
const value = React.useMemo(() => ({activeMediaQuery, theme}), [activeMediaQuery, theme]);
return <LayoutContext.Provider value={value}>{children}</LayoutContext.Provider>;
}

interface LayoutProviderProps {
Expand Down
23 changes: 5 additions & 18 deletions src/components/layout/hooks/useCurrentActiveMediaQuery.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@ export const makeCurrentActiveMediaExpressions = (
xxxl: `(min-width: ${mediaToValue.xxxl}px)`,
});

const safeMatchMedia = (query: string | number): MediaQueryList => {
const safeMatchMedia = (query: string): MediaQueryList => {
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
return mockMediaQueryList;
}

return window.matchMedia(String(query));
return window.matchMedia(query);
};

class Queries {
Expand Down Expand Up @@ -81,33 +81,20 @@ export const useCurrentActiveMediaQuery = (
const [state, _setState] = React.useState<MediaType>(initialMediaQuery);

React.useLayoutEffect(() => {
let mounted = true;

const queries = new Queries(breakpointsMap);

const setState = () => {
_setState(queries.getCurrentActiveMedia());
};

const onChange = () => {
if (!mounted) {
return;
}

setState();
};

queries.addListeners(onChange);
queries.addListeners(setState);

setState();

return () => {
mounted = false;
queries.removeListeners(onChange);
queries.removeListeners(setState);
};
// don't support runtime breakpoint redefinition. Breakpoints defined only one at LayoutTheme
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
}, [breakpointsMap]);

return state;
};
18 changes: 0 additions & 18 deletions src/components/layout/utils/makeLayoutDefaultTheme.ts

This file was deleted.

16 changes: 16 additions & 0 deletions src/components/layout/utils/overrideLayoutTheme.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/* eslint-disable valid-jsdoc */
import merge from 'lodash/merge';

import type {LayoutTheme, RecursivePartial} from '../types';

interface OverrideLayoutThemeOptions {
theme: LayoutTheme;
override?: RecursivePartial<LayoutTheme>;
}

/**
* Use this function to override default `DEFAULT_LAYOUT_THEME`
*/
export function overrideLayoutTheme({theme, override}: OverrideLayoutThemeOptions): LayoutTheme {
return merge(theme, override);
}
9 changes: 3 additions & 6 deletions src/components/theme/ThemeProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@ export function ThemeProvider({
theme,
themeValue,
direction,
scoped,
}) satisfies ThemeContextProps,
[theme, themeValue, direction],
[theme, themeValue, direction, scoped],
);

const themeSettingsContext = React.useMemo(
Expand All @@ -102,11 +103,7 @@ export function ThemeProvider({
},
rootClassName,
)}
dir={
hasParentProvider && direction === parentDirection
? undefined
: direction
}
dir={direction}
>
{children}
</div>
Expand Down
Loading

0 comments on commit 8c7ca2d

Please sign in to comment.