Skip to content

Commit

Permalink
*feat CheckableSelectField adornments (#556)
Browse files Browse the repository at this point in the history
*fix Popover handleFocusIn calls onClose on anchorElement click
  • Loading branch information
Sodik authored May 23, 2024
1 parent 41e2edc commit d13eb58
Show file tree
Hide file tree
Showing 9 changed files with 52 additions and 44 deletions.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 13 additions & 1 deletion packages/ui/__stories__/CheckableSelectField.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ import React, { useState } from 'react'
import { logger } from '@hazelcast/services'
import { Meta, Story } from '@storybook/react'
import { Form, Formik } from 'formik'
import { AlertTriangle, Info } from 'react-feather'

import { CheckableSelectField, CheckableSelectProps } from '../src/Select/CheckableSelectField'
import { SelectFieldOption } from '../src/Select/helpers'
import { CheckableSelectFieldFormik } from '../src/Select/CheckableSelectFieldFormik'
import { LONG_ONE_WORD_TEXT, LONG_MULTIPLE_WORD_TEXT } from './constants'
import { Icon } from '../src/Icon'

const options: SelectFieldOption<string>[] = [
{ value: 'darth_vader', label: 'Darth Vader' },
Expand Down Expand Up @@ -146,7 +148,6 @@ export const CustomSearch = Template.bind({})
CustomSearch.args = {
value: [],
options,
filterOptionsLabel: 'Custom negative search',
defaultOpen: true,
filterOptions: (candidate, input) => {
if (!input) {
Expand All @@ -156,3 +157,14 @@ CustomSearch.args = {
return !candidate.label.toLowerCase().includes(input)
},
}

export const WithSearchInputAdornments = Template.bind({})
WithSearchInputAdornments.args = {
value: [],
options,
defaultOpen: true,
searchInputProps: {
endAdornment: <Icon icon={AlertTriangle} />,
startAdornment: <Icon icon={Info} />,
},
}
48 changes: 28 additions & 20 deletions packages/ui/__tests__/Select/CheckableSelectField.test.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import React from 'react'
import { useUID } from 'react-uid'
import { mountAndCheckA11Y, simulateChange } from '@hazelcast/test-helpers'
import { mountAndCheckA11Y } from '@hazelcast/test-helpers'
import { act } from 'react-dom/test-utils'
import { mount } from 'enzyme'

import { CheckableSelectField } from '../../src/Select/CheckableSelectField'
import { Label } from '../../src/Label'
import { Error } from '../../src/Error'
import { SelectFieldOption } from '../../src/Select/helpers'

import styles from '../src/SelectField.module.scss'
import { mount } from 'enzyme'

jest.mock('react-uid')

Expand Down Expand Up @@ -315,7 +315,7 @@ describe('CheckableSelectField', () => {
id += 1
return id.toString()
})
const wrapper = await mountAndCheckA11Y(
await mountAndCheckA11Y(
<CheckableSelectField
defaultOpen
name={selectName}
Expand All @@ -330,25 +330,33 @@ describe('CheckableSelectField', () => {
/>,
)

const searchInput = wrapper.findDataTestFirst('test-search').find('input')

expect(searchInput).toBeTruthy()
act(() => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
simulateChange(searchInput, 'Luke')
})

expect(filterOptions).toHaveBeenCalledTimes(0)

act(() => {
wrapper.findDataTestFirst('test-toggle-custom-search').find('input').simulate('change')
})
expect(filterOptions).toHaveBeenCalled()
})

act(() => {
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
simulateChange(searchInput, 'Luke2')
it('Renders Adornments', async () => {
let id = 0
const onChange = jest.fn()
useUIDMock.mockImplementation(() => {
id += 1
return id.toString()
})
const wrapper = await mountAndCheckA11Y(
<CheckableSelectField
defaultOpen
name={selectName}
label={selectLabel}
options={options}
value={[]}
id={'21313123'}
onChange={onChange}
data-test="test"
endAdornment={<div data-test={'endAdornment'} />}
startAdornment={<div data-test={'startAdornment'} />}
noOptionsMessage="There are no options"
/>,
)

expect(filterOptions).toHaveBeenCalled()
expect(wrapper.findDataTestFirst('endAdornment')).toBeTruthy()
expect(wrapper.findDataTestFirst('startAdornment')).toBeTruthy()
})
})
4 changes: 2 additions & 2 deletions packages/ui/src/Popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -107,11 +107,11 @@ export const Popover: FC<PopoverProps> = (props) => {

const handleFocusIn = useCallback(
(e: FocusEvent) => {
if (popperElement && !popperElement.contains(e.target as Node)) {
if (popperElement && !popperElement.contains(e.target as Node) && !anchorElement?.contains(e.target as Node)) {
onClose()
}
},
[onClose, popperElement],
[onClose, popperElement, anchorElement],
)
const handleKeyDown = useCallback(
(e: KeyboardEvent) => {
Expand Down
30 changes: 9 additions & 21 deletions packages/ui/src/Select/CheckableSelectField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@ import { Link } from '../Link'
import { SelectFieldOption } from './helpers'
import { TextField } from '../TextField'
import { HelpProps } from '../Help'
import { Tooltip } from '../Tooltip'
import { Checkbox } from '../Checkbox'
import { useOpenCloseState } from '../hooks'
import { TruncatedText } from '../TruncatedText'

Expand Down Expand Up @@ -42,7 +40,10 @@ export type CheckableSelectFieldExtraProps<V> = {
noOptionsMessage?: string
defaultOpen?: boolean
id?: string
filterOptionsLabel?: string
searchInputProps?: {
endAdornment?: ReactNode
startAdornment?: ReactNode
}
filterOptions?: (candidate: SelectFieldOption<V>, input: string) => boolean
}

Expand Down Expand Up @@ -82,11 +83,10 @@ export const CheckableSelectField = <V extends string | number = number>(props:
noOptionsMessage = 'No options',
id: rootId,
filterOptions,
filterOptionsLabel,
searchInputProps = {},
} = props
const id = useUID()
const { isOpen, toggle, close } = useOpenCloseState(defaultOpen)
const { isOpen: isCustomSearchEnabled, toggle: toggleCustomSearch } = useOpenCloseState(false)
const [searchValue, setSearchValue] = useState('')
const [forceUpdateToken, setForceUpdateToken] = useState(1)
const [anchorElement, setAnchorElement] = useState<HTMLElement | null>(null)
Expand All @@ -105,13 +105,13 @@ export const CheckableSelectField = <V extends string | number = number>(props:
const value = searchValue.toLowerCase()

return options.filter((option) => {
if (isCustomSearchEnabled && filterOptions) {
if (filterOptions) {
return filterOptions(option, value)
}

return option.label.toLowerCase().includes(value)
})
}, [options, searchValue, isCustomSearchEnabled, filterOptions])
}, [options, searchValue, filterOptions])

const getValueLabel = () => {
if (placeholderMode === 'permanent') {
Expand Down Expand Up @@ -164,6 +164,7 @@ export const CheckableSelectField = <V extends string | number = number>(props:
>
<div className={styles.dropdown} data-test={`${dataTest}-dropdown`}>
<div className={styles.search}>
{searchInputProps.startAdornment}
<TextField
size={size}
iconSize="medium"
Expand All @@ -176,20 +177,7 @@ export const CheckableSelectField = <V extends string | number = number>(props:
disabled={disabled}
placeholder={placeholder}
/>
{filterOptions && (
<Tooltip content={filterOptionsLabel} zIndex={21}>
{(tooltipRef) => (
<Checkbox
ref={tooltipRef}
aria-label="Custom search checkbox"
checked={isCustomSearchEnabled}
name="toggle custom search"
onChange={toggleCustomSearch}
data-test={`${dataTest}-toggle-custom-search`}
/>
)}
</Tooltip>
)}
{searchInputProps.endAdornment}
</div>
<div className={styles.options}>
{filteredOptions.length > 0 ? (
Expand Down

0 comments on commit d13eb58

Please sign in to comment.