Merge pull request #4147 from kamre/multi-select-fix
Improvements for multi-select property
This commit is contained in:
commit
ca15e12ceb
3 changed files with 75 additions and 5 deletions
|
@ -57,6 +57,12 @@ describe('properties/multiSelect', () => {
|
|||
const board = createBoard()
|
||||
const card = createCard()
|
||||
|
||||
const expectOptionsMenuToBeVisible = (template: IPropertyTemplate) => {
|
||||
for (const option of template.options) {
|
||||
expect(screen.getByRole('menuitem', {name: option.value})).toBeInTheDocument()
|
||||
}
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
jest.resetAllMocks()
|
||||
})
|
||||
|
@ -128,6 +134,7 @@ describe('properties/multiSelect', () => {
|
|||
userEvent.type(screen.getByRole('combobox', {name: /value selector/i}), 'b{enter}')
|
||||
|
||||
expect(mockedMutator.changePropertyValue).toHaveBeenCalledWith(board.id, card, propertyTemplate.id, ['multi-option-1', 'multi-option-2'])
|
||||
expectOptionsMenuToBeVisible(propertyTemplate)
|
||||
})
|
||||
|
||||
it('can unselect a option', async () => {
|
||||
|
@ -152,6 +159,58 @@ describe('properties/multiSelect', () => {
|
|||
userEvent.click(screen.getAllByRole('button', {name: /clear/i})[0])
|
||||
|
||||
expect(mockedMutator.changePropertyValue).toHaveBeenCalledWith(board.id, card, propertyTemplate.id, ['multi-option-2'])
|
||||
expectOptionsMenuToBeVisible(propertyTemplate)
|
||||
})
|
||||
|
||||
it('can unselect a option via backspace', async () => {
|
||||
const propertyTemplate = buildMultiSelectPropertyTemplate()
|
||||
const propertyValue = ['multi-option-1', 'multi-option-2']
|
||||
|
||||
render(
|
||||
<MultiSelect
|
||||
property={new MultiSelectProperty()}
|
||||
readOnly={false}
|
||||
showEmptyPlaceholder={false}
|
||||
propertyTemplate={propertyTemplate}
|
||||
propertyValue={propertyValue}
|
||||
board={{...board}}
|
||||
card={{...card}}
|
||||
/>,
|
||||
{wrapper: Wrapper},
|
||||
)
|
||||
|
||||
userEvent.click(screen.getByTestId(nonEditableMultiSelectTestId))
|
||||
|
||||
userEvent.type(screen.getByRole('combobox', {name: /value selector/i}), '{backspace}')
|
||||
|
||||
expect(mockedMutator.changePropertyValue).toHaveBeenCalledWith(board.id, card, propertyTemplate.id, ['multi-option-1'])
|
||||
expectOptionsMenuToBeVisible(propertyTemplate)
|
||||
})
|
||||
|
||||
it('can close menu on escape', async () => {
|
||||
const propertyTemplate = buildMultiSelectPropertyTemplate()
|
||||
const propertyValue = ['multi-option-1', 'multi-option-2']
|
||||
|
||||
render(
|
||||
<MultiSelect
|
||||
property={new MultiSelectProperty()}
|
||||
readOnly={false}
|
||||
showEmptyPlaceholder={false}
|
||||
propertyTemplate={propertyTemplate}
|
||||
propertyValue={propertyValue}
|
||||
board={{...board}}
|
||||
card={{...card}}
|
||||
/>,
|
||||
{wrapper: Wrapper},
|
||||
)
|
||||
|
||||
userEvent.click(screen.getByTestId(nonEditableMultiSelectTestId))
|
||||
|
||||
userEvent.type(screen.getByRole('combobox', {name: /value selector/i}), '{escape}')
|
||||
|
||||
for (const option of propertyTemplate.options) {
|
||||
expect(screen.queryByRole('menuitem', {name: option.value})).toBeNull()
|
||||
}
|
||||
})
|
||||
|
||||
it('can create a new option', async () => {
|
||||
|
@ -177,6 +236,7 @@ describe('properties/multiSelect', () => {
|
|||
userEvent.type(screen.getByRole('combobox', {name: /value selector/i}), 'new-value{enter}')
|
||||
|
||||
expect(mockedMutator.insertPropertyOption).toHaveBeenCalledWith(board.id, board.cardProperties, propertyTemplate, expect.objectContaining({value: 'new-value'}), 'add property option')
|
||||
expectOptionsMenuToBeVisible(propertyTemplate)
|
||||
})
|
||||
|
||||
it('can delete a option', () => {
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
.IconButton.delete-value {
|
||||
@include z-index(value-selector-delete);
|
||||
width: 16px;
|
||||
min-width: 16px;
|
||||
height: 16px;
|
||||
flex: 0 0 auto;
|
||||
|
||||
i {
|
||||
font-size: 16px;
|
||||
|
|
|
@ -71,7 +71,10 @@ const ValueSelectorLabel = (props: LabelProps): JSX.Element => {
|
|||
)
|
||||
}
|
||||
return (
|
||||
<div className='value-menu-option'>
|
||||
<div
|
||||
className='value-menu-option'
|
||||
role='menuitem'
|
||||
>
|
||||
<div className='label-container'>
|
||||
<Label color={option.color}>{option.value}</Label>
|
||||
</div>
|
||||
|
@ -162,7 +165,6 @@ function ValueSelector(props: Props): JSX.Element {
|
|||
captureMenuScroll={true}
|
||||
maxMenuHeight={1200}
|
||||
isMulti={props.isMulti}
|
||||
menuIsOpen={true}
|
||||
isClearable={true}
|
||||
styles={valueSelectorStyle}
|
||||
formatOptionLabel={(option: IPropertyOption, meta: FormatOptionLabelMeta<IPropertyOption>) => (
|
||||
|
@ -181,24 +183,32 @@ function ValueSelector(props: Props): JSX.Element {
|
|||
getOptionLabel={(o: IPropertyOption) => o.value}
|
||||
getOptionValue={(o: IPropertyOption) => o.id}
|
||||
onChange={(value: OnChangeValue<IPropertyOption, true | false>, action: ActionMeta<IPropertyOption>): void => {
|
||||
if (action.action === 'select-option') {
|
||||
if (action.action === 'select-option' || action.action === 'pop-value') {
|
||||
if (Array.isArray(value)) {
|
||||
props.onChange((value as IPropertyOption[]).map((option) => option.id))
|
||||
} else {
|
||||
props.onChange((value as IPropertyOption).id)
|
||||
props.onBlur?.()
|
||||
}
|
||||
} else if (action.action === 'clear') {
|
||||
props.onChange('')
|
||||
}
|
||||
}}
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === 'Escape') {
|
||||
props.onBlur?.()
|
||||
}
|
||||
}}
|
||||
onBlur={props.onBlur}
|
||||
onCreateOption={props.onCreate}
|
||||
autoFocus={true}
|
||||
value={props.value || null}
|
||||
closeMenuOnSelect={true}
|
||||
closeMenuOnSelect={!props.isMulti}
|
||||
placeholder={props.emptyValue}
|
||||
hideSelectedOptions={false}
|
||||
defaultMenuIsOpen={true}
|
||||
menuIsOpen={props.isMulti}
|
||||
blurInputOnSelect={!props.isMulti}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue