Skip to content

Commit 9efe801

Browse files
committed
feat(transfer): use native single-/multi selects
1 parent 457e04f commit 9efe801

File tree

3 files changed

+52
-51
lines changed

3 files changed

+52
-51
lines changed

components/transfer/src/options-container.js

+32-14
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@ export const OptionsContainer = ({
1212
getOptionClickHandlers,
1313
highlightedOptions,
1414
loading,
15+
maxSelections,
1516
renderOption,
1617
options,
1718
selected,
1819
selectionHandler,
20+
setHighlightedOptions,
1921
toggleHighlightedOption,
2022
}) => {
2123
const optionsRef = useRef(null)
@@ -31,9 +33,28 @@ export const OptionsContainer = ({
3133
)}
3234

3335
<div className="container" data-test={dataTest} ref={optionsRef}>
34-
<div className="content-container" ref={wrapperRef}>
36+
<select
37+
multiple={maxSelections === Infinity}
38+
size={maxSelections === 1 ? 2 : undefined}
39+
className="content-container"
40+
ref={wrapperRef}
41+
onChange={(e) => {
42+
const nextSelected = [...e.target.options].reduce(
43+
(curNextSelected, option) => {
44+
if (!option.selected) {
45+
return curNextSelected
46+
}
47+
48+
return [...curNextSelected, option.value]
49+
},
50+
[]
51+
)
52+
setHighlightedOptions(nextSelected)
53+
}}
54+
>
3555
{!options.length && emptyComponent}
36-
{options.map((option) => {
56+
{options.map((option, index) => {
57+
const isLast = index === options.length - 1
3758
const highlighted = !!highlightedOptions.find(
3859
(highlightedSourceOption) =>
3960
highlightedSourceOption === option.value
@@ -54,28 +75,18 @@ export const OptionsContainer = ({
5475
</Fragment>
5576
)
5677
})}
57-
58-
{onEndReached && (
59-
<EndIntersectionDetector
60-
dataTest={`${dataTest}-endintersectiondetector`}
61-
key={`key-${resizeCounter}`}
62-
rootRef={optionsRef}
63-
onEndReached={onEndReached}
64-
/>
65-
)}
66-
</div>
78+
</select>
6779
</div>
6880

6981
<style jsx>{`
7082
.optionsContainer {
7183
flex-grow: 1;
72-
padding: ${spacers.dp4} 0;
7384
position: relative;
7485
overflow: hidden;
7586
}
7687
7788
.container {
78-
overflow-y: auto;
89+
overflow: hidden;
7990
height: 100%;
8091
}
8192
@@ -94,6 +105,11 @@ export const OptionsContainer = ({
94105
.content-container {
95106
z-index: 1;
96107
position: relative;
108+
height: 100%;
109+
width: 100%;
110+
overflow: auto;
111+
border: 0;
112+
padding: ${spacers.dp4} 0;
97113
}
98114
99115
.loading + .container .content-container {
@@ -111,6 +127,8 @@ OptionsContainer.defaultProps = {
111127
OptionsContainer.propTypes = {
112128
dataTest: PropTypes.string.isRequired,
113129
getOptionClickHandlers: PropTypes.func.isRequired,
130+
maxSelections: PropTypes.oneOf([1, Infinity]).isRequired,
131+
setHighlightedOptions: PropTypes.func.isRequired,
114132
emptyComponent: PropTypes.node,
115133
highlightedOptions: PropTypes.arrayOf(PropTypes.string),
116134
loading: PropTypes.bool,
+16-37
Original file line numberDiff line numberDiff line change
@@ -1,73 +1,53 @@
11
import { colors } from '@dhis2/ui-constants'
22
import cx from 'classnames'
33
import PropTypes from 'prop-types'
4-
import React, { useRef } from 'react'
5-
6-
const DOUBLE_CLICK_MAX_DELAY = 500
4+
import React from 'react'
75

86
export const TransferOption = ({
97
className,
108
disabled,
119
dataTest,
12-
highlighted,
1310
onClick,
1411
onDoubleClick,
1512
label,
1613
value,
1714
}) => {
18-
const doubleClickTimeout = useRef(null)
19-
2015
return (
21-
<div
22-
data-test={dataTest}
23-
onClick={(event) => {
24-
if (disabled) {
25-
return
26-
}
27-
28-
if (doubleClickTimeout.current) {
29-
clearTimeout(doubleClickTimeout.current)
30-
doubleClickTimeout.current = null
31-
32-
onDoubleClick({ value }, event)
33-
} else {
34-
doubleClickTimeout.current = setTimeout(() => {
35-
clearTimeout(doubleClickTimeout.current)
36-
doubleClickTimeout.current = null
37-
}, DOUBLE_CLICK_MAX_DELAY)
38-
39-
onClick({ value }, event)
40-
}
41-
}}
42-
data-value={value}
43-
className={cx(className, { highlighted, disabled })}
44-
>
45-
{label}
16+
<>
17+
<option
18+
className={cx(className, { disabled })}
19+
data-test={dataTest}
20+
data-value={value}
21+
value={value}
22+
onDoubleClick={(e) => onDoubleClick({ value }, event)}
23+
>
24+
{label}
25+
</option>
4626

4727
<style jsx>{`
48-
div {
28+
option {
4929
font-size: 14px;
5030
line-height: 16px;
5131
padding: 4px 8px;
5232
color: ${colors.grey900};
5333
user-select: none;
5434
}
5535
56-
div:hover {
36+
option:hover {
5737
background: ${colors.grey200};
5838
}
5939
60-
div.highlighted {
40+
option:checked {
6141
background: ${colors.teal700};
6242
color: ${colors.white};
6343
}
6444
65-
div.disabled {
45+
option.disabled {
6646
color: ${colors.grey600};
6747
cursor: not-allowed;
6848
}
6949
`}</style>
70-
</div>
50+
</>
7151
)
7252
}
7353

@@ -81,7 +61,6 @@ TransferOption.propTypes = {
8161
className: PropTypes.string,
8262
dataTest: PropTypes.string,
8363
disabled: PropTypes.bool,
84-
highlighted: PropTypes.bool,
8564
onClick: PropTypes.func,
8665
onDoubleClick: PropTypes.func,
8766
}

components/transfer/src/transfer.js

+4
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,8 @@ export const Transfer = ({
217217
)}
218218

219219
<OptionsContainer
220+
maxSelections={maxSelections}
221+
setHighlightedOptions={setHighlightedSourceOptions}
220222
dataTest={`${dataTest}-sourceoptions`}
221223
emptyComponent={sourceEmptyPlaceholder}
222224
getOptionClickHandlers={getOptionClickHandlers}
@@ -324,6 +326,8 @@ export const Transfer = ({
324326
)}
325327

326328
<OptionsContainer
329+
maxSelections={maxSelections}
330+
setHighlightedOptions={setHighlightedPickedOptions}
327331
selected
328332
dataTest={`${dataTest}-pickedoptions`}
329333
emptyComponent={selectedEmptyComponent}

0 commit comments

Comments
 (0)