web: Components: Split AdvancedSelector to several parts + added InfinitLoader
This commit is contained in:
parent
821f804ccd
commit
d2cca81175
@ -1802,7 +1802,7 @@ asap@~2.0.6:
|
|||||||
integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
|
integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
|
||||||
|
|
||||||
"asc-web-components@file:../../../packages/asc-web-components":
|
"asc-web-components@file:../../../packages/asc-web-components":
|
||||||
version "1.0.102"
|
version "1.0.147"
|
||||||
dependencies:
|
dependencies:
|
||||||
moment "^2.24.0"
|
moment "^2.24.0"
|
||||||
prop-types "^15.7.2"
|
prop-types "^15.7.2"
|
||||||
@ -1813,6 +1813,7 @@ asap@~2.0.6:
|
|||||||
react-dropzone "^10.1.8"
|
react-dropzone "^10.1.8"
|
||||||
react-text-mask "^5.4.3"
|
react-text-mask "^5.4.3"
|
||||||
react-toastify "^5.3.2"
|
react-toastify "^5.3.2"
|
||||||
|
react-tooltip "^3.11.1"
|
||||||
react-virtualized-auto-sizer "^1.0.2"
|
react-virtualized-auto-sizer "^1.0.2"
|
||||||
react-window "^1.8.5"
|
react-window "^1.8.5"
|
||||||
reactstrap "^8.0.1"
|
reactstrap "^8.0.1"
|
||||||
@ -2619,7 +2620,7 @@ class-utils@^0.3.5:
|
|||||||
isobject "^3.0.0"
|
isobject "^3.0.0"
|
||||||
static-extend "^0.1.1"
|
static-extend "^0.1.1"
|
||||||
|
|
||||||
classnames@2.x, classnames@^2.2.3, classnames@^2.2.6:
|
classnames@2.x, classnames@^2.2.3, classnames@^2.2.5, classnames@^2.2.6:
|
||||||
version "2.2.6"
|
version "2.2.6"
|
||||||
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
|
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
|
||||||
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
|
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
|
||||||
@ -8518,7 +8519,7 @@ prompts@^2.0.1:
|
|||||||
kleur "^3.0.3"
|
kleur "^3.0.3"
|
||||||
sisteransi "^1.0.3"
|
sisteransi "^1.0.3"
|
||||||
|
|
||||||
prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.8, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
|
prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||||
version "15.7.2"
|
version "15.7.2"
|
||||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||||
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
||||||
@ -8971,6 +8972,14 @@ react-toastify@^5.3.2:
|
|||||||
prop-types "^15.7.2"
|
prop-types "^15.7.2"
|
||||||
react-transition-group "^2.6.1"
|
react-transition-group "^2.6.1"
|
||||||
|
|
||||||
|
react-tooltip@^3.11.1:
|
||||||
|
version "3.11.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-tooltip/-/react-tooltip-3.11.1.tgz#7b4ce48ed26a46e996662b19a2afebbfd483513b"
|
||||||
|
integrity sha512-YCMVlEC2KuHIzOQhPplTK5jmBBwoL+PYJJdJKXj7M/h7oevupd/QSVq6z5U7/ehIGXyHsAqvwpdxexDfyQ0o3A==
|
||||||
|
dependencies:
|
||||||
|
classnames "^2.2.5"
|
||||||
|
prop-types "^15.6.0"
|
||||||
|
|
||||||
react-transition-group@^2.3.1, react-transition-group@^2.6.1:
|
react-transition-group@^2.3.1, react-transition-group@^2.6.1:
|
||||||
version "2.9.0"
|
version "2.9.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
|
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
|
||||||
|
@ -1802,7 +1802,7 @@ asap@~2.0.6:
|
|||||||
integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
|
integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=
|
||||||
|
|
||||||
"asc-web-components@file:../../packages/asc-web-components":
|
"asc-web-components@file:../../packages/asc-web-components":
|
||||||
version "1.0.116"
|
version "1.0.147"
|
||||||
dependencies:
|
dependencies:
|
||||||
moment "^2.24.0"
|
moment "^2.24.0"
|
||||||
prop-types "^15.7.2"
|
prop-types "^15.7.2"
|
||||||
@ -1813,6 +1813,7 @@ asap@~2.0.6:
|
|||||||
react-dropzone "^10.1.8"
|
react-dropzone "^10.1.8"
|
||||||
react-text-mask "^5.4.3"
|
react-text-mask "^5.4.3"
|
||||||
react-toastify "^5.3.2"
|
react-toastify "^5.3.2"
|
||||||
|
react-tooltip "^3.11.1"
|
||||||
react-virtualized-auto-sizer "^1.0.2"
|
react-virtualized-auto-sizer "^1.0.2"
|
||||||
react-window "^1.8.5"
|
react-window "^1.8.5"
|
||||||
reactstrap "^8.0.1"
|
reactstrap "^8.0.1"
|
||||||
@ -2619,7 +2620,7 @@ class-utils@^0.3.5:
|
|||||||
isobject "^3.0.0"
|
isobject "^3.0.0"
|
||||||
static-extend "^0.1.1"
|
static-extend "^0.1.1"
|
||||||
|
|
||||||
classnames@2.x, classnames@^2.2.3, classnames@^2.2.6:
|
classnames@2.x, classnames@^2.2.3, classnames@^2.2.5, classnames@^2.2.6:
|
||||||
version "2.2.6"
|
version "2.2.6"
|
||||||
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
|
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
|
||||||
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
|
integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q==
|
||||||
@ -3736,11 +3737,6 @@ elliptic@^6.0.0:
|
|||||||
minimalistic-assert "^1.0.0"
|
minimalistic-assert "^1.0.0"
|
||||||
minimalistic-crypto-utils "^1.0.0"
|
minimalistic-crypto-utils "^1.0.0"
|
||||||
|
|
||||||
email-addresses@^3.0.3:
|
|
||||||
version "3.0.3"
|
|
||||||
resolved "https://registry.yarnpkg.com/email-addresses/-/email-addresses-3.0.3.tgz#fc3c6952f68da24239914e982c8a7783bc2ed96d"
|
|
||||||
integrity sha512-kUlSC06PVvvjlMRpNIl3kR1NRXLEe86VQ7N0bQeaCZb2g+InShCeHQp/JvyYNTugMnRN2NvJhHlc3q12MWbbpg==
|
|
||||||
|
|
||||||
emoji-regex@^7.0.1, emoji-regex@^7.0.2:
|
emoji-regex@^7.0.1, emoji-regex@^7.0.2:
|
||||||
version "7.0.3"
|
version "7.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
|
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
|
||||||
@ -8516,7 +8512,7 @@ prompts@^2.0.1:
|
|||||||
kleur "^3.0.3"
|
kleur "^3.0.3"
|
||||||
sisteransi "^1.0.3"
|
sisteransi "^1.0.3"
|
||||||
|
|
||||||
prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.8, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
|
prop-types@15.x, prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.6, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2:
|
||||||
version "15.7.2"
|
version "15.7.2"
|
||||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||||
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
|
||||||
@ -8964,6 +8960,14 @@ react-toastify@^5.3.2:
|
|||||||
prop-types "^15.7.2"
|
prop-types "^15.7.2"
|
||||||
react-transition-group "^2.6.1"
|
react-transition-group "^2.6.1"
|
||||||
|
|
||||||
|
react-tooltip@^3.11.1:
|
||||||
|
version "3.11.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-tooltip/-/react-tooltip-3.11.1.tgz#7b4ce48ed26a46e996662b19a2afebbfd483513b"
|
||||||
|
integrity sha512-YCMVlEC2KuHIzOQhPplTK5jmBBwoL+PYJJdJKXj7M/h7oevupd/QSVq6z5U7/ehIGXyHsAqvwpdxexDfyQ0o3A==
|
||||||
|
dependencies:
|
||||||
|
classnames "^2.2.5"
|
||||||
|
prop-types "^15.6.0"
|
||||||
|
|
||||||
react-transition-group@^2.3.1, react-transition-group@^2.6.1:
|
react-transition-group@^2.3.1, react-transition-group@^2.6.1:
|
||||||
version "2.9.0"
|
version "2.9.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
|
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.9.0.tgz#df9cdb025796211151a436c69a8f3b97b5b07c8d"
|
||||||
|
@ -71,6 +71,7 @@
|
|||||||
"enzyme-adapter-react-16": "^1.14.0",
|
"enzyme-adapter-react-16": "^1.14.0",
|
||||||
"eslint": "^6.3.0",
|
"eslint": "^6.3.0",
|
||||||
"eslint-plugin-react": "^7.14.3",
|
"eslint-plugin-react": "^7.14.3",
|
||||||
|
"faker": "^4.1.0",
|
||||||
"jest": "^24.8.0",
|
"jest": "^24.8.0",
|
||||||
"jest-enzyme": "^7.1.0",
|
"jest-enzyme": "^7.1.0",
|
||||||
"jest-junit": "^8.0.0",
|
"jest-junit": "^8.0.0",
|
||||||
@ -114,6 +115,7 @@
|
|||||||
"react-tooltip": "^3.11.1",
|
"react-tooltip": "^3.11.1",
|
||||||
"react-virtualized-auto-sizer": "^1.0.2",
|
"react-virtualized-auto-sizer": "^1.0.2",
|
||||||
"react-window": "^1.8.5",
|
"react-window": "^1.8.5",
|
||||||
|
"react-window-infinite-loader": "^1.0.5",
|
||||||
"reactstrap": "^8.0.1"
|
"reactstrap": "^8.0.1"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
/* eslint-disable react/prop-types */
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { storiesOf } from "@storybook/react";
|
import { storiesOf } from "@storybook/react";
|
||||||
import { action } from '@storybook/addon-actions';
|
import { action } from '@storybook/addon-actions';
|
||||||
@ -6,8 +7,11 @@ import withReadme from "storybook-readme/with-readme";
|
|||||||
import Readme from "./README.md";
|
import Readme from "./README.md";
|
||||||
import AdvancedSelector from "./";
|
import AdvancedSelector from "./";
|
||||||
import Section from "../../../.storybook/decorators/section";
|
import Section from "../../../.storybook/decorators/section";
|
||||||
import { ArrayValue, BooleanValue } from "react-values";
|
import { BooleanValue } from "react-values";
|
||||||
import Button from "../button";
|
import Button from "../button";
|
||||||
|
import { isEqual } from "lodash";
|
||||||
|
import faker, { name } from "faker";
|
||||||
|
import { slice } from "lodash/slice";
|
||||||
|
|
||||||
function getRandomInt(min, max) {
|
function getRandomInt(min, max) {
|
||||||
return Math.floor(Math.random() * (max - min)) + min;
|
return Math.floor(Math.random() * (max - min)) + min;
|
||||||
@ -79,12 +83,28 @@ const groups = [
|
|||||||
const sizes = ["compact", "full"];
|
const sizes = ["compact", "full"];
|
||||||
const displayTypes = ['dropdown', 'aside'];
|
const displayTypes = ['dropdown', 'aside'];
|
||||||
|
|
||||||
storiesOf("Components|AdvancedSelector", module)
|
|
||||||
.addDecorator(withKnobs)
|
class ExampleList extends React.Component {
|
||||||
.addDecorator(withReadme(Readme))
|
constructor(props) {
|
||||||
.add("base", () => {
|
super(props);
|
||||||
const optionsCount = number("Users count", 1000);
|
|
||||||
const options = Array.from({ length: optionsCount }, (v, index) => {
|
const { total, isOpen } = props;
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
isOpen: isOpen,
|
||||||
|
total: total,
|
||||||
|
options: [],
|
||||||
|
hasNextPage: false,
|
||||||
|
isNextPageLoading: false
|
||||||
|
}
|
||||||
|
|
||||||
|
faker.seed(123);
|
||||||
|
this.persons = new Array(50)
|
||||||
|
.fill(true)
|
||||||
|
.map(() => ({ name: name.findName() }));
|
||||||
|
this.persons.sort((a, b) => a.name.localeCompare(b.name));
|
||||||
|
|
||||||
|
this.AllOptions = Array.from({ length: this.state.total }, (v, index) => {
|
||||||
const additional_group = groups[getRandomInt(1, 6)];
|
const additional_group = groups[getRandomInt(1, 6)];
|
||||||
groups[0].total++;
|
groups[0].total++;
|
||||||
additional_group.total++;
|
additional_group.total++;
|
||||||
@ -95,6 +115,115 @@ storiesOf("Components|AdvancedSelector", module)
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
console.log(this.persons);
|
||||||
|
}
|
||||||
|
|
||||||
|
loadNextPage = (startIndex, stopIndex) => {
|
||||||
|
this.setState({ isNextPageLoading: true });
|
||||||
|
|
||||||
|
const promise = new Promise((resolve) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.setState({
|
||||||
|
hasNextPage: this.AllOptions.length < 100,
|
||||||
|
isNextPageLoading: false
|
||||||
|
});
|
||||||
|
|
||||||
|
resolve(slice(this.AllOptions, startIndex, stopIndex - startIndex));
|
||||||
|
}, 2500);
|
||||||
|
});
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
const {total, options, isOpen} = this.props;
|
||||||
|
if(!isEqual(prevProps.options, options))
|
||||||
|
{
|
||||||
|
this.setState({
|
||||||
|
options: options
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(isOpen !== prevProps.isOpen) {
|
||||||
|
this.setState({
|
||||||
|
isOpen: isOpen
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if(total !== prevProps.total) {
|
||||||
|
this.setState({
|
||||||
|
total: total,
|
||||||
|
option: []
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { isOpen, options, total, hasNextPage, isNextPageLoading } = this.state;
|
||||||
|
return (
|
||||||
|
<AdvancedSelector
|
||||||
|
size={select("size", sizes, "full")}
|
||||||
|
placeholder={text("placeholder", "Search users")}
|
||||||
|
onSearchChanged={value => {
|
||||||
|
action("onSearchChanged")(value);
|
||||||
|
/*set(
|
||||||
|
options.filter(option => {
|
||||||
|
return option.label.indexOf(value) > -1;
|
||||||
|
})
|
||||||
|
);*/
|
||||||
|
}}
|
||||||
|
//options={options}
|
||||||
|
total={total}
|
||||||
|
hasNextPage={hasNextPage}
|
||||||
|
isNextPageLoading={isNextPageLoading}
|
||||||
|
loadNextPage={this.loadNextPage}
|
||||||
|
groups={groups}
|
||||||
|
selectedGroups={[groups[0]]}
|
||||||
|
isMultiSelect={boolean("isMultiSelect", true)}
|
||||||
|
buttonLabel={text("buttonLabel", "Add members")}
|
||||||
|
selectAllLabel={text("selectAllLabel", "Select all")}
|
||||||
|
onSelect={selectedOptions => {
|
||||||
|
action("onSelect")(selectedOptions);
|
||||||
|
//toggle();
|
||||||
|
}}
|
||||||
|
//onCancel={toggle}
|
||||||
|
onChangeGroup={group => {
|
||||||
|
/*set(
|
||||||
|
options.filter(option => {
|
||||||
|
return (
|
||||||
|
option.groups &&
|
||||||
|
option.groups.length > 0 &&
|
||||||
|
option.groups.indexOf(group.key) > -1
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);*/
|
||||||
|
}}
|
||||||
|
allowCreation={boolean("allowCreation", false)}
|
||||||
|
onAddNewClick={() => action("onSelect") }
|
||||||
|
isOpen={isOpen}
|
||||||
|
displayType={select("displayType", displayTypes, "dropdown")}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
storiesOf("Components|AdvancedSelector", module)
|
||||||
|
.addDecorator(withKnobs)
|
||||||
|
.addDecorator(withReadme(Readme))
|
||||||
|
.add("base", () => {
|
||||||
|
/*const optionsCount = number("Users count", 1000);
|
||||||
|
const options = Array.from({ length: optionsCount }, (v, index) => {
|
||||||
|
const additional_group = groups[getRandomInt(1, 6)];
|
||||||
|
groups[0].total++;
|
||||||
|
additional_group.total++;
|
||||||
|
return {
|
||||||
|
key: `user${index}`,
|
||||||
|
groups: ["group-all", additional_group.key],
|
||||||
|
label: `User${index + 1} (All groups, ${additional_group.label})`
|
||||||
|
};
|
||||||
|
});*/
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Section>
|
<Section>
|
||||||
<BooleanValue
|
<BooleanValue
|
||||||
@ -104,52 +233,8 @@ storiesOf("Components|AdvancedSelector", module)
|
|||||||
{({ value: isOpen, toggle }) => (
|
{({ value: isOpen, toggle }) => (
|
||||||
<div style={{position: "relative"}}>
|
<div style={{position: "relative"}}>
|
||||||
<Button label="Toggle dropdown" onClick={toggle} />
|
<Button label="Toggle dropdown" onClick={toggle} />
|
||||||
<ArrayValue
|
<ExampleList isOpen={isOpen} total={number("Users count", 1000)} />
|
||||||
defaultValue={options}
|
</div>
|
||||||
onChange={() => action("options onChange")}
|
|
||||||
>
|
|
||||||
{({ value, set }) => (
|
|
||||||
<AdvancedSelector
|
|
||||||
size={select("size", sizes, "full")}
|
|
||||||
placeholder={text("placeholder", "Search users")}
|
|
||||||
onSearchChanged={value => {
|
|
||||||
action("onSearchChanged")(value);
|
|
||||||
set(
|
|
||||||
options.filter(option => {
|
|
||||||
return option.label.indexOf(value) > -1;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
options={value}
|
|
||||||
groups={groups}
|
|
||||||
selectedGroups={[groups[0]]}
|
|
||||||
isMultiSelect={boolean("isMultiSelect", true)}
|
|
||||||
buttonLabel={text("buttonLabel", "Add members")}
|
|
||||||
selectAllLabel={text("selectAllLabel", "Select all")}
|
|
||||||
onSelect={selectedOptions => {
|
|
||||||
action("onSelect")(selectedOptions);
|
|
||||||
toggle();
|
|
||||||
}}
|
|
||||||
onCancel={toggle}
|
|
||||||
onChangeGroup={group => {
|
|
||||||
set(
|
|
||||||
options.filter(option => {
|
|
||||||
return (
|
|
||||||
option.groups &&
|
|
||||||
option.groups.length > 0 &&
|
|
||||||
option.groups.indexOf(group.key) > -1
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
allowCreation={boolean("allowCreation", false)}
|
|
||||||
onAddNewClick={() => action("onSelect") }
|
|
||||||
isOpen={isOpen}
|
|
||||||
displayType={select("displayType", displayTypes, "dropdown")}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</ArrayValue>
|
|
||||||
</div>
|
|
||||||
)}
|
)}
|
||||||
</BooleanValue>
|
</BooleanValue>
|
||||||
</Section>
|
</Section>
|
||||||
|
@ -1,574 +1,24 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import styled, { css } from "styled-components";
|
|
||||||
import PropTypes from "prop-types";
|
import PropTypes from "prop-types";
|
||||||
import SearchInput from "../search-input";
|
|
||||||
import CustomScrollbarsVirtualList from "../scrollbar/custom-scrollbars-virtual-list";
|
|
||||||
import { FixedSizeList } from "react-window";
|
|
||||||
import Link from "../link";
|
|
||||||
import Checkbox from "../checkbox";
|
|
||||||
import Button from "../button";
|
|
||||||
import { Icons } from "../icons";
|
|
||||||
import ComboBox from "../combobox";
|
|
||||||
import { Text } from "../text";
|
|
||||||
import findIndex from "lodash/findIndex";
|
|
||||||
import filter from "lodash/filter";
|
|
||||||
import isEqual from "lodash/isEqual";
|
|
||||||
import DropDown from "../drop-down";
|
import DropDown from "../drop-down";
|
||||||
import { handleAnyClick } from "../../utils/event";
|
|
||||||
import isEmpty from "lodash/isEmpty";
|
|
||||||
import Aside from "../layout/sub-components/aside";
|
import Aside from "../layout/sub-components/aside";
|
||||||
|
import ADSelectorBody from "./sub-components/body";
|
||||||
|
|
||||||
const displayTypes = ["dropdown", "aside"];
|
const displayTypes = ["dropdown", "aside"];
|
||||||
|
|
||||||
/* eslint-disable no-unused-vars */
|
|
||||||
/* eslint-disable react/prop-types */
|
|
||||||
const Container = ({
|
|
||||||
value,
|
|
||||||
placeholder,
|
|
||||||
isMultiSelect,
|
|
||||||
size,
|
|
||||||
width,
|
|
||||||
maxHeight,
|
|
||||||
isDisabled,
|
|
||||||
onSelect,
|
|
||||||
onSearchChanged,
|
|
||||||
options,
|
|
||||||
selectedOptions,
|
|
||||||
buttonLabel,
|
|
||||||
selectAllLabel,
|
|
||||||
groups,
|
|
||||||
selectedGroups,
|
|
||||||
onChangeGroup,
|
|
||||||
isOpen,
|
|
||||||
displayType,
|
|
||||||
containerWidth,
|
|
||||||
containerHeight,
|
|
||||||
allowCreation,
|
|
||||||
onAddNewClick,
|
|
||||||
allowAnyClickClose,
|
|
||||||
...props
|
|
||||||
}) => <div {...props} />;
|
|
||||||
/* eslint-enable react/prop-types */
|
|
||||||
/* eslint-enable no-unused-vars */
|
|
||||||
|
|
||||||
const StyledContainer = styled(Container)`
|
|
||||||
.dropdown-container {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.aside-container {
|
|
||||||
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
const StyledBodyContainer = styled(Container)`
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
|
|
||||||
${props => (props.containerWidth ? `width: ${props.containerWidth};` : "")}
|
|
||||||
${props => (props.containerHeight ? `height: ${props.containerHeight};` : "")}
|
|
||||||
|
|
||||||
.data_container {
|
|
||||||
margin: 16px 16px -5px 16px;
|
|
||||||
|
|
||||||
.head_container {
|
|
||||||
display: flex;
|
|
||||||
margin-bottom: ${props => (props.displayType === "dropdown" ? 8 : 16)}px;
|
|
||||||
|
|
||||||
.options_searcher {
|
|
||||||
display: inline-block;
|
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
${props =>
|
|
||||||
props.displayType === "dropdown" &&
|
|
||||||
props.size === "full" &&
|
|
||||||
css`
|
|
||||||
margin-right: ${props => (props.allowCreation ? 8 : 16)}px;
|
|
||||||
`}
|
|
||||||
/*${props =>
|
|
||||||
props.allowCreation
|
|
||||||
? css`
|
|
||||||
width: 272px;
|
|
||||||
margin-right: 8px;
|
|
||||||
`
|
|
||||||
: css`
|
|
||||||
width: ${props => (props.isDropDown ? "313px" : "100%")};
|
|
||||||
`}*/
|
|
||||||
}
|
|
||||||
|
|
||||||
.add_new_btn {
|
|
||||||
${props =>
|
|
||||||
props.allowCreation &&
|
|
||||||
css`
|
|
||||||
display: inline-block;
|
|
||||||
vertical-align: top;
|
|
||||||
height: 32px;
|
|
||||||
width: 36px;
|
|
||||||
margin-right: 16px;
|
|
||||||
line-height: 18px;
|
|
||||||
`}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
.options_group_selector {
|
|
||||||
margin-bottom: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.data_column_one {
|
|
||||||
${props =>
|
|
||||||
props.displayType === "dropdown" &&
|
|
||||||
props.groups &&
|
|
||||||
props.groups.length > 0
|
|
||||||
? css`
|
|
||||||
width: 50%;
|
|
||||||
display: inline-block;
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
|
|
||||||
.options_list {
|
|
||||||
margin-top: 4px;
|
|
||||||
margin-left: -8px;
|
|
||||||
.option {
|
|
||||||
line-height: 32px;
|
|
||||||
padding-left: ${props => (props.isMultiSelect ? 8 : 0)}px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
.option_checkbox {
|
|
||||||
/*margin-left: 8px;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
.option_link {
|
|
||||||
padding-left: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: #f8f9f9;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.data_column_two {
|
|
||||||
${props =>
|
|
||||||
props.displayType === "dropdown" &&
|
|
||||||
props.groups &&
|
|
||||||
props.groups.length > 0
|
|
||||||
? css`
|
|
||||||
width: 50%;
|
|
||||||
display: inline-block;
|
|
||||||
border-left: 1px solid #eceef1;
|
|
||||||
`
|
|
||||||
: ""}
|
|
||||||
|
|
||||||
.group_header {
|
|
||||||
font-weight: 600;
|
|
||||||
padding-left: 16px;
|
|
||||||
padding-bottom: 14px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.group_list {
|
|
||||||
margin-left: 8px;
|
|
||||||
|
|
||||||
.option {
|
|
||||||
line-height: 32px;
|
|
||||||
padding-left: 8px;
|
|
||||||
cursor: pointer;
|
|
||||||
|
|
||||||
.option_checkbox {
|
|
||||||
/*margin-left: 8px;*/
|
|
||||||
}
|
|
||||||
|
|
||||||
.option_link {
|
|
||||||
padding-left: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: #eceef1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.button_container {
|
|
||||||
border-top: 1px solid #eceef1;
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
.add_members_btn {
|
|
||||||
margin: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
|
|
||||||
class AdvancedSelector extends React.Component {
|
class AdvancedSelector extends React.Component {
|
||||||
constructor(props) {
|
|
||||||
super(props);
|
|
||||||
|
|
||||||
this.ref = React.createRef();
|
|
||||||
|
|
||||||
const groups = this.convertGroups(this.props.groups);
|
|
||||||
const currentGroup = this.getCurrentGroup(groups);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
selectedOptions: this.props.selectedOptions || [],
|
|
||||||
selectedAll: this.props.selectedAll || false,
|
|
||||||
groups: groups,
|
|
||||||
currentGroup: currentGroup
|
|
||||||
};
|
|
||||||
|
|
||||||
if (props.isOpen) handleAnyClick(true, this.handleClick);
|
|
||||||
}
|
|
||||||
|
|
||||||
handleClick = e => {
|
|
||||||
if (
|
|
||||||
this.props.isOpen &&
|
|
||||||
this.props.allowAnyClickClose &&
|
|
||||||
this.ref &&
|
|
||||||
this.ref.current &&
|
|
||||||
!this.ref.current.contains(e.target) &&
|
|
||||||
e &&
|
|
||||||
e.target &&
|
|
||||||
e.target.className &&
|
|
||||||
typeof e.target.className.indexOf === "function" &&
|
|
||||||
e.target.className.indexOf("option_checkbox") === -1
|
|
||||||
) {
|
|
||||||
this.props.onCancel && this.props.onCancel();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
handleAnyClick(false, this.handleClick);
|
|
||||||
}
|
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
|
||||||
return !isEqual(this.props, nextProps) || !isEqual(this.state, nextState);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
|
||||||
if (this.props.isOpen !== prevProps.isOpen) {
|
|
||||||
handleAnyClick(this.props.isOpen, this.handleClick);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.props.allowAnyClickClose !== prevProps.allowAnyClickClose) {
|
|
||||||
handleAnyClick(this.props.allowAnyClickClose, this.handleClick);
|
|
||||||
}
|
|
||||||
|
|
||||||
let newState = {};
|
|
||||||
|
|
||||||
if (!isEqual(this.props.selectedOptions, prevProps.selectedOptions)) {
|
|
||||||
newState = { selectedOptions: this.props.selectedOptions };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.props.isMultiSelect !== prevProps.isMultiSelect) {
|
|
||||||
newState = Object.assign({}, newState, {
|
|
||||||
selectedOptions: []
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.props.selectedAll !== prevProps.selectedAll) {
|
|
||||||
newState = Object.assign({}, newState, {
|
|
||||||
selectedAll: this.props.selectedAll
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isEqual(this.props.groups, prevProps.groups)) {
|
|
||||||
const groups = this.convertGroups(this.props.groups);
|
|
||||||
const currentGroup = this.getCurrentGroup(groups);
|
|
||||||
newState = Object.assign({}, newState, {
|
|
||||||
groups,
|
|
||||||
currentGroup
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!isEmpty(newState)) {
|
|
||||||
this.setState({ ...this.state, ...newState });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
convertGroups = groups => {
|
|
||||||
if (!groups) return [];
|
|
||||||
|
|
||||||
const wrappedGroups = groups.map(this.convertGroup);
|
|
||||||
|
|
||||||
return wrappedGroups;
|
|
||||||
};
|
|
||||||
|
|
||||||
convertGroup = group => {
|
|
||||||
return {
|
|
||||||
key: group.key,
|
|
||||||
label: `${group.label} (${group.total})`,
|
|
||||||
total: group.total
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
getCurrentGroup = groups => {
|
|
||||||
const currentGroup = groups.length > 0 ? groups[0] : "No groups";
|
|
||||||
return currentGroup;
|
|
||||||
};
|
|
||||||
|
|
||||||
onButtonClick = () => {
|
|
||||||
this.props.onSelect &&
|
|
||||||
this.props.onSelect(
|
|
||||||
this.state.selectedAll ? this.props.options : this.state.selectedOptions
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
onSelect = option => {
|
|
||||||
this.props.onSelect && this.props.onSelect(option);
|
|
||||||
};
|
|
||||||
|
|
||||||
onChange = (option, e) => {
|
|
||||||
const { selectedOptions } = this.state;
|
|
||||||
const newSelectedOptions = e.target.checked
|
|
||||||
? [...selectedOptions, option]
|
|
||||||
: filter(selectedOptions, obj => obj.key !== option.key);
|
|
||||||
|
|
||||||
//console.log("onChange", option, e.target.checked, newSelectedOptions);
|
|
||||||
|
|
||||||
this.setState({
|
|
||||||
selectedOptions: newSelectedOptions,
|
|
||||||
selectedAll: newSelectedOptions.length === this.props.options.length
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onSelectedAllChange = e => {
|
|
||||||
this.setState({
|
|
||||||
selectedAll: e.target.checked,
|
|
||||||
selectedOptions: e.target.checked ? this.props.options : []
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
onCurrentGroupChange = group => {
|
|
||||||
this.setState({
|
|
||||||
currentGroup: group
|
|
||||||
});
|
|
||||||
|
|
||||||
this.props.onChangeGroup && this.props.onChangeGroup(group);
|
|
||||||
};
|
|
||||||
|
|
||||||
renderRow = ({ data, index, style }) => {
|
|
||||||
const option = data[index];
|
|
||||||
var isChecked =
|
|
||||||
this.state.selectedAll ||
|
|
||||||
findIndex(this.state.selectedOptions, { key: option.key }) > -1;
|
|
||||||
|
|
||||||
//console.log("renderRow", option, isChecked, this.state.selectedOptions);
|
|
||||||
return (
|
|
||||||
<div className="option" style={style} key={option.key}>
|
|
||||||
{this.props.isMultiSelect ? (
|
|
||||||
<Checkbox
|
|
||||||
label={option.label}
|
|
||||||
isChecked={isChecked}
|
|
||||||
className="option_checkbox"
|
|
||||||
onChange={this.onChange.bind(this, option)}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<Link
|
|
||||||
as="span"
|
|
||||||
truncate={true}
|
|
||||||
className="option_link"
|
|
||||||
onClick={this.onSelect.bind(this, option)}
|
|
||||||
>
|
|
||||||
{option.label}
|
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
renderBody = () => {
|
|
||||||
const {
|
|
||||||
value,
|
|
||||||
placeholder,
|
|
||||||
isDisabled,
|
|
||||||
onSearchChanged,
|
|
||||||
options,
|
|
||||||
isMultiSelect,
|
|
||||||
buttonLabel,
|
|
||||||
selectAllLabel,
|
|
||||||
size,
|
|
||||||
displayType,
|
|
||||||
onAddNewClick,
|
|
||||||
allowCreation
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const { selectedOptions, selectedAll, currentGroup, groups } = this.state;
|
|
||||||
|
|
||||||
/*const containerHeight =
|
|
||||||
size === "compact" ? (!groups || !groups.length ? 336 : 326) : 614;
|
|
||||||
const containerWidth =
|
|
||||||
size === "compact" ? (!groups || !groups.length ? 325 : 326) : isDropDown ? 690 : 326;
|
|
||||||
const listHeight =
|
|
||||||
size === "compact"
|
|
||||||
? !groups || !groups.length
|
|
||||||
? isMultiSelect
|
|
||||||
? 176
|
|
||||||
: 226
|
|
||||||
: 120
|
|
||||||
: 488;
|
|
||||||
const listWidth = isDropDown ? 320 : "100%";*/
|
|
||||||
|
|
||||||
let containerHeight;
|
|
||||||
let containerWidth;
|
|
||||||
let listHeight;
|
|
||||||
let listWidth;
|
|
||||||
const itemHeight = 32;
|
|
||||||
const hasGroups = groups && groups.length > 0;
|
|
||||||
|
|
||||||
switch (size) {
|
|
||||||
case "compact":
|
|
||||||
containerHeight = hasGroups ? "326px" : "100%";
|
|
||||||
containerWidth = "379px";
|
|
||||||
listWidth = displayType === "dropdown" ? 356 : 356;
|
|
||||||
listHeight = hasGroups ? 488 : isMultiSelect ? 176 : 226;
|
|
||||||
break;
|
|
||||||
case "full":
|
|
||||||
default:
|
|
||||||
containerHeight = "100%";
|
|
||||||
containerWidth = displayType === "dropdown" ? "690px" : "326px";
|
|
||||||
listWidth = displayType === "dropdown" ? 320 : 302;
|
|
||||||
listHeight = 488;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<StyledBodyContainer
|
|
||||||
containerHeight={containerHeight}
|
|
||||||
containerWidth={containerWidth}
|
|
||||||
{...this.props}
|
|
||||||
>
|
|
||||||
<div ref={this.ref}>
|
|
||||||
<div className="data_container">
|
|
||||||
<div className="data_column_one">
|
|
||||||
<div className="head_container">
|
|
||||||
<SearchInput
|
|
||||||
className="options_searcher"
|
|
||||||
isDisabled={isDisabled}
|
|
||||||
size="base"
|
|
||||||
scale={true}
|
|
||||||
isNeedFilter={false}
|
|
||||||
placeholder={placeholder}
|
|
||||||
value={value}
|
|
||||||
onChange={onSearchChanged}
|
|
||||||
onClearSearch={onSearchChanged.bind(this, "")}
|
|
||||||
/>
|
|
||||||
{allowCreation && (
|
|
||||||
<Button
|
|
||||||
className="add_new_btn"
|
|
||||||
primary={false}
|
|
||||||
size="base"
|
|
||||||
label=""
|
|
||||||
icon={
|
|
||||||
<Icons.PlusIcon
|
|
||||||
size="medium"
|
|
||||||
isfill={true}
|
|
||||||
color="#D8D8D8"
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
onClick={onAddNewClick}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{displayType === "aside" && groups && groups.length > 0 && (
|
|
||||||
<ComboBox
|
|
||||||
className="options_group_selector"
|
|
||||||
isDisabled={isDisabled}
|
|
||||||
options={groups}
|
|
||||||
selectedOption={currentGroup}
|
|
||||||
dropDownMaxHeight={200}
|
|
||||||
scaled={true}
|
|
||||||
scaledOptions={true}
|
|
||||||
size="content"
|
|
||||||
onSelect={this.onCurrentGroupChange}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{isMultiSelect && !groups && !groups.length && (
|
|
||||||
<Checkbox
|
|
||||||
label={selectAllLabel}
|
|
||||||
isChecked={
|
|
||||||
selectedAll || selectedOptions.length === options.length
|
|
||||||
}
|
|
||||||
isIndeterminate={!selectedAll && selectedOptions.length > 0}
|
|
||||||
className="option_select_all_checkbox"
|
|
||||||
onChange={this.onSelectedAllChange}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
<FixedSizeList
|
|
||||||
className="options_list"
|
|
||||||
height={listHeight}
|
|
||||||
width={listWidth}
|
|
||||||
itemSize={itemHeight}
|
|
||||||
itemCount={this.props.options.length}
|
|
||||||
itemData={this.props.options}
|
|
||||||
outerElementType={CustomScrollbarsVirtualList}
|
|
||||||
>
|
|
||||||
{this.renderRow.bind(this)}
|
|
||||||
</FixedSizeList>
|
|
||||||
</div>
|
|
||||||
{displayType === "dropdown" &&
|
|
||||||
size === "full" &&
|
|
||||||
groups &&
|
|
||||||
groups.length > 0 && (
|
|
||||||
<div className="data_column_two">
|
|
||||||
<Text.Body
|
|
||||||
as="p"
|
|
||||||
className="group_header"
|
|
||||||
fontSize={15}
|
|
||||||
isBold={true}
|
|
||||||
>
|
|
||||||
Groups
|
|
||||||
</Text.Body>
|
|
||||||
<FixedSizeList
|
|
||||||
className="group_list"
|
|
||||||
height={listHeight}
|
|
||||||
itemSize={itemHeight}
|
|
||||||
itemCount={this.props.groups.length}
|
|
||||||
itemData={this.props.groups}
|
|
||||||
outerElementType={CustomScrollbarsVirtualList}
|
|
||||||
>
|
|
||||||
{this.renderRow.bind(this)}
|
|
||||||
</FixedSizeList>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{isMultiSelect && (
|
|
||||||
<div className="button_container">
|
|
||||||
<Button
|
|
||||||
className="add_members_btn"
|
|
||||||
primary={true}
|
|
||||||
size="big"
|
|
||||||
label={buttonLabel}
|
|
||||||
scale={true}
|
|
||||||
isDisabled={
|
|
||||||
!this.state.selectedOptions ||
|
|
||||||
!this.state.selectedOptions.length
|
|
||||||
}
|
|
||||||
onClick={this.onButtonClick}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</StyledBodyContainer>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { displayType, isOpen } = this.props;
|
const { displayType, isOpen } = this.props;
|
||||||
//console.log("AdvancedSelector render()");
|
//console.log("AdvancedSelector render()");
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<StyledContainer>
|
displayType === "dropdown"
|
||||||
{displayType === "dropdown" ? (
|
? <DropDown opened={isOpen} className="dropdown-container">
|
||||||
<DropDown opened={isOpen} className="dropdown-container">
|
<ADSelectorBody {...this.props} />
|
||||||
{this.renderBody()}
|
|
||||||
</DropDown>
|
</DropDown>
|
||||||
) : (
|
: <Aside visible={isOpen} scale={false} className="aside-container">
|
||||||
<Aside visible={isOpen} scale={false} className="aside-container">
|
<ADSelectorBody {...this.props} />
|
||||||
{this.renderBody()}
|
|
||||||
</Aside>
|
</Aside>
|
||||||
)}
|
|
||||||
</StyledContainer>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -581,7 +31,7 @@ AdvancedSelector.propTypes = {
|
|||||||
maxHeight: PropTypes.number,
|
maxHeight: PropTypes.number,
|
||||||
isDisabled: PropTypes.bool,
|
isDisabled: PropTypes.bool,
|
||||||
onSearchChanged: PropTypes.func,
|
onSearchChanged: PropTypes.func,
|
||||||
options: PropTypes.array.isRequired,
|
options: PropTypes.array,
|
||||||
selectedOptions: PropTypes.array,
|
selectedOptions: PropTypes.array,
|
||||||
groups: PropTypes.array,
|
groups: PropTypes.array,
|
||||||
selectedGroups: PropTypes.array,
|
selectedGroups: PropTypes.array,
|
||||||
@ -595,7 +45,10 @@ AdvancedSelector.propTypes = {
|
|||||||
allowCreation: PropTypes.bool,
|
allowCreation: PropTypes.bool,
|
||||||
onAddNewClick: PropTypes.func,
|
onAddNewClick: PropTypes.func,
|
||||||
allowAnyClickClose: PropTypes.bool,
|
allowAnyClickClose: PropTypes.bool,
|
||||||
displayType: PropTypes.oneOf(displayTypes)
|
displayType: PropTypes.oneOf(displayTypes),
|
||||||
|
hasNextPage: PropTypes.bool,
|
||||||
|
isNextPageLoading: PropTypes.bool,
|
||||||
|
loadNextPage: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
AdvancedSelector.defaultProps = {
|
AdvancedSelector.defaultProps = {
|
||||||
@ -604,7 +57,8 @@ AdvancedSelector.defaultProps = {
|
|||||||
buttonLabel: "Add members",
|
buttonLabel: "Add members",
|
||||||
selectAllLabel: "Select all",
|
selectAllLabel: "Select all",
|
||||||
allowAnyClickClose: true,
|
allowAnyClickClose: true,
|
||||||
displayType: "dropdown"
|
displayType: "dropdown",
|
||||||
|
options: []
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AdvancedSelector;
|
export default AdvancedSelector;
|
||||||
|
@ -0,0 +1,480 @@
|
|||||||
|
import React from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import styled, { css } from "styled-components";
|
||||||
|
import CustomScrollbarsVirtualList from "../../scrollbar/custom-scrollbars-virtual-list";
|
||||||
|
import { FixedSizeList } from "react-window";
|
||||||
|
import Checkbox from "../../checkbox";
|
||||||
|
|
||||||
|
import ComboBox from "../../combobox";
|
||||||
|
import { Text } from "../../text";
|
||||||
|
|
||||||
|
import filter from "lodash/filter";
|
||||||
|
import isEqual from "lodash/isEqual";
|
||||||
|
|
||||||
|
import { handleAnyClick } from "../../../utils/event";
|
||||||
|
import isEmpty from "lodash/isEmpty";
|
||||||
|
|
||||||
|
import ADSelectorFooter from "./footer";
|
||||||
|
|
||||||
|
import ADSelectorMainHeader from "./sections/main/header";
|
||||||
|
import ADSelectorMainBody from "./sections/main/body";
|
||||||
|
import ADSelectorAdditionalBody from "./sections/additional/body";
|
||||||
|
|
||||||
|
/* eslint-disable no-unused-vars */
|
||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
const Container = ({
|
||||||
|
value,
|
||||||
|
placeholder,
|
||||||
|
isMultiSelect,
|
||||||
|
size,
|
||||||
|
width,
|
||||||
|
maxHeight,
|
||||||
|
isDisabled,
|
||||||
|
onSelect,
|
||||||
|
onSearchChanged,
|
||||||
|
options,
|
||||||
|
selectedOptions,
|
||||||
|
buttonLabel,
|
||||||
|
selectAllLabel,
|
||||||
|
groups,
|
||||||
|
selectedGroups,
|
||||||
|
onChangeGroup,
|
||||||
|
isOpen,
|
||||||
|
displayType,
|
||||||
|
containerWidth,
|
||||||
|
containerHeight,
|
||||||
|
allowCreation,
|
||||||
|
onAddNewClick,
|
||||||
|
allowAnyClickClose,
|
||||||
|
hasNextPage,
|
||||||
|
isNextPageLoading,
|
||||||
|
loadNextPage,
|
||||||
|
...props
|
||||||
|
}) => <div {...props} />;
|
||||||
|
/* eslint-enable react/prop-types */
|
||||||
|
/* eslint-enable no-unused-vars */
|
||||||
|
|
||||||
|
const StyledBodyContainer = styled(Container)`
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
${props => (props.containerWidth ? `width: ${props.containerWidth};` : "")}
|
||||||
|
${props => (props.containerHeight ? `height: ${props.containerHeight};` : "")}
|
||||||
|
|
||||||
|
.data_container {
|
||||||
|
margin: 16px 16px -5px 16px;
|
||||||
|
|
||||||
|
.head_container {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: ${props => (props.displayType === "dropdown" ? 8 : 16)}px;
|
||||||
|
|
||||||
|
.options_searcher {
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
|
${props =>
|
||||||
|
props.displayType === "dropdown" &&
|
||||||
|
props.size === "full" &&
|
||||||
|
css`
|
||||||
|
margin-right: ${props => (props.allowCreation ? 8 : 16)}px;
|
||||||
|
`}
|
||||||
|
/*${props =>
|
||||||
|
props.allowCreation
|
||||||
|
? css`
|
||||||
|
width: 272px;
|
||||||
|
margin-right: 8px;
|
||||||
|
`
|
||||||
|
: css`
|
||||||
|
width: ${props => (props.isDropDown ? "313px" : "100%")};
|
||||||
|
`}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.add_new_btn {
|
||||||
|
${props =>
|
||||||
|
props.allowCreation &&
|
||||||
|
css`
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: top;
|
||||||
|
height: 32px;
|
||||||
|
width: 36px;
|
||||||
|
margin-right: 16px;
|
||||||
|
line-height: 18px;
|
||||||
|
`}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.options_group_selector {
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data_column_one {
|
||||||
|
${props =>
|
||||||
|
props.displayType === "dropdown" &&
|
||||||
|
props.groups &&
|
||||||
|
props.groups.length > 0
|
||||||
|
? css`
|
||||||
|
width: 50%;
|
||||||
|
display: inline-block;
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
|
||||||
|
.options_list {
|
||||||
|
margin-top: 4px;
|
||||||
|
margin-left: -8px;
|
||||||
|
.option {
|
||||||
|
line-height: 32px;
|
||||||
|
padding-left: ${props => (props.isMultiSelect ? 8 : 0)}px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.option_checkbox {
|
||||||
|
/*margin-left: 8px;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.option_link {
|
||||||
|
padding-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #f8f9f9;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.data_column_two {
|
||||||
|
${props =>
|
||||||
|
props.displayType === "dropdown" &&
|
||||||
|
props.groups &&
|
||||||
|
props.groups.length > 0
|
||||||
|
? css`
|
||||||
|
width: 50%;
|
||||||
|
display: inline-block;
|
||||||
|
border-left: 1px solid #eceef1;
|
||||||
|
`
|
||||||
|
: ""}
|
||||||
|
|
||||||
|
.group_header {
|
||||||
|
font-weight: 600;
|
||||||
|
padding-left: 16px;
|
||||||
|
padding-bottom: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.group_list {
|
||||||
|
margin-left: 8px;
|
||||||
|
|
||||||
|
.option {
|
||||||
|
line-height: 32px;
|
||||||
|
padding-left: 8px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.option_checkbox {
|
||||||
|
/*margin-left: 8px;*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.option_link {
|
||||||
|
padding-left: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: #eceef1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button_container {
|
||||||
|
border-top: 1px solid #eceef1;
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
.add_members_btn {
|
||||||
|
margin: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
class ADSelectorBody extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
|
this.ref = React.createRef();
|
||||||
|
|
||||||
|
const groups = this.convertGroups(this.props.groups);
|
||||||
|
const currentGroup = this.getCurrentGroup(groups);
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
selectedOptions: this.props.selectedOptions || [],
|
||||||
|
selectedAll: this.props.selectedAll || false,
|
||||||
|
groups: groups,
|
||||||
|
currentGroup: currentGroup
|
||||||
|
};
|
||||||
|
|
||||||
|
if (props.isOpen) handleAnyClick(true, this.handleClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleClick = e => {
|
||||||
|
if (
|
||||||
|
this.props.isOpen &&
|
||||||
|
this.props.allowAnyClickClose &&
|
||||||
|
this.ref &&
|
||||||
|
this.ref.current &&
|
||||||
|
!this.ref.current.contains(e.target) &&
|
||||||
|
e &&
|
||||||
|
e.target &&
|
||||||
|
e.target.className &&
|
||||||
|
typeof e.target.className.indexOf === "function" &&
|
||||||
|
e.target.className.indexOf("option_checkbox") === -1
|
||||||
|
) {
|
||||||
|
this.props.onCancel && this.props.onCancel();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
handleAnyClick(false, this.handleClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldComponentUpdate(nextProps, nextState) {
|
||||||
|
return !isEqual(this.props, nextProps) || !isEqual(this.state, nextState);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps) {
|
||||||
|
if (this.props.isOpen !== prevProps.isOpen) {
|
||||||
|
handleAnyClick(this.props.isOpen, this.handleClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.allowAnyClickClose !== prevProps.allowAnyClickClose) {
|
||||||
|
handleAnyClick(this.props.allowAnyClickClose, this.handleClick);
|
||||||
|
}
|
||||||
|
|
||||||
|
let newState = {};
|
||||||
|
|
||||||
|
if (!isEqual(this.props.selectedOptions, prevProps.selectedOptions)) {
|
||||||
|
newState = { selectedOptions: this.props.selectedOptions };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.isMultiSelect !== prevProps.isMultiSelect) {
|
||||||
|
newState = Object.assign({}, newState, {
|
||||||
|
selectedOptions: []
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.selectedAll !== prevProps.selectedAll) {
|
||||||
|
newState = Object.assign({}, newState, {
|
||||||
|
selectedAll: this.props.selectedAll
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isEqual(this.props.groups, prevProps.groups)) {
|
||||||
|
const groups = this.convertGroups(this.props.groups);
|
||||||
|
const currentGroup = this.getCurrentGroup(groups);
|
||||||
|
newState = Object.assign({}, newState, {
|
||||||
|
groups,
|
||||||
|
currentGroup
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isEmpty(newState)) {
|
||||||
|
this.setState({ ...this.state, ...newState });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
convertGroups = groups => {
|
||||||
|
if (!groups) return [];
|
||||||
|
|
||||||
|
const wrappedGroups = groups.map(this.convertGroup);
|
||||||
|
|
||||||
|
return wrappedGroups;
|
||||||
|
};
|
||||||
|
|
||||||
|
convertGroup = group => {
|
||||||
|
return {
|
||||||
|
key: group.key,
|
||||||
|
label: `${group.label} (${group.total})`,
|
||||||
|
total: group.total
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
getCurrentGroup = groups => {
|
||||||
|
const currentGroup = groups.length > 0 ? groups[0] : "No groups";
|
||||||
|
return currentGroup;
|
||||||
|
};
|
||||||
|
|
||||||
|
onButtonClick = () => {
|
||||||
|
this.props.onSelect &&
|
||||||
|
this.props.onSelect(
|
||||||
|
this.state.selectedAll ? this.props.options : this.state.selectedOptions
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
onSelect = option => {
|
||||||
|
this.props.onSelect && this.props.onSelect(option);
|
||||||
|
};
|
||||||
|
|
||||||
|
onChange = (option, e) => {
|
||||||
|
const { selectedOptions } = this.state;
|
||||||
|
const newSelectedOptions = e.target.checked
|
||||||
|
? [...selectedOptions, option]
|
||||||
|
: filter(selectedOptions, obj => obj.key !== option.key);
|
||||||
|
|
||||||
|
//console.log("onChange", option, e.target.checked, newSelectedOptions);
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
selectedOptions: newSelectedOptions,
|
||||||
|
selectedAll: newSelectedOptions.length === this.props.options.length
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onSelectedAllChange = e => {
|
||||||
|
this.setState({
|
||||||
|
selectedAll: e.target.checked,
|
||||||
|
selectedOptions: e.target.checked ? this.props.options : []
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onCurrentGroupChange = group => {
|
||||||
|
this.setState({
|
||||||
|
currentGroup: group
|
||||||
|
});
|
||||||
|
|
||||||
|
this.props.onChangeGroup && this.props.onChangeGroup(group);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Only load 1 page of items at a time.
|
||||||
|
// Pass an empty callback to InfiniteLoader in case it asks us to load more than once.
|
||||||
|
loadMoreItems = this.props.isNextPageLoading ? () => { } : this.props.loadNextPage;
|
||||||
|
|
||||||
|
// Every row is loaded except for our loading indicator row.
|
||||||
|
isItemLoaded = (index) => !this.props.hasNextPage || index < this.props.total;
|
||||||
|
|
||||||
|
render() {
|
||||||
|
|
||||||
|
const {
|
||||||
|
value,
|
||||||
|
placeholder,
|
||||||
|
isDisabled,
|
||||||
|
onSearchChanged,
|
||||||
|
options,
|
||||||
|
isMultiSelect,
|
||||||
|
buttonLabel,
|
||||||
|
selectAllLabel,
|
||||||
|
size,
|
||||||
|
displayType,
|
||||||
|
onAddNewClick,
|
||||||
|
allowCreation,
|
||||||
|
hasNextPage,
|
||||||
|
isNextPageLoading,
|
||||||
|
total
|
||||||
|
} = this.props;
|
||||||
|
|
||||||
|
const { selectedOptions, selectedAll, currentGroup, groups } = this.state;
|
||||||
|
|
||||||
|
let containerHeight;
|
||||||
|
let containerWidth;
|
||||||
|
let listHeight;
|
||||||
|
let listWidth;
|
||||||
|
const itemHeight = 32;
|
||||||
|
const hasGroups = groups && groups.length > 0;
|
||||||
|
|
||||||
|
switch (size) {
|
||||||
|
case "compact":
|
||||||
|
containerHeight = hasGroups ? "326px" : "100%";
|
||||||
|
containerWidth = "379px";
|
||||||
|
listWidth = displayType === "dropdown" ? 356 : 356;
|
||||||
|
listHeight = hasGroups ? 488 : isMultiSelect ? 176 : 226;
|
||||||
|
break;
|
||||||
|
case "full":
|
||||||
|
default:
|
||||||
|
containerHeight = "100%";
|
||||||
|
containerWidth = displayType === "dropdown" ? "690px" : "326px";
|
||||||
|
listWidth = displayType === "dropdown" ? 320 : 302;
|
||||||
|
listHeight = 488;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there are more items to be loaded then add an extra row to hold a loading indicator.
|
||||||
|
const itemCount = hasNextPage ? options.length + 1 : options.length;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<StyledBodyContainer
|
||||||
|
containerHeight={containerHeight}
|
||||||
|
containerWidth={containerWidth}
|
||||||
|
{...this.props}
|
||||||
|
>
|
||||||
|
<div ref={this.ref}>
|
||||||
|
<div className="data_container">
|
||||||
|
<div className="data_column_one">
|
||||||
|
<ADSelectorMainHeader
|
||||||
|
value={value}
|
||||||
|
searchPlaceHolder={placeholder}
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
allowCreation={allowCreation}
|
||||||
|
onAddNewClick={onAddNewClick}
|
||||||
|
onChange={onSearchChanged}
|
||||||
|
onClearSearch={onSearchChanged.bind(this, "")}
|
||||||
|
/>
|
||||||
|
{displayType === "aside" && groups && groups.length > 0 && (
|
||||||
|
<ComboBox
|
||||||
|
className="options_group_selector"
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
options={groups}
|
||||||
|
selectedOption={currentGroup}
|
||||||
|
dropDownMaxHeight={200}
|
||||||
|
scaled={true}
|
||||||
|
scaledOptions={true}
|
||||||
|
size="content"
|
||||||
|
onSelect={this.onCurrentGroupChange}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{isMultiSelect && !groups && !groups.length && (
|
||||||
|
<Checkbox
|
||||||
|
label={selectAllLabel}
|
||||||
|
isChecked={
|
||||||
|
selectedAll || selectedOptions.length === options.length
|
||||||
|
}
|
||||||
|
isIndeterminate={!selectedAll && selectedOptions.length > 0}
|
||||||
|
className="option_select_all_checkbox"
|
||||||
|
onChange={this.onSelectedAllChange}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<ADSelectorMainBody
|
||||||
|
isMultiSelect={this.props.isMultiSelect}
|
||||||
|
total={total}
|
||||||
|
isItemLoaded={this.isItemLoaded}
|
||||||
|
isNextPageLoading={isNextPageLoading}
|
||||||
|
listHeight={listHeight}
|
||||||
|
listWidth={listWidth}
|
||||||
|
itemHeight={itemHeight}
|
||||||
|
loadNextPage={this.props.loadNextPage}
|
||||||
|
onRowChecked={this.onChange}
|
||||||
|
onRowSelect={this.onSelect}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
{/* {displayType === "dropdown" &&
|
||||||
|
size === "full" &&
|
||||||
|
groups &&
|
||||||
|
groups.length > 0 && (
|
||||||
|
<ADSelectorAdditionalBody
|
||||||
|
height={listHeight}
|
||||||
|
itemSize={itemHeight}
|
||||||
|
groups={groups}
|
||||||
|
/>
|
||||||
|
)} */}
|
||||||
|
</div>
|
||||||
|
{isMultiSelect && (
|
||||||
|
<ADSelectorFooter
|
||||||
|
buttonLabel={buttonLabel}
|
||||||
|
isDisabled={
|
||||||
|
!this.state.selectedOptions ||
|
||||||
|
!this.state.selectedOptions.length
|
||||||
|
}
|
||||||
|
onClick={this.onButtonClick}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</StyledBodyContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ADSelectorBody;
|
@ -0,0 +1,29 @@
|
|||||||
|
import React from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import Button from "../../button";
|
||||||
|
|
||||||
|
const ADSelectorFooter = (props) => {
|
||||||
|
const { buttonLabel, isDisabled, onButtonClick } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="button_container">
|
||||||
|
<Button
|
||||||
|
className="add_members_btn"
|
||||||
|
primary={true}
|
||||||
|
size="big"
|
||||||
|
label={buttonLabel}
|
||||||
|
scale={true}
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
onClick={onButtonClick}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ADSelectorFooter.propTypes = {
|
||||||
|
buttonLabel: PropTypes.string,
|
||||||
|
isDisabled: PropTypes.bool,
|
||||||
|
onButtonClick: PropTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ADSelectorFooter;
|
@ -0,0 +1,64 @@
|
|||||||
|
import React from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import CustomScrollbarsVirtualList from "../../../../scrollbar/custom-scrollbars-virtual-list";
|
||||||
|
import { FixedSizeList } from "react-window";
|
||||||
|
import { Text } from "../../../../text";
|
||||||
|
import ADSelectorBodyRow from "../main/row";
|
||||||
|
import findIndex from "lodash/findIndex";
|
||||||
|
|
||||||
|
class ADSelectorAdditionalBody extends React.Component {
|
||||||
|
|
||||||
|
|
||||||
|
renderRow = ({ data, index, style }) => {
|
||||||
|
const option = data[index];
|
||||||
|
var isChecked = this.props.isMultiSelect ? (
|
||||||
|
this.state.selectedAll ||
|
||||||
|
findIndex(this.state.selectedOptions, { key: option.key }) > -1) : undefined;
|
||||||
|
|
||||||
|
//console.log("renderRow", option, isChecked, this.state.selectedOptions);
|
||||||
|
return (
|
||||||
|
<ADSelectorBodyRow
|
||||||
|
key={option.key}
|
||||||
|
label={option.label}
|
||||||
|
isChecked={isChecked}
|
||||||
|
style={style}
|
||||||
|
onChange={this.props.onRowChecked.bind(this, option)}
|
||||||
|
onSelect={this.props.onRowSelect.bind(this, option)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { groups, listHeight, itemHeight } = this.props;
|
||||||
|
return (
|
||||||
|
<div className="data_column_two">
|
||||||
|
<Text.Body
|
||||||
|
as="p"
|
||||||
|
className="group_header"
|
||||||
|
fontSize={15}
|
||||||
|
isBold={true}
|
||||||
|
>
|
||||||
|
Groups
|
||||||
|
</Text.Body>
|
||||||
|
<FixedSizeList
|
||||||
|
className="group_list"
|
||||||
|
height={listHeight}
|
||||||
|
itemSize={itemHeight}
|
||||||
|
itemCount={groups.length}
|
||||||
|
itemData={groups}
|
||||||
|
outerElementType={CustomScrollbarsVirtualList}
|
||||||
|
>
|
||||||
|
{this.renderRow.bind(this)}
|
||||||
|
</FixedSizeList>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ADSelectorAdditionalBody.propTypes = {
|
||||||
|
groups: PropTypes.array,
|
||||||
|
listHeight: PropTypes.number,
|
||||||
|
itemHeight: PropTypes.number
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ADSelectorAdditionalBody;
|
@ -0,0 +1,74 @@
|
|||||||
|
import React from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import CustomScrollbarsVirtualList from "../../../../scrollbar/custom-scrollbars-virtual-list";
|
||||||
|
import { FixedSizeList } from "react-window";
|
||||||
|
import InfiniteLoader from "react-window-infinite-loader";
|
||||||
|
import ADSelectorBodyRow from "./row";
|
||||||
|
import findIndex from "lodash/findIndex";
|
||||||
|
|
||||||
|
class ADSelectorMainBody extends React.Component {
|
||||||
|
|
||||||
|
|
||||||
|
renderRow = ({ data, index, style }) => {
|
||||||
|
const option = data[index];
|
||||||
|
var isChecked = this.props.isMultiSelect ? (
|
||||||
|
this.state.selectedAll ||
|
||||||
|
findIndex(this.state.selectedOptions, { key: option.key }) > -1) : undefined;
|
||||||
|
|
||||||
|
//console.log("renderRow", option, isChecked, this.state.selectedOptions);
|
||||||
|
return (
|
||||||
|
<ADSelectorBodyRow
|
||||||
|
key={option.key}
|
||||||
|
label={option.label}
|
||||||
|
isChecked={isChecked}
|
||||||
|
style={style}
|
||||||
|
onChange={this.props.onRowChecked.bind(this, option)}
|
||||||
|
onSelect={this.props.onRowSelect.bind(this, option)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { total, isNextPageLoading, listHeight, listWidth, itemHeight, isItemLoaded, loadNextPage } = this.props;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<InfiniteLoader
|
||||||
|
isItemLoaded={isItemLoaded}
|
||||||
|
itemCount={total}
|
||||||
|
loadMoreItems={isNextPageLoading ? () => { console.log("loadMoreItems"); } : loadNextPage}
|
||||||
|
>
|
||||||
|
{({ onItemsRendered, ref }) => (
|
||||||
|
<FixedSizeList
|
||||||
|
className="options_list"
|
||||||
|
height={listHeight}
|
||||||
|
width={listWidth}
|
||||||
|
itemSize={itemHeight}
|
||||||
|
//itemCount={this.props.options.length}
|
||||||
|
//itemData={this.props.options}
|
||||||
|
onItemsRendered={onItemsRendered}
|
||||||
|
ref={ref}
|
||||||
|
outerElementType={CustomScrollbarsVirtualList}
|
||||||
|
>
|
||||||
|
{this.renderRow}
|
||||||
|
</FixedSizeList>
|
||||||
|
)}
|
||||||
|
</InfiniteLoader>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ADSelectorMainBody.propTypes = {
|
||||||
|
isMultiSelect: PropTypes.bool,
|
||||||
|
total: PropTypes.number,
|
||||||
|
isItemLoaded: PropTypes.func,
|
||||||
|
isNextPageLoading: PropTypes.bool,
|
||||||
|
listHeight: PropTypes.number,
|
||||||
|
listWidth: PropTypes.number,
|
||||||
|
itemHeight: PropTypes.number,
|
||||||
|
loadNextPage: PropTypes.func,
|
||||||
|
onRowChecked: PropTypes.func,
|
||||||
|
onRowSelect: PropTypes.func,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ADSelectorMainBody;
|
@ -0,0 +1,53 @@
|
|||||||
|
import React from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import SearchInput from "../../../../search-input";
|
||||||
|
import Button from "../../../../button";
|
||||||
|
import { Icons } from "../../../../icons";
|
||||||
|
|
||||||
|
const ADSelectorMainHeader = (props) => {
|
||||||
|
const { searchPlaceHolder, value, isDisabled, allowCreation, onSearchChanged, onAddNewClick } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="head_container">
|
||||||
|
<SearchInput
|
||||||
|
className="options_searcher"
|
||||||
|
isDisabled={isDisabled}
|
||||||
|
size="base"
|
||||||
|
scale={true}
|
||||||
|
isNeedFilter={false}
|
||||||
|
placeholder={searchPlaceHolder}
|
||||||
|
value={value}
|
||||||
|
onChange={onSearchChanged}
|
||||||
|
onClearSearch={onSearchChanged}
|
||||||
|
/>
|
||||||
|
{allowCreation && (
|
||||||
|
<Button
|
||||||
|
className="add_new_btn"
|
||||||
|
primary={false}
|
||||||
|
size="base"
|
||||||
|
label=""
|
||||||
|
icon={
|
||||||
|
<Icons.PlusIcon
|
||||||
|
size="medium"
|
||||||
|
isfill={true}
|
||||||
|
color="#D8D8D8"
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
onClick={onAddNewClick}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ADSelectorMainHeader.propTypes = {
|
||||||
|
searchPlaceHolder: PropTypes.string,
|
||||||
|
value: PropTypes.string,
|
||||||
|
isDisabled: PropTypes.bool,
|
||||||
|
allowCreation: PropTypes.bool,
|
||||||
|
style: PropTypes.object,
|
||||||
|
onSearchChanged: PropTypes.func,
|
||||||
|
onAddNewClick: PropTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ADSelectorMainHeader;
|
@ -0,0 +1,41 @@
|
|||||||
|
import React from "react";
|
||||||
|
import PropTypes from "prop-types";
|
||||||
|
import Checkbox from "../../../../checkbox";
|
||||||
|
import Link from "../../../../link";
|
||||||
|
|
||||||
|
const ADSelectorBodyRow = (props) => {
|
||||||
|
const { key, label, isChecked, style, onChange, onSelect } = props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="option" style={style} key={key}>
|
||||||
|
{props.hasOwnProperty("isChecked") ? (
|
||||||
|
<Checkbox
|
||||||
|
label={label}
|
||||||
|
isChecked={isChecked}
|
||||||
|
className="option_checkbox"
|
||||||
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Link
|
||||||
|
as="span"
|
||||||
|
truncate={true}
|
||||||
|
className="option_link"
|
||||||
|
onClick={onSelect}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
ADSelectorBodyRow.propTypes = {
|
||||||
|
key: PropTypes.string,
|
||||||
|
label: PropTypes.string,
|
||||||
|
isChecked: PropTypes.bool,
|
||||||
|
style: PropTypes.object,
|
||||||
|
onChange: PropTypes.func,
|
||||||
|
onSelect: PropTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ADSelectorBodyRow;
|
@ -5221,6 +5221,11 @@ extsprintf@^1.2.0:
|
|||||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
|
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
|
||||||
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
|
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
|
||||||
|
|
||||||
|
faker@^4.1.0:
|
||||||
|
version "4.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/faker/-/faker-4.1.0.tgz#1e45bbbecc6774b3c195fad2835109c6d748cc3f"
|
||||||
|
integrity sha1-HkW7vsxndLPBlfrSg1EJxtdIzD8=
|
||||||
|
|
||||||
fast-deep-equal@^2.0.1:
|
fast-deep-equal@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
|
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
|
||||||
@ -9857,6 +9862,11 @@ react-virtualized-auto-sizer@^1.0.2:
|
|||||||
resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.2.tgz#a61dd4f756458bbf63bd895a92379f9b70f803bd"
|
resolved "https://registry.yarnpkg.com/react-virtualized-auto-sizer/-/react-virtualized-auto-sizer-1.0.2.tgz#a61dd4f756458bbf63bd895a92379f9b70f803bd"
|
||||||
integrity sha512-MYXhTY1BZpdJFjUovvYHVBmkq79szK/k7V3MO+36gJkWGkrXKtyr4vCPtpphaTLRAdDNoYEYFZWE8LjN+PIHNg==
|
integrity sha512-MYXhTY1BZpdJFjUovvYHVBmkq79szK/k7V3MO+36gJkWGkrXKtyr4vCPtpphaTLRAdDNoYEYFZWE8LjN+PIHNg==
|
||||||
|
|
||||||
|
react-window-infinite-loader@^1.0.5:
|
||||||
|
version "1.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-window-infinite-loader/-/react-window-infinite-loader-1.0.5.tgz#6fe094d538a88978c2c9b623052bc50cb28c2abc"
|
||||||
|
integrity sha512-IcPIq8lADK3zsAcqoLqQGyduicqR6jWkiK2VUX5sKSI9X/rou6OWlOEexnGyujdNTG7hSG8OVBFEhLSDs4qrxg==
|
||||||
|
|
||||||
react-window@^1.8.5:
|
react-window@^1.8.5:
|
||||||
version "1.8.5"
|
version "1.8.5"
|
||||||
resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.5.tgz#a56b39307e79979721021f5d06a67742ecca52d1"
|
resolved "https://registry.yarnpkg.com/react-window/-/react-window-1.8.5.tgz#a56b39307e79979721021f5d06a67742ecca52d1"
|
||||||
|
Loading…
Reference in New Issue
Block a user