diff --git a/theme/components/Tag/Tag.ts b/theme/components/Tag/Tag.ts index 047ce7d698..6ea4c41d10 100644 --- a/theme/components/Tag/Tag.ts +++ b/theme/components/Tag/Tag.ts @@ -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 = { diff --git a/ui/shared/tagGroupSelect/TagGroupSelect.pw.tsx b/ui/shared/tagGroupSelect/TagGroupSelect.pw.tsx new file mode 100644 index 0000000000..4ccc12110c --- /dev/null +++ b/ui/shared/tagGroupSelect/TagGroupSelect.pw.tsx @@ -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( + , + ); + + await component.getByText('Option 2').hover(); + + await expect(component).toHaveScreenshot(); +}); diff --git a/ui/shared/tagGroupSelect/TagGroupSelect.tsx b/ui/shared/tagGroupSelect/TagGroupSelect.tsx new file mode 100644 index 0000000000..4bf53b2ce1 --- /dev/null +++ b/ui/shared/tagGroupSelect/TagGroupSelect.tsx @@ -0,0 +1,56 @@ +import { HStack, Tag } from '@chakra-ui/react'; +import React from 'react'; + +type Props = { + items: Array<{ id: T; title: string }>; +} & ( + { + value: T; + onChange: (value: T) => void; + isMulti?: false; + } | { + value: Array; + onChange: (value: Array) => void; + isMulti: true; + } +) + +const TagGroupSelect = ({ items, value, isMulti, onChange }: Props) => { + 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 ( + + { items.map(item => { + const isSelected = isMulti ? value.includes(item.id) : value === item.id; + return ( + + { item.title } + + ); + }) } + + ); +}; + +export default TagGroupSelect; diff --git a/ui/shared/tagGroupSelect/__screenshots__/TagGroupSelect.pw.tsx_dark-color-mode_base-view-dark-mode-1.png b/ui/shared/tagGroupSelect/__screenshots__/TagGroupSelect.pw.tsx_dark-color-mode_base-view-dark-mode-1.png new file mode 100644 index 0000000000..4684f4fcdc Binary files /dev/null and b/ui/shared/tagGroupSelect/__screenshots__/TagGroupSelect.pw.tsx_dark-color-mode_base-view-dark-mode-1.png differ diff --git a/ui/shared/tagGroupSelect/__screenshots__/TagGroupSelect.pw.tsx_default_base-view-dark-mode-1.png b/ui/shared/tagGroupSelect/__screenshots__/TagGroupSelect.pw.tsx_default_base-view-dark-mode-1.png new file mode 100644 index 0000000000..b6a14300fc Binary files /dev/null and b/ui/shared/tagGroupSelect/__screenshots__/TagGroupSelect.pw.tsx_default_base-view-dark-mode-1.png differ