X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/08fb678c7ff12d3f420477f34610383960b65482..5bf94d55b564bfbd052a61ab8219aa063b2a80c6:/services/workbench2/src/components/multiselect-toolbar/ms-toolbar-overflow-wrapper.tsx diff --git a/services/workbench2/src/components/multiselect-toolbar/ms-toolbar-overflow-wrapper.tsx b/services/workbench2/src/components/multiselect-toolbar/ms-toolbar-overflow-wrapper.tsx index d97c2f0fc8..e0f32f1fa6 100644 --- a/services/workbench2/src/components/multiselect-toolbar/ms-toolbar-overflow-wrapper.tsx +++ b/services/workbench2/src/components/multiselect-toolbar/ms-toolbar-overflow-wrapper.tsx @@ -4,8 +4,9 @@ import React, { useState, useRef, useEffect } from 'react'; import { StyleRulesCallback, WithStyles, withStyles } from '@material-ui/core'; +import classnames from 'classnames'; import { ArvadosTheme } from 'common/custom-theme'; -import { OverflowMenu } from './ms-toolbar-overflow-menu'; +import { OverflowMenu, OverflowChild } from './ms-toolbar-overflow-menu'; type CssRules = 'visible' | 'inVisible' | 'toolbarWrapper' | 'overflowStyle'; @@ -23,28 +24,36 @@ const styles: StyleRulesCallback = (theme: ArvadosTheme) => ({ toolbarWrapper: { display: 'flex', overflow: 'hidden', - padding: '0 20px', - width: '75%', + padding: '0 0px 0 20px', + width: '100%', }, overflowStyle: { order: 99, position: 'sticky', - right: '0', - backgroundColor: 'white', + right: '-2rem', + width: 0, }, }); -export const IntersectionObserverWrapper = withStyles(styles)((props: any & WithStyles) => { - const { classes, children} = props +type WrapperProps = { + children: OverflowChild[]; + menuLength: number; +}; +export const IntersectionObserverWrapper = withStyles(styles)((props: WrapperProps & WithStyles) => { + const { classes, children, menuLength } = props; + const lastEntryId = (children[menuLength - 1] as any).props['data-targetid']; const navRef = useRef(null); - const [visibilityMap, setVisibilityMap] = useState({}); + const [visibilityMap, setVisibilityMap] = useState>({}); + const [numHidden, setNumHidden] = useState(() => findNumHidden(visibilityMap)); + + const prevNumHidden = useRef(numHidden); const handleIntersection = (entries) => { - const updatedEntries = {}; + const updatedEntries: Record = {}; entries.forEach((entry) => { - const targetid = entry.target.dataset.targetid; - console.log(entry, targetid); + const targetid = entry.target.dataset.targetid as string; + //if true, the element is visible if (entry.isIntersecting) { updatedEntries[targetid] = true; } else { @@ -55,14 +64,33 @@ export const IntersectionObserverWrapper = withStyles(styles)((props: any & With setVisibilityMap((prev) => ({ ...prev, ...updatedEntries, + [lastEntryId]: Object.keys(updatedEntries)[0] === lastEntryId, })); }; + + //ensures that the last element is always visible if the second to last is visible + useEffect(() => { + if ((prevNumHidden.current > 1 || prevNumHidden.current === 0) && numHidden === 1) { + setVisibilityMap((prev) => ({ + ...prev, + [lastEntryId]: true, + })); + } + prevNumHidden.current = numHidden; + }, [numHidden, lastEntryId]); + + useEffect(() => { + setNumHidden(findNumHidden(visibilityMap)); + }, [visibilityMap]); + useEffect((): any => { + setVisibilityMap({}); const observer = new IntersectionObserver(handleIntersection, { root: navRef.current, + rootMargin: '0px -30px 0px 0px', threshold: 1, }); - // We are addting observers to child elements of the container div + // We are adding observers to child elements of the container div // with ref as navRef. Notice that we are adding observers // only if we have the data attribute targetid on the child element if (navRef.current) @@ -74,35 +102,34 @@ export const IntersectionObserverWrapper = withStyles(styles)((props: any & With return () => { observer.disconnect(); }; - }, []); + // eslint-disable-next-line + }, [menuLength]); + + function findNumHidden(visMap: {}) { + return Object.values(visMap).filter((x) => x === false).length; + } return ( -
- {React.Children.map(children, (child) => { - return React.cloneElement(child, { - className: classnames(child.props.className, { - [classes.visible]: !!visibilityMap[child.props["data-targetid"]], - [classes.inVisible]: !visibilityMap[child.props["data-targetid"]] - }) - }); - })} - - {children} - -
+
+ {React.Children.map(children, (child) => { + return React.cloneElement(child, { + className: classnames(child.props.className, { + [classes.visible]: !!visibilityMap[child.props['data-targetid']], + [classes.inVisible]: !visibilityMap[child.props['data-targetid']], + }), + }); + })} + {numHidden >= 2 && ( + + {children.filter((child) => !child.props['data-targetid'].includes("Divider"))} + + )} +
); }); - -const classnames = (...args: Array>) => { - return args.reduce((output: string, currentArg: any) => { - if (typeof currentArg === 'string') output += currentArg + ' '; - else - for (const entry in currentArg) { - if (currentArg[entry] === true) output += entry + ' '; - } - return output; - }, ''); -}; \ No newline at end of file