diff --git a/packages/widgets/src/Transfer/PickedOptions.js b/packages/widgets/src/Transfer/PickedOptions.js
new file mode 100644
index 0000000000..78a41a906d
--- /dev/null
+++ b/packages/widgets/src/Transfer/PickedOptions.js
@@ -0,0 +1,29 @@
+import React from 'react'
+import propTypes from '@dhis2/prop-types'
+
+import { spacers } from '@dhis2/ui-constants'
+
+export const PickedOptions = ({
+ children,
+ dataTest,
+ selectedEmptyComponent,
+}) => (
+
+ {!React.Children.count(children) && selectedEmptyComponent}
+ {children}
+
+
+
+)
+
+PickedOptions.propTypes = {
+ children: propTypes.node.isRequired,
+ dataTest: propTypes.string.isRequired,
+ selectedEmptyComponent: propTypes.node,
+}
diff --git a/packages/core/src/Transfer/RemoveAll.js b/packages/widgets/src/Transfer/RemoveAll.js
similarity index 93%
rename from packages/core/src/Transfer/RemoveAll.js
rename to packages/widgets/src/Transfer/RemoveAll.js
index 104b1c4c55..0359b97aa7 100644
--- a/packages/core/src/Transfer/RemoveAll.js
+++ b/packages/widgets/src/Transfer/RemoveAll.js
@@ -1,7 +1,7 @@
+import { Button } from '@dhis2/ui-core'
import React from 'react'
import propTypes from '@dhis2/prop-types'
-import { Button } from '../Button/Button.js'
import { IconRemoveAll } from './icons.js'
export const RemoveAll = ({ label, dataTest, disabled, onClick }) => (
diff --git a/packages/core/src/Transfer/RemoveIndividual.js b/packages/widgets/src/Transfer/RemoveIndividual.js
similarity index 93%
rename from packages/core/src/Transfer/RemoveIndividual.js
rename to packages/widgets/src/Transfer/RemoveIndividual.js
index df382e6a0c..7e5aa58fe2 100644
--- a/packages/core/src/Transfer/RemoveIndividual.js
+++ b/packages/widgets/src/Transfer/RemoveIndividual.js
@@ -1,7 +1,7 @@
+import { Button } from '@dhis2/ui-core'
import React from 'react'
import propTypes from '@dhis2/prop-types'
-import { Button } from '../Button/Button.js'
import { IconRemoveIndividual } from './icons.js'
export const RemoveIndividual = ({ label, dataTest, disabled, onClick }) => (
diff --git a/packages/core/src/Transfer/ReorderingActions.js b/packages/widgets/src/Transfer/ReorderingActions.js
similarity index 91%
rename from packages/core/src/Transfer/ReorderingActions.js
rename to packages/widgets/src/Transfer/ReorderingActions.js
index b349c03fdc..a86ccee158 100644
--- a/packages/core/src/Transfer/ReorderingActions.js
+++ b/packages/widgets/src/Transfer/ReorderingActions.js
@@ -1,9 +1,8 @@
+import { Button } from '@dhis2/ui-core'
+import { spacers } from '@dhis2/ui-constants'
import React from 'react'
import propTypes from '@dhis2/prop-types'
-import { spacers } from '@dhis2/ui-constants'
-
-import { Button } from '../Button/Button.js'
import { IconMoveDown, IconMoveUp } from './icons.js'
export const ReorderingActions = ({
@@ -34,8 +33,8 @@ export const ReorderingActions = ({
dataTest={`${dataTest}-buttonmoveup`}
icon={
}
/>
diff --git a/packages/core/src/Transfer/RightFooter.js b/packages/widgets/src/Transfer/RightFooter.js
similarity index 91%
rename from packages/core/src/Transfer/RightFooter.js
rename to packages/widgets/src/Transfer/RightFooter.js
index 29a03ff865..07cfcad483 100644
--- a/packages/core/src/Transfer/RightFooter.js
+++ b/packages/widgets/src/Transfer/RightFooter.js
@@ -3,7 +3,7 @@ import propTypes from '@dhis2/prop-types'
import { spacers } from '@dhis2/ui-constants'
-import { borderColor } from './common.js'
+import { borderColor } from './common/index.js'
export const RightFooter = ({ children, dataTest }) => (
diff --git a/packages/core/src/Transfer/RightSide.js b/packages/widgets/src/Transfer/RightSide.js
similarity index 92%
rename from packages/core/src/Transfer/RightSide.js
rename to packages/widgets/src/Transfer/RightSide.js
index df3ab4e5ef..b435577de2 100644
--- a/packages/core/src/Transfer/RightSide.js
+++ b/packages/widgets/src/Transfer/RightSide.js
@@ -1,7 +1,7 @@
import React from 'react'
import propTypes from '@dhis2/prop-types'
-import { borderColor, borderRadius } from './common.js'
+import { borderColor, borderRadius } from './common/index.js'
export const RightSide = ({ children, dataTest, width }) => (
diff --git a/packages/widgets/src/Transfer/SourceOptions.js b/packages/widgets/src/Transfer/SourceOptions.js
new file mode 100644
index 0000000000..bfdd24e7fd
--- /dev/null
+++ b/packages/widgets/src/Transfer/SourceOptions.js
@@ -0,0 +1,29 @@
+import React from 'react'
+import propTypes from '@dhis2/prop-types'
+
+import { spacers } from '@dhis2/ui-constants'
+
+export const SourceOptions = ({
+ children,
+ dataTest,
+ sourceEmptyPlaceholder,
+}) => (
+
+ {children}
+ {!React.Children.count(children) && sourceEmptyPlaceholder}
+
+
+
+)
+
+SourceOptions.propTypes = {
+ dataTest: propTypes.string.isRequired,
+ children: propTypes.node,
+ sourceEmptyPlaceholder: propTypes.node,
+}
diff --git a/packages/core/src/Transfer/Transfer.js b/packages/widgets/src/Transfer/Transfer.js
similarity index 69%
rename from packages/core/src/Transfer/Transfer.js
rename to packages/widgets/src/Transfer/Transfer.js
index 6f2b54c2a5..984dc4ebca 100644
--- a/packages/core/src/Transfer/Transfer.js
+++ b/packages/widgets/src/Transfer/Transfer.js
@@ -1,6 +1,4 @@
-import './types.js'
-
-import React, { Children, useState } from 'react'
+import React, { Fragment, useState } from 'react'
import propTypes from '@dhis2/prop-types'
import { Actions } from './Actions.js'
@@ -18,14 +16,13 @@ import { ReorderingActions } from './ReorderingActions.js'
import { RightFooter } from './RightFooter.js'
import { RightSide } from './RightSide.js'
import { SourceOptions } from './SourceOptions.js'
+import { TransferOption } from './TransferOption.js'
import {
addAllSelectableSourceOptions,
addIndividualSourceOptions,
createDoubleClickHandlers,
- extractPickedReactOptions,
defaultFilterCallback,
- filterOutOptions,
- getSubsetByFilter,
+ getOptionClickHandlers,
isReorderDownDisabled,
isReorderUpDisabled,
moveHighlightedPickedOptionDown,
@@ -33,17 +30,9 @@ import {
removeAllPickedOptions,
removeIndividualPickedOptions,
useHighlightedOptions,
-} from './helper/index.js'
-import { filterReactOptionsBy } from './helper/filterReactOptionsBy.js'
-
-// TODO: This will be refactored away to match the MultiSelect
-export const singleSelectedPropType = propTypes.shape({
- label: propTypes.string,
- value: propTypes.string,
-})
+} from './Transfer/index.js'
-export const multiSelectedPropType = propTypes.arrayOf(singleSelectedPropType)
-// ODOT
+const identity = value => value
/**
* @module
@@ -75,9 +64,9 @@ export const multiSelectedPropType = propTypes.arrayOf(singleSelectedPropType)
* rest of the library
*/
export const Transfer = ({
+ options,
onChange,
- children,
className,
dataTest,
disabled,
@@ -97,6 +86,7 @@ export const Transfer = ({
leftHeader,
maxSelections,
optionsWidth,
+ renderOption,
rightFooter,
searchTerm,
selected,
@@ -113,69 +103,78 @@ export const Transfer = ({
*/
const [internalFilter, setInternalFilter] = useState(initialSearchTerm)
const actualFilter = onFilterChange ? searchTerm : internalFilter
+ const actualFilterCallback = filterable ? filterCallback : identity
/*
- * These are all the not-selected option react elements.
- * It will replace all selected options with null
+ * Extract the not-selected options.
+ * Filters options if filterable is true.
*/
- const sourceOptions = filterOutOptions(children, selected)
- const filteredSourceOptions = getSubsetByFilter({
- reactOptions: sourceOptions,
- filter: actualFilter,
- filterable,
- filterCallback,
- })
+ const sourceOptions = actualFilterCallback(
+ options.filter(({ value }) => !selected.includes(value)),
+ actualFilter
+ )
/*
- * Extract the selected options. This way custom options are supported
- * without having to provide a component via the props
- *
- * Children are sorted by the order given in the "selected" array.
- * This is done in order to cover the "append newly selected items
- * at the end" feature/behavior.
+ * Extract the selected options. Can't use `options.filter`
+ * because we need to keep the order of `selected`
*/
- const pickedOptions = extractPickedReactOptions({
- reactOptions: children,
- selectedPlainOptions: selected,
- })
+ const pickedOptions = selected
+ .map(value => options.find(option => value === option.value))
+ // filter -> in case a selected value has been provided
+ // that does not exist as option
+ .filter(identity)
/*
- * These are all the highlighted option react elements on the options side.
+ * These are all the highlighted options on the options side.
*/
const {
highlightedOptions: highlightedSourceOptions,
setHighlightedOptions: setHighlightedSourceOptions,
toggleHighlightedOption: toggleHighlightedSourceOption,
} = useHighlightedOptions({
- reactOptions: filteredSourceOptions,
+ options: sourceOptions,
disabled,
maxSelections,
})
/*
- * These are all the highlighted option react elements on the selected side.
+ * These are all the highlighted options on the selected side.
*/
const {
highlightedOptions: highlightedPickedOptions,
setHighlightedOptions: setHighlightedPickedOptions,
toggleHighlightedOption: toggleHighlightedPickedOption,
} = useHighlightedOptions({
- reactOptions: pickedOptions,
+ options: pickedOptions,
disabled,
maxSelections,
})
+ /*
+ * These are the double click handlers for (de-)selection
+ */
const {
selectSingleOption,
deselectSingleOption,
} = createDoubleClickHandlers({
- selectedPlainOptions: selected,
+ selected,
setHighlightedSourceOptions,
setHighlightedPickedOptions,
onChange,
maxSelections,
})
+ /**
+ * Disabled button states
+ */
+ const isAddAllDisabled =
+ disabled ||
+ sourceOptions.filter(({ disabled }) => !disabled).length === 0
+ const isAddIndividualDisabled = disabled || !highlightedSourceOptions.length
+ const isRemoveAllDisabled = disabled || !selected.length
+ const isRemoveIndividualDisabled =
+ disabled || !highlightedPickedOptions.length
+
return (
@@ -202,13 +201,27 @@ export const Transfer = ({
- {filteredSourceOptions}
+ {sourceOptions.map(option => {
+ const highlighted = !!highlightedSourceOptions.find(
+ highlightedSourceOption =>
+ highlightedSourceOption === option.value
+ )
+
+ return (
+
+ {renderOption({
+ ...option,
+ ...getOptionClickHandlers(
+ option,
+ selectSingleOption,
+ toggleHighlightedSourceOption
+ ),
+ highlighted,
+ })}
+
+ )
+ })}
{leftFooter && (
@@ -223,19 +236,11 @@ export const Transfer = ({
!disabled,
- filteredSourceOptions
- )
- )
- }
+ disabled={isAddAllDisabled}
onClick={() =>
addAllSelectableSourceOptions({
- sourceReactOptions: filteredSourceOptions,
- selectedPlainOptions: selected,
+ sourceOptions,
+ selected,
onChange,
setHighlightedSourceOptions,
})
@@ -246,13 +251,13 @@ export const Transfer = ({
addIndividualSourceOptions({
filterable,
- filteredSourcePlainOptions: filteredSourceOptions,
- highlightedSourcePlainOptions: highlightedSourceOptions,
- selectedPlainOptions: selected,
+ sourceOptions,
+ highlightedSourceOptions,
+ selected,
maxSelections,
onChange,
setHighlightedSourceOptions,
@@ -264,7 +269,7 @@ export const Transfer = ({
removeAllPickedOptions({
setHighlightedPickedOptions,
@@ -277,12 +282,12 @@ export const Transfer = ({
removeIndividualPickedOptions({
- highlightedPickedReactOptions: highlightedPickedOptions,
+ highlightedPickedOptions,
onChange,
- selectedPlainOptions: selected,
+ selected,
setHighlightedPickedOptions,
})
}
@@ -293,13 +298,26 @@ export const Transfer = ({
- {pickedOptions}
+ {pickedOptions.map(option => {
+ const highlighted = !!highlightedPickedOptions.find(
+ value => option.value === value
+ )
+
+ return (
+
+ {renderOption({
+ ...option,
+ ...getOptionClickHandlers(
+ option,
+ deselectSingleOption,
+ toggleHighlightedPickedOption
+ ),
+ highlighted,
+ })}
+
+ )
+ })}
{(rightFooter || enableOrderChange) && (
@@ -308,24 +326,24 @@ export const Transfer = ({
moveHighlightedPickedOptionUp({
- selectedPlainOptions: selected,
- highlightedPickedPlainOptions: highlightedPickedOptions,
+ selected,
+ highlightedPickedOptions,
onChange,
})
}
onChangeDown={() => {
moveHighlightedPickedOptionDown({
- selectedPlainOptions: selected,
- highlightedPickedPlainOptions: highlightedPickedOptions,
+ selected,
+ highlightedPickedOptions,
onChange,
})
}}
@@ -340,14 +358,17 @@ export const Transfer = ({
)
}
+const defaultRenderOption = option =>
+
Transfer.defaultProps = {
dataTest: 'dhis2-uicore-transfer',
- initialSearchTerm: '',
- selected: [],
height: '240px',
+ initialSearchTerm: '',
+ maxSelections: Infinity,
optionsWidth: '320px',
+ renderOption: defaultRenderOption,
+ selected: [],
selectedWidth: '320px',
- maxSelections: Infinity,
filterCallback: defaultFilterCallback,
}
@@ -378,16 +399,22 @@ Transfer.defaultProps = {
* @prop {string} [removeIndividualText]
* @prop {Node} [rightFooter]
* @prop {string} [searchTerm]
- * @prop {Option|Option[]} selected
+ * @prop {string[]} selected
* @prop {string} [selectedWidth]
* @prop {Function} [onFilterChange]
*/
Transfer.propTypes = {
+ options: propTypes.arrayOf(
+ propTypes.shape({
+ label: propTypes.string.isRequired,
+ value: propTypes.string.isRequired,
+ disabled: propTypes.bool,
+ })
+ ).isRequired,
onChange: propTypes.func.isRequired,
addAllText: propTypes.string,
addIndividualText: propTypes.string,
- children: propTypes.node,
className: propTypes.string,
dataTest: propTypes.string,
disabled: propTypes.bool,
@@ -404,12 +431,10 @@ Transfer.propTypes = {
optionsWidth: propTypes.string,
removeAllText: propTypes.string,
removeIndividualText: propTypes.string,
+ renderOption: propTypes.func,
rightFooter: propTypes.node,
searchTerm: propTypes.string,
- selected: propTypes.oneOfType([
- singleSelectedPropType,
- multiSelectedPropType,
- ]),
+ selected: propTypes.arrayOf(propTypes.string),
selectedEmptyComponent: propTypes.node,
selectedWidth: propTypes.string,
sourceEmptyPlaceholder: propTypes.node,
diff --git a/packages/core/src/Transfer/Transfer.stories.js b/packages/widgets/src/Transfer/Transfer.stories.js
similarity index 50%
rename from packages/core/src/Transfer/Transfer.stories.js
rename to packages/widgets/src/Transfer/Transfer.stories.js
index dc75d78db2..693e1c7439 100644
--- a/packages/core/src/Transfer/Transfer.stories.js
+++ b/packages/widgets/src/Transfer/Transfer.stories.js
@@ -1,21 +1,13 @@
/* eslint-disable react/prop-types */
+import { SingleSelectOption, Tab, TabBar } from '@dhis2/ui-core'
import React, { useState } from 'react'
-import {
- Field,
- SingleSelect,
- SingleSelectOption,
- Tab,
- TabBar,
- Transfer,
- TransferOption,
-} from '../index.js'
+import { SingleSelectField, Transfer, TransferOption } from '../index.js'
-export default { title: 'Transfer' }
+export default { title: 'Components/widgets/Transfer' }
const StatefulWrapper = ({ children, initialState }) => {
- const initialSelected = initialState.map(child => child.props)
- const [selected, setSelected] = useState(initialSelected)
+ const [selected, setSelected] = useState(initialState)
return React.Children.map(children, child =>
React.cloneElement(child, {
@@ -30,116 +22,96 @@ StatefulWrapper.defaultProps = {
}
const options = [
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
- ,
+ {
+ label: 'ANC 1st visit',
+ value: 'anc_1st_visit',
+ },
+ {
+ label: 'ANC 2nd visit',
+ value: 'anc_2nd_visit',
+ },
+ {
+ label: 'ANC 3rd visit',
+ value: 'anc_3rd_visit',
+ },
+ {
+ label: 'ANC 4th or more visits',
+ value: 'anc_4th_or_more_visits',
+ },
+ {
+ label: 'ARI treated with antibiotics (pneumonia) follow-up',
+ value: 'ari_treated_with_antibiotics_(pneumonia)_follow-up',
+ },
+ {
+ label: 'ARI treated with antibiotics (pneumonia) new',
+ value: 'ari_treated_with_antibiotics_(pneumonia)_new',
+ },
+ {
+ label: 'ARI treated with antibiotics (pneumonia) referrals',
+ value: 'ari_treated_with_antibiotics_(pneumonia)_referrals',
+ },
+ {
+ label: 'ARI treated without antibiotics (cough) follow-up',
+ value: 'ari_treated_without_antibiotics_(cough)_follow-up',
+ },
+ {
+ label: 'ARI treated without antibiotics (cough) new',
+ value: 'ari_treated_without_antibiotics_(cough)_new',
+ },
+ {
+ label: 'ARI treated without antibiotics (cough) referrals',
+ value: 'ari_treated_without_antibiotics_(cough)_referrals',
+ },
+ {
+ label: 'ART No clients who stopped TRT due to TRT failure',
+ value: 'art_no_clients_who_stopped_trt_due_to_trt_failure',
+ },
+ {
+ label:
+ 'ART No clients who stopped TRT due to adverse clinical status/event',
+ value:
+ 'art_no_clients_who_stopped_trt_due_to_adverse_clinical_status/event',
+ },
+ {
+ label: 'ART No clients with change of regimen due to drug toxicity',
+ value: 'art_no_clients_with_change_of_regimen_due_to_drug_toxicity',
+ },
+ {
+ label: 'ART No clients with new adverse drug reaction',
+ value: 'art_no_clients_with_new_adverse_drug_reaction',
+ },
+ {
+ label: 'ART No started Opportunist Infection prophylaxis',
+ value: 'art_no_started_opportunist_infection_prophylaxis',
+ },
+ {
+ label: 'ART clients with new adverse clinical event',
+ value: 'art_clients_with_new_adverse_clinical_event',
+ },
+ {
+ label: 'ART defaulters',
+ value: 'art_defaulters',
+ },
+ {
+ label: 'ART enrollment stage 1',
+ value: 'art_enrollment_stage_1',
+ },
+ {
+ label: 'ART enrollment stage 2',
+ value: 'art_enrollment_stage_2',
+ },
+ {
+ label: 'ART enrollment stage 3',
+ value: 'art_enrollment_stage_3',
+ },
+ {
+ label: 'ART enrollment stage 4',
+ value: 'art_enrollment_stage_4',
+ },
+ {
+ label: 'ART entry point: No PMTCT',
+ value: 'art_entry_point:_no_pmtct',
+ },
]
export const SingleSelection = () => (
@@ -147,17 +119,17 @@ export const SingleSelection = () => (
console.log('Will be overriden')}
- >
- {options}
-
+ options={options}
+ />
)
export const Multiple = () => (
- console.log('Will be overriden')}>
- {options}
-
+ console.log('Will be overriden')}
+ options={options.slice(0, 3)}
+ />
)
@@ -166,9 +138,8 @@ export const Header = () => (
console.log('Will be overriden')}
leftHeader={Header on the left side
}
- >
- {options}
-
+ options={options}
+ />
)
@@ -188,9 +159,8 @@ export const OptionsFooter = () => (
Reload list
}
- >
- {options}
-
+ options={options}
+ />
)
@@ -201,13 +171,12 @@ export const Filtered = () => (
onChange={() => console.log('Will be overriden by StatefulWrapper')}
initialSearchTerm="ANC"
leftHeader={Header on the left side
}
- >
- {options}
-
+ options={options}
+ />
)
-const CustomOption = ({ label, value, onClick, highlighted }) => (
+const renderOption = ({ label, value, onClick, highlighted }) => (
onClick({ label, value }, event)}
style={{ background: highlighted ? 'green' : 'blue' }}
@@ -220,7 +189,7 @@ export const CustomListOptions = () => (
<>
Custom option code:
- {`const CustomOption = ({ label, value, onClick, highlighted }) => (
+ {`const renderOption = ({ label, value, onClick, highlighted }) => (
onClick({ label, value }, event)}
style={{ background: highlighted ? 'green' : 'blue' }}
@@ -234,19 +203,33 @@ export const CustomListOptions = () => (
onChange={() =>
console.log('Will be overriden by StatefulWrapper')
}
- optionsComponent={CustomOption}
- >
-
-
-
-
-
-
-
+ renderOption={renderOption}
+ options={options}
+ />
>
)
+export const IndividualCustomOption = () => (
+
+ console.log('Will be overriden')}
+ addAllText="Add all"
+ addIndividualText="Add individual"
+ removeAllText="Remove all"
+ removeIndividualText="Remove individual"
+ renderOption={args => {
+ if (args.option.value === options[0].value) {
+ return renderOption(args)
+ }
+
+ return
+ }}
+ options={options}
+ />
+
+)
+
export const CustomButtonText = () => (
(
addIndividualText="Add individual"
removeAllText="Remove all"
removeIndividualText="Remove individual"
- >
- {options}
-
+ options={options}
+ />
)
export const SourceEmptyPlaceholder = () => (
console.log('Will be overriden')}
+ options={[]}
sourceEmptyPlaceholder={
No options found.
@@ -285,16 +268,19 @@ export const PickedEmptyComponent = () => (
}
- >
- {options}
-
+ options={options}
+ />
)
export const Reordering = () => (
-
- null}>
- {options.slice(0, 4)}
-
+ value)}
+ >
+ null}
+ options={options.slice(0, 4)}
+ />
)
@@ -309,9 +295,8 @@ export const IncreasedOptionsHeight = () => (
}
height="400px"
leftHeader={Header on the left side
}
- >
- {options}
-
+ options={options}
+ />
)
@@ -325,34 +310,23 @@ export const DifferentWidths = () => (
leftHeader={
Header on the left side
}
optionsWidth="500px"
selectedWidth="240px"
- >
- {options}
-
+ options={options}
+ />
)
const createCustomFilteringInHeader = hideFilterInput => {
- const relativePeriods = React.Children.map(
- options.slice(0, 10),
- (child, index) =>
- React.cloneElement(child, {
- additionalData: {
- relativePeriod: true,
- year: index < 5 ? '2020' : '2019',
- },
- })
- )
-
- const fixedPeriods = React.Children.map(
- options.slice(10, 20),
- (child, index) =>
- React.cloneElement(child, {
- additionalData: {
- relativePeriod: false,
- year: index < 5 ? '2020' : '2019',
- },
- })
- )
+ const relativePeriods = options.slice(0, 10).map((option, index) => ({
+ ...option,
+ relativePeriod: true,
+ year: index < 5 ? '2020' : '2019',
+ }))
+
+ const fixedPeriods = options.slice(10, 20).map((option, index) => ({
+ ...option,
+ relativePeriod: false,
+ year: index < 5 ? '2020' : '2019',
+ }))
const allOptions = [...relativePeriods, ...fixedPeriods]
@@ -381,25 +355,24 @@ const createCustomFilteringInHeader = hideFilterInput => {
-
-
-
-
-
-
+
+
+
+
>
)
const CustomTransfer = props => {
const [filter, setFilter] = useState('')
const [relativePeriod, setRelativePeriod] = useState(true)
- const [year, setYear] = useState({ label: '2020', value: '2020' })
+ const [year, setYear] = useState('2020')
const filterCallback = (options, filter) => {
const optionsWithYear = options.filter(
- option => option.year === year.value
+ option => option.year === year
)
const optionsWithPeriod = optionsWithYear.filter(
@@ -442,7 +415,7 @@ const createCustomFilteringInHeader = hideFilterInput => {
// eslint-disable-next-line react/display-name
return () => (
- {allOptions}
+
)
}
diff --git a/packages/core/src/Transfer/helper/addAllSelectableSourceOptions.js b/packages/widgets/src/Transfer/Transfer/addAllSelectableSourceOptions.js
similarity index 54%
rename from packages/core/src/Transfer/helper/addAllSelectableSourceOptions.js
rename to packages/widgets/src/Transfer/Transfer/addAllSelectableSourceOptions.js
index a5a23d495a..55735e3517 100644
--- a/packages/core/src/Transfer/helper/addAllSelectableSourceOptions.js
+++ b/packages/widgets/src/Transfer/Transfer/addAllSelectableSourceOptions.js
@@ -1,26 +1,27 @@
-import { addOption, toggleOptions } from '../common'
-import { getPlainOptionsFromReactOptions } from './getPlainOptionsFromReactOptions'
-
/**
* @param {Object} args
- * @param {ReactElement} args.sourceReactOptions
- * @param {Option[]} args.selectedPlainOptions
+ * @param {Object[]} args.sourceOptions
+ * @param {string[]} args.selected
* @param {Function} args.onChange
* @param {Function} arg.setHighlightedSourceOptions
* @returns {void}
*/
export const addAllSelectableSourceOptions = ({
- sourceReactOptions,
+ sourceOptions,
onChange,
- selectedPlainOptions,
+ selected,
setHighlightedSourceOptions,
}) => {
- const all = getPlainOptionsFromReactOptions(sourceReactOptions)
- const allEnabled = all.filter(({ disabled }) => !disabled)
- const newSelected = toggleOptions(
- selectedPlainOptions,
- allEnabled,
- addOption
+ const enabledSourceOptions = sourceOptions.filter(
+ ({ disabled }) => !disabled
+ )
+
+ const newSelected = enabledSourceOptions.reduce(
+ (accumulatedSelected, enabledSourceOption) => [
+ ...accumulatedSelected,
+ enabledSourceOption.value,
+ ],
+ selected
)
setHighlightedSourceOptions([])
diff --git a/packages/core/src/Transfer/helper/addIndividualSourceOptions.js b/packages/widgets/src/Transfer/Transfer/addIndividualSourceOptions.js
similarity index 60%
rename from packages/core/src/Transfer/helper/addIndividualSourceOptions.js
rename to packages/widgets/src/Transfer/Transfer/addIndividualSourceOptions.js
index 404a38c9f3..52f187298d 100644
--- a/packages/core/src/Transfer/helper/addIndividualSourceOptions.js
+++ b/packages/widgets/src/Transfer/Transfer/addIndividualSourceOptions.js
@@ -1,23 +1,20 @@
-import { Children } from 'react'
-import { addOption, isOption, toggleOptions } from '../common'
-
/**
* @param {Object} args
* @param {bool} args.filterable
- * @param {ReactElement} args.filteredSourcePlainOptions
- * @param {Option[]} args.highlightedSourcePlainOptions
+ * @param {Object[]} args.sourceOptions
+ * @param {string[]} args.highlightedSourceOptions
+ * @param {string[]} args.selected
* @param {Function} args.onChange
- * @param {Option[]} args.selectedPlainOptions
* @param {Function} args.setHighlightedSourceOptions
* @returns void
*/
export const addIndividualSourceOptions = ({
filterable,
- filteredSourcePlainOptions,
- highlightedSourcePlainOptions,
+ sourceOptions,
+ highlightedSourceOptions,
maxSelections,
onChange,
- selectedPlainOptions,
+ selected,
setHighlightedSourceOptions,
}) => {
/**
@@ -32,17 +29,22 @@ export const addIndividualSourceOptions = ({
* clicks the "add individuals" button
*/
const filteredHighlightedSourceOptions = filterable
- ? highlightedSourcePlainOptions.filter(option =>
- Children.toArray(filteredSourcePlainOptions)
- .map(({ props }) => props)
- .find(filteredOption => isOption(filteredOption, option))
+ ? highlightedSourceOptions.filter(value =>
+ sourceOptions.find(
+ filteredOption => filteredOption.value === value
+ )
)
- : highlightedSourcePlainOptions
+ : highlightedSourceOptions
- const newSelected = toggleOptions(
- selectedPlainOptions,
- filteredHighlightedSourceOptions,
- addOption
+ const newSelected = filteredHighlightedSourceOptions.reduce(
+ (accumulatedSelected, value) => [
+ ...accumulatedSelected,
+ filteredHighlightedSourceOptions.find(
+ filteredHighlightedSourceOption =>
+ filteredHighlightedSourceOption === value
+ ),
+ ],
+ selected
)
setHighlightedSourceOptions([])
diff --git a/packages/core/src/Transfer/helper/createDoubleClickHandlers.js b/packages/widgets/src/Transfer/Transfer/createDoubleClickHandlers.js
similarity index 64%
rename from packages/core/src/Transfer/helper/createDoubleClickHandlers.js
rename to packages/widgets/src/Transfer/Transfer/createDoubleClickHandlers.js
index 37637e6e33..c5b7898b59 100644
--- a/packages/core/src/Transfer/helper/createDoubleClickHandlers.js
+++ b/packages/widgets/src/Transfer/Transfer/createDoubleClickHandlers.js
@@ -1,10 +1,8 @@
-import { addOption, removeOption } from '../common'
-
/**
* @param {Object} args
* @param {number} args.maxSelections
+ * @param {string[]} args.selected
* @param {Function} args.onChange
- * @param {Option[]} args.selectedPlainOptions
* @param {Function} args.setHighlightedSourceOptions
* @param {Function} args.setHighlightedPickedOptions
* @returns void
@@ -12,18 +10,24 @@ import { addOption, removeOption } from '../common'
export const createDoubleClickHandlers = ({
maxSelections,
onChange,
- selectedPlainOptions,
+ selected,
setHighlightedPickedOptions,
setHighlightedSourceOptions,
}) => {
- const selectSingleOption = ({ option }) => {
- const newSelected = addOption(selectedPlainOptions, option)
+ const selectSingleOption = ({ value }) => {
+ const newSelected = selected.includes(value)
+ ? selected
+ : [...selected, value]
+
setHighlightedSourceOptions([])
onChange({ selected: newSelected.slice(-1 * maxSelections) })
}
- const deselectSingleOption = ({ option }) => {
- const newSelected = removeOption(selectedPlainOptions, option)
+ const deselectSingleOption = ({ value }) => {
+ const newSelected = selected.filter(
+ curSelected => curSelected !== value
+ )
+
setHighlightedPickedOptions([])
onChange({ selected: newSelected })
}
diff --git a/packages/widgets/src/Transfer/Transfer/defaultFilterCallback.js b/packages/widgets/src/Transfer/Transfer/defaultFilterCallback.js
new file mode 100644
index 0000000000..c895f141d2
--- /dev/null
+++ b/packages/widgets/src/Transfer/Transfer/defaultFilterCallback.js
@@ -0,0 +1,9 @@
+/**
+ * @param {Object[]} options
+ * @param {string} filter
+ * @returns {Object[]}
+ */
+export const defaultFilterCallback = (options, filter) =>
+ filter === ''
+ ? options
+ : options.filter(({ label }) => label.match(new RegExp(filter, 'i')))
diff --git a/packages/widgets/src/Transfer/Transfer/getOptionClickHandlers.js b/packages/widgets/src/Transfer/Transfer/getOptionClickHandlers.js
new file mode 100644
index 0000000000..5ee5de09a1
--- /dev/null
+++ b/packages/widgets/src/Transfer/Transfer/getOptionClickHandlers.js
@@ -0,0 +1,19 @@
+import { getModeByModifierKey } from '../common/index.js'
+
+/**
+ * @param {Object} option
+ * @param {Function} selectionHandler
+ * @param {Function} toggleHighlightedOption
+ * @returns {Object}
+ */
+export const getOptionClickHandlers = (
+ option,
+ selectionHandler,
+ toggleHighlightedOption
+) => ({
+ onClick: (_, event) => {
+ const mode = getModeByModifierKey(event)
+ toggleHighlightedOption({ option, mode })
+ },
+ onDoubleClick: selectionHandler,
+})
diff --git a/packages/core/src/Transfer/helper/index.js b/packages/widgets/src/Transfer/Transfer/index.js
similarity index 74%
rename from packages/core/src/Transfer/helper/index.js
rename to packages/widgets/src/Transfer/Transfer/index.js
index 1f8f66c186..8e7e3662f8 100644
--- a/packages/core/src/Transfer/helper/index.js
+++ b/packages/widgets/src/Transfer/Transfer/index.js
@@ -1,11 +1,8 @@
export * from './addAllSelectableSourceOptions.js'
export * from './addIndividualSourceOptions.js'
export * from './createDoubleClickHandlers.js'
-export * from './extractPickedReactOptions.js'
export * from './defaultFilterCallback.js'
-export * from './filterOutOptions.js'
-export * from './getPlainOptionsFromReactOptions.js'
-export * from './getSubsetByFilter.js'
+export * from './getOptionClickHandlers.js'
export * from './isReorderDownDisabled.js'
export * from './isReorderUpDisabled.js'
export * from './moveHighlightedPickedOptionDown.js'
diff --git a/packages/widgets/src/Transfer/Transfer/isReorderDownDisabled.js b/packages/widgets/src/Transfer/Transfer/isReorderDownDisabled.js
new file mode 100644
index 0000000000..10f1042db6
--- /dev/null
+++ b/packages/widgets/src/Transfer/Transfer/isReorderDownDisabled.js
@@ -0,0 +1,11 @@
+/**
+ * @param {Object} args
+ * @param {string} args.highlightedPickedOptions
+ * @param {string[]} args.selected
+ * @returns {bool}
+ */
+export const isReorderDownDisabled = ({ highlightedPickedOptions, selected }) =>
+ // only one item can be moved with the buttons
+ highlightedPickedOptions.length !== 1 ||
+ // can't move an item down if it's the last one
+ selected.indexOf(highlightedPickedOptions[0]) === selected.length - 1
diff --git a/packages/widgets/src/Transfer/Transfer/isReorderUpDisabled.js b/packages/widgets/src/Transfer/Transfer/isReorderUpDisabled.js
new file mode 100644
index 0000000000..9386ac169e
--- /dev/null
+++ b/packages/widgets/src/Transfer/Transfer/isReorderUpDisabled.js
@@ -0,0 +1,11 @@
+/**
+ * @param {Object} args
+ * @param {string} args.highlightedPickedOptions
+ * @param {string[]} args.selected
+ * @returns {bool}
+ */
+export const isReorderUpDisabled = ({ highlightedPickedOptions, selected }) =>
+ // only one item can be moved with the buttons
+ highlightedPickedOptions.length !== 1 ||
+ // can't move an item up if it's the first one
+ selected.indexOf(highlightedPickedOptions[0]) === 0
diff --git a/packages/widgets/src/Transfer/Transfer/moveHighlightedPickedOptionDown.js b/packages/widgets/src/Transfer/Transfer/moveHighlightedPickedOptionDown.js
new file mode 100644
index 0000000000..eb015b392e
--- /dev/null
+++ b/packages/widgets/src/Transfer/Transfer/moveHighlightedPickedOptionDown.js
@@ -0,0 +1,29 @@
+/**
+ * @param {Object} args
+ * @param {string[]} args.selected
+ * @param {string[]} args.highlightedPickedOptions
+ * @param {Function} args.onChange
+ * @returns {void}
+ */
+export const moveHighlightedPickedOptionDown = ({
+ selected,
+ highlightedPickedOptions,
+ onChange,
+}) => {
+ const optionIndex = selected.findIndex(
+ selectedOption => selectedOption === highlightedPickedOptions[0]
+ )
+
+ // Can't move down last or non-existing option
+ if (optionIndex === -1 || optionIndex > selected.length - 2) return
+
+ // swap with next item
+ const reordered = [
+ ...selected.slice(0, optionIndex),
+ selected[optionIndex + 1],
+ selected[optionIndex],
+ ...selected.slice(optionIndex + 2),
+ ]
+
+ onChange({ selected: reordered })
+}
diff --git a/packages/widgets/src/Transfer/Transfer/moveHighlightedPickedOptionUp.js b/packages/widgets/src/Transfer/Transfer/moveHighlightedPickedOptionUp.js
new file mode 100644
index 0000000000..44611779ca
--- /dev/null
+++ b/packages/widgets/src/Transfer/Transfer/moveHighlightedPickedOptionUp.js
@@ -0,0 +1,29 @@
+/**
+ * @param {Object} args
+ * @param {string[]} args.selected
+ * @param {string[]} args.highlightedPickedOptions
+ * @param {Function} args.onChange
+ * @returns {void}
+ */
+export const moveHighlightedPickedOptionUp = ({
+ selected,
+ highlightedPickedOptions,
+ onChange,
+}) => {
+ const optionIndex = selected.findIndex(
+ selectedOption => selectedOption === highlightedPickedOptions[0]
+ )
+
+ // Can't move up option at index 0 or non-existing option
+ if (optionIndex < 1) return
+
+ // swap with previous item
+ const reordered = [
+ ...selected.slice(0, optionIndex - 1),
+ selected[optionIndex],
+ selected[optionIndex - 1],
+ ...selected.slice(optionIndex + 1),
+ ]
+
+ onChange({ selected: reordered })
+}
diff --git a/packages/core/src/Transfer/helper/removeAllPickedOptions.js b/packages/widgets/src/Transfer/Transfer/removeAllPickedOptions.js
similarity index 100%
rename from packages/core/src/Transfer/helper/removeAllPickedOptions.js
rename to packages/widgets/src/Transfer/Transfer/removeAllPickedOptions.js
diff --git a/packages/core/src/Transfer/helper/removeIndividualPickedOptions.js b/packages/widgets/src/Transfer/Transfer/removeIndividualPickedOptions.js
similarity index 58%
rename from packages/core/src/Transfer/helper/removeIndividualPickedOptions.js
rename to packages/widgets/src/Transfer/Transfer/removeIndividualPickedOptions.js
index 90b6a022cc..d5462487b8 100644
--- a/packages/core/src/Transfer/helper/removeIndividualPickedOptions.js
+++ b/packages/widgets/src/Transfer/Transfer/removeIndividualPickedOptions.js
@@ -1,23 +1,19 @@
-import { removeOption, toggleOptions } from '../common'
-
/**
* @param {Object} args
- * @param {ReactElement} args.highlightedPickedReactOptions
+ * @param {string[]} args.highlightedPickedOptions
+ * @param {string[]} args.selected
* @param {Function} args.setHighlightedPickedOptions
- * @param {Option[]} args.selectedPlainOptions
* @param {Function} args.onChange
* @returns {void}
*/
export const removeIndividualPickedOptions = ({
- highlightedPickedReactOptions,
+ highlightedPickedOptions,
onChange,
- selectedPlainOptions,
+ selected,
setHighlightedPickedOptions,
}) => {
- const newSelected = toggleOptions(
- selectedPlainOptions,
- highlightedPickedReactOptions,
- removeOption
+ const newSelected = selected.filter(
+ selectedOption => !highlightedPickedOptions.includes(selectedOption)
)
setHighlightedPickedOptions([])
diff --git a/packages/core/src/Transfer/helper/useHighlightedOptions.js b/packages/widgets/src/Transfer/Transfer/useHighlightedOptions.js
similarity index 79%
rename from packages/core/src/Transfer/helper/useHighlightedOptions.js
rename to packages/widgets/src/Transfer/Transfer/useHighlightedOptions.js
index d4a3d18aae..90175adc1a 100644
--- a/packages/core/src/Transfer/helper/useHighlightedOptions.js
+++ b/packages/widgets/src/Transfer/Transfer/useHighlightedOptions.js
@@ -1,21 +1,15 @@
-import '../types.js'
-
import { useState } from 'react'
-import { createToggleHighlightedOption } from './useHighlightedOptions/createToggleHighlightedOption'
+import { createToggleHighlightedOption } from './useHighlightedOptions/createToggleHighlightedOption.js'
/**
* @param {Object} args
* @param {bool} args.disabled
* @param {number} args.maxSelection
- * @param {ReactElement} args.reactOptions
+ * @param {Object[]} args.options
* @returns {Object} highlighted options & helpers
*/
-export const useHighlightedOptions = ({
- disabled,
- maxSelections,
- reactOptions,
-}) => {
+export const useHighlightedOptions = ({ disabled, maxSelections, options }) => {
/**
* These are important so the stored element can be used
* as range-start when using shift multiple times consecutively
@@ -29,7 +23,7 @@ export const useHighlightedOptions = ({
setHighlightedOptions,
maxSelections,
setLastClicked,
- reactOptions,
+ options,
lastClicked,
})
diff --git a/packages/core/src/Transfer/helper/useHighlightedOptions/createToggleHighlightedOption.js b/packages/widgets/src/Transfer/Transfer/useHighlightedOptions/createToggleHighlightedOption.js
similarity index 55%
rename from packages/core/src/Transfer/helper/useHighlightedOptions/createToggleHighlightedOption.js
rename to packages/widgets/src/Transfer/Transfer/useHighlightedOptions/createToggleHighlightedOption.js
index 153eeae2b7..fc2ceba8e3 100644
--- a/packages/core/src/Transfer/helper/useHighlightedOptions/createToggleHighlightedOption.js
+++ b/packages/widgets/src/Transfer/Transfer/useHighlightedOptions/createToggleHighlightedOption.js
@@ -1,15 +1,26 @@
-import { ADD_MODE, RANGE_MODE } from '../../common'
-import { toggleAdd } from './toggleAdd'
-import { toggleRange } from './toggleRange'
-import { toggleReplace } from './toggleReplace'
+import { ADD_MODE, RANGE_MODE } from '../../common/index.js'
+import { toggleAdd } from './toggleAdd.js'
+import { toggleRange } from './toggleRange.js'
+import { toggleReplace } from './toggleReplace.js'
+/**
+ * @param {Object} args
+ * @param {bool} args.disabled
+ * @param {string[]} args.highlightedOptions
+ * @param {Function} args.setHighlightedOptions
+ * @param {number} args.maxSelections
+ * @param {Function} args.setLastClicked
+ * @param {Object[]} args.options
+ * @param {string} args.lastClicked
+ * @returns {void}
+ */
export const createToggleHighlightedOption = ({
disabled,
highlightedOptions,
setHighlightedOptions,
maxSelections,
setLastClicked,
- reactOptions,
+ options,
lastClicked,
}) => ({ option, mode }) => {
if (disabled) return
@@ -17,7 +28,7 @@ export const createToggleHighlightedOption = ({
setHighlightedOptions([])
if (mode === ADD_MODE) {
- setLastClicked(option)
+ setLastClicked(option.value)
return toggleAdd({
highlightedOptions,
@@ -30,7 +41,7 @@ export const createToggleHighlightedOption = ({
if (mode === RANGE_MODE) {
return toggleRange({
highlightedOptions,
- reactOptions,
+ options,
option,
setHighlightedOptions,
lastClicked,
@@ -39,7 +50,7 @@ export const createToggleHighlightedOption = ({
}
// REPLACE_MODE
- setLastClicked(option)
+ setLastClicked(option.value)
return toggleReplace({
option,
diff --git a/packages/widgets/src/Transfer/Transfer/useHighlightedOptions/toggleAdd.js b/packages/widgets/src/Transfer/Transfer/useHighlightedOptions/toggleAdd.js
new file mode 100644
index 0000000000..30e7f086c6
--- /dev/null
+++ b/packages/widgets/src/Transfer/Transfer/useHighlightedOptions/toggleAdd.js
@@ -0,0 +1,20 @@
+import { toggleValue } from '../../common'
+
+/**
+ * @param {Object} args
+ * @param {number} args.maxSelections
+ * @param {string[]} args.highlightedOptions
+ * @param {Object} args.option
+ * @param {Function} args.setHighlightedOption
+ * @returns {void}
+ */
+export const toggleAdd = ({
+ highlightedOptions,
+ maxSelections,
+ option,
+ setHighlightedOptions,
+}) => {
+ const afterToggled = toggleValue(highlightedOptions, option.value)
+ const capped = afterToggled.slice(-1 * maxSelections)
+ setHighlightedOptions(capped)
+}
diff --git a/packages/core/src/Transfer/helper/useHighlightedOptions/toggleRange.js b/packages/widgets/src/Transfer/Transfer/useHighlightedOptions/toggleRange.js
similarity index 72%
rename from packages/core/src/Transfer/helper/useHighlightedOptions/toggleRange.js
rename to packages/widgets/src/Transfer/Transfer/useHighlightedOptions/toggleRange.js
index 0db1b82fb6..415a2ac4e6 100644
--- a/packages/core/src/Transfer/helper/useHighlightedOptions/toggleRange.js
+++ b/packages/widgets/src/Transfer/Transfer/useHighlightedOptions/toggleRange.js
@@ -1,34 +1,31 @@
-import '../../types.js'
-import { findOption, findOptionIndex } from '../../common'
-import { getPlainOptionsFromReactOptions } from '../getPlainOptionsFromReactOptions'
+import { findOptionIndex } from '../../common/index.js'
/**
* @param {Object} args
- * @param {Option[]} args.highlightedOptions
- * @param {ReactElement} args.reactOptions
- * @param {Option} args.option
- * @param {Function} args.setHighlightedOption
* @param {number} args.maxSelections
- * @param {Option} args.lastClicked
+ * @param {string[]} args.highlightedOptions
+ * @param {Object[]} args.options
+ * @param {Object} args.option
+ * @param {string} args.lastClicked
+ * @param {Function} args.setHighlightedOption
* @returns {void}
*/
export const toggleRange = ({
highlightedOptions,
- reactOptions,
+ options,
option,
setHighlightedOptions,
lastClicked,
maxSelections,
}) => {
if (highlightedOptions.length === 0) {
- setHighlightedOptions([option])
+ setHighlightedOptions([option.value])
} else {
let from, to
- const options = getPlainOptionsFromReactOptions(reactOptions)
const clickedOptionIndex = findOptionIndex(options, option)
const lastClickedSourceOptionWithoutRangeModeIndex = lastClicked
- ? findOptionIndex(options, lastClicked)
+ ? options.findIndex(curOption => curOption.value === lastClicked)
: -1
if (lastClickedSourceOptionWithoutRangeModeIndex !== -1) {
@@ -39,7 +36,9 @@ export const toggleRange = ({
* A filter-change has removed the most recently highlighted option
*/
const firstHighlightedInList = options.findIndex(option =>
- findOption(highlightedOptions, option)
+ highlightedOptions.find(
+ highlightedOption => highlightedOption === option.value
+ )
)
from = firstHighlightedInList
@@ -55,6 +54,7 @@ export const toggleRange = ({
.slice(lower, higher + 1)
.filter(option => !option.disabled)
.slice(maxSelections * -1)
+ .map(({ value }) => value)
setHighlightedOptions(newHighlightedSourceOptions)
}
diff --git a/packages/widgets/src/Transfer/Transfer/useHighlightedOptions/toggleReplace.js b/packages/widgets/src/Transfer/Transfer/useHighlightedOptions/toggleReplace.js
new file mode 100644
index 0000000000..9e676e1119
--- /dev/null
+++ b/packages/widgets/src/Transfer/Transfer/useHighlightedOptions/toggleReplace.js
@@ -0,0 +1,26 @@
+/**
+ * @param {Object} args
+ * @param {string[]} args.highlightedOptions
+ * @param {Object} args.option
+ * @param {Function} args.setHighlightedOption
+ * @returns {void}
+ */
+export const toggleReplace = ({
+ option,
+ highlightedOptions,
+ setHighlightedOptions,
+}) => {
+ if (highlightedOptions.length > 1) {
+ setHighlightedOptions([option.value])
+ } else {
+ const optionIndex = highlightedOptions.findIndex(
+ highlightedOption => highlightedOption === option.value
+ )
+
+ if (optionIndex === -1) {
+ setHighlightedOptions([option.value])
+ } else {
+ setHighlightedOptions([])
+ }
+ }
+}
diff --git a/packages/core/src/Transfer/TransferOption.js b/packages/widgets/src/Transfer/TransferOption.js
similarity index 92%
rename from packages/core/src/Transfer/TransferOption.js
rename to packages/widgets/src/Transfer/TransferOption.js
index dcb4379fda..0c0d7c4860 100644
--- a/packages/core/src/Transfer/TransferOption.js
+++ b/packages/widgets/src/Transfer/TransferOption.js
@@ -20,12 +20,11 @@ export const TransferOption = ({
className,
disabled,
dataTest,
- label,
highlighted,
onClick,
onDoubleClick,
+ label,
value,
- additionalData,
}) => {
const doubleClickTimeout = useRef(null)
@@ -35,20 +34,18 @@ export const TransferOption = ({
onClick={event => {
if (disabled) return
- const option = { label, value, ...additionalData }
-
if (doubleClickTimeout.current) {
clearTimeout(doubleClickTimeout.current)
doubleClickTimeout.current = null
- onDoubleClick({ option }, event)
+ onDoubleClick({ value }, event)
} else {
doubleClickTimeout.current = setTimeout(() => {
clearTimeout(doubleClickTimeout.current)
doubleClickTimeout.current = null
}, DOUBLE_CLICK_MAX_DELAY)
- onClick({ option }, event)
+ onClick({ value }, event)
}
}}
data-value={value}
@@ -104,7 +101,6 @@ TransferOption.defaultProps = {
TransferOption.propTypes = {
label: propTypes.string.isRequired,
value: propTypes.string.isRequired,
- additionalData: propTypes.object,
className: propTypes.string,
dataTest: propTypes.string,
disabled: propTypes.bool,
diff --git a/packages/core/src/Transfer/__e2e__/add_remove-highlighted-options.stories.e2e.js b/packages/widgets/src/Transfer/__e2e__/add_remove-highlighted-options.stories.e2e.js
similarity index 53%
rename from packages/core/src/Transfer/__e2e__/add_remove-highlighted-options.stories.e2e.js
rename to packages/widgets/src/Transfer/__e2e__/add_remove-highlighted-options.stories.e2e.js
index 0fe632cb53..ab73f7b5b1 100644
--- a/packages/core/src/Transfer/__e2e__/add_remove-highlighted-options.stories.e2e.js
+++ b/packages/widgets/src/Transfer/__e2e__/add_remove-highlighted-options.stories.e2e.js
@@ -2,7 +2,8 @@
import React from 'react'
import { Transfer } from '../../index.js'
-import { options, statefulDecorator } from './common'
+import { statefulDecorator } from './common/statefulDecorator'
+import { options } from './common/options'
export default {
title: 'Transfer add & remove highlighted options',
@@ -10,21 +11,22 @@ export default {
}
export const HasOptions = ({ onChange, selected }) => (
-
- {options}
-
+
)
export const HasSelected = ({ onChange, selected }) => (
-
- {options}
-
+
)
HasSelected.story = {
decorators: [
statefulDecorator({
- initialState: options.slice(0, 4),
+ initialState: options.slice(0, 4).map(({ value }) => value),
}),
],
}
diff --git a/packages/widgets/src/Transfer/__e2e__/common.js b/packages/widgets/src/Transfer/__e2e__/common.js
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/widgets/src/Transfer/__e2e__/common/options.js b/packages/widgets/src/Transfer/__e2e__/common/options.js
new file mode 100644
index 0000000000..8010b73e27
--- /dev/null
+++ b/packages/widgets/src/Transfer/__e2e__/common/options.js
@@ -0,0 +1,92 @@
+export const options = [
+ {
+ label: 'ANC 1st visit',
+ value: 'anc_1st_visit',
+ },
+ {
+ label: 'ANC 2nd visit',
+ value: 'anc_2nd_visit',
+ },
+ {
+ label: 'ANC 3rd visit',
+ value: 'anc_3rd_visit',
+ },
+ {
+ label: 'ANC 4th or more visits',
+ value: 'anc_4th_or_more_visits',
+ },
+ {
+ label: 'ARI treated with antibiotics (pneumonia) follow-up',
+ value: 'ari_treated_with_antibiotics_(pneumonia)_follow-up',
+ },
+ {
+ label: 'ARI treated with antibiotics (pneumonia) new',
+ value: 'ari_treated_with_antibiotics_(pneumonia)_new',
+ },
+ {
+ label: 'ARI treated with antibiotics (pneumonia) referrals',
+ value: 'ari_treated_with_antibiotics_(pneumonia)_referrals',
+ },
+ {
+ label: 'ARI treated without antibiotics (cough) follow-up',
+ value: 'ari_treated_without_antibiotics_(cough)_follow-up',
+ },
+ {
+ label: 'ARI treated without antibiotics (cough) new',
+ value: 'ari_treated_without_antibiotics_(cough)_new',
+ },
+ {
+ label: 'ARI treated without antibiotics (cough) referrals',
+ value: 'ari_treated_without_antibiotics_(cough)_referrals',
+ },
+ {
+ label: 'ART No clients who stopped TRT due to TRT failure',
+ value: 'art_no_clients_who_stopped_trt_due_to_trt_failure',
+ },
+ {
+ label:
+ 'ART No clients who stopped TRT due to adverse clinical status/event',
+ value:
+ 'art_no_clients_who_stopped_trt_due_to_adverse_clinical_status/event',
+ },
+ {
+ label: 'ART No clients with change of regimen due to drug toxicity',
+ value: 'art_no_clients_with_change_of_regimen_due_to_drug_toxicity',
+ },
+ {
+ label: 'ART No clients with new adverse drug reaction',
+ value: 'art_no_clients_with_new_adverse_drug_reaction',
+ },
+ {
+ label: 'ART No started Opportunist Infection prophylaxis',
+ value: 'art_no_started_opportunist_infection_prophylaxis',
+ },
+ {
+ label: 'ART clients with new adverse clinical event',
+ value: 'art_clients_with_new_adverse_clinical_event',
+ },
+ {
+ label: 'ART defaulters',
+ value: 'art_defaulters',
+ },
+ {
+ label: 'ART enrollment stage 1',
+ value: 'art_enrollment_stage_1',
+ },
+ {
+ label: 'ART enrollment stage 2',
+ value: 'art_enrollment_stage_2',
+ },
+ {
+ label: 'ART enrollment stage 3',
+ value: 'art_enrollment_stage_3',
+ },
+ {
+ label: 'ART enrollment stage 4',
+ value: 'art_enrollment_stage_4',
+ },
+ {
+ label: 'ART entry point: No PMTCT',
+ value: 'art_entry_point:_no_pmtct',
+ },
+]
diff --git a/packages/widgets/src/Transfer/__e2e__/common/statefulDecorator.js b/packages/widgets/src/Transfer/__e2e__/common/statefulDecorator.js
new file mode 100644
index 0000000000..792cd958a5
--- /dev/null
+++ b/packages/widgets/src/Transfer/__e2e__/common/statefulDecorator.js
@@ -0,0 +1,20 @@
+import React, { useState } from 'react'
+
+export const statefulDecorator = ({
+ initialState = [],
+ controlFilter = false,
+ initialSearchTerm = '',
+} = {}) => fn =>
+ React.createElement(() => {
+ const [selected, setSelected] = useState(initialState)
+ const [searchTerm, setSearchTerm] = useState(initialSearchTerm)
+
+ return fn({
+ selected,
+ searchTerm: controlFilter ? searchTerm : undefined,
+ onChange: payload => setSelected(payload.selected),
+ onFilterChange: controlFilter
+ ? ({ value }) => setSearchTerm(value)
+ : undefined,
+ })
+ })
diff --git a/packages/core/src/Transfer/__e2e__/disabled-transfer-buttons.stories.e2e.js b/packages/widgets/src/Transfer/__e2e__/disabled-transfer-buttons.stories.e2e.js
similarity index 52%
rename from packages/core/src/Transfer/__e2e__/disabled-transfer-buttons.stories.e2e.js
rename to packages/widgets/src/Transfer/__e2e__/disabled-transfer-buttons.stories.e2e.js
index f0d7d4f072..b2046a8f48 100644
--- a/packages/core/src/Transfer/__e2e__/disabled-transfer-buttons.stories.e2e.js
+++ b/packages/widgets/src/Transfer/__e2e__/disabled-transfer-buttons.stories.e2e.js
@@ -2,7 +2,8 @@
import React from 'react'
import { Transfer } from '../../index.js'
-import { options, statefulDecorator } from './common.js'
+import { statefulDecorator } from './common/statefulDecorator'
+import { options } from './common/options'
export default {
title: 'Transfer Disabled Transfer Buttons',
@@ -10,45 +11,41 @@ export default {
}
export const NoOptions = ({ selected, onChange }) => (
-
+
)
export const HasOptions = ({ selected, onChange }) => (
-
- {options}
-
+
)
export const SomeOptionsSelected = ({ selected, onChange }) => (
-
- {options}
-
+
)
export const OnlyDisabledSourceOptions = ({ selected, onChange }) => (
-
- {React.cloneElement(options[0], { disabled: true })}
-
+
)
SomeOptionsSelected.story = {
decorators: [
statefulDecorator({
- initialState: options.slice(0, 4),
+ initialState: options.slice(0, 4).map(({ value }) => value),
}),
],
}
export const AllOptionsSelected = ({ selected, onChange }) => (
-
- {options}
-
+
)
AllOptionsSelected.story = {
decorators: [
statefulDecorator({
- initialState: options,
+ initialState: options.map(({ value }) => value),
}),
],
}
diff --git a/packages/core/src/Transfer/__e2e__/disabled-transfer-options.stories.e2e.js b/packages/widgets/src/Transfer/__e2e__/disabled-transfer-options.stories.e2e.js
similarity index 58%
rename from packages/core/src/Transfer/__e2e__/disabled-transfer-options.stories.e2e.js
rename to packages/widgets/src/Transfer/__e2e__/disabled-transfer-options.stories.e2e.js
index 8529a093e9..8fbefb927d 100644
--- a/packages/core/src/Transfer/__e2e__/disabled-transfer-options.stories.e2e.js
+++ b/packages/widgets/src/Transfer/__e2e__/disabled-transfer-options.stories.e2e.js
@@ -2,7 +2,8 @@
import React from 'react'
import { Transfer } from '../../index.js'
-import { options, statefulDecorator } from './common.js'
+import { statefulDecorator } from './common/statefulDecorator'
+import { options } from './common/options'
export default {
title: 'Disabled Source Options',
@@ -10,11 +11,13 @@ export default {
}
export const OneDisabled = ({ selected, onChange }) => (
-
- {[
+
+ />
)
diff --git a/packages/widgets/src/Transfer/__e2e__/display-order.stories.e2e.js b/packages/widgets/src/Transfer/__e2e__/display-order.stories.e2e.js
new file mode 100644
index 0000000000..8b3f2f98b4
--- /dev/null
+++ b/packages/widgets/src/Transfer/__e2e__/display-order.stories.e2e.js
@@ -0,0 +1,26 @@
+/* eslint-disable react/prop-types */
+import React from 'react'
+
+import { Transfer } from '../../index.js'
+import { statefulDecorator } from './common/statefulDecorator'
+import { options } from './common/options'
+
+export default { title: 'Transfer Display Order' }
+
+window.options = options
+
+export const NoSelection = ({ selected, onChange }) => (
+
+)
+
+export const SomeSelected = ({ selected, onChange }) => (
+
+)
+
+SomeSelected.story = {
+ decorators: [
+ statefulDecorator({
+ initialState: options.slice(0, 4).map(({ value }) => value),
+ }),
+ ],
+}
diff --git a/packages/core/src/Transfer/__e2e__/filter-options-list.stories.e2e.js b/packages/widgets/src/Transfer/__e2e__/filter-options-list.stories.e2e.js
similarity index 86%
rename from packages/core/src/Transfer/__e2e__/filter-options-list.stories.e2e.js
rename to packages/widgets/src/Transfer/__e2e__/filter-options-list.stories.e2e.js
index 932deb7bdf..1d1eedac39 100644
--- a/packages/core/src/Transfer/__e2e__/filter-options-list.stories.e2e.js
+++ b/packages/widgets/src/Transfer/__e2e__/filter-options-list.stories.e2e.js
@@ -1,7 +1,8 @@
/* eslint-disable react/prop-types */
import React from 'react'
-import { options, statefulDecorator } from './common.js'
+import { statefulDecorator } from './common/statefulDecorator'
+import { options } from './common/options'
import { Transfer } from '../../index.js'
export default {
@@ -16,9 +17,8 @@ export const EmptyResult = ({ selected, onChange }) => (
selected={selected}
onChange={onChange}
sourceEmptyPlaceholder={No results}
- >
- {options}
-
+ options={options}
+ />
)
export const SomeResults = ({ selected, onChange }) => (
@@ -27,9 +27,8 @@ export const SomeResults = ({ selected, onChange }) => (
filterable
initialSearchTerm="ANC"
onChange={onChange}
- >
- {options}
-
+ options={options}
+ />
)
export const UppercaseSearch = ({ selected, onChange }) => (
@@ -38,9 +37,8 @@ export const UppercaseSearch = ({ selected, onChange }) => (
filterable
initialSearchTerm="ANC"
onChange={onChange}
- >
- {options}
-
+ options={options}
+ />
)
export const LowercaseSearch = ({ selected, onChange }) => (
@@ -49,9 +47,8 @@ export const LowercaseSearch = ({ selected, onChange }) => (
initialSearchTerm="anc"
selected={selected}
onChange={onChange}
- >
- {options}
-
+ options={options}
+ />
)
export const AncCustomFilter = ({ selected, onChange }) => (
@@ -62,9 +59,8 @@ export const AncCustomFilter = ({ selected, onChange }) => (
filterCallback={(options, filter) =>
options.filter(({ label }) => label.match(`(^| )ANC .*${filter}`))
}
- >
- {options}
-
+ options={options}
+ />
)
window.customFilterCallback = (options, filter) => {
@@ -86,9 +82,8 @@ export const ControlledFilter = ({
filterCallback={window.customFilterCallback}
searchTerm={filter}
onFilterChange={onFilterChange}
- >
- {options}
-
+ options={options}
+ />
)
ControlledFilter.story = {
diff --git a/packages/widgets/src/Transfer/__e2e__/highlight-range-of-options.stories.e2e.js b/packages/widgets/src/Transfer/__e2e__/highlight-range-of-options.stories.e2e.js
new file mode 100644
index 0000000000..3c28283f83
--- /dev/null
+++ b/packages/widgets/src/Transfer/__e2e__/highlight-range-of-options.stories.e2e.js
@@ -0,0 +1,54 @@
+/* eslint-disable react/prop-types */
+import React from 'react'
+
+import { Transfer } from '../../index.js'
+import { statefulDecorator } from './common/statefulDecorator'
+import { options } from './common/options'
+
+export default {
+ title: 'Transfer highlight range of options',
+ decorators: [statefulDecorator()],
+}
+
+export const HasOptions = ({ onChange, selected }) => (
+
+)
+
+export const HasSelected = ({ onChange, selected }) => (
+
+)
+
+HasSelected.story = {
+ decorators: [
+ statefulDecorator({
+ initialState: options.slice(0, 4).map(({ value }) => value),
+ }),
+ ],
+}
+
+export const AllSelected = ({ onChange, selected }) => (
+
+)
+
+AllSelected.story = {
+ decorators: [
+ statefulDecorator({
+ initialState: options.map(({ value }) => value),
+ }),
+ ],
+}
diff --git a/packages/core/src/Transfer/__e2e__/reorder-with-buttons.stories.e2e.js b/packages/widgets/src/Transfer/__e2e__/reorder-with-buttons.stories.e2e.js
similarity index 50%
rename from packages/core/src/Transfer/__e2e__/reorder-with-buttons.stories.e2e.js
rename to packages/widgets/src/Transfer/__e2e__/reorder-with-buttons.stories.e2e.js
index c39bc2ba71..073009ef9e 100644
--- a/packages/core/src/Transfer/__e2e__/reorder-with-buttons.stories.e2e.js
+++ b/packages/widgets/src/Transfer/__e2e__/reorder-with-buttons.stories.e2e.js
@@ -1,20 +1,24 @@
/* eslint-disable react/prop-types */
import React from 'react'
import { Transfer } from '../../index.js'
-import { options, statefulDecorator } from './common.js'
+import { statefulDecorator } from './common/statefulDecorator'
+import { options } from './common/options'
export default { title: 'Transfer Reorder Buttons' }
export const HasSomeSelected = ({ selected, onChange }) => (
-
- {options}
-
+
)
HasSomeSelected.story = {
decorators: [
statefulDecorator({
- initialState: options.slice(0, 3),
+ initialState: options.slice(0, 3).map(({ value }) => value),
}),
],
}
diff --git a/packages/core/src/Transfer/__e2e__/set_unset-highlighted-option.stories.e2e.js b/packages/widgets/src/Transfer/__e2e__/set_unset-highlighted-option.stories.e2e.js
similarity index 53%
rename from packages/core/src/Transfer/__e2e__/set_unset-highlighted-option.stories.e2e.js
rename to packages/widgets/src/Transfer/__e2e__/set_unset-highlighted-option.stories.e2e.js
index 263ba5ec68..519ac0a41a 100644
--- a/packages/core/src/Transfer/__e2e__/set_unset-highlighted-option.stories.e2e.js
+++ b/packages/widgets/src/Transfer/__e2e__/set_unset-highlighted-option.stories.e2e.js
@@ -2,7 +2,8 @@
import React from 'react'
import { Transfer } from '../../index.js'
-import { options, statefulDecorator } from './common.js'
+import { statefulDecorator } from './common/statefulDecorator'
+import { options } from './common/options'
export default {
title: 'Transfer set & unset higlighted options',
@@ -10,21 +11,22 @@ export default {
}
export const HasOptions = ({ onChange, selected }) => (
-
- {options}
-
+
)
export const HasSelected = ({ onChange, selected }) => (
-
- {options}
-
+
)
HasSelected.story = {
decorators: [
statefulDecorator({
- initialState: options.slice(0, 4),
+ initialState: options.slice(0, 4).map(({ value }) => value),
}),
],
}
diff --git a/packages/core/src/Transfer/__e2e__/transferring-items.stories.e2e.js b/packages/widgets/src/Transfer/__e2e__/transferring-items.stories.e2e.js
similarity index 51%
rename from packages/core/src/Transfer/__e2e__/transferring-items.stories.e2e.js
rename to packages/widgets/src/Transfer/__e2e__/transferring-items.stories.e2e.js
index 78c22e5aff..a6a3d5a8bd 100644
--- a/packages/core/src/Transfer/__e2e__/transferring-items.stories.e2e.js
+++ b/packages/widgets/src/Transfer/__e2e__/transferring-items.stories.e2e.js
@@ -1,34 +1,28 @@
/* eslint-disable react/prop-types */
import React from 'react'
import { Transfer } from '../../index.js'
-import { options, statefulDecorator } from './common.js'
+import { statefulDecorator } from './common/statefulDecorator'
+import { options } from './common/options'
export default {
title: 'Transfer Transferring Items',
decorators: [statefulDecorator()],
}
-window.options = options.map(child => {
- const { label, value } = child.props
- return { label, value }
-})
+window.options = options
export const HasOptions = ({ selected, onChange }) => (
-
- {options}
-
+
)
export const SomeSelected = ({ selected, onChange }) => (
-
- {options}
-
+
)
SomeSelected.story = {
decorators: [
statefulDecorator({
- initialState: options.slice(0, 4),
+ initialState: options.slice(0, 4).map(({ value }) => value),
}),
],
}
diff --git a/packages/widgets/src/Transfer/__tests__/common.test.js b/packages/widgets/src/Transfer/__tests__/common.test.js
new file mode 100644
index 0000000000..e8935b45df
--- /dev/null
+++ b/packages/widgets/src/Transfer/__tests__/common.test.js
@@ -0,0 +1,131 @@
+import {
+ ADD_MODE,
+ RANGE_MODE,
+ REPLACE_MODE,
+ findOptionIndex,
+ getModeByModifierKey,
+ isOption,
+ toggleValue,
+} from '../common/index'
+
+describe('Transfer - isOption', () => {
+ it('should return true when the options are the same', () => {
+ const option1 = { label: 'foo', value: 'bar' }
+ const option2 = { label: 'foo', value: 'bar' }
+ const actual = isOption(option1, option2)
+ const expected = true
+
+ expect(actual).toBe(expected)
+ })
+
+ it('should return false when the labels do not match', () => {
+ const option1 = { label: 'foo', value: 'bar' }
+ const option2 = { label: 'baz', value: 'bar' }
+ const actual = isOption(option1, option2)
+ const expected = false
+
+ expect(actual).toBe(expected)
+ })
+
+ it('should return false when the values do not match', () => {
+ const option1 = { label: 'foo', value: 'bar' }
+ const option2 = { label: 'foo', value: 'baz' }
+ const actual = isOption(option1, option2)
+ const expected = false
+
+ expect(actual).toBe(expected)
+ })
+})
+
+describe('Transfer - findOptionIndex', () => {
+ it('should return index 1', () => {
+ const options = [
+ { label: 'foo', value: 'bar' },
+ { label: 'foo', value: 'baz' },
+ ]
+ const option = { label: 'foo', value: 'baz' }
+ const actual = findOptionIndex(options, option)
+ const expected = 1
+
+ expect(actual).toBe(expected)
+ })
+
+ it('should return -1 when the option is not included', () => {
+ const options = [
+ { label: 'foo', value: 'bar' },
+ { label: 'foo', value: 'baz' },
+ ]
+ const option = { label: 'baz', value: 'baz' }
+ const actual = findOptionIndex(options, option)
+ const expected = -1
+
+ expect(actual).toBe(expected)
+ })
+})
+
+describe('Transfer - toggleValue', () => {
+ it('should remove the last value from the array when value inside array', () => {
+ const values = ['foo', 'bar', 'baz']
+ const value = 'baz'
+ const expected = ['foo', 'bar']
+ const actual = toggleValue(values, value)
+
+ expect(actual).toEqual(expected)
+ })
+
+ it('should remove the first value from the array when value inside array', () => {
+ const values = ['foo', 'bar', 'baz']
+ const value = 'foo'
+ const expected = ['bar', 'baz']
+ const actual = toggleValue(values, value)
+
+ expect(actual).toEqual(expected)
+ })
+
+ it('should add the value if not inside the array', () => {
+ const values = ['foo', 'bar']
+ const value = 'baz'
+ const expected = ['foo', 'bar', 'baz']
+ const actual = toggleValue(values, value)
+
+ expect(actual).toEqual(expected)
+ })
+})
+
+describe('Transfer - getModeByModifierKey', () => {
+ it('should return REPLACE_MODE when more than one key is pressed', () => {
+ const expected = REPLACE_MODE
+ const actual = getModeByModifierKey({ altKey: true, ctrlKey: true })
+ expect(actual).toBe(expected)
+ })
+
+ it('should return ADD_MODE if alt key is pressed', () => {
+ const expected = ADD_MODE
+ const actual = getModeByModifierKey({ altKey: true })
+ expect(actual).toBe(expected)
+ })
+
+ it('should return ADD_MODE if ctrl key is pressed', () => {
+ const expected = ADD_MODE
+ const actual = getModeByModifierKey({ ctrlKey: true })
+ expect(actual).toBe(expected)
+ })
+
+ it('should return ADD_MODE if meta key is pressed', () => {
+ const expected = ADD_MODE
+ const actual = getModeByModifierKey({ metaKey: true })
+ expect(actual).toBe(expected)
+ })
+
+ it('should return RANGE_MODE if shift key is pressed', () => {
+ const expected = RANGE_MODE
+ const actual = getModeByModifierKey({ shiftKey: true })
+ expect(actual).toBe(expected)
+ })
+
+ it('should return REPLACE_MODE if no key is pressed', () => {
+ const expected = REPLACE_MODE
+ const actual = getModeByModifierKey({})
+ expect(actual).toBe(expected)
+ })
+})
diff --git a/packages/widgets/src/Transfer/__tests__/helper/addAllSelectableSourceOptions.test.js b/packages/widgets/src/Transfer/__tests__/helper/addAllSelectableSourceOptions.test.js
new file mode 100644
index 0000000000..64e6b938a3
--- /dev/null
+++ b/packages/widgets/src/Transfer/__tests__/helper/addAllSelectableSourceOptions.test.js
@@ -0,0 +1,46 @@
+import { addAllSelectableSourceOptions } from '../../Transfer/addAllSelectableSourceOptions.js'
+
+describe('Transfer - addAllSelectableSourceOptions', () => {
+ const onChange = jest.fn()
+ const setHighlightedSourceOptions = jest.fn()
+
+ const sourceOptions = [
+ { label: 'Foo', value: 'foo' },
+ { label: 'Bar', value: 'bar' },
+ { label: 'Baz', value: 'baz' },
+ { label: 'Foobar', value: 'foobar' },
+ { label: 'Foobaz', value: 'foobaz' },
+ ]
+
+ afterEach(() => {
+ onChange.mockClear()
+ setHighlightedSourceOptions.mockClear()
+ })
+
+ it('should add all selectable source options to the selected array', () => {
+ const selected = ['barfoo']
+ const expected = {
+ selected: ['barfoo', 'foo', 'bar', 'baz', 'foobar', 'foobaz'],
+ }
+
+ addAllSelectableSourceOptions({
+ sourceOptions,
+ selected,
+ onChange,
+ setHighlightedSourceOptions,
+ })
+
+ expect(onChange).toHaveBeenCalledWith(expected)
+ })
+
+ it('should reset all highlighted source options', () => {
+ addAllSelectableSourceOptions({
+ sourceOptions,
+ selected: ['barfoo'],
+ onChange,
+ setHighlightedSourceOptions,
+ })
+
+ expect(setHighlightedSourceOptions).toHaveBeenCalledWith([])
+ })
+})
diff --git a/packages/widgets/src/Transfer/__tests__/helper/addIndividualSourceOptions.test.js b/packages/widgets/src/Transfer/__tests__/helper/addIndividualSourceOptions.test.js
new file mode 100644
index 0000000000..bcaee6656f
--- /dev/null
+++ b/packages/widgets/src/Transfer/__tests__/helper/addIndividualSourceOptions.test.js
@@ -0,0 +1,80 @@
+import { addIndividualSourceOptions } from '../../Transfer/addIndividualSourceOptions.js'
+
+describe('Transfer - addIndividualSourceOptions', () => {
+ const onChange = jest.fn()
+ const setHighlightedSourceOptions = jest.fn()
+
+ const sourceOptions = [
+ { label: 'Foo', value: 'foo' },
+ { label: 'Foobar', value: 'foobar' },
+ { label: 'Foobaz', value: 'foobaz' },
+ ]
+
+ const highlightedSourceOptions = ['foobaz', 'bar']
+ const selected = ['barfoo']
+
+ afterEach(() => {
+ onChange.mockClear()
+ setHighlightedSourceOptions.mockClear()
+ })
+
+ it('should add the highlighted source options to the selected array', () => {
+ addIndividualSourceOptions({
+ highlightedSourceOptions,
+ maxSelections: Infinity,
+ onChange,
+ selected,
+ setHighlightedSourceOptions,
+ })
+
+ expect(onChange).toHaveBeenCalledWith({
+ selected: ['barfoo', 'foobaz', 'bar'],
+ })
+ })
+
+ it('should reset the highlighted source options', () => {
+ addIndividualSourceOptions({
+ highlightedSourceOptions,
+ maxSelections: Infinity,
+ onChange,
+ selected,
+ setHighlightedSourceOptions,
+ })
+
+ expect(setHighlightedSourceOptions).toHaveBeenCalledWith([])
+ })
+
+ it('should only select the filtered source options', () => {
+ addIndividualSourceOptions({
+ filterable: true,
+ filter: 'oo',
+ sourceOptions,
+ highlightedSourceOptions,
+ maxSelections: Infinity,
+ onChange,
+ selected,
+ setHighlightedSourceOptions,
+ })
+
+ expect(onChange).toHaveBeenCalledWith({
+ selected: ['barfoo', 'foobaz'],
+ })
+ })
+
+ it('should only call onChange with the max selection amount', () => {
+ addIndividualSourceOptions({
+ filterable: true,
+ filter: 'oo',
+ sourceOptions,
+ highlightedSourceOptions: highlightedSourceOptions.slice(0, 1),
+ maxSelections: 1,
+ onChange,
+ selected: selected,
+ setHighlightedSourceOptions,
+ })
+
+ expect(onChange).toHaveBeenCalledWith({
+ selected: ['foobaz'],
+ })
+ })
+})
diff --git a/packages/core/src/Transfer/__tests__/helper/defaultFilterCallback.test.js b/packages/widgets/src/Transfer/__tests__/helper/defaultFilterCallback.test.js
similarity index 70%
rename from packages/core/src/Transfer/__tests__/helper/defaultFilterCallback.test.js
rename to packages/widgets/src/Transfer/__tests__/helper/defaultFilterCallback.test.js
index b12c98df99..2a869137ad 100644
--- a/packages/core/src/Transfer/__tests__/helper/defaultFilterCallback.test.js
+++ b/packages/widgets/src/Transfer/__tests__/helper/defaultFilterCallback.test.js
@@ -1,7 +1,7 @@
-import { defaultFilterCallback } from '../../../Transfer/helper/defaultFilterCallback.js'
+import { defaultFilterCallback } from '../../../Transfer/Transfer/defaultFilterCallback.js'
describe('Transfer - defaultFilterCallback', () => {
- const plainOptions = [
+ const options = [
{ label: 'Foo', value: 'foo' },
{ label: 'FOO', value: 'fOO' },
{ label: 'Bar', value: 'bar' },
@@ -10,8 +10,8 @@ describe('Transfer - defaultFilterCallback', () => {
it('should returl all options when the filter is empty', () => {
const filter = ''
- const expected = plainOptions
- const actual = defaultFilterCallback(plainOptions, filter)
+ const expected = options
+ const actual = defaultFilterCallback(options, filter)
expect(actual).toEqual(expected)
})
@@ -22,7 +22,7 @@ describe('Transfer - defaultFilterCallback', () => {
{ label: 'Foo', value: 'foo' },
{ label: 'FOO', value: 'fOO' },
]
- const actual = defaultFilterCallback(plainOptions, filter)
+ const actual = defaultFilterCallback(options, filter)
expect(actual).toEqual(expected)
})
@@ -30,7 +30,7 @@ describe('Transfer - defaultFilterCallback', () => {
it('should return an empty array when there are no matches', () => {
const filter = 'Baz'
const expected = []
- const actual = defaultFilterCallback(plainOptions, filter)
+ const actual = defaultFilterCallback(options, filter)
expect(actual).toEqual(expected)
})
diff --git a/packages/widgets/src/Transfer/__tests__/helper/isReorderDownDisabled.test.js b/packages/widgets/src/Transfer/__tests__/helper/isReorderDownDisabled.test.js
new file mode 100644
index 0000000000..64910e3141
--- /dev/null
+++ b/packages/widgets/src/Transfer/__tests__/helper/isReorderDownDisabled.test.js
@@ -0,0 +1,47 @@
+import { isReorderDownDisabled } from '../../../Transfer/Transfer/isReorderDownDisabled.js'
+
+describe('Transfer - isReorderDownDisabled', () => {
+ const selected = ['foo', 'bar', 'baz']
+
+ it('should return true when there are no highlighted picked options', () => {
+ const highlightedPickedOptions = []
+ const actual = isReorderDownDisabled({
+ highlightedPickedOptions,
+ selected,
+ })
+
+ expect(actual).toBe(true)
+ })
+
+ it('should return true when there are multiple highlighted picked options', () => {
+ const highlightedPickedOptions = ['bar', 'foo']
+ const actual = isReorderDownDisabled({
+ highlightedPickedOptions,
+ selected,
+ })
+
+ expect(actual).toBe(true)
+ })
+
+ it('should return true if the last picked option is highlighted', () => {
+ const highlightedPickedOptions = ['baz']
+
+ const actual = isReorderDownDisabled({
+ highlightedPickedOptions,
+ selected,
+ })
+
+ expect(actual).toBe(true)
+ })
+
+ it('should return false when one picked option is highlighted which is not the last one', () => {
+ const highlightedPickedOptions = ['bar']
+
+ const actual = isReorderDownDisabled({
+ highlightedPickedOptions,
+ selected,
+ })
+
+ expect(actual).toBe(false)
+ })
+})
diff --git a/packages/widgets/src/Transfer/__tests__/helper/isReorderUpDisabled.test.js b/packages/widgets/src/Transfer/__tests__/helper/isReorderUpDisabled.test.js
new file mode 100644
index 0000000000..d4176becaf
--- /dev/null
+++ b/packages/widgets/src/Transfer/__tests__/helper/isReorderUpDisabled.test.js
@@ -0,0 +1,47 @@
+import { isReorderUpDisabled } from '../../../Transfer/Transfer/isReorderUpDisabled.js'
+
+describe('Transfer - isReorderUpDisabled', () => {
+ const selected = ['foo', 'bar', 'baz']
+
+ it('should return true when there are no highlighted picked options', () => {
+ const highlightedPickedOptions = []
+ const actual = isReorderUpDisabled({
+ highlightedPickedOptions,
+ selected,
+ })
+
+ expect(actual).toBe(true)
+ })
+
+ it('should return true when there are multiple highlighted picked options', () => {
+ const highlightedPickedOptions = ['bar', 'baz']
+ const actual = isReorderUpDisabled({
+ highlightedPickedOptions,
+ selected,
+ })
+
+ expect(actual).toBe(true)
+ })
+
+ it('should return true if the first picked option is highlighted', () => {
+ const highlightedPickedOptions = ['foo']
+
+ const actual = isReorderUpDisabled({
+ highlightedPickedOptions,
+ selected,
+ })
+
+ expect(actual).toBe(true)
+ })
+
+ it('should return false when one picked option is highlighted which is not the last one', () => {
+ const highlightedPickedOptions = ['baz']
+
+ const actual = isReorderUpDisabled({
+ highlightedPickedOptions,
+ selected,
+ })
+
+ expect(actual).toBe(false)
+ })
+})
diff --git a/packages/core/src/Transfer/__tests__/helper/moveHighlightedPickedOptionDown.test.js b/packages/widgets/src/Transfer/__tests__/helper/moveHighlightedPickedOptionDown.test.js
similarity index 50%
rename from packages/core/src/Transfer/__tests__/helper/moveHighlightedPickedOptionDown.test.js
rename to packages/widgets/src/Transfer/__tests__/helper/moveHighlightedPickedOptionDown.test.js
index d0eacee6a5..b178e77dd5 100644
--- a/packages/core/src/Transfer/__tests__/helper/moveHighlightedPickedOptionDown.test.js
+++ b/packages/widgets/src/Transfer/__tests__/helper/moveHighlightedPickedOptionDown.test.js
@@ -1,42 +1,33 @@
-import { moveHighlightedPickedOptionDown } from '../../../Transfer/helper/moveHighlightedPickedOptionDown.js'
+import { moveHighlightedPickedOptionDown } from '../../../Transfer/Transfer/moveHighlightedPickedOptionDown.js'
describe('Transfer - moveHighlightedPickedOptionDown', () => {
const onChange = jest.fn()
-
- const selectedPlainOptions = [
- { label: 'Foo', value: 'foo' },
- { label: 'Bar', value: 'bar' },
- { label: 'Baz', value: 'baz' },
- ]
+ const selected = ['foo', 'bar', 'baz']
afterEach(() => {
onChange.mockClear()
})
it('should move the highlighted option down', () => {
- const highlighted = [{ label: 'Bar', value: 'bar' }]
+ const highlighted = ['bar']
moveHighlightedPickedOptionDown({
- selectedPlainOptions,
- highlightedPickedPlainOptions: highlighted,
+ selected,
+ highlightedPickedOptions: highlighted,
onChange,
})
expect(onChange).toHaveBeenCalledWith({
- selected: [
- { label: 'Foo', value: 'foo' },
- { label: 'Baz', value: 'baz' },
- { label: 'Bar', value: 'bar' },
- ],
+ selected: ['foo', 'baz', 'bar'],
})
})
it('should do nothing when trying to move down the last option', () => {
- const highlighted = [{ label: 'Baz', value: 'baz' }]
+ const highlighted = ['baz']
moveHighlightedPickedOptionDown({
- selectedPlainOptions,
- highlightedPickedPlainOptions: highlighted,
+ selected,
+ highlightedPickedOptions: highlighted,
onChange,
})
@@ -44,11 +35,11 @@ describe('Transfer - moveHighlightedPickedOptionDown', () => {
})
it('should do nothing when trying to move down a non-existing option', () => {
- const highlighted = [{ label: 'Foobar', value: 'foobar' }]
+ const highlighted = ['foobar']
moveHighlightedPickedOptionDown({
- selectedPlainOptions,
- highlightedPickedPlainOptions: highlighted,
+ selected,
+ highlightedPickedOptions: highlighted,
onChange,
})
diff --git a/packages/widgets/src/Transfer/__tests__/helper/moveHighlightedPickedOptionUp.test.js b/packages/widgets/src/Transfer/__tests__/helper/moveHighlightedPickedOptionUp.test.js
new file mode 100644
index 0000000000..0919b22908
--- /dev/null
+++ b/packages/widgets/src/Transfer/__tests__/helper/moveHighlightedPickedOptionUp.test.js
@@ -0,0 +1,48 @@
+import { moveHighlightedPickedOptionUp } from '../../../Transfer/Transfer/moveHighlightedPickedOptionUp.js'
+
+describe('Transfer - moveHighlightedPickedOptionUp', () => {
+ const onChange = jest.fn()
+ const selected = ['foo', 'bar', 'baz']
+
+ afterEach(() => {
+ onChange.mockClear()
+ })
+
+ it('should move the highlighted option up', () => {
+ const highlighted = ['bar']
+
+ moveHighlightedPickedOptionUp({
+ selected,
+ highlightedPickedOptions: highlighted,
+ onChange,
+ })
+
+ expect(onChange).toHaveBeenCalledWith({
+ selected: ['bar', 'foo', 'baz'],
+ })
+ })
+
+ it('should do nothing when trying to move up the first option', () => {
+ const highlighted = ['foo']
+
+ moveHighlightedPickedOptionUp({
+ selected,
+ highlightedPickedOptions: highlighted,
+ onChange,
+ })
+
+ expect(onChange).toHaveBeenCalledTimes(0)
+ })
+
+ it('should do nothing when trying to move up a non-existing option', () => {
+ const highlighted = ['foobar']
+
+ moveHighlightedPickedOptionUp({
+ selected,
+ highlightedPickedOptions: highlighted,
+ onChange,
+ })
+
+ expect(onChange).toHaveBeenCalledTimes(0)
+ })
+})
diff --git a/packages/core/src/Transfer/__tests__/helper/removeAllPickedOptions.test.js b/packages/widgets/src/Transfer/__tests__/helper/removeAllPickedOptions.test.js
similarity index 88%
rename from packages/core/src/Transfer/__tests__/helper/removeAllPickedOptions.test.js
rename to packages/widgets/src/Transfer/__tests__/helper/removeAllPickedOptions.test.js
index ea705374c4..ff80ac779d 100644
--- a/packages/core/src/Transfer/__tests__/helper/removeAllPickedOptions.test.js
+++ b/packages/widgets/src/Transfer/__tests__/helper/removeAllPickedOptions.test.js
@@ -1,4 +1,4 @@
-import { removeAllPickedOptions } from '../../../Transfer/helper/removeAllPickedOptions.js'
+import { removeAllPickedOptions } from '../../../Transfer/Transfer/removeAllPickedOptions.js'
describe('Transfer - removeAllPickedOptions', () => {
const onChange = jest.fn()
diff --git a/packages/core/src/Transfer/__tests__/helper/removeIndividualPickedOptions.test.js b/packages/widgets/src/Transfer/__tests__/helper/removeIndividualPickedOptions.test.js
similarity index 60%
rename from packages/core/src/Transfer/__tests__/helper/removeIndividualPickedOptions.test.js
rename to packages/widgets/src/Transfer/__tests__/helper/removeIndividualPickedOptions.test.js
index 0517e95e13..392d0f594e 100644
--- a/packages/core/src/Transfer/__tests__/helper/removeIndividualPickedOptions.test.js
+++ b/packages/widgets/src/Transfer/__tests__/helper/removeIndividualPickedOptions.test.js
@@ -1,4 +1,4 @@
-import { removeIndividualPickedOptions } from '../../../Transfer/helper/removeIndividualPickedOptions.js'
+import { removeIndividualPickedOptions } from '../../../Transfer/Transfer/removeIndividualPickedOptions.js'
describe('Transfer - removeIndividualPickedOptions', () => {
const onChange = jest.fn()
@@ -9,34 +9,26 @@ describe('Transfer - removeIndividualPickedOptions', () => {
setHighlightedPickedOptions.mockClear()
})
- const selectedPlainOptions = [
- { label: 'Foo', value: 'foo' },
- { label: 'Bar', value: 'bar' },
- { label: 'Baz', value: 'baz' },
- ]
-
- const highlightedPickedReactOptions = [
- { label: 'Bar', value: 'bar' },
- { label: 'Baz', value: 'baz' },
- ]
+ const selected = ['foo', 'bar', 'baz']
+ const highlightedPickedOptions = ['bar', 'baz']
it('should remove the highlighted picked options', () => {
removeIndividualPickedOptions({
- highlightedPickedReactOptions,
- selectedPlainOptions,
+ highlightedPickedOptions,
+ selected,
onChange,
setHighlightedPickedOptions,
})
expect(onChange).toHaveBeenCalledWith({
- selected: [{ label: 'Foo', value: 'foo' }],
+ selected: ['foo'],
})
})
it('should reset the highlighted picked options', () => {
removeIndividualPickedOptions({
- highlightedPickedReactOptions,
- selectedPlainOptions,
+ highlightedPickedOptions,
+ selected,
onChange,
setHighlightedPickedOptions,
})
diff --git a/packages/core/src/Transfer/__tests__/helper/useHighlightedOption/createToggleHighlightedOption.test.js b/packages/widgets/src/Transfer/__tests__/helper/useHighlightedOption/createToggleHighlightedOption.test.js
similarity index 79%
rename from packages/core/src/Transfer/__tests__/helper/useHighlightedOption/createToggleHighlightedOption.test.js
rename to packages/widgets/src/Transfer/__tests__/helper/useHighlightedOption/createToggleHighlightedOption.test.js
index 1cbe909867..8f16a0024b 100644
--- a/packages/core/src/Transfer/__tests__/helper/useHighlightedOption/createToggleHighlightedOption.test.js
+++ b/packages/widgets/src/Transfer/__tests__/helper/useHighlightedOption/createToggleHighlightedOption.test.js
@@ -1,22 +1,21 @@
-import { ADD_MODE, RANGE_MODE, REPLACE_MODE } from '../../../common.js'
-import { createChildren } from '../../common/createChildren.js'
-import { createToggleHighlightedOption } from '../../../helper/useHighlightedOptions/createToggleHighlightedOption.js'
-import { toggleAdd } from '../../../helper/useHighlightedOptions/toggleAdd.js'
-import { toggleRange } from '../../../helper/useHighlightedOptions/toggleRange.js'
-import { toggleReplace } from '../../../helper/useHighlightedOptions/toggleReplace.js'
+import { ADD_MODE, RANGE_MODE, REPLACE_MODE } from '../../../common/index.js'
+import { createToggleHighlightedOption } from '../../../Transfer/useHighlightedOptions/createToggleHighlightedOption.js'
+import { toggleAdd } from '../../../Transfer/useHighlightedOptions/toggleAdd.js'
+import { toggleRange } from '../../../Transfer/useHighlightedOptions/toggleRange.js'
+import { toggleReplace } from '../../../Transfer/useHighlightedOptions/toggleReplace.js'
jest.mock(
- '../../../../Transfer/helper/useHighlightedOptions/toggleAdd',
+ '../../../../Transfer/Transfer/useHighlightedOptions/toggleAdd',
() => ({ toggleAdd: jest.fn() })
)
jest.mock(
- '../../../../Transfer/helper/useHighlightedOptions/toggleRange',
+ '../../../../Transfer/Transfer/useHighlightedOptions/toggleRange',
() => ({ toggleRange: jest.fn() })
)
jest.mock(
- '../../../../Transfer/helper/useHighlightedOptions/toggleReplace',
+ '../../../../Transfer/Transfer/useHighlightedOptions/toggleReplace',
() => ({ toggleReplace: jest.fn() })
)
@@ -28,10 +27,10 @@ describe('Transfer- useHighlightedOptions - createToggleHighlightedOption', () =
const highlightedOptions = []
const maxSelections = Infinity
const setHighlightedOptions = jest.fn()
- const reactOptions = createChildren()
+ const options = []
const option = { value: 'foo', label: 'Foo' }
const createToggleHighlightedOptionDefaultPayload = {
- reactOptions,
+ options,
disabled,
highlightedOptions,
lastClicked,
@@ -55,12 +54,12 @@ describe('Transfer- useHighlightedOptions - createToggleHighlightedOption', () =
it('should set the lastClicked to the clicked option when mode is ADD_MODE', () => {
toggleHighlightedOption({ option, mode: ADD_MODE })
- expect(setLastClicked).toHaveBeenCalledWith(option)
+ expect(setLastClicked).toHaveBeenCalledWith(option.value)
})
it('should set the lastClicked to the clicked option when mode is REPLACE_MODE', () => {
toggleHighlightedOption({ option, mode: REPLACE_MODE })
- expect(setLastClicked).toHaveBeenCalledWith(option)
+ expect(setLastClicked).toHaveBeenCalledWith(option.value)
})
it('should not overwrite the lastClicked to the clicked option when mode is RANGE_MODE', () => {
diff --git a/packages/core/src/Transfer/__tests__/helper/useHighlightedOption/toggleAdd.test.js b/packages/widgets/src/Transfer/__tests__/helper/useHighlightedOption/toggleAdd.test.js
similarity index 78%
rename from packages/core/src/Transfer/__tests__/helper/useHighlightedOption/toggleAdd.test.js
rename to packages/widgets/src/Transfer/__tests__/helper/useHighlightedOption/toggleAdd.test.js
index a22c0a0828..e4dbb2c604 100644
--- a/packages/core/src/Transfer/__tests__/helper/useHighlightedOption/toggleAdd.test.js
+++ b/packages/widgets/src/Transfer/__tests__/helper/useHighlightedOption/toggleAdd.test.js
@@ -1,4 +1,4 @@
-import { toggleAdd } from '../../../../Transfer/helper/useHighlightedOptions/toggleAdd.js'
+import { toggleAdd } from '../../../../Transfer/Transfer/useHighlightedOptions/toggleAdd.js'
describe('Transfer - useHighlightedOptions - toggleAdd', () => {
const setHighlightedOptions = jest.fn()
@@ -11,9 +11,9 @@ describe('Transfer - useHighlightedOptions - toggleAdd', () => {
const maxSelections = 1
it('should replace the current highlighted option', () => {
- const highlightedOptions = [{ value: 'foo', label: 'Foo' }]
+ const highlightedOptions = ['foo']
const option = { value: 'bar', label: 'Bar' }
- const expected = [option]
+ const expected = [option.value]
toggleAdd({
maxSelections,
@@ -26,7 +26,7 @@ describe('Transfer - useHighlightedOptions - toggleAdd', () => {
})
it('should empty the highlighted options', () => {
- const highlightedOptions = [{ value: 'foo', label: 'Foo' }]
+ const highlightedOptions = ['foo']
const option = { value: 'foo', label: 'Foo' }
const expected = []
@@ -45,9 +45,9 @@ describe('Transfer - useHighlightedOptions - toggleAdd', () => {
const maxSelections = Infinity
it('should add the option to the highlighted options when maxSelections is Infinity', () => {
- const highlightedOptions = [{ value: 'foo', label: 'Foo' }]
+ const highlightedOptions = ['foo']
const option = { value: 'bar', label: 'Bar' }
- const expected = [...highlightedOptions, option]
+ const expected = [...highlightedOptions, option.value]
toggleAdd({
maxSelections,
@@ -63,8 +63,12 @@ describe('Transfer - useHighlightedOptions - toggleAdd', () => {
const optionOne = { value: 'foo', label: 'Foo' }
const optionTwo = { value: 'bar', label: 'Bar' }
const optionThree = { value: 'baz', label: 'Baz' }
- const highlightedOptions = [optionOne, optionTwo, optionThree]
- const expected = [optionOne, optionThree]
+ const highlightedOptions = [
+ optionOne.value,
+ optionTwo.value,
+ optionThree.value,
+ ]
+ const expected = [optionOne, optionThree].map(({ value }) => value)
const option = optionTwo
toggleAdd({
diff --git a/packages/core/src/Transfer/__tests__/helper/useHighlightedOption/toggleRange.test.js b/packages/widgets/src/Transfer/__tests__/helper/useHighlightedOption/toggleRange.test.js
similarity index 65%
rename from packages/core/src/Transfer/__tests__/helper/useHighlightedOption/toggleRange.test.js
rename to packages/widgets/src/Transfer/__tests__/helper/useHighlightedOption/toggleRange.test.js
index 22c692d7ff..4974931b4c 100644
--- a/packages/core/src/Transfer/__tests__/helper/useHighlightedOption/toggleRange.test.js
+++ b/packages/widgets/src/Transfer/__tests__/helper/useHighlightedOption/toggleRange.test.js
@@ -1,11 +1,8 @@
-import React from 'react'
-
-import { createChildren } from '../../common/createChildren.js'
-import { toggleRange } from '../../../helper/useHighlightedOptions/toggleRange.js'
+import { toggleRange } from '../../../Transfer/useHighlightedOptions/toggleRange.js'
describe('Transfer- useHighlightedOptions - toggleRange', () => {
const setHighlightedOptions = jest.fn()
- const plainOptions = [
+ const options = [
{ label: 'Foo', value: 'foo' },
{ label: 'Bar', value: 'bar' },
{ label: 'Baz', value: 'baz' },
@@ -13,14 +10,6 @@ describe('Transfer- useHighlightedOptions - toggleRange', () => {
{ label: 'Foobaz', value: 'foobaz' },
{ label: 'Foobarbaz', value: 'foobarbaz' },
]
- const reactOptions = createChildren(
- ...plainOptions.map(plainOption =>
- React.createElement('span', {
- ...plainOption,
- key: plainOption.value,
- })
- )
- )
afterEach(() => {
setHighlightedOptions.mockClear()
@@ -28,12 +17,12 @@ describe('Transfer- useHighlightedOptions - toggleRange', () => {
describe('maxSelections=1', () => {
const maxSelections = 1
- const highlightedOptions = plainOptions.slice(0, 1)
- const lastClicked = plainOptions[0]
+ const highlightedOptions = options.slice(0, 1).map(({ value }) => value)
+ const lastClicked = options[0].value
it('should replace the current highlighted option', () => {
- const option = plainOptions[1]
- const expected = [option]
+ const option = options[1]
+ const expected = [option.value]
toggleRange({
lastClicked,
@@ -41,14 +30,14 @@ describe('Transfer- useHighlightedOptions - toggleRange', () => {
highlightedOptions,
option,
setHighlightedOptions,
- reactOptions,
+ options,
})
expect(setHighlightedOptions).toHaveBeenCalledWith(expected)
})
it('should not change the highlighted options', () => {
- const option = plainOptions[0]
+ const option = options[0]
const expected = highlightedOptions
toggleRange({
@@ -57,7 +46,7 @@ describe('Transfer- useHighlightedOptions - toggleRange', () => {
highlightedOptions,
option,
setHighlightedOptions,
- reactOptions,
+ options,
})
expect(setHighlightedOptions).toHaveBeenCalledWith(expected)
@@ -66,11 +55,11 @@ describe('Transfer- useHighlightedOptions - toggleRange', () => {
describe('maxSelections=Infinity', () => {
const maxSelections = Infinity
- const highlightedOptions = plainOptions.slice(0, 1)
- const lastClicked = plainOptions[0]
+ const highlightedOptions = options.slice(0, 1).map(({ value }) => value)
+ const lastClicked = options[0].value
it('should not change the highlighted options', () => {
- const option = plainOptions[0]
+ const option = options[0]
const expected = highlightedOptions
toggleRange({
@@ -79,37 +68,37 @@ describe('Transfer- useHighlightedOptions - toggleRange', () => {
highlightedOptions,
option,
setHighlightedOptions,
- reactOptions,
+ options,
})
expect(setHighlightedOptions).toHaveBeenCalledWith(expected)
})
it('should highlight all option from the highlighted one to the clicked one', () => {
- const expected = plainOptions.slice(0, 4)
+ const expected = options.slice(0, 4).map(({ value }) => value)
toggleRange({
- option: plainOptions[3],
+ option: options[3],
lastClicked,
maxSelections,
highlightedOptions,
setHighlightedOptions,
- reactOptions,
+ options,
})
expect(setHighlightedOptions).toHaveBeenCalledWith(expected)
})
it('should highlight from the lastClicked to the most recently clicked one', () => {
- const expected = plainOptions.slice(1, 4)
+ const expected = options.slice(1, 4).map(({ value }) => value)
toggleRange({
- option: plainOptions[3],
- lastClicked: plainOptions[1],
+ option: options[3],
+ lastClicked: options[1].value,
maxSelections,
highlightedOptions,
setHighlightedOptions,
- reactOptions,
+ options,
})
expect(setHighlightedOptions).toHaveBeenCalledWith(expected)
@@ -119,21 +108,18 @@ describe('Transfer- useHighlightedOptions - toggleRange', () => {
* E. g. lastClicked is hidden because of a filter change
*/
it('should highlight from the highest in list to the clicked when last clicked not visible anymore', () => {
- const expected = plainOptions.slice(1, 6)
+ const expected = options.slice(1, 6).map(({ value }) => value)
toggleRange({
- option: plainOptions[5],
- lastClicked: {
- value: 'not visible anymore',
- label: 'irrelevant',
- },
+ option: options[5],
+ lastClicked: 'not visible anymore',
maxSelections,
highlightedOptions: [
- ...plainOptions.slice(1, 2),
- ...plainOptions.slice(3, 5),
- ],
+ ...options.slice(1, 2),
+ ...options.slice(3, 5),
+ ].map(({ value }) => value),
setHighlightedOptions,
- reactOptions,
+ options,
})
expect(setHighlightedOptions).toHaveBeenCalledWith(expected)
@@ -144,18 +130,18 @@ describe('Transfer- useHighlightedOptions - toggleRange', () => {
* have been clicked with shift
*/
it('should highlight from the highest in list to the clicked when last clicked null', () => {
- const expected = plainOptions.slice(1, 6)
+ const expected = options.slice(1, 6).map(({ value }) => value)
toggleRange({
- option: plainOptions[5],
+ option: options[5],
lastClicked: null,
maxSelections,
highlightedOptions: [
- ...plainOptions.slice(1, 2),
- ...plainOptions.slice(3, 5),
- ],
+ ...options.slice(1, 2),
+ ...options.slice(3, 5),
+ ].map(({ value }) => value),
setHighlightedOptions,
- reactOptions,
+ options,
})
expect(setHighlightedOptions).toHaveBeenCalledWith(expected)
diff --git a/packages/core/src/Transfer/__tests__/helper/useHighlightedOption/toggleReplace.test.js b/packages/widgets/src/Transfer/__tests__/helper/useHighlightedOption/toggleReplace.test.js
similarity index 77%
rename from packages/core/src/Transfer/__tests__/helper/useHighlightedOption/toggleReplace.test.js
rename to packages/widgets/src/Transfer/__tests__/helper/useHighlightedOption/toggleReplace.test.js
index 59a129de95..9cfff0c590 100644
--- a/packages/core/src/Transfer/__tests__/helper/useHighlightedOption/toggleReplace.test.js
+++ b/packages/widgets/src/Transfer/__tests__/helper/useHighlightedOption/toggleReplace.test.js
@@ -1,4 +1,4 @@
-import { toggleReplace } from '../../../../Transfer/helper/useHighlightedOptions/toggleReplace.js'
+import { toggleReplace } from '../../../../Transfer/Transfer/useHighlightedOptions/toggleReplace.js'
describe('Transfer - useHighlightedOptions - toggleReplace', () => {
const setHighlightedOptions = jest.fn()
@@ -9,9 +9,9 @@ describe('Transfer - useHighlightedOptions - toggleReplace', () => {
describe('maxSelections=1', () => {
it('should replace the current highlighted option', () => {
- const highlightedOptions = [{ value: 'foo', label: 'Foo' }]
+ const highlightedOptions = ['foo']
const option = { value: 'bar', label: 'Bar' }
- const expected = [option]
+ const expected = [option.value]
toggleReplace({
highlightedOptions,
@@ -23,7 +23,7 @@ describe('Transfer - useHighlightedOptions - toggleReplace', () => {
})
it('should empty the highlighted options', () => {
- const highlightedOptions = [{ value: 'foo', label: 'Foo' }]
+ const highlightedOptions = ['foo']
const option = { value: 'foo', label: 'Foo' }
const expected = []
diff --git a/packages/core/src/Transfer/__tests__/helper/useHighlightedOptions.test.js b/packages/widgets/src/Transfer/__tests__/helper/useHighlightedOptions.test.js
similarity index 84%
rename from packages/core/src/Transfer/__tests__/helper/useHighlightedOptions.test.js
rename to packages/widgets/src/Transfer/__tests__/helper/useHighlightedOptions.test.js
index f20ebda6d6..8809d8fa50 100644
--- a/packages/core/src/Transfer/__tests__/helper/useHighlightedOptions.test.js
+++ b/packages/widgets/src/Transfer/__tests__/helper/useHighlightedOptions.test.js
@@ -1,8 +1,8 @@
-import { createToggleHighlightedOption } from '../../../Transfer/helper/useHighlightedOptions/createToggleHighlightedOption.js'
-import { useHighlightedOptions } from '../../../Transfer/helper/useHighlightedOptions.js'
+import { createToggleHighlightedOption } from '../../../Transfer/Transfer/useHighlightedOptions/createToggleHighlightedOption.js'
+import { useHighlightedOptions } from '../../../Transfer/Transfer/useHighlightedOptions.js'
jest.mock(
- '../../../Transfer/helper/useHighlightedOptions/createToggleHighlightedOption',
+ '../../../Transfer/Transfer/useHighlightedOptions/createToggleHighlightedOption',
() => ({
createToggleHighlightedOption: jest.fn(),
})
diff --git a/packages/widgets/src/Transfer/common/addOption.js b/packages/widgets/src/Transfer/common/addOption.js
new file mode 100644
index 0000000000..40e8e8e06b
--- /dev/null
+++ b/packages/widgets/src/Transfer/common/addOption.js
@@ -0,0 +1,12 @@
+import { findOption } from './findOption.js'
+
+/**
+ * @param {Object[]} options
+ * @param {Object} option
+ * @returns {Object}
+ */
+export const addOption = (options, option) => {
+ const found = findOption(options, option)
+ if (found) return options
+ return [...options, option]
+}
diff --git a/packages/widgets/src/Transfer/common/findOptionIndex.js b/packages/widgets/src/Transfer/common/findOptionIndex.js
new file mode 100644
index 0000000000..9a19e4f95d
--- /dev/null
+++ b/packages/widgets/src/Transfer/common/findOptionIndex.js
@@ -0,0 +1,9 @@
+import { isOption } from './isOption.js'
+
+/**
+ * @param {Object[]} options
+ * @param {Object} option
+ * @returns {Int}
+ */
+export const findOptionIndex = (options, option) =>
+ options.findIndex(current => isOption(current, option))
diff --git a/packages/widgets/src/Transfer/common/getModeByModifierKey.js b/packages/widgets/src/Transfer/common/getModeByModifierKey.js
new file mode 100644
index 0000000000..cd4dbbeb15
--- /dev/null
+++ b/packages/widgets/src/Transfer/common/getModeByModifierKey.js
@@ -0,0 +1,29 @@
+import { ADD_MODE, RANGE_MODE, REPLACE_MODE } from './modes.js'
+
+/**
+ * @param {Object} args
+ * @param {bool} args.altKey
+ * @param {bool} args.shiftKey
+ * @param {bool} args.ctrlKey
+ * @param {bool} args.metaKey
+ * @return {string}
+ */
+export const getModeByModifierKey = ({
+ altKey,
+ shiftKey,
+ ctrlKey,
+ metaKey,
+}) => {
+ const keys = [altKey, shiftKey, ctrlKey, metaKey]
+ const amountKeyPressed = keys.filter(v => v)
+ const moreThanOneKeyPressed = amountKeyPressed.length
+
+ if (moreThanOneKeyPressed !== 1) return REPLACE_MODE
+
+ if (altKey || ctrlKey || metaKey) return ADD_MODE
+
+ if (shiftKey) return RANGE_MODE
+
+ // default to replace mode
+ return REPLACE_MODE
+}
diff --git a/packages/widgets/src/Transfer/common/index.js b/packages/widgets/src/Transfer/common/index.js
new file mode 100644
index 0000000000..eafe245e1e
--- /dev/null
+++ b/packages/widgets/src/Transfer/common/index.js
@@ -0,0 +1,6 @@
+export { ADD_MODE, RANGE_MODE, REPLACE_MODE } from './modes.js'
+export { borderColor, borderRadius } from './styles.js'
+export { findOptionIndex } from './findOptionIndex.js'
+export { getModeByModifierKey } from './getModeByModifierKey.js'
+export { isOption } from './isOption.js'
+export { toggleValue } from './toggleValue.js'
diff --git a/packages/widgets/src/Transfer/common/isOption.js b/packages/widgets/src/Transfer/common/isOption.js
new file mode 100644
index 0000000000..b66213dbc1
--- /dev/null
+++ b/packages/widgets/src/Transfer/common/isOption.js
@@ -0,0 +1,7 @@
+/**
+ * @param {Object} left
+ * @param {Object} left
+ * @returns {bool}
+ */
+export const isOption = (left, right) =>
+ left.label === right.label && left.value === right.value
diff --git a/packages/widgets/src/Transfer/common/modes.js b/packages/widgets/src/Transfer/common/modes.js
new file mode 100644
index 0000000000..f837eed4be
--- /dev/null
+++ b/packages/widgets/src/Transfer/common/modes.js
@@ -0,0 +1,11 @@
+/**
+ * Click modes when clicking on an option with/without
+ * a modifier key (ctrl, alt, cmd, shift)
+ */
+
+// no or multiple modifier keys
+export const REPLACE_MODE = 'REPLACE_MODE'
+// add/remove options from selection
+export const ADD_MODE = 'ADD_MODE'
+// create selection range
+export const RANGE_MODE = 'RANGE_MODE'
diff --git a/packages/widgets/src/Transfer/common/removeOption.js b/packages/widgets/src/Transfer/common/removeOption.js
new file mode 100644
index 0000000000..4a9555a590
--- /dev/null
+++ b/packages/widgets/src/Transfer/common/removeOption.js
@@ -0,0 +1,15 @@
+import { findOptionIndex } from './findOptionIndex.js'
+
+/**
+ * @param {Object[]} options
+ * @param {Object} option
+ * @returns {Object}
+ */
+export const removeOption = (options, option) => {
+ const index = findOptionIndex(options, option)
+
+ if (index === -1) return options
+ if (index === 0) return options.slice(1)
+
+ return [...options.slice(0, index), ...options.slice(index + 1)]
+}
diff --git a/packages/widgets/src/Transfer/common/styles.js b/packages/widgets/src/Transfer/common/styles.js
new file mode 100644
index 0000000000..5451a45b6d
--- /dev/null
+++ b/packages/widgets/src/Transfer/common/styles.js
@@ -0,0 +1,4 @@
+import { colors } from '@dhis2/ui-constants'
+
+export const borderColor = colors.grey400
+export const borderRadius = '3px'
diff --git a/packages/widgets/src/Transfer/common/toggleValue.js b/packages/widgets/src/Transfer/common/toggleValue.js
new file mode 100644
index 0000000000..ab5fdbe36c
--- /dev/null
+++ b/packages/widgets/src/Transfer/common/toggleValue.js
@@ -0,0 +1,18 @@
+/**
+ * @param {string[]} values
+ * @param {string} value
+ * @returns {string[]}
+ */
+export const toggleValue = (values, value) => {
+ const index = values.indexOf(value)
+
+ if (index === -1) {
+ return [...values, value]
+ } else if (index === 0) {
+ values.slice(1)
+ }
+
+ const prevSlice = values.slice(0, index)
+ const nextSlice = values.slice(index + 1)
+ return [...prevSlice, ...nextSlice]
+}
diff --git a/packages/core/src/Transfer/icons.js b/packages/widgets/src/Transfer/icons.js
similarity index 100%
rename from packages/core/src/Transfer/icons.js
rename to packages/widgets/src/Transfer/icons.js
diff --git a/packages/widgets/src/index.js b/packages/widgets/src/index.js
index eddd92d94d..95d59460de 100755
--- a/packages/widgets/src/index.js
+++ b/packages/widgets/src/index.js
@@ -10,3 +10,5 @@ export { MultiSelectField } from './MultiSelectField/MultiSelectField.js'
export { SingleSelectField } from './SingleSelectField/SingleSelectField.js'
export { SwitchField } from './SwitchField/SwitchField.js'
export { TextAreaField } from './TextAreaField/TextAreaField.js'
+export { Transfer } from './Transfer/Transfer.js'
+export { TransferOption } from './Transfer/TransferOption.js'