Skip to content
Snippets Groups Projects
Commit a77b8505 authored by Chris Beer's avatar Chris Beer
Browse files

Update ScrollTo to wrap the list/menu items without injecting additional DOM elements

parent c03eb24c
No related branches found
No related tags found
2 merge requests!19Draft: Merge video support into mui5,!18Only nudge over badge content for the WindowListButton; it needs special...
import { render, screen } from 'test-utils'; import { render } from 'test-utils';
import { createRef } from 'react'; import { createRef } from 'react';
import { ScrollTo } from '../../../src/components/ScrollTo'; import { ScrollTo } from '../../../src/components/ScrollTo';
...@@ -22,12 +22,6 @@ describe('ScrollTo', () => { ...@@ -22,12 +22,6 @@ describe('ScrollTo', () => {
const scrollToElBelowBoundingRect = { bottom: 601, top: 501 }; const scrollToElBelowBoundingRect = { bottom: 601, top: 501 };
const visibleScrollToElBoundingRect = { bottom: 300, top: 200 }; const visibleScrollToElBoundingRect = { bottom: 300, top: 200 };
it('wraps the given children in a div element', () => {
render(<ScrollTo data-testid="subject" scrollTo>Child Prop</ScrollTo>);
expect(screen.getByTestId('subject')).toHaveTextContent('Child Prop');
});
describe('when updating the scrollTo prop', () => { describe('when updating the scrollTo prop', () => {
beforeEach(() => { beforeEach(() => {
jest.spyOn(ScrollTo.prototype, 'elementToScrollTo').mockImplementation(() => ({ offsetTop: 450 })); jest.spyOn(ScrollTo.prototype, 'elementToScrollTo').mockImplementation(() => ({ offsetTop: 450 }));
...@@ -38,13 +32,13 @@ describe('ScrollTo', () => { ...@@ -38,13 +32,13 @@ describe('ScrollTo', () => {
...scrollToElAboveBoundingRect, ...scrollToElAboveBoundingRect,
})); }));
const { rerender } = render(<ScrollTo scrollTo containerRef={containerRef}>Child</ScrollTo>); const { rerender } = render(<ScrollTo scrollTo containerRef={containerRef}><div>Child</div></ScrollTo>);
// It is called once when initially rendered w/ true // It is called once when initially rendered w/ true
expect(scrollTo).toHaveBeenCalled(); expect(scrollTo).toHaveBeenCalled();
scrollTo.mockReset(); scrollTo.mockReset();
rerender(<ScrollTo containerRef={containerRef}>Child</ScrollTo>); rerender(<ScrollTo containerRef={containerRef}><div>Child</div></ScrollTo>);
// But it is not called on the re-render w/ false // But it is not called on the re-render w/ false
expect(scrollTo).not.toHaveBeenCalled(); expect(scrollTo).not.toHaveBeenCalled();
...@@ -56,9 +50,9 @@ describe('ScrollTo', () => { ...@@ -56,9 +50,9 @@ describe('ScrollTo', () => {
jest.spyOn(ScrollTo.prototype, 'scrollToBoundingRect').mockImplementation(() => ({ jest.spyOn(ScrollTo.prototype, 'scrollToBoundingRect').mockImplementation(() => ({
...scrollToElAboveBoundingRect, ...scrollToElAboveBoundingRect,
})); }));
const { rerender } = render(<ScrollTo containerRef={containerRef}>Child</ScrollTo>); const { rerender } = render(<ScrollTo containerRef={containerRef}><div>Child</div></ScrollTo>);
rerender(<ScrollTo scrollTo containerRef={containerRef}>Child</ScrollTo>); rerender(<ScrollTo scrollTo containerRef={containerRef}><div>Child</div></ScrollTo>);
expect(scrollTo).toHaveBeenCalledWith(0, 230); expect(scrollTo).toHaveBeenCalledWith(0, 230);
}); });
...@@ -68,9 +62,9 @@ describe('ScrollTo', () => { ...@@ -68,9 +62,9 @@ describe('ScrollTo', () => {
...scrollToElBelowBoundingRect, ...scrollToElBelowBoundingRect,
})); }));
const { rerender } = render(<ScrollTo containerRef={containerRef}>Child</ScrollTo>); const { rerender } = render(<ScrollTo containerRef={containerRef}><div>Child</div></ScrollTo>);
rerender(<ScrollTo scrollTo containerRef={containerRef}>Child</ScrollTo>); rerender(<ScrollTo scrollTo containerRef={containerRef}><div>Child</div></ScrollTo>);
expect(scrollTo).toHaveBeenCalledWith(0, 230); expect(scrollTo).toHaveBeenCalledWith(0, 230);
}); });
...@@ -80,9 +74,9 @@ describe('ScrollTo', () => { ...@@ -80,9 +74,9 @@ describe('ScrollTo', () => {
...visibleScrollToElBoundingRect, ...visibleScrollToElBoundingRect,
})); }));
const { rerender } = render(<ScrollTo containerRef={containerRef}>Child</ScrollTo>); const { rerender } = render(<ScrollTo containerRef={containerRef}><div>Child</div></ScrollTo>);
rerender(<ScrollTo scrollTo containerRef={containerRef}>Child</ScrollTo>); rerender(<ScrollTo scrollTo containerRef={containerRef}><div>Child</div></ScrollTo>);
expect(scrollTo).not.toHaveBeenCalled(); expect(scrollTo).not.toHaveBeenCalled();
}); });
......
...@@ -70,6 +70,13 @@ export class CanvasAnnotations extends Component { ...@@ -70,6 +70,13 @@ export class CanvasAnnotations extends Component {
</Typography> </Typography>
<MenuList autoFocusItem variant="selectedMenu"> <MenuList autoFocusItem variant="selectedMenu">
{annotations.map((annotation) => ( {annotations.map((annotation) => (
<ScrollTo
containerRef={containerRef}
key={`${annotation.id}-scroll`}
offsetTop={96} // offset for the height of the form above
scrollTo={selectedAnnotationId === annotation.id}
selected={selectedAnnotationId === annotation.id}
>
<MenuItem <MenuItem
component={listContainerComponent} component={listContainerComponent}
variant="multiline" variant="multiline"
...@@ -82,18 +89,11 @@ export class CanvasAnnotations extends Component { ...@@ -82,18 +89,11 @@ export class CanvasAnnotations extends Component {
}} }}
key={annotation.id} key={annotation.id}
annotationid={annotation.id} annotationid={annotation.id}
selected={selectedAnnotationId === annotation.id}
onClick={(e) => this.handleClick(e, annotation)} onClick={(e) => this.handleClick(e, annotation)}
onFocus={() => this.handleAnnotationHover(annotation)} onFocus={() => this.handleAnnotationHover(annotation)}
onBlur={this.handleAnnotationBlur} onBlur={this.handleAnnotationBlur}
onMouseEnter={() => this.handleAnnotationHover(annotation)} onMouseEnter={() => this.handleAnnotationHover(annotation)}
onMouseLeave={this.handleAnnotationBlur} onMouseLeave={this.handleAnnotationBlur}
>
<ScrollTo
containerRef={containerRef}
key={`${annotation.id}-scroll`}
offsetTop={96} // offset for the height of the form above
scrollTo={selectedAnnotationId === annotation.id}
> >
<ListItemText primaryTypographyProps={{ variant: 'body2' }}> <ListItemText primaryTypographyProps={{ variant: 'body2' }}>
<SanitizedHtml ruleSet={htmlSanitizationRuleSet} htmlString={annotation.content} /> <SanitizedHtml ruleSet={htmlSanitizationRuleSet} htmlString={annotation.content} />
...@@ -103,8 +103,8 @@ export class CanvasAnnotations extends Component { ...@@ -103,8 +103,8 @@ export class CanvasAnnotations extends Component {
))} ))}
</div> </div>
</ListItemText> </ListItemText>
</ScrollTo>
</MenuItem> </MenuItem>
</ScrollTo>
))} ))}
</MenuList> </MenuList>
</> </>
......
import { createRef, Component } from 'react'; import { cloneElement, createRef, Component } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import isEmpty from 'lodash/isEmpty';
/** /**
* ScrollTo ~ * ScrollTo ~
...@@ -107,13 +108,9 @@ export class ScrollTo extends Component { ...@@ -107,13 +108,9 @@ export class ScrollTo extends Component {
children, containerRef, offsetTop, scrollTo, nodeId, ...otherProps children, containerRef, offsetTop, scrollTo, nodeId, ...otherProps
} = this.props; } = this.props;
if (!scrollTo) return children; if (!scrollTo && isEmpty(otherProps)) return children;
return ( return cloneElement(children, { ref: this.scrollToRef, ...otherProps });
<div ref={this.scrollToRef} {...otherProps}>
{children}
</div>
);
} }
} }
......
...@@ -48,26 +48,28 @@ export class SidebarIndexList extends Component { ...@@ -48,26 +48,28 @@ export class SidebarIndexList extends Component {
const onClick = () => { setCanvas(windowId, canvas.id); }; // eslint-disable-line require-jsdoc, max-len const onClick = () => { setCanvas(windowId, canvas.id); }; // eslint-disable-line require-jsdoc, max-len
return ( return (
<ScrollTo
containerRef={containerRef}
key={`${canvas.id}-${variant}`}
offsetTop={96} // offset for the height of the form above
selected={selectedCanvasIds.includes(canvas.id)}
scrollTo={selectedCanvasIds.includes(canvas.id)}
>
<MenuItem <MenuItem
key={canvas.id} key={canvas.id}
disableGutters
sx={{ sx={{
paddingLeft: 2,
paddingRight: 1, paddingRight: 1,
position: 'initial', position: 'initial',
}} }}
divider divider
onClick={onClick} onClick={onClick}
component="li" component="li"
selected={selectedCanvasIds.includes(canvas.id)}
>
<ScrollTo
containerRef={containerRef}
key={`${canvas.id}-${variant}`}
offsetTop={96} // offset for the height of the form above
scrollTo={selectedCanvasIds.includes(canvas.id)}
> >
<Item label={canvas.label} canvas={canvases[canvasIndex]} /> <Item label={canvas.label} canvas={canvases[canvasIndex]} />
</ScrollTo>
</MenuItem> </MenuItem>
</ScrollTo>
); );
}) })
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment