@onewelcome/react-lib-components 6.5.0 → 6.6.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.
Files changed (113) hide show
  1. package/dist/cjs/Form/Select/MultiSelect/MultiOption.cjs.js +1 -1
  2. package/dist/cjs/Form/Select/MultiSelect/MultiOption.cjs.js.map +1 -1
  3. package/dist/cjs/Form/Select/MultiSelect/MultiSelect.cjs.js +1 -1
  4. package/dist/cjs/Form/Select/MultiSelect/MultiSelect.cjs.js.map +1 -1
  5. package/dist/cjs/Form/Select/MultiSelect/MultiSelect.module.cjs.js +1 -1
  6. package/dist/cjs/Form/Select/MultiSelect/SelectButton.cjs.js +1 -1
  7. package/dist/cjs/Form/Select/MultiSelect/SelectButton.cjs.js.map +1 -1
  8. package/dist/cjs/Form/Select/MultiSelect/SelectButton.module.cjs.js +1 -1
  9. package/dist/cjs/Form/Select/MultiSelect/SelectedOptions.cjs.js +1 -1
  10. package/dist/cjs/Form/Select/MultiSelect/SelectedOptions.cjs.js.map +1 -1
  11. package/dist/cjs/Form/Select/MultiSelect/useArrowNavigation.cjs.js +2 -0
  12. package/dist/cjs/Form/Select/MultiSelect/useArrowNavigation.cjs.js.map +1 -0
  13. package/dist/cjs/Form/Select/MultiSelect/useSearch.cjs.js +2 -0
  14. package/dist/cjs/Form/Select/MultiSelect/useSearch.cjs.js.map +1 -0
  15. package/dist/cjs/Form/Select/SingleSelect/Option.cjs.js +1 -1
  16. package/dist/cjs/Form/Select/SingleSelect/Option.cjs.js.map +1 -1
  17. package/dist/cjs/Form/Select/SingleSelect/Select.cjs.js +1 -1
  18. package/dist/cjs/Form/Select/SingleSelect/Select.cjs.js.map +1 -1
  19. package/dist/cjs/Form/Select/SingleSelect/Select.module.cjs.js +1 -1
  20. package/dist/cjs/Form/Select/SingleSelect/useArrowNavigation.cjs.js +2 -0
  21. package/dist/cjs/Form/Select/SingleSelect/useArrowNavigation.cjs.js.map +1 -0
  22. package/dist/cjs/Form/Select/SingleSelect/useSearch.cjs.js +2 -0
  23. package/dist/cjs/Form/Select/SingleSelect/useSearch.cjs.js.map +1 -0
  24. package/dist/cjs/Form/Select/useAddNewBtn.cjs.js +1 -1
  25. package/dist/cjs/Form/Select/useAddNewBtn.cjs.js.map +1 -1
  26. package/dist/cjs/Form/Select/useAddNewBtn.module.cjs.js +1 -1
  27. package/dist/cjs/Form/Select/useSelectPositionList.cjs.js +2 -0
  28. package/dist/cjs/Form/Select/useSelectPositionList.cjs.js.map +1 -0
  29. package/dist/cjs/src/components/Form/Select/MultiSelect/MultiSelect.test.d.ts +63 -1
  30. package/dist/cjs/src/components/Form/Select/MultiSelect/MultiSelectKeyboardNavigation.test.d.ts +1 -0
  31. package/dist/cjs/src/components/Form/Select/MultiSelect/SelectedOptions.d.ts +2 -1
  32. package/dist/cjs/src/components/Form/Select/MultiSelect/useArrowNavigation.d.ts +16 -0
  33. package/dist/cjs/src/components/Form/Select/MultiSelect/useSearch.d.ts +34 -0
  34. package/dist/cjs/src/components/Form/Select/Select.interfaces.d.ts +1 -0
  35. package/dist/cjs/src/components/Form/Select/SingleSelect/Option.d.ts +1 -0
  36. package/dist/cjs/src/components/Form/Select/SingleSelect/useArrowNavigation.d.ts +5 -0
  37. package/dist/cjs/src/components/Form/Select/{useSearch.d.ts → SingleSelect/useSearch.d.ts} +2 -1
  38. package/dist/cjs/src/components/Form/Select/useAddNewBtn.d.ts +10 -3
  39. package/dist/cjs/src/components/Form/Select/useSelectPositionList.d.ts +12 -0
  40. package/dist/cjs/src/util/helper.cjs.js +1 -1
  41. package/dist/cjs/src/util/helper.cjs.js.map +1 -1
  42. package/dist/cjs/src/util/helper.d.ts +1 -0
  43. package/dist/esm/Form/Select/MultiSelect/MultiOption.esm.js +1 -1
  44. package/dist/esm/Form/Select/MultiSelect/MultiOption.esm.js.map +1 -1
  45. package/dist/esm/Form/Select/MultiSelect/MultiSelect.esm.js +1 -1
  46. package/dist/esm/Form/Select/MultiSelect/MultiSelect.esm.js.map +1 -1
  47. package/dist/esm/Form/Select/MultiSelect/MultiSelect.module.esm.js +1 -1
  48. package/dist/esm/Form/Select/MultiSelect/SelectButton.esm.js +1 -1
  49. package/dist/esm/Form/Select/MultiSelect/SelectButton.esm.js.map +1 -1
  50. package/dist/esm/Form/Select/MultiSelect/SelectButton.module.esm.js +1 -1
  51. package/dist/esm/Form/Select/MultiSelect/SelectedOptions.esm.js +1 -1
  52. package/dist/esm/Form/Select/MultiSelect/SelectedOptions.esm.js.map +1 -1
  53. package/dist/esm/Form/Select/MultiSelect/useArrowNavigation.esm.js +2 -0
  54. package/dist/esm/Form/Select/MultiSelect/useArrowNavigation.esm.js.map +1 -0
  55. package/dist/esm/Form/Select/MultiSelect/useSearch.esm.js +2 -0
  56. package/dist/esm/Form/Select/MultiSelect/useSearch.esm.js.map +1 -0
  57. package/dist/esm/Form/Select/SingleSelect/Option.esm.js +1 -1
  58. package/dist/esm/Form/Select/SingleSelect/Option.esm.js.map +1 -1
  59. package/dist/esm/Form/Select/SingleSelect/Select.esm.js +1 -1
  60. package/dist/esm/Form/Select/SingleSelect/Select.esm.js.map +1 -1
  61. package/dist/esm/Form/Select/SingleSelect/Select.module.esm.js +1 -1
  62. package/dist/esm/Form/Select/SingleSelect/useArrowNavigation.esm.js +2 -0
  63. package/dist/esm/Form/Select/SingleSelect/useArrowNavigation.esm.js.map +1 -0
  64. package/dist/esm/Form/Select/SingleSelect/useSearch.esm.js +2 -0
  65. package/dist/esm/Form/Select/SingleSelect/useSearch.esm.js.map +1 -0
  66. package/dist/esm/Form/Select/useAddNewBtn.esm.js +1 -1
  67. package/dist/esm/Form/Select/useAddNewBtn.esm.js.map +1 -1
  68. package/dist/esm/Form/Select/useAddNewBtn.module.esm.js +1 -1
  69. package/dist/esm/Form/Select/useSelectPositionList.esm.js +2 -0
  70. package/dist/esm/Form/Select/useSelectPositionList.esm.js.map +1 -0
  71. package/dist/esm/src/components/Form/Select/MultiSelect/MultiSelect.test.d.ts +63 -1
  72. package/dist/esm/src/components/Form/Select/MultiSelect/MultiSelectKeyboardNavigation.test.d.ts +1 -0
  73. package/dist/esm/src/components/Form/Select/MultiSelect/SelectedOptions.d.ts +2 -1
  74. package/dist/esm/src/components/Form/Select/MultiSelect/useArrowNavigation.d.ts +16 -0
  75. package/dist/esm/src/components/Form/Select/MultiSelect/useSearch.d.ts +34 -0
  76. package/dist/esm/src/components/Form/Select/Select.interfaces.d.ts +1 -0
  77. package/dist/esm/src/components/Form/Select/SingleSelect/Option.d.ts +1 -0
  78. package/dist/esm/src/components/Form/Select/SingleSelect/useArrowNavigation.d.ts +5 -0
  79. package/dist/esm/src/components/Form/Select/{useSearch.d.ts → SingleSelect/useSearch.d.ts} +2 -1
  80. package/dist/esm/src/components/Form/Select/useAddNewBtn.d.ts +10 -3
  81. package/dist/esm/src/components/Form/Select/useSelectPositionList.d.ts +12 -0
  82. package/dist/esm/src/util/helper.d.ts +1 -0
  83. package/dist/esm/src/util/helper.esm.js +1 -1
  84. package/dist/esm/src/util/helper.esm.js.map +1 -1
  85. package/package.json +6 -6
  86. package/src/components/Form/Select/MultiSelect/MultiOption.tsx +36 -3
  87. package/src/components/Form/Select/MultiSelect/MultiSelect.module.scss +29 -19
  88. package/src/components/Form/Select/MultiSelect/MultiSelect.tsx +85 -62
  89. package/src/components/Form/Select/MultiSelect/SelectButton.module.scss +1 -1
  90. package/src/components/Form/Select/MultiSelect/SelectButton.tsx +1 -1
  91. package/src/components/Form/Select/MultiSelect/SelectedOptions.tsx +5 -4
  92. package/src/components/Form/Select/MultiSelect/useArrowNavigation.ts +128 -0
  93. package/src/components/Form/Select/MultiSelect/useSearch.tsx +126 -0
  94. package/src/components/Form/Select/Select.interfaces.ts +1 -0
  95. package/src/components/Form/Select/SingleSelect/Option.tsx +15 -4
  96. package/src/components/Form/Select/SingleSelect/Select.module.scss +13 -2
  97. package/src/components/Form/Select/SingleSelect/Select.tsx +7 -3
  98. package/src/components/Form/Select/{SelectService.ts → SingleSelect/useArrowNavigation.ts} +1 -101
  99. package/src/components/Form/Select/{useSearch.tsx → SingleSelect/useSearch.tsx} +3 -2
  100. package/src/components/Form/Select/useAddNewBtn.module.scss +18 -4
  101. package/src/components/Form/Select/useAddNewBtn.tsx +42 -8
  102. package/src/components/Form/Select/useSelectPositionList.ts +113 -0
  103. package/src/util/helper.tsx +2 -0
  104. package/dist/cjs/Form/Select/SelectService.cjs.js +0 -2
  105. package/dist/cjs/Form/Select/SelectService.cjs.js.map +0 -1
  106. package/dist/cjs/Form/Select/useSearch.cjs.js +0 -2
  107. package/dist/cjs/Form/Select/useSearch.cjs.js.map +0 -1
  108. package/dist/cjs/src/components/Form/Select/SelectService.d.ts +0 -17
  109. package/dist/esm/Form/Select/SelectService.esm.js +0 -2
  110. package/dist/esm/Form/Select/SelectService.esm.js.map +0 -1
  111. package/dist/esm/Form/Select/useSearch.esm.js +0 -2
  112. package/dist/esm/Form/Select/useSearch.esm.js.map +0 -1
  113. package/dist/esm/src/components/Form/Select/SelectService.d.ts +0 -17
@@ -1,2 +1,2 @@
1
- const t=(t=15,e)=>{let r=["1","2","3","4","5","6","7","8","9","0","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"];let o="";for(let n=0;n<t&&o.length<t;n++){let t=typeof e==="string"&&(e===null||e===void 0?void 0:e[n])!==void 0&&!/\s/.test(e[n])?e[n]:"";o=o+t+r[Math.floor(Math.random()*r.length)]}return o.slice(0,t)};const e=(t,e,r=true)=>{if(r)return Object.keys(t).reduce(((r,o)=>{if(e.test(o))r[o]=t[o];return r}),{});else return Object.entries(t).filter((([t])=>!e.test(t))).reduce(((t,e)=>({...t,[e[0]]:e[1]})),{})};const r=(t,e)=>{let r;return function o(...n){const l=()=>{clearTimeout(r);t(...n)};clearTimeout(r);r=setTimeout(l,e)}};const o=(t,e)=>{let r=0;return function(){let o=Date.now();if(o-r>=e){t();r=o}}};const n=t=>t*parseFloat(getComputedStyle(document.documentElement).fontSize);const l=(t,e)=>{if(!e)return t;let r={...t};for(let o in e)if(Object.prototype.hasOwnProperty.call(e,o))if(typeof e[o]==="object"&&e[o]!==null&&Object.prototype.hasOwnProperty.call(t,o)&&!Array.isArray(e[o]))r[o]=l(t[o],e[o]);else r[o]=e[o];return r};export{r as debounce,l as deepMerge,e as filterProps,t as generateID,n as remToPx,o as throttle};
1
+ const t=(t=15,e)=>{let r=["1","2","3","4","5","6","7","8","9","0","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"];let o="";for(let n=0;n<t&&o.length<t;n++){let t=typeof e==="string"&&(e===null||e===void 0?void 0:e[n])!==void 0&&!/\s/.test(e[n])?e[n]:"";o=o+t+r[Math.floor(Math.random()*r.length)]}return o.slice(0,t)};const e=(t,e,r=true)=>{if(r)return Object.keys(t).reduce(((r,o)=>{if(e.test(o))r[o]=t[o];return r}),{});else return Object.entries(t).filter((([t])=>!e.test(t))).reduce(((t,e)=>({...t,[e[0]]:e[1]})),{})};const r=(t,e)=>{let r;return function o(...n){const l=()=>{clearTimeout(r);t(...n)};clearTimeout(r);r=setTimeout(l,e)}};const o=(t,e)=>{let r=0;return function(){let o=Date.now();if(o-r>=e){t();r=o}}};const n=t=>t*parseFloat(getComputedStyle(document.documentElement).fontSize);const l=(t,e)=>{if(!e)return t;let r={...t};for(let o in e)if(Object.prototype.hasOwnProperty.call(e,o))if(typeof e[o]==="object"&&e[o]!==null&&Object.prototype.hasOwnProperty.call(t,o)&&!Array.isArray(e[o]))r[o]=l(t[o],e[o]);else r[o]=e[o];return r};const c=t=>t.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");export{r as debounce,l as deepMerge,c as escapeRegExp,e as filterProps,t as generateID,n as remToPx,o as throttle};
2
2
  //# sourceMappingURL=helper.esm.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"helper.esm.js","sources":["../../../../../../src/util/helper.tsx"],"sourcesContent":["/*\n * Copyright 2022 OneWelcome B.V.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\ntype KeyValuePair = { [key: string]: unknown };\n\nexport const generateID = (length = 15, stringToWeaveIn?: string) => {\n /** We will make sure to mesh the generate id and name property together to basically create a unique ID */\n let hashCharacters = [\n \"1\",\n \"2\",\n \"3\",\n \"4\",\n \"5\",\n \"6\",\n \"7\",\n \"8\",\n \"9\",\n \"0\",\n \"A\",\n \"B\",\n \"C\",\n \"D\",\n \"E\",\n \"F\",\n \"G\",\n \"H\",\n \"I\",\n \"J\",\n \"K\",\n \"L\",\n \"M\",\n \"N\",\n \"O\",\n \"P\",\n \"Q\",\n \"R\",\n \"S\",\n \"T\",\n \"U\",\n \"V\",\n \"W\",\n \"X\",\n \"Y\",\n \"Z\",\n \"a\",\n \"b\",\n \"c\",\n \"d\",\n \"e\",\n \"f\",\n \"g\",\n \"h\",\n \"i\",\n \"j\",\n \"k\",\n \"l\",\n \"m\",\n \"n\",\n \"o\",\n \"p\",\n \"q\",\n \"r\",\n \"s\",\n \"t\",\n \"u\",\n \"v\",\n \"w\",\n \"x\",\n \"y\",\n \"z\"\n ];\n\n let id = \"\";\n\n /** Generate an id of x characters in length */\n for (let i = 0; i < length && id.length < length; i++) {\n let stringCharacter =\n typeof stringToWeaveIn === \"string\" &&\n stringToWeaveIn?.[i] !== undefined &&\n !/\\s/.test(stringToWeaveIn[i])\n ? stringToWeaveIn[i]\n : \"\";\n id = id + stringCharacter + hashCharacters[Math.floor(Math.random() * hashCharacters.length)];\n }\n\n return id.slice(0, length);\n};\n\nexport const filterProps = (props: any, regexPattern: RegExp, returnFiltered: boolean = true) => {\n if (returnFiltered) {\n return Object.keys(props).reduce((acc: KeyValuePair, key) => {\n if (regexPattern.test(key)) {\n acc[key] = props[key];\n }\n\n return acc;\n }, {});\n } else {\n return Object.entries(props)\n .filter(([key]) => !regexPattern.test(key))\n .reduce(\n (prevObj, currKeyValPair) => ({ ...prevObj, [currKeyValPair[0]]: currKeyValPair[1] }),\n {}\n );\n }\n};\n\nexport const debounce = (fn: (...args: unknown[]) => unknown, delay: number) => {\n let timeout: undefined | ReturnType<typeof setTimeout>;\n\n return function executedFunction(...args: unknown[]) {\n const later = () => {\n clearTimeout(timeout);\n fn(...args);\n };\n\n clearTimeout(timeout);\n\n timeout = setTimeout(later, delay);\n };\n};\n\nexport const throttle = (fn: (...args: unknown[]) => unknown, delay: number) => {\n let lastTime = 0;\n\n return function () {\n let now = Date.now();\n\n if (now - lastTime >= delay) {\n fn();\n lastTime = now;\n }\n };\n};\n\nexport const isEqual = (x: any, y: any): boolean => {\n const typesCoincide = x && y && typeof x === \"object\" && typeof y === \"object\";\n return typesCoincide\n ? Object.keys(x).length === Object.keys(y).length &&\n Object.keys(x).every(key => isEqual(x[key], y[key]))\n : x === y;\n};\n\nexport const areArraysDifferent = (\n arr1: Record<string, any>[],\n arr2: Record<string, any>[],\n key: string\n) => {\n if (arr1.length !== arr2.length) {\n return true;\n } else {\n const firstFilteredArray = arr1.filter(arr1Item =>\n arr2.some((arr2Item: { [x: string]: any }) => !isEqual(arr1Item[key], arr2Item[key]))\n );\n const secondFilteredArray = arr2.filter(arr2Item =>\n arr1.some((arr1Item: { [x: string]: any }) => !isEqual(arr1Item[key], arr2Item[key]))\n );\n\n return !!firstFilteredArray.length || !!secondFilteredArray.length;\n }\n};\n\nexport const getValueByPath = (obj: { [key: string]: any }, path: string): any => {\n return path.split(\".\").reduce((res, prop) => {\n return res[prop];\n }, obj);\n};\n\n/** Source: https://stackoverflow.com/a/42769683/5084110 */\nexport const remToPx = (rem: number): number => {\n return rem * parseFloat(getComputedStyle(document.documentElement).fontSize);\n};\n\nexport const isJsonString = (str: any) => {\n try {\n JSON.parse(str);\n } catch (e) {\n return false;\n }\n return true;\n};\n\ntype ObjectType = { [key: string]: any };\n\nexport const deepMerge = <T extends {}>(obj1: ObjectType, obj2: ObjectType | false): T => {\n if (!obj2) return obj1 as T;\n\n let result: ObjectType = { ...obj1 };\n\n for (let key in obj2) {\n if (Object.prototype.hasOwnProperty.call(obj2, key)) {\n if (\n typeof obj2[key] === \"object\" &&\n obj2[key] !== null &&\n Object.prototype.hasOwnProperty.call(obj1, key) &&\n !Array.isArray(obj2[key])\n ) {\n result[key] = deepMerge(obj1[key], obj2[key]);\n } else {\n result[key] = obj2[key];\n }\n }\n }\n\n return result as T;\n};\n"],"names":["generateID","length","stringToWeaveIn","hashCharacters","id","i","stringCharacter","undefined","test","Math","floor","random","slice","filterProps","props","regexPattern","returnFiltered","Object","keys","reduce","acc","key","entries","filter","prevObj","currKeyValPair","debounce","fn","delay","timeout","executedFunction","args","later","clearTimeout","setTimeout","throttle","lastTime","now","Date","remToPx","rem","parseFloat","getComputedStyle","document","documentElement","fontSize","deepMerge","obj1","obj2","result","prototype","hasOwnProperty","call","Array","isArray"],"mappings":"AAkBa,MAAAA,EAAa,CAACC,EAAS,GAAIC,KAEtC,IAAIC,EAAiB,CACnB,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,KAGF,IAAIC,EAAK,GAGT,IAAK,IAAIC,EAAI,EAAGA,EAAIJ,GAAUG,EAAGH,OAASA,EAAQI,IAAK,CACrD,IAAIC,SACKJ,IAAoB,WAC3BA,UAAAA,SAAe,OAAA,EAAfA,EAAkBG,WAAOE,IACxB,KAAKC,KAAKN,EAAgBG,IACvBH,EAAgBG,GAChB,GACND,EAAKA,EAAKE,EAAkBH,EAAeM,KAAKC,MAAMD,KAAKE,SAAWR,EAAeF,QACtF,CAED,OAAOG,EAAGQ,MAAM,EAAGX,EAAO,EAGrB,MAAMY,EAAc,CAACC,EAAYC,EAAsBC,EAA0B,QACtF,GAAIA,EACF,OAAOC,OAAOC,KAAKJ,GAAOK,QAAO,CAACC,EAAmBC,KACnD,GAAIN,EAAaP,KAAKa,GACpBD,EAAIC,GAAOP,EAAMO,GAGnB,OAAOD,CAAG,GACT,CAAE,QAEL,OAAOH,OAAOK,QAAQR,GACnBS,QAAO,EAAEF,MAAUN,EAAaP,KAAKa,KACrCF,QACC,CAACK,EAASC,KAAc,IAAWD,EAAS,CAACC,EAAe,IAAKA,EAAe,MAChF,CAAE,EAEP,QAGUC,EAAW,CAACC,EAAqCC,KAC5D,IAAIC,EAEJ,OAAO,SAASC,KAAoBC,GAClC,MAAMC,EAAQ,KACZC,aAAaJ,GACbF,KAAMI,EAAK,EAGbE,aAAaJ,GAEbA,EAAUK,WAAWF,EAAOJ,EAC9B,CAAC,QAGUO,EAAW,CAACR,EAAqCC,KAC5D,IAAIQ,EAAW,EAEf,OAAO,WACL,IAAIC,EAAMC,KAAKD,MAEf,GAAIA,EAAMD,GAAYR,EAAO,CAC3BD,IACAS,EAAWC,CACZ,CACH,CAAC,EAqCU,MAAAE,EAAWC,GACfA,EAAMC,WAAWC,iBAAiBC,SAASC,iBAAiBC,gBAcxDC,EAAY,CAAeC,EAAkBC,KACxD,IAAKA,EAAM,OAAOD,EAElB,IAAIE,EAAqB,IAAKF,GAE9B,IAAK,IAAI1B,KAAO2B,EACd,GAAI/B,OAAOiC,UAAUC,eAAeC,KAAKJ,EAAM3B,GAC7C,UACS2B,EAAK3B,KAAS,UACrB2B,EAAK3B,KAAS,MACdJ,OAAOiC,UAAUC,eAAeC,KAAKL,EAAM1B,KAC1CgC,MAAMC,QAAQN,EAAK3B,IAEpB4B,EAAO5B,GAAOyB,EAAUC,EAAK1B,GAAM2B,EAAK3B,SAExC4B,EAAO5B,GAAO2B,EAAK3B,GAKzB,OAAO4B,CAAW"}
1
+ {"version":3,"file":"helper.esm.js","sources":["../../../../../../src/util/helper.tsx"],"sourcesContent":["/*\n * Copyright 2022 OneWelcome B.V.\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\ntype KeyValuePair = { [key: string]: unknown };\n\nexport const generateID = (length = 15, stringToWeaveIn?: string) => {\n /** We will make sure to mesh the generate id and name property together to basically create a unique ID */\n let hashCharacters = [\n \"1\",\n \"2\",\n \"3\",\n \"4\",\n \"5\",\n \"6\",\n \"7\",\n \"8\",\n \"9\",\n \"0\",\n \"A\",\n \"B\",\n \"C\",\n \"D\",\n \"E\",\n \"F\",\n \"G\",\n \"H\",\n \"I\",\n \"J\",\n \"K\",\n \"L\",\n \"M\",\n \"N\",\n \"O\",\n \"P\",\n \"Q\",\n \"R\",\n \"S\",\n \"T\",\n \"U\",\n \"V\",\n \"W\",\n \"X\",\n \"Y\",\n \"Z\",\n \"a\",\n \"b\",\n \"c\",\n \"d\",\n \"e\",\n \"f\",\n \"g\",\n \"h\",\n \"i\",\n \"j\",\n \"k\",\n \"l\",\n \"m\",\n \"n\",\n \"o\",\n \"p\",\n \"q\",\n \"r\",\n \"s\",\n \"t\",\n \"u\",\n \"v\",\n \"w\",\n \"x\",\n \"y\",\n \"z\"\n ];\n\n let id = \"\";\n\n /** Generate an id of x characters in length */\n for (let i = 0; i < length && id.length < length; i++) {\n let stringCharacter =\n typeof stringToWeaveIn === \"string\" &&\n stringToWeaveIn?.[i] !== undefined &&\n !/\\s/.test(stringToWeaveIn[i])\n ? stringToWeaveIn[i]\n : \"\";\n id = id + stringCharacter + hashCharacters[Math.floor(Math.random() * hashCharacters.length)];\n }\n\n return id.slice(0, length);\n};\n\nexport const filterProps = (props: any, regexPattern: RegExp, returnFiltered: boolean = true) => {\n if (returnFiltered) {\n return Object.keys(props).reduce((acc: KeyValuePair, key) => {\n if (regexPattern.test(key)) {\n acc[key] = props[key];\n }\n\n return acc;\n }, {});\n } else {\n return Object.entries(props)\n .filter(([key]) => !regexPattern.test(key))\n .reduce(\n (prevObj, currKeyValPair) => ({ ...prevObj, [currKeyValPair[0]]: currKeyValPair[1] }),\n {}\n );\n }\n};\n\nexport const debounce = (fn: (...args: unknown[]) => unknown, delay: number) => {\n let timeout: undefined | ReturnType<typeof setTimeout>;\n\n return function executedFunction(...args: unknown[]) {\n const later = () => {\n clearTimeout(timeout);\n fn(...args);\n };\n\n clearTimeout(timeout);\n\n timeout = setTimeout(later, delay);\n };\n};\n\nexport const throttle = (fn: (...args: unknown[]) => unknown, delay: number) => {\n let lastTime = 0;\n\n return function () {\n let now = Date.now();\n\n if (now - lastTime >= delay) {\n fn();\n lastTime = now;\n }\n };\n};\n\nexport const isEqual = (x: any, y: any): boolean => {\n const typesCoincide = x && y && typeof x === \"object\" && typeof y === \"object\";\n return typesCoincide\n ? Object.keys(x).length === Object.keys(y).length &&\n Object.keys(x).every(key => isEqual(x[key], y[key]))\n : x === y;\n};\n\nexport const areArraysDifferent = (\n arr1: Record<string, any>[],\n arr2: Record<string, any>[],\n key: string\n) => {\n if (arr1.length !== arr2.length) {\n return true;\n } else {\n const firstFilteredArray = arr1.filter(arr1Item =>\n arr2.some((arr2Item: { [x: string]: any }) => !isEqual(arr1Item[key], arr2Item[key]))\n );\n const secondFilteredArray = arr2.filter(arr2Item =>\n arr1.some((arr1Item: { [x: string]: any }) => !isEqual(arr1Item[key], arr2Item[key]))\n );\n\n return !!firstFilteredArray.length || !!secondFilteredArray.length;\n }\n};\n\nexport const getValueByPath = (obj: { [key: string]: any }, path: string): any => {\n return path.split(\".\").reduce((res, prop) => {\n return res[prop];\n }, obj);\n};\n\n/** Source: https://stackoverflow.com/a/42769683/5084110 */\nexport const remToPx = (rem: number): number => {\n return rem * parseFloat(getComputedStyle(document.documentElement).fontSize);\n};\n\nexport const isJsonString = (str: any) => {\n try {\n JSON.parse(str);\n } catch (e) {\n return false;\n }\n return true;\n};\n\ntype ObjectType = { [key: string]: any };\n\nexport const deepMerge = <T extends {}>(obj1: ObjectType, obj2: ObjectType | false): T => {\n if (!obj2) return obj1 as T;\n\n let result: ObjectType = { ...obj1 };\n\n for (let key in obj2) {\n if (Object.prototype.hasOwnProperty.call(obj2, key)) {\n if (\n typeof obj2[key] === \"object\" &&\n obj2[key] !== null &&\n Object.prototype.hasOwnProperty.call(obj1, key) &&\n !Array.isArray(obj2[key])\n ) {\n result[key] = deepMerge(obj1[key], obj2[key]);\n } else {\n result[key] = obj2[key];\n }\n }\n }\n\n return result as T;\n};\n\nexport const escapeRegExp = (str: string) => str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n"],"names":["generateID","length","stringToWeaveIn","hashCharacters","id","i","stringCharacter","undefined","test","Math","floor","random","slice","filterProps","props","regexPattern","returnFiltered","Object","keys","reduce","acc","key","entries","filter","prevObj","currKeyValPair","debounce","fn","delay","timeout","executedFunction","args","later","clearTimeout","setTimeout","throttle","lastTime","now","Date","remToPx","rem","parseFloat","getComputedStyle","document","documentElement","fontSize","deepMerge","obj1","obj2","result","prototype","hasOwnProperty","call","Array","isArray","escapeRegExp","str","replace"],"mappings":"AAkBa,MAAAA,EAAa,CAACC,EAAS,GAAIC,KAEtC,IAAIC,EAAiB,CACnB,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,IACA,KAGF,IAAIC,EAAK,GAGT,IAAK,IAAIC,EAAI,EAAGA,EAAIJ,GAAUG,EAAGH,OAASA,EAAQI,IAAK,CACrD,IAAIC,SACKJ,IAAoB,WAC3BA,UAAAA,SAAe,OAAA,EAAfA,EAAkBG,WAAOE,IACxB,KAAKC,KAAKN,EAAgBG,IACvBH,EAAgBG,GAChB,GACND,EAAKA,EAAKE,EAAkBH,EAAeM,KAAKC,MAAMD,KAAKE,SAAWR,EAAeF,QACtF,CAED,OAAOG,EAAGQ,MAAM,EAAGX,EAAO,EAGrB,MAAMY,EAAc,CAACC,EAAYC,EAAsBC,EAA0B,QACtF,GAAIA,EACF,OAAOC,OAAOC,KAAKJ,GAAOK,QAAO,CAACC,EAAmBC,KACnD,GAAIN,EAAaP,KAAKa,GACpBD,EAAIC,GAAOP,EAAMO,GAGnB,OAAOD,CAAG,GACT,CAAE,QAEL,OAAOH,OAAOK,QAAQR,GACnBS,QAAO,EAAEF,MAAUN,EAAaP,KAAKa,KACrCF,QACC,CAACK,EAASC,KAAc,IAAWD,EAAS,CAACC,EAAe,IAAKA,EAAe,MAChF,CAAE,EAEP,QAGUC,EAAW,CAACC,EAAqCC,KAC5D,IAAIC,EAEJ,OAAO,SAASC,KAAoBC,GAClC,MAAMC,EAAQ,KACZC,aAAaJ,GACbF,KAAMI,EAAK,EAGbE,aAAaJ,GAEbA,EAAUK,WAAWF,EAAOJ,EAC9B,CAAC,QAGUO,EAAW,CAACR,EAAqCC,KAC5D,IAAIQ,EAAW,EAEf,OAAO,WACL,IAAIC,EAAMC,KAAKD,MAEf,GAAIA,EAAMD,GAAYR,EAAO,CAC3BD,IACAS,EAAWC,CACZ,CACH,CAAC,EAqCU,MAAAE,EAAWC,GACfA,EAAMC,WAAWC,iBAAiBC,SAASC,iBAAiBC,gBAcxDC,EAAY,CAAeC,EAAkBC,KACxD,IAAKA,EAAM,OAAOD,EAElB,IAAIE,EAAqB,IAAKF,GAE9B,IAAK,IAAI1B,KAAO2B,EACd,GAAI/B,OAAOiC,UAAUC,eAAeC,KAAKJ,EAAM3B,GAC7C,UACS2B,EAAK3B,KAAS,UACrB2B,EAAK3B,KAAS,MACdJ,OAAOiC,UAAUC,eAAeC,KAAKL,EAAM1B,KAC1CgC,MAAMC,QAAQN,EAAK3B,IAEpB4B,EAAO5B,GAAOyB,EAAUC,EAAK1B,GAAM2B,EAAK3B,SAExC4B,EAAO5B,GAAO2B,EAAK3B,GAKzB,OAAO4B,CAAW,EAGP,MAAAM,EAAgBC,GAAgBA,EAAIC,QAAQ,sBAAuB"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "homepage": "http://onewelcome.github.io/react-lib-components",
3
3
  "name": "@onewelcome/react-lib-components",
4
- "version": "6.5.0",
4
+ "version": "6.6.0",
5
5
  "license": "Apache-2.0",
6
6
  "author": "OneWelcome B.V.",
7
7
  "main": "dist/cjs/src/index.cjs.js",
@@ -82,14 +82,14 @@
82
82
  "@testing-library/user-event": "^14.5.2",
83
83
  "@types/jest": "^29.5.12",
84
84
  "@types/mdx": "^2.0.12",
85
- "@types/react": "^18.2.72",
86
- "@types/react-dom": "^18.2.22",
85
+ "@types/react": "^18.2.73",
86
+ "@types/react-dom": "^18.2.23",
87
87
  "@types/react-router": "^5.1.20",
88
88
  "@types/react-router-dom": "^5.3.3",
89
- "@typescript-eslint/eslint-plugin": "^6.21.0",
90
- "@typescript-eslint/parser": "^6.21.0",
89
+ "@typescript-eslint/eslint-plugin": "^7.5.0",
90
+ "@typescript-eslint/parser": "^7.5.0",
91
91
  "babel-loader": "^9.1.3",
92
- "chromatic": "^10.9.6",
92
+ "chromatic": "^11.2.0",
93
93
  "css-loader": "^6.10.0",
94
94
  "eslint": "^8.57.0",
95
95
  "eslint-config-prettier": "^9.1.0",
@@ -14,18 +14,51 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- import React, { ForwardRefRenderFunction } from "react";
17
+ import React, { ForwardRefRenderFunction, RefObject, createRef, useEffect } from "react";
18
18
  import { Props as SelectOptionProps, Option as SelectOption } from "../SingleSelect/Option";
19
19
 
20
+ import classes from "./MultiSelect.module.scss";
21
+
20
22
  export interface Props extends SelectOptionProps {
21
23
  fixed?: boolean;
22
24
  }
23
25
 
24
26
  const MultiOptionComponent: ForwardRefRenderFunction<HTMLLIElement, Props> = (
25
- { fixed: _fixed, ...rest }: Props,
27
+ { fixed: _fixed, hasFocus, className, ...rest }: Props,
26
28
  ref
27
29
  ) => {
28
- return <SelectOption ref={ref} {...rest} />;
30
+ let innerOptionRef = (ref as RefObject<HTMLLIElement>) || createRef<HTMLLIElement>();
31
+
32
+ const additionalClasses = [];
33
+ className && additionalClasses.push(className);
34
+ hasFocus && additionalClasses.push(classes["focus"]);
35
+
36
+ const scrollToSelectedElement = (element: HTMLLIElement) => {
37
+ const listbox = element.parentElement;
38
+ const listboxWrapper = element.parentElement?.parentElement;
39
+ const isListboxWrapperScrollable = !!listboxWrapper?.style.maxHeight;
40
+ if (isListboxWrapperScrollable) {
41
+ listboxWrapper?.scrollTo(0, element.offsetTop - (listboxWrapper?.offsetHeight ?? 1) / 2);
42
+ }
43
+ listbox?.scrollTo(0, element.offsetTop - (listbox?.offsetHeight ?? 1) / 2);
44
+ };
45
+
46
+ useEffect(() => {
47
+ if (innerOptionRef.current && hasFocus) {
48
+ scrollToSelectedElement(innerOptionRef.current);
49
+ }
50
+ }, [hasFocus, innerOptionRef]);
51
+
52
+ return (
53
+ <SelectOption
54
+ ref={innerOptionRef}
55
+ isSelected={hasFocus}
56
+ disableDefaultSelectedStyle
57
+ className={additionalClasses.join(" ")}
58
+ aria-disabled={false}
59
+ {...rest}
60
+ />
61
+ );
29
62
  };
30
63
 
31
64
  export const MultiOption = React.forwardRef(MultiOptionComponent);
@@ -90,6 +90,7 @@ $listItemHeight: 2.5rem;
90
90
  display: flex;
91
91
  align-items: center;
92
92
  padding: 0.1875rem 0;
93
+ gap: 0.375rem;
93
94
  }
94
95
  }
95
96
 
@@ -143,9 +144,21 @@ $listItemHeight: 2.5rem;
143
144
  opacity: 0.05;
144
145
  }
145
146
 
146
- &:focus {
147
- outline: var(--input-border-width-focus) solid var(--color-primary300);
148
- outline-offset: -var(--input-border-width-focus);
147
+ &:focus,
148
+ &.focus {
149
+ outline: none;
150
+
151
+ &::before {
152
+ @include mixins.focusVisibleOutline($outlineOffset: 0, $selectors: null);
153
+ content: "";
154
+ position: absolute;
155
+ top: 0;
156
+ left: 0.125rem;
157
+ height: 100%;
158
+ width: calc(100% - 0.25rem);
159
+ opacity: 1;
160
+ z-index: calc(variables.$popover-z-index + 1);
161
+ }
149
162
  }
150
163
 
151
164
  &:hover:after,
@@ -166,20 +179,6 @@ $listItemHeight: 2.5rem;
166
179
  }
167
180
  }
168
181
 
169
- .selected-option {
170
- &:before {
171
- content: "";
172
- position: absolute;
173
- top: 0;
174
- left: 0;
175
- height: 100%;
176
- border-top-right-radius: 0.125rem;
177
- border-bottom-right-radius: 0.125rem;
178
- border-left: 0.25rem solid var(--color-primary);
179
- }
180
- color: var(--color-primary);
181
- }
182
-
183
182
  .status {
184
183
  padding: 0.3125rem;
185
184
  display: flex;
@@ -210,11 +209,22 @@ $listItemHeight: 2.5rem;
210
209
  }
211
210
 
212
211
  .select-search {
213
- position: relative;
214
- width: 100%;
212
+ flex: 1;
215
213
  box-sizing: border-box;
216
214
  border-bottom-left-radius: 0;
217
215
  border-bottom-right-radius: 0;
216
+ border: 0;
217
+ background-color: transparent;
218
+ color: var(--default);
219
+ font-family: var(--font-family);
220
+ line-height: 1.3333;
221
+ margin: 0;
222
+ padding: 0;
223
+
224
+ &:focus-visible,
225
+ &:focus {
226
+ outline: none;
227
+ }
218
228
  }
219
229
 
220
230
  .disabled {
@@ -17,28 +17,35 @@
17
17
  import classes from "./MultiSelect.module.scss";
18
18
 
19
19
  import React, {
20
- createRef,
21
20
  ForwardRefRenderFunction,
22
21
  Fragment,
23
22
  ReactElement,
23
+ createRef,
24
24
  useEffect,
25
25
  useRef,
26
26
  useState
27
27
  } from "react";
28
- import { Icon, Icons } from "../../../Icon/Icon";
29
28
  import { useBodyClick } from "../../../../hooks/useBodyClick";
30
- import readyclasses from "../../../../readyclasses.module.scss";
31
- import { filterProps } from "../../../../util/helper";
32
- import { useArrowNavigation, useSelectPositionList } from "../SelectService";
33
29
  import { useDetermineStatusIcon } from "../../../../hooks/useDetermineStatusIcon";
34
- import { SelectedOptions, Display } from "./SelectedOptions";
35
- import { SelectButton } from "./SelectButton";
30
+ import readyclasses from "../../../../readyclasses.module.scss";
31
+ import { escapeRegExp, filterProps, generateID } from "../../../../util/helper";
32
+ import { Icon, Icons } from "../../../Icon/Icon";
36
33
  import { MultiSelectProps } from "../Select.interfaces";
37
- import { useSearch } from "../useSearch";
38
34
  import { useAddNewBtn } from "../useAddNewBtn";
35
+ import { useSelectPositionList } from "../useSelectPositionList";
36
+ import { SelectButton } from "./SelectButton";
37
+ import { Display, SelectedOptions } from "./SelectedOptions";
38
+ import { useArrowNavigation } from "./useArrowNavigation";
39
+ import { useSearch } from "./useSearch";
40
+
41
+ const getOptionId = (multiSelectId: string, optionIndex: number) =>
42
+ `${multiSelectId}_option${optionIndex}`;
43
+
44
+ const getListboxId = (multiSelectId: string) => `${multiSelectId}_listbox`;
39
45
 
40
46
  const MultiSelectComponent: ForwardRefRenderFunction<HTMLSelectElement, MultiSelectProps> = (
41
47
  {
48
+ id,
42
49
  children,
43
50
  name,
44
51
  disabled = false,
@@ -56,42 +63,51 @@ const MultiSelectComponent: ForwardRefRenderFunction<HTMLSelectElement, MultiSel
56
63
  noResultsLabel = "No results found",
57
64
  onChange,
58
65
  addNew,
59
- search,
66
+ search = { enabled: true, renderThreshold: 0 },
60
67
  ...rest
61
68
  }: MultiSelectProps,
62
69
  ref
63
70
  ) => {
71
+ const multiSelectId = useRef(id ?? generateID(20));
64
72
  const [expanded, setExpanded] = useState(false);
65
- const [display, setDisplay] = useState<Record<string, Display>>({});
73
+ const [display, setDisplay] = useState<Display[]>([]);
66
74
  const containerReference = useRef<HTMLDivElement>(null);
67
75
  const optionListReference = useRef<HTMLDivElement>(null);
68
- const [focusedSelectItem, setFocusedSelectItem] = useState(-1);
76
+ const [focusedSelectItem, setFocusedSelectItem] = useState(0);
69
77
  const [shouldClick, setShouldClick] =
70
78
  useState(
71
79
  false
72
80
  ); /** We need this, because whenever we use the arrow keys to select the select item, and we focus the currently selected item it fires the "click" listener in Option component. Instead, we only want this to fire if we press "enter" or "spacebar" so we set this to true whenever that is the case, and back to false when it has been executed. */
73
81
  const [shouldFocusButtonAfterClose, setShouldFocusButtonAfterClose] = useState(false);
74
- const optionsVisibleCount = React.Children.count(children) - Object.keys(display).length;
75
- const {
76
- filter,
77
- isSearching,
78
- renderSearch,
79
- searchInputRef,
80
- setIsSearching,
81
- searchThreshold,
82
- searchVisible
83
- } = useSearch({
82
+ const [optionsVisibleCount, setOptionsVisibleCount] = useState(
83
+ React.Children.count(children) - display.length
84
+ );
85
+ const { filter, renderSearch, searchInputRef, resetSearchState, searchVisible } = useSearch({
86
+ selectId: multiSelectId.current,
84
87
  expanded,
85
88
  search,
86
89
  searchInputClassName: classes["select-search"],
87
90
  optionsCount: optionsVisibleCount,
91
+ focusedSelectItem,
88
92
  setFocusedSelectItem,
89
93
  searchInputProps,
90
- searchPlaceholder
94
+ searchPlaceholder,
95
+ describedBy,
96
+ getOptionId,
97
+ getListboxId
91
98
  });
92
99
  const { addBtnRef, addNewBtnOptionsContainerClassName, renderAddNew } = useAddNewBtn({
100
+ id: getOptionId(multiSelectId.current, optionsVisibleCount),
93
101
  addNew,
94
- filter
102
+ filter,
103
+ focusedSelectItem,
104
+ optionsCount: optionsVisibleCount,
105
+ searchInputRef,
106
+ shouldClick,
107
+ onClickCallback: () => {
108
+ setShouldClick(false);
109
+ resetSearchState();
110
+ }
95
111
  });
96
112
 
97
113
  const nativeSelect = (ref as React.RefObject<HTMLSelectElement>) || createRef();
@@ -110,8 +126,8 @@ const MultiSelectComponent: ForwardRefRenderFunction<HTMLSelectElement, MultiSel
110
126
  });
111
127
  nativeSelect.current.dispatchEvent(new Event("change", { bubbles: true }));
112
128
  }
113
-
114
129
  setExpanded(false);
130
+ resetSearchState();
115
131
  };
116
132
 
117
133
  const onSelectedOptionRemoveHandler = (value: string) => {
@@ -126,33 +142,24 @@ const MultiSelectComponent: ForwardRefRenderFunction<HTMLSelectElement, MultiSel
126
142
  const { onArrowNavigation } = useArrowNavigation({
127
143
  expanded,
128
144
  setExpanded,
129
- isSearching,
130
- setIsSearching,
131
145
  setFocusedSelectItem,
132
- onOptionChangeHandler,
133
146
  childrenCount: optionsVisibleCount,
134
147
  setShouldClick,
135
- searchInputRef,
136
148
  addBtnRef,
137
- renderThreshold: searchThreshold
149
+ searchInputRef,
150
+ customSelectButtonRef,
151
+ onClose: resetSearchState
138
152
  });
139
153
 
140
154
  const { listPosition, opacity, optionsListMaxHeight, setListPosition, setOpacity } =
141
155
  useSelectPositionList({ expanded, optionListReference, containerReference, addBtnRef });
142
156
 
143
- const syncDisplayValue = (vals: string[]) => {
144
- const displayArray = React.Children.map(children, child => child).reduce(
145
- (prevOption, curOption) => {
146
- if (vals.includes(curOption.props.value)) {
147
- prevOption[curOption.props.value] = {
148
- label: curOption.props.children,
149
- fixed: curOption.props.fixed
150
- };
151
- }
152
- return prevOption;
153
- },
154
- {} as Record<string, Display>
155
- );
157
+ const syncDisplayValue = (values: string[]) => {
158
+ const options = React.Children.map(children, child => child);
159
+ const displayArray: Display[] = values.map(value => {
160
+ const option = options.find(option => option.props.value === value);
161
+ return { value, label: option?.props.children, fixed: option?.props.fixed };
162
+ });
156
163
  setDisplay(displayArray);
157
164
  };
158
165
 
@@ -177,31 +184,37 @@ const MultiSelectComponent: ForwardRefRenderFunction<HTMLSelectElement, MultiSel
177
184
  type ReactChildrenType = ReturnType<typeof React.Children.toArray>;
178
185
 
179
186
  const filterOutSelectedChildren = (internalChildren: ReactChildrenType) => {
180
- const selectedValues = Object.keys(display);
181
187
  return internalChildren.filter(
182
188
  child =>
183
189
  typeof child === "object" &&
184
190
  "props" in child &&
185
- !selectedValues.includes(child.props.value as string)
191
+ !display.find(option => option.value === child.props.value)
186
192
  );
187
193
  };
188
194
 
189
- if (isSearching || filter !== "") {
195
+ let results;
196
+ if (filter !== "") {
190
197
  const filteredChildren = React.Children.toArray(children).filter(
191
198
  child =>
192
- (child as ReactElement).props.children.toLowerCase().match(filter.toLowerCase()) !== null
199
+ (child as ReactElement).props.children
200
+ .toLowerCase()
201
+ .match(escapeRegExp(filter.toLowerCase())) !== null
193
202
  );
194
203
 
195
- const internalChildren = _internalRenderChildren(filterOutSelectedChildren(filteredChildren));
204
+ results = _internalRenderChildren(filterOutSelectedChildren(filteredChildren));
205
+ } else {
206
+ results = _internalRenderChildren(
207
+ filterOutSelectedChildren(React.Children.toArray(children))
208
+ );
209
+ }
196
210
 
197
- if (internalChildren.length === 0) {
198
- return <li className={classes["no-results"]}>{noResultsLabel}</li>;
199
- }
211
+ optionsVisibleCount !== results.length && setOptionsVisibleCount(results.length);
200
212
 
201
- return internalChildren;
213
+ if (results.length === 0) {
214
+ return <li className={classes["no-results"]}>{noResultsLabel}</li>;
202
215
  }
203
216
 
204
- return _internalRenderChildren(filterOutSelectedChildren(React.Children.toArray(children)));
217
+ return results;
205
218
 
206
219
  function _internalRenderChildren(internalChildren: ReactChildrenType) {
207
220
  return React.Children.map(internalChildren, (child, index) => {
@@ -211,13 +224,15 @@ const MultiSelectComponent: ForwardRefRenderFunction<HTMLSelectElement, MultiSel
211
224
  },
212
225
  onOptionSelect: (optionRef: React.RefObject<HTMLLIElement>) => {
213
226
  onOptionChangeHandler(optionRef.current);
227
+ setExpanded(false);
214
228
  setShouldClick(false);
215
229
  },
216
- isSearching: isSearching,
230
+ isSearching: false,
217
231
  selectOpened: expanded,
218
232
  childIndex: index,
219
233
  hasFocus: focusedSelectItem === index,
220
- shouldClick: shouldClick
234
+ shouldClick: shouldClick,
235
+ id: getOptionId(multiSelectId.current, index)
221
236
  });
222
237
  });
223
238
  }
@@ -238,16 +253,21 @@ const MultiSelectComponent: ForwardRefRenderFunction<HTMLSelectElement, MultiSel
238
253
  };
239
254
 
240
255
  useEffect(() => {
241
- if (expanded) {
242
- setFocusedSelectItem(0);
256
+ if (expanded && searchInputRef.current) {
243
257
  setShouldFocusButtonAfterClose(true);
258
+ searchInputRef.current.focus();
244
259
  }
245
260
 
246
261
  if (!expanded && customSelectButtonRef.current && shouldFocusButtonAfterClose) {
247
- customSelectButtonRef.current.focus();
248
262
  setShouldFocusButtonAfterClose(false);
263
+ customSelectButtonRef.current.focus();
249
264
  }
250
- }, [expanded, customSelectButtonRef.current, shouldFocusButtonAfterClose]);
265
+ }, [
266
+ expanded,
267
+ customSelectButtonRef.current,
268
+ shouldFocusButtonAfterClose,
269
+ searchInputRef.current
270
+ ]);
251
271
 
252
272
  useEffect(() => {
253
273
  syncDisplayValue(value);
@@ -272,7 +292,8 @@ const MultiSelectComponent: ForwardRefRenderFunction<HTMLSelectElement, MultiSel
272
292
  success && additionalClasses.push(classes.success);
273
293
 
274
294
  const onSelectButtonClick = () => {
275
- setExpanded(!expanded);
295
+ setExpanded(expanded => !expanded);
296
+ setShouldClick(false);
276
297
  };
277
298
 
278
299
  /** The native select is purely for external form libraries. We use it to emit an onChange with native select event object so they know exactly what's happening. */
@@ -295,16 +316,16 @@ const MultiSelectComponent: ForwardRefRenderFunction<HTMLSelectElement, MultiSel
295
316
  </select>
296
317
  <div
297
318
  {...filterProps(rest, /^data-/)}
319
+ id={multiSelectId.current}
298
320
  ref={containerReference}
299
321
  onKeyDown={onArrowNavigation}
300
322
  className={`custom-select ${classes.select} ${additionalClasses.join(" ")} ${
301
323
  className ?? ""
302
324
  }`}
303
325
  >
304
- {searchVisible && renderSearch()}
305
326
  <div
306
327
  className={`${classes["custom-select"]} ${additionalClasses.join(" ")} `}
307
- style={{ display: expanded && searchVisible ? "none" : "flex" }}
328
+ style={{ display: "flex" }}
308
329
  >
309
330
  <div className={classes["display-container"]} data-display>
310
331
  <SelectButton
@@ -331,10 +352,10 @@ const MultiSelectComponent: ForwardRefRenderFunction<HTMLSelectElement, MultiSel
331
352
  onRemove={onSelectedOptionRemoveHandler}
332
353
  />
333
354
  )}
355
+ {searchVisible && renderSearch()}
334
356
  </div>
335
357
  <div className={classes["status"]}>{icon || renderChevronIcon()}</div>
336
358
  </div>
337
-
338
359
  <div
339
360
  ref={optionListReference}
340
361
  className={`list-wrapper ${classes["list-wrapper"]}`}
@@ -347,8 +368,10 @@ const MultiSelectComponent: ForwardRefRenderFunction<HTMLSelectElement, MultiSel
347
368
  }}
348
369
  >
349
370
  <ul
371
+ id={getListboxId(multiSelectId.current)}
350
372
  className={addNewBtnOptionsContainerClassName}
351
373
  role="listbox"
374
+ aria-multiselectable="true"
352
375
  style={{ maxHeight: optionsListMaxHeight.list }}
353
376
  >
354
377
  {renderOptions()}
@@ -14,7 +14,7 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- .add-btn {
17
+ .btn {
18
18
  position: absolute;
19
19
  top: 0;
20
20
  left: 0;
@@ -26,7 +26,7 @@ const SelectButtonComponent: ForwardRefRenderFunction<HTMLButtonElement, Props>
26
26
  return (
27
27
  <button
28
28
  {...rest}
29
- className={classes["add-btn"]}
29
+ className={classes["btn"]}
30
30
  onClick={onClick}
31
31
  ref={ref}
32
32
  type="button"
@@ -20,12 +20,13 @@ import { Tag } from "../../../Tag/Tag";
20
20
  import classes from "./SelectedOptions.module.scss";
21
21
 
22
22
  export type Display = {
23
+ value: string;
23
24
  label: string;
24
25
  fixed?: boolean;
25
26
  };
26
27
 
27
28
  export interface Props extends ComponentPropsWithRef<"div"> {
28
- display: Record<string, Display>;
29
+ display: Display[];
29
30
  onRemove: (value: string) => void;
30
31
  disabled: boolean;
31
32
  }
@@ -36,9 +37,9 @@ const SelectedOptionsComponent: ForwardRefRenderFunction<HTMLDivElement, Props>
36
37
  ) => {
37
38
  return (
38
39
  <div {...rest} className={classes["options"]} ref={ref}>
39
- {Object.entries(display).map(([value, item]) => (
40
+ {display.map(item => (
40
41
  <Tag
41
- key={value}
42
+ key={item.value}
42
43
  onClick={(e: React.MouseEvent<HTMLDivElement>) => {
43
44
  e.stopPropagation();
44
45
  }}
@@ -48,7 +49,7 @@ const SelectedOptionsComponent: ForwardRefRenderFunction<HTMLDivElement, Props>
48
49
  ? {
49
50
  onRemove: (e: React.MouseEvent<HTMLButtonElement>) => {
50
51
  e.stopPropagation();
51
- onRemove(value);
52
+ onRemove(item.value);
52
53
  },
53
54
  className: classes["remove-btn"]
54
55
  }