@contentful/f36-multiselect 4.19.1-0 → 4.19.1-2

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/index.js CHANGED
@@ -6,7 +6,7 @@ var e = require('react');
6
6
  var f36Forms = require('@contentful/f36-forms');
7
7
  var f36Typography = require('@contentful/f36-typography');
8
8
  var emotion = require('emotion');
9
- var i = require('@contentful/f36-tokens');
9
+ var t = require('@contentful/f36-tokens');
10
10
  var f36Utils = require('@contentful/f36-utils');
11
11
  var f36Core = require('@contentful/f36-core');
12
12
  var f36Button = require('@contentful/f36-button');
@@ -17,10 +17,10 @@ var f36Popover = require('@contentful/f36-popover');
17
17
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
18
18
 
19
19
  var e__default = /*#__PURE__*/_interopDefaultLegacy(e);
20
- var i__default = /*#__PURE__*/_interopDefaultLegacy(i);
20
+ var t__default = /*#__PURE__*/_interopDefaultLegacy(t);
21
21
 
22
- var J=Object.defineProperty;var M=Object.getOwnPropertySymbols;var L=Object.prototype.hasOwnProperty,N=Object.prototype.propertyIsEnumerable;var H=(t,n,o)=>n in t?J(t,n,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[n]=o,v=(t,n)=>{for(var o in n||(n={}))L.call(n,o)&&H(t,o,n[o]);if(M)for(var o of M(n))N.call(n,o)&&H(t,o,n[o]);return t};var B=(t,n)=>{var o={};for(var r in t)L.call(t,r)&&n.indexOf(r)<0&&(o[r]=t[r]);if(t!=null&&M)for(var r of M(t))n.indexOf(r)<0&&N.call(t,r)&&(o[r]=t[r]);return o};var b=()=>({multiselect:emotion.css({position:"relative",width:"100%"}),currentSelection:emotion.css({width:"50%",whiteSpace:"nowrap",textOverflow:"ellipsis",overflow:"hidden",verticalAlign:"bottom",marginRight:i__default["default"].spacing2Xs}),inputField:emotion.css({paddingRight:i__default["default"].spacingXl,textOverflow:"ellipsis",whiteSpace:"nowrap"}),toggleButton:emotion.css({position:"absolute",top:"1px",right:"1px",zIndex:i__default["default"].zIndexDefault,padding:i__default["default"].spacing2Xs,height:i__default["default"].spacingXl}),content:t=>emotion.css({overflow:"auto",maxHeight:`${t}px`}),list:emotion.css({listStyle:"none",padding:`${i__default["default"].spacingXs} 0`,margin:0}),groupTitle:emotion.css({padding:`${i__default["default"].spacingXs} ${i__default["default"].spacingM}`,lineHeight:i__default["default"].lineHeightM}),noMatchesTitle:emotion.css({color:i__default["default"].gray500,margin:i__default["default"].spacingM}),item:emotion.css({padding:`${i__default["default"].spacingXs} ${i__default["default"].spacingM}`,wordBreak:"break-word",whiteSpace:"break-spaces",hyphens:"auto",display:"flex",flexDirection:"row",alignItems:"center","&:focus, &:hover":{backgroundColor:i__default["default"].gray100},"&:active":{backgroundColor:i__default["default"].gray200},"&:focus":{boxShadow:i__default["default"].glowPrimary},"&:focus:not(:focus-visible)":{boxShadow:"unset"},"&:focus-visible":{boxShadow:i__default["default"].glowPrimary}}),disabled:emotion.css({opacity:.5,cursor:"not-allowed"})});var C=w=>{var f=w,{label:t,value:n,itemId:o,onSelectItem:r,searchValue:m,isChecked:u=!1,isDisabled:c=!1}=f,S=B(f,["label","value","itemId","onSelectItem","searchValue","isChecked","isDisabled"]);let h=b();return e__default["default"].createElement("li",v({},S),e__default["default"].createElement("label",{htmlFor:o,className:emotion.cx(h.item,c&&h.disabled)},e__default["default"].createElement(f36Forms.Checkbox,{id:o,value:n,onChange:d=>r(d),isChecked:u,isDisabled:c}),e__default["default"].createElement(f36Typography.Text,{"data-test-id":`cf-multiselect-list-item-${o}`},e__default["default"].createElement(V,{item:t,inputValue:m}))))};function V({item:t,inputValue:n=""}){let{before:o,match:r,after:m}=f36Utils.getStringMatch(t,n);return e__default["default"].createElement(e__default["default"].Fragment,null,o,e__default["default"].createElement("b",{"data-test-id":"cf-multiselect-item-match"},r),m)}V.displayName="HighlightedItem";function me(t,n){let{className:o,startIcon:r,placeholder:m="Select one or more Items",currentSelection:u=[],onSearchValueChange:c,searchPlaceholder:S="Search",searchInputRef:w,noMatchesMessage:f="No matches found",toggleRef:h,isLoading:d=!1,testId:F="cf-multiselect",popoverProps:P={},children:x}=t,{listMaxHeight:A=180,listRef:j}=P,a=b(),[g,O]=e.useState(""),[k,T]=e.useState(!1),y=e.useRef(null),U=typeof c=="function",W=e.useCallback(l=>{O(l.target.value),c==null||c(l);},[c,O]),_=()=>{Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value").set.call(y.current,"");let G=new Event("change",{bubbles:!0});y.current.dispatchEvent(G);},q=e.useCallback(()=>{if(u.length===0)return e__default["default"].createElement(e__default["default"].Fragment,null,m);let l=u.length-1;return l===0?e__default["default"].createElement("span",{"data-test-id":"cf-multiselect-current-selection",className:a.currentSelection},u[0]):e__default["default"].createElement("span",{"data-test-id":"cf-multiselect-current-selection",className:a.currentSelection},u[0]," and ",l," more"," ")},[u,m,a.currentSelection]),E=e.useMemo(()=>e__default["default"].Children.count(x),[x]);return e__default["default"].createElement("div",{"data-test-id":F,className:emotion.cx(a.multiselect,o),ref:n},e__default["default"].createElement(f36Popover.Popover,v({isOpen:k,onClose:()=>T(!1),renderOnlyWhenOpen:!1},P),e__default["default"].createElement(f36Popover.Popover.Trigger,null,e__default["default"].createElement(f36Button.Button,{"aria-label":"Toggle Multiselect",ref:h,onClick:()=>T(!k),startIcon:r,endIcon:e__default["default"].createElement(f36Icons.ChevronDownIcon,null)},q())),e__default["default"].createElement(f36Popover.Popover.Content,{ref:j,className:a.content(A),testId:"cf-multiselect-container"},e__default["default"].createElement(e__default["default"].Fragment,null,U&&e__default["default"].createElement(e__default["default"].Fragment,null,e__default["default"].createElement(f36Forms.TextInput,{"aria-label":"Search",type:"text",value:g,className:a.inputField,testId:"cf-multiselect-search",placeholder:S,onChange:W,ref:f36Core.mergeRefs(w,y)}),e__default["default"].createElement(f36Button.IconButton,{"aria-label":g?"Clear search":"Search",className:a.toggleButton,variant:"transparent",icon:g?e__default["default"].createElement(f36Icons.CloseIcon,{variant:"muted"}):e__default["default"].createElement(f36Icons.SearchIcon,{variant:"muted"}),onClick:()=>{g&&_();},isDisabled:!g,size:"small"})),d&&e__default["default"].createElement(ge,null),!d&&E>0&&e__default["default"].createElement("ul",{className:a.list,"data-test-id":"cf-multiselect-items"},e__default["default"].Children.map(x,l=>e__default["default"].isValidElement(l)?e__default["default"].cloneElement(l,{searchValue:g}):l)),!d&&E===0&&e__default["default"].createElement(f36Typography.Subheading,{className:a.noMatchesTitle},f)))))}var ge=()=>e__default["default"].createElement(f36Skeleton.SkeletonContainer,{svgHeight:16},e__default["default"].createElement(f36Skeleton.SkeletonBodyText,{numberOfLines:1})),$=e__default["default"].forwardRef(me);var z=$;z.Option=C;
22
+ var v=()=>({multiselect:emotion.css({position:"relative",width:"100%"}),currentSelection:emotion.css({width:"50%",whiteSpace:"nowrap",textOverflow:"ellipsis",overflow:"hidden",verticalAlign:"bottom",marginRight:t__default["default"].spacing2Xs}),inputField:emotion.css({paddingRight:t__default["default"].spacingXl,textOverflow:"ellipsis",whiteSpace:"nowrap"}),toggleButton:emotion.css({position:"absolute",top:"1px",right:"1px",zIndex:t__default["default"].zIndexDefault,padding:t__default["default"].spacing2Xs,height:t__default["default"].spacingXl}),content:s=>emotion.css({overflow:"auto",maxHeight:`${s}px`}),list:emotion.css({listStyle:"none",padding:`${t__default["default"].spacingXs} 0`,margin:0}),groupTitle:emotion.css({padding:`${t__default["default"].spacingXs} ${t__default["default"].spacingM}`,lineHeight:t__default["default"].lineHeightM}),noMatchesTitle:emotion.css({color:t__default["default"].gray500,margin:t__default["default"].spacingM}),item:emotion.css({padding:`${t__default["default"].spacingXs} ${t__default["default"].spacingM}`,wordBreak:"break-word",whiteSpace:"break-spaces",hyphens:"auto",display:"flex",flexDirection:"row",alignItems:"center","&:focus, &:hover":{backgroundColor:t__default["default"].gray100},"&:active":{backgroundColor:t__default["default"].gray200},"&:focus":{boxShadow:t__default["default"].glowPrimary},"&:focus:not(:focus-visible)":{boxShadow:"unset"},"&:focus-visible":{boxShadow:t__default["default"].glowPrimary}}),disabled:emotion.css({opacity:.5,cursor:"not-allowed"})});var d=({label:s,value:g,itemId:a,onSelectItem:f,searchValue:u,isChecked:c=!1,isDisabled:m=!1,...S})=>{let h=v();return e__default["default"].createElement("li",{...S},e__default["default"].createElement("label",{htmlFor:a,className:emotion.cx(h.item,m&&h.disabled)},e__default["default"].createElement(f36Forms.Checkbox,{id:a,value:g,onChange:b=>f(b),isChecked:c,isDisabled:m}),e__default["default"].createElement(f36Typography.Text,{"data-test-id":`cf-multiselect-list-item-${a}`},e__default["default"].createElement(E,{item:s,inputValue:u}))))};function E({item:s,inputValue:g=""}){let{before:a,match:f,after:u}=f36Utils.getStringMatch(s,g);return e__default["default"].createElement(e__default["default"].Fragment,null,a,e__default["default"].createElement("b",{"data-test-id":"cf-multiselect-item-match"},f),u)}E.displayName="HighlightedItem";function le(s,g){let{className:a,startIcon:f,placeholder:u="Select one or more Items",currentSelection:c=[],onSearchValueChange:m,searchPlaceholder:S="Search",searchInputRef:h,noMatchesMessage:b="No matches found",toggleRef:D,isLoading:x=!1,testId:X="cf-multiselect",popoverProps:I={},children:M}=s,{listMaxHeight:$=180,listRef:F}=I,n=v(),[p,w]=e.useState(""),[O,P]=e.useState(!1),y=e.useRef(null),k=typeof m=="function",z=e.useCallback(i=>{w(i.target.value),m?.(i);},[m,w]),A=()=>{Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value").set.call(y.current,"");let r=new Event("change",{bubbles:!0});y.current.dispatchEvent(r);},j=e.useCallback(()=>{if(c.length===0)return e__default["default"].createElement(e__default["default"].Fragment,null,u);let i=c.length-1;return i===0?e__default["default"].createElement("span",{"data-test-id":"cf-multiselect-current-selection",className:n.currentSelection},c[0]):e__default["default"].createElement("span",{"data-test-id":"cf-multiselect-current-selection",className:n.currentSelection},c[0]," and ",i," more"," ")},[c,u,n.currentSelection]),N=e.useMemo(()=>e__default["default"].Children.count(M),[M]),T=e__default["default"].useCallback(i=>e__default["default"].Children.map(i,r=>e__default["default"].isValidElement(r)?r.type===e__default["default"].Fragment?T(r.props.children):r.type===d?e__default["default"].cloneElement(r,{searchValue:p}):r:r),[p]);return e__default["default"].createElement("div",{"data-test-id":X,className:emotion.cx(n.multiselect,a),ref:g},e__default["default"].createElement(f36Popover.Popover,{isOpen:O,onClose:()=>P(!1),renderOnlyWhenOpen:!1,...I},e__default["default"].createElement(f36Popover.Popover.Trigger,null,e__default["default"].createElement(f36Button.Button,{"aria-label":"Toggle Multiselect",ref:D,onClick:()=>P(!O),startIcon:f,endIcon:e__default["default"].createElement(f36Icons.ChevronDownIcon,null)},j())),e__default["default"].createElement(f36Popover.Popover.Content,{ref:F,className:n.content($),testId:"cf-multiselect-container"},e__default["default"].createElement(e__default["default"].Fragment,null,k&&e__default["default"].createElement(e__default["default"].Fragment,null,e__default["default"].createElement(f36Forms.TextInput,{"aria-label":"Search",type:"text",value:p,className:n.inputField,testId:"cf-multiselect-search",placeholder:S,onChange:z,ref:f36Core.mergeRefs(h,y)}),e__default["default"].createElement(f36Button.IconButton,{"aria-label":p?"Clear search":"Search",className:n.toggleButton,variant:"transparent",icon:p?e__default["default"].createElement(f36Icons.CloseIcon,{variant:"muted"}):e__default["default"].createElement(f36Icons.SearchIcon,{variant:"muted"}),onClick:()=>{p&&A();},isDisabled:!p,size:"small"})),x&&e__default["default"].createElement(se,null),!x&&N>0&&e__default["default"].createElement("ul",{className:n.list,"data-test-id":"cf-multiselect-items"},k?T(M):M),!x&&N===0&&e__default["default"].createElement(f36Typography.Subheading,{className:n.noMatchesTitle},b)))))}var se=()=>e__default["default"].createElement(f36Skeleton.SkeletonContainer,{svgHeight:16},e__default["default"].createElement(f36Skeleton.SkeletonBodyText,{numberOfLines:1})),V=e__default["default"].forwardRef(le);var B=V;B.Option=d;
23
23
 
24
- exports.Multiselect = z;
25
- exports.MultiselectOption = C;
24
+ exports.Multiselect = B;
25
+ exports.MultiselectOption = d;
26
26
  //# 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/CompoundMultiselect.tsx"],"names":["React","Checkbox","Text","css","tokens","getMultiselectStyles","listMaxHeight","getStringMatch","cx","MultiselectOption","_a","_b","label","value","itemId","onSelectItem","searchValue","isChecked","isDisabled","rest","__objRest","styles","__spreadValues","event","HighlightedItem","item","inputValue","before","match","after","useRef","useState","useCallback","useMemo","mergeRefs","Button","IconButton","TextInput","CloseIcon","ChevronDownIcon","SearchIcon","SkeletonContainer","SkeletonBodyText","Popover","Subheading","_Multiselect","props","ref","className","startIcon","placeholder","currentSelection","onSearchValueChange","searchPlaceholder","searchInputRef","noMatchesMessage","toggleRef","isLoading","testId","popoverProps","children","listRef","setSearchValue","isOpen","setIsOpen","internalSearchInputRef","hasSearch","handleSearchChange","resetSearch","forcedEvent","renderMultiselectLabel","leftoverCount","childrenLength","ListItemLoadingState","child","Multiselect"],"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\nexport interface MulitselectOptionProps {\n label: string;\n value: string;\n itemId: string;\n searchValue?: string;\n onSelectItem: (event: React.ChangeEvent) => void;\n isChecked?: boolean;\n isDisabled?: boolean;\n}\n\nexport const MultiselectOption = ({\n label,\n value,\n itemId,\n onSelectItem,\n searchValue,\n isChecked = false,\n isDisabled = false,\n ...rest\n}: MulitselectOptionProps) => {\n const styles = getMultiselectStyles();\n\n return (\n <li {...rest}>\n <label\n htmlFor={itemId}\n className={cx(styles.item, isDisabled && styles.disabled)}\n >\n <Checkbox\n id={itemId}\n value={value}\n onChange={(event) => onSelectItem(event)}\n isChecked={isChecked}\n isDisabled={isDisabled}\n />\n <Text data-test-id={`cf-multiselect-list-item-${itemId}`}>\n <HighlightedItem item={label} inputValue={searchValue} />\n </Text>\n </label>\n </li>\n );\n};\n\nfunction HighlightedItem({\n item,\n inputValue = '',\n}: {\n item: string;\n inputValue?: string;\n}) {\n const { before, match, after } = getStringMatch(item, inputValue);\n return (\n <>\n {before}\n <b data-test-id=\"cf-multiselect-item-match\">{match}</b>\n {after}\n </>\n );\n}\n\nHighlightedItem.displayName = 'HighlightedItem';\n","import { css } from 'emotion';\nimport tokens from '@contentful/f36-tokens';\n\nexport const getMultiselectStyles = () => ({\n multiselect: css({\n position: 'relative',\n width: '100%',\n }),\n currentSelection: css({\n width: '50%',\n whiteSpace: 'nowrap',\n textOverflow: 'ellipsis',\n overflow: 'hidden',\n verticalAlign: 'bottom',\n marginRight: tokens.spacing2Xs,\n }),\n inputField: css({\n paddingRight: tokens.spacingXl,\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\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 list: css({\n listStyle: 'none',\n padding: `${tokens.spacingXs} 0`,\n margin: 0,\n }),\n groupTitle: css({\n padding: `${tokens.spacingXs} ${tokens.spacingM}`,\n lineHeight: tokens.lineHeightM,\n }),\n noMatchesTitle: css({\n color: tokens.gray500,\n margin: tokens.spacingM,\n }),\n item: css({\n padding: `${tokens.spacingXs} ${tokens.spacingM}`,\n wordBreak: 'break-word',\n whiteSpace: 'break-spaces',\n hyphens: 'auto',\n display: 'flex',\n flexDirection: 'row',\n alignItems: 'center',\n '&:focus, &:hover': {\n backgroundColor: tokens.gray100,\n },\n '&:active': {\n backgroundColor: tokens.gray200,\n },\n '&:focus': {\n boxShadow: tokens.glowPrimary,\n },\n '&:focus:not(:focus-visible)': {\n boxShadow: 'unset',\n },\n '&:focus-visible': {\n boxShadow: tokens.glowPrimary,\n },\n }),\n disabled: css({\n opacity: 0.5,\n cursor: 'not-allowed',\n }),\n});\n","import React, { useRef, useState, useCallback, useMemo } from 'react';\nimport { cx } from 'emotion';\n\nimport { mergeRefs, type CommonProps } from '@contentful/f36-core';\nimport { Button, IconButton } from '@contentful/f36-button';\nimport { TextInput } from '@contentful/f36-forms';\nimport { CloseIcon, ChevronDownIcon, SearchIcon } from '@contentful/f36-icons';\nimport { SkeletonContainer, SkeletonBodyText } from '@contentful/f36-skeleton';\nimport { Popover, type PopoverProps } from '@contentful/f36-popover';\nimport { Subheading } from '@contentful/f36-typography';\n\nimport { getMultiselectStyles } from './Multiselect.styles';\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 * Function called whenever the search input value changes\n */\n onSearchValueChange?: (event: React.ChangeEvent) => 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 * A message that will be shown when it is not possible to find any option that matches the input value\n * @default \"No matches\"\n */\n noMatchesMessage?: string;\n\n /**\n * Use this prop to get a ref to the input element of the component\n */\n searchInputRef?: React.Ref<HTMLInputElement>;\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 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 };\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 onSearchValueChange,\n searchPlaceholder = 'Search',\n searchInputRef,\n noMatchesMessage = 'No matches found',\n toggleRef,\n isLoading = false,\n testId = 'cf-multiselect',\n popoverProps = {},\n children,\n } = props;\n\n const { listMaxHeight = 180, listRef } = popoverProps;\n\n const styles = getMultiselectStyles();\n\n const [searchValue, setSearchValue] = useState('');\n const [isOpen, setIsOpen] = useState(false);\n\n const internalSearchInputRef = useRef(null);\n\n const hasSearch = typeof onSearchValueChange === 'function';\n\n const handleSearchChange = useCallback(\n (event) => {\n setSearchValue(event.target.value);\n onSearchValueChange?.(event);\n },\n [onSearchValueChange, setSearchValue],\n );\n\n const resetSearch = () => {\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\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 };\n\n const renderMultiselectLabel = useCallback(() => {\n if (currentSelection.length === 0) {\n return <>{placeholder}</>;\n }\n const leftoverCount = currentSelection.length - 1;\n if (leftoverCount === 0) {\n return (\n <span\n data-test-id=\"cf-multiselect-current-selection\"\n className={styles.currentSelection}\n >\n {currentSelection[0]}\n </span>\n );\n }\n return (\n <span\n data-test-id=\"cf-multiselect-current-selection\"\n className={styles.currentSelection}\n >\n {currentSelection[0]} and {leftoverCount} more{' '}\n </span>\n );\n }, [currentSelection, placeholder, styles.currentSelection]);\n\n const childrenLength = useMemo(\n () => React.Children.count(children),\n [children],\n );\n\n return (\n <div\n data-test-id={testId}\n className={cx(styles.multiselect, className)}\n ref={ref}\n >\n <Popover\n isOpen={isOpen}\n onClose={() => setIsOpen(false)}\n renderOnlyWhenOpen={false}\n {...popoverProps}\n >\n <Popover.Trigger>\n <Button\n aria-label=\"Toggle Multiselect\"\n ref={toggleRef}\n onClick={() => setIsOpen(!isOpen)}\n startIcon={startIcon}\n endIcon={<ChevronDownIcon />}\n >\n {renderMultiselectLabel()}\n </Button>\n </Popover.Trigger>\n <Popover.Content\n ref={listRef}\n className={styles.content(listMaxHeight)}\n testId=\"cf-multiselect-container\"\n >\n <>\n {hasSearch && (\n <>\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 />\n <IconButton\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={() => {\n if (searchValue) {\n resetSearch();\n }\n }}\n isDisabled={!searchValue}\n size=\"small\"\n />\n </>\n )}\n {isLoading && <ListItemLoadingState />}\n\n {!isLoading && childrenLength > 0 && (\n <ul className={styles.list} data-test-id=\"cf-multiselect-items\">\n {React.Children.map(children, (child) => {\n if (React.isValidElement(child)) {\n return React.cloneElement(child, {\n searchValue,\n });\n }\n return child;\n })}\n </ul>\n )}\n\n {!isLoading && childrenLength === 0 && (\n <Subheading className={styles.noMatchesTitle}>\n {noMatchesMessage}\n </Subheading>\n )}\n </>\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 { Multiselect as OriginalMultiSelect } from './Multiselect';\nimport { MultiselectOption } from './MultiselectOption';\n\ntype CompoundMultiselect = typeof OriginalMultiSelect & {\n Option: typeof MultiselectOption;\n};\n\nexport const Multiselect = OriginalMultiSelect as CompoundMultiselect;\nMultiselect.Option = MultiselectOption;\n"]}
1
+ {"version":3,"sources":["../src/MultiselectOption.tsx","../src/Multiselect.styles.ts","../src/Multiselect.tsx","../src/CompoundMultiselect.tsx"],"names":["React","Checkbox","Text","css","tokens","getMultiselectStyles","listMaxHeight","getStringMatch","cx","MultiselectOption","label","value","itemId","onSelectItem","searchValue","isChecked","isDisabled","rest","styles","event","HighlightedItem","item","inputValue","before","match","after","useRef","useState","useCallback","useMemo","mergeRefs","Button","IconButton","TextInput","CloseIcon","ChevronDownIcon","SearchIcon","SkeletonContainer","SkeletonBodyText","Popover","Subheading","_Multiselect","props","ref","className","startIcon","placeholder","currentSelection","onSearchValueChange","searchPlaceholder","searchInputRef","noMatchesMessage","toggleRef","isLoading","testId","popoverProps","children","listRef","setSearchValue","isOpen","setIsOpen","internalSearchInputRef","hasSearch","handleSearchChange","resetSearch","forcedEvent","renderMultiselectLabel","leftoverCount","childrenLength","enrichOptions","child","ListItemLoadingState","Multiselect"],"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\nexport interface MulitselectOptionProps {\n label: string;\n value: string;\n itemId: string;\n searchValue?: string;\n onSelectItem: (event: React.ChangeEvent) => void;\n isChecked?: boolean;\n isDisabled?: boolean;\n}\n\nexport const MultiselectOption = ({\n label,\n value,\n itemId,\n onSelectItem,\n searchValue,\n isChecked = false,\n isDisabled = false,\n ...rest\n}: MulitselectOptionProps) => {\n const styles = getMultiselectStyles();\n\n return (\n <li {...rest}>\n <label\n htmlFor={itemId}\n className={cx(styles.item, isDisabled && styles.disabled)}\n >\n <Checkbox\n id={itemId}\n value={value}\n onChange={(event) => onSelectItem(event)}\n isChecked={isChecked}\n isDisabled={isDisabled}\n />\n <Text data-test-id={`cf-multiselect-list-item-${itemId}`}>\n <HighlightedItem item={label} inputValue={searchValue} />\n </Text>\n </label>\n </li>\n );\n};\n\nfunction HighlightedItem({\n item,\n inputValue = '',\n}: {\n item: string;\n inputValue?: string;\n}) {\n const { before, match, after } = getStringMatch(item, inputValue);\n return (\n <>\n {before}\n <b data-test-id=\"cf-multiselect-item-match\">{match}</b>\n {after}\n </>\n );\n}\n\nHighlightedItem.displayName = 'HighlightedItem';\n","import { css } from 'emotion';\nimport tokens from '@contentful/f36-tokens';\n\nexport const getMultiselectStyles = () => ({\n multiselect: css({\n position: 'relative',\n width: '100%',\n }),\n currentSelection: css({\n width: '50%',\n whiteSpace: 'nowrap',\n textOverflow: 'ellipsis',\n overflow: 'hidden',\n verticalAlign: 'bottom',\n marginRight: tokens.spacing2Xs,\n }),\n inputField: css({\n paddingRight: tokens.spacingXl,\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\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 list: css({\n listStyle: 'none',\n padding: `${tokens.spacingXs} 0`,\n margin: 0,\n }),\n groupTitle: css({\n padding: `${tokens.spacingXs} ${tokens.spacingM}`,\n lineHeight: tokens.lineHeightM,\n }),\n noMatchesTitle: css({\n color: tokens.gray500,\n margin: tokens.spacingM,\n }),\n item: css({\n padding: `${tokens.spacingXs} ${tokens.spacingM}`,\n wordBreak: 'break-word',\n whiteSpace: 'break-spaces',\n hyphens: 'auto',\n display: 'flex',\n flexDirection: 'row',\n alignItems: 'center',\n '&:focus, &:hover': {\n backgroundColor: tokens.gray100,\n },\n '&:active': {\n backgroundColor: tokens.gray200,\n },\n '&:focus': {\n boxShadow: tokens.glowPrimary,\n },\n '&:focus:not(:focus-visible)': {\n boxShadow: 'unset',\n },\n '&:focus-visible': {\n boxShadow: tokens.glowPrimary,\n },\n }),\n disabled: css({\n opacity: 0.5,\n cursor: 'not-allowed',\n }),\n});\n","import React, { useRef, useState, useCallback, useMemo } from 'react';\nimport { cx } from 'emotion';\n\nimport { mergeRefs, type CommonProps } from '@contentful/f36-core';\nimport { Button, IconButton } from '@contentful/f36-button';\nimport { TextInput } from '@contentful/f36-forms';\nimport { CloseIcon, ChevronDownIcon, SearchIcon } from '@contentful/f36-icons';\nimport { SkeletonContainer, SkeletonBodyText } from '@contentful/f36-skeleton';\nimport { Popover, type PopoverProps } from '@contentful/f36-popover';\nimport { Subheading } from '@contentful/f36-typography';\n\nimport { getMultiselectStyles } from './Multiselect.styles';\nimport { MultiselectOption } from './MultiselectOption';\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 * Function called whenever the search input value changes\n */\n onSearchValueChange?: (event: React.ChangeEvent) => 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 * A message that will be shown when it is not possible to find any option that matches the input value\n * @default \"No matches\"\n */\n noMatchesMessage?: string;\n\n /**\n * Use this prop to get a ref to the input element of the component\n */\n searchInputRef?: React.Ref<HTMLInputElement>;\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 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 };\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 onSearchValueChange,\n searchPlaceholder = 'Search',\n searchInputRef,\n noMatchesMessage = 'No matches found',\n toggleRef,\n isLoading = false,\n testId = 'cf-multiselect',\n popoverProps = {},\n children,\n } = props;\n\n const { listMaxHeight = 180, listRef } = popoverProps;\n\n const styles = getMultiselectStyles();\n\n const [searchValue, setSearchValue] = useState('');\n const [isOpen, setIsOpen] = useState(false);\n\n const internalSearchInputRef = useRef(null);\n\n const hasSearch = typeof onSearchValueChange === 'function';\n\n const handleSearchChange = useCallback(\n (event) => {\n setSearchValue(event.target.value);\n onSearchValueChange?.(event);\n },\n [onSearchValueChange, setSearchValue],\n );\n\n const resetSearch = () => {\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\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 };\n\n const renderMultiselectLabel = useCallback(() => {\n if (currentSelection.length === 0) {\n return <>{placeholder}</>;\n }\n const leftoverCount = currentSelection.length - 1;\n if (leftoverCount === 0) {\n return (\n <span\n data-test-id=\"cf-multiselect-current-selection\"\n className={styles.currentSelection}\n >\n {currentSelection[0]}\n </span>\n );\n }\n return (\n <span\n data-test-id=\"cf-multiselect-current-selection\"\n className={styles.currentSelection}\n >\n {currentSelection[0]} and {leftoverCount} more{' '}\n </span>\n );\n }, [currentSelection, placeholder, styles.currentSelection]);\n\n const childrenLength = useMemo(\n () => React.Children.count(children),\n [children],\n );\n\n // clones and enriches the multiselect options\n const enrichOptions = React.useCallback(\n (children: React.ReactNode): React.ReactNode => {\n return React.Children.map(children, (child) => {\n if (React.isValidElement(child)) {\n if (child.type === React.Fragment) {\n return enrichOptions(child.props.children);\n }\n if (child.type === MultiselectOption) {\n return React.cloneElement(child, { searchValue });\n }\n return child;\n }\n return child;\n });\n },\n [searchValue],\n );\n\n return (\n <div\n data-test-id={testId}\n className={cx(styles.multiselect, className)}\n ref={ref}\n >\n <Popover\n isOpen={isOpen}\n onClose={() => setIsOpen(false)}\n renderOnlyWhenOpen={false}\n {...popoverProps}\n >\n <Popover.Trigger>\n <Button\n aria-label=\"Toggle Multiselect\"\n ref={toggleRef}\n onClick={() => setIsOpen(!isOpen)}\n startIcon={startIcon}\n endIcon={<ChevronDownIcon />}\n >\n {renderMultiselectLabel()}\n </Button>\n </Popover.Trigger>\n <Popover.Content\n ref={listRef}\n className={styles.content(listMaxHeight)}\n testId=\"cf-multiselect-container\"\n >\n <>\n {hasSearch && (\n <>\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 />\n <IconButton\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={() => {\n if (searchValue) {\n resetSearch();\n }\n }}\n isDisabled={!searchValue}\n size=\"small\"\n />\n </>\n )}\n {isLoading && <ListItemLoadingState />}\n\n {!isLoading && childrenLength > 0 && (\n <ul className={styles.list} data-test-id=\"cf-multiselect-items\">\n {hasSearch ? enrichOptions(children) : children}\n </ul>\n )}\n\n {!isLoading && childrenLength === 0 && (\n <Subheading className={styles.noMatchesTitle}>\n {noMatchesMessage}\n </Subheading>\n )}\n </>\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 { Multiselect as OriginalMultiSelect } from './Multiselect';\nimport { MultiselectOption } from './MultiselectOption';\n\ntype CompoundMultiselect = typeof OriginalMultiSelect & {\n Option: typeof MultiselectOption;\n};\n\nexport const Multiselect = OriginalMultiSelect as CompoundMultiselect;\nMultiselect.Option = MultiselectOption;\n"]}
package/dist/index.mjs CHANGED
@@ -2,7 +2,7 @@ import e, { useState, useRef, useCallback, useMemo } from 'react';
2
2
  import { Checkbox, TextInput } from '@contentful/f36-forms';
3
3
  import { Text, Subheading } from '@contentful/f36-typography';
4
4
  import { cx, css } from 'emotion';
5
- import i from '@contentful/f36-tokens';
5
+ import t from '@contentful/f36-tokens';
6
6
  import { getStringMatch } from '@contentful/f36-utils';
7
7
  import { mergeRefs } from '@contentful/f36-core';
8
8
  import { Button, IconButton } from '@contentful/f36-button';
@@ -10,7 +10,7 @@ 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
 
13
- var J=Object.defineProperty;var M=Object.getOwnPropertySymbols;var L=Object.prototype.hasOwnProperty,N=Object.prototype.propertyIsEnumerable;var H=(t,n,o)=>n in t?J(t,n,{enumerable:!0,configurable:!0,writable:!0,value:o}):t[n]=o,v=(t,n)=>{for(var o in n||(n={}))L.call(n,o)&&H(t,o,n[o]);if(M)for(var o of M(n))N.call(n,o)&&H(t,o,n[o]);return t};var B=(t,n)=>{var o={};for(var r in t)L.call(t,r)&&n.indexOf(r)<0&&(o[r]=t[r]);if(t!=null&&M)for(var r of M(t))n.indexOf(r)<0&&N.call(t,r)&&(o[r]=t[r]);return o};var b=()=>({multiselect:css({position:"relative",width:"100%"}),currentSelection:css({width:"50%",whiteSpace:"nowrap",textOverflow:"ellipsis",overflow:"hidden",verticalAlign:"bottom",marginRight:i.spacing2Xs}),inputField:css({paddingRight:i.spacingXl,textOverflow:"ellipsis",whiteSpace:"nowrap"}),toggleButton:css({position:"absolute",top:"1px",right:"1px",zIndex:i.zIndexDefault,padding:i.spacing2Xs,height:i.spacingXl}),content:t=>css({overflow:"auto",maxHeight:`${t}px`}),list:css({listStyle:"none",padding:`${i.spacingXs} 0`,margin:0}),groupTitle:css({padding:`${i.spacingXs} ${i.spacingM}`,lineHeight:i.lineHeightM}),noMatchesTitle:css({color:i.gray500,margin:i.spacingM}),item:css({padding:`${i.spacingXs} ${i.spacingM}`,wordBreak:"break-word",whiteSpace:"break-spaces",hyphens:"auto",display:"flex",flexDirection:"row",alignItems:"center","&:focus, &:hover":{backgroundColor:i.gray100},"&:active":{backgroundColor:i.gray200},"&:focus":{boxShadow:i.glowPrimary},"&:focus:not(:focus-visible)":{boxShadow:"unset"},"&:focus-visible":{boxShadow:i.glowPrimary}}),disabled:css({opacity:.5,cursor:"not-allowed"})});var C=w=>{var f=w,{label:t,value:n,itemId:o,onSelectItem:r,searchValue:m,isChecked:u=!1,isDisabled:c=!1}=f,S=B(f,["label","value","itemId","onSelectItem","searchValue","isChecked","isDisabled"]);let h=b();return e.createElement("li",v({},S),e.createElement("label",{htmlFor:o,className:cx(h.item,c&&h.disabled)},e.createElement(Checkbox,{id:o,value:n,onChange:d=>r(d),isChecked:u,isDisabled:c}),e.createElement(Text,{"data-test-id":`cf-multiselect-list-item-${o}`},e.createElement(V,{item:t,inputValue:m}))))};function V({item:t,inputValue:n=""}){let{before:o,match:r,after:m}=getStringMatch(t,n);return e.createElement(e.Fragment,null,o,e.createElement("b",{"data-test-id":"cf-multiselect-item-match"},r),m)}V.displayName="HighlightedItem";function me(t,n){let{className:o,startIcon:r,placeholder:m="Select one or more Items",currentSelection:u=[],onSearchValueChange:c,searchPlaceholder:S="Search",searchInputRef:w,noMatchesMessage:f="No matches found",toggleRef:h,isLoading:d=!1,testId:F="cf-multiselect",popoverProps:P={},children:x}=t,{listMaxHeight:A=180,listRef:j}=P,a=b(),[g,O]=useState(""),[k,T]=useState(!1),y=useRef(null),U=typeof c=="function",W=useCallback(l=>{O(l.target.value),c==null||c(l);},[c,O]),_=()=>{Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value").set.call(y.current,"");let G=new Event("change",{bubbles:!0});y.current.dispatchEvent(G);},q=useCallback(()=>{if(u.length===0)return e.createElement(e.Fragment,null,m);let l=u.length-1;return l===0?e.createElement("span",{"data-test-id":"cf-multiselect-current-selection",className:a.currentSelection},u[0]):e.createElement("span",{"data-test-id":"cf-multiselect-current-selection",className:a.currentSelection},u[0]," and ",l," more"," ")},[u,m,a.currentSelection]),E=useMemo(()=>e.Children.count(x),[x]);return e.createElement("div",{"data-test-id":F,className:cx(a.multiselect,o),ref:n},e.createElement(Popover,v({isOpen:k,onClose:()=>T(!1),renderOnlyWhenOpen:!1},P),e.createElement(Popover.Trigger,null,e.createElement(Button,{"aria-label":"Toggle Multiselect",ref:h,onClick:()=>T(!k),startIcon:r,endIcon:e.createElement(ChevronDownIcon,null)},q())),e.createElement(Popover.Content,{ref:j,className:a.content(A),testId:"cf-multiselect-container"},e.createElement(e.Fragment,null,U&&e.createElement(e.Fragment,null,e.createElement(TextInput,{"aria-label":"Search",type:"text",value:g,className:a.inputField,testId:"cf-multiselect-search",placeholder:S,onChange:W,ref:mergeRefs(w,y)}),e.createElement(IconButton,{"aria-label":g?"Clear search":"Search",className:a.toggleButton,variant:"transparent",icon:g?e.createElement(CloseIcon,{variant:"muted"}):e.createElement(SearchIcon,{variant:"muted"}),onClick:()=>{g&&_();},isDisabled:!g,size:"small"})),d&&e.createElement(ge,null),!d&&E>0&&e.createElement("ul",{className:a.list,"data-test-id":"cf-multiselect-items"},e.Children.map(x,l=>e.isValidElement(l)?e.cloneElement(l,{searchValue:g}):l)),!d&&E===0&&e.createElement(Subheading,{className:a.noMatchesTitle},f)))))}var ge=()=>e.createElement(SkeletonContainer,{svgHeight:16},e.createElement(SkeletonBodyText,{numberOfLines:1})),$=e.forwardRef(me);var z=$;z.Option=C;
13
+ var v=()=>({multiselect:css({position:"relative",width:"100%"}),currentSelection:css({width:"50%",whiteSpace:"nowrap",textOverflow:"ellipsis",overflow:"hidden",verticalAlign:"bottom",marginRight:t.spacing2Xs}),inputField:css({paddingRight:t.spacingXl,textOverflow:"ellipsis",whiteSpace:"nowrap"}),toggleButton:css({position:"absolute",top:"1px",right:"1px",zIndex:t.zIndexDefault,padding:t.spacing2Xs,height:t.spacingXl}),content:s=>css({overflow:"auto",maxHeight:`${s}px`}),list:css({listStyle:"none",padding:`${t.spacingXs} 0`,margin:0}),groupTitle:css({padding:`${t.spacingXs} ${t.spacingM}`,lineHeight:t.lineHeightM}),noMatchesTitle:css({color:t.gray500,margin:t.spacingM}),item:css({padding:`${t.spacingXs} ${t.spacingM}`,wordBreak:"break-word",whiteSpace:"break-spaces",hyphens:"auto",display:"flex",flexDirection:"row",alignItems:"center","&:focus, &:hover":{backgroundColor:t.gray100},"&:active":{backgroundColor:t.gray200},"&:focus":{boxShadow:t.glowPrimary},"&:focus:not(:focus-visible)":{boxShadow:"unset"},"&:focus-visible":{boxShadow:t.glowPrimary}}),disabled:css({opacity:.5,cursor:"not-allowed"})});var d=({label:s,value:g,itemId:a,onSelectItem:f,searchValue:u,isChecked:c=!1,isDisabled:m=!1,...S})=>{let h=v();return e.createElement("li",{...S},e.createElement("label",{htmlFor:a,className:cx(h.item,m&&h.disabled)},e.createElement(Checkbox,{id:a,value:g,onChange:b=>f(b),isChecked:c,isDisabled:m}),e.createElement(Text,{"data-test-id":`cf-multiselect-list-item-${a}`},e.createElement(E,{item:s,inputValue:u}))))};function E({item:s,inputValue:g=""}){let{before:a,match:f,after:u}=getStringMatch(s,g);return e.createElement(e.Fragment,null,a,e.createElement("b",{"data-test-id":"cf-multiselect-item-match"},f),u)}E.displayName="HighlightedItem";function le(s,g){let{className:a,startIcon:f,placeholder:u="Select one or more Items",currentSelection:c=[],onSearchValueChange:m,searchPlaceholder:S="Search",searchInputRef:h,noMatchesMessage:b="No matches found",toggleRef:D,isLoading:x=!1,testId:X="cf-multiselect",popoverProps:I={},children:M}=s,{listMaxHeight:$=180,listRef:F}=I,n=v(),[p,w]=useState(""),[O,P]=useState(!1),y=useRef(null),k=typeof m=="function",z=useCallback(i=>{w(i.target.value),m?.(i);},[m,w]),A=()=>{Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype,"value").set.call(y.current,"");let r=new Event("change",{bubbles:!0});y.current.dispatchEvent(r);},j=useCallback(()=>{if(c.length===0)return e.createElement(e.Fragment,null,u);let i=c.length-1;return i===0?e.createElement("span",{"data-test-id":"cf-multiselect-current-selection",className:n.currentSelection},c[0]):e.createElement("span",{"data-test-id":"cf-multiselect-current-selection",className:n.currentSelection},c[0]," and ",i," more"," ")},[c,u,n.currentSelection]),N=useMemo(()=>e.Children.count(M),[M]),T=e.useCallback(i=>e.Children.map(i,r=>e.isValidElement(r)?r.type===e.Fragment?T(r.props.children):r.type===d?e.cloneElement(r,{searchValue:p}):r:r),[p]);return e.createElement("div",{"data-test-id":X,className:cx(n.multiselect,a),ref:g},e.createElement(Popover,{isOpen:O,onClose:()=>P(!1),renderOnlyWhenOpen:!1,...I},e.createElement(Popover.Trigger,null,e.createElement(Button,{"aria-label":"Toggle Multiselect",ref:D,onClick:()=>P(!O),startIcon:f,endIcon:e.createElement(ChevronDownIcon,null)},j())),e.createElement(Popover.Content,{ref:F,className:n.content($),testId:"cf-multiselect-container"},e.createElement(e.Fragment,null,k&&e.createElement(e.Fragment,null,e.createElement(TextInput,{"aria-label":"Search",type:"text",value:p,className:n.inputField,testId:"cf-multiselect-search",placeholder:S,onChange:z,ref:mergeRefs(h,y)}),e.createElement(IconButton,{"aria-label":p?"Clear search":"Search",className:n.toggleButton,variant:"transparent",icon:p?e.createElement(CloseIcon,{variant:"muted"}):e.createElement(SearchIcon,{variant:"muted"}),onClick:()=>{p&&A();},isDisabled:!p,size:"small"})),x&&e.createElement(se,null),!x&&N>0&&e.createElement("ul",{className:n.list,"data-test-id":"cf-multiselect-items"},k?T(M):M),!x&&N===0&&e.createElement(Subheading,{className:n.noMatchesTitle},b)))))}var se=()=>e.createElement(SkeletonContainer,{svgHeight:16},e.createElement(SkeletonBodyText,{numberOfLines:1})),V=e.forwardRef(le);var B=V;B.Option=d;
14
14
 
15
- export { z as Multiselect, C as MultiselectOption };
15
+ export { B as Multiselect, d as MultiselectOption };
16
16
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/MultiselectOption.tsx","../src/Multiselect.styles.ts","../src/Multiselect.tsx","../src/CompoundMultiselect.tsx"],"names":["React","Checkbox","Text","css","tokens","getMultiselectStyles","listMaxHeight","getStringMatch","cx","MultiselectOption","_a","_b","label","value","itemId","onSelectItem","searchValue","isChecked","isDisabled","rest","__objRest","styles","__spreadValues","event","HighlightedItem","item","inputValue","before","match","after","useRef","useState","useCallback","useMemo","mergeRefs","Button","IconButton","TextInput","CloseIcon","ChevronDownIcon","SearchIcon","SkeletonContainer","SkeletonBodyText","Popover","Subheading","_Multiselect","props","ref","className","startIcon","placeholder","currentSelection","onSearchValueChange","searchPlaceholder","searchInputRef","noMatchesMessage","toggleRef","isLoading","testId","popoverProps","children","listRef","setSearchValue","isOpen","setIsOpen","internalSearchInputRef","hasSearch","handleSearchChange","resetSearch","forcedEvent","renderMultiselectLabel","leftoverCount","childrenLength","ListItemLoadingState","child","Multiselect"],"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\nexport interface MulitselectOptionProps {\n label: string;\n value: string;\n itemId: string;\n searchValue?: string;\n onSelectItem: (event: React.ChangeEvent) => void;\n isChecked?: boolean;\n isDisabled?: boolean;\n}\n\nexport const MultiselectOption = ({\n label,\n value,\n itemId,\n onSelectItem,\n searchValue,\n isChecked = false,\n isDisabled = false,\n ...rest\n}: MulitselectOptionProps) => {\n const styles = getMultiselectStyles();\n\n return (\n <li {...rest}>\n <label\n htmlFor={itemId}\n className={cx(styles.item, isDisabled && styles.disabled)}\n >\n <Checkbox\n id={itemId}\n value={value}\n onChange={(event) => onSelectItem(event)}\n isChecked={isChecked}\n isDisabled={isDisabled}\n />\n <Text data-test-id={`cf-multiselect-list-item-${itemId}`}>\n <HighlightedItem item={label} inputValue={searchValue} />\n </Text>\n </label>\n </li>\n );\n};\n\nfunction HighlightedItem({\n item,\n inputValue = '',\n}: {\n item: string;\n inputValue?: string;\n}) {\n const { before, match, after } = getStringMatch(item, inputValue);\n return (\n <>\n {before}\n <b data-test-id=\"cf-multiselect-item-match\">{match}</b>\n {after}\n </>\n );\n}\n\nHighlightedItem.displayName = 'HighlightedItem';\n","import { css } from 'emotion';\nimport tokens from '@contentful/f36-tokens';\n\nexport const getMultiselectStyles = () => ({\n multiselect: css({\n position: 'relative',\n width: '100%',\n }),\n currentSelection: css({\n width: '50%',\n whiteSpace: 'nowrap',\n textOverflow: 'ellipsis',\n overflow: 'hidden',\n verticalAlign: 'bottom',\n marginRight: tokens.spacing2Xs,\n }),\n inputField: css({\n paddingRight: tokens.spacingXl,\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\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 list: css({\n listStyle: 'none',\n padding: `${tokens.spacingXs} 0`,\n margin: 0,\n }),\n groupTitle: css({\n padding: `${tokens.spacingXs} ${tokens.spacingM}`,\n lineHeight: tokens.lineHeightM,\n }),\n noMatchesTitle: css({\n color: tokens.gray500,\n margin: tokens.spacingM,\n }),\n item: css({\n padding: `${tokens.spacingXs} ${tokens.spacingM}`,\n wordBreak: 'break-word',\n whiteSpace: 'break-spaces',\n hyphens: 'auto',\n display: 'flex',\n flexDirection: 'row',\n alignItems: 'center',\n '&:focus, &:hover': {\n backgroundColor: tokens.gray100,\n },\n '&:active': {\n backgroundColor: tokens.gray200,\n },\n '&:focus': {\n boxShadow: tokens.glowPrimary,\n },\n '&:focus:not(:focus-visible)': {\n boxShadow: 'unset',\n },\n '&:focus-visible': {\n boxShadow: tokens.glowPrimary,\n },\n }),\n disabled: css({\n opacity: 0.5,\n cursor: 'not-allowed',\n }),\n});\n","import React, { useRef, useState, useCallback, useMemo } from 'react';\nimport { cx } from 'emotion';\n\nimport { mergeRefs, type CommonProps } from '@contentful/f36-core';\nimport { Button, IconButton } from '@contentful/f36-button';\nimport { TextInput } from '@contentful/f36-forms';\nimport { CloseIcon, ChevronDownIcon, SearchIcon } from '@contentful/f36-icons';\nimport { SkeletonContainer, SkeletonBodyText } from '@contentful/f36-skeleton';\nimport { Popover, type PopoverProps } from '@contentful/f36-popover';\nimport { Subheading } from '@contentful/f36-typography';\n\nimport { getMultiselectStyles } from './Multiselect.styles';\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 * Function called whenever the search input value changes\n */\n onSearchValueChange?: (event: React.ChangeEvent) => 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 * A message that will be shown when it is not possible to find any option that matches the input value\n * @default \"No matches\"\n */\n noMatchesMessage?: string;\n\n /**\n * Use this prop to get a ref to the input element of the component\n */\n searchInputRef?: React.Ref<HTMLInputElement>;\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 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 };\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 onSearchValueChange,\n searchPlaceholder = 'Search',\n searchInputRef,\n noMatchesMessage = 'No matches found',\n toggleRef,\n isLoading = false,\n testId = 'cf-multiselect',\n popoverProps = {},\n children,\n } = props;\n\n const { listMaxHeight = 180, listRef } = popoverProps;\n\n const styles = getMultiselectStyles();\n\n const [searchValue, setSearchValue] = useState('');\n const [isOpen, setIsOpen] = useState(false);\n\n const internalSearchInputRef = useRef(null);\n\n const hasSearch = typeof onSearchValueChange === 'function';\n\n const handleSearchChange = useCallback(\n (event) => {\n setSearchValue(event.target.value);\n onSearchValueChange?.(event);\n },\n [onSearchValueChange, setSearchValue],\n );\n\n const resetSearch = () => {\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\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 };\n\n const renderMultiselectLabel = useCallback(() => {\n if (currentSelection.length === 0) {\n return <>{placeholder}</>;\n }\n const leftoverCount = currentSelection.length - 1;\n if (leftoverCount === 0) {\n return (\n <span\n data-test-id=\"cf-multiselect-current-selection\"\n className={styles.currentSelection}\n >\n {currentSelection[0]}\n </span>\n );\n }\n return (\n <span\n data-test-id=\"cf-multiselect-current-selection\"\n className={styles.currentSelection}\n >\n {currentSelection[0]} and {leftoverCount} more{' '}\n </span>\n );\n }, [currentSelection, placeholder, styles.currentSelection]);\n\n const childrenLength = useMemo(\n () => React.Children.count(children),\n [children],\n );\n\n return (\n <div\n data-test-id={testId}\n className={cx(styles.multiselect, className)}\n ref={ref}\n >\n <Popover\n isOpen={isOpen}\n onClose={() => setIsOpen(false)}\n renderOnlyWhenOpen={false}\n {...popoverProps}\n >\n <Popover.Trigger>\n <Button\n aria-label=\"Toggle Multiselect\"\n ref={toggleRef}\n onClick={() => setIsOpen(!isOpen)}\n startIcon={startIcon}\n endIcon={<ChevronDownIcon />}\n >\n {renderMultiselectLabel()}\n </Button>\n </Popover.Trigger>\n <Popover.Content\n ref={listRef}\n className={styles.content(listMaxHeight)}\n testId=\"cf-multiselect-container\"\n >\n <>\n {hasSearch && (\n <>\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 />\n <IconButton\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={() => {\n if (searchValue) {\n resetSearch();\n }\n }}\n isDisabled={!searchValue}\n size=\"small\"\n />\n </>\n )}\n {isLoading && <ListItemLoadingState />}\n\n {!isLoading && childrenLength > 0 && (\n <ul className={styles.list} data-test-id=\"cf-multiselect-items\">\n {React.Children.map(children, (child) => {\n if (React.isValidElement(child)) {\n return React.cloneElement(child, {\n searchValue,\n });\n }\n return child;\n })}\n </ul>\n )}\n\n {!isLoading && childrenLength === 0 && (\n <Subheading className={styles.noMatchesTitle}>\n {noMatchesMessage}\n </Subheading>\n )}\n </>\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 { Multiselect as OriginalMultiSelect } from './Multiselect';\nimport { MultiselectOption } from './MultiselectOption';\n\ntype CompoundMultiselect = typeof OriginalMultiSelect & {\n Option: typeof MultiselectOption;\n};\n\nexport const Multiselect = OriginalMultiSelect as CompoundMultiselect;\nMultiselect.Option = MultiselectOption;\n"]}
1
+ {"version":3,"sources":["../src/MultiselectOption.tsx","../src/Multiselect.styles.ts","../src/Multiselect.tsx","../src/CompoundMultiselect.tsx"],"names":["React","Checkbox","Text","css","tokens","getMultiselectStyles","listMaxHeight","getStringMatch","cx","MultiselectOption","label","value","itemId","onSelectItem","searchValue","isChecked","isDisabled","rest","styles","event","HighlightedItem","item","inputValue","before","match","after","useRef","useState","useCallback","useMemo","mergeRefs","Button","IconButton","TextInput","CloseIcon","ChevronDownIcon","SearchIcon","SkeletonContainer","SkeletonBodyText","Popover","Subheading","_Multiselect","props","ref","className","startIcon","placeholder","currentSelection","onSearchValueChange","searchPlaceholder","searchInputRef","noMatchesMessage","toggleRef","isLoading","testId","popoverProps","children","listRef","setSearchValue","isOpen","setIsOpen","internalSearchInputRef","hasSearch","handleSearchChange","resetSearch","forcedEvent","renderMultiselectLabel","leftoverCount","childrenLength","enrichOptions","child","ListItemLoadingState","Multiselect"],"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\nexport interface MulitselectOptionProps {\n label: string;\n value: string;\n itemId: string;\n searchValue?: string;\n onSelectItem: (event: React.ChangeEvent) => void;\n isChecked?: boolean;\n isDisabled?: boolean;\n}\n\nexport const MultiselectOption = ({\n label,\n value,\n itemId,\n onSelectItem,\n searchValue,\n isChecked = false,\n isDisabled = false,\n ...rest\n}: MulitselectOptionProps) => {\n const styles = getMultiselectStyles();\n\n return (\n <li {...rest}>\n <label\n htmlFor={itemId}\n className={cx(styles.item, isDisabled && styles.disabled)}\n >\n <Checkbox\n id={itemId}\n value={value}\n onChange={(event) => onSelectItem(event)}\n isChecked={isChecked}\n isDisabled={isDisabled}\n />\n <Text data-test-id={`cf-multiselect-list-item-${itemId}`}>\n <HighlightedItem item={label} inputValue={searchValue} />\n </Text>\n </label>\n </li>\n );\n};\n\nfunction HighlightedItem({\n item,\n inputValue = '',\n}: {\n item: string;\n inputValue?: string;\n}) {\n const { before, match, after } = getStringMatch(item, inputValue);\n return (\n <>\n {before}\n <b data-test-id=\"cf-multiselect-item-match\">{match}</b>\n {after}\n </>\n );\n}\n\nHighlightedItem.displayName = 'HighlightedItem';\n","import { css } from 'emotion';\nimport tokens from '@contentful/f36-tokens';\n\nexport const getMultiselectStyles = () => ({\n multiselect: css({\n position: 'relative',\n width: '100%',\n }),\n currentSelection: css({\n width: '50%',\n whiteSpace: 'nowrap',\n textOverflow: 'ellipsis',\n overflow: 'hidden',\n verticalAlign: 'bottom',\n marginRight: tokens.spacing2Xs,\n }),\n inputField: css({\n paddingRight: tokens.spacingXl,\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\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 list: css({\n listStyle: 'none',\n padding: `${tokens.spacingXs} 0`,\n margin: 0,\n }),\n groupTitle: css({\n padding: `${tokens.spacingXs} ${tokens.spacingM}`,\n lineHeight: tokens.lineHeightM,\n }),\n noMatchesTitle: css({\n color: tokens.gray500,\n margin: tokens.spacingM,\n }),\n item: css({\n padding: `${tokens.spacingXs} ${tokens.spacingM}`,\n wordBreak: 'break-word',\n whiteSpace: 'break-spaces',\n hyphens: 'auto',\n display: 'flex',\n flexDirection: 'row',\n alignItems: 'center',\n '&:focus, &:hover': {\n backgroundColor: tokens.gray100,\n },\n '&:active': {\n backgroundColor: tokens.gray200,\n },\n '&:focus': {\n boxShadow: tokens.glowPrimary,\n },\n '&:focus:not(:focus-visible)': {\n boxShadow: 'unset',\n },\n '&:focus-visible': {\n boxShadow: tokens.glowPrimary,\n },\n }),\n disabled: css({\n opacity: 0.5,\n cursor: 'not-allowed',\n }),\n});\n","import React, { useRef, useState, useCallback, useMemo } from 'react';\nimport { cx } from 'emotion';\n\nimport { mergeRefs, type CommonProps } from '@contentful/f36-core';\nimport { Button, IconButton } from '@contentful/f36-button';\nimport { TextInput } from '@contentful/f36-forms';\nimport { CloseIcon, ChevronDownIcon, SearchIcon } from '@contentful/f36-icons';\nimport { SkeletonContainer, SkeletonBodyText } from '@contentful/f36-skeleton';\nimport { Popover, type PopoverProps } from '@contentful/f36-popover';\nimport { Subheading } from '@contentful/f36-typography';\n\nimport { getMultiselectStyles } from './Multiselect.styles';\nimport { MultiselectOption } from './MultiselectOption';\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 * Function called whenever the search input value changes\n */\n onSearchValueChange?: (event: React.ChangeEvent) => 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 * A message that will be shown when it is not possible to find any option that matches the input value\n * @default \"No matches\"\n */\n noMatchesMessage?: string;\n\n /**\n * Use this prop to get a ref to the input element of the component\n */\n searchInputRef?: React.Ref<HTMLInputElement>;\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 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 };\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 onSearchValueChange,\n searchPlaceholder = 'Search',\n searchInputRef,\n noMatchesMessage = 'No matches found',\n toggleRef,\n isLoading = false,\n testId = 'cf-multiselect',\n popoverProps = {},\n children,\n } = props;\n\n const { listMaxHeight = 180, listRef } = popoverProps;\n\n const styles = getMultiselectStyles();\n\n const [searchValue, setSearchValue] = useState('');\n const [isOpen, setIsOpen] = useState(false);\n\n const internalSearchInputRef = useRef(null);\n\n const hasSearch = typeof onSearchValueChange === 'function';\n\n const handleSearchChange = useCallback(\n (event) => {\n setSearchValue(event.target.value);\n onSearchValueChange?.(event);\n },\n [onSearchValueChange, setSearchValue],\n );\n\n const resetSearch = () => {\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\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 };\n\n const renderMultiselectLabel = useCallback(() => {\n if (currentSelection.length === 0) {\n return <>{placeholder}</>;\n }\n const leftoverCount = currentSelection.length - 1;\n if (leftoverCount === 0) {\n return (\n <span\n data-test-id=\"cf-multiselect-current-selection\"\n className={styles.currentSelection}\n >\n {currentSelection[0]}\n </span>\n );\n }\n return (\n <span\n data-test-id=\"cf-multiselect-current-selection\"\n className={styles.currentSelection}\n >\n {currentSelection[0]} and {leftoverCount} more{' '}\n </span>\n );\n }, [currentSelection, placeholder, styles.currentSelection]);\n\n const childrenLength = useMemo(\n () => React.Children.count(children),\n [children],\n );\n\n // clones and enriches the multiselect options\n const enrichOptions = React.useCallback(\n (children: React.ReactNode): React.ReactNode => {\n return React.Children.map(children, (child) => {\n if (React.isValidElement(child)) {\n if (child.type === React.Fragment) {\n return enrichOptions(child.props.children);\n }\n if (child.type === MultiselectOption) {\n return React.cloneElement(child, { searchValue });\n }\n return child;\n }\n return child;\n });\n },\n [searchValue],\n );\n\n return (\n <div\n data-test-id={testId}\n className={cx(styles.multiselect, className)}\n ref={ref}\n >\n <Popover\n isOpen={isOpen}\n onClose={() => setIsOpen(false)}\n renderOnlyWhenOpen={false}\n {...popoverProps}\n >\n <Popover.Trigger>\n <Button\n aria-label=\"Toggle Multiselect\"\n ref={toggleRef}\n onClick={() => setIsOpen(!isOpen)}\n startIcon={startIcon}\n endIcon={<ChevronDownIcon />}\n >\n {renderMultiselectLabel()}\n </Button>\n </Popover.Trigger>\n <Popover.Content\n ref={listRef}\n className={styles.content(listMaxHeight)}\n testId=\"cf-multiselect-container\"\n >\n <>\n {hasSearch && (\n <>\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 />\n <IconButton\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={() => {\n if (searchValue) {\n resetSearch();\n }\n }}\n isDisabled={!searchValue}\n size=\"small\"\n />\n </>\n )}\n {isLoading && <ListItemLoadingState />}\n\n {!isLoading && childrenLength > 0 && (\n <ul className={styles.list} data-test-id=\"cf-multiselect-items\">\n {hasSearch ? enrichOptions(children) : children}\n </ul>\n )}\n\n {!isLoading && childrenLength === 0 && (\n <Subheading className={styles.noMatchesTitle}>\n {noMatchesMessage}\n </Subheading>\n )}\n </>\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 { Multiselect as OriginalMultiSelect } from './Multiselect';\nimport { MultiselectOption } from './MultiselectOption';\n\ntype CompoundMultiselect = typeof OriginalMultiSelect & {\n Option: typeof MultiselectOption;\n};\n\nexport const Multiselect = OriginalMultiSelect as CompoundMultiselect;\nMultiselect.Option = MultiselectOption;\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contentful/f36-multiselect",
3
- "version": "4.19.1-0",
3
+ "version": "4.19.1-2",
4
4
  "description": "Forma 36: Multiselect Component",
5
5
  "scripts": {
6
6
  "build": "tsup"