Skip to content

Commit

Permalink
feat(components): set toolbar components to a fixed width #389
Browse files Browse the repository at this point in the history
  • Loading branch information
JonasKellerer committed Jul 31, 2024
1 parent 1286031 commit c7b1b3b
Show file tree
Hide file tree
Showing 30 changed files with 352 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ export const ColorScaleSelectorDropdown: FunctionComponent<ColorScaleSelectorDro
setColorScale,
}) => {
return (
<Dropdown buttonTitle={`Color scale`} placement={'bottom-start'}>
<ColorScaleSelector colorScale={colorScale} setColorScale={setColorScale} />
</Dropdown>
<div className='w-20'>
<Dropdown buttonTitle={`Color scale`} placement={'bottom-start'}>
<ColorScaleSelector colorScale={colorScale} setColorScale={setColorScale} />
</Dropdown>
</div>
);
};
6 changes: 3 additions & 3 deletions components/src/preact/components/dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ export const Dropdown: FunctionComponent<DropdownProps> = ({ children, buttonTit
};

return (
<div>
<button type='button' className='btn btn-xs whitespace-nowrap' onClick={toggle} ref={referenceRef}>
<>
<button type='button' className='btn btn-xs whitespace-nowrap w-full' onClick={toggle} ref={referenceRef}>
{buttonTitle}
</button>
<div ref={floatingRef} className={`${dropdownClass} ${showContent ? '' : 'hidden'}`}>
{children}
</div>
</div>
</>
);
};
115 changes: 115 additions & 0 deletions components/src/preact/components/mutation-type-selector.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
import { type Meta, type StoryObj } from '@storybook/preact';
import { expect, within } from '@storybook/test';
import { type FunctionComponent } from 'preact';
import { useState } from 'preact/hooks';

import {
type DisplayedMutationType,
MutationTypeSelector,
type MutationTypeSelectorProps,
} from './mutation-type-selector';

const meta: Meta<MutationTypeSelectorProps> = {
title: 'Component/Mutation type selector',
component: MutationTypeSelector,
parameters: { fetchMock: {} },
};

export default meta;

const WrapperWithState: FunctionComponent<{
displayedMutationTypes: DisplayedMutationType[];
}> = ({ displayedMutationTypes: initialMutationTypes }) => {
const [displayedMutationTypes, setDisplayedMutationTypes] = useState<DisplayedMutationType[]>(initialMutationTypes);

return (
<MutationTypeSelector
displayedMutationTypes={displayedMutationTypes}
setDisplayedMutationTypes={(mutationTypes: DisplayedMutationType[]) => {
setDisplayedMutationTypes(mutationTypes);
}}
/>
);
};

const MutationTypeSelectorStory: StoryObj<MutationTypeSelectorProps> = {
render: (args) => {
return <WrapperWithState {...args} />;
},
};

export const AllMutationTypesSelected: StoryObj<MutationTypeSelectorProps> = {
...MutationTypeSelectorStory,
args: {
displayedMutationTypes: [
{
label: 'Substitution',
type: 'substitution',
checked: true,
},
{
label: 'Deletion',
type: 'deletion',
checked: true,
},
],
},
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement);

await step('Show short form of types as label', async () => {
await expect(canvas.getByText('Subst., Del.')).toBeInTheDocument();
});
},
};

export const NoMutationTypesSelected: StoryObj<MutationTypeSelectorProps> = {
...MutationTypeSelectorStory,
args: {
displayedMutationTypes: [
{
label: 'Substitution',
type: 'substitution',
checked: false,
},
{
label: 'Deletion',
type: 'deletion',
checked: false,
},
],
},
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement);

await step("Show 'No types' as label", async () => {
await expect(canvas.getByText('No types')).toBeInTheDocument();
});
},
};

export const OneTypesSelected: StoryObj<MutationTypeSelectorProps> = {
...MutationTypeSelectorStory,
args: {
displayedMutationTypes: [
{
label: 'Substitution',
type: 'substitution',
checked: true,
},
{
label: 'Deletion',
type: 'deletion',
checked: false,
},
],
},
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement);

await step('Show the selected type as label', async () => {
const substitutionElements = await canvas.getAllByText('Substitution');
await expect(substitutionElements.length).toBe(2);
});
},
};
41 changes: 33 additions & 8 deletions components/src/preact/components/mutation-type-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,39 @@ export const MutationTypeSelector: FunctionComponent<MutationTypeSelectorProps>
displayedMutationTypes,
setDisplayedMutationTypes,
}) => {
const checkedLabels = displayedMutationTypes.filter((type) => type.checked).map((type) => type.label);
const mutationTypesSelectorLabel = `Types: ${checkedLabels.length > 0 ? checkedLabels.join(', ') : 'None'}`;

return (
<CheckboxSelector
items={displayedMutationTypes}
label={mutationTypesSelectorLabel}
setItems={(items) => setDisplayedMutationTypes(items)}
/>
<div className='w-[6rem]'>
<CheckboxSelector
items={displayedMutationTypes}
label={getMutationTypesSelectorLabel(displayedMutationTypes)}
setItems={(items) => setDisplayedMutationTypes(items)}
/>
</div>
);
};

const getMutationTypesSelectorLabel = (displayedMutationTypes: DisplayedMutationType[]) => {
const checkedLabels = displayedMutationTypes.filter((displayedMutationType) => displayedMutationType.checked);

if (checkedLabels.length === 0) {
return `No types`;
}
if (displayedMutationTypes.length === checkedLabels.length) {
return displayedMutationTypes
.map((type) => {
switch (type.type) {
case 'substitution':
return 'Subst.';
case 'deletion':
return 'Del.';
}
})
.join(', ');
}

return checkedLabels
.map((type) => {
return type.label;
})
.join(', ');
};
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,14 @@ export const ProportionSelectorDropdown: FunctionComponent<ProportionSelectorDro
const label = `${(proportionInterval.min * 100).toFixed(1)}% - ${(proportionInterval.max * 100).toFixed(1)}%`;

return (
<Dropdown buttonTitle={`Proportion ${label}`} placement={'bottom-start'}>
<ProportionSelector
proportionInterval={proportionInterval}
setMinProportion={setMinProportion}
setMaxProportion={setMaxProportion}
/>
</Dropdown>
<div className='w-44'>
<Dropdown buttonTitle={`Proportion ${label}`} placement={'bottom-start'}>
<ProportionSelector
proportionInterval={proportionInterval}
setMinProportion={setMinProportion}
setMaxProportion={setMaxProportion}
/>
</Dropdown>
</div>
);
};
151 changes: 151 additions & 0 deletions components/src/preact/components/segment-selector.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
import { type Meta, type StoryObj } from '@storybook/preact';
import { expect, within } from '@storybook/test';
import { type FunctionComponent } from 'preact';
import { useState } from 'preact/hooks';

import { type DisplayedSegment, SegmentSelector, type SegmentSelectorProps } from './segment-selector';

const meta: Meta<SegmentSelectorProps> = {
title: 'Component/Segment selector',
component: SegmentSelector,
parameters: { fetchMock: {} },
};

export default meta;

const WrapperWithState: FunctionComponent<{
displayedSegments: DisplayedSegment[];
}> = ({ displayedSegments: initialDisplayedSegments }) => {
const [displayedSegments, setDisplayedSegments] = useState<DisplayedSegment[]>(initialDisplayedSegments);

return (
<SegmentSelector
displayedSegments={displayedSegments}
setDisplayedSegments={(items: DisplayedSegment[]) => {
setDisplayedSegments(items);
}}
/>
);
};

export const AllSegmentsSelected: StoryObj<SegmentSelectorProps> = {
render: (args) => {
return <WrapperWithState {...args} />;
},
args: {
displayedSegments: [
{
segment: 'ORF1a',
label: 'ORF1a',
checked: true,
},
{
segment: 'S',
label: 'S',
checked: true,
},
{
segment: 'VeryLongSegmentName',
label: 'VeryLongSegmentName',
checked: true,
},
],
},
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement);

await step("Show 'All segments' as label", async () => {
await expect(canvas.getByText('All segments')).toBeInTheDocument();
});
},
};

export const NoSegmentsSelected: StoryObj<SegmentSelectorProps> = {
...AllSegmentsSelected,
args: {
displayedSegments: [
{
segment: 'ORF1a',
label: 'ORF1a',
checked: false,
},
{
segment: 'S',
label: 'S',
checked: false,
},
{
segment: 'VeryLongSegmentName',
label: 'VeryLongSegmentName',
checked: false,
},
],
},
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement);

await step("Show 'No segments' as label", async () => {
await expect(canvas.getByText('No segments')).toBeInTheDocument();
});
},
};

export const LongSegmentsSelected: StoryObj<SegmentSelectorProps> = {
...AllSegmentsSelected,
args: {
displayedSegments: [
{
segment: 'ORF1a',
label: 'ORF1a',
checked: true,
},
{
segment: 'S',
label: 'S',
checked: false,
},
{
segment: 'VeryLongSegmentName',
label: 'VeryLongSegmentName',
checked: true,
},
],
},
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement);

await step('Show number of active segments as label', async () => {
await expect(canvas.getByText('2 segments')).toBeInTheDocument();
});
},
};

export const ShortSegmentsSelected: StoryObj<SegmentSelectorProps> = {
...AllSegmentsSelected,
args: {
displayedSegments: [
{
segment: 'ORF1a',
label: 'ORF1a',
checked: true,
},
{
segment: 'S',
label: 'S',
checked: true,
},
{
segment: 'VeryLongSegmentName',
label: 'VeryLongSegmentName',
checked: false,
},
],
},
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement);

await step('Show active segments as label', async () => {
await expect(canvas.getByText('ORF1a, S')).toBeInTheDocument();
});
},
};
Loading

0 comments on commit c7b1b3b

Please sign in to comment.