Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
510 changes: 507 additions & 3 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions packages/compass-components/.depcheckrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,8 @@ ignores: [
'@mongodb-js/prettier-config-compass',
'@mongodb-js/tsconfig-compass',
'@types/chai-dom',
# making sure all of the leafygreen is using the same version of these core
# dependencies
'@emotion/css',
"@leafygreen-ui/lib",
]
4 changes: 2 additions & 2 deletions packages/compass-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"@leafygreen-ui/combobox": "^11.0.2",
"@leafygreen-ui/confirmation-modal": "^6.0.2",
"@leafygreen-ui/copyable": "^10.0.14",
"@leafygreen-ui/descendants": "^2.1.0",
"@leafygreen-ui/drawer": "^5.0.3",
"@leafygreen-ui/emotion": "^4.0.9",
"@leafygreen-ui/guide-cue": "^7.0.2",
"@leafygreen-ui/hooks": "^8.3.4",
Expand All @@ -55,7 +55,6 @@
"@leafygreen-ui/info-sprinkle": "^4.0.2",
"@leafygreen-ui/input-option": "^3.0.12",
"@leafygreen-ui/leafygreen-provider": "^4.0.2",
"@leafygreen-ui/lib": "^15.3.0",
"@leafygreen-ui/logo": "^10.0.2",
"@leafygreen-ui/marketing-modal": "^5.0.2",
"@leafygreen-ui/menu": "^29.0.5",
Expand Down Expand Up @@ -119,6 +118,7 @@
},
"devDependencies": {
"@emotion/css": "^11.11.2",
"@leafygreen-ui/lib": "^15.3.0",
"@mongodb-js/eslint-config-compass": "^1.4.10",
"@mongodb-js/mocha-config-compass": "^1.7.1",
"@mongodb-js/prettier-config-compass": "^1.2.8",
Expand Down
102 changes: 73 additions & 29 deletions packages/compass-components/src/components/drawer-portal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,27 @@ import React, {
useRef,
useState,
} from 'react';

import {
DrawerLayout,
DisplayMode as DrawerDisplayMode,
useDrawerToolbarContext,
type DrawerLayoutProps,
} from './drawer';
} from '@leafygreen-ui/drawer';
import { css, cx } from '@leafygreen-ui/emotion';
import { isEqual } from 'lodash';
import { rafraf } from '../utils/rafraf';
import { BaseFontSize, fontWeights } from '@leafygreen-ui/tokens';

type ToolbarData = Required<DrawerLayoutProps>['toolbarData'];

type SectionData = Required<DrawerLayoutProps>['toolbarData'][number];
type SectionData = ToolbarData[number];

type DrawerSectionProps = Omit<SectionData, 'content' | 'onClick'> & {
// Title exists in DrawerLayoutProps, but is optional, whereas for us it needs
// to be required (also due to merging of types inside leafygreen, we can't
// convince typescript that our toolbarData is compatible with lg toolbarData
// if that is not explicit)
title: React.ReactNode;
/**
* If `true` will automatically open the section when first mounted. Default: `false`
*/
Expand Down Expand Up @@ -163,22 +170,19 @@ const drawerLayoutFixesStyles = css({
},

// drawer section
'& > div:nth-child(2)': {
marginTop: -1, // hiding the top border as we already have one in the place where the Anchor is currently rendered
'& > div:nth-child(2) > div': {
// hiding the border border as we already have one in the place where the
// Anchor is currently rendered
borderTop: 'none',
borderBottom: 'none',
},

// We're stretching the title container to all available width so that we can
// layout the controls there better. Doing our best to target the section
// title here, leafygreen really doesn't give us anything else to try.
//
// TODO(ticket): This is obviously a horrible selector and we should make sure
// that LG team provides a better one for us to achieve this behavior when
// we're removing the vendored version of the drawer
'& > div:nth-child(2) > div:nth-child(2) > div:first-child > div:first-child > div:first-child > div:first-child':
// drawer content > title content
'& > div:nth-child(2) > div:nth-child(2) > div:nth-child(2) > div:first-child > div:first-child > div:first-child':
{
flex: 'none',
width: 'calc(100% - 28px)', // disallow going over the title size (100 - close button width)
overflow: 'hidden',
// fix for the flex parent not allowing flex children to collapse if they
// are overflowing the container
minWidth: 0,
},
});

Expand Down Expand Up @@ -210,13 +214,21 @@ const drawerSectionPortalStyles = css({
height: '100%',
});

// Leafygreen dynamically changes styles of the title group based on whether or
// not title is a `string` or a `ReactNode`, we want it to consistently have
// bold title styles no matter what title you provided, so we wrap it in our own
// container
const drawerTitleGroupStyles = css({
width: '100%',
fontSize: BaseFontSize.Body2,
fontWeight: fontWeights.bold,
});

/**
* DrawerAnchor component will render the drawer in any place it is rendered.
* This component has to wrap any content that Drawer will be shown near
*/
export const DrawerAnchor: React.FunctionComponent<{
displayMode?: DrawerDisplayMode;
}> = ({ displayMode, children }) => {
export const DrawerAnchor: React.FunctionComponent = ({ children }) => {
const actions = useContext(DrawerActionsContext);
const drawerSectionItems = useContext(DrawerStateContext);
const prevDrawerSectionItems = useRef<DrawerSectionProps[]>([]);
Expand All @@ -239,7 +251,13 @@ export const DrawerAnchor: React.FunctionComponent<{
return drawerSectionItems
.map((data) => {
return {
hasPadding: false,
...data,
title: (
<div key={data.id} className={drawerTitleGroupStyles}>
{data.title}
</div>
),
content: (
<div
key={data.id}
Expand All @@ -255,7 +273,8 @@ export const DrawerAnchor: React.FunctionComponent<{
}, [drawerSectionItems]);
return (
<DrawerLayout
displayMode={displayMode ?? DrawerDisplayMode.Embedded}
displayMode={DrawerDisplayMode.Embedded}
resizable
toolbarData={toolbarData}
className={cx(
drawerLayoutFixesStyles,
Expand All @@ -270,6 +289,15 @@ export const DrawerAnchor: React.FunctionComponent<{
);
};

function querySectionPortal(
parent: Document | Element | null,
id?: string
): HTMLElement | null {
return (
parent?.querySelector(`[data-drawer-section${id ? `=${id}` : ''}]`) ?? null
);
}

/**
* DrawerSection allows to declaratively render sections inside the drawer
* independantly from the Drawer itself
Expand All @@ -278,7 +306,9 @@ export const DrawerSection: React.FunctionComponent<DrawerSectionProps> = ({
children,
...props
}) => {
const [portalNode, setPortalNode] = useState<Element | null>(null);
const [portalNode, setPortalNode] = useState<Element | null>(() => {
return querySectionPortal(document, props.id);
});
const actions = useContext(DrawerActionsContext);
const prevProps = useRef<DrawerSectionProps>();
useEffect(() => {
Expand All @@ -296,14 +326,24 @@ export const DrawerSection: React.FunctionComponent<DrawerSectionProps> = ({
'Can not use DrawerSection without DrawerAnchor being mounted on the page'
);
}
setPortalNode(
document.querySelector(`[data-drawer-section="${props.id}"]`)
);
setPortalNode(querySectionPortal(drawerEl, props.id));
const mutationObserver = new MutationObserver((mutations) => {
for (const mutation of mutations) {
for (const node of Array.from(mutation.addedNodes) as HTMLElement[]) {
if (node.dataset && node.dataset.drawerSection === props.id) {
setPortalNode(node);
if (mutation.type === 'childList') {
for (const node of Array.from(mutation.addedNodes)) {
// Added node can be either the drawer section portal itself, a
// parent node containing the section (in that case we won't get an
// explicit mutation for the section itself), or something
// completely unrelated, like a text node insert. By searching for
// the section portal from added node parent element we cover all
// these cases in one go
const drawerSectionNode = querySectionPortal(
node.parentElement,
props.id
);
if (drawerSectionNode) {
setPortalNode(drawerSectionNode);
}
}
}
}
Expand All @@ -315,7 +355,7 @@ export const DrawerSection: React.FunctionComponent<DrawerSectionProps> = ({
return () => {
mutationObserver.disconnect();
};
}, [actions, props.id]);
}, [props.id]);
useEffect(() => {
return () => {
actions.current.removeToolbarData(props.id);
Expand All @@ -333,7 +373,9 @@ export function useDrawerActions() {
const actions = useContext(DrawerActionsContext);
const stableActions = useRef({
openDrawer: (id: string) => {
actions.current.openDrawer(id);
rafraf(() => {
actions.current.openDrawer(id);
});
},
closeDrawer: () => {
actions.current.closeDrawer();
Expand All @@ -352,3 +394,5 @@ export const useDrawerState = () => {
drawerState.length > 0,
};
};

export { getLgIds as getDrawerIds } from '@leafygreen-ui/drawer';
10 changes: 0 additions & 10 deletions packages/compass-components/src/components/drawer/constants.ts

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Loading
Loading