Skip to content
Snippets Groups Projects
Unverified Commit 2735aec0 authored by Chris Beer's avatar Chris Beer Committed by GitHub
Browse files

Workspace add focus styling (#3192)

parent 371ac841
Branches
No related tags found
No related merge requests found
...@@ -22,6 +22,8 @@ ...@@ -22,6 +22,8 @@
manifestId: 'https://iiif.bodleian.ox.ac.uk/iiif/manifest/e32a277e-91e2-4a6d-8ba6-cc4bad230410.json', manifestId: 'https://iiif.bodleian.ox.ac.uk/iiif/manifest/e32a277e-91e2-4a6d-8ba6-cc4bad230410.json',
}], }],
catalog: [ catalog: [
{ manifestId: 'https://iiif.bodleian.ox.ac.uk/iiif/manifest/e32a277e-91e2-4a6d-8ba6-cc4bad230410.json' },
{ manifestId: 'https://iiif.harvardartmuseums.org/manifests/object/299843' },
{ manifestId: "https://media.nga.gov/public/manifests/nga_highlights.json", provider: "National Gallery of Art"}, { manifestId: "https://media.nga.gov/public/manifests/nga_highlights.json", provider: "National Gallery of Art"},
{ manifestId: "https://data.ucd.ie/api/img/manifests/ucdlib:33064", provider: "Irish Architectural Archive"}, { manifestId: "https://data.ucd.ie/api/img/manifests/ucdlib:33064", provider: "Irish Architectural Archive"},
{ manifestId: "https://wellcomelibrary.org/iiif/b18035723/manifest", provider: "Wellcome Library"}, { manifestId: "https://wellcomelibrary.org/iiif/b18035723/manifest", provider: "Wellcome Library"},
......
...@@ -23,9 +23,10 @@ function createWrapper(props) { ...@@ -23,9 +23,10 @@ function createWrapper(props) {
describe('ManifestListItem', () => { describe('ManifestListItem', () => {
it('renders without an error', () => { it('renders without an error', () => {
const wrapper = createWrapper(); const wrapper = createWrapper({ buttonRef: 'ref' });
expect(wrapper.find('.mirador-manifest-list-item').length).toBe(1); expect(wrapper.find('.mirador-manifest-list-item').length).toBe(1);
expect(wrapper.find(ButtonBase).length).toBe(1); expect(wrapper.find(ButtonBase).length).toBe(1);
expect(wrapper.find(ButtonBase).getElement().ref).toBe('ref');
expect(wrapper.find(ButtonBase).find(Typography).children().text()).toEqual('xyz'); expect(wrapper.find(ButtonBase).find(Typography).children().text()).toEqual('xyz');
}); });
it('adds a class when the item is active', () => { it('adds a class when the item is active', () => {
......
...@@ -31,6 +31,15 @@ describe('WorkspaceAdd', () => { ...@@ -31,6 +31,15 @@ describe('WorkspaceAdd', () => {
expect(wrapper.find(ManifestListItem).length).toBe(2); expect(wrapper.find(ManifestListItem).length).toBe(2);
}); });
it('focuses on the first manifest item', () => {
const el = { focus: jest.fn() };
const wrapper = createWrapper();
expect(wrapper.find(ManifestListItem).at(1).prop('buttonRef')).toBe(undefined);
wrapper.find(ManifestListItem).at(0).prop('buttonRef')(el);
expect(el.focus).toHaveBeenCalled();
});
it('without manifests, renders an empty message', () => { it('without manifests, renders an empty message', () => {
const wrapper = createWrapper({ catalog: [] }); const wrapper = createWrapper({ catalog: [] });
expect(wrapper.find(ManifestListItem).length).toEqual(0); expect(wrapper.find(ManifestListItem).length).toEqual(0);
...@@ -75,6 +84,15 @@ describe('WorkspaceAdd', () => { ...@@ -75,6 +84,15 @@ describe('WorkspaceAdd', () => {
expect(wrapper.find(Drawer).props().open).toBe(false); expect(wrapper.find(Drawer).props().open).toBe(false);
}); });
it('scrolls to the top after an item is added', () => {
const ref = { current: { scrollTo: jest.fn() } };
const wrapper = createWrapper();
wrapper.instance().ref = ref;
wrapper.instance().onSubmit();
expect(ref.current.scrollTo).toHaveBeenCalledWith({ behavior: 'smooth', left: 0, top: 0 });
});
it('passes a cancel action through to the form', () => { it('passes a cancel action through to the form', () => {
const wrapper = createWrapper(); const wrapper = createWrapper();
wrapper.setState({ addResourcesOpen: true }); wrapper.setState({ addResourcesOpen: true });
......
...@@ -36,6 +36,7 @@ export class ManifestListItem extends React.Component { ...@@ -36,6 +36,7 @@ export class ManifestListItem extends React.Component {
render() { render() {
const { const {
active, active,
buttonRef,
manifestId, manifestId,
ready, ready,
title, title,
...@@ -82,6 +83,7 @@ export class ManifestListItem extends React.Component { ...@@ -82,6 +83,7 @@ export class ManifestListItem extends React.Component {
<Grid container className={ns('manifest-list-item')} spacing={2}> <Grid container className={ns('manifest-list-item')} spacing={2}>
<Grid item xs={12} sm={6} className={classes.buttonGrid}> <Grid item xs={12} sm={6} className={classes.buttonGrid}>
<ButtonBase <ButtonBase
ref={buttonRef}
className={ns('manifest-list-item-title')} className={ns('manifest-list-item-title')}
style={{ width: '100%' }} style={{ width: '100%' }}
onClick={ onClick={
...@@ -148,6 +150,7 @@ export class ManifestListItem extends React.Component { ...@@ -148,6 +150,7 @@ export class ManifestListItem extends React.Component {
ManifestListItem.propTypes = { ManifestListItem.propTypes = {
active: PropTypes.bool, active: PropTypes.bool,
addWindow: PropTypes.func.isRequired, addWindow: PropTypes.func.isRequired,
buttonRef: PropTypes.elementType,
classes: PropTypes.objectOf(PropTypes.string), classes: PropTypes.objectOf(PropTypes.string),
error: PropTypes.string, error: PropTypes.string,
fetchManifest: PropTypes.func.isRequired, fetchManifest: PropTypes.func.isRequired,
...@@ -165,6 +168,7 @@ ManifestListItem.propTypes = { ...@@ -165,6 +168,7 @@ ManifestListItem.propTypes = {
ManifestListItem.defaultProps = { ManifestListItem.defaultProps = {
active: false, active: false,
buttonRef: undefined,
classes: {}, classes: {},
error: null, error: null,
handleClose: () => {}, handleClose: () => {},
......
...@@ -29,11 +29,19 @@ export class WorkspaceAdd extends React.Component { ...@@ -29,11 +29,19 @@ export class WorkspaceAdd extends React.Component {
super(props); super(props);
this.state = { addResourcesOpen: false }; this.state = { addResourcesOpen: false };
this.ref = React.createRef();
this.onSubmit = this.onSubmit.bind(this);
this.setAddResourcesVisibility = this.setAddResourcesVisibility.bind(this); this.setAddResourcesVisibility = this.setAddResourcesVisibility.bind(this);
this.handleDrop = this.handleDrop.bind(this); this.handleDrop = this.handleDrop.bind(this);
} }
/** @private */
onSubmit() {
this.setAddResourcesVisibility(false);
this.scrollToTop();
}
/** /**
* @private * @private
*/ */
...@@ -50,6 +58,16 @@ export class WorkspaceAdd extends React.Component { ...@@ -50,6 +58,16 @@ export class WorkspaceAdd extends React.Component {
} else { } else {
addResource(manifestId); addResource(manifestId);
} }
this.scrollToTop();
}
/** Scroll the list back to the top */
scrollToTop() {
if (this.ref.current) {
const el = this.ref.current;
el.scrollTo({ behavior: 'smooth', left: 0, top: 0 });
}
} }
/** /**
...@@ -61,8 +79,9 @@ export class WorkspaceAdd extends React.Component { ...@@ -61,8 +79,9 @@ export class WorkspaceAdd extends React.Component {
} = this.props; } = this.props;
const { addResourcesOpen } = this.state; const { addResourcesOpen } = this.state;
const manifestList = catalog.map(resource => ( const manifestList = catalog.map((resource, index) => (
<ManifestListItem <ManifestListItem
{...(index === 0 && { buttonRef: (ref => ref && ref.focus()) })}
key={resource.manifestId} key={resource.manifestId}
manifestId={resource.manifestId} manifestId={resource.manifestId}
provider={resource.provider} provider={resource.provider}
...@@ -72,7 +91,7 @@ export class WorkspaceAdd extends React.Component { ...@@ -72,7 +91,7 @@ export class WorkspaceAdd extends React.Component {
return ( return (
<IIIFDropTarget onDrop={this.handleDrop}> <IIIFDropTarget onDrop={this.handleDrop}>
<div className={classNames(ns('workspace-add'), classes.workspaceAdd)}> <div ref={this.ref} className={classNames(ns('workspace-add'), classes.workspaceAdd)}>
{catalog.length < 1 ? ( {catalog.length < 1 ? (
<Grid <Grid
alignItems="center" alignItems="center"
...@@ -98,7 +117,7 @@ export class WorkspaceAdd extends React.Component { ...@@ -98,7 +117,7 @@ export class WorkspaceAdd extends React.Component {
<Paper className={classes.list}> <Paper className={classes.list}>
<Typography variant="srOnly" component="h1">{t('miradorResources')}</Typography> <Typography variant="srOnly" component="h1">{t('miradorResources')}</Typography>
<PluginHook {...this.props} /> <PluginHook {...this.props} />
<List> <List disablePadding>
{manifestList} {manifestList}
</List> </List>
</Paper> </Paper>
...@@ -147,7 +166,7 @@ export class WorkspaceAdd extends React.Component { ...@@ -147,7 +166,7 @@ export class WorkspaceAdd extends React.Component {
</AppBar> </AppBar>
<ManifestForm <ManifestForm
addResourcesOpen={addResourcesOpen} addResourcesOpen={addResourcesOpen}
onSubmit={() => (this.setAddResourcesVisibility(false))} onSubmit={this.onSubmit}
onCancel={() => (this.setAddResourcesVisibility(false))} onCancel={() => (this.setAddResourcesVisibility(false))}
/> />
</Paper> </Paper>
......
...@@ -43,9 +43,6 @@ const mapDispatchToProps = { addWindow: actions.addWindow, fetchManifest: action ...@@ -43,9 +43,6 @@ const mapDispatchToProps = { addWindow: actions.addWindow, fetchManifest: action
const styles = theme => ({ const styles = theme => ({
active: {}, active: {},
buttonGrid: { buttonGrid: {
'&:hover': {
backgroundColor: theme.palette.action.hover,
},
}, },
label: { label: {
textAlign: 'left', textAlign: 'left',
...@@ -65,6 +62,13 @@ const styles = theme => ({ ...@@ -65,6 +62,13 @@ const styles = theme => ({
'&$active': { '&$active': {
borderLeft: `4px solid ${theme.palette.primary.main}`, borderLeft: `4px solid ${theme.palette.primary.main}`,
}, },
'&:hover,&:focus-within': {
'&$active': {
borderLeft: `4px solid ${theme.palette.primary.main}`,
},
backgroundColor: theme.palette.action.hover,
borderLeft: `4px solid ${theme.palette.action.hover}`,
},
borderLeft: '4px solid transparent', borderLeft: '4px solid transparent',
}, },
thumbnail: { thumbnail: {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment