@amboss/design-system 4.16.0 → 4.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/components/DropdownMenu/Menu.js +1 -1
- package/build/cjs/components/Form/Combobox/OptionsList.js +1 -1
- package/build/cjs/components/Form/Select/SelectWithCustomTrigger.js +1 -1
- package/build/cjs/shared/useContainedEscape.d.ts +13 -0
- package/build/cjs/shared/useContainedEscape.js +1 -0
- package/build/esm/components/DropdownMenu/Menu.js +1 -1
- package/build/esm/components/Form/Combobox/OptionsList.js +1 -1
- package/build/esm/components/Form/Select/SelectWithCustomTrigger.js +1 -1
- package/build/esm/shared/useContainedEscape.d.ts +13 -0
- package/build/esm/shared/useContainedEscape.js +1 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"Menu",{enumerable:!0,get:function(){return Menu}});const _interop_require_default=require("@swc/helpers/_/_interop_require_default"),_react=/*#__PURE__*/require("@swc/helpers/_/_interop_require_wildcard")._(require("react")),_styled=/*#__PURE__*/_interop_require_default._(require("@emotion/styled")),_useKeyboard=require("../../shared/useKeyboard"),_Divider=require("../Divider/Divider"),_MenuItem=require("./MenuItem"),_usePopupMenu=require("../../shared/popupMenu/usePopupMenu"),_useOutsideInteract=require("../../shared/useOutsideInteract"),_Portal=require("../Portal/Portal"),isSeperator=item=>"separator"===item,StyledMenu=(0,_styled.default)("div",{target:"
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"Menu",{enumerable:!0,get:function(){return Menu}});const _interop_require_default=require("@swc/helpers/_/_interop_require_default"),_react=/*#__PURE__*/require("@swc/helpers/_/_interop_require_wildcard")._(require("react")),_styled=/*#__PURE__*/_interop_require_default._(require("@emotion/styled")),_useKeyboard=require("../../shared/useKeyboard"),_useContainedEscape=require("../../shared/useContainedEscape"),_Divider=require("../Divider/Divider"),_MenuItem=require("./MenuItem"),_usePopupMenu=require("../../shared/popupMenu/usePopupMenu"),_useOutsideInteract=require("../../shared/useOutsideInteract"),_Portal=require("../Portal/Portal"),isSeperator=item=>"separator"===item,StyledMenu=(0,_styled.default)("div",{target:"ecmxohu0",label:"StyledMenu"})(({theme})=>{let zIndex=(0,_Portal.usePortalChildZIndex)(theme.variables.zIndex.dropdown);return{position:"absolute",display:"inline-block",width:"fit-content",minWidth:theme.variables.size.dimension.dropdownMenu.width,zIndex,borderRadius:theme.variables.size.borderRadius.s,backgroundColor:theme.values.color.background.primary.default,paddingTop:theme.variables.size.spacing.xs,paddingBottom:theme.variables.size.spacing.xs,":after":{content:'" "',position:"absolute",top:0,left:0,width:"100%",height:"100%",pointerEvents:"none",borderRadius:"inherit",boxShadow:theme.values.elevation[3]}}}),StyledUl=(0,_styled.default)("ul",{target:"ecmxohu1",label:"StyledUl"})(()=>({margin:0,padding:0,overflow:"hidden"})),StyledLi=(0,_styled.default)("li",{target:"ecmxohu2",label:"StyledLi"})(()=>({margin:0,padding:0,width:"100%",listStyleType:"none",whiteSpace:"nowrap"})),StyledLiSeparator=(0,_styled.default)(StyledLi,{target:"ecmxohu3",label:"StyledLiSeparator"})(({theme})=>({marginTop:theme.variables.size.spacing.xs,marginBottom:theme.variables.size.spacing.xs}));function Menu({isOpen,items,portalContainer,triggerRef,placement,onCloseMenu}){let menuRef=(0,_react.useRef)(null),[focusIndex,setFocusIndex]=(0,_react.useState)(0),{menuStyle}=(0,_usePopupMenu.usePopupMenu)({triggerRef,menuRef,isOpen,placement});(0,_useOutsideInteract.useOutsideInteract)({ref:menuRef,excludeRefs:[triggerRef],onInteractOutside:onCloseMenu,isActive:isOpen}),(0,_useContainedEscape.useContainedEscape)([menuRef,triggerRef],onCloseMenu,isOpen),(0,_useKeyboard.useKeyboard)({ArrowUp:()=>{setFocusIndex(index=>index-1)},ArrowDown:()=>{setFocusIndex(index=>index+1)}},menuRef,isOpen),(0,_react.useEffect)(()=>{if(menuRef&&menuRef.current){let buttons=menuRef.current.querySelectorAll("button");buttons[Math.abs(focusIndex)%buttons.length].focus({preventScroll:!0})}isOpen||setFocusIndex(0)},[menuRef,focusIndex,isOpen]);let menuElm=_react.default.createElement(StyledMenu,{ref:menuRef,style:menuStyle},_react.default.createElement(StyledUl,{role:"menu"},items.map((item,index)=>{if(isSeperator(item))return _react.default.createElement(StyledLiSeparator,{role:"separator",key:`menuitem-separator-${index}`},_react.default.createElement(_Divider.Divider,{"aria-hidden":"true"}));let{label,destructive,disabled,emphasized,icon,onSelect}=item;return _react.default.createElement(StyledLi,{role:"menuitem",key:`menuitem-${label}`},_react.default.createElement(_MenuItem.MenuItem,{onSelect:onSelect,icon:icon,label:label,disabled:disabled,destructive:destructive,emphasized:emphasized}))})));return isOpen?_react.default.createElement(_Portal.Portal,{portalContainer:portalContainer},menuElm):null}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var target=exports,all={get OPTIONS_LIST_SELECTOR(){return OPTIONS_LIST_SELECTOR},get OptionsList(){return OptionsList},get getOptionId(){return getOptionId},get getOptionsListId(){return getOptionsListId}};for(var name in all)Object.defineProperty(target,name,{enumerable:!0,get:Object.getOwnPropertyDescriptor(all,name).get});const _interop_require_default=require("@swc/helpers/_/_interop_require_default"),_react=/*#__PURE__*/require("@swc/helpers/_/_interop_require_wildcard")._(require("react")),_react1=require("@emotion/react"),_styled=/*#__PURE__*/_interop_require_default._(require("@emotion/styled")),_useKeyboard=require("../../../shared/useKeyboard"),_useWindow=require("../../../shared/useWindow"),_usePopupMenu=require("../../../shared/popupMenu/usePopupMenu"),_VirtualScrollList=require("../../VirtualScrollList/VirtualScrollList"),_Text=require("../../Typography/Text/Text"),_Box=require("../../Box/Box"),_Inline=require("../../Inline/Inline"),_Icon=require("../../Icon/Icon"),_StyledSelectComponents=require("./StyledSelectComponents"),_constants=require("./constants"),_Stack=require("../../Stack/Stack"),_Checkbox=require("../Checkbox/Checkbox"),_Portal=require("../../Portal/Portal"),_ScreenReaderText=require("../../Utilities/ScreenReaderText/ScreenReaderText"),OPTIONS_LIST_SELECTOR='[role="listbox"], [role="option"]';function getOptionId(selectName,optionValue){return`${selectName}Option${optionValue}`}function getOptionsListId(selectName){return`${selectName}OptionsList`}const scrollToItem=({list,itemIndex,behavior})=>{list[itemIndex]?.scrollIntoView?.({behavior,block:"nearest"})},CustomOption=(0,_styled.default)(_StyledSelectComponents.StyledOption,{target:"
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var target=exports,all={get OPTIONS_LIST_SELECTOR(){return OPTIONS_LIST_SELECTOR},get OptionsList(){return OptionsList},get getOptionId(){return getOptionId},get getOptionsListId(){return getOptionsListId}};for(var name in all)Object.defineProperty(target,name,{enumerable:!0,get:Object.getOwnPropertyDescriptor(all,name).get});const _interop_require_default=require("@swc/helpers/_/_interop_require_default"),_react=/*#__PURE__*/require("@swc/helpers/_/_interop_require_wildcard")._(require("react")),_react1=require("@emotion/react"),_styled=/*#__PURE__*/_interop_require_default._(require("@emotion/styled")),_useKeyboard=require("../../../shared/useKeyboard"),_useContainedEscape=require("../../../shared/useContainedEscape"),_useWindow=require("../../../shared/useWindow"),_usePopupMenu=require("../../../shared/popupMenu/usePopupMenu"),_VirtualScrollList=require("../../VirtualScrollList/VirtualScrollList"),_Text=require("../../Typography/Text/Text"),_Box=require("../../Box/Box"),_Inline=require("../../Inline/Inline"),_Icon=require("../../Icon/Icon"),_StyledSelectComponents=require("./StyledSelectComponents"),_constants=require("./constants"),_Stack=require("../../Stack/Stack"),_Checkbox=require("../Checkbox/Checkbox"),_Portal=require("../../Portal/Portal"),_ScreenReaderText=require("../../Utilities/ScreenReaderText/ScreenReaderText"),OPTIONS_LIST_SELECTOR='[role="listbox"], [role="option"]';function getOptionId(selectName,optionValue){return`${selectName}Option${optionValue}`}function getOptionsListId(selectName){return`${selectName}OptionsList`}const scrollToItem=({list,itemIndex,behavior})=>{list[itemIndex]?.scrollIntoView?.({behavior,block:"nearest"})},CustomOption=(0,_styled.default)(_StyledSelectComponents.StyledOption,{target:"evwdew0",label:"CustomOption"})(({theme})=>({paddingTop:0,paddingBottom:0,"& > div":{paddingTop:theme.variables.size.spacing.xs,paddingBottom:theme.variables.size.spacing.xs},"& > div *":{marginTop:0}})),StyledListContainer=(0,_styled.default)("div",{target:"evwdew1",label:"StyledListContainer"})(({theme,maxHeight})=>({maxHeight,boxSizing:"border-box",overflow:"auto",padding:`${theme.variables.size.spacing.xxs} 0`}));function OptionsList({isOpen,isMultiSelect=!1,value,disabled,options=[],portalContainer,triggerRef,triggerWrapperRef,maxHeight,emptyStateMessage="No options available",selectedIndex,optionsListWidth,isVirtualized=!0,name,onCloseDropdown,onSelectedIndexChange,forceChangeFakeSelect}){let optionsListRef=(0,_react.useRef)(null),listContainerRef=(0,_react.useRef)(null),listItemsRef=(0,_react.useRef)(null),refForPositioning=triggerWrapperRef||triggerRef,activeItemIndex=(0,_react.useMemo)(()=>options.findIndex(option=>isMultiSelect?value.includes(option.value):option.value===value),[options,isMultiSelect,value]),{menuStyle:optionsListStyle,calculateStyle}=(0,_usePopupMenu.usePopupMenu)({triggerRef:refForPositioning,menuRef:optionsListRef,isOpen}),win=(0,_useWindow.useWindow)(),{variables}=(0,_react1.useTheme)(),effectiveMaxHeight=(0,_react.useMemo)(()=>{if(!win||!optionsListStyle.top)return maxHeight;let menuViewportMargin=parseInt(variables.size.spacing.xs,10),menuTopInViewport=optionsListStyle.top-(win.scrollY??0),spaceBelow=win.innerHeight-menuTopInViewport-menuViewportMargin;return!Number.isFinite(spaceBelow)||spaceBelow<=0?maxHeight:maxHeight?Math.min(maxHeight,spaceBelow):spaceBelow},[maxHeight,optionsListStyle,win,variables]);(0,_react.useLayoutEffect)(()=>{if(isOpen&&listContainerRef.current&&!isVirtualized&&optionsListStyle.top){let listElm=listContainerRef.current;listElm.clientHeight<listElm.scrollHeight&&(listItemsRef.current=listElm.querySelectorAll("[data-list-item]"),scrollToItem({list:listItemsRef.current,itemIndex:activeItemIndex,behavior:"instant"}))}else listItemsRef.current=null},[isOpen,isVirtualized,listContainerRef,options,maxHeight,optionsListStyle,activeItemIndex]),(0,_react.useEffect)(()=>{listItemsRef.current&&scrollToItem({list:listItemsRef.current,itemIndex:selectedIndex,behavior:"smooth"})},[listItemsRef,selectedIndex]);let closeDropdownWithoutSelect=(0,_react.useCallback)(()=>onCloseDropdown(!0),[onCloseDropdown]);(0,_useContainedEscape.useContainedEscape)([triggerRef],closeDropdownWithoutSelect,isOpen&&!disabled),(0,_useKeyboard.useKeyboard)({Enter:()=>{let preselectedOption=options[selectedIndex];if(!preselectedOption?.disabled){if(preselectedOption){forceChangeFakeSelect(preselectedOption),isMultiSelect||onCloseDropdown(!0);return}isMultiSelect||onCloseDropdown()}},ArrowUp:()=>{let newIndex=-1===selectedIndex?activeItemIndex:selectedIndex;for(;newIndex>0&&(newIndex-=1,options[newIndex]?.disabled););options[newIndex]?.disabled||onSelectedIndexChange(newIndex)},ArrowDown:()=>{let newIndex=-1===selectedIndex?activeItemIndex:selectedIndex;for(;newIndex<options.length-1&&(newIndex+=1,options[newIndex]?.disabled););options[newIndex]?.disabled||onSelectedIndexChange(newIndex)}},triggerRef,isOpen&&!disabled);let renderItem=index=>{let option=options[index],id=getOptionId(name,option.value);if(isMultiSelect){let isActive=value.includes(option.value);return _react.default.createElement(CustomOption,{role:"option","aria-selected":isActive,"aria-disabled":option.disabled,id:id,key:option.value,active:isActive,disabled:option.disabled??!1,preSelected:selectedIndex===index,"data-list-item":!0,onMouseDown:()=>{option.disabled||forceChangeFakeSelect(option)},onClick:evt=>evt.stopPropagation()},_react.default.createElement(_Checkbox.CheckboxRaw,{name:"",disabled:option.disabled,checked:isActive,size:"s",label:option.label,onChange:()=>null,labelHint:option?.description}))}let isActive=value===option.value,optionText=_react.default.createElement(_Stack.Stack,{space:"zero"},_react.default.createElement(_Text.Text,{color:"primary",size:"m"},option.label),option.description&&_react.default.createElement(_Text.Text,{color:"tertiary",size:"s"},option.description));return _react.default.createElement(_StyledSelectComponents.StyledOption,{role:"option","aria-selected":isActive,"aria-disabled":option.disabled,id:id,key:option.value,active:isActive,disabled:option.disabled??!1,preSelected:selectedIndex===index,"data-list-item":!0,onMouseDown:()=>{option.disabled||(forceChangeFakeSelect(option),onCloseDropdown(!0))}},isActive?_react.default.createElement(_Inline.Inline,{noWrap:!0,alignItems:"spaceBetween"},optionText,_react.default.createElement(_Box.Box,{space:"zero",tSpace:"xxxs"},_react.default.createElement(_Icon.Icon,{name:"check",size:"s",color:"accent"}))):optionText)},listStyle={...optionsListStyle,width:optionsListWidth||refForPositioning.current?.getBoundingClientRect().width},listElm=_react.default.createElement(_StyledSelectComponents.StyledDropdown,{style:listStyle,ref:optionsListRef,onMouseDown:e=>e.preventDefault(),"data-e2e-test-id":"optionsList"},isVirtualized?_react.default.createElement(_VirtualScrollList.VirtualScrollList,{id:getOptionsListId(name),maxHeight:effectiveMaxHeight,itemHeight:36,itemAmount:options.length,emptyState:()=>null,containerStyle:_constants.dropdownContainerStyle,itemInView:selectedIndex,itemTemplate:renderItem,onContentHeightChange:calculateStyle,role:"listbox"}):_react.default.createElement(StyledListContainer,{maxHeight:effectiveMaxHeight,role:"listbox",id:getOptionsListId(name),ref:listContainerRef},options.map((_option,index)=>renderItem(index))));if(!isOpen)return null;let listPortal=options.length?_react.default.createElement(_Portal.Portal,{portalContainer:portalContainer},listElm):null;return _react.default.createElement(_react.default.Fragment,null,_react.default.createElement(_ScreenReaderText.ScreenReaderText,{role:"status","aria-live":"polite"},options.length?"":emptyStateMessage),listPortal)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"SelectWithCustomTrigger",{enumerable:!0,get:function(){return SelectWithCustomTrigger}});const _interop_require_default=require("@swc/helpers/_/_interop_require_default"),_react=/*#__PURE__*/require("@swc/helpers/_/_interop_require_wildcard")._(require("react")),_styled=/*#__PURE__*/_interop_require_default._(require("@emotion/styled")),_OptionsList=require("../Combobox/OptionsList"),_useKeyboard=require("../../../shared/useKeyboard"),_useTypeAheadSearch=require("./useTypeAheadSearch"),HiddenSelectInput=(0,_styled.default)("select",{target:"
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"SelectWithCustomTrigger",{enumerable:!0,get:function(){return SelectWithCustomTrigger}});const _interop_require_default=require("@swc/helpers/_/_interop_require_default"),_react=/*#__PURE__*/require("@swc/helpers/_/_interop_require_wildcard")._(require("react")),_styled=/*#__PURE__*/_interop_require_default._(require("@emotion/styled")),_OptionsList=require("../Combobox/OptionsList"),_useContainedEscape=require("../../../shared/useContainedEscape"),_useKeyboard=require("../../../shared/useKeyboard"),_useTypeAheadSearch=require("./useTypeAheadSearch"),HiddenSelectInput=(0,_styled.default)("select",{target:"e2kj7nk0",label:"HiddenSelectInput"})(()=>({display:"none"}));function SelectWithCustomTrigger({renderTrigger,optionsListWidth,options=[],name,value,portalContainer,disabled=!1,maxHeight=230,autoComplete="on",readOnly=!1,excludeFromFormData=!1,onChange}){let[isOpen,setIsOpen]=(0,_react.useState)(!1),[selectedIndex,setSelectedIndex]=(0,_react.useState)(-1),triggerRef=(0,_react.useRef)(null),hiddenSelectRef=(0,_react.useRef)(null),currentOptionIndex=(0,_react.useMemo)(()=>options.findIndex(option=>option.value===value),[options,value]),closeOptionsList=(0,_react.useCallback)(()=>{isOpen&&(setIsOpen(!1),setSelectedIndex(-1))},[isOpen]),openOptionsList=(0,_react.useCallback)(()=>{isOpen||readOnly||(setIsOpen(!0),triggerRef.current?.focus())},[isOpen,readOnly]),toggleOptionsList=(0,_react.useCallback)(()=>{isOpen?closeOptionsList():openOptionsList()},[isOpen,openOptionsList,closeOptionsList]),handleSelectedIndexChange=(0,_react.useCallback)(index=>setSelectedIndex(index),[]),handleChange=(0,_react.useCallback)(option=>{let hiddenSelect=hiddenSelectRef.current;hiddenSelect&&(hiddenSelect.value=option.value,hiddenSelect.dispatchEvent(new Event("change",{bubbles:!0})))},[hiddenSelectRef]),handleSearchMatch=(0,_react.useCallback)(matchedIndex=>{-1!==matchedIndex&&(isOpen?setSelectedIndex(matchedIndex):handleChange(options[matchedIndex]))},[isOpen,options,setSelectedIndex,handleChange]);(0,_useKeyboard.useKeyboard)({"Enter Space ArrowUp ArrowDown":()=>{openOptionsList()}},triggerRef,!isOpen&&!disabled),(0,_useTypeAheadSearch.useTypeAheadSearch)({options,triggerRef,isActive:!disabled,fromIndex:-1!==selectedIndex?selectedIndex:currentOptionIndex,onMatch:handleSearchMatch}),(0,_react.useEffect)(()=>{let triggerElm=triggerRef.current,handlePointerDown=evt=>{evt.preventDefault()};return triggerElm&&!disabled&&(triggerElm.setAttribute("tabIndex","0"),triggerElm.addEventListener("click",toggleOptionsList),triggerElm.addEventListener("blur",closeOptionsList),triggerElm.addEventListener("pointerdown",handlePointerDown)),()=>{triggerElm?.removeEventListener("click",toggleOptionsList),triggerElm?.removeEventListener("blur",closeOptionsList),triggerElm?.removeEventListener("pointerdown",handlePointerDown)}},[triggerRef,disabled,closeOptionsList,toggleOptionsList]),(0,_useContainedEscape.useContainedEscape)([triggerRef],closeOptionsList,isOpen);let optionsListId=(0,_OptionsList.getOptionsListId)(name),ariaActiveDescendant=-1!==selectedIndex?(0,_OptionsList.getOptionId)(name,options[selectedIndex].value):"",triggerElm=renderTrigger({triggerRef,isOpen,disabled,role:"combobox","aria-activedescendant":isOpen?ariaActiveDescendant:"","aria-controls":isOpen?optionsListId:"","aria-expanded":isOpen}),optionsListElm=_react.default.createElement(_OptionsList.OptionsList,{name:name,isOpen:isOpen,isVirtualized:!1,options:options,triggerRef:triggerRef,onCloseDropdown:closeOptionsList,portalContainer:portalContainer,selectedIndex:selectedIndex,onSelectedIndexChange:handleSelectedIndexChange,forceChangeFakeSelect:handleChange,value:value,disabled:disabled,maxHeight:maxHeight,optionsListWidth:optionsListWidth});return _react.default.createElement(_react.default.Fragment,null,triggerElm,optionsListElm,_react.default.createElement(HiddenSelectInput,{name:excludeFromFormData?void 0:name,onChange:onChange,value:value,ref:hiddenSelectRef,autoComplete:autoComplete},_react.default.createElement("option",{value:"","aria-label":"Empty option"}),options.map(option=>_react.default.createElement("option",{value:option.value,key:option.value},option.label))))}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { RefObject } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* useContainedEscape handles Escape on the given elements and stops it there,
|
|
4
|
+
* before it reaches document. An enclosing focus trap with escapeDeactivates
|
|
5
|
+
* (e.g. a Modal) listens on document, so a popup that closes on Escape must
|
|
6
|
+
* stop the event first to close only itself.
|
|
7
|
+
* @param {RefObject[]} refs - Elements that receive keydown while the popup is open, e.g. its trigger.
|
|
8
|
+
* @param {e: KeyboardEvent => void} onEscape - Function invoked when Escape is pressed on one of the elements.
|
|
9
|
+
* @param {boolean} isActive - A flag to determine when the Escape listener needs to be applied.
|
|
10
|
+
*
|
|
11
|
+
* Example: useContainedEscape([triggerRef], closeList, listIsOpen)
|
|
12
|
+
*/
|
|
13
|
+
export declare const useContainedEscape: (refs: RefObject<HTMLElement>[], onEscape: (e: KeyboardEvent) => void, isActive: boolean) => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),Object.defineProperty(exports,"useContainedEscape",{enumerable:!0,get:function(){return useContainedEscape}});const _react=require("react"),useContainedEscape=(refs,onEscape,isActive)=>{let refsRef=(0,_react.useRef)(refs);refsRef.current=refs,(0,_react.useEffect)(()=>{if(!isActive)return;let elements=refsRef.current.map(ref=>ref.current),handleEscapeKeyDown=evt=>{"Escape"===evt.code&&(evt.preventDefault(),evt.stopPropagation(),onEscape(evt))};return elements.forEach(elm=>elm?.addEventListener("keydown",handleEscapeKeyDown)),()=>{elements.forEach(elm=>elm?.removeEventListener("keydown",handleEscapeKeyDown))}},[onEscape,isActive])};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import React,{useEffect,useRef,useState}from"react";import styled from"@emotion/styled";import{useKeyboard}from"../../shared/useKeyboard";import{Divider}from"../Divider/Divider";import{MenuItem}from"./MenuItem";import{usePopupMenu}from"../../shared/popupMenu/usePopupMenu";import{useOutsideInteract}from"../../shared/useOutsideInteract";import{Portal,usePortalChildZIndex}from"../Portal/Portal";let isSeperator=item=>"separator"===item,StyledMenu=styled("div",{target:"
|
|
1
|
+
import React,{useEffect,useRef,useState}from"react";import styled from"@emotion/styled";import{useKeyboard}from"../../shared/useKeyboard";import{useContainedEscape}from"../../shared/useContainedEscape";import{Divider}from"../Divider/Divider";import{MenuItem}from"./MenuItem";import{usePopupMenu}from"../../shared/popupMenu/usePopupMenu";import{useOutsideInteract}from"../../shared/useOutsideInteract";import{Portal,usePortalChildZIndex}from"../Portal/Portal";let isSeperator=item=>"separator"===item,StyledMenu=styled("div",{target:"ecmxohu0",label:"StyledMenu"})(({theme})=>{let zIndex=usePortalChildZIndex(theme.variables.zIndex.dropdown);return{position:"absolute",display:"inline-block",width:"fit-content",minWidth:theme.variables.size.dimension.dropdownMenu.width,zIndex,borderRadius:theme.variables.size.borderRadius.s,backgroundColor:theme.values.color.background.primary.default,paddingTop:theme.variables.size.spacing.xs,paddingBottom:theme.variables.size.spacing.xs,":after":{content:'" "',position:"absolute",top:0,left:0,width:"100%",height:"100%",pointerEvents:"none",borderRadius:"inherit",boxShadow:theme.values.elevation[3]}}}),StyledUl=styled("ul",{target:"ecmxohu1",label:"StyledUl"})(()=>({margin:0,padding:0,overflow:"hidden"})),StyledLi=styled("li",{target:"ecmxohu2",label:"StyledLi"})(()=>({margin:0,padding:0,width:"100%",listStyleType:"none",whiteSpace:"nowrap"})),StyledLiSeparator=styled(StyledLi,{target:"ecmxohu3",label:"StyledLiSeparator"})(({theme})=>({marginTop:theme.variables.size.spacing.xs,marginBottom:theme.variables.size.spacing.xs}));export function Menu({isOpen,items,portalContainer,triggerRef,placement,onCloseMenu}){let menuRef=useRef(null),[focusIndex,setFocusIndex]=useState(0),{menuStyle}=usePopupMenu({triggerRef,menuRef,isOpen,placement});useOutsideInteract({ref:menuRef,excludeRefs:[triggerRef],onInteractOutside:onCloseMenu,isActive:isOpen}),useContainedEscape([menuRef,triggerRef],onCloseMenu,isOpen),useKeyboard({ArrowUp:()=>{setFocusIndex(index=>index-1)},ArrowDown:()=>{setFocusIndex(index=>index+1)}},menuRef,isOpen),useEffect(()=>{if(menuRef&&menuRef.current){let buttons=menuRef.current.querySelectorAll("button");buttons[Math.abs(focusIndex)%buttons.length].focus({preventScroll:!0})}isOpen||setFocusIndex(0)},[menuRef,focusIndex,isOpen]);let menuElm=React.createElement(StyledMenu,{ref:menuRef,style:menuStyle},React.createElement(StyledUl,{role:"menu"},items.map((item,index)=>{if(isSeperator(item))return React.createElement(StyledLiSeparator,{role:"separator",key:`menuitem-separator-${index}`},React.createElement(Divider,{"aria-hidden":"true"}));let{label,destructive,disabled,emphasized,icon,onSelect}=item;return React.createElement(StyledLi,{role:"menuitem",key:`menuitem-${label}`},React.createElement(MenuItem,{onSelect:onSelect,icon:icon,label:label,disabled:disabled,destructive:destructive,emphasized:emphasized}))})));return isOpen?React.createElement(Portal,{portalContainer:portalContainer},menuElm):null}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import React,{useRef,useEffect,useLayoutEffect,useMemo}from"react";import{useTheme}from"@emotion/react";import styled from"@emotion/styled";import{useKeyboard}from"../../../shared/useKeyboard";import{useWindow}from"../../../shared/useWindow";import{usePopupMenu}from"../../../shared/popupMenu/usePopupMenu";import{VirtualScrollList}from"../../VirtualScrollList/VirtualScrollList";import{Text}from"../../Typography/Text/Text";import{Box}from"../../Box/Box";import{Inline}from"../../Inline/Inline";import{Icon}from"../../Icon/Icon";import{StyledDropdown,StyledOption}from"./StyledSelectComponents";import{dropdownContainerStyle}from"./constants";import{Stack}from"../../Stack/Stack";import{CheckboxRaw}from"../Checkbox/Checkbox";import{Portal}from"../../Portal/Portal";import{ScreenReaderText}from"../../Utilities/ScreenReaderText/ScreenReaderText";export const OPTIONS_LIST_SELECTOR='[role="listbox"], [role="option"]';export function getOptionId(selectName,optionValue){return`${selectName}Option${optionValue}`}export function getOptionsListId(selectName){return`${selectName}OptionsList`}let scrollToItem=({list,itemIndex,behavior})=>{list[itemIndex]?.scrollIntoView?.({behavior,block:"nearest"})},CustomOption=styled(StyledOption,{target:"
|
|
1
|
+
import React,{useRef,useEffect,useLayoutEffect,useMemo,useCallback}from"react";import{useTheme}from"@emotion/react";import styled from"@emotion/styled";import{useKeyboard}from"../../../shared/useKeyboard";import{useContainedEscape}from"../../../shared/useContainedEscape";import{useWindow}from"../../../shared/useWindow";import{usePopupMenu}from"../../../shared/popupMenu/usePopupMenu";import{VirtualScrollList}from"../../VirtualScrollList/VirtualScrollList";import{Text}from"../../Typography/Text/Text";import{Box}from"../../Box/Box";import{Inline}from"../../Inline/Inline";import{Icon}from"../../Icon/Icon";import{StyledDropdown,StyledOption}from"./StyledSelectComponents";import{dropdownContainerStyle}from"./constants";import{Stack}from"../../Stack/Stack";import{CheckboxRaw}from"../Checkbox/Checkbox";import{Portal}from"../../Portal/Portal";import{ScreenReaderText}from"../../Utilities/ScreenReaderText/ScreenReaderText";export const OPTIONS_LIST_SELECTOR='[role="listbox"], [role="option"]';export function getOptionId(selectName,optionValue){return`${selectName}Option${optionValue}`}export function getOptionsListId(selectName){return`${selectName}OptionsList`}let scrollToItem=({list,itemIndex,behavior})=>{list[itemIndex]?.scrollIntoView?.({behavior,block:"nearest"})},CustomOption=styled(StyledOption,{target:"evwdew0",label:"CustomOption"})(({theme})=>({paddingTop:0,paddingBottom:0,"& > div":{paddingTop:theme.variables.size.spacing.xs,paddingBottom:theme.variables.size.spacing.xs},"& > div *":{marginTop:0}})),StyledListContainer=styled("div",{target:"evwdew1",label:"StyledListContainer"})(({theme,maxHeight})=>({maxHeight,boxSizing:"border-box",overflow:"auto",padding:`${theme.variables.size.spacing.xxs} 0`}));export function OptionsList({isOpen,isMultiSelect=!1,value,disabled,options=[],portalContainer,triggerRef,triggerWrapperRef,maxHeight,emptyStateMessage="No options available",selectedIndex,optionsListWidth,isVirtualized=!0,name,onCloseDropdown,onSelectedIndexChange,forceChangeFakeSelect}){let optionsListRef=useRef(null),listContainerRef=useRef(null),listItemsRef=useRef(null),refForPositioning=triggerWrapperRef||triggerRef,activeItemIndex=useMemo(()=>options.findIndex(option=>isMultiSelect?value.includes(option.value):option.value===value),[options,isMultiSelect,value]),{menuStyle:optionsListStyle,calculateStyle}=usePopupMenu({triggerRef:refForPositioning,menuRef:optionsListRef,isOpen}),win=useWindow(),{variables}=useTheme(),effectiveMaxHeight=useMemo(()=>{if(!win||!optionsListStyle.top)return maxHeight;let menuViewportMargin=parseInt(variables.size.spacing.xs,10),menuTopInViewport=optionsListStyle.top-(win.scrollY??0),spaceBelow=win.innerHeight-menuTopInViewport-menuViewportMargin;return!Number.isFinite(spaceBelow)||spaceBelow<=0?maxHeight:maxHeight?Math.min(maxHeight,spaceBelow):spaceBelow},[maxHeight,optionsListStyle,win,variables]);useLayoutEffect(()=>{if(isOpen&&listContainerRef.current&&!isVirtualized&&optionsListStyle.top){let listElm=listContainerRef.current;listElm.clientHeight<listElm.scrollHeight&&(listItemsRef.current=listElm.querySelectorAll("[data-list-item]"),scrollToItem({list:listItemsRef.current,itemIndex:activeItemIndex,behavior:"instant"}))}else listItemsRef.current=null},[isOpen,isVirtualized,listContainerRef,options,maxHeight,optionsListStyle,activeItemIndex]),useEffect(()=>{listItemsRef.current&&scrollToItem({list:listItemsRef.current,itemIndex:selectedIndex,behavior:"smooth"})},[listItemsRef,selectedIndex]),useContainedEscape([triggerRef],useCallback(()=>onCloseDropdown(!0),[onCloseDropdown]),isOpen&&!disabled),useKeyboard({Enter:()=>{let preselectedOption=options[selectedIndex];if(!preselectedOption?.disabled){if(preselectedOption){forceChangeFakeSelect(preselectedOption),isMultiSelect||onCloseDropdown(!0);return}isMultiSelect||onCloseDropdown()}},ArrowUp:()=>{let newIndex=-1===selectedIndex?activeItemIndex:selectedIndex;for(;newIndex>0&&(newIndex-=1,options[newIndex]?.disabled););options[newIndex]?.disabled||onSelectedIndexChange(newIndex)},ArrowDown:()=>{let newIndex=-1===selectedIndex?activeItemIndex:selectedIndex;for(;newIndex<options.length-1&&(newIndex+=1,options[newIndex]?.disabled););options[newIndex]?.disabled||onSelectedIndexChange(newIndex)}},triggerRef,isOpen&&!disabled);let renderItem=index=>{let option=options[index],id=getOptionId(name,option.value);if(isMultiSelect){let isActive=value.includes(option.value);return React.createElement(CustomOption,{role:"option","aria-selected":isActive,"aria-disabled":option.disabled,id:id,key:option.value,active:isActive,disabled:option.disabled??!1,preSelected:selectedIndex===index,"data-list-item":!0,onMouseDown:()=>{option.disabled||forceChangeFakeSelect(option)},onClick:evt=>evt.stopPropagation()},React.createElement(CheckboxRaw,{name:"",disabled:option.disabled,checked:isActive,size:"s",label:option.label,onChange:()=>null,labelHint:option?.description}))}let isActive=value===option.value,optionText=React.createElement(Stack,{space:"zero"},React.createElement(Text,{color:"primary",size:"m"},option.label),option.description&&React.createElement(Text,{color:"tertiary",size:"s"},option.description));return React.createElement(StyledOption,{role:"option","aria-selected":isActive,"aria-disabled":option.disabled,id:id,key:option.value,active:isActive,disabled:option.disabled??!1,preSelected:selectedIndex===index,"data-list-item":!0,onMouseDown:()=>{option.disabled||(forceChangeFakeSelect(option),onCloseDropdown(!0))}},isActive?React.createElement(Inline,{noWrap:!0,alignItems:"spaceBetween"},optionText,React.createElement(Box,{space:"zero",tSpace:"xxxs"},React.createElement(Icon,{name:"check",size:"s",color:"accent"}))):optionText)},listStyle={...optionsListStyle,width:optionsListWidth||refForPositioning.current?.getBoundingClientRect().width},listElm=React.createElement(StyledDropdown,{style:listStyle,ref:optionsListRef,onMouseDown:e=>e.preventDefault(),"data-e2e-test-id":"optionsList"},isVirtualized?React.createElement(VirtualScrollList,{id:getOptionsListId(name),maxHeight:effectiveMaxHeight,itemHeight:36,itemAmount:options.length,emptyState:()=>null,containerStyle:dropdownContainerStyle,itemInView:selectedIndex,itemTemplate:renderItem,onContentHeightChange:calculateStyle,role:"listbox"}):React.createElement(StyledListContainer,{maxHeight:effectiveMaxHeight,role:"listbox",id:getOptionsListId(name),ref:listContainerRef},options.map((_option,index)=>renderItem(index))));if(!isOpen)return null;let listPortal=options.length?React.createElement(Portal,{portalContainer:portalContainer},listElm):null;return React.createElement(React.Fragment,null,React.createElement(ScreenReaderText,{role:"status","aria-live":"polite"},options.length?"":emptyStateMessage),listPortal)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import React,{useState,useRef,useEffect,useCallback,useMemo}from"react";import styled from"@emotion/styled";import{getOptionId,getOptionsListId,OptionsList}from"../Combobox/OptionsList";import{useKeyboard}from"../../../shared/useKeyboard";import{useTypeAheadSearch}from"./useTypeAheadSearch";let HiddenSelectInput=styled("select",{target:"
|
|
1
|
+
import React,{useState,useRef,useEffect,useCallback,useMemo}from"react";import styled from"@emotion/styled";import{getOptionId,getOptionsListId,OptionsList}from"../Combobox/OptionsList";import{useContainedEscape}from"../../../shared/useContainedEscape";import{useKeyboard}from"../../../shared/useKeyboard";import{useTypeAheadSearch}from"./useTypeAheadSearch";let HiddenSelectInput=styled("select",{target:"e2kj7nk0",label:"HiddenSelectInput"})(()=>({display:"none"}));export function SelectWithCustomTrigger({renderTrigger,optionsListWidth,options=[],name,value,portalContainer,disabled=!1,maxHeight=230,autoComplete="on",readOnly=!1,excludeFromFormData=!1,onChange}){let[isOpen,setIsOpen]=useState(!1),[selectedIndex,setSelectedIndex]=useState(-1),triggerRef=useRef(null),hiddenSelectRef=useRef(null),currentOptionIndex=useMemo(()=>options.findIndex(option=>option.value===value),[options,value]),closeOptionsList=useCallback(()=>{isOpen&&(setIsOpen(!1),setSelectedIndex(-1))},[isOpen]),openOptionsList=useCallback(()=>{isOpen||readOnly||(setIsOpen(!0),triggerRef.current?.focus())},[isOpen,readOnly]),toggleOptionsList=useCallback(()=>{isOpen?closeOptionsList():openOptionsList()},[isOpen,openOptionsList,closeOptionsList]),handleSelectedIndexChange=useCallback(index=>setSelectedIndex(index),[]),handleChange=useCallback(option=>{let hiddenSelect=hiddenSelectRef.current;hiddenSelect&&(hiddenSelect.value=option.value,hiddenSelect.dispatchEvent(new Event("change",{bubbles:!0})))},[hiddenSelectRef]),handleSearchMatch=useCallback(matchedIndex=>{-1!==matchedIndex&&(isOpen?setSelectedIndex(matchedIndex):handleChange(options[matchedIndex]))},[isOpen,options,setSelectedIndex,handleChange]);useKeyboard({"Enter Space ArrowUp ArrowDown":()=>{openOptionsList()}},triggerRef,!isOpen&&!disabled),useTypeAheadSearch({options,triggerRef,isActive:!disabled,fromIndex:-1!==selectedIndex?selectedIndex:currentOptionIndex,onMatch:handleSearchMatch}),useEffect(()=>{let triggerElm=triggerRef.current,handlePointerDown=evt=>{evt.preventDefault()};return triggerElm&&!disabled&&(triggerElm.setAttribute("tabIndex","0"),triggerElm.addEventListener("click",toggleOptionsList),triggerElm.addEventListener("blur",closeOptionsList),triggerElm.addEventListener("pointerdown",handlePointerDown)),()=>{triggerElm?.removeEventListener("click",toggleOptionsList),triggerElm?.removeEventListener("blur",closeOptionsList),triggerElm?.removeEventListener("pointerdown",handlePointerDown)}},[triggerRef,disabled,closeOptionsList,toggleOptionsList]),useContainedEscape([triggerRef],closeOptionsList,isOpen);let optionsListId=getOptionsListId(name),ariaActiveDescendant=-1!==selectedIndex?getOptionId(name,options[selectedIndex].value):"",triggerElm=renderTrigger({triggerRef,isOpen,disabled,role:"combobox","aria-activedescendant":isOpen?ariaActiveDescendant:"","aria-controls":isOpen?optionsListId:"","aria-expanded":isOpen}),optionsListElm=React.createElement(OptionsList,{name:name,isOpen:isOpen,isVirtualized:!1,options:options,triggerRef:triggerRef,onCloseDropdown:closeOptionsList,portalContainer:portalContainer,selectedIndex:selectedIndex,onSelectedIndexChange:handleSelectedIndexChange,forceChangeFakeSelect:handleChange,value:value,disabled:disabled,maxHeight:maxHeight,optionsListWidth:optionsListWidth});return React.createElement(React.Fragment,null,triggerElm,optionsListElm,React.createElement(HiddenSelectInput,{name:excludeFromFormData?void 0:name,onChange:onChange,value:value,ref:hiddenSelectRef,autoComplete:autoComplete},React.createElement("option",{value:"","aria-label":"Empty option"}),options.map(option=>React.createElement("option",{value:option.value,key:option.value},option.label))))}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { RefObject } from "react";
|
|
2
|
+
/**
|
|
3
|
+
* useContainedEscape handles Escape on the given elements and stops it there,
|
|
4
|
+
* before it reaches document. An enclosing focus trap with escapeDeactivates
|
|
5
|
+
* (e.g. a Modal) listens on document, so a popup that closes on Escape must
|
|
6
|
+
* stop the event first to close only itself.
|
|
7
|
+
* @param {RefObject[]} refs - Elements that receive keydown while the popup is open, e.g. its trigger.
|
|
8
|
+
* @param {e: KeyboardEvent => void} onEscape - Function invoked when Escape is pressed on one of the elements.
|
|
9
|
+
* @param {boolean} isActive - A flag to determine when the Escape listener needs to be applied.
|
|
10
|
+
*
|
|
11
|
+
* Example: useContainedEscape([triggerRef], closeList, listIsOpen)
|
|
12
|
+
*/
|
|
13
|
+
export declare const useContainedEscape: (refs: RefObject<HTMLElement>[], onEscape: (e: KeyboardEvent) => void, isActive: boolean) => void;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{useEffect,useRef}from"react";export const useContainedEscape=(refs,onEscape,isActive)=>{let refsRef=useRef(refs);refsRef.current=refs,useEffect(()=>{if(!isActive)return;let elements=refsRef.current.map(ref=>ref.current),handleEscapeKeyDown=evt=>{"Escape"===evt.code&&(evt.preventDefault(),evt.stopPropagation(),onEscape(evt))};return elements.forEach(elm=>elm?.addEventListener("keydown",handleEscapeKeyDown)),()=>{elements.forEach(elm=>elm?.removeEventListener("keydown",handleEscapeKeyDown))}},[onEscape,isActive])};
|