Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions packages/core/components/ComboBox/ComboBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ const ComboBox: React.FC<ComboBoxProps> = ({
setQuery('')
setFocused(false)
setActiveIndex(-1)
inputRef.current?.blur()
}

// Handle input change (typing)
Expand Down Expand Up @@ -181,7 +180,6 @@ const ComboBox: React.FC<ComboBoxProps> = ({
setQuery('')
setFocused(false)
setActiveIndex(-1)
inputRef.current?.blur()
break

case 'Tab':
Expand Down
13 changes: 9 additions & 4 deletions packages/core/components/ComboBox/combobox.styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
display: flex;
position: relative;
width: 100%;

&:focus-within {
outline: dashed 2px rgb(0, 122, 153) !important;
outline-offset: 3px !important;
}
}

input.cove-combobox-input[role='combobox'] {
Expand Down Expand Up @@ -36,12 +41,12 @@
border: 1px solid var(--cool-gray-10) !important;
box-shadow: none;
color: var(--cool-gray-90);
outline: none !important;
}

input.cove-combobox-input[role='combobox']:focus-visible {
border-radius: 6px !important;
outline: dashed 2px rgb(0, 122, 153) !important;
outline-offset: 3px !important;
outline: none !important;
}

input.cove-combobox-input[role='combobox']:disabled {
Expand Down Expand Up @@ -119,9 +124,9 @@
color: var(--cool-gray-90);
cursor: pointer;
font-family: var(--app-font-secondary);
font-size: 0.778rem;
font-size: 0.883rem;
font-weight: 300;
padding: 0.5rem 0.5rem;
padding: 0.3rem 0.3rem;
transition: background-color 0.15s ease-in-out;
user-select: none;
}
Expand Down
57 changes: 57 additions & 0 deletions packages/core/components/ComboBox/tests/ComboBox.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { fireEvent, render, screen } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import ComboBox from '../ComboBox'

vi.mock('../../../assets/icon-magnifying-glass.svg', () => ({
default: props => <svg data-testid='mock-magnifying-glass' {...props} />
}))

const options = [
{ value: '2023', label: '2023' },
{ value: '2024', label: '2024' },
{ value: '2025', label: '2025' }
]

const renderComboBox = (selected = '2023') => {
const updateField = vi.fn()

render(
<ComboBox fieldName='year' label='Year' options={options} selected={selected} updateField={updateField} />
)

return {
input: screen.getByRole('combobox'),
updateField
}
}

describe('ComboBox', () => {
it('keeps focus on the input when escape closes the listbox', () => {
const { input } = renderComboBox()

input.focus()
fireEvent.keyDown(input, { key: 'ArrowDown' })

expect(input).toHaveAttribute('aria-expanded', 'true')

fireEvent.keyDown(input, { key: 'Escape' })

expect(input).toHaveFocus()
expect(input).toHaveAttribute('aria-expanded', 'false')
expect(input).toHaveDisplayValue('2023')
})

it('selects the active option with enter and restores the closed display', () => {
const { input, updateField } = renderComboBox()

input.focus()
fireEvent.change(input, { target: { value: '2024' } })
fireEvent.keyDown(input, { key: 'ArrowDown' })
fireEvent.keyDown(input, { key: 'Enter' })

expect(updateField).toHaveBeenCalledWith(null, null, 'year', '2024')
expect(input).toHaveFocus()
expect(input).toHaveAttribute('aria-expanded', 'false')
expect(input).toHaveDisplayValue('2023')
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import { fireEvent, render, screen } from '@testing-library/react'
import { describe, expect, it, vi } from 'vitest'
import NestedDropdownEditor from './NestedDropdownEditor'

describe('NestedDropdownEditor', () => {
it('renders the subgroup-only checkbox below Create query parameters and defaults it to unchecked', () => {
const updateField = vi.fn()

render(
<NestedDropdownEditor
config={
{
filters: [
{
label: 'Year and Quarter',
filterStyle: 'nested-dropdown',
columnName: 'year',
values: ['2023', '2024'],
order: 'asc',
subGrouping: {
columnName: 'quarter',
valuesLookup: {
'2023': { values: ['Q1', 'Q2'] },
'2024': { values: ['Q3', 'Q4'] }
}
}
}
]
} as any
}
dataColumns={['year', 'quarter', 'region']}
filterIndex={0}
handleGroupingCustomOrder={vi.fn()}
handleNameChange={vi.fn()}
rawData={[
{ year: '2023', quarter: 'Q1' },
{ year: '2023', quarter: 'Q2' },
{ year: '2024', quarter: 'Q3' }
]}
updateField={updateField}
updateFilterStyle={vi.fn()}
/>
)

const queryParameters = screen.getByLabelText('Create query parameters')
const displaySubgroupingOnly = screen.getByLabelText('Display subgrouping only')

expect(displaySubgroupingOnly).not.toBeChecked()

const queryParametersLabel = queryParameters.closest('label')
const displaySubgroupingOnlyLabel = displaySubgroupingOnly.closest('label')
const isBelowQueryParameters = !!(
queryParametersLabel &&
displaySubgroupingOnlyLabel &&
queryParametersLabel.compareDocumentPosition(displaySubgroupingOnlyLabel) & Node.DOCUMENT_POSITION_FOLLOWING
)

expect(isBelowQueryParameters).toBe(true)

fireEvent.click(displaySubgroupingOnly)

expect(updateField).toHaveBeenCalledWith('filters', 0, 'displaySubgroupingOnly', true)
})

it('does not render the subgroup-only checkbox when the filter is not nested-dropdown', () => {
render(
<NestedDropdownEditor
config={
{
filters: [
{
label: 'Year and Quarter',
filterStyle: 'dropdown',
columnName: 'year',
values: ['2023', '2024'],
order: 'asc',
subGrouping: {
columnName: 'quarter',
valuesLookup: {
'2023': { values: ['Q1', 'Q2'] },
'2024': { values: ['Q3', 'Q4'] }
}
}
}
]
} as any
}
dataColumns={['year', 'quarter', 'region']}
filterIndex={0}
handleGroupingCustomOrder={vi.fn()}
handleNameChange={vi.fn()}
rawData={[
{ year: '2023', quarter: 'Q1' },
{ year: '2023', quarter: 'Q2' },
{ year: '2024', quarter: 'Q3' }
]}
updateField={vi.fn()}
updateFilterStyle={vi.fn()}
/>
)

expect(screen.queryByLabelText('Display subgrouping only')).not.toBeInTheDocument()
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,20 @@ const NestedDropdownEditor: React.FC<NestedDropdownEditorProps> = ({
)}
</label>

{filter.filterStyle === 'nested-dropdown' && (
<label>
<input
type='checkbox'
checked={!!filter.displaySubgroupingOnly}
aria-label='Display subgrouping only'
onChange={e => {
updateGroupingFilterProp('displaySubgroupingOnly', e.target.checked)
}}
/>
<span> Display subgrouping only</span>
</label>
)}

<div className='mt-2'>
<div className='edit-label column-heading float-right'>{filter.columnName} </div>
<Select
Expand Down
1 change: 1 addition & 0 deletions packages/core/components/Filters/Filters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ const Filters: React.FC<FilterProps> = ({
<NestedDropdown
activeGroup={nestedActiveGroup}
activeSubGroup={nestedActiveSubGroup}
displaySubgroupingOnly={singleFilter.displaySubgroupingOnly}
filterIndex={outerIndex}
options={getNestedOptions(singleFilter)}
listLabel={label}
Expand Down
Loading
Loading