diff --git a/platform/ui/index.js b/platform/ui/index.js
index 853de0534..164ee9850 100644
--- a/platform/ui/index.js
+++ b/platform/ui/index.js
@@ -15,6 +15,10 @@ export {
Button,
ButtonGroup,
DateRange,
+ InputDateRange,
+ InputMultiSelect,
+ InputText,
+ InputLabelWrapper,
EmptyStudies,
Icon,
IconButton,
diff --git a/platform/ui/src/components/InputDateRange/InputDateRange.jsx b/platform/ui/src/components/InputDateRange/InputDateRange.jsx
new file mode 100644
index 000000000..3424ab01f
--- /dev/null
+++ b/platform/ui/src/components/InputDateRange/InputDateRange.jsx
@@ -0,0 +1,52 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import { DateRange, InputLabelWrapper } from '@ohif/ui';
+
+const InputDateRange = ({
+ label,
+ isSortable,
+ sortDirection,
+ onLabelClick,
+ value,
+ onChange,
+}) => {
+ const { startDate, endDate } = value;
+ return (
+
+
+
+
+
+ );
+};
+
+InputDateRange.defaultProps = {
+ value: {},
+};
+
+InputDateRange.propTypes = {
+ label: PropTypes.string.isRequired,
+ isSortable: PropTypes.bool.isRequired,
+ sortDirection: PropTypes.oneOf(['ascending', 'descending', 'none'])
+ .isRequired,
+ onLabelClick: PropTypes.func.isRequired,
+ value: PropTypes.shape({
+ /** Start date moment object */
+ startDate: PropTypes.object, // moment date is an object
+ /** End date moment object */
+ endDate: PropTypes.object, // moment date is an object
+ }),
+ onChange: PropTypes.func.isRequired,
+};
+
+export default InputDateRange;
diff --git a/platform/ui/src/components/InputDateRange/InputDateRange.mdx b/platform/ui/src/components/InputDateRange/InputDateRange.mdx
new file mode 100644
index 000000000..c7458d8ae
--- /dev/null
+++ b/platform/ui/src/components/InputDateRange/InputDateRange.mdx
@@ -0,0 +1,43 @@
+---
+name: InputDateRange
+menu: Components
+route: components/InputDateRange
+---
+
+import { useState } from 'react';
+import { Playground, Props } from 'docz';
+import InputDateRange from './';
+
+# Input Date Range
+
+## Import
+
+```javascript
+import { InputDateRange } from '@ohif/ui';
+```
+
+## Basic usage
+
+
+ {() => {
+ const [dates, setDates] = useState({
+ startDate: null,
+ endDate: null,
+ });
+ return (
+
+
+ setDates(dates)}
+ />
+
+
+ );
+ }}
+
+
+## Properties
+
+
diff --git a/platform/ui/src/components/InputDateRange/index.js b/platform/ui/src/components/InputDateRange/index.js
new file mode 100644
index 000000000..b620c15bf
--- /dev/null
+++ b/platform/ui/src/components/InputDateRange/index.js
@@ -0,0 +1,2 @@
+import InputDateRange from './InputDateRange';
+export default InputDateRange;
diff --git a/platform/ui/src/components/InputLabelWrapper/InputLabelWrapper.jsx b/platform/ui/src/components/InputLabelWrapper/InputLabelWrapper.jsx
new file mode 100644
index 000000000..710555ba7
--- /dev/null
+++ b/platform/ui/src/components/InputLabelWrapper/InputLabelWrapper.jsx
@@ -0,0 +1,63 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import classnames from 'classnames';
+
+import { Icon } from '@ohif/ui';
+
+const baseLabelClassName =
+ 'flex flex-col flex-1 text-white text-lg pl-1 select-none';
+const spanClassName = 'flex flex-row items-center cursor-pointer';
+const sortIconMap = {
+ ascending: 'sorting-active-up',
+ descending: 'sorting-active-down',
+ none: 'sorting',
+};
+
+const InputLabelWrapper = ({
+ label,
+ isSortable,
+ sortDirection,
+ onLabelClick,
+ className,
+ children,
+}) => {
+ return (
+
+ );
+};
+
+InputLabelWrapper.defaultProps = {
+ className: '',
+};
+
+InputLabelWrapper.propTypes = {
+ label: PropTypes.string.isRequired,
+ isSortable: PropTypes.bool.isRequired,
+ sortDirection: PropTypes.oneOf(['ascending', 'descending', 'none'])
+ .isRequired,
+ onLabelClick: PropTypes.func.isRequired,
+ className: PropTypes.string,
+ children: PropTypes.node,
+};
+
+export default InputLabelWrapper;
diff --git a/platform/ui/src/components/InputLabelWrapper/index.js b/platform/ui/src/components/InputLabelWrapper/index.js
new file mode 100644
index 000000000..fc2667073
--- /dev/null
+++ b/platform/ui/src/components/InputLabelWrapper/index.js
@@ -0,0 +1,2 @@
+import InputLabelWrapper from './InputLabelWrapper';
+export default InputLabelWrapper;
diff --git a/platform/ui/src/components/InputMultiSelect/InputMultiSelect.jsx b/platform/ui/src/components/InputMultiSelect/InputMultiSelect.jsx
new file mode 100644
index 000000000..69008dded
--- /dev/null
+++ b/platform/ui/src/components/InputMultiSelect/InputMultiSelect.jsx
@@ -0,0 +1,84 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import { Select, InputLabelWrapper } from '@ohif/ui';
+
+const InputMultiSelect = ({
+ label,
+ isSortable,
+ sortDirection,
+ onLabelClick,
+ value,
+ placeholder,
+ options,
+ onChange,
+}) => {
+ return (
+
+
+ );
+};
+
+InputMultiSelect.defaultProps = {
+ value: [],
+ placeholder: '',
+ options: [],
+};
+
+InputMultiSelect.propTypes = {
+ label: PropTypes.string.isRequired,
+ isSortable: PropTypes.bool.isRequired,
+ sortDirection: PropTypes.oneOf(['ascending', 'descending', 'none'])
+ .isRequired,
+ onLabelClick: PropTypes.func.isRequired,
+ placeholder: PropTypes.string,
+ options: PropTypes.arrayOf(
+ PropTypes.shape({
+ value: PropTypes.string,
+ label: PropTypes.string,
+ })
+ ),
+ value: PropTypes.oneOfType([
+ PropTypes.arrayOf(
+ PropTypes.shape({
+ value: PropTypes.string,
+ label: PropTypes.string,
+ })
+ ),
+ PropTypes.shape({
+ value: PropTypes.string,
+ label: PropTypes.string,
+ }),
+ ]),
+ onChange: PropTypes.func.isRequired,
+};
+
+export default InputMultiSelect;
diff --git a/platform/ui/src/components/InputMultiSelect/InputMultiSelect.mdx b/platform/ui/src/components/InputMultiSelect/InputMultiSelect.mdx
new file mode 100644
index 000000000..c8b3f42ee
--- /dev/null
+++ b/platform/ui/src/components/InputMultiSelect/InputMultiSelect.mdx
@@ -0,0 +1,48 @@
+---
+name: InputMultiSelect
+menu: Components
+route: components/InputMultiSelect
+---
+
+import { useState } from 'react';
+import { Playground, Props } from 'docz';
+import InputMultiSelect from './';
+
+# Input Multi Select
+
+## Import
+
+```javascript
+import { InputMultiSelect } from '@ohif/ui';
+```
+
+## Basic usage
+
+
+ {() => {
+ const [values, setValues] = useState([]);
+ return (
+
+
+ {
+ setValues(values);
+ }}
+ />
+
+
+ );
+ }}
+
+
+## Properties
+
+
diff --git a/platform/ui/src/components/InputMultiSelect/index.js b/platform/ui/src/components/InputMultiSelect/index.js
new file mode 100644
index 000000000..ecb6011ad
--- /dev/null
+++ b/platform/ui/src/components/InputMultiSelect/index.js
@@ -0,0 +1,2 @@
+import InputMultiSelect from './InputMultiSelect';
+export default InputMultiSelect;
diff --git a/platform/ui/src/components/InputText/InputText.jsx b/platform/ui/src/components/InputText/InputText.jsx
new file mode 100644
index 000000000..7fd1a6827
--- /dev/null
+++ b/platform/ui/src/components/InputText/InputText.jsx
@@ -0,0 +1,48 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import { Input, InputLabelWrapper } from '@ohif/ui';
+
+const InputText = ({
+ label,
+ isSortable,
+ sortDirection,
+ onLabelClick,
+ value,
+ onChange,
+}) => {
+ return (
+
+ {
+ onChange(event.target.value);
+ }}
+ />
+
+ );
+};
+
+InputText.defaultProps = {
+ value: '',
+};
+
+InputText.propTypes = {
+ label: PropTypes.string.isRequired,
+ isSortable: PropTypes.bool.isRequired,
+ sortDirection: PropTypes.oneOf(['ascending', 'descending', 'none'])
+ .isRequired,
+ onLabelClick: PropTypes.func.isRequired,
+ value: PropTypes.string,
+ onChange: PropTypes.func.isRequired,
+};
+
+export default InputText;
diff --git a/platform/ui/src/components/InputText/InputText.mdx b/platform/ui/src/components/InputText/InputText.mdx
new file mode 100644
index 000000000..8f7d27b27
--- /dev/null
+++ b/platform/ui/src/components/InputText/InputText.mdx
@@ -0,0 +1,41 @@
+---
+name: InputText
+menu: Components
+route: components/InputText
+---
+
+import { useState } from 'react';
+import { Playground, Props } from 'docz';
+import InputText from './';
+
+# Input Text
+
+## Import
+
+```javascript
+import { InputText } from '@ohif/ui';
+```
+
+## Basic usage
+
+
+ {() => {
+ const [text, setText] = useState('');
+ return (
+
+
+ {setText(value)}}
+ />
+
+
+ )
+ }}
+
+
+
+## Properties
+
+
diff --git a/platform/ui/src/components/InputText/index.js b/platform/ui/src/components/InputText/index.js
new file mode 100644
index 000000000..174f89fe1
--- /dev/null
+++ b/platform/ui/src/components/InputText/index.js
@@ -0,0 +1,2 @@
+import InputText from './InputText';
+export default InputText;
diff --git a/platform/ui/src/components/Select/Select.css b/platform/ui/src/components/Select/Select.css
index f20565142..694bb287c 100644
--- a/platform/ui/src/components/Select/Select.css
+++ b/platform/ui/src/components/Select/Select.css
@@ -6,12 +6,13 @@
@apply border-gray-500;
}
-.customSelect__wrapper .customSelect__control:focus {
+.customSelect__wrapper .customSelect__control:focus,
+.customSelect__wrapper .customSelect__control--menu-is-open {
@apply border-gray-500 outline-none;
}
-.customSelect__wrapper .customSelect__control--menu-is-open {
- @apply border-gray-500 outline-none;
+.customSelect--is-disabled .customSelect__control--is-disabled {
+ @apply pointer-events-none;
}
.customSelect__wrapper .customSelect__indicator-separator {
@@ -23,17 +24,25 @@
}
.customSelect__wrapper .customSelect__option {
- @apply text-black;
+ @apply text-black flex flex-row items-center;
+}
+
+.customSelect__wrapper .customSelect__option:focus {
+ @apply bg-custom-blue;
+}
+
+.customSelect__wrapper .customSelect__option--is-selected {
+ @apply bg-transparent;
}
.customSelect__wrapper .customSelect__single-value {
@apply text-white;
}
-.customSelect--is-disabled .customSelect__control--is-disabled {
- @apply pointer-events-none;
-}
-
.customSelect__wrapper.customSelect--is-disabled {
@apply cursor-not-allowed pointer-events-auto;
}
+
+.customSelect__wrapper .customSelect__value-container--is-multi {
+ @apply px-3 py-2 inline-block truncate;
+}
diff --git a/platform/ui/src/components/Select/Select.jsx b/platform/ui/src/components/Select/Select.jsx
index 04a513c2d..c8c84638a 100644
--- a/platform/ui/src/components/Select/Select.jsx
+++ b/platform/ui/src/components/Select/Select.jsx
@@ -1,52 +1,93 @@
import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
-import ReactSelect from 'react-select';
+import ReactSelect, { components } from 'react-select';
import './Select.css';
+const MultiValue = props => {
+ const values = props.selectProps.value;
+ const lastValue = values[values.length - 1];
+ let label = props.data.label;
+ if (lastValue.label !== label) {
+ label += ', ';
+ }
+
+ return {label};
+};
+
+const Option = props => {
+ return (
+
+
+ null}
+ />
+
+
+
+ );
+};
+
const Select = ({
- autoFocus,
className,
+ closeMenuOnSelect,
+ hideSelectedOptions,
+ isClearable,
isDisabled,
isMulti,
isSearchable,
- name,
onChange,
options,
placeholder,
- noOptionsMessage,
value,
}) => {
+ const _components = isMulti ? { Option, MultiValue } : {};
+
return (
);
};
+Select.defaultProps = {
+ className: '',
+ closeMenuOnSelect: true,
+ hideSelectedOptions: true,
+ isClearable: true,
+ isDisabled: false,
+ isMulti: false,
+ isSearchable: true,
+};
+
Select.propTypes = {
- autoFocus: PropTypes.bool,
className: PropTypes.string,
+ closeMenuOnSelect: PropTypes.bool,
+ hideSelectedOptions: PropTypes.bool,
+ isClearable: PropTypes.bool,
isDisabled: PropTypes.bool,
isMulti: PropTypes.bool,
isSearchable: PropTypes.bool,
- name: PropTypes.string,
- onChange: PropTypes.func,
+ onChange: PropTypes.func.isRequired,
options: PropTypes.arrayOf(
PropTypes.shape({
value: PropTypes.string,
@@ -54,8 +95,18 @@ Select.propTypes = {
})
),
placeholder: PropTypes.string,
- noOptionsMessage: PropTypes.func,
- value: PropTypes.string,
+ value: PropTypes.oneOfType([
+ PropTypes.arrayOf(
+ PropTypes.shape({
+ value: PropTypes.string,
+ label: PropTypes.string,
+ })
+ ),
+ PropTypes.shape({
+ value: PropTypes.string,
+ label: PropTypes.string,
+ }),
+ ]),
};
export default Select;
diff --git a/platform/ui/src/components/Select/Select.mdx b/platform/ui/src/components/Select/Select.mdx
index 29ab9701c..1a8f732f7 100644
--- a/platform/ui/src/components/Select/Select.mdx
+++ b/platform/ui/src/components/Select/Select.mdx
@@ -19,13 +19,13 @@ import { Select } from '@ohif/ui';
-
+
@@ -36,14 +36,14 @@ import { Select } from '@ohif/ui';
-
+
@@ -54,7 +54,7 @@ import { Select } from '@ohif/ui';
-
+
- {isFiltering() && (
+ {isFiltering(currentFiltersValues, filtersValues) && (
@@ -275,20 +220,24 @@ const StudyListFilter = ({
);
};
+StudyListFilter.defaultProps = {
+ filtersMeta: [],
+ filtersValues: {},
+ numOfStudies: 0,
+};
+
StudyListFilter.propTypes = {
filtersMeta: PropTypes.arrayOf(
PropTypes.shape({
name: PropTypes.string,
dsplayName: PropTypes.string,
- inputType: PropTypes.oneOf(['text', 'select', 'date-range', 'none']),
+ inputType: PropTypes.oneOf(['Text', 'MultiSelect', 'DateRange', 'None']),
isSortable: PropTypes.bool,
gridCol: PropTypes.oneOf([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]),
})
),
filtersValues: PropTypes.object,
numOfStudies: PropTypes.number,
- startDate: PropTypes.string,
- endDate: PropTypes.string,
};
export default StudyListFilter;