mirror of
https://github.com/luxfi/explore.git
synced 2026-09-24 00:28:18 +00:00
Merge pull request #2014 from blockscout/tag-group-select
tag group select component
This commit is contained in:
@@ -3,9 +3,11 @@ import {
|
||||
createMultiStyleConfigHelpers,
|
||||
defineStyle,
|
||||
} from '@chakra-ui/styled-system';
|
||||
import { mode } from '@chakra-ui/theme-tools';
|
||||
|
||||
import getDefaultTransitionProps from '../../utils/getDefaultTransitionProps';
|
||||
import Badge from '../Badge';
|
||||
|
||||
const transitionProps = getDefaultTransitionProps();
|
||||
|
||||
const { defineMultiStyleConfig, definePartsStyle } =
|
||||
@@ -15,6 +17,23 @@ const variants = {
|
||||
subtle: definePartsStyle((props) => ({
|
||||
container: Badge.variants?.subtle(props),
|
||||
})),
|
||||
select: definePartsStyle((props) => ({
|
||||
container: {
|
||||
bg: mode('gray.100', 'gray.800')(props),
|
||||
color: mode('gray.500', 'whiteAlpha.800')(props),
|
||||
_hover: {
|
||||
color: 'blue.400',
|
||||
opacity: 0.76,
|
||||
},
|
||||
[`
|
||||
&[data-selected=true],
|
||||
&[data-selected=true][aria-selected=true]
|
||||
`]: {
|
||||
bg: mode('blue.500', 'blue.900')(props),
|
||||
color: 'whiteAlpha.800',
|
||||
},
|
||||
},
|
||||
})),
|
||||
};
|
||||
|
||||
const sizes = {
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
import _noop from 'lodash/noop';
|
||||
import React from 'react';
|
||||
|
||||
import { test, expect } from 'playwright/lib';
|
||||
|
||||
import TagGroupSelect from './TagGroupSelect';
|
||||
|
||||
test.use({ viewport: { width: 480, height: 140 } });
|
||||
|
||||
test('base view +@dark-mode', async({ render }) => {
|
||||
const component = await render(
|
||||
<TagGroupSelect
|
||||
items={ [ { id: '1', title: 'Option 1' }, { id: '2', title: 'Option 2' }, { id: 'duck', title: 'Cute little duck' } ] }
|
||||
value="duck"
|
||||
onChange={ _noop }
|
||||
/>,
|
||||
);
|
||||
|
||||
await component.getByText('Option 2').hover();
|
||||
|
||||
await expect(component).toHaveScreenshot();
|
||||
});
|
||||
@@ -0,0 +1,56 @@
|
||||
import { HStack, Tag } from '@chakra-ui/react';
|
||||
import React from 'react';
|
||||
|
||||
type Props<T extends string> = {
|
||||
items: Array<{ id: T; title: string }>;
|
||||
} & (
|
||||
{
|
||||
value: T;
|
||||
onChange: (value: T) => void;
|
||||
isMulti?: false;
|
||||
} | {
|
||||
value: Array<T>;
|
||||
onChange: (value: Array<T>) => void;
|
||||
isMulti: true;
|
||||
}
|
||||
)
|
||||
|
||||
const TagGroupSelect = <T extends string>({ items, value, isMulti, onChange }: Props<T>) => {
|
||||
const onItemClick = React.useCallback((event: React.SyntheticEvent) => {
|
||||
const itemValue = (event.currentTarget as HTMLDivElement).getAttribute('data-id') as T;
|
||||
if (isMulti) {
|
||||
let newValue;
|
||||
if (value.includes(itemValue)) {
|
||||
newValue = value.filter(i => i !== itemValue);
|
||||
} else {
|
||||
newValue = [ ...value, itemValue ];
|
||||
}
|
||||
onChange(newValue);
|
||||
} else {
|
||||
onChange(itemValue);
|
||||
}
|
||||
}, [ isMulti, onChange, value ]);
|
||||
|
||||
return (
|
||||
<HStack>
|
||||
{ items.map(item => {
|
||||
const isSelected = isMulti ? value.includes(item.id) : value === item.id;
|
||||
return (
|
||||
<Tag
|
||||
variant="select"
|
||||
key={ item.id }
|
||||
data-id={ item.id }
|
||||
data-selected={ isSelected }
|
||||
fontWeight={ 500 }
|
||||
cursor="pointer"
|
||||
onClick={ onItemClick }
|
||||
>
|
||||
{ item.title }
|
||||
</Tag>
|
||||
);
|
||||
}) }
|
||||
</HStack>
|
||||
);
|
||||
};
|
||||
|
||||
export default TagGroupSelect;
|
||||
BIN
Binary file not shown.
|
After Width: | Height: | Size: 3.9 KiB |
BIN
Binary file not shown.
|
After Width: | Height: | Size: 3.7 KiB |
Reference in New Issue
Block a user