@contentful/f36-multiselect 4.26.0 → 4.26.1

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/dist/esm/index.js CHANGED
@@ -10,10 +10,10 @@ import { ChevronDownIcon, CloseIcon, SearchIcon } from '@contentful/f36-icons';
10
10
  import { SkeletonContainer, SkeletonBodyText } from '@contentful/f36-skeleton';
11
11
  import { Popover } from '@contentful/f36-popover';
12
12
  import { Tooltip } from '@contentful/f36-tooltip';
13
- import Ae from 'react-focus-lock';
13
+ import De from 'react-focus-lock';
14
14
 
15
- var ce=Object.defineProperty,pe=Object.defineProperties;var me=Object.getOwnPropertyDescriptors;var O=Object.getOwnPropertySymbols;var U=Object.prototype.hasOwnProperty,_=Object.prototype.propertyIsEnumerable;var j=(e,t,o)=>t in e?ce(e,t,{enumerable:!0,configurable:!0,writable:!0,value:o}):e[t]=o,b=(e,t)=>{for(var o in t||(t={}))U.call(t,o)&&j(e,o,t[o]);if(O)for(var o of O(t))_.call(t,o)&&j(e,o,t[o]);return e},H=(e,t)=>pe(e,me(t));var N=(e,t)=>{var o={};for(var n in e)U.call(e,n)&&t.indexOf(n)<0&&(o[n]=e[n]);if(e!=null&&O)for(var n of O(e))t.indexOf(n)<0&&_.call(e,n)&&(o[n]=e[n]);return o};var S=()=>({multiselect:css({position:"relative",width:"100%"}),triggerButton:css({justifyContent:"space-between"}),currentSelection:css({display:"inline-block",width:"100%",whiteSpace:"nowrap",textOverflow:"ellipsis",overflow:"hidden",verticalAlign:"bottom",marginRight:r.spacing2Xs}),currentSelectionWithClearButton:css({paddingRight:"40px"}),currentSelectionAddition:css({color:r.gray600}),searchBar:css({paddingTop:r.spacing2Xs,position:"sticky",top:"0px",zIndex:r.zIndexWorkbenchHeader,backgroundColor:r.colorWhite}),inputField:css({padding:`6px ${r.spacingXl} 10px ${r.spacingXs}`,textOverflow:"ellipsis",whiteSpace:"nowrap",border:"none",borderRadius:"0px",borderBottom:`1px solid ${r.gray200}`,boxShadow:"none","&:focus, &:active, &:active:hover":{boxShadow:"none",borderBottom:`1px solid ${r.gray200}`}}),toggleButton:css({position:"absolute",top:"1px",right:"1px",zIndex:r.zIndexDefault,padding:r.spacing2Xs,height:r.spacingXl}),content:e=>css({overflow:"auto",maxHeight:`${e}px`}),container:css({}),list:css({listStyle:"none",padding:`${r.spacing2Xs}`,margin:0}),groupTitle:css({padding:`6px ${r.spacingXs}`,lineHeight:r.lineHeightM}),noMatchesTitle:css({color:r.gray500,margin:r.spacingM,textAlign:"center"}),clearSelectionButton:css({marginLeft:"-80px"}),selectAll:css({borderBottom:`1px solid ${r.gray200}`,marginBottom:r.spacing2Xs,paddingBottom:r.spacing2Xs,"label > *":{fontWeight:r.fontWeightMedium}}),option:css({listStyleType:"none"}),optionText:css({alignItems:"center",display:"flex",span:{color:r.gray900,fontWeight:r.fontWeightDemiBold}}),optionCheck:({isActive:e,isDisabled:t})=>css({label:cx(getMenuItemStyles({isActive:e,isDisabled:t}),css({width:"100%"}))})});var M=y=>{var f=y,{children:e,label:t,value:o,itemId:n,onSelectItem:s,searchValue:c,isChecked:v=!1,isDisabled:p=!1,className:d}=f,g=N(f,["children","label","value","itemId","onSelectItem","searchValue","isChecked","isDisabled","className"]);let m=S();return l.createElement("li",b({className:cx(m.option,d)},g),l.createElement(Checkbox,{id:n,value:o,onChange:x=>s(x),isChecked:v,isDisabled:p,className:m.optionCheck({isActive:v,isDisabled:p})},l.createElement(Text,{className:m.optionText,"data-test-id":`cf-multiselect-list-item-${n}`},typeof t=="string"?l.createElement(L,{item:t,inputValue:c}):e)))};function L({item:e,inputValue:t=""}){let{before:o,match:n,after:s}=getStringMatch(e,t.trim());return o.length+n.length+s.length===0?l.createElement(l.Fragment,null,e):l.createElement(l.Fragment,null,o,l.createElement("span",{"data-test-id":"cf-multiselect-item-match"},n),s)}L.displayName="HighlightedItem";var G=({searchValue:e,setSearchValue:t,onSearchValueChange:o,searchInputName:n,searchInputRef:s,resetSearchRef:c,searchPlaceholder:v="Search",focusList:p})=>{let d=S(),g=useRef(null),y=useCallback(m=>{t(m.target.value),o==null||o(m);},[o,t]),f=useCallback(()=>{if(!e)return;p(),Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value").set.call(g.current,"");let x=new Event("change",{bubbles:!0});g.current.dispatchEvent(x);},[e,p]);return l.createElement("div",{className:d.searchBar},l.createElement(TextInput,{"aria-label":"Search",type:"text",value:e,className:d.inputField,testId:"cf-multiselect-search",placeholder:v,onChange:y,ref:mergeRefs(s,g),name:n,size:"small"}),l.createElement(IconButton,{ref:c,"aria-label":e?"Clear search":"Search",className:d.toggleButton,variant:"transparent",icon:e?l.createElement(CloseIcon,{variant:"muted"}):l.createElement(SearchIcon,{variant:"muted"}),onClick:f,isDisabled:!e,size:"small"}))};var Q=(e,t,o)=>l.Children.map(e,n=>{if(!l.isValidElement(n))return n;if(t(n))return o(n);let s=Q(n.props.children,t,o);return l.cloneElement(n,{children:s})}),Y=(e,t)=>{let o=0;return l.Children.forEach(e,n=>{l.isValidElement(n)&&(t(n)?o+=1:o+=Y(n.props.children,t));}),o};function We(e,t){let{className:o,startIcon:n,placeholder:s="Select one or more Items",currentSelection:c=[],toggleRef:v,isLoading:p=!1,testId:d="cf-multiselect",noMatchesMessage:g="No matches found",searchProps:y={},popoverProps:f={},children:m,onBlur:x,onClearSelection:P}=e,{listMaxHeight:ee=180,listRef:te,onClose:W}=f,a=S(),[T,oe]=useState(""),[D,X]=useState(!1),F=useRef(null),R=c.length>1&&typeof P=="function",$=typeof e.onSearchValueChange=="function"||typeof y.onSearchValueChange=="function",ne=Object.keys(y).length>0?y:{onSearchValueChange:e.onSearchValueChange,searchPlaceholder:e.searchPlaceholder,searchInputName:e.searchInputName,searchInputRef:e.searchInputRef},B=useCallback(()=>{var u;(u=F.current)==null||u.focus();},[]),le=u=>{P==null||P(),u.stopPropagation();},re=useCallback(()=>{if(c.length===0)return l.createElement(l.Fragment,null,s);let u=c.length-1,I=cx(a.currentSelection,R&&a.currentSelectionWithClearButton);return u===0?l.createElement("span",{"data-test-id":"cf-multiselect-current-selection",className:I},c[0]):l.createElement("span",{"data-test-id":"cf-multiselect-current-selection",className:I},c[0]," ",l.createElement("span",{className:a.currentSelectionAddition},"and ",u," more"))},[c,s,R,a.currentSelection,a.currentSelectionAddition,a.currentSelectionWithClearButton]),V=useMemo(()=>Y(m,u=>u.type===M),[m]),ie=l.useCallback(u=>Q(u,I=>I.type===M,I=>{let se=ae=>{var z;B(),(z=I.props)==null||z.onSelectItem(ae);};return l.cloneElement(I,{searchValue:T,onSelectItem:se})}),[T,B]);return l.createElement("div",{"data-test-id":d,className:cx(a.multiselect,o),ref:t},l.createElement(Popover,H(b({renderOnlyWhenOpen:!1,isFullWidth:!0},f),{isOpen:D,onClose:()=>{X(!1),W&&W();}}),l.createElement(Flex,{alignItems:"center"},l.createElement(Popover.Trigger,null,l.createElement(Button,{"aria-label":"Toggle Multiselect",ref:v,onClick:()=>X(!D),startIcon:n,endIcon:l.createElement(ChevronDownIcon,null),isFullWidth:!0,className:a.triggerButton},re())),R&&l.createElement("div",{className:a.clearSelectionButton},l.createElement(Tooltip,{content:"Clear selection",showDelay:800,placement:"top",as:"div"},l.createElement(IconButton,{onClick:le,icon:l.createElement(CloseIcon,null),"aria-label":"Clear selection",size:"small"})))),l.createElement(Popover.Content,{ref:mergeRefs(te,F),className:cx(a.content(ee),f.className,a.container),testId:"cf-multiselect-container",onBlur:()=>x==null?void 0:x()},l.createElement(Ae,{focusOptions:{preventScroll:!0},returnFocus:!0},$&&l.createElement(G,H(b({},ne),{setSearchValue:oe,searchValue:T,focusList:B})),p&&l.createElement(De,null),!p&&V>0&&l.createElement("ul",{className:a.list,"data-test-id":"cf-multiselect-items"},$?ie(m):m),!p&&V===0&&l.createElement(Subheading,{className:a.noMatchesTitle},g)))))}var De=()=>l.createElement(SkeletonContainer,{svgHeight:16},l.createElement(SkeletonBodyText,{numberOfLines:1})),Z=l.forwardRef(We);var A=v=>{var p=v,{label:e,itemId:t="SelectAll",onSelectItem:o,isChecked:n=!1,className:s}=p,c=N(p,["label","itemId","onSelectItem","isChecked","className"]);let d=S();return l.createElement(M,b({value:"all",label:e||n?"Deselect all":"Select all",itemId:t,onSelectItem:o,isChecked:n,className:cx(d.selectAll,s)},c))};var E=Z;E.HighlightedItem=L;E.Option=M;E.SelectAll=A;
15
+ var ue=Object.defineProperty,me=Object.defineProperties;var de=Object.getOwnPropertyDescriptors;var L=Object.getOwnPropertySymbols;var q=Object.prototype.hasOwnProperty,G=Object.prototype.propertyIsEnumerable;var _=(e,t,o)=>t in e?ue(e,t,{enumerable:!0,configurable:!0,writable:!0,value:o}):e[t]=o,I=(e,t)=>{for(var o in t||(t={}))q.call(t,o)&&_(e,o,t[o]);if(L)for(var o of L(t))G.call(t,o)&&_(e,o,t[o]);return e},A=(e,t)=>me(e,de(t));var N=(e,t)=>{var o={};for(var n in e)q.call(e,n)&&t.indexOf(n)<0&&(o[n]=e[n]);if(e!=null&&L)for(var n of L(e))t.indexOf(n)<0&&G.call(e,n)&&(o[n]=e[n]);return o};var v=()=>({multiselect:css({position:"relative",width:"100%"}),triggerButton:css({justifyContent:"space-between"}),currentSelection:css({display:"inline-block",width:"100%",whiteSpace:"nowrap",textOverflow:"ellipsis",overflow:"hidden",verticalAlign:"bottom",marginRight:r.spacing2Xs}),currentSelectionWithClearButton:css({paddingRight:"40px"}),currentSelectionAddition:css({color:r.gray600}),searchBar:css({paddingTop:r.spacing2Xs,position:"sticky",top:"0px",zIndex:r.zIndexWorkbenchHeader,backgroundColor:r.colorWhite}),inputField:css({padding:`6px ${r.spacingXl} 10px ${r.spacingXs}`,textOverflow:"ellipsis",whiteSpace:"nowrap",border:"none",borderRadius:"0px",borderBottom:`1px solid ${r.gray200}`,boxShadow:"none","&:focus, &:active, &:active:hover":{boxShadow:"none",borderBottom:`1px solid ${r.gray200}`}}),toggleButton:css({position:"absolute",top:"1px",right:"1px",zIndex:r.zIndexDefault,padding:r.spacing2Xs,height:r.spacingXl}),content:e=>css({overflow:"auto",maxHeight:`${e}px`}),container:css({}),list:css({listStyle:"none",padding:`${r.spacing2Xs}`,margin:0}),groupTitle:css({padding:`6px ${r.spacingXs}`,lineHeight:r.lineHeightM}),noMatchesTitle:css({color:r.gray500,margin:r.spacingM,textAlign:"center"}),clearSelectionButton:css({marginLeft:"-80px"}),selectAll:css({borderBottom:`1px solid ${r.gray200}`,marginBottom:r.spacing2Xs,paddingBottom:r.spacing2Xs,"label > *":{fontWeight:r.fontWeightMedium}}),option:css({listStyleType:"none"}),optionText:css({alignItems:"center",display:"flex",span:{color:r.gray900,fontWeight:r.fontWeightDemiBold}}),optionCheck:({isActive:e,isDisabled:t})=>css({label:cx(getMenuItemStyles({isActive:e,isDisabled:t}),css({width:"100%"}))})});var b=C=>{var S=C,{children:e,label:t,value:o,itemId:n,onSelectItem:s,searchValue:c,isChecked:g=!1,isDisabled:f=!1,className:p}=S,d=N(S,["children","label","value","itemId","onSelectItem","searchValue","isChecked","isDisabled","className"]);let u=v();return l.createElement("li",I({className:cx(u.option,p)},d),l.createElement(Checkbox,{id:n,value:o,onChange:M=>s(M),isChecked:g,isDisabled:f,className:u.optionCheck({isActive:g,isDisabled:f})},l.createElement(Text,{className:u.optionText,"data-test-id":`cf-multiselect-list-item-${n}`},typeof t=="string"?l.createElement(B,{item:t,inputValue:c}):e)))};function B({item:e,inputValue:t=""}){let{before:o,match:n,after:s}=getStringMatch(e,t.trim());return o.length+n.length+s.length===0?l.createElement(l.Fragment,null,e):l.createElement(l.Fragment,null,o,l.createElement("span",{"data-test-id":"cf-multiselect-item-match"},n),s)}B.displayName="HighlightedItem";var K=({searchValue:e,setSearchValue:t,onSearchValueChange:o,searchInputName:n,searchInputRef:s,resetSearchRef:c,searchPlaceholder:g="Search",focusList:f})=>{let p=v(),d=useRef(null),C=useCallback(u=>{t(u.target.value),o==null||o(u);},[o,t]),S=useCallback(()=>{if(!e)return;f(),Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value").set.call(d.current,"");let M=new Event("change",{bubbles:!0});d.current.dispatchEvent(M);},[e,f]);return l.createElement("div",{className:p.searchBar},l.createElement(TextInput,{"aria-label":"Search",type:"text",value:e,className:p.inputField,testId:"cf-multiselect-search",placeholder:g,onChange:C,ref:mergeRefs(s,d),name:n,size:"small"}),l.createElement(IconButton,{ref:c,"aria-label":e?"Clear search":"Search",className:p.toggleButton,variant:"transparent",icon:e?l.createElement(CloseIcon,{variant:"muted"}):l.createElement(SearchIcon,{variant:"muted"}),onClick:S,isDisabled:!e,size:"small"}))};var Z=(e,t,o)=>l.Children.map(e,n=>{if(!l.isValidElement(n))return n;if(t(n))return o(n);let s=Z(n.props.children,t,o);return l.cloneElement(n,{children:s})}),ee=(e,t)=>{let o=0;return l.Children.forEach(e,n=>{l.isValidElement(n)&&(t(n)?o+=1:o+=ee(n.props.children,t));}),o};function Xe(e,t){let{className:o,startIcon:n,placeholder:s="Select one or more Items",currentSelection:c=[],toggleRef:g,toggleButtonAriaLabel:f="Toggle Multiselect",isLoading:p=!1,testId:d="cf-multiselect",noMatchesMessage:C="No matches found",searchProps:S={},popoverProps:u={},children:M,onBlur:T,onClearSelection:P,clearButtonProps:O={tooltip:"Clear selection",ariaLabel:"Clear selection"}}=e,{listMaxHeight:oe=180,listRef:ne,onClose:X}=u,a=v(),[k,le]=useState(""),[F,$]=useState(!1),V=useRef(null),R=c.length>1&&typeof P=="function",z=typeof e.onSearchValueChange=="function"||typeof S.onSearchValueChange=="function",re=Object.keys(S).length>0?S:{onSearchValueChange:e.onSearchValueChange,searchPlaceholder:e.searchPlaceholder,searchInputName:e.searchInputName,searchInputRef:e.searchInputRef},H=useCallback(()=>{var m;(m=V.current)==null||m.focus();},[]),ie=m=>{P==null||P(),m.stopPropagation();},se=useCallback(()=>{if(c.length===0)return l.createElement(l.Fragment,null,s);let m=c.length-1,x=cx(a.currentSelection,R&&a.currentSelectionWithClearButton);return m===0?l.createElement("span",{"data-test-id":"cf-multiselect-current-selection",className:x},c[0]):l.createElement("span",{"data-test-id":"cf-multiselect-current-selection",className:x},c[0]," ",l.createElement("span",{className:a.currentSelectionAddition},"and ",m," more"))},[c,s,R,a.currentSelection,a.currentSelectionAddition,a.currentSelectionWithClearButton]),j=useMemo(()=>ee(M,m=>m.type===b),[M]),ae=l.useCallback(m=>Z(m,x=>x.type===b,x=>{let ce=pe=>{var U;H(),(U=x.props)==null||U.onSelectItem(pe);};return l.cloneElement(x,{searchValue:k,onSelectItem:ce})}),[k,H]);return l.createElement("div",{"data-test-id":d,className:cx(a.multiselect,o),ref:t},l.createElement(Popover,A(I({renderOnlyWhenOpen:!1,isFullWidth:!0},u),{isOpen:F,onClose:()=>{$(!1),X&&X();}}),l.createElement(Flex,{alignItems:"center"},l.createElement(Popover.Trigger,null,l.createElement(Button,{"aria-label":f,ref:g,onClick:()=>$(!F),startIcon:n,endIcon:l.createElement(ChevronDownIcon,null),isFullWidth:!0,className:a.triggerButton},se())),R&&l.createElement("div",{className:a.clearSelectionButton},l.createElement(Tooltip,{content:O.tooltip?O.tooltip:"Clear selection",showDelay:800,placement:"top",as:"div"},l.createElement(IconButton,{onClick:ie,icon:l.createElement(CloseIcon,null),"aria-label":O.ariaLabel?O.ariaLabel:"Clear selection",size:"small"})))),l.createElement(Popover.Content,{ref:mergeRefs(ne,V),className:cx(a.content(oe),u.className,a.container),testId:"cf-multiselect-container",onBlur:()=>T==null?void 0:T()},l.createElement(De,{focusOptions:{preventScroll:!0},returnFocus:!0},z&&l.createElement(K,A(I({},re),{setSearchValue:le,searchValue:k,focusList:H})),p&&l.createElement(Fe,null),!p&&j>0&&l.createElement("ul",{className:a.list,"data-test-id":"cf-multiselect-items"},z?ae(M):M),!p&&j===0&&l.createElement(Subheading,{className:a.noMatchesTitle},C)))))}var Fe=()=>l.createElement(SkeletonContainer,{svgHeight:16},l.createElement(SkeletonBodyText,{numberOfLines:1})),te=l.forwardRef(Xe);var D=f=>{var p=f,{label:e,itemId:t="SelectAll",onSelectItem:o,isChecked:n=!1,selectAllOptionLabel:s={checked:"Deselect all",unchecked:"Select all"},className:c}=p,g=N(p,["label","itemId","onSelectItem","isChecked","selectAllOptionLabel","className"]);let d=v(),C=e||n?s.checked:s.unchecked;return l.createElement(b,I({value:"all",label:C,itemId:t,onSelectItem:o,isChecked:n,className:cx(d.selectAll,c)},g))};var E=te;E.HighlightedItem=B;E.Option=b;E.SelectAll=D;
16
16
 
17
- export { E as Multiselect, M as MultiselectOption, A as SelectAllOption };
17
+ export { E as Multiselect, b as MultiselectOption, D as SelectAllOption };
18
18
  //# sourceMappingURL=out.js.map
19
19
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/MultiselectOption.tsx","../../src/Multiselect.styles.ts","../../src/Multiselect.tsx","../../src/MultiselectSearch.tsx","../../src/SelectAllOption.tsx","../../src/CompoundMultiselect.tsx"],"names":["React","Checkbox","Text","css","cx","tokens","getMenuItemStyles","getMultiselectStyles","listMaxHeight","isActive","isDisabled","getStringMatch","MultiselectOption","_a","_b","children","label","value","itemId","onSelectItem","searchValue","isChecked","className","rest","__objRest","styles","__spreadValues","event","HighlightedItem","item","inputValue","before","match","after","useRef","useState","useCallback","useMemo","mergeRefs","Flex","Button","IconButton","ChevronDownIcon","CloseIcon","SkeletonContainer","SkeletonBodyText","Popover","Subheading","Tooltip","FocusLock","TextInput","SearchIcon","MultiselectSearch","setSearchValue","onSearchValueChange","searchInputName","searchInputRef","resetSearchRef","searchPlaceholder","focusList","internalSearchInputRef","handleSearchChange","resetSearchInput","forcedEvent","iterateOverChildren","filter","callback","child","childChildren","countMatchingChildren","counter","_Multiselect","props","ref","startIcon","placeholder","currentSelection","toggleRef","isLoading","testId","noMatchesMessage","searchProps","popoverProps","onBlur","onClearSelection","listRef","onClose","isOpen","setIsOpen","internalListRef","showClearButton","hasSearch","handoverSearchProps","handleClearSelection","e","renderMultiselectLabel","leftoverCount","currentSelectionClassName","optionsLength","enrichOptions","__spreadProps","ListItemLoadingState","Multiselect","SelectAllOption","otherProps"],"mappings":"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","sourcesContent":["import React from 'react';\nimport { Checkbox } from '@contentful/f36-forms';\nimport { Text } from '@contentful/f36-typography';\nimport { getMultiselectStyles } from './Multiselect.styles';\nimport { getStringMatch } from '@contentful/f36-utils';\nimport { cx } from 'emotion';\n\ntype LabelOrChildren =\n | {\n /**\n * When using React children it is your own responsibility to highlight\n * the matching part of the item label. Use the `HighlightedItem`\n * component for this.\n */\n children: React.ReactNode;\n label?: never;\n }\n | {\n children?: never;\n label: string;\n };\n\nexport type MultiselectOptionProps = {\n value: string;\n itemId: string;\n searchValue?: string;\n className?: string;\n onSelectItem: (event: React.ChangeEvent<HTMLInputElement>) => void;\n isChecked?: boolean;\n isDisabled?: boolean;\n} & LabelOrChildren;\n\nexport const MultiselectOption = ({\n children,\n label,\n value,\n itemId,\n onSelectItem,\n searchValue,\n isChecked = false,\n isDisabled = false,\n className,\n ...rest\n}: MultiselectOptionProps) => {\n const styles = getMultiselectStyles();\n\n return (\n <li className={cx(styles.option, className)} {...rest}>\n <Checkbox\n id={itemId}\n value={value}\n onChange={(event) => onSelectItem(event)}\n isChecked={isChecked}\n isDisabled={isDisabled}\n className={styles.optionCheck({ isActive: isChecked, isDisabled })}\n >\n <Text\n className={styles.optionText}\n data-test-id={`cf-multiselect-list-item-${itemId}`}\n >\n {typeof label === 'string' ? (\n <HighlightedItem item={label} inputValue={searchValue} />\n ) : (\n children\n )}\n </Text>\n </Checkbox>\n </li>\n );\n};\n\nexport function HighlightedItem({\n item,\n inputValue = '',\n}: {\n item: string;\n inputValue?: string;\n}) {\n const { before, match, after } = getStringMatch(item, inputValue.trim());\n\n if (before.length + match.length + after.length === 0) {\n return <>{item}</>;\n }\n\n return (\n <>\n {before}\n <span data-test-id=\"cf-multiselect-item-match\">{match}</span>\n {after}\n </>\n );\n}\n\nHighlightedItem.displayName = 'HighlightedItem';\n","import { css, cx } from 'emotion';\nimport tokens from '@contentful/f36-tokens';\nimport { getMenuItemStyles } from '@contentful/f36-core';\n\nexport const getMultiselectStyles = () => ({\n multiselect: css({\n position: 'relative',\n width: '100%',\n }),\n triggerButton: css({\n justifyContent: 'space-between',\n }),\n currentSelection: css({\n display: 'inline-block',\n width: '100%',\n whiteSpace: 'nowrap',\n textOverflow: 'ellipsis',\n overflow: 'hidden',\n verticalAlign: 'bottom',\n marginRight: tokens.spacing2Xs,\n }),\n currentSelectionWithClearButton: css({\n paddingRight: '40px',\n }),\n currentSelectionAddition: css({\n color: tokens.gray600,\n }),\n searchBar: css({\n paddingTop: tokens.spacing2Xs,\n position: 'sticky',\n top: '0px',\n zIndex: tokens.zIndexWorkbenchHeader,\n backgroundColor: tokens.colorWhite,\n }),\n inputField: css({\n padding: `6px ${tokens.spacingXl} 10px ${tokens.spacingXs}`,\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n border: 'none',\n borderRadius: '0px',\n borderBottom: `1px solid ${tokens.gray200}`,\n boxShadow: 'none',\n '&:focus, &:active, &:active:hover': {\n boxShadow: 'none',\n borderBottom: `1px solid ${tokens.gray200}`,\n },\n }),\n toggleButton: css({\n position: 'absolute',\n top: '1px',\n right: '1px',\n zIndex: tokens.zIndexDefault,\n padding: tokens.spacing2Xs,\n height: tokens.spacingXl,\n }),\n content: (listMaxHeight: number) =>\n css({\n overflow: 'auto',\n maxHeight: `${listMaxHeight}px`,\n }),\n container: css({}),\n list: css({\n listStyle: 'none',\n padding: `${tokens.spacing2Xs}`,\n margin: 0,\n }),\n groupTitle: css({\n // Magic number to get a height of 32px on the item\n padding: `6px ${tokens.spacingXs}`,\n lineHeight: tokens.lineHeightM,\n }),\n noMatchesTitle: css({\n color: tokens.gray500,\n margin: tokens.spacingM,\n textAlign: 'center',\n }),\n clearSelectionButton: css({\n marginLeft: '-80px',\n }),\n selectAll: css({\n borderBottom: `1px solid ${tokens.gray200}`,\n marginBottom: tokens.spacing2Xs,\n paddingBottom: tokens.spacing2Xs,\n 'label > *': {\n fontWeight: tokens.fontWeightMedium,\n },\n }),\n option: css({\n listStyleType: 'none',\n }),\n optionText: css({\n alignItems: 'center',\n display: 'flex',\n span: {\n color: tokens.gray900,\n fontWeight: tokens.fontWeightDemiBold,\n },\n }),\n optionCheck: ({\n isActive,\n isDisabled,\n }: {\n isActive?: boolean;\n isDisabled?: boolean;\n }) =>\n css({\n label: cx(\n getMenuItemStyles({ isActive, isDisabled }),\n css({\n width: '100%',\n }),\n ),\n }),\n});\n","import React, { useRef, useState, useCallback, useMemo } from 'react';\nimport { cx } from 'emotion';\n\nimport { mergeRefs, type CommonProps, Flex } from '@contentful/f36-core';\nimport { Button, IconButton } from '@contentful/f36-button';\nimport { ChevronDownIcon, CloseIcon } from '@contentful/f36-icons';\n\nimport { SkeletonContainer, SkeletonBodyText } from '@contentful/f36-skeleton';\nimport { Popover, type PopoverProps } from '@contentful/f36-popover';\nimport { Subheading } from '@contentful/f36-typography';\nimport { Tooltip } from '@contentful/f36-tooltip';\n\nimport { getMultiselectStyles } from './Multiselect.styles';\nimport { MultiselectOption, MultiselectOptionProps } from './MultiselectOption';\nimport FocusLock from 'react-focus-lock';\n\nimport type { MultiselectSearchProps as SearchProps } from './MultiselectSearch';\nimport { MultiselectSearch } from './MultiselectSearch';\n\nexport interface MultiselectProps extends CommonProps {\n /** Select Options */\n children?: React.ReactNode;\n\n /**\n * Set a custom icon for the text input\n */\n startIcon?: React.ReactElement;\n\n /**\n * Placeholder shown before selecting any elements. Defaults to 'Select one or more items'\n */\n placeholder?: string;\n\n /**\n * current Selected items, to be shown on the trigger button\n */\n currentSelection?: Array<string>;\n\n /**\n * Sets the list to show its loading state\n * @default false\n */\n isLoading?: boolean;\n\n /**\n * Use this prop to get a ref to the toggle button of the component\n */\n toggleRef?: React.Ref<HTMLButtonElement>;\n\n /**\n * Props to pass to the optional search field\n */\n searchProps?: SearchProps;\n\n /**\n * Function called whenever the search input value changes\n * @deprecated Handover this prop in the searchProps subcomponent properties\n */\n onSearchValueChange?: (\n event: React.ChangeEvent<HTMLInputElement>,\n ) => void | undefined;\n\n /**\n * This is the value will be passed to the `placeholder` prop of the input.\n * @deprecated Handover this prop in the searchProps subcomponent properties\n * @default \"Search\"\n */\n searchPlaceholder?: string;\n\n /**\n * A message that will be shown when it is not possible to find any option that matches the search value\n * @default \"No matches\"\n */\n noMatchesMessage?: string;\n\n /**\n * Pass a form name to the search text input\n * @deprecated Handover this prop in the searchProps subcomponent properties\n */\n searchInputName?: string;\n\n /**\n * Use this prop to get a ref to the search input element of the component\n * @deprecated Handover this prop in the searchProps subcomponent properties\n */\n searchInputRef?: React.Ref<HTMLInputElement>;\n\n /**\n * Props to pass to the Popover (Dropdown) component\n */\n popoverProps?: Partial<PopoverProps> & {\n /**\n * It sets the max-height, in pixels, of the list\n * The default value is the height of 5 single line items\n * @default 180\n */\n listMaxHeight?: number;\n\n /**\n * Use this prop to get a ref to the list of items of the component\n */\n listRef?: React.Ref<HTMLUListElement>;\n } & Pick<CommonProps, 'className'>;\n\n /**\n * Function called when the popover loses its focus.\n */\n onBlur?: () => void;\n\n /**\n * Function called when the clear all button is clicked\n * If no function is provided the clear button is not shown\n */\n onClearSelection?: () => void;\n}\n\n// Scan through the whole hierachy until `filter` returns true and apply `transform`\n// Inspired from https://stackoverflow.com/a/70676868/17269164\nconst iterateOverChildren = (\n children: React.ReactNode,\n filter: (child: React.ReactElement) => boolean,\n callback: (child: React.ReactElement) => React.ReactElement | void,\n): React.ReactNode => {\n return React.Children.map(children, (child) => {\n // equal to (if (child == null || typeof child == 'string'))\n if (!React.isValidElement(child)) return child;\n if (filter(child)) {\n return callback(child);\n }\n const childChildren = iterateOverChildren(\n child.props.children,\n filter,\n callback,\n );\n return React.cloneElement(child, { children: childChildren } as unknown);\n });\n};\n\n// Scan through the whole hierachy to count the number of children where `filter` returns true\nconst countMatchingChildren = (\n children: React.ReactNode,\n filter: (child: React.ReactElement) => boolean,\n): number => {\n let counter = 0;\n React.Children.forEach(children, (child) => {\n // equal to (if (child == null || typeof child == 'string'))\n if (!React.isValidElement(child)) return;\n if (!filter(child)) {\n counter += countMatchingChildren(child.props.children, filter);\n } else {\n counter += 1;\n }\n });\n return counter;\n};\n\nfunction _Multiselect(props: MultiselectProps, ref: React.Ref<HTMLDivElement>) {\n const {\n className,\n startIcon,\n placeholder = 'Select one or more Items',\n currentSelection = [],\n toggleRef,\n isLoading = false,\n testId = 'cf-multiselect',\n noMatchesMessage = 'No matches found',\n searchProps = {},\n popoverProps = {},\n children,\n onBlur,\n onClearSelection,\n } = props;\n\n const { listMaxHeight = 180, listRef, onClose } = popoverProps;\n\n const styles = getMultiselectStyles();\n\n const [searchValue, setSearchValue] = useState('');\n const [isOpen, setIsOpen] = useState(false);\n\n const internalListRef = useRef<HTMLUListElement>(null);\n\n const showClearButton =\n currentSelection.length > 1 && typeof onClearSelection === 'function';\n\n const hasSearch =\n typeof props.onSearchValueChange === 'function' ||\n typeof searchProps.onSearchValueChange === 'function';\n\n const handoverSearchProps =\n Object.keys(searchProps).length > 0\n ? searchProps\n : {\n onSearchValueChange: props.onSearchValueChange,\n searchPlaceholder: props.searchPlaceholder,\n searchInputName: props.searchInputName,\n searchInputRef: props.searchInputRef,\n };\n\n const focusList = useCallback(() => {\n // Clearing the search input or selecting an item triggers a rerendering and\n // thereby the client loses the focus on the clicked element. To avoid having\n // the focus on the document body (which breaks `closeOnBlur`), we force it\n // back to the list in the popup.\n internalListRef.current?.focus();\n }, []);\n\n const handleClearSelection = (e: React.MouseEvent<HTMLButtonElement>) => {\n onClearSelection?.();\n e.stopPropagation();\n };\n\n const renderMultiselectLabel = useCallback(() => {\n if (currentSelection.length === 0) {\n return <>{placeholder}</>;\n }\n const leftoverCount = currentSelection.length - 1;\n const currentSelectionClassName = cx(\n styles.currentSelection,\n showClearButton && styles.currentSelectionWithClearButton,\n );\n if (leftoverCount === 0) {\n return (\n <span\n data-test-id=\"cf-multiselect-current-selection\"\n className={currentSelectionClassName}\n >\n {currentSelection[0]}\n </span>\n );\n }\n return (\n <span\n data-test-id=\"cf-multiselect-current-selection\"\n className={currentSelectionClassName}\n >\n {currentSelection[0]}{' '}\n <span className={styles.currentSelectionAddition}>\n and {leftoverCount} more\n </span>\n </span>\n );\n }, [\n currentSelection,\n placeholder,\n showClearButton,\n styles.currentSelection,\n styles.currentSelectionAddition,\n styles.currentSelectionWithClearButton,\n ]);\n\n const optionsLength = useMemo(\n () =>\n countMatchingChildren(\n children,\n (child) => child.type === MultiselectOption,\n ),\n [children],\n );\n\n // clones and enriches the multiselect options\n const enrichOptions = React.useCallback(\n (children: React.ReactNode): React.ReactNode => {\n return iterateOverChildren(\n children,\n (child) => child.type === MultiselectOption,\n (child) => {\n const onSelectItem = (event: React.ChangeEvent<HTMLInputElement>) => {\n focusList();\n child.props?.onSelectItem(event);\n };\n return React.cloneElement(child, {\n searchValue,\n onSelectItem,\n } as Partial<MultiselectOptionProps>);\n },\n );\n },\n [searchValue, focusList],\n );\n\n return (\n <div\n data-test-id={testId}\n className={cx(styles.multiselect, className)}\n ref={ref}\n >\n <Popover\n renderOnlyWhenOpen={false}\n isFullWidth\n {...popoverProps}\n // popoverProps should never overwrite the internal opening logic\n isOpen={isOpen}\n onClose={() => {\n setIsOpen(false);\n if (onClose) {\n onClose();\n }\n }}\n >\n <Flex alignItems=\"center\">\n <Popover.Trigger>\n <Button\n aria-label=\"Toggle Multiselect\"\n ref={toggleRef}\n onClick={() => setIsOpen(!isOpen)}\n startIcon={startIcon}\n endIcon={<ChevronDownIcon />}\n isFullWidth\n className={styles.triggerButton}\n >\n {renderMultiselectLabel()}\n </Button>\n </Popover.Trigger>\n {showClearButton && (\n <div className={styles.clearSelectionButton}>\n <Tooltip\n content=\"Clear selection\"\n showDelay={800}\n placement=\"top\"\n as=\"div\"\n >\n <IconButton\n onClick={handleClearSelection}\n icon={<CloseIcon />}\n aria-label=\"Clear selection\"\n size=\"small\"\n />\n </Tooltip>\n </div>\n )}\n </Flex>\n <Popover.Content\n ref={mergeRefs(listRef, internalListRef)}\n className={cx(\n styles.content(listMaxHeight),\n popoverProps.className,\n styles.container,\n )}\n testId=\"cf-multiselect-container\"\n onBlur={() => onBlur?.()}\n >\n <FocusLock focusOptions={{ preventScroll: true }} returnFocus={true}>\n {hasSearch && (\n <MultiselectSearch\n {...handoverSearchProps}\n setSearchValue={setSearchValue}\n searchValue={searchValue}\n focusList={focusList}\n />\n )}\n {isLoading && <ListItemLoadingState />}\n\n {!isLoading && optionsLength > 0 && (\n <ul className={styles.list} data-test-id=\"cf-multiselect-items\">\n {hasSearch ? enrichOptions(children) : children}\n </ul>\n )}\n\n {!isLoading && optionsLength === 0 && (\n <Subheading className={styles.noMatchesTitle}>\n {noMatchesMessage}\n </Subheading>\n )}\n </FocusLock>\n </Popover.Content>\n </Popover>\n </div>\n );\n}\n\nconst ListItemLoadingState = () => {\n return (\n <SkeletonContainer svgHeight={16}>\n <SkeletonBodyText numberOfLines={1} />\n </SkeletonContainer>\n );\n};\n\n/**\n * The Multiselect is a component that will allow a user to select multiple items.\n * It has an optional\n */\nexport const Multiselect = React.forwardRef(_Multiselect);\n","import React, { useCallback, useRef } from 'react';\nimport { TextInput } from '@contentful/f36-forms';\nimport { CloseIcon, SearchIcon } from '@contentful/f36-icons';\nimport { IconButton } from '@contentful/f36-button';\nimport { getMultiselectStyles } from './Multiselect.styles';\nimport { mergeRefs } from '@contentful/f36-core';\n\nexport interface MultiselectSearchProps {\n /**\n * Function called whenever the search input value changes\n */\n onSearchValueChange?: (\n event: React.ChangeEvent<HTMLInputElement>,\n ) => void | undefined;\n\n /**\n * This is the value will be passed to the `placeholder` prop of the input.\n * @default \"Search\"\n */\n searchPlaceholder?: string;\n\n /**\n * Pass a form name to the search text input\n */\n searchInputName?: string;\n\n /**\n * Use this prop to get a ref to the search input element of the component\n */\n searchInputRef?: React.Ref<HTMLInputElement>;\n\n /**\n * Use this prop to get a ref to the reset search button of the component\n */\n resetSearchRef?: React.Ref<HTMLButtonElement>;\n\n /**\n * State from the parent component\n */\n searchValue?: string;\n\n /**\n * State setter of the parent\n */\n setSearchValue?: React.Dispatch<React.SetStateAction<string>>;\n\n /**\n * List helper function\n */\n focusList?: () => void;\n}\n\nexport const MultiselectSearch = ({\n searchValue,\n setSearchValue,\n onSearchValueChange,\n searchInputName,\n searchInputRef,\n resetSearchRef,\n searchPlaceholder = 'Search',\n focusList,\n}: MultiselectSearchProps) => {\n const styles = getMultiselectStyles();\n const internalSearchInputRef = useRef<HTMLInputElement>(null);\n\n const handleSearchChange = useCallback(\n (event) => {\n setSearchValue(event.target.value);\n onSearchValueChange?.(event);\n },\n [onSearchValueChange, setSearchValue],\n );\n\n const resetSearchInput = useCallback(() => {\n if (!searchValue) return;\n focusList();\n // this looks a bit hacky, but is the official way of externally triggering the onChange handler for an input\n // https://stackoverflow.com/a/46012210/17269164\n const nativeInputValueSetter = Object.getOwnPropertyDescriptor(\n window.HTMLInputElement.prototype,\n 'value',\n ).set;\n nativeInputValueSetter.call(internalSearchInputRef.current, '');\n const forcedEvent = new Event('change', { bubbles: true });\n internalSearchInputRef.current.dispatchEvent(forcedEvent);\n }, [searchValue, focusList]);\n\n return (\n <div className={styles.searchBar}>\n <TextInput\n aria-label=\"Search\"\n type=\"text\"\n value={searchValue}\n className={styles.inputField}\n testId=\"cf-multiselect-search\"\n placeholder={searchPlaceholder}\n onChange={handleSearchChange}\n ref={mergeRefs(searchInputRef, internalSearchInputRef)}\n name={searchInputName}\n size=\"small\"\n />\n <IconButton\n ref={resetSearchRef}\n aria-label={searchValue ? 'Clear search' : 'Search'}\n className={styles.toggleButton}\n variant=\"transparent\"\n icon={\n searchValue ? (\n <CloseIcon variant=\"muted\" />\n ) : (\n <SearchIcon variant=\"muted\" />\n )\n }\n onClick={resetSearchInput}\n isDisabled={!searchValue}\n size=\"small\"\n />\n </div>\n );\n};\n","import React from 'react';\nimport { MultiselectOption, MultiselectOptionProps } from './MultiselectOption';\nimport { getMultiselectStyles } from './Multiselect.styles';\nimport { cx } from 'emotion';\n\nexport interface SelectAllOptionProps\n extends Omit<\n MultiselectOptionProps,\n 'children' | 'value' | 'itemId' | 'label'\n > {\n label?: string;\n itemId?: string;\n}\n\nexport const SelectAllOption = ({\n label,\n itemId = 'SelectAll',\n onSelectItem,\n isChecked = false,\n className,\n ...otherProps\n}: SelectAllOptionProps) => {\n const styles = getMultiselectStyles();\n const displayLabel = label || isChecked ? 'Deselect all' : 'Select all';\n return (\n <MultiselectOption\n value=\"all\"\n label={displayLabel}\n itemId={itemId}\n onSelectItem={onSelectItem}\n isChecked={isChecked}\n className={cx(styles.selectAll, className)}\n {...otherProps}\n />\n );\n};\n","import { Multiselect as OriginalMultiSelect } from './Multiselect';\nimport { HighlightedItem, MultiselectOption } from './MultiselectOption';\nimport { SelectAllOption } from './SelectAllOption';\n\ntype CompoundMultiselect = typeof OriginalMultiSelect & {\n HighlightedItem: typeof HighlightedItem;\n Option: typeof MultiselectOption;\n SelectAll: typeof SelectAllOption;\n};\n\nexport const Multiselect = OriginalMultiSelect as CompoundMultiselect;\nMultiselect.HighlightedItem = HighlightedItem;\nMultiselect.Option = MultiselectOption;\nMultiselect.SelectAll = SelectAllOption;\n"]}
1
+ {"version":3,"sources":["../../src/MultiselectOption.tsx","../../src/Multiselect.styles.ts","../../src/Multiselect.tsx","../../src/MultiselectSearch.tsx","../../src/SelectAllOption.tsx","../../src/CompoundMultiselect.tsx"],"names":["React","Checkbox","Text","css","cx","tokens","getMenuItemStyles","getMultiselectStyles","listMaxHeight","isActive","isDisabled","getStringMatch","MultiselectOption","_a","_b","children","label","value","itemId","onSelectItem","searchValue","isChecked","className","rest","__objRest","styles","__spreadValues","event","HighlightedItem","item","inputValue","before","match","after","useRef","useState","useCallback","useMemo","mergeRefs","Flex","Button","IconButton","ChevronDownIcon","CloseIcon","SkeletonContainer","SkeletonBodyText","Popover","Subheading","Tooltip","FocusLock","TextInput","SearchIcon","MultiselectSearch","setSearchValue","onSearchValueChange","searchInputName","searchInputRef","resetSearchRef","searchPlaceholder","focusList","internalSearchInputRef","handleSearchChange","resetSearchInput","forcedEvent","iterateOverChildren","filter","callback","child","childChildren","countMatchingChildren","counter","_Multiselect","props","ref","startIcon","placeholder","currentSelection","toggleRef","toggleButtonAriaLabel","isLoading","testId","noMatchesMessage","searchProps","popoverProps","onBlur","onClearSelection","clearButtonProps","listRef","onClose","isOpen","setIsOpen","internalListRef","showClearButton","hasSearch","handoverSearchProps","handleClearSelection","e","renderMultiselectLabel","leftoverCount","currentSelectionClassName","optionsLength","enrichOptions","__spreadProps","ListItemLoadingState","Multiselect","SelectAllOption","selectAllOptionLabel","otherProps","displayLabel"],"mappings":"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","sourcesContent":["import React from 'react';\nimport { Checkbox } from '@contentful/f36-forms';\nimport { Text } from '@contentful/f36-typography';\nimport { getMultiselectStyles } from './Multiselect.styles';\nimport { getStringMatch } from '@contentful/f36-utils';\nimport { cx } from 'emotion';\n\ntype LabelOrChildren =\n | {\n /**\n * When using React children it is your own responsibility to highlight\n * the matching part of the item label. Use the `HighlightedItem`\n * component for this.\n */\n children: React.ReactNode;\n label?: never;\n }\n | {\n children?: never;\n label: string;\n };\n\nexport type MultiselectOptionProps = {\n value: string;\n itemId: string;\n searchValue?: string;\n className?: string;\n onSelectItem: (event: React.ChangeEvent<HTMLInputElement>) => void;\n isChecked?: boolean;\n isDisabled?: boolean;\n} & LabelOrChildren;\n\nexport const MultiselectOption = ({\n children,\n label,\n value,\n itemId,\n onSelectItem,\n searchValue,\n isChecked = false,\n isDisabled = false,\n className,\n ...rest\n}: MultiselectOptionProps) => {\n const styles = getMultiselectStyles();\n\n return (\n <li className={cx(styles.option, className)} {...rest}>\n <Checkbox\n id={itemId}\n value={value}\n onChange={(event) => onSelectItem(event)}\n isChecked={isChecked}\n isDisabled={isDisabled}\n className={styles.optionCheck({ isActive: isChecked, isDisabled })}\n >\n <Text\n className={styles.optionText}\n data-test-id={`cf-multiselect-list-item-${itemId}`}\n >\n {typeof label === 'string' ? (\n <HighlightedItem item={label} inputValue={searchValue} />\n ) : (\n children\n )}\n </Text>\n </Checkbox>\n </li>\n );\n};\n\nexport function HighlightedItem({\n item,\n inputValue = '',\n}: {\n item: string;\n inputValue?: string;\n}) {\n const { before, match, after } = getStringMatch(item, inputValue.trim());\n\n if (before.length + match.length + after.length === 0) {\n return <>{item}</>;\n }\n\n return (\n <>\n {before}\n <span data-test-id=\"cf-multiselect-item-match\">{match}</span>\n {after}\n </>\n );\n}\n\nHighlightedItem.displayName = 'HighlightedItem';\n","import { css, cx } from 'emotion';\nimport tokens from '@contentful/f36-tokens';\nimport { getMenuItemStyles } from '@contentful/f36-core';\n\nexport const getMultiselectStyles = () => ({\n multiselect: css({\n position: 'relative',\n width: '100%',\n }),\n triggerButton: css({\n justifyContent: 'space-between',\n }),\n currentSelection: css({\n display: 'inline-block',\n width: '100%',\n whiteSpace: 'nowrap',\n textOverflow: 'ellipsis',\n overflow: 'hidden',\n verticalAlign: 'bottom',\n marginRight: tokens.spacing2Xs,\n }),\n currentSelectionWithClearButton: css({\n paddingRight: '40px',\n }),\n currentSelectionAddition: css({\n color: tokens.gray600,\n }),\n searchBar: css({\n paddingTop: tokens.spacing2Xs,\n position: 'sticky',\n top: '0px',\n zIndex: tokens.zIndexWorkbenchHeader,\n backgroundColor: tokens.colorWhite,\n }),\n inputField: css({\n padding: `6px ${tokens.spacingXl} 10px ${tokens.spacingXs}`,\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n border: 'none',\n borderRadius: '0px',\n borderBottom: `1px solid ${tokens.gray200}`,\n boxShadow: 'none',\n '&:focus, &:active, &:active:hover': {\n boxShadow: 'none',\n borderBottom: `1px solid ${tokens.gray200}`,\n },\n }),\n toggleButton: css({\n position: 'absolute',\n top: '1px',\n right: '1px',\n zIndex: tokens.zIndexDefault,\n padding: tokens.spacing2Xs,\n height: tokens.spacingXl,\n }),\n content: (listMaxHeight: number) =>\n css({\n overflow: 'auto',\n maxHeight: `${listMaxHeight}px`,\n }),\n container: css({}),\n list: css({\n listStyle: 'none',\n padding: `${tokens.spacing2Xs}`,\n margin: 0,\n }),\n groupTitle: css({\n // Magic number to get a height of 32px on the item\n padding: `6px ${tokens.spacingXs}`,\n lineHeight: tokens.lineHeightM,\n }),\n noMatchesTitle: css({\n color: tokens.gray500,\n margin: tokens.spacingM,\n textAlign: 'center',\n }),\n clearSelectionButton: css({\n marginLeft: '-80px',\n }),\n selectAll: css({\n borderBottom: `1px solid ${tokens.gray200}`,\n marginBottom: tokens.spacing2Xs,\n paddingBottom: tokens.spacing2Xs,\n 'label > *': {\n fontWeight: tokens.fontWeightMedium,\n },\n }),\n option: css({\n listStyleType: 'none',\n }),\n optionText: css({\n alignItems: 'center',\n display: 'flex',\n span: {\n color: tokens.gray900,\n fontWeight: tokens.fontWeightDemiBold,\n },\n }),\n optionCheck: ({\n isActive,\n isDisabled,\n }: {\n isActive?: boolean;\n isDisabled?: boolean;\n }) =>\n css({\n label: cx(\n getMenuItemStyles({ isActive, isDisabled }),\n css({\n width: '100%',\n }),\n ),\n }),\n});\n","import React, { useRef, useState, useCallback, useMemo } from 'react';\nimport { cx } from 'emotion';\n\nimport { mergeRefs, type CommonProps, Flex } from '@contentful/f36-core';\nimport { Button, IconButton } from '@contentful/f36-button';\nimport { ChevronDownIcon, CloseIcon } from '@contentful/f36-icons';\n\nimport { SkeletonContainer, SkeletonBodyText } from '@contentful/f36-skeleton';\nimport { Popover, type PopoverProps } from '@contentful/f36-popover';\nimport { Subheading } from '@contentful/f36-typography';\nimport { Tooltip } from '@contentful/f36-tooltip';\n\nimport { getMultiselectStyles } from './Multiselect.styles';\nimport { MultiselectOption, MultiselectOptionProps } from './MultiselectOption';\nimport FocusLock from 'react-focus-lock';\n\nimport type { MultiselectSearchProps as SearchProps } from './MultiselectSearch';\nimport { MultiselectSearch } from './MultiselectSearch';\n\ntype ClearButtonProps = {\n /**\n * Aria label for the clear button\n * @default 'Clear selection'\n */\n ariaLabel?: string;\n\n /**\n * Tooltip for the clear button\n * @default 'Clear selection'\n */\n tooltip?: string;\n};\n\nexport interface MultiselectProps extends CommonProps {\n /** Select Options */\n children?: React.ReactNode;\n\n /**\n * Set a custom icon for the text input\n */\n startIcon?: React.ReactElement;\n\n /**\n * Placeholder shown before selecting any elements. Defaults to 'Select one or more items'\n */\n placeholder?: string;\n\n /**\n * current Selected items, to be shown on the trigger button\n */\n currentSelection?: Array<string>;\n\n /**\n * Sets the list to show its loading state\n * @default false\n */\n isLoading?: boolean;\n\n /**\n * Use this prop to get a ref to the toggle button of the component\n */\n toggleRef?: React.Ref<HTMLButtonElement>;\n\n /**\n * Aria label for the toggle button that opens the list\n * @default 'Toggle Multiselect'\n */\n toggleButtonAriaLabel?: string;\n\n /**\n * Props to pass to the optional search field\n */\n searchProps?: SearchProps;\n\n /**\n * Function called whenever the search input value changes\n * @deprecated Handover this prop in the searchProps subcomponent properties\n */\n onSearchValueChange?: (\n event: React.ChangeEvent<HTMLInputElement>,\n ) => void | undefined;\n\n /**\n * This is the value will be passed to the `placeholder` prop of the input.\n * @deprecated Handover this prop in the searchProps subcomponent properties\n * @default \"Search\"\n */\n searchPlaceholder?: string;\n\n /**\n * A message that will be shown when it is not possible to find any option that matches the search value\n * @default \"No matches\"\n */\n noMatchesMessage?: string;\n\n /**\n * Pass a form name to the search text input\n * @deprecated Handover this prop in the searchProps subcomponent properties\n */\n searchInputName?: string;\n\n /**\n * Use this prop to get a ref to the search input element of the component\n * @deprecated Handover this prop in the searchProps subcomponent properties\n */\n searchInputRef?: React.Ref<HTMLInputElement>;\n\n /**\n * Props to pass to the Popover (Dropdown) component\n */\n popoverProps?: Partial<PopoverProps> & {\n /**\n * It sets the max-height, in pixels, of the list\n * The default value is the height of 5 single line items\n * @default 180\n */\n listMaxHeight?: number;\n\n /**\n * Use this prop to get a ref to the list of items of the component\n */\n listRef?: React.Ref<HTMLUListElement>;\n } & Pick<CommonProps, 'className'>;\n\n /**\n * Function called when the popover loses its focus.\n */\n onBlur?: () => void;\n\n /**\n * Function called when the clear all button is clicked\n * If no function is provided the clear button is not shown\n */\n onClearSelection?: () => void;\n\n /**\n * Clear Button Props used for localization\n * @default { ariaLabel: 'Clear selection', tooltip: 'Clear selection' }\n */\n clearButtonProps?: ClearButtonProps;\n}\n\n// Scan through the whole hierachy until `filter` returns true and apply `transform`\n// Inspired from https://stackoverflow.com/a/70676868/17269164\nconst iterateOverChildren = (\n children: React.ReactNode,\n filter: (child: React.ReactElement) => boolean,\n callback: (child: React.ReactElement) => React.ReactElement | void,\n): React.ReactNode => {\n return React.Children.map(children, (child) => {\n // equal to (if (child == null || typeof child == 'string'))\n if (!React.isValidElement(child)) return child;\n if (filter(child)) {\n return callback(child);\n }\n const childChildren = iterateOverChildren(\n child.props.children,\n filter,\n callback,\n );\n return React.cloneElement(child, { children: childChildren } as unknown);\n });\n};\n\n// Scan through the whole hierachy to count the number of children where `filter` returns true\nconst countMatchingChildren = (\n children: React.ReactNode,\n filter: (child: React.ReactElement) => boolean,\n): number => {\n let counter = 0;\n React.Children.forEach(children, (child) => {\n // equal to (if (child == null || typeof child == 'string'))\n if (!React.isValidElement(child)) return;\n if (!filter(child)) {\n counter += countMatchingChildren(child.props.children, filter);\n } else {\n counter += 1;\n }\n });\n return counter;\n};\n\nfunction _Multiselect(props: MultiselectProps, ref: React.Ref<HTMLDivElement>) {\n const {\n className,\n startIcon,\n placeholder = 'Select one or more Items',\n currentSelection = [],\n toggleRef,\n toggleButtonAriaLabel = 'Toggle Multiselect',\n isLoading = false,\n testId = 'cf-multiselect',\n noMatchesMessage = 'No matches found',\n searchProps = {},\n popoverProps = {},\n children,\n onBlur,\n onClearSelection,\n clearButtonProps = {\n tooltip: 'Clear selection',\n ariaLabel: 'Clear selection',\n },\n } = props;\n\n const { listMaxHeight = 180, listRef, onClose } = popoverProps;\n\n const styles = getMultiselectStyles();\n\n const [searchValue, setSearchValue] = useState('');\n const [isOpen, setIsOpen] = useState(false);\n\n const internalListRef = useRef<HTMLUListElement>(null);\n\n const showClearButton =\n currentSelection.length > 1 && typeof onClearSelection === 'function';\n\n const hasSearch =\n typeof props.onSearchValueChange === 'function' ||\n typeof searchProps.onSearchValueChange === 'function';\n\n const handoverSearchProps =\n Object.keys(searchProps).length > 0\n ? searchProps\n : {\n onSearchValueChange: props.onSearchValueChange,\n searchPlaceholder: props.searchPlaceholder,\n searchInputName: props.searchInputName,\n searchInputRef: props.searchInputRef,\n };\n\n const focusList = useCallback(() => {\n // Clearing the search input or selecting an item triggers a rerendering and\n // thereby the client loses the focus on the clicked element. To avoid having\n // the focus on the document body (which breaks `closeOnBlur`), we force it\n // back to the list in the popup.\n internalListRef.current?.focus();\n }, []);\n\n const handleClearSelection = (e: React.MouseEvent<HTMLButtonElement>) => {\n onClearSelection?.();\n e.stopPropagation();\n };\n\n const renderMultiselectLabel = useCallback(() => {\n if (currentSelection.length === 0) {\n return <>{placeholder}</>;\n }\n const leftoverCount = currentSelection.length - 1;\n const currentSelectionClassName = cx(\n styles.currentSelection,\n showClearButton && styles.currentSelectionWithClearButton,\n );\n if (leftoverCount === 0) {\n return (\n <span\n data-test-id=\"cf-multiselect-current-selection\"\n className={currentSelectionClassName}\n >\n {currentSelection[0]}\n </span>\n );\n }\n return (\n <span\n data-test-id=\"cf-multiselect-current-selection\"\n className={currentSelectionClassName}\n >\n {currentSelection[0]}{' '}\n <span className={styles.currentSelectionAddition}>\n and {leftoverCount} more\n </span>\n </span>\n );\n }, [\n currentSelection,\n placeholder,\n showClearButton,\n styles.currentSelection,\n styles.currentSelectionAddition,\n styles.currentSelectionWithClearButton,\n ]);\n\n const optionsLength = useMemo(\n () =>\n countMatchingChildren(\n children,\n (child) => child.type === MultiselectOption,\n ),\n [children],\n );\n\n // clones and enriches the multiselect options\n const enrichOptions = React.useCallback(\n (children: React.ReactNode): React.ReactNode => {\n return iterateOverChildren(\n children,\n (child) => child.type === MultiselectOption,\n (child) => {\n const onSelectItem = (event: React.ChangeEvent<HTMLInputElement>) => {\n focusList();\n child.props?.onSelectItem(event);\n };\n return React.cloneElement(child, {\n searchValue,\n onSelectItem,\n } as Partial<MultiselectOptionProps>);\n },\n );\n },\n [searchValue, focusList],\n );\n\n return (\n <div\n data-test-id={testId}\n className={cx(styles.multiselect, className)}\n ref={ref}\n >\n <Popover\n renderOnlyWhenOpen={false}\n isFullWidth\n {...popoverProps}\n // popoverProps should never overwrite the internal opening logic\n isOpen={isOpen}\n onClose={() => {\n setIsOpen(false);\n if (onClose) {\n onClose();\n }\n }}\n >\n <Flex alignItems=\"center\">\n <Popover.Trigger>\n <Button\n aria-label={toggleButtonAriaLabel}\n ref={toggleRef}\n onClick={() => setIsOpen(!isOpen)}\n startIcon={startIcon}\n endIcon={<ChevronDownIcon />}\n isFullWidth\n className={styles.triggerButton}\n >\n {renderMultiselectLabel()}\n </Button>\n </Popover.Trigger>\n {showClearButton && (\n <div className={styles.clearSelectionButton}>\n <Tooltip\n content={\n clearButtonProps.tooltip\n ? clearButtonProps.tooltip\n : 'Clear selection'\n }\n showDelay={800}\n placement=\"top\"\n as=\"div\"\n >\n <IconButton\n onClick={handleClearSelection}\n icon={<CloseIcon />}\n aria-label={\n clearButtonProps.ariaLabel\n ? clearButtonProps.ariaLabel\n : 'Clear selection'\n }\n size=\"small\"\n />\n </Tooltip>\n </div>\n )}\n </Flex>\n <Popover.Content\n ref={mergeRefs(listRef, internalListRef)}\n className={cx(\n styles.content(listMaxHeight),\n popoverProps.className,\n styles.container,\n )}\n testId=\"cf-multiselect-container\"\n onBlur={() => onBlur?.()}\n >\n <FocusLock focusOptions={{ preventScroll: true }} returnFocus={true}>\n {hasSearch && (\n <MultiselectSearch\n {...handoverSearchProps}\n setSearchValue={setSearchValue}\n searchValue={searchValue}\n focusList={focusList}\n />\n )}\n {isLoading && <ListItemLoadingState />}\n\n {!isLoading && optionsLength > 0 && (\n <ul className={styles.list} data-test-id=\"cf-multiselect-items\">\n {hasSearch ? enrichOptions(children) : children}\n </ul>\n )}\n\n {!isLoading && optionsLength === 0 && (\n <Subheading className={styles.noMatchesTitle}>\n {noMatchesMessage}\n </Subheading>\n )}\n </FocusLock>\n </Popover.Content>\n </Popover>\n </div>\n );\n}\n\nconst ListItemLoadingState = () => {\n return (\n <SkeletonContainer svgHeight={16}>\n <SkeletonBodyText numberOfLines={1} />\n </SkeletonContainer>\n );\n};\n\n/**\n * The Multiselect is a component that will allow a user to select multiple items.\n * It has an optional\n */\nexport const Multiselect = React.forwardRef(_Multiselect);\n","import React, { useCallback, useRef } from 'react';\nimport { TextInput } from '@contentful/f36-forms';\nimport { CloseIcon, SearchIcon } from '@contentful/f36-icons';\nimport { IconButton } from '@contentful/f36-button';\nimport { getMultiselectStyles } from './Multiselect.styles';\nimport { mergeRefs } from '@contentful/f36-core';\n\nexport interface MultiselectSearchProps {\n /**\n * Function called whenever the search input value changes\n */\n onSearchValueChange?: (\n event: React.ChangeEvent<HTMLInputElement>,\n ) => void | undefined;\n\n /**\n * This is the value will be passed to the `placeholder` prop of the input.\n * @default \"Search\"\n */\n searchPlaceholder?: string;\n\n /**\n * Pass a form name to the search text input\n */\n searchInputName?: string;\n\n /**\n * Use this prop to get a ref to the search input element of the component\n */\n searchInputRef?: React.Ref<HTMLInputElement>;\n\n /**\n * Use this prop to get a ref to the reset search button of the component\n */\n resetSearchRef?: React.Ref<HTMLButtonElement>;\n\n /**\n * State from the parent component\n */\n searchValue?: string;\n\n /**\n * State setter of the parent\n */\n setSearchValue?: React.Dispatch<React.SetStateAction<string>>;\n\n /**\n * List helper function\n */\n focusList?: () => void;\n}\n\nexport const MultiselectSearch = ({\n searchValue,\n setSearchValue,\n onSearchValueChange,\n searchInputName,\n searchInputRef,\n resetSearchRef,\n searchPlaceholder = 'Search',\n focusList,\n}: MultiselectSearchProps) => {\n const styles = getMultiselectStyles();\n const internalSearchInputRef = useRef<HTMLInputElement>(null);\n\n const handleSearchChange = useCallback(\n (event) => {\n setSearchValue(event.target.value);\n onSearchValueChange?.(event);\n },\n [onSearchValueChange, setSearchValue],\n );\n\n const resetSearchInput = useCallback(() => {\n if (!searchValue) return;\n focusList();\n // this looks a bit hacky, but is the official way of externally triggering the onChange handler for an input\n // https://stackoverflow.com/a/46012210/17269164\n const nativeInputValueSetter = Object.getOwnPropertyDescriptor(\n window.HTMLInputElement.prototype,\n 'value',\n ).set;\n nativeInputValueSetter.call(internalSearchInputRef.current, '');\n const forcedEvent = new Event('change', { bubbles: true });\n internalSearchInputRef.current.dispatchEvent(forcedEvent);\n }, [searchValue, focusList]);\n\n return (\n <div className={styles.searchBar}>\n <TextInput\n aria-label=\"Search\"\n type=\"text\"\n value={searchValue}\n className={styles.inputField}\n testId=\"cf-multiselect-search\"\n placeholder={searchPlaceholder}\n onChange={handleSearchChange}\n ref={mergeRefs(searchInputRef, internalSearchInputRef)}\n name={searchInputName}\n size=\"small\"\n />\n <IconButton\n ref={resetSearchRef}\n aria-label={searchValue ? 'Clear search' : 'Search'}\n className={styles.toggleButton}\n variant=\"transparent\"\n icon={\n searchValue ? (\n <CloseIcon variant=\"muted\" />\n ) : (\n <SearchIcon variant=\"muted\" />\n )\n }\n onClick={resetSearchInput}\n isDisabled={!searchValue}\n size=\"small\"\n />\n </div>\n );\n};\n","import React from 'react';\nimport { MultiselectOption, MultiselectOptionProps } from './MultiselectOption';\nimport { getMultiselectStyles } from './Multiselect.styles';\nimport { cx } from 'emotion';\n\n/**\n * Labels for the select all option\n */\ntype SelectAllOptionLabel = {\n /**\n * Label for the select all option when it is checked\n * @default 'Deselect all'\n */\n checked: string;\n\n /**\n * Label for the select all option when it is unchecked\n * @default 'Select all'\n */\n unchecked: string;\n};\nexport interface SelectAllOptionProps\n extends Omit<\n MultiselectOptionProps,\n 'children' | 'value' | 'itemId' | 'label'\n > {\n label?: string;\n itemId?: string;\n selectAllOptionLabel?: SelectAllOptionLabel;\n}\n\nexport const SelectAllOption = ({\n label,\n itemId = 'SelectAll',\n onSelectItem,\n isChecked = false,\n selectAllOptionLabel = {\n checked: 'Deselect all',\n unchecked: 'Select all',\n },\n className,\n ...otherProps\n}: SelectAllOptionProps) => {\n const styles = getMultiselectStyles();\n const displayLabel =\n label || isChecked\n ? selectAllOptionLabel.checked\n : selectAllOptionLabel.unchecked;\n return (\n <MultiselectOption\n value=\"all\"\n label={displayLabel}\n itemId={itemId}\n onSelectItem={onSelectItem}\n isChecked={isChecked}\n className={cx(styles.selectAll, className)}\n {...otherProps}\n />\n );\n};\n","import { Multiselect as OriginalMultiSelect } from './Multiselect';\nimport { HighlightedItem, MultiselectOption } from './MultiselectOption';\nimport { SelectAllOption } from './SelectAllOption';\n\ntype CompoundMultiselect = typeof OriginalMultiSelect & {\n HighlightedItem: typeof HighlightedItem;\n Option: typeof MultiselectOption;\n SelectAll: typeof SelectAllOption;\n};\n\nexport const Multiselect = OriginalMultiSelect as CompoundMultiselect;\nMultiselect.HighlightedItem = HighlightedItem;\nMultiselect.Option = MultiselectOption;\nMultiselect.SelectAll = SelectAllOption;\n"]}
package/dist/index.d.mts CHANGED
@@ -68,6 +68,18 @@ interface MultiselectSearchProps {
68
68
  focusList?: () => void;
69
69
  }
70
70
 
71
+ declare type ClearButtonProps = {
72
+ /**
73
+ * Aria label for the clear button
74
+ * @default 'Clear selection'
75
+ */
76
+ ariaLabel?: string;
77
+ /**
78
+ * Tooltip for the clear button
79
+ * @default 'Clear selection'
80
+ */
81
+ tooltip?: string;
82
+ };
71
83
  interface MultiselectProps extends CommonProps {
72
84
  /** Select Options */
73
85
  children?: React.ReactNode;
@@ -92,6 +104,11 @@ interface MultiselectProps extends CommonProps {
92
104
  * Use this prop to get a ref to the toggle button of the component
93
105
  */
94
106
  toggleRef?: React.Ref<HTMLButtonElement>;
107
+ /**
108
+ * Aria label for the toggle button that opens the list
109
+ * @default 'Toggle Multiselect'
110
+ */
111
+ toggleButtonAriaLabel?: string;
95
112
  /**
96
113
  * Props to pass to the optional search field
97
114
  */
@@ -146,6 +163,11 @@ interface MultiselectProps extends CommonProps {
146
163
  * If no function is provided the clear button is not shown
147
164
  */
148
165
  onClearSelection?: () => void;
166
+ /**
167
+ * Clear Button Props used for localization
168
+ * @default { ariaLabel: 'Clear selection', tooltip: 'Clear selection' }
169
+ */
170
+ clearButtonProps?: ClearButtonProps;
149
171
  }
150
172
  /**
151
173
  * The Multiselect is a component that will allow a user to select multiple items.
@@ -153,11 +175,27 @@ interface MultiselectProps extends CommonProps {
153
175
  */
154
176
  declare const Multiselect$1: React.ForwardRefExoticComponent<MultiselectProps & React.RefAttributes<HTMLDivElement>>;
155
177
 
178
+ /**
179
+ * Labels for the select all option
180
+ */
181
+ declare type SelectAllOptionLabel = {
182
+ /**
183
+ * Label for the select all option when it is checked
184
+ * @default 'Deselect all'
185
+ */
186
+ checked: string;
187
+ /**
188
+ * Label for the select all option when it is unchecked
189
+ * @default 'Select all'
190
+ */
191
+ unchecked: string;
192
+ };
156
193
  interface SelectAllOptionProps extends Omit<MultiselectOptionProps, 'children' | 'value' | 'itemId' | 'label'> {
157
194
  label?: string;
158
195
  itemId?: string;
196
+ selectAllOptionLabel?: SelectAllOptionLabel;
159
197
  }
160
- declare const SelectAllOption: ({ label, itemId, onSelectItem, isChecked, className, ...otherProps }: SelectAllOptionProps) => JSX.Element;
198
+ declare const SelectAllOption: ({ label, itemId, onSelectItem, isChecked, selectAllOptionLabel, className, ...otherProps }: SelectAllOptionProps) => JSX.Element;
161
199
 
162
200
  declare type CompoundMultiselect = typeof Multiselect$1 & {
163
201
  HighlightedItem: typeof HighlightedItem;
package/dist/index.d.ts CHANGED
@@ -68,6 +68,18 @@ interface MultiselectSearchProps {
68
68
  focusList?: () => void;
69
69
  }
70
70
 
71
+ declare type ClearButtonProps = {
72
+ /**
73
+ * Aria label for the clear button
74
+ * @default 'Clear selection'
75
+ */
76
+ ariaLabel?: string;
77
+ /**
78
+ * Tooltip for the clear button
79
+ * @default 'Clear selection'
80
+ */
81
+ tooltip?: string;
82
+ };
71
83
  interface MultiselectProps extends CommonProps {
72
84
  /** Select Options */
73
85
  children?: React.ReactNode;
@@ -92,6 +104,11 @@ interface MultiselectProps extends CommonProps {
92
104
  * Use this prop to get a ref to the toggle button of the component
93
105
  */
94
106
  toggleRef?: React.Ref<HTMLButtonElement>;
107
+ /**
108
+ * Aria label for the toggle button that opens the list
109
+ * @default 'Toggle Multiselect'
110
+ */
111
+ toggleButtonAriaLabel?: string;
95
112
  /**
96
113
  * Props to pass to the optional search field
97
114
  */
@@ -146,6 +163,11 @@ interface MultiselectProps extends CommonProps {
146
163
  * If no function is provided the clear button is not shown
147
164
  */
148
165
  onClearSelection?: () => void;
166
+ /**
167
+ * Clear Button Props used for localization
168
+ * @default { ariaLabel: 'Clear selection', tooltip: 'Clear selection' }
169
+ */
170
+ clearButtonProps?: ClearButtonProps;
149
171
  }
150
172
  /**
151
173
  * The Multiselect is a component that will allow a user to select multiple items.
@@ -153,11 +175,27 @@ interface MultiselectProps extends CommonProps {
153
175
  */
154
176
  declare const Multiselect$1: React.ForwardRefExoticComponent<MultiselectProps & React.RefAttributes<HTMLDivElement>>;
155
177
 
178
+ /**
179
+ * Labels for the select all option
180
+ */
181
+ declare type SelectAllOptionLabel = {
182
+ /**
183
+ * Label for the select all option when it is checked
184
+ * @default 'Deselect all'
185
+ */
186
+ checked: string;
187
+ /**
188
+ * Label for the select all option when it is unchecked
189
+ * @default 'Select all'
190
+ */
191
+ unchecked: string;
192
+ };
156
193
  interface SelectAllOptionProps extends Omit<MultiselectOptionProps, 'children' | 'value' | 'itemId' | 'label'> {
157
194
  label?: string;
158
195
  itemId?: string;
196
+ selectAllOptionLabel?: SelectAllOptionLabel;
159
197
  }
160
- declare const SelectAllOption: ({ label, itemId, onSelectItem, isChecked, className, ...otherProps }: SelectAllOptionProps) => JSX.Element;
198
+ declare const SelectAllOption: ({ label, itemId, onSelectItem, isChecked, selectAllOptionLabel, className, ...otherProps }: SelectAllOptionProps) => JSX.Element;
161
199
 
162
200
  declare type CompoundMultiselect = typeof Multiselect$1 & {
163
201
  HighlightedItem: typeof HighlightedItem;
package/dist/index.js CHANGED
@@ -12,18 +12,18 @@ var f36Icons = require('@contentful/f36-icons');
12
12
  var f36Skeleton = require('@contentful/f36-skeleton');
13
13
  var f36Popover = require('@contentful/f36-popover');
14
14
  var f36Tooltip = require('@contentful/f36-tooltip');
15
- var Ae = require('react-focus-lock');
15
+ var De = require('react-focus-lock');
16
16
 
17
17
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
18
18
 
19
19
  var l__default = /*#__PURE__*/_interopDefault(l);
20
20
  var r__default = /*#__PURE__*/_interopDefault(r);
21
- var Ae__default = /*#__PURE__*/_interopDefault(Ae);
21
+ var De__default = /*#__PURE__*/_interopDefault(De);
22
22
 
23
- var ce=Object.defineProperty,pe=Object.defineProperties;var me=Object.getOwnPropertyDescriptors;var O=Object.getOwnPropertySymbols;var U=Object.prototype.hasOwnProperty,_=Object.prototype.propertyIsEnumerable;var j=(e,t,o)=>t in e?ce(e,t,{enumerable:!0,configurable:!0,writable:!0,value:o}):e[t]=o,b=(e,t)=>{for(var o in t||(t={}))U.call(t,o)&&j(e,o,t[o]);if(O)for(var o of O(t))_.call(t,o)&&j(e,o,t[o]);return e},H=(e,t)=>pe(e,me(t));var N=(e,t)=>{var o={};for(var n in e)U.call(e,n)&&t.indexOf(n)<0&&(o[n]=e[n]);if(e!=null&&O)for(var n of O(e))t.indexOf(n)<0&&_.call(e,n)&&(o[n]=e[n]);return o};var S=()=>({multiselect:emotion.css({position:"relative",width:"100%"}),triggerButton:emotion.css({justifyContent:"space-between"}),currentSelection:emotion.css({display:"inline-block",width:"100%",whiteSpace:"nowrap",textOverflow:"ellipsis",overflow:"hidden",verticalAlign:"bottom",marginRight:r__default.default.spacing2Xs}),currentSelectionWithClearButton:emotion.css({paddingRight:"40px"}),currentSelectionAddition:emotion.css({color:r__default.default.gray600}),searchBar:emotion.css({paddingTop:r__default.default.spacing2Xs,position:"sticky",top:"0px",zIndex:r__default.default.zIndexWorkbenchHeader,backgroundColor:r__default.default.colorWhite}),inputField:emotion.css({padding:`6px ${r__default.default.spacingXl} 10px ${r__default.default.spacingXs}`,textOverflow:"ellipsis",whiteSpace:"nowrap",border:"none",borderRadius:"0px",borderBottom:`1px solid ${r__default.default.gray200}`,boxShadow:"none","&:focus, &:active, &:active:hover":{boxShadow:"none",borderBottom:`1px solid ${r__default.default.gray200}`}}),toggleButton:emotion.css({position:"absolute",top:"1px",right:"1px",zIndex:r__default.default.zIndexDefault,padding:r__default.default.spacing2Xs,height:r__default.default.spacingXl}),content:e=>emotion.css({overflow:"auto",maxHeight:`${e}px`}),container:emotion.css({}),list:emotion.css({listStyle:"none",padding:`${r__default.default.spacing2Xs}`,margin:0}),groupTitle:emotion.css({padding:`6px ${r__default.default.spacingXs}`,lineHeight:r__default.default.lineHeightM}),noMatchesTitle:emotion.css({color:r__default.default.gray500,margin:r__default.default.spacingM,textAlign:"center"}),clearSelectionButton:emotion.css({marginLeft:"-80px"}),selectAll:emotion.css({borderBottom:`1px solid ${r__default.default.gray200}`,marginBottom:r__default.default.spacing2Xs,paddingBottom:r__default.default.spacing2Xs,"label > *":{fontWeight:r__default.default.fontWeightMedium}}),option:emotion.css({listStyleType:"none"}),optionText:emotion.css({alignItems:"center",display:"flex",span:{color:r__default.default.gray900,fontWeight:r__default.default.fontWeightDemiBold}}),optionCheck:({isActive:e,isDisabled:t})=>emotion.css({label:emotion.cx(f36Core.getMenuItemStyles({isActive:e,isDisabled:t}),emotion.css({width:"100%"}))})});var M=y=>{var f=y,{children:e,label:t,value:o,itemId:n,onSelectItem:s,searchValue:c,isChecked:v=!1,isDisabled:p=!1,className:d}=f,g=N(f,["children","label","value","itemId","onSelectItem","searchValue","isChecked","isDisabled","className"]);let m=S();return l__default.default.createElement("li",b({className:emotion.cx(m.option,d)},g),l__default.default.createElement(f36Forms.Checkbox,{id:n,value:o,onChange:x=>s(x),isChecked:v,isDisabled:p,className:m.optionCheck({isActive:v,isDisabled:p})},l__default.default.createElement(f36Typography.Text,{className:m.optionText,"data-test-id":`cf-multiselect-list-item-${n}`},typeof t=="string"?l__default.default.createElement(L,{item:t,inputValue:c}):e)))};function L({item:e,inputValue:t=""}){let{before:o,match:n,after:s}=f36Utils.getStringMatch(e,t.trim());return o.length+n.length+s.length===0?l__default.default.createElement(l__default.default.Fragment,null,e):l__default.default.createElement(l__default.default.Fragment,null,o,l__default.default.createElement("span",{"data-test-id":"cf-multiselect-item-match"},n),s)}L.displayName="HighlightedItem";var G=({searchValue:e,setSearchValue:t,onSearchValueChange:o,searchInputName:n,searchInputRef:s,resetSearchRef:c,searchPlaceholder:v="Search",focusList:p})=>{let d=S(),g=l.useRef(null),y=l.useCallback(m=>{t(m.target.value),o==null||o(m);},[o,t]),f=l.useCallback(()=>{if(!e)return;p(),Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value").set.call(g.current,"");let x=new Event("change",{bubbles:!0});g.current.dispatchEvent(x);},[e,p]);return l__default.default.createElement("div",{className:d.searchBar},l__default.default.createElement(f36Forms.TextInput,{"aria-label":"Search",type:"text",value:e,className:d.inputField,testId:"cf-multiselect-search",placeholder:v,onChange:y,ref:f36Core.mergeRefs(s,g),name:n,size:"small"}),l__default.default.createElement(f36Button.IconButton,{ref:c,"aria-label":e?"Clear search":"Search",className:d.toggleButton,variant:"transparent",icon:e?l__default.default.createElement(f36Icons.CloseIcon,{variant:"muted"}):l__default.default.createElement(f36Icons.SearchIcon,{variant:"muted"}),onClick:f,isDisabled:!e,size:"small"}))};var Q=(e,t,o)=>l__default.default.Children.map(e,n=>{if(!l__default.default.isValidElement(n))return n;if(t(n))return o(n);let s=Q(n.props.children,t,o);return l__default.default.cloneElement(n,{children:s})}),Y=(e,t)=>{let o=0;return l__default.default.Children.forEach(e,n=>{l__default.default.isValidElement(n)&&(t(n)?o+=1:o+=Y(n.props.children,t));}),o};function We(e,t){let{className:o,startIcon:n,placeholder:s="Select one or more Items",currentSelection:c=[],toggleRef:v,isLoading:p=!1,testId:d="cf-multiselect",noMatchesMessage:g="No matches found",searchProps:y={},popoverProps:f={},children:m,onBlur:x,onClearSelection:P}=e,{listMaxHeight:ee=180,listRef:te,onClose:W}=f,a=S(),[T,oe]=l.useState(""),[D,X]=l.useState(!1),F=l.useRef(null),R=c.length>1&&typeof P=="function",$=typeof e.onSearchValueChange=="function"||typeof y.onSearchValueChange=="function",ne=Object.keys(y).length>0?y:{onSearchValueChange:e.onSearchValueChange,searchPlaceholder:e.searchPlaceholder,searchInputName:e.searchInputName,searchInputRef:e.searchInputRef},B=l.useCallback(()=>{var u;(u=F.current)==null||u.focus();},[]),le=u=>{P==null||P(),u.stopPropagation();},re=l.useCallback(()=>{if(c.length===0)return l__default.default.createElement(l__default.default.Fragment,null,s);let u=c.length-1,I=emotion.cx(a.currentSelection,R&&a.currentSelectionWithClearButton);return u===0?l__default.default.createElement("span",{"data-test-id":"cf-multiselect-current-selection",className:I},c[0]):l__default.default.createElement("span",{"data-test-id":"cf-multiselect-current-selection",className:I},c[0]," ",l__default.default.createElement("span",{className:a.currentSelectionAddition},"and ",u," more"))},[c,s,R,a.currentSelection,a.currentSelectionAddition,a.currentSelectionWithClearButton]),V=l.useMemo(()=>Y(m,u=>u.type===M),[m]),ie=l__default.default.useCallback(u=>Q(u,I=>I.type===M,I=>{let se=ae=>{var z;B(),(z=I.props)==null||z.onSelectItem(ae);};return l__default.default.cloneElement(I,{searchValue:T,onSelectItem:se})}),[T,B]);return l__default.default.createElement("div",{"data-test-id":d,className:emotion.cx(a.multiselect,o),ref:t},l__default.default.createElement(f36Popover.Popover,H(b({renderOnlyWhenOpen:!1,isFullWidth:!0},f),{isOpen:D,onClose:()=>{X(!1),W&&W();}}),l__default.default.createElement(f36Core.Flex,{alignItems:"center"},l__default.default.createElement(f36Popover.Popover.Trigger,null,l__default.default.createElement(f36Button.Button,{"aria-label":"Toggle Multiselect",ref:v,onClick:()=>X(!D),startIcon:n,endIcon:l__default.default.createElement(f36Icons.ChevronDownIcon,null),isFullWidth:!0,className:a.triggerButton},re())),R&&l__default.default.createElement("div",{className:a.clearSelectionButton},l__default.default.createElement(f36Tooltip.Tooltip,{content:"Clear selection",showDelay:800,placement:"top",as:"div"},l__default.default.createElement(f36Button.IconButton,{onClick:le,icon:l__default.default.createElement(f36Icons.CloseIcon,null),"aria-label":"Clear selection",size:"small"})))),l__default.default.createElement(f36Popover.Popover.Content,{ref:f36Core.mergeRefs(te,F),className:emotion.cx(a.content(ee),f.className,a.container),testId:"cf-multiselect-container",onBlur:()=>x==null?void 0:x()},l__default.default.createElement(Ae__default.default,{focusOptions:{preventScroll:!0},returnFocus:!0},$&&l__default.default.createElement(G,H(b({},ne),{setSearchValue:oe,searchValue:T,focusList:B})),p&&l__default.default.createElement(De,null),!p&&V>0&&l__default.default.createElement("ul",{className:a.list,"data-test-id":"cf-multiselect-items"},$?ie(m):m),!p&&V===0&&l__default.default.createElement(f36Typography.Subheading,{className:a.noMatchesTitle},g)))))}var De=()=>l__default.default.createElement(f36Skeleton.SkeletonContainer,{svgHeight:16},l__default.default.createElement(f36Skeleton.SkeletonBodyText,{numberOfLines:1})),Z=l__default.default.forwardRef(We);var A=v=>{var p=v,{label:e,itemId:t="SelectAll",onSelectItem:o,isChecked:n=!1,className:s}=p,c=N(p,["label","itemId","onSelectItem","isChecked","className"]);let d=S();return l__default.default.createElement(M,b({value:"all",label:e||n?"Deselect all":"Select all",itemId:t,onSelectItem:o,isChecked:n,className:emotion.cx(d.selectAll,s)},c))};var E=Z;E.HighlightedItem=L;E.Option=M;E.SelectAll=A;
23
+ var ue=Object.defineProperty,me=Object.defineProperties;var de=Object.getOwnPropertyDescriptors;var L=Object.getOwnPropertySymbols;var q=Object.prototype.hasOwnProperty,G=Object.prototype.propertyIsEnumerable;var _=(e,t,o)=>t in e?ue(e,t,{enumerable:!0,configurable:!0,writable:!0,value:o}):e[t]=o,I=(e,t)=>{for(var o in t||(t={}))q.call(t,o)&&_(e,o,t[o]);if(L)for(var o of L(t))G.call(t,o)&&_(e,o,t[o]);return e},A=(e,t)=>me(e,de(t));var N=(e,t)=>{var o={};for(var n in e)q.call(e,n)&&t.indexOf(n)<0&&(o[n]=e[n]);if(e!=null&&L)for(var n of L(e))t.indexOf(n)<0&&G.call(e,n)&&(o[n]=e[n]);return o};var v=()=>({multiselect:emotion.css({position:"relative",width:"100%"}),triggerButton:emotion.css({justifyContent:"space-between"}),currentSelection:emotion.css({display:"inline-block",width:"100%",whiteSpace:"nowrap",textOverflow:"ellipsis",overflow:"hidden",verticalAlign:"bottom",marginRight:r__default.default.spacing2Xs}),currentSelectionWithClearButton:emotion.css({paddingRight:"40px"}),currentSelectionAddition:emotion.css({color:r__default.default.gray600}),searchBar:emotion.css({paddingTop:r__default.default.spacing2Xs,position:"sticky",top:"0px",zIndex:r__default.default.zIndexWorkbenchHeader,backgroundColor:r__default.default.colorWhite}),inputField:emotion.css({padding:`6px ${r__default.default.spacingXl} 10px ${r__default.default.spacingXs}`,textOverflow:"ellipsis",whiteSpace:"nowrap",border:"none",borderRadius:"0px",borderBottom:`1px solid ${r__default.default.gray200}`,boxShadow:"none","&:focus, &:active, &:active:hover":{boxShadow:"none",borderBottom:`1px solid ${r__default.default.gray200}`}}),toggleButton:emotion.css({position:"absolute",top:"1px",right:"1px",zIndex:r__default.default.zIndexDefault,padding:r__default.default.spacing2Xs,height:r__default.default.spacingXl}),content:e=>emotion.css({overflow:"auto",maxHeight:`${e}px`}),container:emotion.css({}),list:emotion.css({listStyle:"none",padding:`${r__default.default.spacing2Xs}`,margin:0}),groupTitle:emotion.css({padding:`6px ${r__default.default.spacingXs}`,lineHeight:r__default.default.lineHeightM}),noMatchesTitle:emotion.css({color:r__default.default.gray500,margin:r__default.default.spacingM,textAlign:"center"}),clearSelectionButton:emotion.css({marginLeft:"-80px"}),selectAll:emotion.css({borderBottom:`1px solid ${r__default.default.gray200}`,marginBottom:r__default.default.spacing2Xs,paddingBottom:r__default.default.spacing2Xs,"label > *":{fontWeight:r__default.default.fontWeightMedium}}),option:emotion.css({listStyleType:"none"}),optionText:emotion.css({alignItems:"center",display:"flex",span:{color:r__default.default.gray900,fontWeight:r__default.default.fontWeightDemiBold}}),optionCheck:({isActive:e,isDisabled:t})=>emotion.css({label:emotion.cx(f36Core.getMenuItemStyles({isActive:e,isDisabled:t}),emotion.css({width:"100%"}))})});var b=C=>{var S=C,{children:e,label:t,value:o,itemId:n,onSelectItem:s,searchValue:c,isChecked:g=!1,isDisabled:f=!1,className:p}=S,d=N(S,["children","label","value","itemId","onSelectItem","searchValue","isChecked","isDisabled","className"]);let u=v();return l__default.default.createElement("li",I({className:emotion.cx(u.option,p)},d),l__default.default.createElement(f36Forms.Checkbox,{id:n,value:o,onChange:M=>s(M),isChecked:g,isDisabled:f,className:u.optionCheck({isActive:g,isDisabled:f})},l__default.default.createElement(f36Typography.Text,{className:u.optionText,"data-test-id":`cf-multiselect-list-item-${n}`},typeof t=="string"?l__default.default.createElement(B,{item:t,inputValue:c}):e)))};function B({item:e,inputValue:t=""}){let{before:o,match:n,after:s}=f36Utils.getStringMatch(e,t.trim());return o.length+n.length+s.length===0?l__default.default.createElement(l__default.default.Fragment,null,e):l__default.default.createElement(l__default.default.Fragment,null,o,l__default.default.createElement("span",{"data-test-id":"cf-multiselect-item-match"},n),s)}B.displayName="HighlightedItem";var K=({searchValue:e,setSearchValue:t,onSearchValueChange:o,searchInputName:n,searchInputRef:s,resetSearchRef:c,searchPlaceholder:g="Search",focusList:f})=>{let p=v(),d=l.useRef(null),C=l.useCallback(u=>{t(u.target.value),o==null||o(u);},[o,t]),S=l.useCallback(()=>{if(!e)return;f(),Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value").set.call(d.current,"");let M=new Event("change",{bubbles:!0});d.current.dispatchEvent(M);},[e,f]);return l__default.default.createElement("div",{className:p.searchBar},l__default.default.createElement(f36Forms.TextInput,{"aria-label":"Search",type:"text",value:e,className:p.inputField,testId:"cf-multiselect-search",placeholder:g,onChange:C,ref:f36Core.mergeRefs(s,d),name:n,size:"small"}),l__default.default.createElement(f36Button.IconButton,{ref:c,"aria-label":e?"Clear search":"Search",className:p.toggleButton,variant:"transparent",icon:e?l__default.default.createElement(f36Icons.CloseIcon,{variant:"muted"}):l__default.default.createElement(f36Icons.SearchIcon,{variant:"muted"}),onClick:S,isDisabled:!e,size:"small"}))};var Z=(e,t,o)=>l__default.default.Children.map(e,n=>{if(!l__default.default.isValidElement(n))return n;if(t(n))return o(n);let s=Z(n.props.children,t,o);return l__default.default.cloneElement(n,{children:s})}),ee=(e,t)=>{let o=0;return l__default.default.Children.forEach(e,n=>{l__default.default.isValidElement(n)&&(t(n)?o+=1:o+=ee(n.props.children,t));}),o};function Xe(e,t){let{className:o,startIcon:n,placeholder:s="Select one or more Items",currentSelection:c=[],toggleRef:g,toggleButtonAriaLabel:f="Toggle Multiselect",isLoading:p=!1,testId:d="cf-multiselect",noMatchesMessage:C="No matches found",searchProps:S={},popoverProps:u={},children:M,onBlur:T,onClearSelection:P,clearButtonProps:O={tooltip:"Clear selection",ariaLabel:"Clear selection"}}=e,{listMaxHeight:oe=180,listRef:ne,onClose:X}=u,a=v(),[k,le]=l.useState(""),[F,$]=l.useState(!1),V=l.useRef(null),R=c.length>1&&typeof P=="function",z=typeof e.onSearchValueChange=="function"||typeof S.onSearchValueChange=="function",re=Object.keys(S).length>0?S:{onSearchValueChange:e.onSearchValueChange,searchPlaceholder:e.searchPlaceholder,searchInputName:e.searchInputName,searchInputRef:e.searchInputRef},H=l.useCallback(()=>{var m;(m=V.current)==null||m.focus();},[]),ie=m=>{P==null||P(),m.stopPropagation();},se=l.useCallback(()=>{if(c.length===0)return l__default.default.createElement(l__default.default.Fragment,null,s);let m=c.length-1,x=emotion.cx(a.currentSelection,R&&a.currentSelectionWithClearButton);return m===0?l__default.default.createElement("span",{"data-test-id":"cf-multiselect-current-selection",className:x},c[0]):l__default.default.createElement("span",{"data-test-id":"cf-multiselect-current-selection",className:x},c[0]," ",l__default.default.createElement("span",{className:a.currentSelectionAddition},"and ",m," more"))},[c,s,R,a.currentSelection,a.currentSelectionAddition,a.currentSelectionWithClearButton]),j=l.useMemo(()=>ee(M,m=>m.type===b),[M]),ae=l__default.default.useCallback(m=>Z(m,x=>x.type===b,x=>{let ce=pe=>{var U;H(),(U=x.props)==null||U.onSelectItem(pe);};return l__default.default.cloneElement(x,{searchValue:k,onSelectItem:ce})}),[k,H]);return l__default.default.createElement("div",{"data-test-id":d,className:emotion.cx(a.multiselect,o),ref:t},l__default.default.createElement(f36Popover.Popover,A(I({renderOnlyWhenOpen:!1,isFullWidth:!0},u),{isOpen:F,onClose:()=>{$(!1),X&&X();}}),l__default.default.createElement(f36Core.Flex,{alignItems:"center"},l__default.default.createElement(f36Popover.Popover.Trigger,null,l__default.default.createElement(f36Button.Button,{"aria-label":f,ref:g,onClick:()=>$(!F),startIcon:n,endIcon:l__default.default.createElement(f36Icons.ChevronDownIcon,null),isFullWidth:!0,className:a.triggerButton},se())),R&&l__default.default.createElement("div",{className:a.clearSelectionButton},l__default.default.createElement(f36Tooltip.Tooltip,{content:O.tooltip?O.tooltip:"Clear selection",showDelay:800,placement:"top",as:"div"},l__default.default.createElement(f36Button.IconButton,{onClick:ie,icon:l__default.default.createElement(f36Icons.CloseIcon,null),"aria-label":O.ariaLabel?O.ariaLabel:"Clear selection",size:"small"})))),l__default.default.createElement(f36Popover.Popover.Content,{ref:f36Core.mergeRefs(ne,V),className:emotion.cx(a.content(oe),u.className,a.container),testId:"cf-multiselect-container",onBlur:()=>T==null?void 0:T()},l__default.default.createElement(De__default.default,{focusOptions:{preventScroll:!0},returnFocus:!0},z&&l__default.default.createElement(K,A(I({},re),{setSearchValue:le,searchValue:k,focusList:H})),p&&l__default.default.createElement(Fe,null),!p&&j>0&&l__default.default.createElement("ul",{className:a.list,"data-test-id":"cf-multiselect-items"},z?ae(M):M),!p&&j===0&&l__default.default.createElement(f36Typography.Subheading,{className:a.noMatchesTitle},C)))))}var Fe=()=>l__default.default.createElement(f36Skeleton.SkeletonContainer,{svgHeight:16},l__default.default.createElement(f36Skeleton.SkeletonBodyText,{numberOfLines:1})),te=l__default.default.forwardRef(Xe);var D=f=>{var p=f,{label:e,itemId:t="SelectAll",onSelectItem:o,isChecked:n=!1,selectAllOptionLabel:s={checked:"Deselect all",unchecked:"Select all"},className:c}=p,g=N(p,["label","itemId","onSelectItem","isChecked","selectAllOptionLabel","className"]);let d=v(),C=e||n?s.checked:s.unchecked;return l__default.default.createElement(b,I({value:"all",label:C,itemId:t,onSelectItem:o,isChecked:n,className:emotion.cx(d.selectAll,c)},g))};var E=te;E.HighlightedItem=B;E.Option=b;E.SelectAll=D;
24
24
 
25
25
  exports.Multiselect = E;
26
- exports.MultiselectOption = M;
27
- exports.SelectAllOption = A;
26
+ exports.MultiselectOption = b;
27
+ exports.SelectAllOption = D;
28
28
  //# sourceMappingURL=out.js.map
29
29
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/MultiselectOption.tsx","../src/Multiselect.styles.ts","../src/Multiselect.tsx","../src/MultiselectSearch.tsx","../src/SelectAllOption.tsx","../src/CompoundMultiselect.tsx"],"names":["React","Checkbox","Text","css","cx","tokens","getMenuItemStyles","getMultiselectStyles","listMaxHeight","isActive","isDisabled","getStringMatch","MultiselectOption","_a","_b","children","label","value","itemId","onSelectItem","searchValue","isChecked","className","rest","__objRest","styles","__spreadValues","event","HighlightedItem","item","inputValue","before","match","after","useRef","useState","useCallback","useMemo","mergeRefs","Flex","Button","IconButton","ChevronDownIcon","CloseIcon","SkeletonContainer","SkeletonBodyText","Popover","Subheading","Tooltip","FocusLock","TextInput","SearchIcon","MultiselectSearch","setSearchValue","onSearchValueChange","searchInputName","searchInputRef","resetSearchRef","searchPlaceholder","focusList","internalSearchInputRef","handleSearchChange","resetSearchInput","forcedEvent","iterateOverChildren","filter","callback","child","childChildren","countMatchingChildren","counter","_Multiselect","props","ref","startIcon","placeholder","currentSelection","toggleRef","isLoading","testId","noMatchesMessage","searchProps","popoverProps","onBlur","onClearSelection","listRef","onClose","isOpen","setIsOpen","internalListRef","showClearButton","hasSearch","handoverSearchProps","handleClearSelection","e","renderMultiselectLabel","leftoverCount","currentSelectionClassName","optionsLength","enrichOptions","__spreadProps","ListItemLoadingState","Multiselect","SelectAllOption","otherProps"],"mappings":"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","sourcesContent":["import React from 'react';\nimport { Checkbox } from '@contentful/f36-forms';\nimport { Text } from '@contentful/f36-typography';\nimport { getMultiselectStyles } from './Multiselect.styles';\nimport { getStringMatch } from '@contentful/f36-utils';\nimport { cx } from 'emotion';\n\ntype LabelOrChildren =\n | {\n /**\n * When using React children it is your own responsibility to highlight\n * the matching part of the item label. Use the `HighlightedItem`\n * component for this.\n */\n children: React.ReactNode;\n label?: never;\n }\n | {\n children?: never;\n label: string;\n };\n\nexport type MultiselectOptionProps = {\n value: string;\n itemId: string;\n searchValue?: string;\n className?: string;\n onSelectItem: (event: React.ChangeEvent<HTMLInputElement>) => void;\n isChecked?: boolean;\n isDisabled?: boolean;\n} & LabelOrChildren;\n\nexport const MultiselectOption = ({\n children,\n label,\n value,\n itemId,\n onSelectItem,\n searchValue,\n isChecked = false,\n isDisabled = false,\n className,\n ...rest\n}: MultiselectOptionProps) => {\n const styles = getMultiselectStyles();\n\n return (\n <li className={cx(styles.option, className)} {...rest}>\n <Checkbox\n id={itemId}\n value={value}\n onChange={(event) => onSelectItem(event)}\n isChecked={isChecked}\n isDisabled={isDisabled}\n className={styles.optionCheck({ isActive: isChecked, isDisabled })}\n >\n <Text\n className={styles.optionText}\n data-test-id={`cf-multiselect-list-item-${itemId}`}\n >\n {typeof label === 'string' ? (\n <HighlightedItem item={label} inputValue={searchValue} />\n ) : (\n children\n )}\n </Text>\n </Checkbox>\n </li>\n );\n};\n\nexport function HighlightedItem({\n item,\n inputValue = '',\n}: {\n item: string;\n inputValue?: string;\n}) {\n const { before, match, after } = getStringMatch(item, inputValue.trim());\n\n if (before.length + match.length + after.length === 0) {\n return <>{item}</>;\n }\n\n return (\n <>\n {before}\n <span data-test-id=\"cf-multiselect-item-match\">{match}</span>\n {after}\n </>\n );\n}\n\nHighlightedItem.displayName = 'HighlightedItem';\n","import { css, cx } from 'emotion';\nimport tokens from '@contentful/f36-tokens';\nimport { getMenuItemStyles } from '@contentful/f36-core';\n\nexport const getMultiselectStyles = () => ({\n multiselect: css({\n position: 'relative',\n width: '100%',\n }),\n triggerButton: css({\n justifyContent: 'space-between',\n }),\n currentSelection: css({\n display: 'inline-block',\n width: '100%',\n whiteSpace: 'nowrap',\n textOverflow: 'ellipsis',\n overflow: 'hidden',\n verticalAlign: 'bottom',\n marginRight: tokens.spacing2Xs,\n }),\n currentSelectionWithClearButton: css({\n paddingRight: '40px',\n }),\n currentSelectionAddition: css({\n color: tokens.gray600,\n }),\n searchBar: css({\n paddingTop: tokens.spacing2Xs,\n position: 'sticky',\n top: '0px',\n zIndex: tokens.zIndexWorkbenchHeader,\n backgroundColor: tokens.colorWhite,\n }),\n inputField: css({\n padding: `6px ${tokens.spacingXl} 10px ${tokens.spacingXs}`,\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n border: 'none',\n borderRadius: '0px',\n borderBottom: `1px solid ${tokens.gray200}`,\n boxShadow: 'none',\n '&:focus, &:active, &:active:hover': {\n boxShadow: 'none',\n borderBottom: `1px solid ${tokens.gray200}`,\n },\n }),\n toggleButton: css({\n position: 'absolute',\n top: '1px',\n right: '1px',\n zIndex: tokens.zIndexDefault,\n padding: tokens.spacing2Xs,\n height: tokens.spacingXl,\n }),\n content: (listMaxHeight: number) =>\n css({\n overflow: 'auto',\n maxHeight: `${listMaxHeight}px`,\n }),\n container: css({}),\n list: css({\n listStyle: 'none',\n padding: `${tokens.spacing2Xs}`,\n margin: 0,\n }),\n groupTitle: css({\n // Magic number to get a height of 32px on the item\n padding: `6px ${tokens.spacingXs}`,\n lineHeight: tokens.lineHeightM,\n }),\n noMatchesTitle: css({\n color: tokens.gray500,\n margin: tokens.spacingM,\n textAlign: 'center',\n }),\n clearSelectionButton: css({\n marginLeft: '-80px',\n }),\n selectAll: css({\n borderBottom: `1px solid ${tokens.gray200}`,\n marginBottom: tokens.spacing2Xs,\n paddingBottom: tokens.spacing2Xs,\n 'label > *': {\n fontWeight: tokens.fontWeightMedium,\n },\n }),\n option: css({\n listStyleType: 'none',\n }),\n optionText: css({\n alignItems: 'center',\n display: 'flex',\n span: {\n color: tokens.gray900,\n fontWeight: tokens.fontWeightDemiBold,\n },\n }),\n optionCheck: ({\n isActive,\n isDisabled,\n }: {\n isActive?: boolean;\n isDisabled?: boolean;\n }) =>\n css({\n label: cx(\n getMenuItemStyles({ isActive, isDisabled }),\n css({\n width: '100%',\n }),\n ),\n }),\n});\n","import React, { useRef, useState, useCallback, useMemo } from 'react';\nimport { cx } from 'emotion';\n\nimport { mergeRefs, type CommonProps, Flex } from '@contentful/f36-core';\nimport { Button, IconButton } from '@contentful/f36-button';\nimport { ChevronDownIcon, CloseIcon } from '@contentful/f36-icons';\n\nimport { SkeletonContainer, SkeletonBodyText } from '@contentful/f36-skeleton';\nimport { Popover, type PopoverProps } from '@contentful/f36-popover';\nimport { Subheading } from '@contentful/f36-typography';\nimport { Tooltip } from '@contentful/f36-tooltip';\n\nimport { getMultiselectStyles } from './Multiselect.styles';\nimport { MultiselectOption, MultiselectOptionProps } from './MultiselectOption';\nimport FocusLock from 'react-focus-lock';\n\nimport type { MultiselectSearchProps as SearchProps } from './MultiselectSearch';\nimport { MultiselectSearch } from './MultiselectSearch';\n\nexport interface MultiselectProps extends CommonProps {\n /** Select Options */\n children?: React.ReactNode;\n\n /**\n * Set a custom icon for the text input\n */\n startIcon?: React.ReactElement;\n\n /**\n * Placeholder shown before selecting any elements. Defaults to 'Select one or more items'\n */\n placeholder?: string;\n\n /**\n * current Selected items, to be shown on the trigger button\n */\n currentSelection?: Array<string>;\n\n /**\n * Sets the list to show its loading state\n * @default false\n */\n isLoading?: boolean;\n\n /**\n * Use this prop to get a ref to the toggle button of the component\n */\n toggleRef?: React.Ref<HTMLButtonElement>;\n\n /**\n * Props to pass to the optional search field\n */\n searchProps?: SearchProps;\n\n /**\n * Function called whenever the search input value changes\n * @deprecated Handover this prop in the searchProps subcomponent properties\n */\n onSearchValueChange?: (\n event: React.ChangeEvent<HTMLInputElement>,\n ) => void | undefined;\n\n /**\n * This is the value will be passed to the `placeholder` prop of the input.\n * @deprecated Handover this prop in the searchProps subcomponent properties\n * @default \"Search\"\n */\n searchPlaceholder?: string;\n\n /**\n * A message that will be shown when it is not possible to find any option that matches the search value\n * @default \"No matches\"\n */\n noMatchesMessage?: string;\n\n /**\n * Pass a form name to the search text input\n * @deprecated Handover this prop in the searchProps subcomponent properties\n */\n searchInputName?: string;\n\n /**\n * Use this prop to get a ref to the search input element of the component\n * @deprecated Handover this prop in the searchProps subcomponent properties\n */\n searchInputRef?: React.Ref<HTMLInputElement>;\n\n /**\n * Props to pass to the Popover (Dropdown) component\n */\n popoverProps?: Partial<PopoverProps> & {\n /**\n * It sets the max-height, in pixels, of the list\n * The default value is the height of 5 single line items\n * @default 180\n */\n listMaxHeight?: number;\n\n /**\n * Use this prop to get a ref to the list of items of the component\n */\n listRef?: React.Ref<HTMLUListElement>;\n } & Pick<CommonProps, 'className'>;\n\n /**\n * Function called when the popover loses its focus.\n */\n onBlur?: () => void;\n\n /**\n * Function called when the clear all button is clicked\n * If no function is provided the clear button is not shown\n */\n onClearSelection?: () => void;\n}\n\n// Scan through the whole hierachy until `filter` returns true and apply `transform`\n// Inspired from https://stackoverflow.com/a/70676868/17269164\nconst iterateOverChildren = (\n children: React.ReactNode,\n filter: (child: React.ReactElement) => boolean,\n callback: (child: React.ReactElement) => React.ReactElement | void,\n): React.ReactNode => {\n return React.Children.map(children, (child) => {\n // equal to (if (child == null || typeof child == 'string'))\n if (!React.isValidElement(child)) return child;\n if (filter(child)) {\n return callback(child);\n }\n const childChildren = iterateOverChildren(\n child.props.children,\n filter,\n callback,\n );\n return React.cloneElement(child, { children: childChildren } as unknown);\n });\n};\n\n// Scan through the whole hierachy to count the number of children where `filter` returns true\nconst countMatchingChildren = (\n children: React.ReactNode,\n filter: (child: React.ReactElement) => boolean,\n): number => {\n let counter = 0;\n React.Children.forEach(children, (child) => {\n // equal to (if (child == null || typeof child == 'string'))\n if (!React.isValidElement(child)) return;\n if (!filter(child)) {\n counter += countMatchingChildren(child.props.children, filter);\n } else {\n counter += 1;\n }\n });\n return counter;\n};\n\nfunction _Multiselect(props: MultiselectProps, ref: React.Ref<HTMLDivElement>) {\n const {\n className,\n startIcon,\n placeholder = 'Select one or more Items',\n currentSelection = [],\n toggleRef,\n isLoading = false,\n testId = 'cf-multiselect',\n noMatchesMessage = 'No matches found',\n searchProps = {},\n popoverProps = {},\n children,\n onBlur,\n onClearSelection,\n } = props;\n\n const { listMaxHeight = 180, listRef, onClose } = popoverProps;\n\n const styles = getMultiselectStyles();\n\n const [searchValue, setSearchValue] = useState('');\n const [isOpen, setIsOpen] = useState(false);\n\n const internalListRef = useRef<HTMLUListElement>(null);\n\n const showClearButton =\n currentSelection.length > 1 && typeof onClearSelection === 'function';\n\n const hasSearch =\n typeof props.onSearchValueChange === 'function' ||\n typeof searchProps.onSearchValueChange === 'function';\n\n const handoverSearchProps =\n Object.keys(searchProps).length > 0\n ? searchProps\n : {\n onSearchValueChange: props.onSearchValueChange,\n searchPlaceholder: props.searchPlaceholder,\n searchInputName: props.searchInputName,\n searchInputRef: props.searchInputRef,\n };\n\n const focusList = useCallback(() => {\n // Clearing the search input or selecting an item triggers a rerendering and\n // thereby the client loses the focus on the clicked element. To avoid having\n // the focus on the document body (which breaks `closeOnBlur`), we force it\n // back to the list in the popup.\n internalListRef.current?.focus();\n }, []);\n\n const handleClearSelection = (e: React.MouseEvent<HTMLButtonElement>) => {\n onClearSelection?.();\n e.stopPropagation();\n };\n\n const renderMultiselectLabel = useCallback(() => {\n if (currentSelection.length === 0) {\n return <>{placeholder}</>;\n }\n const leftoverCount = currentSelection.length - 1;\n const currentSelectionClassName = cx(\n styles.currentSelection,\n showClearButton && styles.currentSelectionWithClearButton,\n );\n if (leftoverCount === 0) {\n return (\n <span\n data-test-id=\"cf-multiselect-current-selection\"\n className={currentSelectionClassName}\n >\n {currentSelection[0]}\n </span>\n );\n }\n return (\n <span\n data-test-id=\"cf-multiselect-current-selection\"\n className={currentSelectionClassName}\n >\n {currentSelection[0]}{' '}\n <span className={styles.currentSelectionAddition}>\n and {leftoverCount} more\n </span>\n </span>\n );\n }, [\n currentSelection,\n placeholder,\n showClearButton,\n styles.currentSelection,\n styles.currentSelectionAddition,\n styles.currentSelectionWithClearButton,\n ]);\n\n const optionsLength = useMemo(\n () =>\n countMatchingChildren(\n children,\n (child) => child.type === MultiselectOption,\n ),\n [children],\n );\n\n // clones and enriches the multiselect options\n const enrichOptions = React.useCallback(\n (children: React.ReactNode): React.ReactNode => {\n return iterateOverChildren(\n children,\n (child) => child.type === MultiselectOption,\n (child) => {\n const onSelectItem = (event: React.ChangeEvent<HTMLInputElement>) => {\n focusList();\n child.props?.onSelectItem(event);\n };\n return React.cloneElement(child, {\n searchValue,\n onSelectItem,\n } as Partial<MultiselectOptionProps>);\n },\n );\n },\n [searchValue, focusList],\n );\n\n return (\n <div\n data-test-id={testId}\n className={cx(styles.multiselect, className)}\n ref={ref}\n >\n <Popover\n renderOnlyWhenOpen={false}\n isFullWidth\n {...popoverProps}\n // popoverProps should never overwrite the internal opening logic\n isOpen={isOpen}\n onClose={() => {\n setIsOpen(false);\n if (onClose) {\n onClose();\n }\n }}\n >\n <Flex alignItems=\"center\">\n <Popover.Trigger>\n <Button\n aria-label=\"Toggle Multiselect\"\n ref={toggleRef}\n onClick={() => setIsOpen(!isOpen)}\n startIcon={startIcon}\n endIcon={<ChevronDownIcon />}\n isFullWidth\n className={styles.triggerButton}\n >\n {renderMultiselectLabel()}\n </Button>\n </Popover.Trigger>\n {showClearButton && (\n <div className={styles.clearSelectionButton}>\n <Tooltip\n content=\"Clear selection\"\n showDelay={800}\n placement=\"top\"\n as=\"div\"\n >\n <IconButton\n onClick={handleClearSelection}\n icon={<CloseIcon />}\n aria-label=\"Clear selection\"\n size=\"small\"\n />\n </Tooltip>\n </div>\n )}\n </Flex>\n <Popover.Content\n ref={mergeRefs(listRef, internalListRef)}\n className={cx(\n styles.content(listMaxHeight),\n popoverProps.className,\n styles.container,\n )}\n testId=\"cf-multiselect-container\"\n onBlur={() => onBlur?.()}\n >\n <FocusLock focusOptions={{ preventScroll: true }} returnFocus={true}>\n {hasSearch && (\n <MultiselectSearch\n {...handoverSearchProps}\n setSearchValue={setSearchValue}\n searchValue={searchValue}\n focusList={focusList}\n />\n )}\n {isLoading && <ListItemLoadingState />}\n\n {!isLoading && optionsLength > 0 && (\n <ul className={styles.list} data-test-id=\"cf-multiselect-items\">\n {hasSearch ? enrichOptions(children) : children}\n </ul>\n )}\n\n {!isLoading && optionsLength === 0 && (\n <Subheading className={styles.noMatchesTitle}>\n {noMatchesMessage}\n </Subheading>\n )}\n </FocusLock>\n </Popover.Content>\n </Popover>\n </div>\n );\n}\n\nconst ListItemLoadingState = () => {\n return (\n <SkeletonContainer svgHeight={16}>\n <SkeletonBodyText numberOfLines={1} />\n </SkeletonContainer>\n );\n};\n\n/**\n * The Multiselect is a component that will allow a user to select multiple items.\n * It has an optional\n */\nexport const Multiselect = React.forwardRef(_Multiselect);\n","import React, { useCallback, useRef } from 'react';\nimport { TextInput } from '@contentful/f36-forms';\nimport { CloseIcon, SearchIcon } from '@contentful/f36-icons';\nimport { IconButton } from '@contentful/f36-button';\nimport { getMultiselectStyles } from './Multiselect.styles';\nimport { mergeRefs } from '@contentful/f36-core';\n\nexport interface MultiselectSearchProps {\n /**\n * Function called whenever the search input value changes\n */\n onSearchValueChange?: (\n event: React.ChangeEvent<HTMLInputElement>,\n ) => void | undefined;\n\n /**\n * This is the value will be passed to the `placeholder` prop of the input.\n * @default \"Search\"\n */\n searchPlaceholder?: string;\n\n /**\n * Pass a form name to the search text input\n */\n searchInputName?: string;\n\n /**\n * Use this prop to get a ref to the search input element of the component\n */\n searchInputRef?: React.Ref<HTMLInputElement>;\n\n /**\n * Use this prop to get a ref to the reset search button of the component\n */\n resetSearchRef?: React.Ref<HTMLButtonElement>;\n\n /**\n * State from the parent component\n */\n searchValue?: string;\n\n /**\n * State setter of the parent\n */\n setSearchValue?: React.Dispatch<React.SetStateAction<string>>;\n\n /**\n * List helper function\n */\n focusList?: () => void;\n}\n\nexport const MultiselectSearch = ({\n searchValue,\n setSearchValue,\n onSearchValueChange,\n searchInputName,\n searchInputRef,\n resetSearchRef,\n searchPlaceholder = 'Search',\n focusList,\n}: MultiselectSearchProps) => {\n const styles = getMultiselectStyles();\n const internalSearchInputRef = useRef<HTMLInputElement>(null);\n\n const handleSearchChange = useCallback(\n (event) => {\n setSearchValue(event.target.value);\n onSearchValueChange?.(event);\n },\n [onSearchValueChange, setSearchValue],\n );\n\n const resetSearchInput = useCallback(() => {\n if (!searchValue) return;\n focusList();\n // this looks a bit hacky, but is the official way of externally triggering the onChange handler for an input\n // https://stackoverflow.com/a/46012210/17269164\n const nativeInputValueSetter = Object.getOwnPropertyDescriptor(\n window.HTMLInputElement.prototype,\n 'value',\n ).set;\n nativeInputValueSetter.call(internalSearchInputRef.current, '');\n const forcedEvent = new Event('change', { bubbles: true });\n internalSearchInputRef.current.dispatchEvent(forcedEvent);\n }, [searchValue, focusList]);\n\n return (\n <div className={styles.searchBar}>\n <TextInput\n aria-label=\"Search\"\n type=\"text\"\n value={searchValue}\n className={styles.inputField}\n testId=\"cf-multiselect-search\"\n placeholder={searchPlaceholder}\n onChange={handleSearchChange}\n ref={mergeRefs(searchInputRef, internalSearchInputRef)}\n name={searchInputName}\n size=\"small\"\n />\n <IconButton\n ref={resetSearchRef}\n aria-label={searchValue ? 'Clear search' : 'Search'}\n className={styles.toggleButton}\n variant=\"transparent\"\n icon={\n searchValue ? (\n <CloseIcon variant=\"muted\" />\n ) : (\n <SearchIcon variant=\"muted\" />\n )\n }\n onClick={resetSearchInput}\n isDisabled={!searchValue}\n size=\"small\"\n />\n </div>\n );\n};\n","import React from 'react';\nimport { MultiselectOption, MultiselectOptionProps } from './MultiselectOption';\nimport { getMultiselectStyles } from './Multiselect.styles';\nimport { cx } from 'emotion';\n\nexport interface SelectAllOptionProps\n extends Omit<\n MultiselectOptionProps,\n 'children' | 'value' | 'itemId' | 'label'\n > {\n label?: string;\n itemId?: string;\n}\n\nexport const SelectAllOption = ({\n label,\n itemId = 'SelectAll',\n onSelectItem,\n isChecked = false,\n className,\n ...otherProps\n}: SelectAllOptionProps) => {\n const styles = getMultiselectStyles();\n const displayLabel = label || isChecked ? 'Deselect all' : 'Select all';\n return (\n <MultiselectOption\n value=\"all\"\n label={displayLabel}\n itemId={itemId}\n onSelectItem={onSelectItem}\n isChecked={isChecked}\n className={cx(styles.selectAll, className)}\n {...otherProps}\n />\n );\n};\n","import { Multiselect as OriginalMultiSelect } from './Multiselect';\nimport { HighlightedItem, MultiselectOption } from './MultiselectOption';\nimport { SelectAllOption } from './SelectAllOption';\n\ntype CompoundMultiselect = typeof OriginalMultiSelect & {\n HighlightedItem: typeof HighlightedItem;\n Option: typeof MultiselectOption;\n SelectAll: typeof SelectAllOption;\n};\n\nexport const Multiselect = OriginalMultiSelect as CompoundMultiselect;\nMultiselect.HighlightedItem = HighlightedItem;\nMultiselect.Option = MultiselectOption;\nMultiselect.SelectAll = SelectAllOption;\n"]}
1
+ {"version":3,"sources":["../src/MultiselectOption.tsx","../src/Multiselect.styles.ts","../src/Multiselect.tsx","../src/MultiselectSearch.tsx","../src/SelectAllOption.tsx","../src/CompoundMultiselect.tsx"],"names":["React","Checkbox","Text","css","cx","tokens","getMenuItemStyles","getMultiselectStyles","listMaxHeight","isActive","isDisabled","getStringMatch","MultiselectOption","_a","_b","children","label","value","itemId","onSelectItem","searchValue","isChecked","className","rest","__objRest","styles","__spreadValues","event","HighlightedItem","item","inputValue","before","match","after","useRef","useState","useCallback","useMemo","mergeRefs","Flex","Button","IconButton","ChevronDownIcon","CloseIcon","SkeletonContainer","SkeletonBodyText","Popover","Subheading","Tooltip","FocusLock","TextInput","SearchIcon","MultiselectSearch","setSearchValue","onSearchValueChange","searchInputName","searchInputRef","resetSearchRef","searchPlaceholder","focusList","internalSearchInputRef","handleSearchChange","resetSearchInput","forcedEvent","iterateOverChildren","filter","callback","child","childChildren","countMatchingChildren","counter","_Multiselect","props","ref","startIcon","placeholder","currentSelection","toggleRef","toggleButtonAriaLabel","isLoading","testId","noMatchesMessage","searchProps","popoverProps","onBlur","onClearSelection","clearButtonProps","listRef","onClose","isOpen","setIsOpen","internalListRef","showClearButton","hasSearch","handoverSearchProps","handleClearSelection","e","renderMultiselectLabel","leftoverCount","currentSelectionClassName","optionsLength","enrichOptions","__spreadProps","ListItemLoadingState","Multiselect","SelectAllOption","selectAllOptionLabel","otherProps","displayLabel"],"mappings":"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","sourcesContent":["import React from 'react';\nimport { Checkbox } from '@contentful/f36-forms';\nimport { Text } from '@contentful/f36-typography';\nimport { getMultiselectStyles } from './Multiselect.styles';\nimport { getStringMatch } from '@contentful/f36-utils';\nimport { cx } from 'emotion';\n\ntype LabelOrChildren =\n | {\n /**\n * When using React children it is your own responsibility to highlight\n * the matching part of the item label. Use the `HighlightedItem`\n * component for this.\n */\n children: React.ReactNode;\n label?: never;\n }\n | {\n children?: never;\n label: string;\n };\n\nexport type MultiselectOptionProps = {\n value: string;\n itemId: string;\n searchValue?: string;\n className?: string;\n onSelectItem: (event: React.ChangeEvent<HTMLInputElement>) => void;\n isChecked?: boolean;\n isDisabled?: boolean;\n} & LabelOrChildren;\n\nexport const MultiselectOption = ({\n children,\n label,\n value,\n itemId,\n onSelectItem,\n searchValue,\n isChecked = false,\n isDisabled = false,\n className,\n ...rest\n}: MultiselectOptionProps) => {\n const styles = getMultiselectStyles();\n\n return (\n <li className={cx(styles.option, className)} {...rest}>\n <Checkbox\n id={itemId}\n value={value}\n onChange={(event) => onSelectItem(event)}\n isChecked={isChecked}\n isDisabled={isDisabled}\n className={styles.optionCheck({ isActive: isChecked, isDisabled })}\n >\n <Text\n className={styles.optionText}\n data-test-id={`cf-multiselect-list-item-${itemId}`}\n >\n {typeof label === 'string' ? (\n <HighlightedItem item={label} inputValue={searchValue} />\n ) : (\n children\n )}\n </Text>\n </Checkbox>\n </li>\n );\n};\n\nexport function HighlightedItem({\n item,\n inputValue = '',\n}: {\n item: string;\n inputValue?: string;\n}) {\n const { before, match, after } = getStringMatch(item, inputValue.trim());\n\n if (before.length + match.length + after.length === 0) {\n return <>{item}</>;\n }\n\n return (\n <>\n {before}\n <span data-test-id=\"cf-multiselect-item-match\">{match}</span>\n {after}\n </>\n );\n}\n\nHighlightedItem.displayName = 'HighlightedItem';\n","import { css, cx } from 'emotion';\nimport tokens from '@contentful/f36-tokens';\nimport { getMenuItemStyles } from '@contentful/f36-core';\n\nexport const getMultiselectStyles = () => ({\n multiselect: css({\n position: 'relative',\n width: '100%',\n }),\n triggerButton: css({\n justifyContent: 'space-between',\n }),\n currentSelection: css({\n display: 'inline-block',\n width: '100%',\n whiteSpace: 'nowrap',\n textOverflow: 'ellipsis',\n overflow: 'hidden',\n verticalAlign: 'bottom',\n marginRight: tokens.spacing2Xs,\n }),\n currentSelectionWithClearButton: css({\n paddingRight: '40px',\n }),\n currentSelectionAddition: css({\n color: tokens.gray600,\n }),\n searchBar: css({\n paddingTop: tokens.spacing2Xs,\n position: 'sticky',\n top: '0px',\n zIndex: tokens.zIndexWorkbenchHeader,\n backgroundColor: tokens.colorWhite,\n }),\n inputField: css({\n padding: `6px ${tokens.spacingXl} 10px ${tokens.spacingXs}`,\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n border: 'none',\n borderRadius: '0px',\n borderBottom: `1px solid ${tokens.gray200}`,\n boxShadow: 'none',\n '&:focus, &:active, &:active:hover': {\n boxShadow: 'none',\n borderBottom: `1px solid ${tokens.gray200}`,\n },\n }),\n toggleButton: css({\n position: 'absolute',\n top: '1px',\n right: '1px',\n zIndex: tokens.zIndexDefault,\n padding: tokens.spacing2Xs,\n height: tokens.spacingXl,\n }),\n content: (listMaxHeight: number) =>\n css({\n overflow: 'auto',\n maxHeight: `${listMaxHeight}px`,\n }),\n container: css({}),\n list: css({\n listStyle: 'none',\n padding: `${tokens.spacing2Xs}`,\n margin: 0,\n }),\n groupTitle: css({\n // Magic number to get a height of 32px on the item\n padding: `6px ${tokens.spacingXs}`,\n lineHeight: tokens.lineHeightM,\n }),\n noMatchesTitle: css({\n color: tokens.gray500,\n margin: tokens.spacingM,\n textAlign: 'center',\n }),\n clearSelectionButton: css({\n marginLeft: '-80px',\n }),\n selectAll: css({\n borderBottom: `1px solid ${tokens.gray200}`,\n marginBottom: tokens.spacing2Xs,\n paddingBottom: tokens.spacing2Xs,\n 'label > *': {\n fontWeight: tokens.fontWeightMedium,\n },\n }),\n option: css({\n listStyleType: 'none',\n }),\n optionText: css({\n alignItems: 'center',\n display: 'flex',\n span: {\n color: tokens.gray900,\n fontWeight: tokens.fontWeightDemiBold,\n },\n }),\n optionCheck: ({\n isActive,\n isDisabled,\n }: {\n isActive?: boolean;\n isDisabled?: boolean;\n }) =>\n css({\n label: cx(\n getMenuItemStyles({ isActive, isDisabled }),\n css({\n width: '100%',\n }),\n ),\n }),\n});\n","import React, { useRef, useState, useCallback, useMemo } from 'react';\nimport { cx } from 'emotion';\n\nimport { mergeRefs, type CommonProps, Flex } from '@contentful/f36-core';\nimport { Button, IconButton } from '@contentful/f36-button';\nimport { ChevronDownIcon, CloseIcon } from '@contentful/f36-icons';\n\nimport { SkeletonContainer, SkeletonBodyText } from '@contentful/f36-skeleton';\nimport { Popover, type PopoverProps } from '@contentful/f36-popover';\nimport { Subheading } from '@contentful/f36-typography';\nimport { Tooltip } from '@contentful/f36-tooltip';\n\nimport { getMultiselectStyles } from './Multiselect.styles';\nimport { MultiselectOption, MultiselectOptionProps } from './MultiselectOption';\nimport FocusLock from 'react-focus-lock';\n\nimport type { MultiselectSearchProps as SearchProps } from './MultiselectSearch';\nimport { MultiselectSearch } from './MultiselectSearch';\n\ntype ClearButtonProps = {\n /**\n * Aria label for the clear button\n * @default 'Clear selection'\n */\n ariaLabel?: string;\n\n /**\n * Tooltip for the clear button\n * @default 'Clear selection'\n */\n tooltip?: string;\n};\n\nexport interface MultiselectProps extends CommonProps {\n /** Select Options */\n children?: React.ReactNode;\n\n /**\n * Set a custom icon for the text input\n */\n startIcon?: React.ReactElement;\n\n /**\n * Placeholder shown before selecting any elements. Defaults to 'Select one or more items'\n */\n placeholder?: string;\n\n /**\n * current Selected items, to be shown on the trigger button\n */\n currentSelection?: Array<string>;\n\n /**\n * Sets the list to show its loading state\n * @default false\n */\n isLoading?: boolean;\n\n /**\n * Use this prop to get a ref to the toggle button of the component\n */\n toggleRef?: React.Ref<HTMLButtonElement>;\n\n /**\n * Aria label for the toggle button that opens the list\n * @default 'Toggle Multiselect'\n */\n toggleButtonAriaLabel?: string;\n\n /**\n * Props to pass to the optional search field\n */\n searchProps?: SearchProps;\n\n /**\n * Function called whenever the search input value changes\n * @deprecated Handover this prop in the searchProps subcomponent properties\n */\n onSearchValueChange?: (\n event: React.ChangeEvent<HTMLInputElement>,\n ) => void | undefined;\n\n /**\n * This is the value will be passed to the `placeholder` prop of the input.\n * @deprecated Handover this prop in the searchProps subcomponent properties\n * @default \"Search\"\n */\n searchPlaceholder?: string;\n\n /**\n * A message that will be shown when it is not possible to find any option that matches the search value\n * @default \"No matches\"\n */\n noMatchesMessage?: string;\n\n /**\n * Pass a form name to the search text input\n * @deprecated Handover this prop in the searchProps subcomponent properties\n */\n searchInputName?: string;\n\n /**\n * Use this prop to get a ref to the search input element of the component\n * @deprecated Handover this prop in the searchProps subcomponent properties\n */\n searchInputRef?: React.Ref<HTMLInputElement>;\n\n /**\n * Props to pass to the Popover (Dropdown) component\n */\n popoverProps?: Partial<PopoverProps> & {\n /**\n * It sets the max-height, in pixels, of the list\n * The default value is the height of 5 single line items\n * @default 180\n */\n listMaxHeight?: number;\n\n /**\n * Use this prop to get a ref to the list of items of the component\n */\n listRef?: React.Ref<HTMLUListElement>;\n } & Pick<CommonProps, 'className'>;\n\n /**\n * Function called when the popover loses its focus.\n */\n onBlur?: () => void;\n\n /**\n * Function called when the clear all button is clicked\n * If no function is provided the clear button is not shown\n */\n onClearSelection?: () => void;\n\n /**\n * Clear Button Props used for localization\n * @default { ariaLabel: 'Clear selection', tooltip: 'Clear selection' }\n */\n clearButtonProps?: ClearButtonProps;\n}\n\n// Scan through the whole hierachy until `filter` returns true and apply `transform`\n// Inspired from https://stackoverflow.com/a/70676868/17269164\nconst iterateOverChildren = (\n children: React.ReactNode,\n filter: (child: React.ReactElement) => boolean,\n callback: (child: React.ReactElement) => React.ReactElement | void,\n): React.ReactNode => {\n return React.Children.map(children, (child) => {\n // equal to (if (child == null || typeof child == 'string'))\n if (!React.isValidElement(child)) return child;\n if (filter(child)) {\n return callback(child);\n }\n const childChildren = iterateOverChildren(\n child.props.children,\n filter,\n callback,\n );\n return React.cloneElement(child, { children: childChildren } as unknown);\n });\n};\n\n// Scan through the whole hierachy to count the number of children where `filter` returns true\nconst countMatchingChildren = (\n children: React.ReactNode,\n filter: (child: React.ReactElement) => boolean,\n): number => {\n let counter = 0;\n React.Children.forEach(children, (child) => {\n // equal to (if (child == null || typeof child == 'string'))\n if (!React.isValidElement(child)) return;\n if (!filter(child)) {\n counter += countMatchingChildren(child.props.children, filter);\n } else {\n counter += 1;\n }\n });\n return counter;\n};\n\nfunction _Multiselect(props: MultiselectProps, ref: React.Ref<HTMLDivElement>) {\n const {\n className,\n startIcon,\n placeholder = 'Select one or more Items',\n currentSelection = [],\n toggleRef,\n toggleButtonAriaLabel = 'Toggle Multiselect',\n isLoading = false,\n testId = 'cf-multiselect',\n noMatchesMessage = 'No matches found',\n searchProps = {},\n popoverProps = {},\n children,\n onBlur,\n onClearSelection,\n clearButtonProps = {\n tooltip: 'Clear selection',\n ariaLabel: 'Clear selection',\n },\n } = props;\n\n const { listMaxHeight = 180, listRef, onClose } = popoverProps;\n\n const styles = getMultiselectStyles();\n\n const [searchValue, setSearchValue] = useState('');\n const [isOpen, setIsOpen] = useState(false);\n\n const internalListRef = useRef<HTMLUListElement>(null);\n\n const showClearButton =\n currentSelection.length > 1 && typeof onClearSelection === 'function';\n\n const hasSearch =\n typeof props.onSearchValueChange === 'function' ||\n typeof searchProps.onSearchValueChange === 'function';\n\n const handoverSearchProps =\n Object.keys(searchProps).length > 0\n ? searchProps\n : {\n onSearchValueChange: props.onSearchValueChange,\n searchPlaceholder: props.searchPlaceholder,\n searchInputName: props.searchInputName,\n searchInputRef: props.searchInputRef,\n };\n\n const focusList = useCallback(() => {\n // Clearing the search input or selecting an item triggers a rerendering and\n // thereby the client loses the focus on the clicked element. To avoid having\n // the focus on the document body (which breaks `closeOnBlur`), we force it\n // back to the list in the popup.\n internalListRef.current?.focus();\n }, []);\n\n const handleClearSelection = (e: React.MouseEvent<HTMLButtonElement>) => {\n onClearSelection?.();\n e.stopPropagation();\n };\n\n const renderMultiselectLabel = useCallback(() => {\n if (currentSelection.length === 0) {\n return <>{placeholder}</>;\n }\n const leftoverCount = currentSelection.length - 1;\n const currentSelectionClassName = cx(\n styles.currentSelection,\n showClearButton && styles.currentSelectionWithClearButton,\n );\n if (leftoverCount === 0) {\n return (\n <span\n data-test-id=\"cf-multiselect-current-selection\"\n className={currentSelectionClassName}\n >\n {currentSelection[0]}\n </span>\n );\n }\n return (\n <span\n data-test-id=\"cf-multiselect-current-selection\"\n className={currentSelectionClassName}\n >\n {currentSelection[0]}{' '}\n <span className={styles.currentSelectionAddition}>\n and {leftoverCount} more\n </span>\n </span>\n );\n }, [\n currentSelection,\n placeholder,\n showClearButton,\n styles.currentSelection,\n styles.currentSelectionAddition,\n styles.currentSelectionWithClearButton,\n ]);\n\n const optionsLength = useMemo(\n () =>\n countMatchingChildren(\n children,\n (child) => child.type === MultiselectOption,\n ),\n [children],\n );\n\n // clones and enriches the multiselect options\n const enrichOptions = React.useCallback(\n (children: React.ReactNode): React.ReactNode => {\n return iterateOverChildren(\n children,\n (child) => child.type === MultiselectOption,\n (child) => {\n const onSelectItem = (event: React.ChangeEvent<HTMLInputElement>) => {\n focusList();\n child.props?.onSelectItem(event);\n };\n return React.cloneElement(child, {\n searchValue,\n onSelectItem,\n } as Partial<MultiselectOptionProps>);\n },\n );\n },\n [searchValue, focusList],\n );\n\n return (\n <div\n data-test-id={testId}\n className={cx(styles.multiselect, className)}\n ref={ref}\n >\n <Popover\n renderOnlyWhenOpen={false}\n isFullWidth\n {...popoverProps}\n // popoverProps should never overwrite the internal opening logic\n isOpen={isOpen}\n onClose={() => {\n setIsOpen(false);\n if (onClose) {\n onClose();\n }\n }}\n >\n <Flex alignItems=\"center\">\n <Popover.Trigger>\n <Button\n aria-label={toggleButtonAriaLabel}\n ref={toggleRef}\n onClick={() => setIsOpen(!isOpen)}\n startIcon={startIcon}\n endIcon={<ChevronDownIcon />}\n isFullWidth\n className={styles.triggerButton}\n >\n {renderMultiselectLabel()}\n </Button>\n </Popover.Trigger>\n {showClearButton && (\n <div className={styles.clearSelectionButton}>\n <Tooltip\n content={\n clearButtonProps.tooltip\n ? clearButtonProps.tooltip\n : 'Clear selection'\n }\n showDelay={800}\n placement=\"top\"\n as=\"div\"\n >\n <IconButton\n onClick={handleClearSelection}\n icon={<CloseIcon />}\n aria-label={\n clearButtonProps.ariaLabel\n ? clearButtonProps.ariaLabel\n : 'Clear selection'\n }\n size=\"small\"\n />\n </Tooltip>\n </div>\n )}\n </Flex>\n <Popover.Content\n ref={mergeRefs(listRef, internalListRef)}\n className={cx(\n styles.content(listMaxHeight),\n popoverProps.className,\n styles.container,\n )}\n testId=\"cf-multiselect-container\"\n onBlur={() => onBlur?.()}\n >\n <FocusLock focusOptions={{ preventScroll: true }} returnFocus={true}>\n {hasSearch && (\n <MultiselectSearch\n {...handoverSearchProps}\n setSearchValue={setSearchValue}\n searchValue={searchValue}\n focusList={focusList}\n />\n )}\n {isLoading && <ListItemLoadingState />}\n\n {!isLoading && optionsLength > 0 && (\n <ul className={styles.list} data-test-id=\"cf-multiselect-items\">\n {hasSearch ? enrichOptions(children) : children}\n </ul>\n )}\n\n {!isLoading && optionsLength === 0 && (\n <Subheading className={styles.noMatchesTitle}>\n {noMatchesMessage}\n </Subheading>\n )}\n </FocusLock>\n </Popover.Content>\n </Popover>\n </div>\n );\n}\n\nconst ListItemLoadingState = () => {\n return (\n <SkeletonContainer svgHeight={16}>\n <SkeletonBodyText numberOfLines={1} />\n </SkeletonContainer>\n );\n};\n\n/**\n * The Multiselect is a component that will allow a user to select multiple items.\n * It has an optional\n */\nexport const Multiselect = React.forwardRef(_Multiselect);\n","import React, { useCallback, useRef } from 'react';\nimport { TextInput } from '@contentful/f36-forms';\nimport { CloseIcon, SearchIcon } from '@contentful/f36-icons';\nimport { IconButton } from '@contentful/f36-button';\nimport { getMultiselectStyles } from './Multiselect.styles';\nimport { mergeRefs } from '@contentful/f36-core';\n\nexport interface MultiselectSearchProps {\n /**\n * Function called whenever the search input value changes\n */\n onSearchValueChange?: (\n event: React.ChangeEvent<HTMLInputElement>,\n ) => void | undefined;\n\n /**\n * This is the value will be passed to the `placeholder` prop of the input.\n * @default \"Search\"\n */\n searchPlaceholder?: string;\n\n /**\n * Pass a form name to the search text input\n */\n searchInputName?: string;\n\n /**\n * Use this prop to get a ref to the search input element of the component\n */\n searchInputRef?: React.Ref<HTMLInputElement>;\n\n /**\n * Use this prop to get a ref to the reset search button of the component\n */\n resetSearchRef?: React.Ref<HTMLButtonElement>;\n\n /**\n * State from the parent component\n */\n searchValue?: string;\n\n /**\n * State setter of the parent\n */\n setSearchValue?: React.Dispatch<React.SetStateAction<string>>;\n\n /**\n * List helper function\n */\n focusList?: () => void;\n}\n\nexport const MultiselectSearch = ({\n searchValue,\n setSearchValue,\n onSearchValueChange,\n searchInputName,\n searchInputRef,\n resetSearchRef,\n searchPlaceholder = 'Search',\n focusList,\n}: MultiselectSearchProps) => {\n const styles = getMultiselectStyles();\n const internalSearchInputRef = useRef<HTMLInputElement>(null);\n\n const handleSearchChange = useCallback(\n (event) => {\n setSearchValue(event.target.value);\n onSearchValueChange?.(event);\n },\n [onSearchValueChange, setSearchValue],\n );\n\n const resetSearchInput = useCallback(() => {\n if (!searchValue) return;\n focusList();\n // this looks a bit hacky, but is the official way of externally triggering the onChange handler for an input\n // https://stackoverflow.com/a/46012210/17269164\n const nativeInputValueSetter = Object.getOwnPropertyDescriptor(\n window.HTMLInputElement.prototype,\n 'value',\n ).set;\n nativeInputValueSetter.call(internalSearchInputRef.current, '');\n const forcedEvent = new Event('change', { bubbles: true });\n internalSearchInputRef.current.dispatchEvent(forcedEvent);\n }, [searchValue, focusList]);\n\n return (\n <div className={styles.searchBar}>\n <TextInput\n aria-label=\"Search\"\n type=\"text\"\n value={searchValue}\n className={styles.inputField}\n testId=\"cf-multiselect-search\"\n placeholder={searchPlaceholder}\n onChange={handleSearchChange}\n ref={mergeRefs(searchInputRef, internalSearchInputRef)}\n name={searchInputName}\n size=\"small\"\n />\n <IconButton\n ref={resetSearchRef}\n aria-label={searchValue ? 'Clear search' : 'Search'}\n className={styles.toggleButton}\n variant=\"transparent\"\n icon={\n searchValue ? (\n <CloseIcon variant=\"muted\" />\n ) : (\n <SearchIcon variant=\"muted\" />\n )\n }\n onClick={resetSearchInput}\n isDisabled={!searchValue}\n size=\"small\"\n />\n </div>\n );\n};\n","import React from 'react';\nimport { MultiselectOption, MultiselectOptionProps } from './MultiselectOption';\nimport { getMultiselectStyles } from './Multiselect.styles';\nimport { cx } from 'emotion';\n\n/**\n * Labels for the select all option\n */\ntype SelectAllOptionLabel = {\n /**\n * Label for the select all option when it is checked\n * @default 'Deselect all'\n */\n checked: string;\n\n /**\n * Label for the select all option when it is unchecked\n * @default 'Select all'\n */\n unchecked: string;\n};\nexport interface SelectAllOptionProps\n extends Omit<\n MultiselectOptionProps,\n 'children' | 'value' | 'itemId' | 'label'\n > {\n label?: string;\n itemId?: string;\n selectAllOptionLabel?: SelectAllOptionLabel;\n}\n\nexport const SelectAllOption = ({\n label,\n itemId = 'SelectAll',\n onSelectItem,\n isChecked = false,\n selectAllOptionLabel = {\n checked: 'Deselect all',\n unchecked: 'Select all',\n },\n className,\n ...otherProps\n}: SelectAllOptionProps) => {\n const styles = getMultiselectStyles();\n const displayLabel =\n label || isChecked\n ? selectAllOptionLabel.checked\n : selectAllOptionLabel.unchecked;\n return (\n <MultiselectOption\n value=\"all\"\n label={displayLabel}\n itemId={itemId}\n onSelectItem={onSelectItem}\n isChecked={isChecked}\n className={cx(styles.selectAll, className)}\n {...otherProps}\n />\n );\n};\n","import { Multiselect as OriginalMultiSelect } from './Multiselect';\nimport { HighlightedItem, MultiselectOption } from './MultiselectOption';\nimport { SelectAllOption } from './SelectAllOption';\n\ntype CompoundMultiselect = typeof OriginalMultiSelect & {\n HighlightedItem: typeof HighlightedItem;\n Option: typeof MultiselectOption;\n SelectAll: typeof SelectAllOption;\n};\n\nexport const Multiselect = OriginalMultiSelect as CompoundMultiselect;\nMultiselect.HighlightedItem = HighlightedItem;\nMultiselect.Option = MultiselectOption;\nMultiselect.SelectAll = SelectAllOption;\n"]}
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@contentful/f36-multiselect",
3
- "version": "4.26.0",
3
+ "version": "4.26.1",
4
4
  "description": "Forma 36: Multiselect Component",
5
5
  "scripts": {
6
6
  "build": "tsup"
7
7
  },
8
8
  "dependencies": {
9
- "@babel/runtime": "^7.21.0",
9
+ "@babel/runtime": "^7.27.1",
10
10
  "@contentful/f36-button": "^4.78.0",
11
11
  "@contentful/f36-core": "^4.78.0",
12
12
  "@contentful/f36-forms": "^4.78.0",