Skip to content

Commit 250e4b0

Browse files
ActionList: Use icon instead of input for multiple selection (#1601)
* Use icon instead of input for multiple selection * use icon for ActionList1 as well * removed unused variable * center items in visual container * update Autocomplete snapshots for new selection Co-authored-by: Mike Perrotti <mperrotti@github.com>
1 parent ebaba02 commit 250e4b0

File tree

5 files changed

+785
-281
lines changed

5 files changed

+785
-281
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@primer/components': patch
3+
---
4+
5+
ActionList: Use icon instead of input for multiple selection in ActionList

src/ActionList/Item.tsx

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,9 @@ const BaseVisualContainer = styled.div<{variant?: ItemProps['variant']; disabled
295295
height: 20px;
296296
width: ${get('space.3')};
297297
margin-right: ${get('space.2')};
298+
display: flex;
299+
justify-content: center;
300+
align-items: center;
298301
`
299302

300303
const ColoredVisualContainer = styled(BaseVisualContainer)`
@@ -333,8 +336,16 @@ const DescriptionContainer = styled.span`
333336
flex-basis: var(--description-container-flex-basis);
334337
`
335338

336-
const MultiSelectInput = styled.input`
337-
pointer-events: none;
339+
const MultiSelectIcon = styled.svg<{selected?: boolean}>`
340+
rect {
341+
fill: ${({selected}) => (selected ? get('colors.accent.fg') : get('colors.canvas.default'))};
342+
stroke: ${({selected}) => (selected ? get('colors.accent.fg') : get('colors.border.default'))};
343+
}
344+
path {
345+
fill: ${get('colors.fg.onEmphasis')};
346+
boxshadow: ${get('shadow.small')};
347+
opacity: ${({selected}) => (selected ? 1 : 0)};
348+
}
338349
`
339350

340351
/**
@@ -372,11 +383,6 @@ export const Item = React.forwardRef((itemProps, ref) => {
372383
return
373384
}
374385
onKeyPress?.(event)
375-
const isCheckbox = event.target instanceof HTMLInputElement && event.target.type === 'checkbox'
376-
if (isCheckbox && event.key === ' ') {
377-
// space key on a checkbox will also trigger a click event. Ignore the space key so we don't get double events
378-
return
379-
}
380386

381387
if (!event.defaultPrevented && [' ', 'Enter'].includes(event.key)) {
382388
onAction?.(itemProps, event)
@@ -425,19 +431,26 @@ export const Item = React.forwardRef((itemProps, ref) => {
425431
<BaseVisualContainer>
426432
{selectionVariant === 'multiple' ? (
427433
<>
428-
{/*
429-
* readOnly is required because we are doing a one-way bind to `checked`.
430-
* aria-readonly="false" tells screen that they can still interact with the checkbox
434+
{/**
435+
* we use a svg instead of an input because there should not
436+
* be an interactive element inside an option
437+
* svg copied from primer/css
431438
*/}
432-
<MultiSelectInput
433-
disabled={disabled}
434-
tabIndex={-1}
435-
type="checkbox"
436-
checked={selected}
437-
aria-label={text}
438-
readOnly
439-
aria-readonly="false"
440-
/>
439+
<MultiSelectIcon
440+
selected={selected}
441+
width="16"
442+
height="16"
443+
viewBox="0 0 16 16"
444+
xmlns="http://www.w3.org/2000/svg"
445+
aria-hidden="true"
446+
>
447+
<rect x="2" y="2" width="12" height="12" rx="4"></rect>
448+
<path
449+
fillRule="evenodd"
450+
strokeWidth="0"
451+
d="M4.03231 8.69862C3.84775 8.20646 4.49385 7.77554 4.95539 7.77554C5.41693 7.77554 6.80154 9.85246 6.80154 9.85246C6.80154 9.85246 10.2631 4.314 10.4938 4.08323C10.7246 3.85246 11.8785 4.08323 11.4169 5.00631C11.0081 5.82388 7.26308 11.4678 7.26308 11.4678C7.26308 11.4678 6.80154 12.1602 6.34 11.4678C5.87846 10.7755 4.21687 9.19077 4.03231 8.69862Z"
452+
/>
453+
</MultiSelectIcon>
441454
</>
442455
) : (
443456
selected && <CheckIcon fill={theme?.colors.fg.default} />

src/ActionList2/Item.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ export const Item = React.forwardRef<HTMLLIElement, ItemProps>(
207207
{...props}
208208
>
209209
<ItemWrapper>
210-
<Selection selected={selected} disabled={disabled} />
210+
<Selection selected={selected} />
211211
{slots.LeadingVisual}
212212
<Box
213213
data-component="ActionList.Item--DividerContainer"

src/ActionList2/Selection.tsx

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ import {GroupContext} from './Group'
55
import {ItemProps} from './Item'
66
import {LeadingVisualContainer} from './Visuals'
77

8-
type SelectionProps = Pick<ItemProps, 'selected' | 'disabled'>
9-
export const Selection: React.FC<SelectionProps> = ({selected, disabled}) => {
8+
type SelectionProps = Pick<ItemProps, 'selected'>
9+
export const Selection: React.FC<SelectionProps> = ({selected}) => {
1010
const {selectionVariant: listSelectionVariant} = React.useContext(ListContext)
1111
const {selectionVariant: groupSelectionVariant} = React.useContext(GroupContext)
1212

@@ -29,12 +29,32 @@ export const Selection: React.FC<SelectionProps> = ({selected, disabled}) => {
2929

3030
/**
3131
* selectionVariant is multiple
32-
* readOnly is required because we are doing a one-way bind to `checked`
33-
* aria-readonly="false" tells screen that they can still interact with the checkbox
32+
* we use a svg instead of an input because there should not
33+
* be an interactive element inside an option
34+
* svg copied from primer/css
3435
*/
3536
return (
36-
<LeadingVisualContainer sx={{input: {margin: 0, pointerEvents: 'none'}}}>
37-
<input type="checkbox" checked={selected} disabled={disabled} tabIndex={-1} readOnly aria-readonly="false" />
37+
<LeadingVisualContainer
38+
sx={{
39+
rect: {
40+
fill: selected ? 'accent.fg' : 'canvas.default',
41+
stroke: selected ? 'accent.fg' : 'border.default'
42+
},
43+
path: {
44+
fill: 'fg.onEmphasis',
45+
boxShadow: 'shadow.small',
46+
opacity: selected ? 1 : 0
47+
}
48+
}}
49+
>
50+
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
51+
<rect x="2" y="2" width="12" height="12" rx="4"></rect>
52+
<path
53+
fillRule="evenodd"
54+
strokeWidth="0"
55+
d="M4.03231 8.69862C3.84775 8.20646 4.49385 7.77554 4.95539 7.77554C5.41693 7.77554 6.80154 9.85246 6.80154 9.85246C6.80154 9.85246 10.2631 4.314 10.4938 4.08323C10.7246 3.85246 11.8785 4.08323 11.4169 5.00631C11.0081 5.82388 7.26308 11.4678 7.26308 11.4678C7.26308 11.4678 6.80154 12.1602 6.34 11.4678C5.87846 10.7755 4.21687 9.19077 4.03231 8.69862Z"
56+
/>
57+
</svg>
3858
</LeadingVisualContainer>
3959
)
4060
}

0 commit comments

Comments
 (0)