Unverified Commit 6122caa1 authored by Jyothish's avatar Jyothish Committed by GitHub
Browse files

New species lozenge (#350)

* New selected species lozenge component with tests and stories
parent b337092f
Pipeline #100889 passed with stages
in 8 minutes and 10 seconds
@import 'src/styles/common';
@import './selected-species-common';
.species {
@include selected-species-common;
border: 1px solid $blue;
cursor: pointer;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
color: $white;
}
.nameActive,
.assemblyActive {
color: $white;
}
.inUseActive {
background-color: $black;
border: 1px solid $black;
}
.inUseInactive {
background-color: $blue;
border: 1px solid $blue;
}
.notInUseActive {
background-color: $grey;
border: 1px solid $grey;
cursor: auto;
}
.notInUseInactive {
background-color: $white;
border: 1px solid $blue;
color: $blue;
}
/**
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import faker from 'faker';
import { mount } from 'enzyme';
import set from 'lodash/fp/set';
import merge from 'lodash/fp/merge';
import SelectedSpecies, {
Props as SelectedSpeciesProps
} from './SelectedSpecies';
import { CommittedItem } from 'src/content/app/species-selector/types/species-search';
const speciesData = {
genome_id: faker.random.uuid(),
reference_genome_id: null,
common_name: 'Human',
scientific_name: 'Homo sapiens',
assembly_name: 'GRCh38',
isEnabled: true
};
const minimalProps = {
species: speciesData as CommittedItem,
isActive: true,
onClick: jest.fn()
};
describe('<SelectedSpecies />', () => {
const renderSelectedSpecies = (props: SelectedSpeciesProps) =>
mount(<SelectedSpecies {...speciesData} {...props} />);
it('renders without error', () => {
expect(() => renderSelectedSpecies(minimalProps)).not.toThrow();
});
describe('lozenge', () => {
it('has correct classes whenactive and enabled', () => {
const wrapper = renderSelectedSpecies(minimalProps);
expect(wrapper.children('div').hasClass('inUseActive')).toEqual(true);
});
it('has correct classes when active and not enabled', () => {
const props = set('species.isEnabled', false, minimalProps);
const wrapper = renderSelectedSpecies(props);
expect(wrapper.children('div').hasClass('notInUseActive')).toEqual(true);
});
it('has correct classes when inactive and enabled', () => {
const props = set('isActive', false, minimalProps);
const wrapper = renderSelectedSpecies(props);
expect(wrapper.children('div').hasClass('inUseInactive')).toEqual(true);
});
it('has correct classes when inactive and disabled', () => {
const props = merge(minimalProps, {
isActive: false,
species: { isEnabled: false }
});
const wrapper = renderSelectedSpecies(props);
expect(wrapper.children('div').hasClass('notInUseInactive')).toEqual(
true
);
});
});
describe('behaviour', () => {
afterEach(() => {
jest.resetAllMocks();
});
it('responds to clicks when inactive', () => {
const props = set('isActive', false, minimalProps);
const wrapper = renderSelectedSpecies(props);
wrapper.simulate('click');
expect(props.onClick).toHaveBeenCalledWith(speciesData.genome_id);
});
it('does not respond to clicks when active', () => {
const wrapper = renderSelectedSpecies(minimalProps);
wrapper.simulate('click');
expect(minimalProps.onClick).not.toHaveBeenCalled();
});
});
});
/**
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import classNames from 'classnames';
import SelectedSpeciesContent from './SelectedSpeciesContent';
import styles from './SelectedSpecies.scss';
import { CommittedItem } from 'src/content/app/species-selector/types/species-search';
export type Props = {
species: CommittedItem;
isActive: boolean;
onClick: (genomeId: string) => void;
onMouseEnter?: () => void;
onMouseLeave?: () => void;
className?: string;
};
const chooseClassName = (props: Props) => {
const {
isActive,
species: { isEnabled }
} = props;
if (isActive && isEnabled) {
return styles.inUseActive;
} else if (isActive && !isEnabled) {
return styles.notInUseActive;
} else if (!isActive && isEnabled) {
return styles.inUseInactive;
} else {
return styles.notInUseInactive;
}
};
const SelectedSpecies = (props: Props) => {
const handleMouseEnter = () => {
props.onMouseEnter && props.onMouseEnter();
};
const handleMouseLeave = () => {
props.onMouseLeave && props.onMouseLeave();
};
const handleClick = () => {
if (!props.isActive) {
props.onClick(props.species.genome_id);
}
};
const className = classNames(
styles.species,
chooseClassName(props),
props.className
);
return (
<div
className={className}
onMouseEnter={handleMouseEnter}
onMouseLeave={handleMouseLeave}
onClick={handleClick}
>
<SelectedSpeciesContent species={props.species} />
</div>
);
};
SelectedSpecies.defaultProps = {
isActive: false
};
export default SelectedSpecies;
/**
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import classNames from 'classnames';
import { getDisplayName } from './selectedSpeciesHelpers';
import { CommittedItem } from 'src/content/app/species-selector/types/species-search';
import styles from './selected-species-common.scss';
type Props = {
species: CommittedItem;
classNames?: {
name?: string;
assembly?: string;
};
};
const SelectedSpeciesContent = (props: Props) => {
const displayName = getDisplayName(props.species);
const nameClasses = classNames(
styles.name,
props.classNames && props.classNames.name
);
const assemblyClasses = classNames(
styles.assembly,
props.classNames && props.classNames.assembly
);
return (
<>
<span className={nameClasses}>{displayName}</span>
<span className={assemblyClasses}>{props.species.assembly_name}</span>
</>
);
};
export default SelectedSpeciesContent;
/**
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { default as SelectedSpecies } from './SelectedSpecies';
@import 'src/styles/common';
$selectedSpeciesBorderRadius: 20px;
$selectedSpeciesPadding: 6px 20px;
$deleteButtonPadding: 8px 20px 8px 28px;
@mixin selected-species-common {
display: inline-block;
padding: $selectedSpeciesPadding;
border-radius: $selectedSpeciesBorderRadius;
line-height: 1;
user-select: none;
margin-bottom: 4px;
&:not(:last-child) {
margin-right: 12px;
}
}
.name {
font-size: 14px;
font-weight: $bold;
margin-right: 0.5rem;
}
.assembly {
font-size: 11px;
}
/**
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { CommittedItem } from 'src/content/app/species-selector/types/species-search';
const SPECIES_NAME_SIZE = 14;
const ASSEMBLY_NAME_SIZE = 11;
const PADDING_SIZE = 20;
const SPACE_BETWEEN = 7;
const BORDER_WIDTH = 1;
export const getDisplayName = (species: CommittedItem) =>
species.common_name || species.scientific_name;
export const getFullSpeciesItemWidth = (species: CommittedItem) => {
const name = getDisplayName(species);
const { assembly_name } = species;
const canvas = document.createElement('canvas');
const canvasContext = canvas.getContext('2d') as CanvasRenderingContext2D;
canvasContext.font = `700 ${SPECIES_NAME_SIZE}px Lato`;
const speciesNameWidth = Math.ceil(canvasContext.measureText(name).width);
canvasContext.font = `${ASSEMBLY_NAME_SIZE}px Lato`;
const assemblyNameWidth = Math.ceil(
canvasContext.measureText(assembly_name).width
);
const fullWidth =
PADDING_SIZE * 2 +
speciesNameWidth +
SPACE_BETWEEN +
assemblyNameWidth +
2 * BORDER_WIDTH;
return fullWidth;
};
......@@ -17,10 +17,6 @@ $deleteButtonPadding: 8px 20px 8px 28px;
}
}
.name,
.assembly {
color: $white;
}
.name {
font-size: 14px;
......
/**
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import SelectedSpecies from 'src/shared/components/new-selected-species/SelectedSpecies';
import speciesData from '../species-tabs-wrapper/speciesData';
import styles from './SelectedSpecies.stories.scss';
export default {
title: 'Components/Shared Components/New Selected Species',
argTypes: { onClick: { action: 'Clicked' } }
};
type StoryArgs = {
onClick: () => void;
};
export const SelectedSpeciesStory = (args: StoryArgs) => {
const enabledSpecies = speciesData[0];
const disabledSpecies = {
...enabledSpecies,
isEnabled: false
};
return (
<div className={styles.wrapper}>
<SelectedSpecies
species={enabledSpecies}
onClick={args.onClick}
></SelectedSpecies>
<SelectedSpecies
species={enabledSpecies}
isActive={true}
onClick={args.onClick}
></SelectedSpecies>
<SelectedSpecies
species={disabledSpecies}
onClick={args.onClick}
></SelectedSpecies>
<SelectedSpecies
species={disabledSpecies}
isActive={true}
onClick={args.onClick}
></SelectedSpecies>
</div>
);
};
SelectedSpeciesStory.storyName = 'Lozenge';
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment