@mctinetti/react-multiselectbox 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,21 @@
1
+ # react-multiselectbox
2
+
3
+ A React multiselect box, it can also be a dropdown by parametrization.
4
+
5
+ ## Build for prod
6
+ 1. copy myapp\react-multiselectbox
7
+ 2. cd \react-multiselectbox
8
+ 3. npm install
9
+ 4. npm run build
10
+
11
+ ## Developement
12
+ If you want to do developement:
13
+ 1. copy myapp\react-multiselectbox
14
+ 2. cd react-multiselectbox
15
+ 3. npm install
16
+ 4. cd react-multiselectbox\example
17
+ 5. npx webpack serve
18
+
19
+ ### [Changelog](CHANGELOG.md)
20
+
21
+ ### [MIT Licensed](LICENSE.md)
@@ -0,0 +1,2 @@
1
+ /*! For license information please see react-multiselectbox.js.LICENSE.txt */
2
+ !function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var r=t();for(var n in r)("object"==typeof exports?exports:e)[n]=r[n]}}(self,(()=>(()=>{var e={287:(e,t)=>{"use strict";var r=Symbol.for("react.element"),n=Symbol.for("react.portal"),o=Symbol.for("react.fragment"),i=Symbol.for("react.strict_mode"),u=Symbol.for("react.profiler"),a=Symbol.for("react.provider"),c=Symbol.for("react.context"),l=Symbol.for("react.forward_ref"),s=Symbol.for("react.suspense"),f=Symbol.for("react.memo"),d=Symbol.for("react.lazy"),p=Symbol.iterator,y={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},m=Object.assign,b={};function v(e,t,r){this.props=e,this.context=t,this.refs=b,this.updater=r||y}function h(){}function g(e,t,r){this.props=e,this.context=t,this.refs=b,this.updater=r||y}v.prototype.isReactComponent={},v.prototype.setState=function(e,t){if("object"!=typeof e&&"function"!=typeof e&&null!=e)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")},v.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")},h.prototype=v.prototype;var S=g.prototype=new h;S.constructor=g,m(S,v.prototype),S.isPureReactComponent=!0;var E=Array.isArray,_=Object.prototype.hasOwnProperty,O={current:null},k={key:!0,ref:!0,__self:!0,__source:!0};function w(e,t,n){var o,i={},u=null,a=null;if(null!=t)for(o in void 0!==t.ref&&(a=t.ref),void 0!==t.key&&(u=""+t.key),t)_.call(t,o)&&!k.hasOwnProperty(o)&&(i[o]=t[o]);var c=arguments.length-2;if(1===c)i.children=n;else if(1<c){for(var l=Array(c),s=0;s<c;s++)l[s]=arguments[s+2];i.children=l}if(e&&e.defaultProps)for(o in c=e.defaultProps)void 0===i[o]&&(i[o]=c[o]);return{$$typeof:r,type:e,key:u,ref:a,props:i,_owner:O.current}}function j(e){return"object"==typeof e&&null!==e&&e.$$typeof===r}var x=/\/+/g;function C(e,t){return"object"==typeof e&&null!==e&&null!=e.key?function(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,(function(e){return t[e]}))}(""+e.key):t.toString(36)}function P(e,t,o,i,u){var a=typeof e;"undefined"!==a&&"boolean"!==a||(e=null);var c=!1;if(null===e)c=!0;else switch(a){case"string":case"number":c=!0;break;case"object":switch(e.$$typeof){case r:case n:c=!0}}if(c)return u=u(c=e),e=""===i?"."+C(c,0):i,E(u)?(o="",null!=e&&(o=e.replace(x,"$&/")+"/"),P(u,t,o,"",(function(e){return e}))):null!=u&&(j(u)&&(u=function(e,t){return{$$typeof:r,type:e.type,key:t,ref:e.ref,props:e.props,_owner:e._owner}}(u,o+(!u.key||c&&c.key===u.key?"":(""+u.key).replace(x,"$&/")+"/")+e)),t.push(u)),1;if(c=0,i=""===i?".":i+":",E(e))for(var l=0;l<e.length;l++){var s=i+C(a=e[l],l);c+=P(a,t,o,s,u)}else if(s=function(e){return null===e||"object"!=typeof e?null:"function"==typeof(e=p&&e[p]||e["@@iterator"])?e:null}(e),"function"==typeof s)for(e=s.call(e),l=0;!(a=e.next()).done;)c+=P(a=a.value,t,o,s=i+C(a,l++),u);else if("object"===a)throw t=String(e),Error("Objects are not valid as a React child (found: "+("[object Object]"===t?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.");return c}function N(e,t,r){if(null==e)return e;var n=[],o=0;return P(e,n,"","",(function(e){return t.call(r,e,o++)})),n}function I(e){if(-1===e._status){var t=e._result;(t=t()).then((function(t){0!==e._status&&-1!==e._status||(e._status=1,e._result=t)}),(function(t){0!==e._status&&-1!==e._status||(e._status=2,e._result=t)})),-1===e._status&&(e._status=0,e._result=t)}if(1===e._status)return e._result.default;throw e._result}var R={current:null},T={transition:null},A={ReactCurrentDispatcher:R,ReactCurrentBatchConfig:T,ReactCurrentOwner:O};function D(){throw Error("act(...) is not supported in production builds of React.")}t.Children={map:N,forEach:function(e,t,r){N(e,(function(){t.apply(this,arguments)}),r)},count:function(e){var t=0;return N(e,(function(){t++})),t},toArray:function(e){return N(e,(function(e){return e}))||[]},only:function(e){if(!j(e))throw Error("React.Children.only expected to receive a single React element child.");return e}},t.Component=v,t.Fragment=o,t.Profiler=u,t.PureComponent=g,t.StrictMode=i,t.Suspense=s,t.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED=A,t.act=D,t.cloneElement=function(e,t,n){if(null==e)throw Error("React.cloneElement(...): The argument must be a React element, but you passed "+e+".");var o=m({},e.props),i=e.key,u=e.ref,a=e._owner;if(null!=t){if(void 0!==t.ref&&(u=t.ref,a=O.current),void 0!==t.key&&(i=""+t.key),e.type&&e.type.defaultProps)var c=e.type.defaultProps;for(l in t)_.call(t,l)&&!k.hasOwnProperty(l)&&(o[l]=void 0===t[l]&&void 0!==c?c[l]:t[l])}var l=arguments.length-2;if(1===l)o.children=n;else if(1<l){c=Array(l);for(var s=0;s<l;s++)c[s]=arguments[s+2];o.children=c}return{$$typeof:r,type:e.type,key:i,ref:u,props:o,_owner:a}},t.createContext=function(e){return(e={$$typeof:c,_currentValue:e,_currentValue2:e,_threadCount:0,Provider:null,Consumer:null,_defaultValue:null,_globalName:null}).Provider={$$typeof:a,_context:e},e.Consumer=e},t.createElement=w,t.createFactory=function(e){var t=w.bind(null,e);return t.type=e,t},t.createRef=function(){return{current:null}},t.forwardRef=function(e){return{$$typeof:l,render:e}},t.isValidElement=j,t.lazy=function(e){return{$$typeof:d,_payload:{_status:-1,_result:e},_init:I}},t.memo=function(e,t){return{$$typeof:f,type:e,compare:void 0===t?null:t}},t.startTransition=function(e){var t=T.transition;T.transition={};try{e()}finally{T.transition=t}},t.unstable_act=D,t.useCallback=function(e,t){return R.current.useCallback(e,t)},t.useContext=function(e){return R.current.useContext(e)},t.useDebugValue=function(){},t.useDeferredValue=function(e){return R.current.useDeferredValue(e)},t.useEffect=function(e,t){return R.current.useEffect(e,t)},t.useId=function(){return R.current.useId()},t.useImperativeHandle=function(e,t,r){return R.current.useImperativeHandle(e,t,r)},t.useInsertionEffect=function(e,t){return R.current.useInsertionEffect(e,t)},t.useLayoutEffect=function(e,t){return R.current.useLayoutEffect(e,t)},t.useMemo=function(e,t){return R.current.useMemo(e,t)},t.useReducer=function(e,t,r){return R.current.useReducer(e,t,r)},t.useRef=function(e){return R.current.useRef(e)},t.useState=function(e){return R.current.useState(e)},t.useSyncExternalStore=function(e,t,r){return R.current.useSyncExternalStore(e,t,r)},t.useTransition=function(){return R.current.useTransition()},t.version="18.3.1"},540:(e,t,r)=>{"use strict";e.exports=r(287)},556:(e,t,r)=>{e.exports=r(694)()},694:(e,t,r)=>{"use strict";var n=r(925);function o(){}function i(){}i.resetWarningCache=o,e.exports=function(){function e(e,t,r,o,i,u){if(u!==n){var a=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw a.name="Invariant Violation",a}}function t(){return e}e.isRequired=e;var r={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:t,element:e,elementType:e,instanceOf:t,node:e,objectOf:t,oneOf:t,oneOfType:t,shape:t,exact:t,checkPropTypes:i,resetWarningCache:o};return r.PropTypes=r,r}},925:e=>{"use strict";e.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},942:(e,t)=>{var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e="",t=0;t<arguments.length;t++){var r=arguments[t];r&&(e=u(e,i(r)))}return e}function i(e){if("string"==typeof e||"number"==typeof e)return e;if("object"!=typeof e)return"";if(Array.isArray(e))return o.apply(null,e);if(e.toString!==Object.prototype.toString&&!e.toString.toString().includes("[native code]"))return e.toString();var t="";for(var r in e)n.call(e,r)&&e[r]&&(t=u(t,r));return t}function u(e,t){return t?e?e+" "+t:e+t:e}e.exports?(o.default=o,e.exports=o):void 0===(r=function(){return o}.apply(t,[]))||(e.exports=r)}()}},t={};function r(n){var o=t[n];if(void 0!==o)return o.exports;var i=t[n]={exports:{}};return e[n](i,i.exports,r),i.exports}r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},r.d=(e,t)=>{for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),r.r=e=>{"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})};var n={};return(()=>{"use strict";r.r(n),r.d(n,{default:()=>b});var e=r(540),t=r(556),o=r.n(t),i=r(942),u=r.n(i);function a(e){return a="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},a(e)}function c(e,t){var r=Object.keys(e);if(Object.getOwnPropertySymbols){var n=Object.getOwnPropertySymbols(e);t&&(n=n.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),r.push.apply(r,n)}return r}function l(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{};t%2?c(Object(r),!0).forEach((function(t){s(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):c(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function s(e,t,r){return(t=function(e){var t=function(e){if("object"!=a(e)||!e)return e;var t=e[Symbol.toPrimitive];if(void 0!==t){var r=t.call(e,"string");if("object"!=a(r))return r;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(e)}(e);return"symbol"==a(t)?t:t+""}(t))in e?Object.defineProperty(e,t,{value:r,enumerable:!0,configurable:!0,writable:!0}):e[t]=r,e}function f(e){return function(e){if(Array.isArray(e))return y(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||p(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function d(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var r=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null!=r){var n,o,i,u,a=[],c=!0,l=!1;try{if(i=(r=r.call(e)).next,0===t){if(Object(r)!==r)return;c=!1}else for(;!(c=(n=i.call(r)).done)&&(a.push(n.value),a.length!==t);c=!0);}catch(e){l=!0,o=e}finally{try{if(!c&&null!=r.return&&(u=r.return(),Object(u)!==u))return}finally{if(l)throw o}}return a}}(e,t)||p(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function p(e,t){if(e){if("string"==typeof e)return y(e,t);var r={}.toString.call(e).slice(8,-1);return"Object"===r&&e.constructor&&(r=e.constructor.name),"Map"===r||"Set"===r?Array.from(e):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?y(e,t):void 0}}function y(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=Array(t);r<t;r++)n[r]=e[r];return n}var m=function(t){var r=t.id,n=t.name,o=(t.value,t.options),i=t.selectedItems,a=t.placeholder,c=t.disabled,s=t.onChange,p=(t.onBlur,t.onFocus,t.autoFocus),y=t.autoComplete,m=t.displayAsDropdown,b=void 0!==m&&m,v=d((0,e.useState)(""),2),h=v[0],g=v[1],S=d((0,e.useState)(!1),2),E=S[0],_=S[1],O=d((0,e.useState)(o),2),k=O[0],w=O[1],j=d((0,e.useState)(o.map((function(e,t){return{id:e.id,sortOrder:t}}))),2),x=j[0],C=j[1],P=d((0,e.useState)(i),2),N=P[0],I=P[1],R=d((0,e.useState)(!1),2),T=R[0],A=R[1],D=function(e,t){return e.filter((function(e){return e.label.toLowerCase().includes(t.toLowerCase())}))};(0,e.useEffect)((function(){C(o.map((function(e,t){return{id:e.id,sortOrder:t}}))),w(o),I(N.filter((function(e){return o.some((function(t){return t.id===e.id}))})))}),[o]);(0,e.useEffect)((function(){var e;e=h&&!b?D(N,h).filter((function(e){return!e.disabled})).length:N.filter((function(e){return!e.disabled})).length,_(k.filter((function(e){return!e.disabled})).length==e&&0!=k.length)}),[N]);var $=(0,e.useCallback)((function(e){b&&(L.current&&L.current.contains(e.target)?A(!0):(A(!1),g(""),w(o),N.length==o.length&&0!=o.length?_(!0):_(!1)))}),[o,N]),L=(0,e.useRef)(null);(0,e.useEffect)((function(){return document.addEventListener("click",$),function(){document.removeEventListener("click",$)}}),[$]);var V=e.createElement("label",{className:"itemlabel"},e.createElement("input",{type:"checkbox",className:"notVisible",checked:E,onChange:function(e){return function(e){var t;_(e.target.checked),t=0==e.target.checked?N.filter((function(e){return!k.some((function(t){return t.id===e.id&&!t.disabled}))})):[].concat(f(N),f(k.filter((function(e){return 1!=e.disabled})))).filter((function(e,t,r){return t===r.findIndex((function(t){return t.id===e.id}))})),I(t),s&&s(t,"selectedItems"),b&&w(o)}(e)}}),e.createElement("span",{className:"checkbox-custom"}),"Select All");return e.createElement("div",{className:"containerMultiSelectBox",ref:L},e.createElement("div",{id:"box1",className:u()(b?"boxDropDown":"box")},e.createElement("div",{className:"firstline"},e.createElement("div",{className:"leftDivs"},e.createElement("input",{autoFocus:p,autoComplete:y,type:"text",id:r,name:n,value:T?h:b?function(e,t){var r=e.map((function(e){return l(l({},e),{},{sortOrder:t.find((function(t){return t.id==e.id})).sortOrder})})).sort((function(e,t){return e.sortOrder-t.sortOrder})).map((function(e){return e.label})).join(", ");return r.length>30?"".concat(r.substring(0,30),"..."):r}(N,x):h,className:"searchField",disabled:c,placeholder:a||"Search...",onChange:function(e){return function(e){g(e.target.value);var t=e.target.value.trim(),r=o;t&&(r=D(o,t)),w(r),_(r.filter((function(e){return!e.disabled})).every((function(e){return N.some((function(t){return e.id===t.id}))}))&&r.length>0)}(e)}}))),e.createElement("div",{className:u()("items","selectAllLine",b?"notVisible":"")},V),e.createElement("div",{className:b?T?"itemsListScrollDropDown":"itemsListScrollDropDown notVisible":"itemsListScroll"},e.createElement("div",{className:u()("items","selectAllLine",b&&T?"":"notVisible")},V),e.createElement("div",{className:b?0==k.length?"itemsListScroll noItemsToList":"itemsListScroll":0==k.length?"noItemsToList inheritHeight":""},0==k.length?"No Items...":"",k.map((function(t,r){return e.createElement("div",{key:"chd01-"+t.id,className:u()("items",N.some((function(e){return e.id===t.id}))?"paintGray":"paintWhite")},e.createElement("label",{key:"chd02-"+t.id,className:u()("itemlabel",t.disabled?"itemlabeldisabled":"")},e.createElement("input",{key:"chd03-"+t.id,id:t.id,className:"notVisible",type:"checkbox",checked:1==N.some((function(e){return e.id===t.id}))||"",onChange:function(e){return function(e,t,r,n){var o,i={id:e.target.id,label:t,disabled:r,data:n};o=0==e.target.checked?N.filter((function(t){return t.id!==e.target.id})):[].concat(f(N),[i]),I(o),s&&s(o,"selectedItems")}(e,t.label,t.disabled,t.data)},disabled:t.disabled}),e.createElement("span",{className:"checkbox-custom"}),t.label," "))}))))),b?"":e.createElement("div",{id:"box2",className:"box",style:{backgroundColor:"white"}},e.createElement("div",{className:"firstline"},e.createElement("div",{className:"rightDivs"},N.length>0?N.length:"None"," Selected"),e.createElement("div",{className:"rightDivs"}," ",e.createElement("a",{href:"#",onClick:function(){f(N.filter((function(e){return e.disabled}))),I(f(N.filter((function(e){return e.disabled})))),s&&s(o,"selectedItems")},className:"link_clear"},"Clear All")," ")),e.createElement("div",{className:u()("itemsListScrollRight",0==N.length?"noItemsToList":"")},0==N.length?"No Items...":"",N.map((function(e){return l(l({},e),{},{sortOrder:x.find((function(t){return t.id==e.id})).sortOrder})})).sort((function(e,t){return e.sortOrder-t.sortOrder})).map((function(t){return e.createElement("div",{key:"chd04-"+t.id,className:u()("items","delete-div"),onClick:function(){return function(e){var t=N.filter((function(t){return t.id!=e||t.disabled}));I(t),s&&s(t,"selectedItems")}(t.id)}},e.createElement("label",{key:"chd02-"+t.id,className:u()("itemlabel",t.disabled?"itemlabeldisabled":"")},t.label),t.disabled?"":e.createElement("button",{key:"chd05-"+t.id,type:"button",className:"buttonDelete"},"x"))})))))};m.propTypes={id:o().string,options:o().array,selectedItems:o().array,name:o().string,value:o().any,placeholder:o().string,disabled:o().bool,onChange:o().func,onBlur:o().func,onFocus:o().func,autoFocus:o().any,autoComplete:o().any,displayAsDropdown:o().bool};const b=m})(),n})()));
@@ -0,0 +1,15 @@
1
+ /*!
2
+ Copyright (c) 2018 Jed Watson.
3
+ Licensed under the MIT License (MIT), see
4
+ http://jedwatson.github.io/classnames
5
+ */
6
+
7
+ /**
8
+ * @license React
9
+ * react.production.min.js
10
+ *
11
+ * Copyright (c) Facebook, Inc. and its affiliates.
12
+ *
13
+ * This source code is licensed under the MIT license found in the
14
+ * LICENSE file in the root directory of this source tree.
15
+ */
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@mctinetti/react-multiselectbox",
3
+ "version": "1.0.0",
4
+ "private": false,
5
+ "license": "MIT",
6
+ "description": "multiselectbox with option search.",
7
+ "package_json_docs": "https://docs.npmjs.com/files/package.json",
8
+ "main": "dist/react-multiselectbox.js",
9
+ "files": [
10
+ "react-multiselectbox.jsx",
11
+ "dist"
12
+ ],
13
+ "scripts": {
14
+ "build": "webpack"
15
+ },
16
+ "author": "Cristina Tinetti",
17
+ "dependencies": {
18
+ "classnames": "^2.5.1",
19
+ "css-loader": "^7.1.2",
20
+ "prop-types": "^15.8.1",
21
+ "react": "^18.3.1",
22
+ "react-dom": "^18.3.1",
23
+ "style-loader": "^4.0.0"
24
+ },
25
+ "devDependencies": {
26
+ "@babel/core": "^7.26.7",
27
+ "@babel/preset-env": "^7.26.7",
28
+ "@babel/preset-react": "^7.26.3",
29
+ "babel-loader": "^9.2.1",
30
+ "webpack": "^5.97.1",
31
+ "webpack-cli": "^6.0.1",
32
+ "webpack-dev-server": "^5.2.0"
33
+ }
34
+ }
@@ -0,0 +1,261 @@
1
+ import React, { useEffect, useRef, useState, useCallback } from 'react';
2
+ import PropTypes from "prop-types";
3
+ import classNames from 'classnames';
4
+
5
+ const MultiSelectBox = ({
6
+ id,
7
+ name,
8
+ value,
9
+ options,
10
+ selectedItems,
11
+ placeholder,
12
+ disabled,
13
+ onChange,
14
+ //onClick,
15
+ onBlur,
16
+ onFocus,
17
+ autoFocus,
18
+ autoComplete,
19
+ displayAsDropdown = false,
20
+ }) => {
21
+ let [searchValue, setSearchValue] = useState("")
22
+ let [checkedAllValue, setcheckedAllValue] = useState(false) // SelectAll
23
+ let [optionsMyState, setOptionsMyState] = useState(options)
24
+
25
+ let [optionsSortMyState, setOptionsSortMyState] = useState(options.map((item, index) => ({ // Items selected but I added orderSort
26
+ id:item.id,
27
+ sortOrder: index
28
+ })))
29
+ let [selectedItemsMyState, setSelectedItemsMyState] = useState( selectedItems )
30
+ const [isOpen, setIsOpen] = useState(false)
31
+
32
+ const filterProcess = (options, searchValue) => {
33
+ return options.filter(item => item.label.toLowerCase().includes(searchValue.toLowerCase()))
34
+ }
35
+
36
+ const handleChangeOnSearch = (e) => { //Search ...
37
+ setSearchValue(e.target.value);
38
+ const searchValue = e.target.value.trim()
39
+
40
+ let newOptions = options
41
+ if(searchValue){
42
+ newOptions = filterProcess(options,searchValue)
43
+ }
44
+ setOptionsMyState(newOptions)
45
+ setcheckedAllValue(newOptions.filter(i=>!i.disabled).every(itemA => selectedItemsMyState.some(itemB => itemA.id === itemB.id)) && newOptions.length > 0)
46
+ };
47
+
48
+ useEffect(() => {
49
+ setOptionsSortMyState(options.map((item, index) => ({ // Items selected but I added orderSort
50
+ id:item.id,
51
+ sortOrder: index
52
+ })))
53
+ setOptionsMyState(options)
54
+ setSelectedItemsMyState(selectedItemsMyState.filter(item => options.some(option => option.id === item.id))) // Removing items from the selectedItemsMyState if they are not in the options list
55
+ }, [options]);
56
+
57
+ const handleChangeCheckAll = (e) => { // SelectAll
58
+ setcheckedAllValue(e.target.checked)
59
+
60
+ let newSelectedItems
61
+ if (e.target.checked == false) {
62
+ //Remove the items listed on page
63
+ newSelectedItems = selectedItemsMyState.filter(itemA => !optionsMyState.some(option => option.id === itemA.id && !option.disabled ) );
64
+ } else {
65
+ //Add the items listed on page
66
+ newSelectedItems = [...selectedItemsMyState, ...optionsMyState.filter(ite=>ite.disabled!=true)].filter((value, index, self) =>
67
+ index === self.findIndex((t) => (
68
+ t.id === value.id
69
+ ))
70
+ )
71
+ }
72
+ setSelectedItemsMyState(newSelectedItems)
73
+ if (onChange) onChange(newSelectedItems,'selectedItems')
74
+
75
+ if (displayAsDropdown) setOptionsMyState(options)
76
+ }
77
+
78
+ const handleChangeIndividualCheck = (e, labeltxt, disabled, data) => {
79
+ let newSelectedItems
80
+ const newItem = { id: e.target.id, label: labeltxt, disabled: disabled, data: data};
81
+
82
+ newSelectedItems = e.target.checked == false ? (selectedItemsMyState.filter((item) => item.id !== e.target.id)) // removing
83
+ : ([...selectedItemsMyState,newItem]) // adding
84
+
85
+ setSelectedItemsMyState(newSelectedItems)
86
+ if (onChange) onChange(newSelectedItems,'selectedItems')
87
+ }
88
+
89
+ const handleBlur = (e) => {
90
+ // lose focus
91
+ };
92
+
93
+ const handleClickToClearAll = () =>{
94
+ let newSelectedItems = [ ...selectedItemsMyState.filter(item=>item.disabled)]
95
+ setSelectedItemsMyState([ ...selectedItemsMyState.filter(item=>item.disabled)])
96
+ if (onChange) onChange(options,'selectedItems') // sent to the main component all the list
97
+ }
98
+
99
+ const handleClickToRemoveItem = (id) =>{
100
+ let newSelectedItems = selectedItemsMyState.filter(item=> item.id != id || item.disabled )
101
+ setSelectedItemsMyState(newSelectedItems)
102
+ if (onChange) onChange(newSelectedItems,'selectedItems')
103
+ }
104
+
105
+ useEffect(()=> { // this effect it's basically to set the Select All checkbox
106
+ let selectedItemsLen
107
+ if(searchValue && !displayAsDropdown){
108
+ selectedItemsLen = filterProcess(selectedItemsMyState,searchValue).filter(option=>!option.disabled).length
109
+ } else{
110
+
111
+ selectedItemsLen = selectedItemsMyState.filter(option=>!option.disabled).length
112
+ }
113
+ setcheckedAllValue( optionsMyState.filter(option=>!option.disabled).length == selectedItemsLen ? optionsMyState.length==0 ? false : true
114
+ : false);
115
+ },[selectedItemsMyState])
116
+
117
+
118
+ const handleClickOnElement = useCallback((event) => {
119
+ if (displayAsDropdown) {
120
+ if(ref.current && ref.current.contains(event.target)){
121
+ setIsOpen(true)
122
+ }else{
123
+ setIsOpen(false) // Close the item list
124
+ setSearchValue('') // Clean the search value in case it has value
125
+ setOptionsMyState(options) // Reset the options
126
+ selectedItemsMyState.length==options.length && options.length!=0 ? setcheckedAllValue(true) : setcheckedAllValue(false) // Check if Select All should be mark or not
127
+ }
128
+ }
129
+ }, [options, selectedItemsMyState]);
130
+
131
+ // Code to handle clicks in/outside the component
132
+ const ref = useRef(null);
133
+ useEffect(() => {
134
+ //Mount
135
+ document.addEventListener("click", handleClickOnElement);
136
+ //Unmount
137
+ return () => {
138
+ document.removeEventListener("click", handleClickOnElement);
139
+ };
140
+ }, [handleClickOnElement]);
141
+
142
+ const generatePreview = (selectedItems,optionsSort) => {
143
+ const preview = selectedItems.map(item => ({
144
+ ...item,
145
+ sortOrder: optionsSort.find(option => option.id == item.id).sortOrder
146
+ })).sort((a,b) => a.sortOrder - b.sortOrder).map(item => item.label).join(', ')
147
+ return preview.length > 30 ? `${preview.substring(0, 30)}...` : preview
148
+ }
149
+
150
+ const checkboxSelectAll = <label className={"itemlabel"}>
151
+ <input type="checkbox" className="notVisible" checked={checkedAllValue} onChange={(e) => handleChangeCheckAll(e)}/>
152
+ <span className="checkbox-custom"></span>
153
+ Select All
154
+ </label>
155
+
156
+ return(
157
+ <div className={"containerMultiSelectBox"} ref={ref}>
158
+ <div id="box1" className={ classNames(displayAsDropdown?"boxDropDown":"box")} >
159
+ <div className='firstline'>
160
+ <div className='leftDivs'>
161
+ <input
162
+ autoFocus={autoFocus}
163
+ autoComplete={autoComplete}
164
+ type='text'
165
+ id={id}
166
+ name={name}
167
+ value= { isOpen ? searchValue : displayAsDropdown ? generatePreview(selectedItemsMyState, optionsSortMyState)
168
+ : searchValue }
169
+ className={'searchField'}
170
+ disabled={disabled}
171
+ placeholder={placeholder?placeholder:'Search...'}
172
+ onChange={(e) => handleChangeOnSearch(e)}
173
+ //onClick={(e) => handleClickOnSearch(e)}
174
+ //onBlur={(e) => handleBlur(e)}
175
+ //onFocus={(e) => handleFocus(e)} classNames("items", "selectAllLine", displayAsDropdown ? isOpen ? "":"notVisible" :'')
176
+ />
177
+ </div>
178
+ </div>
179
+
180
+ <div className={ classNames("items", "selectAllLine", displayAsDropdown ? "notVisible" :'') }>
181
+ {checkboxSelectAll}
182
+ </div>
183
+
184
+
185
+ <div className= { displayAsDropdown ? isOpen ? "itemsListScrollDropDown":"itemsListScrollDropDown notVisible" :'itemsListScroll' }>
186
+
187
+ <div className={ classNames("items", "selectAllLine", displayAsDropdown ? isOpen ? "":"notVisible" :'notVisible') }>
188
+ {checkboxSelectAll}
189
+ </div>
190
+
191
+ <div className={ displayAsDropdown ? optionsMyState.length == 0 ? "itemsListScroll noItemsToList":"itemsListScroll" : optionsMyState.length == 0 ? "noItemsToList inheritHeight":"" }>
192
+ { optionsMyState.length == 0? 'No Items...':'' }
193
+ {
194
+ optionsMyState.map(( (item, index) => (
195
+ <div key={'chd01-'+item.id}
196
+ className={ classNames("items", selectedItemsMyState.some((itemSelected) => itemSelected.id === item.id)? "paintGray" : "paintWhite" )}>
197
+
198
+ <label key={'chd02-'+item.id} className={ classNames("itemlabel", item.disabled?"itemlabeldisabled":"")}>
199
+
200
+ <input key={'chd03-'+item.id}
201
+ id={item.id}
202
+ className="notVisible"
203
+ type="checkbox"
204
+ checked={ selectedItemsMyState.some((itemSelected) => itemSelected.id === item.id)==true? true : "" }
205
+ onChange={(e) => handleChangeIndividualCheck(e, item.label, item.disabled, item.data) }
206
+ disabled={item.disabled}
207
+ />
208
+ <span className="checkbox-custom"></span>
209
+
210
+ {item.label} </label>
211
+ </div>
212
+ ) ))
213
+ }
214
+ </div>
215
+ </div>
216
+ </div>
217
+
218
+ { displayAsDropdown ? '' :
219
+ <div id="box2" className="box" style={{backgroundColor:'white'}}>
220
+ <div className='firstline'>
221
+ <div className='rightDivs' >{selectedItemsMyState.length>0?selectedItemsMyState.length:'None'} Selected</div>
222
+ <div className='rightDivs'> <a href="#" onClick={handleClickToClearAll} className='link_clear'>Clear All</a> </div>
223
+ </div>
224
+ <div className={ classNames("itemsListScrollRight", selectedItemsMyState.length==0?"noItemsToList":"")}>
225
+ { selectedItemsMyState.length == 0? 'No Items...':'' }
226
+ {
227
+ selectedItemsMyState.map(item => ({
228
+ ...item,
229
+ sortOrder: optionsSortMyState.find(option => option.id == item.id).sortOrder
230
+ })).sort((a,b) => a.sortOrder - b.sortOrder).map(( (items) => (
231
+ <div key={'chd04-'+items.id} className={ classNames("items", "delete-div")} onClick={()=>handleClickToRemoveItem(items.id)} >
232
+ <label key={'chd02-'+items.id} className={ classNames("itemlabel", items.disabled?"itemlabeldisabled":"")}>{items.label}</label>
233
+ {items.disabled?"":<button key={'chd05-'+items.id} type="button" className='buttonDelete'>x</button>}
234
+ </div>
235
+ )))
236
+ }
237
+ </div>
238
+ </div>
239
+ }
240
+ </div>
241
+ )
242
+ };
243
+
244
+ MultiSelectBox.propTypes = {
245
+ id: PropTypes.string,
246
+ options: PropTypes.array,
247
+ selectedItems: PropTypes.array,
248
+ name: PropTypes.string,
249
+ value: PropTypes.any,
250
+ placeholder: PropTypes.string,
251
+ disabled: PropTypes.bool,
252
+ onChange: PropTypes.func,
253
+ //onClick: PropTypes.func,
254
+ onBlur: PropTypes.func,
255
+ onFocus: PropTypes.func,
256
+ autoFocus: PropTypes.any,
257
+ autoComplete: PropTypes.any,
258
+ displayAsDropdown: PropTypes.bool,
259
+ }
260
+
261
+ export default MultiSelectBox;